mandala-computer-mcp 0.5.0 → 0.7.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 (84) hide show
  1. package/README.md +277 -20
  2. package/dist/api.d.ts +73 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +271 -22
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +17 -0
  8. package/dist/cli.js.map +1 -1
  9. package/dist/errors.d.ts +183 -5
  10. package/dist/errors.d.ts.map +1 -1
  11. package/dist/errors.js +377 -10
  12. package/dist/errors.js.map +1 -1
  13. package/dist/format.d.ts +90 -0
  14. package/dist/format.d.ts.map +1 -1
  15. package/dist/format.js +102 -2
  16. package/dist/format.js.map +1 -1
  17. package/dist/http.d.ts +42 -0
  18. package/dist/http.d.ts.map +1 -1
  19. package/dist/http.js +392 -6
  20. package/dist/http.js.map +1 -1
  21. package/dist/index.d.ts +4 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/paths.d.ts +74 -3
  26. package/dist/paths.d.ts.map +1 -1
  27. package/dist/paths.js +89 -10
  28. package/dist/paths.js.map +1 -1
  29. package/dist/secret-errors.d.ts +59 -0
  30. package/dist/secret-errors.d.ts.map +1 -0
  31. package/dist/secret-errors.js +199 -0
  32. package/dist/secret-errors.js.map +1 -0
  33. package/dist/secret-store.d.ts +115 -0
  34. package/dist/secret-store.d.ts.map +1 -0
  35. package/dist/secret-store.js +105 -0
  36. package/dist/secret-store.js.map +1 -0
  37. package/dist/server.d.ts +1 -1
  38. package/dist/server.d.ts.map +1 -1
  39. package/dist/server.js +3 -1
  40. package/dist/server.js.map +1 -1
  41. package/dist/session.d.ts +6 -1
  42. package/dist/session.d.ts.map +1 -1
  43. package/dist/session.js +1 -1
  44. package/dist/session.js.map +1 -1
  45. package/dist/tool-filters.d.ts +4 -4
  46. package/dist/tool-filters.d.ts.map +1 -1
  47. package/dist/tool-filters.js +22 -2
  48. package/dist/tool-filters.js.map +1 -1
  49. package/dist/tools/account.d.ts +14 -0
  50. package/dist/tools/account.d.ts.map +1 -1
  51. package/dist/tools/account.js +118 -0
  52. package/dist/tools/account.js.map +1 -1
  53. package/dist/tools/agent.d.ts.map +1 -1
  54. package/dist/tools/agent.js +7 -2
  55. package/dist/tools/agent.js.map +1 -1
  56. package/dist/tools/computers.d.ts.map +1 -1
  57. package/dist/tools/computers.js +277 -57
  58. package/dist/tools/computers.js.map +1 -1
  59. package/dist/tools/guest.d.ts.map +1 -1
  60. package/dist/tools/guest.js +140 -22
  61. package/dist/tools/guest.js.map +1 -1
  62. package/dist/tools/input.d.ts +11 -0
  63. package/dist/tools/input.d.ts.map +1 -1
  64. package/dist/tools/input.js +277 -20
  65. package/dist/tools/input.js.map +1 -1
  66. package/dist/tools/operations.d.ts +44 -0
  67. package/dist/tools/operations.d.ts.map +1 -0
  68. package/dist/tools/operations.js +232 -0
  69. package/dist/tools/operations.js.map +1 -0
  70. package/dist/tools/secrets.d.ts +42 -13
  71. package/dist/tools/secrets.d.ts.map +1 -1
  72. package/dist/tools/secrets.js +306 -15
  73. package/dist/tools/secrets.js.map +1 -1
  74. package/dist/tools/snapshots.d.ts.map +1 -1
  75. package/dist/tools/snapshots.js +44 -15
  76. package/dist/tools/snapshots.js.map +1 -1
  77. package/dist/tools/ssh.d.ts.map +1 -1
  78. package/dist/tools/ssh.js +19 -2
  79. package/dist/tools/ssh.js.map +1 -1
  80. package/dist/tools/templates.js +1 -1
  81. package/dist/tools/templates.js.map +1 -1
  82. package/dist/tools/webhooks.js +1 -1
  83. package/dist/tools/webhooks.js.map +1 -1
  84. package/package.json +1 -1
