@run402/sdk 4.97.0 → 4.99.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 (138) hide show
  1. package/README.md +2 -2
  2. package/core-dist/binding-file.d.ts +14 -0
  3. package/core-dist/binding-file.js +28 -1
  4. package/core-dist/wallet.js +3 -3
  5. package/dist/errors.d.ts +24 -2
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/errors.js +44 -2
  8. package/dist/errors.js.map +1 -1
  9. package/dist/index.d.ts +18 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +12 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/kernel.d.ts +34 -0
  14. package/dist/kernel.d.ts.map +1 -1
  15. package/dist/kernel.js +15 -1
  16. package/dist/kernel.js.map +1 -1
  17. package/dist/namespaces/admin.d.ts.map +1 -1
  18. package/dist/namespaces/admin.js +8 -0
  19. package/dist/namespaces/admin.js.map +1 -1
  20. package/dist/namespaces/agent.d.ts +2 -2
  21. package/dist/namespaces/agent.d.ts.map +1 -1
  22. package/dist/namespaces/agent.js +4 -0
  23. package/dist/namespaces/agent.js.map +1 -1
  24. package/dist/namespaces/agent.types.d.ts +5 -0
  25. package/dist/namespaces/agent.types.d.ts.map +1 -1
  26. package/dist/namespaces/apps.d.ts.map +1 -1
  27. package/dist/namespaces/apps.js +2 -0
  28. package/dist/namespaces/apps.js.map +1 -1
  29. package/dist/namespaces/auth.d.ts.map +1 -1
  30. package/dist/namespaces/auth.js +9 -0
  31. package/dist/namespaces/auth.js.map +1 -1
  32. package/dist/namespaces/branches.d.ts.map +1 -1
  33. package/dist/namespaces/branches.js +2 -0
  34. package/dist/namespaces/branches.js.map +1 -1
  35. package/dist/namespaces/ci.d.ts.map +1 -1
  36. package/dist/namespaces/ci.js +2 -0
  37. package/dist/namespaces/ci.js.map +1 -1
  38. package/dist/namespaces/credentials.d.ts +0 -23
  39. package/dist/namespaces/credentials.d.ts.map +1 -1
  40. package/dist/namespaces/credentials.js +29 -0
  41. package/dist/namespaces/credentials.js.map +1 -1
  42. package/dist/namespaces/escalations.d.ts.map +1 -1
  43. package/dist/namespaces/escalations.js +2 -0
  44. package/dist/namespaces/escalations.js.map +1 -1
  45. package/dist/namespaces/grants.d.ts.map +1 -1
  46. package/dist/namespaces/grants.js +4 -0
  47. package/dist/namespaces/grants.js.map +1 -1
  48. package/dist/namespaces/live.d.ts +0 -16
  49. package/dist/namespaces/live.d.ts.map +1 -1
  50. package/dist/namespaces/live.js +19 -0
  51. package/dist/namespaces/live.js.map +1 -1
  52. package/dist/namespaces/me.d.ts.map +1 -1
  53. package/dist/namespaces/me.js +3 -0
  54. package/dist/namespaces/me.js.map +1 -1
  55. package/dist/namespaces/org.d.ts.map +1 -1
  56. package/dist/namespaces/org.js +3 -0
  57. package/dist/namespaces/org.js.map +1 -1
  58. package/dist/namespaces/projects.d.ts.map +1 -1
  59. package/dist/namespaces/projects.js +5 -0
  60. package/dist/namespaces/projects.js.map +1 -1
  61. package/dist/namespaces/repos.d.ts.map +1 -1
  62. package/dist/namespaces/repos.js +5 -0
  63. package/dist/namespaces/repos.js.map +1 -1
  64. package/dist/namespaces/rooms.d.ts.map +1 -1
  65. package/dist/namespaces/rooms.js +3 -0
  66. package/dist/namespaces/rooms.js.map +1 -1
  67. package/dist/namespaces/session.d.ts.map +1 -1
  68. package/dist/namespaces/session.js +18 -0
  69. package/dist/namespaces/session.js.map +1 -1
  70. package/dist/namespaces/transfers.d.ts.map +1 -1
  71. package/dist/namespaces/transfers.js +3 -0
  72. package/dist/namespaces/transfers.js.map +1 -1
  73. package/dist/namespaces/wallets.d.ts.map +1 -1
  74. package/dist/namespaces/wallets.js +2 -0
  75. package/dist/namespaces/wallets.js.map +1 -1
  76. package/dist/namespaces/write-approval.d.ts.map +1 -1
  77. package/dist/namespaces/write-approval.js +3 -0
  78. package/dist/namespaces/write-approval.js.map +1 -1
  79. package/dist/node/actions-node.d.ts.map +1 -1
  80. package/dist/node/actions-node.js +3 -0
  81. package/dist/node/actions-node.js.map +1 -1
  82. package/dist/node/buzz-doctor-contract.d.ts +155 -0
  83. package/dist/node/buzz-doctor-contract.d.ts.map +1 -0
  84. package/dist/node/buzz-doctor-contract.js +385 -0
  85. package/dist/node/buzz-doctor-contract.js.map +1 -0
  86. package/dist/node/buzz-doctor.d.ts +155 -0
  87. package/dist/node/buzz-doctor.d.ts.map +1 -0
  88. package/dist/node/buzz-doctor.js +810 -0
  89. package/dist/node/buzz-doctor.js.map +1 -0
  90. package/dist/node/credentials.d.ts +9 -4
  91. package/dist/node/credentials.d.ts.map +1 -1
  92. package/dist/node/credentials.js +1 -1
  93. package/dist/node/credentials.js.map +1 -1
  94. package/dist/node/diagnostics.d.ts +45 -0
  95. package/dist/node/diagnostics.d.ts.map +1 -0
  96. package/dist/node/diagnostics.js +67 -0
  97. package/dist/node/diagnostics.js.map +1 -0
  98. package/dist/node/doctor.d.ts +101 -0
  99. package/dist/node/doctor.d.ts.map +1 -0
  100. package/dist/node/doctor.js +618 -0
  101. package/dist/node/doctor.js.map +1 -0
  102. package/dist/node/index.d.ts +57 -5
  103. package/dist/node/index.d.ts.map +1 -1
  104. package/dist/node/index.js +36 -1
  105. package/dist/node/index.js.map +1 -1
  106. package/dist/node/init.d.ts +137 -0
  107. package/dist/node/init.d.ts.map +1 -0
  108. package/dist/node/init.js +507 -0
  109. package/dist/node/init.js.map +1 -0
  110. package/dist/node/lightning-wallet.d.ts +61 -0
  111. package/dist/node/lightning-wallet.d.ts.map +1 -0
  112. package/dist/node/lightning-wallet.js +126 -0
  113. package/dist/node/lightning-wallet.js.map +1 -0
  114. package/dist/node/local-actions.d.ts +23 -0
  115. package/dist/node/local-actions.d.ts.map +1 -0
  116. package/dist/node/local-actions.js +38 -0
  117. package/dist/node/local-actions.js.map +1 -0
  118. package/dist/node/org-context.d.ts +169 -0
  119. package/dist/node/org-context.d.ts.map +1 -0
  120. package/dist/node/org-context.js +403 -0
  121. package/dist/node/org-context.js.map +1 -0
  122. package/dist/node/status.d.ts +62 -0
  123. package/dist/node/status.d.ts.map +1 -0
  124. package/dist/node/status.js +132 -0
  125. package/dist/node/status.js.map +1 -0
  126. package/dist/node/vault-target.d.ts +49 -0
  127. package/dist/node/vault-target.d.ts.map +1 -0
  128. package/dist/node/vault-target.js +109 -0
  129. package/dist/node/vault-target.js.map +1 -0
  130. package/dist/node/wallets.d.ts +242 -0
  131. package/dist/node/wallets.d.ts.map +1 -0
  132. package/dist/node/wallets.js +484 -0
  133. package/dist/node/wallets.js.map +1 -0
  134. package/dist/secret-gate.d.ts +377 -0
  135. package/dist/secret-gate.d.ts.map +1 -0
  136. package/dist/secret-gate.js +273 -0
  137. package/dist/secret-gate.js.map +1 -0
  138. package/package.json +2 -1
