mandala-computer-mcp 0.4.0 → 0.6.0

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.
Files changed (128) hide show
  1. package/README.md +558 -29
  2. package/dist/api.d.ts +59 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +404 -33
  5. package/dist/api.js.map +1 -1
  6. package/dist/artifacts.d.ts +63 -0
  7. package/dist/artifacts.d.ts.map +1 -0
  8. package/dist/artifacts.js +81 -0
  9. package/dist/artifacts.js.map +1 -0
  10. package/dist/cli.d.ts +4 -0
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +52 -21
  13. package/dist/cli.js.map +1 -1
  14. package/dist/credentials.d.ts +33 -0
  15. package/dist/credentials.d.ts.map +1 -0
  16. package/dist/credentials.js +395 -0
  17. package/dist/credentials.js.map +1 -0
  18. package/dist/errors.d.ts +122 -11
  19. package/dist/errors.d.ts.map +1 -1
  20. package/dist/errors.js +237 -41
  21. package/dist/errors.js.map +1 -1
  22. package/dist/executions.d.ts +43 -0
  23. package/dist/executions.d.ts.map +1 -0
  24. package/dist/executions.js +162 -0
  25. package/dist/executions.js.map +1 -0
  26. package/dist/format.d.ts +33 -8
  27. package/dist/format.d.ts.map +1 -1
  28. package/dist/format.js +107 -12
  29. package/dist/format.js.map +1 -1
  30. package/dist/http.d.ts +42 -0
  31. package/dist/http.d.ts.map +1 -1
  32. package/dist/http.js +383 -3
  33. package/dist/http.js.map +1 -1
  34. package/dist/index.d.ts +5 -4
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -3
  37. package/dist/index.js.map +1 -1
  38. package/dist/paths.d.ts +50 -2
  39. package/dist/paths.d.ts.map +1 -1
  40. package/dist/paths.js +65 -5
  41. package/dist/paths.js.map +1 -1
  42. package/dist/results.d.ts +97 -0
  43. package/dist/results.d.ts.map +1 -0
  44. package/dist/results.js +263 -0
  45. package/dist/results.js.map +1 -0
  46. package/dist/secret-errors.d.ts +59 -0
  47. package/dist/secret-errors.d.ts.map +1 -0
  48. package/dist/secret-errors.js +199 -0
  49. package/dist/secret-errors.js.map +1 -0
  50. package/dist/secret-store.d.ts +115 -0
  51. package/dist/secret-store.d.ts.map +1 -0
  52. package/dist/secret-store.js +105 -0
  53. package/dist/secret-store.js.map +1 -0
  54. package/dist/server.d.ts +3 -2
  55. package/dist/server.d.ts.map +1 -1
  56. package/dist/server.js +60 -9
  57. package/dist/server.js.map +1 -1
  58. package/dist/session.d.ts +6 -1
  59. package/dist/session.d.ts.map +1 -1
  60. package/dist/session.js +1 -1
  61. package/dist/session.js.map +1 -1
  62. package/dist/stdio.d.ts +5 -1
  63. package/dist/stdio.d.ts.map +1 -1
  64. package/dist/stdio.js +10 -4
  65. package/dist/stdio.js.map +1 -1
  66. package/dist/tool-filters.d.ts +38 -0
  67. package/dist/tool-filters.d.ts.map +1 -0
  68. package/dist/tool-filters.js +137 -0
  69. package/dist/tool-filters.js.map +1 -0
  70. package/dist/tools/account.d.ts +3 -0
  71. package/dist/tools/account.d.ts.map +1 -0
  72. package/dist/tools/account.js +122 -0
  73. package/dist/tools/account.js.map +1 -0
  74. package/dist/tools/activities.d.ts +3 -0
  75. package/dist/tools/activities.d.ts.map +1 -0
  76. package/dist/tools/activities.js +140 -0
  77. package/dist/tools/activities.js.map +1 -0
  78. package/dist/tools/agent.d.ts.map +1 -1
  79. package/dist/tools/agent.js +21 -9
  80. package/dist/tools/agent.js.map +1 -1
  81. package/dist/tools/artifacts.d.ts +3 -0
  82. package/dist/tools/artifacts.d.ts.map +1 -0
  83. package/dist/tools/artifacts.js +97 -0
  84. package/dist/tools/artifacts.js.map +1 -0
  85. package/dist/tools/chat.d.ts +6 -0
  86. package/dist/tools/chat.d.ts.map +1 -0
  87. package/dist/tools/chat.js +192 -0
  88. package/dist/tools/chat.js.map +1 -0
  89. package/dist/tools/computers.d.ts.map +1 -1
  90. package/dist/tools/computers.js +28 -16
  91. package/dist/tools/computers.js.map +1 -1
  92. package/dist/tools/directory.d.ts +13 -0
  93. package/dist/tools/directory.d.ts.map +1 -0
  94. package/dist/tools/directory.js +88 -0
  95. package/dist/tools/directory.js.map +1 -0
  96. package/dist/tools/executions.d.ts +3 -0
  97. package/dist/tools/executions.d.ts.map +1 -0
  98. package/dist/tools/executions.js +87 -0
  99. package/dist/tools/executions.js.map +1 -0
  100. package/dist/tools/guest.d.ts.map +1 -1
  101. package/dist/tools/guest.js +184 -35
  102. package/dist/tools/guest.js.map +1 -1
  103. package/dist/tools/input.d.ts +2 -0
  104. package/dist/tools/input.d.ts.map +1 -1
  105. package/dist/tools/input.js +31 -5
  106. package/dist/tools/input.js.map +1 -1
  107. package/dist/tools/results.d.ts +30 -0
  108. package/dist/tools/results.d.ts.map +1 -0
  109. package/dist/tools/results.js +106 -0
  110. package/dist/tools/results.js.map +1 -0
  111. package/dist/tools/secrets.d.ts +78 -0
  112. package/dist/tools/secrets.d.ts.map +1 -0
  113. package/dist/tools/secrets.js +448 -0
  114. package/dist/tools/secrets.js.map +1 -0
  115. package/dist/tools/signals.d.ts +3 -0
  116. package/dist/tools/signals.d.ts.map +1 -0
  117. package/dist/tools/signals.js +116 -0
  118. package/dist/tools/signals.js.map +1 -0
  119. package/dist/tools/snapshots.d.ts.map +1 -1
  120. package/dist/tools/snapshots.js +52 -10
  121. package/dist/tools/snapshots.js.map +1 -1
  122. package/dist/tools/ssh.d.ts +3 -0
  123. package/dist/tools/ssh.d.ts.map +1 -0
  124. package/dist/tools/ssh.js +186 -0
  125. package/dist/tools/ssh.js.map +1 -0
  126. package/dist/tools/webhooks.js +1 -1
  127. package/dist/tools/webhooks.js.map +1 -1
  128. package/package.json +1 -1