@@ -0,0 +1,44 @@
1
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import { z } from 'zod';
3
+ import type { Registrar } from './types.js';
4
+ /**
5
+ * The key on a step a read of the computer shows: start, stop, suspend,
6
+ * delete, move, update_computer (not restart: see
7
+ * {@link restartIdempotencyKeyArg}). See {@link resendAfterSpentKey}.
8
+ */
9
+ export declare const idempotencyKeyArg: z.ZodOptional<z.ZodString>;
10
+ /**
11
+ * The key on restart_computer, whose step no read of the computer shows: it
12
+ * reads running before and after a reset. So the route never conditions a
13
+ * resend on get_computer; see {@link resendAfterSpentKey}.
14
+ */
15
+ export declare const restartIdempotencyKeyArg: z.ZodOptional<z.ZodString>;
16
+ /**
17
+ * The key on a call that makes a new computer or overwrites a disk: create,
18
+ * clone, clone_snapshot, restore_snapshot. A resend after a spent key waits for
19
+ * the operation to be final. See {@link resendAfterSpentKey}.
20
+ */
21
+ export declare const buildIdempotencyKeyArg: z.ZodOptional<z.ZodString>;
22
+ /**
23
+ * The answer to a lifecycle tool call that failed, with what its key means.
24
+ *
25
+ * The platform's own `idempotency_*` refusals get their sentence instead of the
26
+ * generic `reason` advice. A failure whose outcome is unknown ENDS with the
27
+ * retry that cannot do the step twice, and which one depends on who answered:
28
+ *
29
+ * - The answer never arrived, the keyed call is still running, or a proxy in
30
+ * front of the platform answered: the same tool, with the same key.
31
+ * - The platform itself answered a `5xx`: it has settled that key as lost
32
+ * (OPL-5304), so the same key can only be answered
33
+ * `idempotency_outcome_unknown`. The next step is a read, then a resend
34
+ * with a new key or none if the step did not happen. Which read depends on
35
+ * the tool (see {@link resendAfterSpentKey}): a create, clone or restore
36
+ * waits for its operation to be final, since a read of the computer made
37
+ * at once cannot see one still landing; a restart, which no read of the
38
+ * computer shows, is read off its operation and otherwise left to the user;
39
+ * every other step is read off the computer, since its operation stays
40
+ * `pending` for an hour regardless.
41
+ */
42
+ export declare function keyedFailure(err: unknown, tool: string, what: string, key: string): CallToolResult;
43
+ export declare const registerOperations: Registrar;
44
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/tools/operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA8C5C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,4BAE7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,4BAEpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,4BAElC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,cAAc,CAiBhB;AAuBD,eAAO,MAAM,kBAAkB,EAAE,SAmJhC,CAAC"}
@@ -0,0 +1,232 @@
1
+ import { z } from 'zod';
2
+ import { IDEMPOTENCY_KEY_PATTERN } from '../api.js';
3
+ import { CancelledError, idempotencyAdvice, isTransientForPoll, keyedOutcomeUnknown, platformAnsweredFailure, resendAfterSpentKey, resendUnseenByRead, } from '../errors.js';
4
+ import { failed, guarded, operationIdOf, refused, said } from '../format.js';
5
+ import * as P from '../paths.js';
6
+ import { heartbeat, POLL_MS, pollDelay, sleep } from '../poll.js';
7
+ import { label, metadata, metadataCall } from './directory.js';
8
+ import { readAnnotations } from './results.js';
9
+ /**
10
+ * One lifecycle operation (platform OPL-5055), projected to its public fields.
11
+ *
12
+ * `kind` and `state` are open strings: the platform adds kinds, and one this
13
+ * server does not know is a kind, not a malformed answer. Strict on the error's
14
+ * shape, because a `failed` operation relayed without its reason is a failure
15
+ * with nothing to say about why.
16
+ */
17
+ const operation = z.object({
18
+ id: label,
19
+ kind: label,
20
+ computer_id: z.string().nullable(),
21
+ state: label,
22
+ error: z.object({ code: z.string(), message: z.string() }).nullable(),
23
+ // The key the call that started it was sent with (OPL-5127): null for one
24
+ // sent without, and absent from a platform that predates the field.
25
+ idempotency_key: z.string().nullable().optional(),
26
+ created_at: z.string(),
27
+ updated_at: z.string(),
28
+ finished_at: z.string().nullable(),
29
+ });
30
+ const page = z.object({
31
+ operations: z.array(operation),
32
+ next_cursor: z.string().min(1).nullable(),
33
+ });
34
+ /**
35
+ * The `idempotency_key` a lifecycle tool takes (platform OPL-5127), checked
36
+ * against the platform's rule here so a key it would refuse never leaves.
37
+ */
38
+ const keyArg = z
39
+ .string()
40
+ .regex(IDEMPOTENCY_KEY_PATTERN, 'idempotency_key must be 1 to 255 characters, each printable ASCII other than a space')
41
+ .optional();
42
+ const KEY_FIRST = "Optional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx the platform answered, or idempotency_outcome_unknown, the key is spent (resending with it answers idempotency_outcome_unknown)";
43
+ const KEY_LAST = ' Keys last 24 hours; the same key with different arguments is refused.';
44
+ /**
45
+ * The key on a step a read of the computer shows: start, stop, suspend,
46
+ * delete, move, update_computer (not restart: see
47
+ * {@link restartIdempotencyKeyArg}). See {@link resendAfterSpentKey}.
48
+ */
49
+ export const idempotencyKeyArg = keyArg.describe(`${KEY_FIRST}: read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none.${KEY_LAST}`);
50
+ /**
51
+ * The key on restart_computer, whose step no read of the computer shows: it
52
+ * reads running before and after a reset. So the route never conditions a
53
+ * resend on get_computer; see {@link resendAfterSpentKey}.
54
+ */
55
+ export const restartIdempotencyKeyArg = keyArg.describe(`${KEY_FIRST}. A restart cannot be seen in get_computer (it reads running before and after one), so do not read the computer to decide: read get_operation with the operation_id the error named, or list_operations with the key. Succeeded means the restart happened; running means wait on it. Anything else leaves it possibly done, so ask the user before sending it again with a new key, or none — a second restart resets the guest again.${KEY_LAST}`);
56
+ /**
57
+ * The key on a call that makes a new computer or overwrites a disk: create,
58
+ * clone, clone_snapshot, restore_snapshot. A resend after a spent key waits for
59
+ * the operation to be final. See {@link resendAfterSpentKey}.
60
+ */
61
+ export const buildIdempotencyKeyArg = keyArg.describe(`${KEY_FIRST} and the call may still be under way: read its operation first (get_operation with the operation_id the error named, or list_operations with the key), wait while it is pending or running and do not resend meanwhile, and send the call with a new key (or none) only once the operation is final as failed or not found AND get_computer shows the step did not happen.${KEY_LAST}`);
62
+ /**
63
+ * The answer to a lifecycle tool call that failed, with what its key means.
64
+ *
65
+ * The platform's own `idempotency_*` refusals get their sentence instead of the
66
+ * generic `reason` advice. A failure whose outcome is unknown ENDS with the
67
+ * retry that cannot do the step twice, and which one depends on who answered:
68
+ *
69
+ * - The answer never arrived, the keyed call is still running, or a proxy in
70
+ * front of the platform answered: the same tool, with the same key.
71
+ * - The platform itself answered a `5xx`: it has settled that key as lost
72
+ * (OPL-5304), so the same key can only be answered
73
+ * `idempotency_outcome_unknown`. The next step is a read, then a resend
74
+ * with a new key or none if the step did not happen. Which read depends on
75
+ * the tool (see {@link resendAfterSpentKey}): a create, clone or restore
76
+ * waits for its operation to be final, since a read of the computer made
77
+ * at once cannot see one still landing; a restart, which no read of the
78
+ * computer shows, is read off its operation and otherwise left to the user;
79
+ * every other step is read off the computer, since its operation stays
80
+ * `pending` for an hour regardless.
81
+ */
82
+ export function keyedFailure(err, tool, what, key) {
83
+ const advice = idempotencyAdvice(err, tool);
84
+ const result = failed(err, advice === undefined);
85
+ const [first, ...rest] = result.content;
86
+ if (first?.type !== 'text')
87
+ return result;
88
+ let text = first.text;
89
+ if (advice)
90
+ text += `\n\nAbout its idempotency_key: ${advice}.`;
91
+ if (keyedOutcomeUnknown(err)) {
92
+ text += `\n\nTo retry without risking a second ${what}, call ${tool} again with idempotency_key "${key}".`;
93
+ }
94
+ else if (platformAnsweredFailure(err)) {
95
+ const op = operationIdOf(err.body);
96
+ text +=
97
+ `\n\nThe platform answered this itself, so whether it took effect is unknown — its host may still be carrying out the ${what} — and it has settled idempotency_key "${key}": resending with that key will answer idempotency_outcome_unknown, not do it. ` +
98
+ `${resendAfterSpentKey(tool, op, key, `call ${tool} again`)}.` +
99
+ (resendUnseenByRead(tool) ? '' : ` That way there is no second ${what}.`);
100
+ }
101
+ return { ...result, content: [{ ...first, text }, ...rest] };
102
+ }
103
+ const operationIdArg = z
104
+ .string()
105
+ .min(1)
106
+ .describe('The operation_id a lifecycle tool answered: a create, a clone, a start, stop, suspend or restart, a resize, a snapshot restore, or a move.');
107
+ /** The sentence every answer about an operation starts with. */
108
+ const line = (op) => `${op.id}: ${op.kind}${op.computer_id ? ` of ${op.computer_id}` : ''} — ${op.state}` +
109
+ (op.error ? ` (${op.error.code}: ${op.error.message})` : '') +
110
+ (op.idempotency_key ? ` [idempotency_key ${JSON.stringify(op.idempotency_key)}]` : '');
111
+ /**
112
+ * Said beside every `succeeded`, because it is the misreading that costs the
113
+ * most: a model that reads a succeeded start as a desktop that answers drives
114
+ * a guest that is still booting.
115
+ */
116
+ const NOT_BOOTED = 'succeeded means the platform finished its step, not that the desktop has booted: wait_for_computer is still the wait for a desktop that answers.';
117
+ export const registerOperations = (server, session) => {
118
+ server.registerTool('get_operation', {
119
+ title: 'Read a lifecycle operation',
120
+ description: `One lifecycle operation: what an accepted create, clone, start, stop, suspend, restart, snapshot restore, resize, move or delete started, and where it got to. A call made with an idempotency_key is recorded pending before it is carried out, so it can be found even when its answer was lost; one the platform never heard end is failed with error.code lost. state is pending or running while live, and succeeded or failed once final; a failed one carries error.code (start_failed, build_failed, computer_gone, move_failed, resize_not_applied, lost, and more may be added) and a sentence. Most are already succeeded when the call that started them answered; a clone is running until its disk is copied, and a move until it lands. ${NOT_BOOTED} An id this key cannot see, or one that has expired, is not found.`,
121
+ inputSchema: { operation_id: operationIdArg },
122
+ annotations: readAnnotations,
123
+ }, ({ operation_id }, extra) => metadataCall(async () => {
124
+ const op = metadata(operation, await session.api.json('GET', P.operation(operation_id), { signal: extra.signal }));
125
+ return said(line(op), op);
126
+ }));
127
+ server.registerTool('list_operations', {
128
+ title: 'List lifecycle operations',
129
+ description: "The lifecycle operations this account's API calls started, newest first, a page at a time: kind, computer_id, state, error and timestamps. computer_id keeps one computer's (for a clone, the new computer's) — omitted, it is the whole account's, not the selected computer's. Pass next_cursor back as cursor for the next page; it is null on the last. Calls made from the dashboard record none.",
130
+ inputSchema: {
131
+ computer_id: z
132
+ .string()
133
+ .min(1)
134
+ .optional()
135
+ .describe("Only this computer's operations. Not defaulted to the selected computer."),
136
+ limit: z.number().int().min(1).max(100).optional().describe('Page size; default 20.'),
137
+ cursor: z.string().min(1).optional().describe('The next_cursor of the page before.'),
138
+ idempotency_key: z
139
+ .string()
140
+ .regex(IDEMPOTENCY_KEY_PATTERN, 'idempotency_key must be 1 to 255 characters, each printable ASCII other than a space')
141
+ .optional()
142
+ .describe("Only the operation the lifecycle call sent with this idempotency_key recorded — found even when that call's answer was lost — within the key's 24 hours."),
143
+ },
144
+ annotations: readAnnotations,
145
+ }, ({ computer_id, limit, cursor, idempotency_key }, extra) => metadataCall(async () => {
146
+ const data = metadata(page, await session.api.json('GET', P.OPERATIONS, {
147
+ query: { computer_id, limit, cursor, idempotency_key },
148
+ signal: extra.signal,
149
+ }));
150
+ if (!data.operations.length)
151
+ return said('No operations.', data);
152
+ return said(data.operations.map(line).join('\n') +
153
+ (data.next_cursor
154
+ ? `\n\nMore: pass cursor=${data.next_cursor} for the next page.`
155
+ : ''), data);
156
+ }));
157
+ server.registerTool('wait_for_operation', {
158
+ title: 'Wait for a lifecycle operation to finish',
159
+ description: `Poll a lifecycle operation until it is final. Answers once it has succeeded; a failed one is an error carrying error.code and the platform's sentence (resize_not_applied is a move that landed at the old size: the computer has moved, and update_computer finishes the resize). ${NOT_BOOTED} Most operations are already final when their call answers, so this is for a clone (running until its disk is copied) or a move. Reports progress while it waits, so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; get_operation reads it if the wait runs out.`,
160
+ inputSchema: {
161
+ operation_id: operationIdArg,
162
+ timeout_s: z
163
+ .number()
164
+ .int()
165
+ .min(1)
166
+ .max(900)
167
+ .default(300)
168
+ .describe('How long to wait before handing back and letting you poll.'),
169
+ },
170
+ annotations: readAnnotations,
171
+ }, ({ operation_id, timeout_s }, extra) => guarded(async () => {
172
+ const path = P.operation(operation_id);
173
+ const untilDeadline = AbortSignal.timeout(timeout_s * 1000);
174
+ const signal = extra.signal
175
+ ? AbortSignal.any([extra.signal, untilDeadline])
176
+ : untilDeadline;
177
+ const api = session.api.with(signal);
178
+ const beat = heartbeat(extra, server.server);
179
+ let last;
180
+ let blocked;
181
+ try {
182
+ while (!untilDeadline.aborted) {
183
+ if (extra.signal?.aborted) {
184
+ return refused(`Cancelled while waiting for ${operation_id}. The operation is not stopped by that; get_operation says where it got to.`, last);
185
+ }
186
+ let raw;
187
+ try {
188
+ raw = await api.json('GET', path);
189
+ }
190
+ catch (err) {
191
+ if (extra.signal?.aborted)
192
+ continue;
193
+ if (err instanceof CancelledError) {
194
+ if (untilDeadline.aborted)
195
+ break;
196
+ blocked = err.message;
197
+ await sleep(POLL_MS, signal);
198
+ continue;
199
+ }
200
+ if (!isTransientForPoll(err))
201
+ throw err;
202
+ blocked = err instanceof Error ? err.message : String(err);
203
+ await beat(`${operation_id} — the platform could not be asked: ${blocked}`);
204
+ await sleep(pollDelay(err), signal);
205
+ continue;
206
+ }
207
+ const op = metadata(operation, raw);
208
+ last = op;
209
+ blocked = undefined;
210
+ if (op.state === 'succeeded')
211
+ return said(`${line(op)}.\n\n${NOT_BOOTED}`, op);
212
+ if (op.state === 'failed')
213
+ return refused(`${line(op)}.`, op);
214
+ // A state this server does not know, on an operation the platform
215
+ // says has FINISHED, is a final state added after it was written.
216
+ // Polling it would run to the deadline and then call it live.
217
+ if (op.finished_at !== null && op.state !== 'pending' && op.state !== 'running') {
218
+ return refused(`${line(op)}. It has finished in a state this server does not know; read it with get_operation.`, op);
219
+ }
220
+ await beat(line(op));
221
+ await sleep(POLL_MS, signal);
222
+ }
223
+ return refused(blocked
224
+ ? `Gave up after ${timeout_s}s; the platform could not be asked — the last attempt said: ${blocked}. The operation is not stopped by that; get_operation says where it got to.`
225
+ : `Still ${last?.state ?? 'live'} after ${timeout_s}s. The operation is not stopped by that; wait again, or read it with get_operation.`, last);
226
+ }
227
+ finally {
228
+ await beat.stop();
229
+ }
230
+ }));
231
+ };
232
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/tools/operations.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,26 @@
1
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
1
2
  import { z } from 'zod';
