totemlayer 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -3
- package/bin/collaboration-companion.mjs +328 -0
- package/bin/collaboration-listener.mjs +425 -0
- package/bin/local-mcp.mjs +97 -0
- package/bin/managed-collaboration.mjs +94 -0
- package/bin/mcp-install.mjs +155 -0
- package/bin/mcp.mjs +777 -0
- package/bin/network-runtime.mjs +685 -0
- package/bin/network.mjs +323 -0
- package/bin/presenter-mcp.mjs +238 -0
- package/bin/repository.d.mts +27 -0
- package/bin/repository.mjs +135 -0
- package/bin/sdk/errors.js +54 -0
- package/bin/sdk/index.js +307 -0
- package/bin/sdk/transport.js +197 -0
- package/bin/sdk/types.js +1 -0
- package/bin/totem.mjs +579 -152
- package/package.json +10 -2
- package/scripts/prepare.mjs +15 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_ORIGIN = "https://totemlayer.com";
|
|
7
|
+
const DEFAULT_NAME = "totem-local";
|
|
8
|
+
const SERVER_ENTRY = fileURLToPath(new URL("./totem.mjs", import.meta.url));
|
|
9
|
+
|
|
10
|
+
export const MCP_INSTALL_HELP = `Connect Totem to an AI app
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
totem mcp install codex --key-file /absolute/path/to/agent.key
|
|
14
|
+
totem mcp install claude --key-file /absolute/path/to/agent.key
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--base-url <origin> Totem origin (default: https://totemlayer.com)
|
|
18
|
+
--name <name> MCP server name (default: totem-local)
|
|
19
|
+
--key-file <path> Existing private agent key file (required)
|
|
20
|
+
--help Show this guide
|
|
21
|
+
|
|
22
|
+
This installs a user-level local stdio MCP connection. It never puts the key
|
|
23
|
+
value in a command, client config, or repository. It will not overwrite an
|
|
24
|
+
existing MCP server. Restart the AI app afterward and ask for totem_get_identity.
|
|
25
|
+
On macOS/Linux the key file must be mode 0600. The package must remain installed.
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
function fail(message) {
|
|
29
|
+
throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function parseInstallArgs(args, environment) {
|
|
33
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) return { help: true };
|
|
34
|
+
const [client, ...rest] = args;
|
|
35
|
+
if (client !== "codex" && client !== "claude")
|
|
36
|
+
fail("Choose codex or claude. Run `totem mcp install --help` for examples.");
|
|
37
|
+
const values = {};
|
|
38
|
+
for (let index = 0; index < rest.length; index += 2) {
|
|
39
|
+
const option = rest[index];
|
|
40
|
+
const value = rest[index + 1];
|
|
41
|
+
if (
|
|
42
|
+
!["--key-file", "--base-url", "--name"].includes(option) ||
|
|
43
|
+
!value ||
|
|
44
|
+
value.startsWith("--")
|
|
45
|
+
)
|
|
46
|
+
fail(`Invalid option ${option ?? ""}. Run \`totem mcp install --help\`.`);
|
|
47
|
+
if (values[option] !== undefined) fail(`${option} was provided more than once.`);
|
|
48
|
+
values[option] = value;
|
|
49
|
+
}
|
|
50
|
+
const keyFile = values["--key-file"] ?? environment.TOTEM_NETWORK_API_KEY_FILE;
|
|
51
|
+
if (!keyFile) fail("Pass --key-file with the path to your own Totem agent key file.");
|
|
52
|
+
const name = values["--name"] ?? DEFAULT_NAME;
|
|
53
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(name))
|
|
54
|
+
fail(
|
|
55
|
+
"The MCP name must be 1-64 letters, numbers, hyphens or underscores and start with a letter.",
|
|
56
|
+
);
|
|
57
|
+
const rawOrigin = values["--base-url"] ?? environment.TOTEM_BASE_URL ?? DEFAULT_ORIGIN;
|
|
58
|
+
let url;
|
|
59
|
+
try {
|
|
60
|
+
url = new URL(rawOrigin);
|
|
61
|
+
} catch {
|
|
62
|
+
fail("--base-url must be a valid HTTPS origin (or HTTP loopback for local development).");
|
|
63
|
+
}
|
|
64
|
+
if (
|
|
65
|
+
url.username ||
|
|
66
|
+
url.password ||
|
|
67
|
+
url.search ||
|
|
68
|
+
url.hash ||
|
|
69
|
+
url.pathname !== "/" ||
|
|
70
|
+
(url.protocol !== "https:" &&
|
|
71
|
+
!(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)))
|
|
72
|
+
)
|
|
73
|
+
fail(
|
|
74
|
+
"--base-url must be a credential-free HTTPS origin (or HTTP loopback for local development).",
|
|
75
|
+
);
|
|
76
|
+
return { client, keyFile: resolve(keyFile), name, baseUrl: url.origin };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function validateKeyFile(path) {
|
|
80
|
+
const info = await stat(path);
|
|
81
|
+
if (!info.isFile() || info.size === 0 || info.size > 8 * 1024)
|
|
82
|
+
fail("The Totem agent key must be a nonempty regular file no larger than 8 KiB.");
|
|
83
|
+
if (process.platform !== "win32" && (info.mode & 0o077) !== 0)
|
|
84
|
+
fail("The Totem agent key file must be private (mode 0600). Fix its permissions and retry.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function runClient(command, args, environment) {
|
|
88
|
+
const result = spawnSync(command, args, {
|
|
89
|
+
encoding: "utf8",
|
|
90
|
+
env: environment,
|
|
91
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
92
|
+
timeout: 20_000,
|
|
93
|
+
});
|
|
94
|
+
if (result.error?.code === "ENOENT")
|
|
95
|
+
fail(
|
|
96
|
+
`${command} is not installed or is not on PATH. Install and sign in to that AI client first.`,
|
|
97
|
+
);
|
|
98
|
+
if (result.error) fail(`${command} could not complete MCP setup: ${result.error.message}`);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function installTotemMcp(args, environment = process.env) {
|
|
103
|
+
const options = parseInstallArgs(args, environment);
|
|
104
|
+
if (options.help) return MCP_INSTALL_HELP;
|
|
105
|
+
if (process.platform === "win32")
|
|
106
|
+
fail(
|
|
107
|
+
"Automatic MCP setup is not yet supported on Windows. Use the manual stdio MCP configuration in the Totem CLI README.",
|
|
108
|
+
);
|
|
109
|
+
await validateKeyFile(options.keyFile);
|
|
110
|
+
|
|
111
|
+
const command = options.client;
|
|
112
|
+
const existing = runClient(command, ["mcp", "get", options.name], environment);
|
|
113
|
+
if (existing.status === 0)
|
|
114
|
+
fail(
|
|
115
|
+
`${options.name} already exists in ${command}. No configuration was changed. Choose another --name or inspect the existing connection first.`,
|
|
116
|
+
);
|
|
117
|
+
if (!/no mcp server|not found|does not exist/i.test(`${existing.stderr}\n${existing.stdout}`))
|
|
118
|
+
fail(
|
|
119
|
+
`${command} could not check whether ${options.name} already exists. No configuration was changed.`,
|
|
120
|
+
);
|
|
121
|
+
const envArgs = [
|
|
122
|
+
"--env",
|
|
123
|
+
`TOTEM_BASE_URL=${options.baseUrl}`,
|
|
124
|
+
"--env",
|
|
125
|
+
`TOTEM_NETWORK_API_KEY_FILE=${options.keyFile}`,
|
|
126
|
+
];
|
|
127
|
+
const addArgs =
|
|
128
|
+
options.client === "codex"
|
|
129
|
+
? ["mcp", "add", options.name, ...envArgs, "--", process.execPath, SERVER_ENTRY, "mcp"]
|
|
130
|
+
: [
|
|
131
|
+
"mcp",
|
|
132
|
+
"add",
|
|
133
|
+
...envArgs,
|
|
134
|
+
"--scope",
|
|
135
|
+
"user",
|
|
136
|
+
"--transport",
|
|
137
|
+
"stdio",
|
|
138
|
+
options.name,
|
|
139
|
+
"--",
|
|
140
|
+
process.execPath,
|
|
141
|
+
SERVER_ENTRY,
|
|
142
|
+
"mcp",
|
|
143
|
+
];
|
|
144
|
+
const added = runClient(command, addArgs, environment);
|
|
145
|
+
if (added.status !== 0)
|
|
146
|
+
fail(
|
|
147
|
+
`${command} could not add ${options.name}. No Totem key value was sent. Check the client's MCP setup and retry.`,
|
|
148
|
+
);
|
|
149
|
+
const verified = runClient(command, ["mcp", "get", options.name], environment);
|
|
150
|
+
if (verified.status !== 0)
|
|
151
|
+
fail(
|
|
152
|
+
`${command} reported an install, but ${options.name} could not be verified. Inspect its MCP settings before using it.`,
|
|
153
|
+
);
|
|
154
|
+
return `Connected ${options.name} to ${command} at ${options.baseUrl}. Restart ${command}, then ask it to call totem_get_identity. The Totem CLI package must remain installed.\n`;
|
|
155
|
+
}
|