@@ -0,0 +1,377 @@
1
+ /**
2
+ * The secret gate: every SDK method whose result carries a one-time secret the
3
+ * caller would otherwise receive (a grant key, a Handoff or Invite Key, a Room
4
+ * Invite Key, project credentials, a private key, a Lightning pairing, a
5
+ * sign-in session or write-approval token), or whose input IS such a bearer
6
+ * secret, calls {@link gateSecret} as its first statement. On a client whose
7
+ * `capabilities.returnSecrets` is false — the `sandbox` surface an MCP `run`
8
+ * snippet executes on — that call throws `SECRET_REQUIRES_CLI` before any
9
+ * request, naming the exact CLI command for the same operation. On every
10
+ * other surface it is a no-op.
11
+ *
12
+ * The gate is the method itself, keyed on a client capability: there is no
13
+ * tool-name denylist and no path filter anywhere else, so every future door
14
+ * that builds a `sandbox` client inherits it for free.
15
+ *
16
+ * {@link SECRET_RETURNING_METHODS} is the registry: one entry per gated
17
+ * method (by its dotted path from the client root), with the command builder
18
+ * and, for a method that carries a secret only when a particular option is
19
+ * supplied, the predicate that says so. `sdk/src/node/secret-gate.test.ts`
20
+ * owns the inventory: it fails when a method's types carry a secret-named
21
+ * field and no entry names it, and when a registered method reaches the
22
+ * network on a `sandbox` client.
23
+ *
24
+ * A command never embeds a secret value: where the input is the secret, the
25
+ * command carries its placeholder (`<kgh1_…>`), never the key.
26
+ */
27
+ import type { Client } from "./kernel.js";
28
+ type Args = any[];
29
+ export interface SecretGateEntry {
30
+ /** The exact CLI command line for the same operation, built from the call's own arguments. */
31
+ command: (...args: Args) => string;
32
+ /** When present, the call is gated only when this returns true (the secret-bearing option was supplied). */
33
+ when?: (...args: Args) => boolean;
34
+ /** Why the operation belongs to the CLI; defaults to the generic one-time-secret sentence. */
35
+ why?: string;
36
+ }
37
+ /**
38
+ * Every gated method, by its dotted path from the client root. The command is
39
+ * the CLI line for the same operation; the drift test calls each one on a
40
+ * `sandbox` client and requires the refusal before any request.
41
+ */
42
+ export declare const SECRET_RETURNING_METHODS: {
43
+ "grants.create": {
44
+ when: (_projectId: unknown, input: unknown) => boolean;
45
+ command: (projectId: unknown, input: unknown) => string;
46
+ why: string;
47
+ };
48
+ "grants.createKey": {
49
+ command: (projectId: unknown) => string;
50
+ why: string;
51
+ };
52
+ "grants.rotateKey": {
53
+ command: (projectId: unknown, keyId: unknown) => string;
54
+ why: string;
55
+ };
56
+ "repos.handoff": {
57
+ command: (opts: unknown) => string;
58
+ };
59
+ "repos.invite": {
60
+ command: (opts: unknown) => string;
61
+ };
62
+ "repos.resume": {
63
+ command: () => string;
64
+ why: string;
65
+ };
66
+ "repos.join": {
67
+ command: () => string;
68
+ why: string;
69
+ };
70
+ "rooms.invite": {
71
+ command: (orgId: unknown, roomKey: unknown) => string;
72
+ };
73
+ "rooms.join": {
74
+ command: () => string;
75
+ why: string;
76
+ };
77
+ "projects.provision": {
78
+ command: (opts: unknown) => string;
79
+ why: string;
80
+ };
81
+ "projects.list": {
82
+ when: (opts: unknown) => boolean;
83
+ command: () => string;
84
+ why: string;
85
+ };
86
+ "projects.info": {
87
+ command: (id: unknown) => string;
88
+ why: string;
89
+ };
90
+ "projects.keys": {
91
+ command: (id: unknown) => string;
92
+ why: string;
93
+ };
94
+ "credentials.projectKeys.import": {
95
+ command: (projectId: unknown) => string;
96
+ why: string;
97
+ };
98
+ "credentials.projectKeys.export": {
99
+ command: (projectId: unknown) => string;
100
+ why: string;
101
+ };
102
+ "credentials.issue": {
103
+ command: (projectId: unknown, input: unknown) => string;
104
+ why: string;
105
+ };
106
+ "credentials.rotate": {
107
+ command: (projectId: unknown, credentialId: unknown) => string;
108
+ why: string;
109
+ };
110
+ "credentials.mintToken": {
111
+ command: (projectId: unknown, opts: unknown) => string;
112
+ why: string;
113
+ };
114
+ "apps.fork": {
115
+ command: (opts: unknown) => string;
116
+ why: string;
117
+ };
118
+ "branches.create": {
119
+ command: (projectId: unknown) => string;
120
+ why: string;
121
+ };
122
+ "admin.transfers.initiate": {
123
+ when: (input: unknown) => boolean;
124
+ command: (input: unknown) => string;
125
+ why: string;
126
+ };
127
+ "admin.transfers.accept": {
128
+ command: (transferId: unknown) => string;
129
+ why: string;
130
+ };
131
+ "admin.rotateWebhookSecret": {
132
+ command: () => string;
133
+ why: string;
134
+ };
135
+ "wallets.create": {
136
+ command: (name: unknown) => string;
137
+ why: string;
138
+ };
139
+ "wallets.import": {
140
+ command: (name: unknown) => string;
141
+ why: string;
142
+ };
143
+ "agent.lightningWallet.mint": {
144
+ command: () => string;
145
+ why: string;
146
+ };
147
+ "agent.lightningWallet.get": {
148
+ command: () => string;
149
+ why: string;
150
+ };
151
+ "agent.lightningWallet.waitForActive": {
152
+ command: () => string;
153
+ why: string;
154
+ };
155
+ init: {
156
+ when: (opts: unknown) => boolean;
157
+ command: () => string;
158
+ why: string;
159
+ };
160
+ "actions.run": {
161
+ when: (input: unknown) => boolean;
162
+ command: (input: unknown) => "run402 projects provision" | "run402 up";
163
+ why: string;
164
+ };
165
+ "actions.up": {
166
+ command: () => string;
167
+ why: string;
168
+ };
169
+ "session.exchangeCliToken": {
170
+ command: () => string;
171
+ why: string;
172
+ };
173
+ "session.devicePoll": {
174
+ command: () => string;
175
+ why: string;
176
+ };
177
+ "session.verifyEmail": {
178
+ command: () => string;
179
+ why: string;
180
+ };
181
+ "session.passkeyVerify": {
182
+ command: () => string;
183
+ why: string;
184
+ };
185
+ "session.consumeRecoveryCode": {
186
+ command: () => string;
187
+ why: string;
188
+ };
189
+ "session.whoami": {
190
+ when: (opts: unknown) => boolean;
191
+ command: () => string;
192
+ why: string;
193
+ };
194
+ "session.refresh": {
195
+ command: () => string;
196
+ why: string;
197
+ };
198
+ "session.revoke": {
199
+ when: (opts: unknown) => boolean;
200
+ command: () => string;
201
+ why: string;
202
+ };
203
+ "session.enrollPasskeyOptions": {
204
+ when: (opts: unknown) => boolean;
205
+ command: () => string;
206
+ why: string;
207
+ };
208
+ "session.enrollPasskeyVerify": {
209
+ when: (opts: unknown) => boolean;
210
+ command: () => string;
211
+ why: string;
212
+ };
213
+ "session.stepUpOptions": {
214
+ when: (opts: unknown) => boolean;
215
+ command: () => string;
216
+ why: string;
217
+ };
218
+ "session.stepUpVerify": {
219
+ when: (opts: unknown) => boolean;
220
+ command: () => string;
221
+ why: string;
222
+ };
223
+ "session.issueRecoveryCodes": {
224
+ command: () => string;
225
+ why: string;
226
+ };
227
+ "session.listAuthenticators": {
228
+ when: (opts: unknown) => boolean;
229
+ command: () => string;
230
+ why: string;
231
+ };
232
+ "session.revokeAuthenticator": {
233
+ when: (opts: unknown) => boolean;
234
+ command: () => string;
235
+ why: string;
236
+ };
237
+ "session.sourceAccessWrappers": {
238
+ when: (opts: unknown) => boolean;
239
+ command: () => string;
240
+ why: string;
241
+ };
242
+ "session.sourceAccessRecoveryBundle": {
243
+ when: (opts: unknown) => boolean;
244
+ command: () => string;
245
+ why: string;
246
+ };
247
+ "writeApproval.requestChallenge": {
248
+ command: () => string;
249
+ why: string;
250
+ };
251
+ "writeApproval.exchangeClaimCode": {
252
+ command: () => string;
253
+ why: string;
254
+ };
255
+ "me.overview": {
256
+ when: (opts: unknown) => boolean;
257
+ command: () => string;
258
+ why: string;
259
+ };
260
+ "me.status": {
261
+ when: (opts: unknown) => boolean;
262
+ command: () => string;
263
+ why: string;
264
+ };
265
+ "orgs.adopt.challenge": {
266
+ when: (opts: unknown) => boolean;
267
+ command: () => string;
268
+ why: string;
269
+ };
270
+ "orgs.adopt.submit": {
271
+ when: (opts: unknown) => boolean;
272
+ command: () => string;
273
+ why: string;
274
+ };
275
+ "admin.channels.connectTelegram": {
276
+ when: (_opts: unknown, proofs: unknown) => boolean;
277
+ command: () => string;
278
+ why: string;
279
+ };
280
+ "admin.channels.revokeTelegram": {
281
+ when: (_id: unknown, proofs: unknown) => boolean;
282
+ command: (id: unknown) => string;
283
+ why: string;
284
+ };
285
+ "admin.rules.create": {
286
+ when: (_i: unknown, proofs: unknown) => boolean;
287
+ command: () => string;
288
+ why: string;
289
+ };
290
+ "admin.rules.update": {
291
+ when: (_id: unknown, _p: unknown, proofs: unknown) => boolean;
292
+ command: () => string;
293
+ why: string;
294
+ };
295
+ "admin.rules.delete": {
296
+ when: (_id: unknown, proofs: unknown) => boolean;
297
+ command: (id: unknown) => string;
298
+ why: string;
299
+ };
300
+ "admin.setNotificationPreferences": {
301
+ when: (_p: unknown, proofs: unknown) => boolean;
302
+ command: () => string;
303
+ why: string;
304
+ };
305
+ "auth.verifyMagicLink": {
306
+ command: (projectId: unknown) => string;
307
+ why: string;
308
+ };
309
+ "auth.verify": {
310
+ command: (projectId: unknown) => string;
311
+ why: string;
312
+ };
313
+ "auth.verifyEmailCode": {
314
+ command: (projectId: unknown, opts: unknown) => string;
315
+ why: string;
316
+ };
317
+ "auth.setUserPassword": {
318
+ command: (projectId: unknown) => string;
319
+ why: string;
320
+ };
321
+ "auth.setPassword": {
322
+ command: (projectId: unknown) => string;
323
+ why: string;
324
+ };
325
+ "auth.createPasskeyRegistrationOptions": {
326
+ command: (projectId: unknown) => string;
327
+ why: string;
328
+ };
329
+ "auth.verifyPasskeyRegistration": {
330
+ command: (projectId: unknown) => string;
331
+ why: string;
332
+ };
333
+ "auth.verifyPasskeyLogin": {
334
+ command: (projectId: unknown) => string;
335
+ why: string;
336
+ };
337
+ "auth.listPasskeys": {
338
+ command: (projectId: unknown) => string;
339
+ why: string;
340
+ };
341
+ "auth.deletePasskey": {
342
+ command: (projectId: unknown) => string;
343
+ why: string;
344
+ };
345
+ "live.changes": {
346
+ when: (_projectId: unknown, opts: unknown) => boolean;
347
+ command: (projectId: unknown, opts: unknown) => string;
348
+ why: string;
349
+ };
350
+ "live.subscribe": {
351
+ when: (_projectId: unknown, opts: unknown) => boolean;
352
+ command: (projectId: unknown, opts: unknown) => string;
353
+ why: string;
354
+ };
355
+ "escalations.ackWithToken": {
356
+ command: () => string;
357
+ why: string;
358
+ };
359
+ "ci.exchangeToken": {
360
+ command: () => string;
361
+ why: string;
362
+ };
363
+ };
364
+ export type SecretReturningMethod = keyof typeof SECRET_RETURNING_METHODS;
365
+ /** Dotted path → entry, typed loosely for callers that look methods up by string. */
366
+ export declare const SECRET_GATE_REGISTRY: Readonly<Record<string, SecretGateEntry>>;
367
+ /**
368
+ * Refuse this call before any request when the client may not return
369
+ * secrets. The first statement of every registered method. The command is
370
+ * built only on refusal, so the check costs nothing on the permissive path.
371
+ */
372
+ export declare function gateSecret(client: {
373
+ readonly capabilities?: Readonly<Client["capabilities"]>;
374
+ assertSecretReturn?: Client["assertSecretReturn"];
375
+ }, method: SecretReturningMethod, ...args: Args): void;
376
+ export {};
377
+ //# sourceMappingURL=secret-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-gate.d.ts","sourceRoot":"","sources":["../src/secret-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * The secret gate: every SDK method whose result carries a one-time secret the
3
+ * caller would otherwise receive (a grant key, a Handoff or Invite Key, a Room
4
+ * Invite Key, project credentials, a private key, a Lightning pairing, a
5
+ * sign-in session or write-approval token), or whose input IS such a bearer
6
+ * secret, calls {@link gateSecret} as its first statement. On a client whose
7
+ * `capabilities.returnSecrets` is false — the `sandbox` surface an MCP `run`
8
+ * snippet executes on — that call throws `SECRET_REQUIRES_CLI` before any
9
+ * request, naming the exact CLI command for the same operation. On every
10
+ * other surface it is a no-op.
11
+ *
12
+ * The gate is the method itself, keyed on a client capability: there is no
13
+ * tool-name denylist and no path filter anywhere else, so every future door
14
+ * that builds a `sandbox` client inherits it for free.
15
+ *
16
+ * {@link SECRET_RETURNING_METHODS} is the registry: one entry per gated
17
+ * method (by its dotted path from the client root), with the command builder
18
+ * and, for a method that carries a secret only when a particular option is
19
+ * supplied, the predicate that says so. `sdk/src/node/secret-gate.test.ts`
20
+ * owns the inventory: it fails when a method's types carry a secret-named
21
+ * field and no entry names it, and when a registered method reaches the
22
+ * network on a `sandbox` client.
23
+ *
24
+ * A command never embeds a secret value: where the input is the secret, the
25
+ * command carries its placeholder (`<kgh1_…>`), never the key.
26
+ */
27
+ import { SecretRequiresCliError } from "./errors.js";
28
+ const str = (v) => (typeof v === "string" && v.trim() ? v.trim() : null);
29
+ const obj = (v) => (v && typeof v === "object" ? v : {});
30
+ /** Quote a shell word only when it needs it. */
31
+ const word = (v) => (/^[A-Za-z0-9_./:=@+,-]+$/.test(v) ? v : `'${v.replaceAll("'", "'\\''")}'`);
32
+ /** A caller-supplied value as a shell word, or the placeholder (never quoted) when absent. */
33
+ const arg = (v, placeholder) => {
34
+ const s = str(v);
35
+ return s ? word(s) : placeholder;
36
+ };
37
+ const projectFlag = (projectId) => {
38
+ const id = str(projectId);
39
+ return id ? ` --project ${word(id)}` : "";
40
+ };
41
+ const orgFlag = (orgId) => {
42
+ const id = str(orgId);
43
+ return id ? ` --org ${word(id)}` : "";
44
+ };
45
+ const vaultFlags = (opts) => {
46
+ const o = obj(opts);
47
+ const repo = str(o.repo_id);
48
+ return `${projectFlag(o.project_id)}${repo ? ` --repo ${word(repo)}` : ""}`;
49
+ };
50
+ const hasToken = (opts) => Boolean(str(obj(opts).token));
51
+ /** A wallet name only when it is plainly one; anything else (a pasted key) becomes the placeholder. */
52
+ const walletName = (v) => {
53
+ const s = str(v);
54
+ return s && s.length <= 40 && /^[a-z0-9][a-z0-9_-]*$/.test(s) ? s : "<name>";
55
+ };
56
+ const SIGN_IN_WHY = "A sign-in session token is a person's credential; the CLI holds it for them.";
57
+ const PROJECT_KEYS_WHY = "Project keys are credentials; the CLI stores them in the local key cache without handing them to a snippet.";
58
+ /**
59
+ * Every gated method, by its dotted path from the client root. The command is
60
+ * the CLI line for the same operation; the drift test calls each one on a
61
+ * `sandbox` client and requires the refusal before any request.
62
+ */
63
+ export const SECRET_RETURNING_METHODS = {
64
+ // ── grants: a grant key's bearer prints once ────────────────────────────
65
+ "grants.create": {
66
+ when: (_projectId, input) => obj(input).key != null && obj(input).key !== false,
67
+ command: (projectId, input) => {
68
+ const i = obj(input);
69
+ return `run402 grants create ${arg(i.wallet, "<wallet>")} --capability ${arg(i.capability, "<capability>")} --key${projectFlag(projectId)}`;
70
+ },
71
+ why: "A grant key's bearer is returned once; the CLI prints it to the person who will hand it on.",
72
+ },
73
+ "grants.createKey": {
74
+ command: (projectId) => `run402 grants create <wallet> --capability <capability> --key${projectFlag(projectId)}`,
75
+ why: "A grant key's bearer is returned once; the CLI mints keys by issuing the grant with --key.",
76
+ },
77
+ "grants.rotateKey": {
78
+ command: (projectId, keyId) => `run402 grants rotate-key ${arg(keyId, "<key_id>")}${projectFlag(projectId)}`,
79
+ why: "The rotated grant key's bearer is returned once; the CLI prints it to the person who will hand it on.",
80
+ },
81
+ // ── KyGit: Handoff and Invite Keys ───────────────────────────────────────
82
+ "repos.handoff": { command: (opts) => `run402 repos handoff${vaultFlags(opts)}` },
83
+ "repos.invite": {
84
+ command: (opts) => {
85
+ const room = str(obj(opts).roomKey);
86
+ return `run402 repos invite${vaultFlags(opts)}${room ? ` --room ${word(room)}` : ""}`;
87
+ },
88
+ },
89
+ "repos.resume": { command: () => "run402 repos resume <kgh1_…>", why: "A Handoff Key is a bearer secret; redeem it from the CLI so it never enters a snippet." },
90
+ "repos.join": { command: () => "run402 repos join <kgi1_…>", why: "An Invite Key is a bearer secret; redeem it from the CLI so it never enters a snippet." },
91
+ // ── rooms: Room Invite Keys ──────────────────────────────────────────────
92
+ "rooms.invite": {
93
+ command: (orgId, roomKey) => {
94
+ const room = str(roomKey);
95
+ return `run402 rooms invite${orgFlag(orgId)}${room ? ` --room ${word(room)}` : ""}`;
96
+ },
97
+ },
98
+ "rooms.join": { command: () => "run402 rooms join <kri1_…>", why: "A Room Invite Key is a bearer secret; redeem it from the CLI so it never enters a snippet." },
99
+ // ── projects and their credentials ───────────────────────────────────────
100
+ "projects.provision": {
101
+ command: (opts) => {
102
+ const o = obj(opts);
103
+ const name = str(o.name);
104
+ const tier = str(o.tier);
105
+ return `run402 projects provision${tier ? ` --tier ${word(tier)}` : ""}${name ? ` --name ${word(name)}` : ""}`;
106
+ },
107
+ why: PROJECT_KEYS_WHY,
108
+ },
109
+ "projects.list": {
110
+ when: (opts) => hasToken(opts),
111
+ command: () => "run402 projects list --all",
112
+ why: SIGN_IN_WHY,
113
+ },
114
+ "projects.info": { command: (id) => `run402 credentials project-keys status${projectFlag(id)}`, why: PROJECT_KEYS_WHY },
115
+ "projects.keys": { command: (id) => `run402 credentials project-keys export${projectFlag(id)} --reveal`, why: PROJECT_KEYS_WHY },
116
+ "credentials.projectKeys.import": {
117
+ command: (projectId) => `run402 credentials project-keys import${projectFlag(projectId)} --service-key-stdin`,
118
+ why: PROJECT_KEYS_WHY,
119
+ },
120
+ "credentials.projectKeys.export": { command: (projectId) => `run402 credentials project-keys export${projectFlag(projectId)} --reveal`, why: PROJECT_KEYS_WHY },
121
+ "credentials.issue": {
122
+ command: (projectId, input) => {
123
+ const i = obj(input);
124
+ return `run402 credentials issue --kind ${arg(i.kind, "<anon|service>")} --name ${arg(i.name, "<name>")}${projectFlag(projectId)}`;
125
+ },
126
+ why: "A project credential's secret is returned once.",
127
+ },
128
+ "credentials.rotate": {
129
+ command: (projectId, credentialId) => `run402 credentials rotate ${arg(credentialId, "<credential_id>")}${projectFlag(projectId)}`,
130
+ why: "The rotated credential's secret is returned once.",
131
+ },
132
+ "credentials.mintToken": {
133
+ command: (projectId, opts) => {
134
+ const kind = str(obj(opts).kind);
135
+ return `run402 credentials token${projectFlag(projectId)}${kind ? ` --kind ${word(kind)}` : ""}`;
136
+ },
137
+ why: "A project token is a bearer credential.",
138
+ },
139
+ "apps.fork": {
140
+ command: (opts) => {
141
+ const o = obj(opts);
142
+ const sub = str(o.subdomain);
143
+ return `run402 apps fork ${arg(o.versionId, "<version_id>")} ${arg(o.name, "<name>")}${sub ? ` --subdomain ${word(sub)}` : ""}`;
144
+ },
145
+ why: PROJECT_KEYS_WHY,
146
+ },
147
+ "branches.create": { command: (projectId) => `run402 branches create${projectFlag(projectId)}`, why: PROJECT_KEYS_WHY },
148
+ "admin.transfers.initiate": {
149
+ when: (input) => Boolean(str(obj(input).toOrgId)),
150
+ command: (input) => {
151
+ const i = obj(input);
152
+ return `run402 transfer init --to-org ${arg(i.toOrgId, "<org_id>")}${projectFlag(i.projectId)}`;
153
+ },
154
+ why: PROJECT_KEYS_WHY,
155
+ },
156
+ "admin.transfers.accept": {
157
+ command: (transferId) => `run402 transfer accept ${arg(transferId, "<transfer_id>")}`,
158
+ why: PROJECT_KEYS_WHY,
159
+ },
160
+ "admin.rotateWebhookSecret": {
161
+ command: () => "run402 webhook-secret rotate",
162
+ why: "The new webhook signing secret is returned once.",
163
+ },
164
+ // ── the local wallet ─────────────────────────────────────────────────────
165
+ "wallets.create": {
166
+ command: (name) => (str(name) ? `run402 wallets new ${walletName(name)}` : "run402 init"),
167
+ why: "Creating a wallet writes a private key; the CLI creates wallets for a person.",
168
+ },
169
+ "wallets.import": {
170
+ command: (name) => `run402 wallets import ${walletName(name)} --key <path|->`,
171
+ why: "Importing a wallet hands over a private key; read it from a file or stdin in the CLI, never from a snippet.",
172
+ },
173
+ "agent.lightningWallet.mint": { command: () => "run402 init lightning", why: "The Lightning wallet's pairing secret is returned once." },
174
+ "agent.lightningWallet.get": { command: () => "run402 wallets lightning status", why: "The first read of an active Lightning wallet hands out its pairing secret." },
175
+ "agent.lightningWallet.waitForActive": { command: () => "run402 init lightning", why: "The first read of an active Lightning wallet hands out its pairing secret." },
176
+ "init": {
177
+ when: (opts) => obj(opts).rail === "lightning",
178
+ command: () => "run402 init lightning",
179
+ why: "The Lightning wallet's pairing secret is returned once and stored beside the wallet key.",
180
+ },
181
+ // ── actions that provision and hand back project keys ────────────────────
182
+ "actions.run": {
183
+ when: (input) => obj(input).type !== "tier.set",
184
+ command: (input) => (obj(input).type === "projects.provision" ? "run402 projects provision" : "run402 up"),
185
+ why: "up and project provisioning hand back project keys; run them from the CLI or the MCP up tool.",
186
+ },
187
+ "actions.up": { command: () => "run402 up", why: "up provisions projects and handles their keys; run it from the CLI or the MCP up tool." },
188
+ // ── a person's sign-in session and write approvals ───────────────────────
189
+ "session.exchangeCliToken": { command: () => "run402 login", why: SIGN_IN_WHY },
190
+ "session.devicePoll": { command: () => "run402 login --device", why: SIGN_IN_WHY },
191
+ "session.verifyEmail": { command: () => "run402 login", why: SIGN_IN_WHY },
192
+ "session.passkeyVerify": { command: () => "run402 login", why: SIGN_IN_WHY },
193
+ "session.consumeRecoveryCode": { command: () => "run402 login", why: SIGN_IN_WHY },
194
+ "session.whoami": { when: hasToken, command: () => "run402 whoami", why: SIGN_IN_WHY },
195
+ "session.refresh": { command: () => "run402 login", why: SIGN_IN_WHY },
196
+ "session.revoke": { when: hasToken, command: () => "run402 logout", why: SIGN_IN_WHY },
197
+ "session.enrollPasskeyOptions": { when: hasToken, command: () => "run402 login", why: SIGN_IN_WHY },
198
+ "session.enrollPasskeyVerify": { when: hasToken, command: () => "run402 login", why: SIGN_IN_WHY },
199
+ "session.stepUpOptions": { when: hasToken, command: () => "run402 login", why: SIGN_IN_WHY },
200
+ "session.stepUpVerify": { when: hasToken, command: () => "run402 login", why: SIGN_IN_WHY },
201
+ "session.issueRecoveryCodes": { command: () => "run402 login", why: "Recovery codes are shown once." },
202
+ "session.listAuthenticators": { when: hasToken, command: () => "run402 whoami", why: SIGN_IN_WHY },
203
+ "session.revokeAuthenticator": { when: hasToken, command: () => "run402 login", why: SIGN_IN_WHY },
204
+ "session.sourceAccessWrappers": { when: hasToken, command: () => "run402 repos recovery-bundle", why: SIGN_IN_WHY },
205
+ "session.sourceAccessRecoveryBundle": { when: hasToken, command: () => "run402 repos recovery-bundle", why: SIGN_IN_WHY },
206
+ "writeApproval.requestChallenge": { command: () => "run402 approve", why: "A write approval is a person's passkey-signed credential." },
207
+ "writeApproval.exchangeClaimCode": { command: () => "run402 approve", why: "A write approval is a person's passkey-signed credential." },
208
+ "me.overview": { when: hasToken, command: () => "run402 orgs list", why: SIGN_IN_WHY },
209
+ "me.status": { when: hasToken, command: () => "run402 whoami", why: SIGN_IN_WHY },
210
+ "orgs.adopt.challenge": { when: hasToken, command: () => "run402 orgs adopt", why: SIGN_IN_WHY },
211
+ "orgs.adopt.submit": { when: hasToken, command: () => "run402 orgs adopt", why: SIGN_IN_WHY },
212
+ "admin.channels.connectTelegram": { when: (_opts, proofs) => hasToken(proofs), command: () => "run402 contacts connect telegram", why: SIGN_IN_WHY },
213
+ "admin.channels.revokeTelegram": { when: (_id, proofs) => hasToken(proofs), command: (id) => `run402 contacts rm ${arg(id, "<binding_id>")}`, why: SIGN_IN_WHY },
214
+ "admin.rules.create": { when: (_i, proofs) => hasToken(proofs), command: () => "run402 subscriptions add", why: SIGN_IN_WHY },
215
+ "admin.rules.update": { when: (_id, _p, proofs) => hasToken(proofs), command: () => "run402 subscriptions add", why: SIGN_IN_WHY },
216
+ "admin.rules.delete": { when: (_id, proofs) => hasToken(proofs), command: (id) => `run402 subscriptions rm ${arg(id, "<rule_id>")}`, why: SIGN_IN_WHY },
217
+ "admin.setNotificationPreferences": { when: (_p, proofs) => hasToken(proofs), command: () => "run402 contacts preferences", why: SIGN_IN_WHY },
218
+ // ── project end users' session tokens (the project's own auth) ───────────
219
+ "auth.verifyMagicLink": { command: (projectId) => `run402 auth verify --token <token>${projectFlag(projectId)}`, why: "The end user's access token is returned once." },
220
+ "auth.verify": { command: (projectId) => `run402 auth verify --token <token>${projectFlag(projectId)}`, why: "The end user's access token is returned once." },
221
+ "auth.verifyEmailCode": {
222
+ command: (projectId, opts) => {
223
+ const challenge = str(obj(opts).challengeId);
224
+ return `run402 auth verify --challenge-id ${word(challenge ?? "<challenge_id>")} --code <code>${projectFlag(projectId)}`;
225
+ },
226
+ why: "The end user's access token is returned once.",
227
+ },
228
+ "auth.setUserPassword": { command: (projectId) => `run402 auth set-password --token <bearer> --new <password>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
229
+ "auth.setPassword": { command: (projectId) => `run402 auth set-password --token <bearer> --new <password>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
230
+ "auth.createPasskeyRegistrationOptions": { command: (projectId) => `run402 auth passkey-register-options --token <bearer> --app-origin <origin>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
231
+ "auth.verifyPasskeyRegistration": { command: (projectId) => `run402 auth passkey-register-verify --token <bearer>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
232
+ "auth.verifyPasskeyLogin": { command: (projectId) => `run402 auth passkey-login-verify${projectFlag(projectId)}`, why: "The end user's access token is returned once." },
233
+ "auth.listPasskeys": { command: (projectId) => `run402 auth passkeys --token <bearer>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
234
+ "auth.deletePasskey": { command: (projectId) => `run402 auth delete-passkey --token <bearer>${projectFlag(projectId)}`, why: "An end user's access token is a bearer credential." },
235
+ "live.changes": {
236
+ when: (_projectId, opts) => obj(opts).as === "user",
237
+ command: (projectId, opts) => `run402 live --tables ${arg((obj(opts).tables ?? []).join(","), "<a,b>")}${projectFlag(projectId)}`,
238
+ why: "An end user's access token is a bearer credential.",
239
+ },
240
+ "live.subscribe": {
241
+ when: (_projectId, opts) => obj(opts).as === "user",
242
+ command: (projectId, opts) => `run402 live --tables ${arg((obj(opts).tables ?? []).join(","), "<a,b>")}${projectFlag(projectId)}`,
243
+ why: "An end user's access token is a bearer credential.",
244
+ },
245
+ // ── bearer inputs from outside ───────────────────────────────────────────
246
+ "escalations.ackWithToken": {
247
+ command: () => "run402 escalations ack <escalation_id>",
248
+ why: "An acknowledgement token is a bearer secret from a notification; acknowledge by id instead.",
249
+ },
250
+ "ci.exchangeToken": {
251
+ command: () => "run402 ci link github",
252
+ why: "The GitHub OIDC exchange mints a Run402 CI session inside GitHub Actions; link the repository from the CLI.",
253
+ },
254
+ };
255
+ /** Dotted path → entry, typed loosely for callers that look methods up by string. */
256
+ export const SECRET_GATE_REGISTRY = SECRET_RETURNING_METHODS;
257
+ /**
258
+ * Refuse this call before any request when the client may not return
259
+ * secrets. The first statement of every registered method. The command is
260
+ * built only on refusal, so the check costs nothing on the permissive path.
261
+ */
262
+ export function gateSecret(client, method, ...args) {
263
+ if (client.capabilities?.returnSecrets !== false)
264
+ return;
265
+ const entry = SECRET_GATE_REGISTRY[method];
266
+ if (entry.when && !entry.when(...args))
267
+ return;
268
+ const refusal = { command: entry.command(...args), ...(entry.why ? { why: entry.why } : {}) };
269
+ if (client.assertSecretReturn)
270
+ client.assertSecretReturn(refusal);
271
+ throw new SecretRequiresCliError(refusal.command, refusal.why);
272
+ }
273
+ //# sourceMappingURL=secret-gate.js.map