@@ -0,0 +1,448 @@
1
+ import { z } from 'zod';
2
+ import { APIError, MandalaError, NotFoundError, statusAdvice } from '../errors.js';
3
+ import { guarded, refused, said, unavailableAdvice } from '../format.js';
4
+ import * as P from '../paths.js';
5
+ import { DOCUMENTED_REASONS, isRequestId, overlaps, } from '../secret-store.js';
6
+ /**
7
+ * Secrets: the account's store of named values, and which of them each
8
+ * computer is bound to.
9
+ *
10
+ * The BINDINGS (get/set_computer_secrets) carry only ids, revision ids, env
11
+ * names and file names — no value crosses those routes in either direction.
12
+ *
13
+ * The STORE (list/get/create/replace/delete_secret) is where a value goes in,
14
+ * and only in: the platform never answers one, the decoded answers here carry
15
+ * none, and a tool that took a value never repeats it — not in a success, not
16
+ * in a refusal. See {@link withoutValue}.
17
+ *
18
+ * A change of bindings takes effect at the computer's NEXT START OR RESTART. A
19
+ * running computer keeps what it booted with until then, and a suspended one
20
+ * resumes with its old values; the sentences below say so every time, because a
21
+ * model that reads "saved" as "delivered" goes on to use a credential the guest
22
+ * does not have yet. What reaches a running computer sooner is a replaced VALUE:
23
+ * a file binding's file is rewritten in place, and on an image that supports it
24
+ * an env binding's new value reaches new shells and desktop-session commands.
25
+ */
26
+ /** Where a file binding is published in the guest. */
27
+ export const FILES_DIR = '/run/mandala-secrets/user/files';
28
+ /** At most this many secrets per computer, and this many of them as files. */
29
+ export const SECRET_BINDINGS_MAX = 32;
30
+ export const SECRET_FILES_MAX = 8;
31
+ const SECRET_ENV = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
32
+ const SECRET_FILE = /^[a-z][a-z0-9_-]{0,47}$/;
33
+ const ENV_RULE = 'letters, digits and underscores, not starting with a digit, at most 64 characters';
34
+ const FILE_RULE = 'lowercase letters, digits, - and _, starting with a letter, at most 48 characters';
35
+ /** An id as the platform spells one: not empty, and nothing around it. */
36
+ const isId = (v) => typeof v === 'string' && v !== '' && v.trim() === v;
37
+ const idString = (what) => z.string().refine(isId, `${what} must not be empty or have spaces around it`);
38
+ /**
39
+ * A binding list as the platform takes it, checked here for what it would
40
+ * refuse anyway — so the mistake is named against the entry that made it
41
+ * rather than coming back as a 400. `revision` adds the optional `revision_id`
42
+ * a rebind may send; a create has nothing to keep and takes none.
43
+ */
44
+ export function secretBindingsSchema(revision) {
45
+ // Strict: a key this tool does not take is refused, not dropped. A create
46
+ // that carried a `revision_id` would otherwise validate, bind the latest, and
47
+ // leave the caller believing it had chosen a revision.
48
+ const entry = z.strictObject({
49
+ secret_id: idString('secret_id').describe('The secret to bind — `csec-` and sixteen hex.'),
50
+ env: z
51
+ .string()
52
+ .regex(SECRET_ENV, `env must be ${ENV_RULE}`)
53
+ .optional()
54
+ .describe(`Deliver it as this environment variable in the desktop session: ${ENV_RULE}. Exactly one of env and file.`),
55
+ file: z
56
+ .string()
57
+ .regex(SECRET_FILE, `file must be ${FILE_RULE}`)
58
+ .optional()
59
+ .describe(`Deliver it as the file ${FILES_DIR}/<file>, for a program that reads a path (a kubeconfig, a key): ${FILE_RULE}. May hold any bytes. Exactly one of env and file.`),
60
+ ...(revision
61
+ ? {
62
+ revision_id: idString('revision_id')
63
+ .optional()
64
+ .describe('Omit to record the latest revision. Name the one the computer holds now to keep it: a revision is what the computer last received, not a pin, and every start or restart delivers the latest value regardless.'),
65
+ }
66
+ : {}),
67
+ });
68
+ return z
69
+ .array(entry)
70
+ .max(SECRET_BINDINGS_MAX, `at most ${SECRET_BINDINGS_MAX} secrets per computer`)
71
+ .superRefine((list, ctx) => {
72
+ const ids = new Set();
73
+ const envs = new Set();
74
+ const files = new Set();
75
+ list.forEach((b, i) => {
76
+ const at = (message) => ctx.addIssue({ code: 'custom', path: [i], message });
77
+ if ((b.env === undefined) === (b.file === undefined)) {
78
+ at(`secrets[${i}] must name exactly one of env and file`);
79
+ }
80
+ if (ids.has(b.secret_id))
81
+ at(`secrets[${i}]: ${b.secret_id} is bound twice`);
82
+ ids.add(b.secret_id);
83
+ // Two namespaces: a variable and a file may share a spelling.
84
+ if (b.env !== undefined) {
85
+ if (envs.has(b.env))
86
+ at(`secrets[${i}].env ${b.env} is bound twice`);
87
+ envs.add(b.env);
88
+ }
89
+ if (b.file !== undefined) {
90
+ if (files.has(b.file))
91
+ at(`secrets[${i}].file ${b.file} is bound twice`);
92
+ files.add(b.file);
93
+ }
94
+ });
95
+ if (files.size > SECRET_FILES_MAX) {
96
+ ctx.addIssue({ code: 'custom', message: `at most ${SECRET_FILES_MAX} secrets as files` });
97
+ }
98
+ });
99
+ }
100
+ const idArg = {
101
+ computer_id: z
102
+ .string()
103
+ .optional()
104
+ .describe('Which computer. Defaults to the one selected with use_computer.'),
105
+ };
106
+ const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
107
+ const shapeOf = (v) => v === undefined ? 'no body at all' : v === null ? 'null' : Array.isArray(v) ? 'a list' : typeof v;
108
+ function bindingsOf(body) {
109
+ if (!isRecord(body))
110
+ return undefined;
111
+ const { secrets, version } = body;
112
+ if (!Array.isArray(secrets))
113
+ return undefined;
114
+ if (typeof version !== 'number' || !Number.isSafeInteger(version) || version < 0)
115
+ return undefined;
116
+ const out = [];
117
+ for (const entry of secrets) {
118
+ if (!isRecord(entry))
119
+ return undefined;
120
+ const { secret_id, revision_id, env, file } = entry;
121
+ if (!isId(secret_id) || !isId(revision_id))
122
+ return undefined;
123
+ // Exactly one, spelled as the platform would accept it. Null reads as
124
+ // absent; anything else present — an empty string included — counts, so a
125
+ // row naming both or neither is refused rather than guessed at.
126
+ const hasEnv = env !== undefined && env !== null;
127
+ const hasFile = file !== undefined && file !== null;
128
+ if (hasEnv === hasFile)
129
+ return undefined;
130
+ if (hasEnv) {
131
+ if (typeof env !== 'string' || !SECRET_ENV.test(env))
132
+ return undefined;
133
+ out.push({ secret_id, revision_id, env });
134
+ }
135
+ else {
136
+ if (typeof file !== 'string' || !SECRET_FILE.test(file))
137
+ return undefined;
138
+ out.push({ secret_id, revision_id, file });
139
+ }
140
+ }
141
+ return { secrets: out, version };
142
+ }
143
+ /**
144
+ * One binding in a line: where the guest finds it — a variable name, or a file's
145
+ * full path — then what it is bound to.
146
+ */
147
+ const bindingLine = (b) => `${b.env ?? `${FILES_DIR}/${b.file}`} = ${b.secret_id} @ ${b.revision_id}`;
148
+ const LEGEND = 'variable or file = secret @ revision, values never shown';
149
+ /** The bindings, one per line. Callers say "none" themselves for an empty list. */
150
+ function listing(b) {
151
+ return `\n${b.secrets.map(bindingLine).join('\n')}`;
152
+ }
153
+ const TIMING = 'The new bindings reach the guest at its NEXT START OR RESTART: a running computer keeps what it booted with until then, and a suspended one resumes with its old values.';
154
+ /**
155
+ * What reaches a running computer without a restart: a replaced VALUE.
156
+ *
157
+ * Worded to hold whichever way the platform answers a plain exec. Today a plain
158
+ * exec runs as root and is never given bound secrets; platform work under way
159
+ * (OPL-5028) gives it the bound environment too. `desktop: true` sees them
160
+ * either way, so that is the instruction, and the plain-exec case is stated as
161
+ * something not to rely on rather than as a fact that is about to change.
162
+ */
163
+ const LIVE_VALUES = "Every start and restart delivers each secret's latest value. Separately, when a secret's value is replaced on a running computer: a secret bound as a FILE has that file rewritten in place within seconds; one bound as an ENVIRONMENT VARIABLE, on an image that supports it, reaches new shells and exec commands run with desktop: true within seconds, while programs already running — the desktop session among them — keep the value they started with until a restart (older images wait for the restart). A command that needs a bound secret should run with desktop: true; do not rely on a plain exec seeing it. A file newly bound or renamed waits for the restart either way.";
164
+ /** A secret in a line: what a model recognises it by, and the revision a change needs. Never a value. */
165
+ const secretLine = (s) => `${s.name} ${s.id} revision ${s.revision_id} ${s.workspace_id === null ? 'account-wide' : `workspace ${s.workspace_id}`} ${s.last_used_at === null ? 'never delivered' : `last delivered ${s.last_used_at}`}`;
166
+ const STORE_LEGEND = 'name id revision scope last delivery; values are never shown';
167
+ /** The byte length of a value as the platform counts it: UTF-8. */
168
+ const utf8Bytes = (s) => new TextEncoder().encode(s).length;
169
+ /** The published ceiling on a value, in bytes of UTF-8. */
170
+ export const SECRET_VALUE_MAX_BYTES = 4096;
171
+ /** The published ceiling on a name, in characters. */
172
+ export const SECRET_NAME_MAX_CHARS = 60;
173
+ /**
174
+ * A secret value as a tool argument.
175
+ *
176
+ * Checked here for what the platform would refuse anyway, with messages that
177
+ * name the rule and never the value: a validation failure is shown to the model,
178
+ * and the whole point of this argument is that it is not shown to anyone.
179
+ */
180
+ const valueArg = (what) => z
181
+ .string()
182
+ .refine((v) => {
183
+ const n = utf8Bytes(v);
184
+ return n >= 1 && n <= SECRET_VALUE_MAX_BYTES;
185
+ }, { message: `value must be 1 to ${SECRET_VALUE_MAX_BYTES} bytes of UTF-8` })
186
+ .describe(`${what}, as text: 1 to ${SECRET_VALUE_MAX_BYTES} bytes of UTF-8. Sent to the platform once, encrypted there, and never shown again — not in this tool's answer, not by any other tool, not by any route.`);
187
+ const secretIdArg = idString('secret_id').describe('The secret — `csec-` and sixteen hex characters, from list_secrets.');
188
+ const workspaceArg = z
189
+ .string()
190
+ .refine(isId, 'workspace_id must not be empty or have spaces around it')
191
+ .optional()
192
+ .describe('The workspace the secret belongs to. Leave it out for an account-wide secret. A secret in a workspace is found only with its workspace_id.');
193
+ const revisionArg = (use) => idString('revision_id').describe(`The \`revision_id\` list_secrets or get_secret answered for this secret — \`csr-\` and twenty-four hex characters. ${use}`);
194
+ /**
195
+ * A tool result with every occurrence of a value taken out.
196
+ *
197
+ * The SECOND layer. The first is that no secret-store tool puts response text
198
+ * in its answer at all — see {@link storeGuarded} — and the Api keeps none for
199
+ * those routes. This catches what the first could still let through: a value
200
+ * that happens to equal a decoded field, or a message this server did not
201
+ * write. No length exemption: a one-character value is searched for too,
202
+ * which can mangle the sentence and is the price of never showing it. The
203
+ * JSON-escaped spelling is searched for as well, since data is shown as JSON.
204
+ */
205
+ export function withoutValue(result, value) {
206
+ if (value === '')
207
+ return result;
208
+ const spellings = [...new Set([value, JSON.stringify(value).slice(1, -1)])].filter(Boolean);
209
+ return {
210
+ ...result,
211
+ content: result.content.map((c) => c.type === 'text'
212
+ ? {
213
+ ...c,
214
+ text: spellings.reduce((t, v) => t.split(v).join('[secret value withheld]'), c.text),
215
+ }
216
+ : c),
217
+ };
218
+ }
219
+ /** This server's own sentence for a store refusal, by status. Never the platform's. */
220
+ function storeAdvice(err, change) {
221
+ const unavailable = unavailableAdvice(err);
222
+ if (unavailable)
223
+ return unavailable;
224
+ const status = statusAdvice(err.status, err.reason);
225
+ if (status)
226
+ return status;
227
+ switch (err.status) {
228
+ case 400:
229
+ return 'the request was refused as invalid: a name or value outside the documented limits, a malformed id or revision_id, or the store\u2019s limit on secrets held or created (list_secrets reports both). Sending it again unchanged is refused the same way';
230
+ case 404:
231
+ return 'no such secret in this scope. A secret in a workspace is found only with its workspace_id; list_secrets says which exist';
232
+ case 409:
233
+ return change
234
+ ? 'refused as a conflict and nothing changed: for a create, the name is taken in that scope; for a replace or delete, the revision_id is no longer the current one — get_secret for the current one, and send it again only if you still mean to'
235
+ : 'refused as a conflict';
236
+ case 429:
237
+ return `too many requests${err.retryAfterMs === undefined ? '' : `; wait ${Math.ceil(err.retryAfterMs / 1000)}s`} before sending it again`;
238
+ default:
239
+ return change
240
+ ? 'the platform did not complete this, and whether the change was made is not known. Read the secret back with list_secrets or get_secret before sending it again'
241
+ : 'the platform did not answer this; it can be asked again shortly';
242
+ }
243
+ }
244
+ /**
245
+ * Run a secret-store tool, answering a failure only in this server's words.
246
+ *
247
+ * `failed` shows the platform's own sentence, which is right almost everywhere
248
+ * and wrong here: a request that carried a value is the one whose refusal
249
+ * could quote it back. So a refusal is reported as the status, the reason word
250
+ * when it is a word, the request id, and a fixed sentence — and the result,
251
+ * success or failure, goes through {@link withoutValue} as well.
252
+ */
253
+ async function storeGuarded(what, change, value, fn) {
254
+ let result;
255
+ try {
256
+ result = await fn();
257
+ }
258
+ catch (err) {
259
+ if (err instanceof APIError) {
260
+ // Exactly a documented word, and exactly a platform-minted id — and
261
+ // neither if it shares four characters with the value sent. Nothing else
262
+ // from the refusal is interpolated.
263
+ const safe = (v) => value === undefined || !overlaps(v, value);
264
+ const reason = err.reason !== undefined && DOCUMENTED_REASONS.has(err.reason) && safe(err.reason)
265
+ ? `, reason "${err.reason}"`
266
+ : '';
267
+ const id = isRequestId(err.requestId) && safe(err.requestId) ? ` Request id ${err.requestId}.` : '';
268
+ result = refused(`${what} was refused (HTTP ${err.status}${reason}): ${storeAdvice(err, change)}. The platform\u2019s own message is not shown, because a refusal of a secret-store request could quote the value.${id}`);
269
+ }
270
+ else if (err instanceof MandalaError) {
271
+ // Written by this package, and for these routes never carrying response
272
+ // text: a transport failure, a cancellation, or a malformed answer.
273
+ result = refused(`${what} failed: ${err.message}`);
274
+ }
275
+ else {
276
+ result = refused(`${what} failed inside this server before an answer could be read.`);
277
+ }
278
+ }
279
+ return value === undefined ? result : withoutValue(result, value);
280
+ }
281
+ export const registerSecrets = (server, session) => {
282
+ server.registerTool('get_computer_secrets', {
283
+ title: "Read a computer's secret bindings",
284
+ description: `Which of the account's secrets a computer is bound to: for each, the secret id, the revision last delivered, and where the guest finds it — an environment variable name, or a file under ${FILES_DIR}. Values are NEVER shown — no value crosses this route. Also answers \`version\`, the number to send to set_computer_secrets so it changes only this list (0 for a computer never bound). Any role may read it. The list is what the computer receives at its next start or restart, which a running computer may not have yet. ${LIVE_VALUES}`,
285
+ inputSchema: idArg,
286
+ annotations: { readOnlyHint: true },
287
+ }, ({ computer_id }, extra) => guarded(async () => {
288
+ const id = session.resolve(computer_id);
289
+ const body = await session.api
290
+ .with(extra.signal)
291
+ .json('GET', P.computerAction(id, 'secrets'));
292
+ const bindings = bindingsOf(body);
293
+ if (!bindings) {
294
+ return refused(`GET /computers/${id}/secrets answered with ${shapeOf(body)}, not a list of secret bindings. This does not mean the computer has none.`, body);
295
+ }
296
+ if (!bindings.secrets.length) {
297
+ return said(`${id} is bound to no secrets (version ${bindings.version}). set_computer_secrets binds some.`, body);
298
+ }
299
+ const n = bindings.secrets.length;
300
+ return said(`${id} is bound to ${n} secret${n === 1 ? '' : 's'} (version ${bindings.version}; ${LEGEND}):${listing(bindings)}`, body);
301
+ }));
302
+ server.registerTool('set_computer_secrets', {
303
+ title: "Replace a computer's secret bindings",
304
+ description: `Replace the WHOLE list of secrets a computer is bound to — not a merge: any binding left out is removed, and \`secrets: []\` removes every binding. Each entry names a secret id and exactly one of \`env\` (the environment variable it is delivered under) or \`file\` (delivered as ${FILES_DIR}/<file>) — at most ${SECRET_BINDINGS_MAX} secrets, ${SECRET_FILES_MAX} of them as files, none twice and no variable or file name twice — and is recorded at that secret's latest revision unless it names \`revision_id\`, which must be the revision the computer holds now (any other revision is refused). A binding's revision is what the computer last received, never a pin: naming it only says this change keeps the value the running computer already has, so the change does not stop it being suspended. Only ids, revisions and names are sent and answered — values are NEVER shown or set here. ${TIMING} ${LIVE_VALUES} Binding a computer that has NO secrets yet requires it to be STOPPED: that first binding is refused with 409 while the computer is running or suspended, because a computer started without secrets cannot receive them until it starts again, and a restart does not do that. Start it afterwards to deliver them. Send \`version\` from get_computer_secrets to change only the list you read: if it changed since, this is refused with 409 and nothing changes. Also 409 while a delivery to the computer is in progress. After a change that drops a secret or moves one to another revision, a running computer cannot be suspended or memory-snapshotted until it restarts. Owners and members only; Linux computers only, and binding one for the first time needs a template whose image can receive secrets.`,
305
+ inputSchema: {
306
+ ...idArg,
307
+ secrets: secretBindingsSchema(true).describe('The complete new list. Every binding not in it is removed; [] removes them all.'),
308
+ version: z
309
+ .number()
310
+ .int()
311
+ .nonnegative()
312
+ .optional()
313
+ .describe('The `version` a read answered. Sent, the change is refused (409) if the list changed since; omitted, it replaces whatever is there.'),
314
+ },
315
+ annotations: { destructiveHint: true },
316
+ }, ({ computer_id, secrets, version }, extra) => guarded(async () => {
317
+ const id = session.resolve(computer_id);
318
+ const body = await session.api
319
+ .with(extra.signal)
320
+ .json('PUT', P.computerAction(id, 'secrets'), {
321
+ body: { secrets, ...(version === undefined ? {} : { version }) },
322
+ });
323
+ const bindings = bindingsOf(body);
324
+ if (!bindings) {
325
+ return refused(`PUT /computers/${id}/secrets answered with ${shapeOf(body)}, not a list of secret bindings. THE CHANGE MAY HAVE BEEN MADE — get_computer_secrets says what the computer is bound to now.`, body);
326
+ }
327
+ const n = bindings.secrets.length;
328
+ const what = n
329
+ ? `${id} is now bound to ${n} secret${n === 1 ? '' : 's'} (version ${bindings.version}; ${LEGEND}):${listing(bindings)}`
330
+ : `${id} is now bound to no secrets (version ${bindings.version}).`;
331
+ return said(`${what}\n${TIMING} ${LIVE_VALUES}`, body);
332
+ }));
333
+ // --- the store --------------------------------------------------------
334
+ //
335
+ // Which tools, and why (OPL-5026):
336
+ //
337
+ // - list_secrets and get_secret: yes. Names, ids and revisions are what a
338
+ // binding and every change need, and no value is ever in them.
339
+ // - create_secret and replace_secret: yes. An agent that sets a computer up
340
+ // for a task is the caller that has the credential to put in, and the
341
+ // alternative is asking a person to paste it into Settings. The value is an
342
+ // argument and goes one way: no answer repeats it.
343
+ // - delete_secret: yes, behind `confirm: true` and a description that says
344
+ // what it breaks — a computer still bound to a deleted secret cannot start —
345
+ // because cleaning up what a task created is part of the task.
346
+ server.registerTool('list_secrets', {
347
+ title: "List the account's secrets",
348
+ description: "The secrets stored on this account, in one scope: the account-wide ones by default, or one workspace's with workspace_id. For each: its name, its id (what set_computer_secrets binds), its current revision_id (what replace_secret and delete_secret need), its scope and when it was last delivered to a computer. Values are NEVER shown — no route returns one. Also says whether binding secrets to computers is switched on here, and the store's limits. Owners and members may read; a viewer is refused. An API key confined to a workspace lists that workspace's secrets, and naming another scope is refused.",
349
+ inputSchema: {
350
+ workspace_id: workspaceArg.describe('The workspace to list. Leave it out for the account-wide secrets.'),
351
+ },
352
+ annotations: { readOnlyHint: true },
353
+ }, ({ workspace_id }, extra) => storeGuarded('Listing the secrets', false, undefined, async () => {
354
+ const list = await session.api
355
+ .with(extra.signal)
356
+ .secrets.list({ workspaceId: workspace_id });
357
+ const scope = workspace_id === undefined ? 'account-wide' : `in workspace ${workspace_id}`;
358
+ const delivery = list.delivery
359
+ ? 'Binding secrets to computers is on.'
360
+ : 'Binding secrets to computers is OFF on this platform: secrets can be stored, but set_computer_secrets and a create carrying secrets are refused.';
361
+ const { limits } = list;
362
+ const limitLine = `Limits: names up to ${limits.name_max_chars} characters, values up to ${limits.value_max_bytes} bytes; at most ${limits.active_per_account} secrets held at once across the account (deleting frees a place) and ${limits.created_per_account} created over its lifetime (deleting does not).`;
363
+ const n = list.secrets.length;
364
+ const head = n
365
+ ? `${n} secret${n === 1 ? '' : 's'} ${scope} (${STORE_LEGEND}):\n${list.secrets.map(secretLine).join('\n')}`
366
+ : `No secrets ${scope}. create_secret stores one.`;
367
+ return said(`${head}\n${delivery} ${limitLine}`, list);
368
+ }));
369
+ server.registerTool('get_secret', {
370
+ title: 'Read one secret',
371
+ description: "One secret's name, scope, current revision_id and when it was last delivered — never its value. Read it for the current revision_id after replace_secret or delete_secret is refused because the revision moved. A secret in a workspace is found only with its workspace_id; otherwise it is not found.",
372
+ inputSchema: { secret_id: secretIdArg, workspace_id: workspaceArg },
373
+ annotations: { readOnlyHint: true },
374
+ }, ({ secret_id, workspace_id }, extra) => storeGuarded(`Reading ${secret_id}`, false, undefined, async () => {
375
+ const secret = await session.api
376
+ .with(extra.signal)
377
+ .secrets.get(secret_id, { workspaceId: workspace_id });
378
+ return said(`${secretLine(secret)} (values are never shown)`, secret);
379
+ }));
380
+ server.registerTool('create_secret', {
381
+ title: 'Store a new secret',
382
+ description: `Store a value under a name on this account, encrypted, for binding to computers with set_computer_secrets (or the secrets field of a create). The value is sent once and NEVER shown again: this answer, every other tool and every route give back only the name, id and revision. Do not put the value anywhere else — not in a command line, a file or a message — when a binding can deliver it. Owners only. A name is unique within its scope (up to ${SECRET_NAME_MAX_CHARS} characters, no control characters); a taken name is refused with 409. The account holds at most 100 secrets at once and may create at most 1000 over its lifetime — list_secrets reports both. Without workspace_id the secret is account-wide and any computer on the account may be bound to it. NOT safe to repeat blind: if the answer is lost, list_secrets before creating again, since the secret may exist.`,
383
+ inputSchema: {
384
+ name: z
385
+ .string()
386
+ .min(1, 'name must not be empty')
387
+ .refine((v) => [...v].length <= SECRET_NAME_MAX_CHARS, {
388
+ message: `name must be at most ${SECRET_NAME_MAX_CHARS} characters`,
389
+ })
390
+ .refine((v) => !/\p{Cc}/u.test(v), {
391
+ message: 'name must not contain control characters',
392
+ })
393
+ .describe(`What the secret is called, e.g. OPENAI_API_KEY. Up to ${SECRET_NAME_MAX_CHARS} characters, unique in its scope. This is a label, not where the value lands: set_computer_secrets names the variable or file.`),
394
+ value: valueArg('The value'),
395
+ workspace_id: workspaceArg.describe('The workspace it belongs to. Leave it out for an account-wide secret.'),
396
+ },
397
+ annotations: { destructiveHint: false, idempotentHint: false },
398
+ }, ({ name, value, workspace_id }, extra) => storeGuarded('Storing the secret', true, value, async () => {
399
+ const secret = await session.api
400
+ .with(extra.signal)
401
+ .secrets.create({ name, value, workspaceId: workspace_id });
402
+ return said(`Stored ${secret.name} as ${secret.id}, revision ${secret.revision_id}, ${secret.workspace_id === null ? 'account-wide' : `in workspace ${secret.workspace_id}`}. The value is not shown and cannot be read back. Bind it to a computer with set_computer_secrets.`, secret);
403
+ }));
404
+ server.registerTool('replace_secret', {
405
+ title: "Replace a secret's value",
406
+ description: `Replace a stored secret's value, and move its revision_id. Send the revision_id list_secrets or get_secret answered: if it has moved since, this is refused with 409 and nothing changed — read it again, and replace again only if you still mean to. The new value is NEVER shown back. Owners only. ${LIVE_VALUES} That live send is asynchronous and best effort: this answer does not wait for it or say whether it landed, and a running computer may still hold the old value until its next start or restart, which always delivers the latest. get_computer's secrets_pending says whether one is still missing the change.`,
407
+ inputSchema: {
408
+ secret_id: secretIdArg,
409
+ value: valueArg('The new value'),
410
+ revision_id: revisionArg('A stale one is refused and nothing changes.'),
411
+ workspace_id: workspaceArg,
412
+ },
413
+ annotations: { destructiveHint: true, idempotentHint: false },
414
+ }, ({ secret_id, value, revision_id, workspace_id }, extra) => storeGuarded(`Replacing the value of ${secret_id}`, true, value, async () => {
415
+ const secret = await session.api.with(extra.signal).secrets.replace(secret_id, {
416
+ value,
417
+ revisionId: revision_id,
418
+ workspaceId: workspace_id,
419
+ });
420
+ return said(`Replaced the value of ${secret.name} (${secret.id}); it is now at revision ${secret.revision_id}. The value is not shown. Computers bound to it get it at their next start or restart, and a running one is sent it now on a best-effort basis.`, secret);
421
+ }));
422
+ server.registerTool('delete_secret', {
423
+ title: 'Delete a secret',
424
+ description: "Permanently delete a stored secret. This cannot be undone, and it is NOT refused while computers are bound to it: such a computer keeps the value it already holds, but can never be given its secrets again — its next start is refused (409), a restart or a reboot inside it stops it, and a suspended one cannot resume. Remove the binding with set_computer_secrets first (or on the stopped computer afterwards) so it can start. Deleting does not recall a value already delivered. Needs the current revision_id (a stale one is refused and nothing is deleted) and confirm: true. Owners only. Deleting frees a place under the account's limit on secrets held at once, but not under its lifetime limit on secrets created.",
425
+ inputSchema: {
426
+ secret_id: secretIdArg,
427
+ revision_id: revisionArg('Required; a stale one is refused and nothing is deleted.'),
428
+ workspace_id: workspaceArg,
429
+ confirm: z
430
+ .literal(true)
431
+ .describe('Must be true. A computer still bound to this secret cannot start again until that binding is removed.'),
432
+ },
433
+ annotations: { destructiveHint: true, idempotentHint: true },
434
+ }, ({ secret_id, revision_id, workspace_id }, extra) => storeGuarded(`Deleting ${secret_id}`, true, undefined, async () => {
435
+ try {
436
+ await session.api
437
+ .with(extra.signal)
438
+ .secrets.delete(secret_id, { revisionId: revision_id, workspaceId: workspace_id });
439
+ }
440
+ catch (err) {
441
+ if (!(err instanceof NotFoundError))
442
+ throw err;
443
+ return refused(`Nothing was deleted: no secret ${secret_id} was found${workspace_id === undefined ? ' among the account-wide secrets' : ` in workspace ${workspace_id}`}. Either it was already deleted, or it is in a scope this did not name — list_secrets says which.`);
444
+ }
445
+ return said(`Deleted ${secret_id}. Any computer still bound to it cannot start again until set_computer_secrets removes that binding.`);
446
+ }));
447
+ };
448
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/tools/secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Registrar } from './types.js';
2
+ export declare const registerSignals: Registrar;
3
+ //# sourceMappingURL=signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/tools/signals.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0E5C,eAAO,MAAM,eAAe,EAAE,SAqD7B,CAAC"}
@@ -0,0 +1,116 @@
1
+ import { z } from 'zod';
2
+ import { said } from '../format.js';
3
+ import * as P from '../paths.js';
4
+ import { count, executionId, exitCode, label, metadata, metadataCall } from './directory.js';
5
+ import { computerSchema, readAnnotations } from './results.js';
6
+ const position = {
7
+ seq: count,
8
+ cursor: label,
9
+ at: label,
10
+ computer: label,
11
+ source: z.literal('daemon'),
12
+ };
13
+ const status = z.enum([
14
+ 'running',
15
+ 'stopped',
16
+ 'suspended',
17
+ 'building',
18
+ 'build-failed',
19
+ 'half-removed',
20
+ ]);
21
+ const processData = z.union([
22
+ z.object({
23
+ pid: count.min(1).max(2147483647),
24
+ execution_id: executionId.optional(),
25
+ exit_code: exitCode,
26
+ lost: z.never().optional(),
27
+ }),
28
+ z.object({
29
+ pid: count.min(1).max(2147483647),
30
+ execution_id: executionId.optional(),
31
+ lost: z.literal(true),
32
+ exit_code: z.never().optional(),
33
+ }),
34
+ ]);
35
+ const event = z.discriminatedUnion('type', [
36
+ z.object({ ...position, type: z.literal('process.exited'), data: processData }),
37
+ z.object({
38
+ ...position,
39
+ type: z.literal('computer.started'),
40
+ data: z.object({ status: z.literal('running'), previous: status.optional() }),
41
+ }),
42
+ z.object({
43
+ ...position,
44
+ type: z.literal('computer.stopped'),
45
+ data: z.object({ status: z.literal('stopped'), previous: status.optional() }),
46
+ }),
47
+ z.object({
48
+ ...position,
49
+ type: z.literal('computer.suspended'),
50
+ data: z.object({ status: z.literal('suspended'), previous: status.optional() }),
51
+ }),
52
+ z.object({
53
+ ...position,
54
+ type: z.literal('computer.idle'),
55
+ data: z.object({ idle_seconds: count }),
56
+ }),
57
+ ]);
58
+ const page = z.object({
59
+ computer: label,
60
+ from: z.string(),
61
+ cursor: label,
62
+ events: z.array(event).max(100),
63
+ more: z.boolean(),
64
+ baseline: z.boolean(),
65
+ gap: z
66
+ .object({
67
+ cursor: label,
68
+ at: label,
69
+ type: z.literal('gap'),
70
+ computer: label,
71
+ source: z.literal('daemon'),
72
+ data: z.object({ oldest_cursor: label.optional(), detail: label }),
73
+ })
74
+ .optional(),
75
+ supported: z.array(label),
76
+ retention: z.literal('ephemeral'),
77
+ });
78
+ export const registerSignals = (server, session) => {
79
+ server.registerTool('read_signals', {
80
+ title: 'Read one passive platform signal page',
81
+ description: 'Read finite daemon facts without waking the computer, guest contact, event socket, watcher, capture or polling loop. Omit since or send empty for a head-only baseline with no replay; neither a baseline nor gap proves no earlier activity or task success. Keep the returned cursor even on an empty page: filtered-out rows can advance it. Retention is ephemeral, and resets are explicit gaps.',
82
+ inputSchema: {
83
+ computer_id: computerSchema,
84
+ since: z.string().max(2048).optional(),
85
+ limit: z.number().int().min(1).max(100).optional(),
86
+ },
87
+ annotations: readAnnotations,
88
+ }, ({ computer_id, since, limit }, extra) => metadataCall(async () => {
89
+ const id = session.resolve(computer_id);
90
+ const data = metadata(page, await session.api.json('GET', P.signals(id), {
91
+ query: { since, limit },
92
+ signal: extra.signal,
93
+ }));
94
+ // Compare opaque checkpoints without parsing or deriving a next cursor.
95
+ // Baselines and explicit resets describe one head; replay starts at since.
96
+ // Events must advance; the next cursor may also pass filtered rows.
97
+ const checkpoints = new Set([data.from, ...data.events.map((e) => e.cursor)]);
98
+ if (data.computer !== id ||
99
+ data.events.some((e, i) => e.computer !== id || (i > 0 && e.seq <= data.events[i - 1].seq)) ||
100
+ checkpoints.size !== data.events.length + 1 ||
101
+ (data.events.length > 0 &&
102
+ data.cursor !== data.events.at(-1)?.cursor &&
103
+ checkpoints.has(data.cursor)) ||
104
+ data.baseline !== (since === undefined || since === '') ||
105
+ (data.baseline && data.gap) ||
106
+ (data.gap && (data.gap.computer !== id || data.gap.cursor !== data.cursor)) ||
107
+ ((data.baseline || data.gap) &&
108
+ (data.events.length || data.more || data.from !== data.cursor)) ||
109
+ (!data.baseline && !data.gap && data.from !== since) ||
110
+ (data.more && !data.events.length) ||
111
+ data.events.length > (limit ?? 50))
112
+ throw new Error('Inconsistent signal page; no checkpoint was established.');
113
+ return said(`${data.gap ? 'GAP: the checkpoint was reset. ' : ''}${data.baseline ? 'Head-only baseline; no historical replay. ' : ''}One ephemeral page; use the returned cursor, including after an empty page. These facts do not establish task success.`, data);
114
+ }));
115
+ };
116
+ //# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/tools/signals.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA4M5C,eAAO,MAAM,iBAAiB,EAAE,SAkyB/B,CAAC"}
1
+ {"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA4M5C,eAAO,MAAM,iBAAiB,EAAE,SAk1B/B,CAAC"}