3
+ import { type Secret } from '../secret-store.js';
2
4
  import type { Registrar } from './types.js';
3
5
  /**
4
- * A computer's secret bindings: which of the account's secrets it receives, at
5
- * which revision, and where — as an environment variable (`env`) or as a file
6
- * under FILES_DIR (`file`).
6
+ * Secrets: the account's store of named values, and which of them each
7
+ * computer is bound to.
7
8
  *
8
- * No value ever crosses these routes, in either direction — only secret ids,
9
- * revision ids, env names and file names — so nothing here can show one, and
10
- * nothing a model sends can set one. Secrets themselves are created and rotated
11
- * elsewhere.
9
+ * The BINDINGS (get/set_computer_secrets) carry only ids, revision ids, env
10
+ * names and file names — no value crosses those routes in either direction.
11
+ *
12
+ * The STORE (list/get/create/set/replace/delete_secret) is where a value goes in,
13
+ * and only in: the platform never answers one, the decoded answers here carry
14
+ * none, and a tool that took a value never repeats it — not in a success, not
15
+ * in a refusal. See {@link withoutValue}.
12
16
  *
13
17
  * A change of bindings takes effect at the computer's NEXT START OR RESTART. A
14
18
  * running computer keeps what it booted with until then, and a suspended one
15
19
  * resumes with its old values; the sentences below say so every time, because a
16
20
  * model that reads "saved" as "delivered" goes on to use a credential the guest
17
- * does not have yet. The one thing that reaches a running computer sooner is a
18
- * replaced VALUE of a secret bound as a file: that file is rewritten in place.
21
+ * does not have yet. What reaches a running computer sooner is a replaced VALUE:
22
+ * a file binding's file is rewritten in place, and on an image that supports it
23
+ * an env binding's new value reaches new shells and desktop-session commands.
19
24
  */
