totemlayer 0.1.68 → 0.1.74
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 +9 -13
- package/bin/agent-runner.mjs +23 -1
- package/bin/automatic-runtime.mjs +23 -12
- package/bin/codex-chat-bridge.mjs +72 -38
- package/bin/codex-desktop-wake.mjs +47 -20
- package/bin/codex-human-chat-bridge.mjs +57 -21
- package/bin/codex-mission-bridge.mjs +167 -0
- package/bin/connected-agent-service.mjs +12 -2
- package/bin/executor-diagnostic.mjs +169 -61
- package/bin/installation.mjs +8 -16
- package/bin/local-inspector.mjs +6 -0
- package/bin/mcp-install.mjs +12 -1
- package/bin/mcp.mjs +43 -1
- package/bin/mission-worker.mjs +62 -39
- package/bin/model-adapter.mjs +30 -1
- package/bin/native/darwin-lifetime +0 -0
- package/bin/native/darwin-lifetime.json +1 -1
- package/bin/network-contract.mjs +125 -0
- package/bin/network-runtime.mjs +367 -315
- package/bin/observability.mjs +336 -0
- package/bin/platform-client.mjs +6 -3
- package/bin/plugin-connect.mjs +10 -0
- package/bin/provider-diagnostics.mjs +40 -11
- package/bin/runtime-installation.mjs +4 -1
- package/bin/runtime-lock.mjs +43 -6
- package/bin/sdk/index.d.ts +1 -0
- package/bin/sdk/index.js +1 -1
- package/bin/setup-assets/api-connect.backup.md +129 -0
- package/bin/setup-assets/api-connect.md +129 -0
- package/bin/setup-assets/api-manifest.json +1 -0
- package/bin/setup-assets/manifest.json +1 -0
- package/bin/setup-assets/setup.backup.md +178 -0
- package/bin/setup-assets/setup.md +178 -0
- package/bin/setup-guide.mjs +39 -0
- package/bin/setup-receipts.mjs +181 -0
- package/bin/strict-codex-adapter.mjs +456 -0
- package/bin/strict-installation.mjs +206 -0
- package/bin/strict-setup-jobs.mjs +253 -0
- package/bin/strict-setup.mjs +385 -0
- package/bin/totem.mjs +11 -1
- package/package.json +4 -3
- package/scripts/prepare.mjs +2 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export const SETUP_CHECKS = Object.freeze([
|
|
4
|
+
"guide",
|
|
5
|
+
"model",
|
|
6
|
+
"identity",
|
|
7
|
+
"transport",
|
|
8
|
+
"receiver",
|
|
9
|
+
"startup",
|
|
10
|
+
"recovery",
|
|
11
|
+
"nativeWake",
|
|
12
|
+
"peerReply",
|
|
13
|
+
"ownerChat",
|
|
14
|
+
]);
|
|
15
|
+
export const GUIDE_UNAVAILABLE = "Setup incomplete: setup.md could not be read in full.";
|
|
16
|
+
const token = (value) =>
|
|
17
|
+
typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:/@-]{0,319}$/.test(value);
|
|
18
|
+
const uuid = (value) =>
|
|
19
|
+
typeof value === "string" && /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(value);
|
|
20
|
+
const digest = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
21
|
+
const stop = (code) => {
|
|
22
|
+
throw Object.assign(new Error(code), { code });
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function setupBinding(identity, host, transport, connection) {
|
|
26
|
+
if (
|
|
27
|
+
!uuid(identity?.id) ||
|
|
28
|
+
!token(identity.address) ||
|
|
29
|
+
!uuid(identity.organization?.id) ||
|
|
30
|
+
!["PRODUCTION", "SANDBOX"].includes(identity.environment) ||
|
|
31
|
+
!token(host?.name) ||
|
|
32
|
+
!token(host.model) ||
|
|
33
|
+
host.model === "default" ||
|
|
34
|
+
!token(host.sessionId) ||
|
|
35
|
+
!["mcp", "api"].includes(transport) ||
|
|
36
|
+
!/^[a-f0-9]{64}$/.test(connection?.fingerprint ?? "")
|
|
37
|
+
)
|
|
38
|
+
stop("SETUP_BINDING_UNVERIFIED");
|
|
39
|
+
let origin;
|
|
40
|
+
try {
|
|
41
|
+
const url = new URL(connection.origin);
|
|
42
|
+
if (
|
|
43
|
+
url.username ||
|
|
44
|
+
url.password ||
|
|
45
|
+
url.search ||
|
|
46
|
+
url.hash ||
|
|
47
|
+
url.pathname !== "/" ||
|
|
48
|
+
(url.protocol !== "https:" &&
|
|
49
|
+
!(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)))
|
|
50
|
+
)
|
|
51
|
+
stop("SETUP_BINDING_UNVERIFIED");
|
|
52
|
+
origin = url.origin;
|
|
53
|
+
} catch {
|
|
54
|
+
stop("SETUP_BINDING_UNVERIFIED");
|
|
55
|
+
}
|
|
56
|
+
return digest([
|
|
57
|
+
identity.id,
|
|
58
|
+
identity.address,
|
|
59
|
+
identity.organization.id,
|
|
60
|
+
identity.environment,
|
|
61
|
+
origin,
|
|
62
|
+
connection.fingerprint,
|
|
63
|
+
host.name,
|
|
64
|
+
host.model,
|
|
65
|
+
host.sessionId,
|
|
66
|
+
transport,
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function sameHost(before, after) {
|
|
71
|
+
return (
|
|
72
|
+
after?.modelVerified === true &&
|
|
73
|
+
before.name === after.name &&
|
|
74
|
+
before.model === after.model &&
|
|
75
|
+
before.sessionId === after.sessionId &&
|
|
76
|
+
before.policyDigest === after.policyDigest
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** This controller accepts observations from installed adapters, never model-supplied proofs. */
|
|
81
|
+
export async function runStrictSetup(adapter, options = {}) {
|
|
82
|
+
const checks = Object.fromEntries(SETUP_CHECKS.map((name) => [name, false]));
|
|
83
|
+
let identity,
|
|
84
|
+
host,
|
|
85
|
+
transport,
|
|
86
|
+
binding,
|
|
87
|
+
receiver,
|
|
88
|
+
proofs,
|
|
89
|
+
apiReason,
|
|
90
|
+
operation = "readGuide";
|
|
91
|
+
const progress = async (stage) => options.progress?.({ stage, checks: { ...checks } });
|
|
92
|
+
const report = (code) => ({
|
|
93
|
+
version: 1,
|
|
94
|
+
complete: !code && SETUP_CHECKS.every((name) => checks[name]),
|
|
95
|
+
state:
|
|
96
|
+
code === "RECEIVER_INTENTIONALLY_PAUSED"
|
|
97
|
+
? "paused"
|
|
98
|
+
: !code && SETUP_CHECKS.every((name) => checks[name])
|
|
99
|
+
? "complete"
|
|
100
|
+
: "incomplete",
|
|
101
|
+
...(code ? { code } : {}),
|
|
102
|
+
message:
|
|
103
|
+
code === "GUIDE_UNAVAILABLE"
|
|
104
|
+
? GUIDE_UNAVAILABLE
|
|
105
|
+
: !code && SETUP_CHECKS.every((name) => checks[name])
|
|
106
|
+
? "Totem setup complete; required checks verified."
|
|
107
|
+
: checks.identity
|
|
108
|
+
? "Connection verified; automatic receiving setup incomplete"
|
|
109
|
+
: "Setup incomplete",
|
|
110
|
+
...(host ? { host: host.name, model: host.model, sessionId: host.sessionId } : {}),
|
|
111
|
+
...(identity && checks.identity
|
|
112
|
+
? {
|
|
113
|
+
agentId: identity.id,
|
|
114
|
+
address: identity.address,
|
|
115
|
+
organizationId: identity.organization.id,
|
|
116
|
+
environment: identity.environment,
|
|
117
|
+
}
|
|
118
|
+
: {}),
|
|
119
|
+
...(transport ? { transport } : {}),
|
|
120
|
+
...(apiReason ? { apiReason } : {}),
|
|
121
|
+
...(receiver
|
|
122
|
+
? {
|
|
123
|
+
intervalSeconds: receiver.intervalSeconds,
|
|
124
|
+
measuredCheckSeconds: receiver.measuredCheckSeconds,
|
|
125
|
+
}
|
|
126
|
+
: {}),
|
|
127
|
+
...(checks.peerReply
|
|
128
|
+
? {
|
|
129
|
+
peerVerification: {
|
|
130
|
+
messageId: proofs.peer.messageId,
|
|
131
|
+
replyId: proofs.peer.replyId,
|
|
132
|
+
receivedAt: proofs.peer.receivedAt,
|
|
133
|
+
repliedAt: proofs.peer.repliedAt,
|
|
134
|
+
exactlyOneReply: true,
|
|
135
|
+
acknowledgedAfterReply: true,
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
: {}),
|
|
139
|
+
...(checks.ownerChat
|
|
140
|
+
? {
|
|
141
|
+
ownerChatVerification: {
|
|
142
|
+
commandId: proofs.ownerChat.commandId,
|
|
143
|
+
chatId: proofs.ownerChat.chatId,
|
|
144
|
+
eventId: proofs.ownerChat.eventId,
|
|
145
|
+
leaseRenewed: true,
|
|
146
|
+
completedInOriginalChat: true,
|
|
147
|
+
queuedAt: proofs.ownerChat.queuedAt,
|
|
148
|
+
completedAt: proofs.ownerChat.completedAt,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
checks: { ...checks },
|
|
153
|
+
remaining: SETUP_CHECKS.filter((name) => !checks[name]),
|
|
154
|
+
});
|
|
155
|
+
try {
|
|
156
|
+
// No host inspection, approval or setup mutation is permitted before a complete guide.
|
|
157
|
+
let guide;
|
|
158
|
+
for (const reader of ["primary", "alternate"]) {
|
|
159
|
+
try {
|
|
160
|
+
const value = await adapter.readGuide(reader);
|
|
161
|
+
if (
|
|
162
|
+
value?.complete === true &&
|
|
163
|
+
value.integrityVerified === true &&
|
|
164
|
+
/^[a-f0-9]{64}$/.test(value.sha256 ?? "") &&
|
|
165
|
+
typeof value.text === "string" &&
|
|
166
|
+
value.text.startsWith("# Set up Totem") &&
|
|
167
|
+
value.text.endsWith("<!-- totem-setup:end -->\n")
|
|
168
|
+
) {
|
|
169
|
+
guide = value;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
/* Try the independent supported reader before stopping. */
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!guide) return report("GUIDE_UNAVAILABLE");
|
|
177
|
+
checks.guide = true;
|
|
178
|
+
await progress("guide_verified");
|
|
179
|
+
operation = "inspectHost";
|
|
180
|
+
const inspected = await adapter.inspect();
|
|
181
|
+
const proposedHost = inspected.host;
|
|
182
|
+
if (
|
|
183
|
+
!token(proposedHost?.name) ||
|
|
184
|
+
!token(proposedHost.model) ||
|
|
185
|
+
proposedHost.model === "default" ||
|
|
186
|
+
/(?:tn_(?:live|test)_|Bearer|secret|token=)/i.test(proposedHost.model) ||
|
|
187
|
+
!token(proposedHost.sessionId) ||
|
|
188
|
+
!/^[a-f0-9]{64}$/.test(proposedHost.policyDigest ?? "") ||
|
|
189
|
+
proposedHost.modelVerified !== true
|
|
190
|
+
)
|
|
191
|
+
stop("CURRENT_MODEL_UNVERIFIED");
|
|
192
|
+
host = proposedHost;
|
|
193
|
+
checks.model = true;
|
|
194
|
+
if (inspected.policyDenied) stop("HOST_POLICY_DENIED");
|
|
195
|
+
if (inspected.identityConflict) stop("AGENT_IDENTITY_MISMATCH");
|
|
196
|
+
// Existing transport, identity, credential generation and intentional pauses win.
|
|
197
|
+
transport = inspected.connection?.transport;
|
|
198
|
+
if (!transport) {
|
|
199
|
+
if (inspected.ownerSelectedTransport === "api" && inspected.apiSupported === true) {
|
|
200
|
+
transport = "api";
|
|
201
|
+
apiReason = "The owner explicitly selected API for this host.";
|
|
202
|
+
} else if (inspected.customMcp === true) transport = "mcp";
|
|
203
|
+
else if (
|
|
204
|
+
inspected.customMcp === false &&
|
|
205
|
+
inspected.apiSupported === true &&
|
|
206
|
+
typeof inspected.missingMcpCapability === "string" &&
|
|
207
|
+
inspected.missingMcpCapability.trim()
|
|
208
|
+
) {
|
|
209
|
+
transport = "api";
|
|
210
|
+
apiReason = inspected.missingMcpCapability.slice(0, 500);
|
|
211
|
+
} else stop("HOST_MCP_CAPABILITY_UNVERIFIED");
|
|
212
|
+
}
|
|
213
|
+
if (!["mcp", "api"].includes(transport)) stop("TRANSPORT_UNSUPPORTED");
|
|
214
|
+
if (transport === "api" && !inspected.connection) {
|
|
215
|
+
let apiGuide;
|
|
216
|
+
for (const reader of ["primary", "alternate"]) {
|
|
217
|
+
try {
|
|
218
|
+
const value = await adapter.readApiGuide?.(reader);
|
|
219
|
+
if (
|
|
220
|
+
value?.complete === true &&
|
|
221
|
+
value.integrityVerified === true &&
|
|
222
|
+
/^[a-f0-9]{64}$/.test(value.sha256 ?? "") &&
|
|
223
|
+
value.text?.startsWith("# Connect an agent to the Totem API") &&
|
|
224
|
+
value.text.endsWith("<!-- totem-api-setup:end -->\n")
|
|
225
|
+
) {
|
|
226
|
+
apiGuide = value;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
} catch {}
|
|
230
|
+
}
|
|
231
|
+
if (!apiGuide) {
|
|
232
|
+
checks.guide = false;
|
|
233
|
+
stop("API_GUIDE_UNAVAILABLE");
|
|
234
|
+
}
|
|
235
|
+
const delivery = await adapter.explainApi(apiReason);
|
|
236
|
+
if (delivery?.ownerVisible !== true || delivery.deliveredBeforeRequest !== true)
|
|
237
|
+
stop("API_EXPLANATION_NOT_DELIVERED");
|
|
238
|
+
}
|
|
239
|
+
// A stopped connection is inspected read-only, without login, repair, recovery or tests.
|
|
240
|
+
const connection =
|
|
241
|
+
inspected.connection ?? (inspected.paused ? undefined : await adapter.connect(transport));
|
|
242
|
+
if (!connection) stop("CONNECTION_APPROVAL_REQUIRED");
|
|
243
|
+
identity = await adapter.identity(connection, transport);
|
|
244
|
+
const expected = inspected.connection?.identity ?? connection.identity;
|
|
245
|
+
if (
|
|
246
|
+
expected &&
|
|
247
|
+
(identity?.id !== expected.id ||
|
|
248
|
+
identity.environment !== expected.environment ||
|
|
249
|
+
(expected.organization?.id && identity.organization?.id !== expected.organization.id))
|
|
250
|
+
)
|
|
251
|
+
stop("AGENT_IDENTITY_MISMATCH");
|
|
252
|
+
if (options.expectedAgentId && identity?.id !== options.expectedAgentId)
|
|
253
|
+
stop("AGENT_IDENTITY_MISMATCH");
|
|
254
|
+
if (options.expectedEnvironment && identity?.environment !== options.expectedEnvironment)
|
|
255
|
+
stop("AGENT_IDENTITY_MISMATCH");
|
|
256
|
+
binding = setupBinding(identity, host, transport, connection);
|
|
257
|
+
checks.identity = true;
|
|
258
|
+
checks.transport =
|
|
259
|
+
transport === "mcp"
|
|
260
|
+
? connection.mcpIdentityVerified === true
|
|
261
|
+
: connection.apiIdentityVerified === true &&
|
|
262
|
+
connection.inboxVerified === true &&
|
|
263
|
+
connection.installationAcknowledged === true;
|
|
264
|
+
if (!checks.transport) stop("CONNECTION_VERIFICATION_INCOMPLETE");
|
|
265
|
+
if (inspected.paused) return report("RECEIVER_INTENTIONALLY_PAUSED");
|
|
266
|
+
await progress("identity_verified");
|
|
267
|
+
const context = Object.freeze({
|
|
268
|
+
identity,
|
|
269
|
+
host,
|
|
270
|
+
transport,
|
|
271
|
+
binding,
|
|
272
|
+
connectionFingerprint: connection.fingerprint,
|
|
273
|
+
guideSha256: guide.sha256,
|
|
274
|
+
});
|
|
275
|
+
operation = "configureReceiver";
|
|
276
|
+
await adapter.configureReceiver(context);
|
|
277
|
+
receiver = await adapter.readReceiver(context);
|
|
278
|
+
if (receiver?.binding !== binding || receiver.count !== 1 || receiver.sameConnection !== true)
|
|
279
|
+
stop("EXACT_RECEIVER_UNVERIFIED");
|
|
280
|
+
if (receiver.paused) return report("RECEIVER_INTENTIONALLY_PAUSED");
|
|
281
|
+
if (!Number.isFinite(receiver.intervalSeconds) || receiver.intervalSeconds <= 0)
|
|
282
|
+
stop("RECEIVER_INTERVAL_UNVERIFIED");
|
|
283
|
+
// A preserved slower interval or documented fallback remains installed and is reported honestly.
|
|
284
|
+
const operational =
|
|
285
|
+
receiver.running === true &&
|
|
286
|
+
Number.isFinite(receiver.measuredCheckSeconds) &&
|
|
287
|
+
receiver.measuredCheckSeconds > 0 &&
|
|
288
|
+
receiver.independentOfModel === true &&
|
|
289
|
+
receiver.silentWhenIdle === true &&
|
|
290
|
+
receiver.bothQueues === true &&
|
|
291
|
+
receiver.privateState === true;
|
|
292
|
+
checks.receiver = operational && receiver.intervalSeconds === 5;
|
|
293
|
+
checks.startup =
|
|
294
|
+
receiver.startupEnabled === true &&
|
|
295
|
+
receiver.restartOnFailure === true &&
|
|
296
|
+
receiver.persistent === true;
|
|
297
|
+
if (!sameHost(host, await adapter.readHost(context))) {
|
|
298
|
+
checks.model = false;
|
|
299
|
+
stop("CURRENT_MODEL_CHANGED");
|
|
300
|
+
}
|
|
301
|
+
if (!operational || !checks.startup)
|
|
302
|
+
return {
|
|
303
|
+
...report("RECEIVER_CAPABILITY_INCOMPLETE"),
|
|
304
|
+
intervalSeconds: receiver.intervalSeconds,
|
|
305
|
+
};
|
|
306
|
+
await progress("receiver_verified");
|
|
307
|
+
const recovery = await adapter.verifyRecovery(context);
|
|
308
|
+
checks.recovery =
|
|
309
|
+
recovery?.binding === binding &&
|
|
310
|
+
recovery.newRunVerified === true &&
|
|
311
|
+
recovery.savedStatePreserved === true &&
|
|
312
|
+
recovery.ownerPausePreserved === true &&
|
|
313
|
+
recovery.noDuplicateReceiver === true;
|
|
314
|
+
if (!checks.recovery) return report("RECOVERY_UNVERIFIED");
|
|
315
|
+
await progress("recovery_verified");
|
|
316
|
+
// This requests incoming tests from the owner. It never sends traffic to another agent.
|
|
317
|
+
await adapter.requestTests(context);
|
|
318
|
+
proofs = await adapter.readTests(context);
|
|
319
|
+
const peer = proofs?.peer,
|
|
320
|
+
chat = proofs?.ownerChat;
|
|
321
|
+
checks.nativeWake =
|
|
322
|
+
peer?.binding === binding &&
|
|
323
|
+
peer.nativeSessionId === host.sessionId &&
|
|
324
|
+
peer.newMessageTriggeredWake === true &&
|
|
325
|
+
peer.appearedInNativeChat === true;
|
|
326
|
+
checks.peerReply =
|
|
327
|
+
peer?.binding === binding &&
|
|
328
|
+
peer.nativeSessionId === host.sessionId &&
|
|
329
|
+
peer.appearedInNativeChat === true &&
|
|
330
|
+
uuid(peer.messageId) &&
|
|
331
|
+
uuid(peer.replyId) &&
|
|
332
|
+
peer.correlated === true &&
|
|
333
|
+
peer.exactlyOneReply === true &&
|
|
334
|
+
peer.acknowledgedAfterReply === true &&
|
|
335
|
+
peer.authorized === true &&
|
|
336
|
+
Number.isFinite(peer.receivedAt) &&
|
|
337
|
+
Number.isFinite(peer.repliedAt) &&
|
|
338
|
+
peer.repliedAt >= peer.receivedAt;
|
|
339
|
+
checks.ownerChat =
|
|
340
|
+
chat?.binding === binding &&
|
|
341
|
+
uuid(chat.commandId) &&
|
|
342
|
+
uuid(chat.chatId) &&
|
|
343
|
+
uuid(chat.eventId) &&
|
|
344
|
+
chat.claimed === true &&
|
|
345
|
+
chat.leaseRenewed === true &&
|
|
346
|
+
chat.completedInOriginalChat === true &&
|
|
347
|
+
chat.authorized === true &&
|
|
348
|
+
Number.isFinite(chat.queuedAt) &&
|
|
349
|
+
Number.isFinite(chat.completedAt) &&
|
|
350
|
+
chat.completedAt >= chat.queuedAt;
|
|
351
|
+
if (!sameHost(host, await adapter.readHost(context))) {
|
|
352
|
+
checks.model = false;
|
|
353
|
+
stop("CURRENT_MODEL_CHANGED");
|
|
354
|
+
}
|
|
355
|
+
await progress("tests_checked");
|
|
356
|
+
return report(
|
|
357
|
+
!checks.peerReply || !checks.ownerChat
|
|
358
|
+
? "AUTHORIZED_TESTS_PENDING"
|
|
359
|
+
: !checks.receiver
|
|
360
|
+
? "RECEIVER_INTERVAL_LIMITATION"
|
|
361
|
+
: !checks.nativeWake
|
|
362
|
+
? "NATIVE_WAKE_UNVERIFIED"
|
|
363
|
+
: undefined,
|
|
364
|
+
);
|
|
365
|
+
} catch (error) {
|
|
366
|
+
// Adapter error messages may contain private host diagnostics. Export only bounded codes.
|
|
367
|
+
const code = /^[A-Z][A-Z0-9_]{0,79}$/.test(error?.code ?? "")
|
|
368
|
+
? error.code
|
|
369
|
+
: "SETUP_ADAPTER_FAILED";
|
|
370
|
+
if (code === "HOST_POLICY_DENIED") {
|
|
371
|
+
const reason =
|
|
372
|
+
typeof error.publicReason === "string"
|
|
373
|
+
? error.publicReason
|
|
374
|
+
.slice(0, 1000)
|
|
375
|
+
.replace(/tn_(?:live|test)_[A-Za-z0-9_-]+|Bearer\s+\S+/gi, "[redacted]")
|
|
376
|
+
: "The host did not supply a public reason.";
|
|
377
|
+
return { ...report(code), deniedOperation: operation, statedReason: reason };
|
|
378
|
+
}
|
|
379
|
+
return report(code);
|
|
380
|
+
} finally {
|
|
381
|
+
await Promise.resolve()
|
|
382
|
+
.then(() => adapter.close?.())
|
|
383
|
+
.catch(() => {});
|
|
384
|
+
}
|
|
385
|
+
}
|
package/bin/totem.mjs
CHANGED
|
@@ -1754,6 +1754,11 @@ async function runRfq(options, baseUrl) {
|
|
|
1754
1754
|
}
|
|
1755
1755
|
|
|
1756
1756
|
async function main() {
|
|
1757
|
+
if (process.argv[2] === "install-worker") {
|
|
1758
|
+
const { strictSetupWorkerMain } = await import("./strict-setup-jobs.mjs");
|
|
1759
|
+
process.exitCode = await strictSetupWorkerMain(process.argv[3]);
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1757
1762
|
if (process.argv[2] === "update") {
|
|
1758
1763
|
const { runtimeUpdateMain } = await import("./managed-mcp.mjs");
|
|
1759
1764
|
await runtimeUpdateMain(process.argv.slice(3));
|
|
@@ -1769,7 +1774,12 @@ async function main() {
|
|
|
1769
1774
|
process.exitCode = await executorDiagnosticMain(process.argv.slice(3));
|
|
1770
1775
|
return;
|
|
1771
1776
|
}
|
|
1772
|
-
if (
|
|
1777
|
+
if (process.argv[2] === "install") {
|
|
1778
|
+
const { strictInstallationMain } = await import("./strict-installation.mjs");
|
|
1779
|
+
process.exitCode = await strictInstallationMain(process.argv.slice(3));
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
if (!process.argv[2] || process.argv[2] === "login") {
|
|
1773
1783
|
const { installationMain } = await import("./installation.mjs");
|
|
1774
1784
|
process.exitCode = await installationMain(process.argv.slice(3), {});
|
|
1775
1785
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "totemlayer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.74",
|
|
4
4
|
"description": "Cross-platform CLI for TotemLayer agent identity and authorization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
"registry": "https://registry.npmjs.org/"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/client": "2.3.0",
|
|
36
37
|
"@modelcontextprotocol/server": "2.3.0",
|
|
37
|
-
"undici": "7.30.
|
|
38
|
-
"zod": "4.
|
|
38
|
+
"undici": "7.30.1",
|
|
39
|
+
"zod": "4.6.6"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"postinstall": "node bin/installation.mjs --postinstall",
|
package/scripts/prepare.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { access, readdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { transform } from "esbuild";
|
|
3
3
|
import "./build-native.mjs";
|
|
4
4
|
import { generateNetworkContract } from "../../../scripts/generate-network-contract.mjs";
|
|
5
|
+
import "../../../scripts/build-strict-installer-guide.mjs";
|
|
5
6
|
await generateNetworkContract();
|
|
6
7
|
// This candidate rebases coordination on the immutable published 0.1.21 bundle.
|
|
7
8
|
// Its bundled SDK is the release source; do not rebuild it from an older sibling checkout.
|
|
@@ -18,6 +19,7 @@ for (const name of [
|
|
|
18
19
|
"runtime-diagnostics.mjs",
|
|
19
20
|
"codex-chat-bridge.mjs",
|
|
20
21
|
"codex-human-chat-bridge.mjs",
|
|
22
|
+
"codex-mission-bridge.mjs",
|
|
21
23
|
"chat-prompt-limit.mjs",
|
|
22
24
|
"worker-core/adapters.mjs",
|
|
23
25
|
"worker-core/errors.mjs",
|