20
25
  /** Where a file binding is published in the guest. */
21
26
  export declare const FILES_DIR = "/run/mandala-secrets/user/files";
@@ -35,24 +40,48 @@ export declare function secretBindingsSchema(revision: boolean): z.ZodEffects<z.
35
40
  file: z.ZodOptional<z.ZodString>;
36
41
  }, "strict", z.ZodTypeAny, {
37
42
  secret_id: string;
38
- file?: string | undefined;
39
43
  env?: string | undefined;
40
44
  revision_id?: unknown;
45
+ file?: string | undefined;
41
46
  }, {
42
47
  secret_id: string;
43
- file?: string | undefined;
44
48
  env?: string | undefined;
45
49
  revision_id?: unknown;
50
+ file?: string | undefined;
46
51
  }>, "many">, {
47
52
  secret_id: string;
48
- file?: string | undefined;
49
53
  env?: string | undefined;
50
54
  revision_id?: unknown;
55
+ file?: string | undefined;
51
56
  }[], {
52
57
  secret_id: string;
53
- file?: string | undefined;
54
58
  env?: string | undefined;
55
59
  revision_id?: unknown;
60
+ file?: string | undefined;
56
61
  }[]>;
62
+ /** The published ceiling on a value, in bytes of UTF-8. */
63
+ export declare const SECRET_VALUE_MAX_BYTES = 4096;
64
+ /** The published ceiling on a name, in characters. */
65
+ export declare const SECRET_NAME_MAX_CHARS = 60;
66
+ /** How many times set_secret reads the scope again after a conflict. */
67
+ export declare const SECRET_SET_RETRIES = 3;
68
+ /**
69
+ * The secret called `name` in a listing of one scope, or `undefined`: trimmed
70
+ * as the platform trims names, and ignoring ASCII case and nothing else, which
71
+ * is how it keeps them unique — `openai_api_key` is taken when `OPENAI_API_KEY` is.
72
+ */
73
+ export declare function namedSecret(secrets: readonly Secret[], name: string): Secret | undefined;
74
+ /**
75
+ * A tool result with every occurrence of a value taken out.
76
+ *
77
+ * The SECOND layer. The first is that no secret-store tool puts response text
78
+ * in its answer at all — see {@link storeGuarded} — and the Api keeps none for
79
+ * those routes. This catches what the first could still let through: a value
80
+ * that happens to equal a decoded field, or a message this server did not
81
+ * write. No length exemption: a one-character value is searched for too,
82
+ * which can mangle the sentence and is the price of never showing it. The
83
+ * JSON-escaped spelling is searched for as well, since data is shown as JSON.
84
+ */
85
+ export declare function withoutValue(result: CallToolResult, value: string): CallToolResult;
57
86
  export declare const registerSecrets: Registrar;
58
87
  //# sourceMappingURL=secrets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/tools/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;AAEH,sDAAsD;AACtD,eAAO,MAAM,SAAS,oCAAoC,CAAC;AAE3D,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAiBlC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;KA0DrD;AAyED,eAAO,MAAM,eAAe,EAAE,SA+E7B,CAAC"}
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/tools/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAIL,KAAK,MAAM,EAEZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,sDAAsD;AACtD,eAAO,MAAM,SAAS,oCAAoC,CAAC;AAE3D,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAiBlC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;KA0DrD;AA0FD,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,sDAAsD;AACtD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAiDxC,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIxF;AAOD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAclF;AAsED,eAAO,MAAM,eAAe,EAAE,SAqR7B,CAAC"}