run402 4.96.0 → 4.98.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 (225) hide show
  1. package/README.md +3 -3
  2. package/cli.mjs +1 -7
  3. package/core-dist/binding-file.js +28 -1
  4. package/core-dist/wallet.js +3 -3
  5. package/lib/auth.mjs +1 -2
  6. package/lib/buzz-doctor.mjs +21 -806
  7. package/lib/buzz-doctor.test.mjs +7 -6
  8. package/lib/buzz.mjs +1 -1
  9. package/lib/buzz.test.mjs +13 -2
  10. package/lib/command-manifest.mjs +3 -6
  11. package/lib/credentials.mjs +4 -4
  12. package/lib/deploy-v2.mjs +27 -27
  13. package/lib/doctor.mjs +72 -811
  14. package/lib/errors.mjs +1 -1
  15. package/lib/events.mjs +1 -1
  16. package/lib/grants.mjs +148 -46
  17. package/lib/init.mjs +35 -576
  18. package/lib/logs.mjs +1 -1
  19. package/lib/org-context.mjs +39 -376
  20. package/lib/orgs.mjs +22 -106
  21. package/lib/projects.mjs +2 -3
  22. package/lib/repos.mjs +6 -6
  23. package/lib/rooms.mjs +1 -2
  24. package/lib/sdk-errors.mjs +26 -0
  25. package/lib/sites.mjs +5 -5
  26. package/lib/status.mjs +14 -154
  27. package/lib/up.mjs +1 -2
  28. package/lib/vault-scaffold.mjs +2 -3
  29. package/lib/vault-target.mjs +14 -141
  30. package/lib/wallet-context.mjs +61 -227
  31. package/lib/wallets.mjs +47 -310
  32. package/package.json +1 -2
  33. package/sdk/core-dist/binding-file.js +28 -1
  34. package/sdk/core-dist/wallet.js +3 -3
  35. package/sdk/dist/errors.d.ts +25 -3
  36. package/sdk/dist/errors.d.ts.map +1 -1
  37. package/sdk/dist/errors.js +46 -4
  38. package/sdk/dist/errors.js.map +1 -1
  39. package/sdk/dist/grant-key-credentials.d.ts +38 -0
  40. package/sdk/dist/grant-key-credentials.d.ts.map +1 -0
  41. package/sdk/dist/grant-key-credentials.js +42 -0
  42. package/sdk/dist/grant-key-credentials.js.map +1 -0
  43. package/sdk/dist/index.d.ts +25 -17
  44. package/sdk/dist/index.d.ts.map +1 -1
  45. package/sdk/dist/index.js +18 -14
  46. package/sdk/dist/index.js.map +1 -1
  47. package/sdk/dist/kernel.d.ts +34 -0
  48. package/sdk/dist/kernel.d.ts.map +1 -1
  49. package/sdk/dist/kernel.js +15 -1
  50. package/sdk/dist/kernel.js.map +1 -1
  51. package/sdk/dist/namespaces/admin.d.ts.map +1 -1
  52. package/sdk/dist/namespaces/admin.js +8 -0
  53. package/sdk/dist/namespaces/admin.js.map +1 -1
  54. package/sdk/dist/namespaces/agent.d.ts +2 -2
  55. package/sdk/dist/namespaces/agent.d.ts.map +1 -1
  56. package/sdk/dist/namespaces/agent.js +4 -0
  57. package/sdk/dist/namespaces/agent.js.map +1 -1
  58. package/sdk/dist/namespaces/agent.types.d.ts +5 -0
  59. package/sdk/dist/namespaces/agent.types.d.ts.map +1 -1
  60. package/sdk/dist/namespaces/apps.d.ts.map +1 -1
  61. package/sdk/dist/namespaces/apps.js +2 -0
  62. package/sdk/dist/namespaces/apps.js.map +1 -1
  63. package/sdk/dist/namespaces/auth.d.ts.map +1 -1
  64. package/sdk/dist/namespaces/auth.js +9 -0
  65. package/sdk/dist/namespaces/auth.js.map +1 -1
  66. package/sdk/dist/namespaces/billing.d.ts +1 -1
  67. package/sdk/dist/namespaces/billing.js +1 -1
  68. package/sdk/dist/namespaces/branches.d.ts.map +1 -1
  69. package/sdk/dist/namespaces/branches.js +2 -0
  70. package/sdk/dist/namespaces/branches.js.map +1 -1
  71. package/sdk/dist/namespaces/buzz.js +1 -1
  72. package/sdk/dist/namespaces/buzz.js.map +1 -1
  73. package/sdk/dist/namespaces/ci.d.ts.map +1 -1
  74. package/sdk/dist/namespaces/ci.js +2 -0
  75. package/sdk/dist/namespaces/ci.js.map +1 -1
  76. package/sdk/dist/namespaces/credentials.d.ts +4 -27
  77. package/sdk/dist/namespaces/credentials.d.ts.map +1 -1
  78. package/sdk/dist/namespaces/credentials.js +33 -4
  79. package/sdk/dist/namespaces/credentials.js.map +1 -1
  80. package/sdk/dist/namespaces/deploy.js +5 -5
  81. package/sdk/dist/namespaces/deploy.js.map +1 -1
  82. package/sdk/dist/namespaces/domains.d.ts +1 -1
  83. package/sdk/dist/namespaces/domains.js +1 -1
  84. package/sdk/dist/namespaces/errors.d.ts +1 -1
  85. package/sdk/dist/namespaces/errors.js +2 -2
  86. package/sdk/dist/namespaces/escalations.d.ts +2 -2
  87. package/sdk/dist/namespaces/escalations.d.ts.map +1 -1
  88. package/sdk/dist/namespaces/escalations.js +4 -2
  89. package/sdk/dist/namespaces/escalations.js.map +1 -1
  90. package/sdk/dist/namespaces/escalations.types.d.ts +3 -3
  91. package/sdk/dist/namespaces/escalations.types.d.ts.map +1 -1
  92. package/sdk/dist/namespaces/events.d.ts +1 -1
  93. package/sdk/dist/namespaces/events.js +1 -1
  94. package/sdk/dist/namespaces/functions.js +1 -1
  95. package/sdk/dist/namespaces/functions.js.map +1 -1
  96. package/sdk/dist/namespaces/grants.d.ts +43 -9
  97. package/sdk/dist/namespaces/grants.d.ts.map +1 -1
  98. package/sdk/dist/namespaces/grants.js +103 -10
  99. package/sdk/dist/namespaces/grants.js.map +1 -1
  100. package/sdk/dist/namespaces/grants.types.d.ts +120 -15
  101. package/sdk/dist/namespaces/grants.types.d.ts.map +1 -1
  102. package/sdk/dist/namespaces/grants.types.js +12 -3
  103. package/sdk/dist/namespaces/grants.types.js.map +1 -1
  104. package/sdk/dist/namespaces/identity-links.types.d.ts +2 -2
  105. package/sdk/dist/namespaces/identity-links.types.d.ts.map +1 -1
  106. package/sdk/dist/namespaces/live.d.ts +0 -16
  107. package/sdk/dist/namespaces/live.d.ts.map +1 -1
  108. package/sdk/dist/namespaces/live.js +19 -0
  109. package/sdk/dist/namespaces/live.js.map +1 -1
  110. package/sdk/dist/namespaces/me.d.ts.map +1 -1
  111. package/sdk/dist/namespaces/me.js +3 -0
  112. package/sdk/dist/namespaces/me.js.map +1 -1
  113. package/sdk/dist/namespaces/org.d.ts +1 -1
  114. package/sdk/dist/namespaces/org.d.ts.map +1 -1
  115. package/sdk/dist/namespaces/org.js +4 -1
  116. package/sdk/dist/namespaces/org.js.map +1 -1
  117. package/sdk/dist/namespaces/projects.d.ts +1 -1
  118. package/sdk/dist/namespaces/projects.d.ts.map +1 -1
  119. package/sdk/dist/namespaces/projects.js +6 -1
  120. package/sdk/dist/namespaces/projects.js.map +1 -1
  121. package/sdk/dist/namespaces/repos.d.ts.map +1 -1
  122. package/sdk/dist/namespaces/repos.js +7 -2
  123. package/sdk/dist/namespaces/repos.js.map +1 -1
  124. package/sdk/dist/namespaces/rooms.d.ts +3 -3
  125. package/sdk/dist/namespaces/rooms.d.ts.map +1 -1
  126. package/sdk/dist/namespaces/rooms.js +6 -3
  127. package/sdk/dist/namespaces/rooms.js.map +1 -1
  128. package/sdk/dist/namespaces/session.d.ts.map +1 -1
  129. package/sdk/dist/namespaces/session.js +18 -0
  130. package/sdk/dist/namespaces/session.js.map +1 -1
  131. package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
  132. package/sdk/dist/namespaces/transfers.js +3 -0
  133. package/sdk/dist/namespaces/transfers.js.map +1 -1
  134. package/sdk/dist/namespaces/wallets.d.ts.map +1 -1
  135. package/sdk/dist/namespaces/wallets.js +2 -0
  136. package/sdk/dist/namespaces/wallets.js.map +1 -1
  137. package/sdk/dist/namespaces/write-approval.d.ts.map +1 -1
  138. package/sdk/dist/namespaces/write-approval.js +3 -0
  139. package/sdk/dist/namespaces/write-approval.js.map +1 -1
  140. package/sdk/dist/node/actions-node.d.ts.map +1 -1
  141. package/sdk/dist/node/actions-node.js +3 -0
  142. package/sdk/dist/node/actions-node.js.map +1 -1
  143. package/sdk/dist/node/buzz-doctor-contract.d.ts +155 -0
  144. package/sdk/dist/node/buzz-doctor-contract.d.ts.map +1 -0
  145. package/sdk/dist/node/buzz-doctor-contract.js +385 -0
  146. package/sdk/dist/node/buzz-doctor-contract.js.map +1 -0
  147. package/sdk/dist/node/buzz-doctor.d.ts +155 -0
  148. package/sdk/dist/node/buzz-doctor.d.ts.map +1 -0
  149. package/sdk/dist/node/buzz-doctor.js +810 -0
  150. package/sdk/dist/node/buzz-doctor.js.map +1 -0
  151. package/sdk/dist/node/credentials.d.ts +18 -13
  152. package/sdk/dist/node/credentials.d.ts.map +1 -1
  153. package/sdk/dist/node/credentials.js +13 -13
  154. package/sdk/dist/node/credentials.js.map +1 -1
  155. package/sdk/dist/node/diagnostics.d.ts +45 -0
  156. package/sdk/dist/node/diagnostics.d.ts.map +1 -0
  157. package/sdk/dist/node/diagnostics.js +67 -0
  158. package/sdk/dist/node/diagnostics.js.map +1 -0
  159. package/sdk/dist/node/doctor.d.ts +101 -0
  160. package/sdk/dist/node/doctor.d.ts.map +1 -0
  161. package/sdk/dist/node/doctor.js +618 -0
  162. package/sdk/dist/node/doctor.js.map +1 -0
  163. package/sdk/dist/node/index.d.ts +61 -9
  164. package/sdk/dist/node/index.d.ts.map +1 -1
  165. package/sdk/dist/node/index.js +37 -2
  166. package/sdk/dist/node/index.js.map +1 -1
  167. package/sdk/dist/node/init.d.ts +137 -0
  168. package/sdk/dist/node/init.d.ts.map +1 -0
  169. package/sdk/dist/node/init.js +507 -0
  170. package/sdk/dist/node/init.js.map +1 -0
  171. package/sdk/dist/node/lightning-wallet.d.ts +61 -0
  172. package/sdk/dist/node/lightning-wallet.d.ts.map +1 -0
  173. package/sdk/dist/node/lightning-wallet.js +126 -0
  174. package/sdk/dist/node/lightning-wallet.js.map +1 -0
  175. package/sdk/dist/node/local-actions.d.ts +23 -0
  176. package/sdk/dist/node/local-actions.d.ts.map +1 -0
  177. package/sdk/dist/node/local-actions.js +38 -0
  178. package/sdk/dist/node/local-actions.js.map +1 -0
  179. package/sdk/dist/node/org-context.d.ts +169 -0
  180. package/sdk/dist/node/org-context.d.ts.map +1 -0
  181. package/sdk/dist/node/org-context.js +403 -0
  182. package/sdk/dist/node/org-context.js.map +1 -0
  183. package/sdk/dist/node/status.d.ts +62 -0
  184. package/sdk/dist/node/status.d.ts.map +1 -0
  185. package/sdk/dist/node/status.js +132 -0
  186. package/sdk/dist/node/status.js.map +1 -0
  187. package/sdk/dist/node/vault-target.d.ts +49 -0
  188. package/sdk/dist/node/vault-target.d.ts.map +1 -0
  189. package/sdk/dist/node/vault-target.js +109 -0
  190. package/sdk/dist/node/vault-target.js.map +1 -0
  191. package/sdk/dist/node/wallets.d.ts +242 -0
  192. package/sdk/dist/node/wallets.d.ts.map +1 -0
  193. package/sdk/dist/node/wallets.js +484 -0
  194. package/sdk/dist/node/wallets.js.map +1 -0
  195. package/sdk/dist/project-auth-classification.d.ts +8 -8
  196. package/sdk/dist/project-auth-classification.d.ts.map +1 -1
  197. package/sdk/dist/project-auth-classification.js +7 -7
  198. package/sdk/dist/project-auth-classification.js.map +1 -1
  199. package/sdk/dist/scoped.d.ts +6 -14
  200. package/sdk/dist/scoped.d.ts.map +1 -1
  201. package/sdk/dist/scoped.js +10 -21
  202. package/sdk/dist/scoped.js.map +1 -1
  203. package/sdk/dist/secret-gate.d.ts +377 -0
  204. package/sdk/dist/secret-gate.d.ts.map +1 -0
  205. package/sdk/dist/secret-gate.js +273 -0
  206. package/sdk/dist/secret-gate.js.map +1 -0
  207. package/vault-surface.json +1 -1
  208. package/fixtures/buzz-v0.5.2-cli-capabilities.json +0 -92
  209. package/fixtures/run402-buzz-doctor-v1-contract.json +0 -140
  210. package/lib/buzz-doctor-contract.mjs +0 -97
  211. package/lib/buzz-doctor-contract.test.mjs +0 -134
  212. package/lib/delegates.mjs +0 -189
  213. package/lib/lightning-wallet.mjs +0 -115
  214. package/sdk/dist/delegate-credentials.d.ts +0 -37
  215. package/sdk/dist/delegate-credentials.d.ts.map +0 -1
  216. package/sdk/dist/delegate-credentials.js +0 -41
  217. package/sdk/dist/delegate-credentials.js.map +0 -1
  218. package/sdk/dist/namespaces/delegates.d.ts +0 -50
  219. package/sdk/dist/namespaces/delegates.d.ts.map +0 -1
  220. package/sdk/dist/namespaces/delegates.js +0 -99
  221. package/sdk/dist/namespaces/delegates.js.map +0 -1
  222. package/sdk/dist/namespaces/delegates.types.d.ts +0 -88
  223. package/sdk/dist/namespaces/delegates.types.d.ts.map +0 -1
  224. package/sdk/dist/namespaces/delegates.types.js +0 -10
  225. package/sdk/dist/namespaces/delegates.types.js.map +0 -1
package/lib/errors.mjs CHANGED
@@ -110,7 +110,7 @@ Exit codes (the promote gate — only when --fail-on-new is set):
110
110
 
111
111
  Auth:
112
112
  The addressed project's own service_key when it is cached locally; otherwise
113
- your wallet / session / delegate, which the gateway authorizes with
113
+ your wallet / session / grant key, which the gateway authorizes with
114
114
  project.read — an org member or teammate agent needs no project key. A key
115
115
  for project A requesting project B's errors gets 403 (never a 404 that
116
116
  leaks existence). Read-only; never lifecycle-gated.
package/lib/events.mjs CHANGED
@@ -95,7 +95,7 @@ Event shape:
95
95
 
96
96
  Auth:
97
97
  --project: the project's own service_key, your SIWX wallet, a control-plane
98
- session, or a scoped delegate with project.read.
98
+ session, or a grant key with project.read.
99
99
  --org: wallet / control-plane session with an active org membership
100
100
  (a project service_key cannot read sibling projects' events).
101
101
  The feed is read-only and never lifecycle-gated: a frozen project's feed
package/lib/grants.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getSdk } from "./sdk.mjs";
2
- import { reportSdkError, parseFlagJson } from "./sdk-errors.mjs";
2
+ import { reportSdkError, parseFlagJson, fail } from "./sdk-errors.mjs";
3
3
  import {
4
4
  normalizeArgv,
5
5
  assertKnownFlags,
@@ -9,114 +9,213 @@ import {
9
9
  failUnknownSubcommand,
10
10
  } from "./argparse.mjs";
11
11
 
12
- const HELP = `run402 grants — per-project capability grants (agent/CI principals)
12
+ const HELP = `run402 grants — per-project capability grants and their grant keys
13
13
 
14
14
  Usage:
15
15
  run402 grants <subcommand> [args...]
16
16
 
17
17
  Subcommands:
18
- create <wallet> --capability <cap> [--project <project_id>] [--policy <json>] [--expires <iso8601>]
19
- Issue a capability grant (owner of the project's org)
18
+ create <wallet> --capability <cap> [--project <project_id>] [--policy <json>] [--expires-at <iso8601>]
19
+ [--key [--kind <kind>] [--scope <json>] [--spend-cap <json>]]
20
+ Issue a grant; with --key also mint its first
21
+ grant key (the token is printed ONCE)
22
+ list [--project <project_id>] List grants with their keys nested (never tokens)
20
23
  revoke <grant_id> [--project <project_id>]
21
- Revoke a capability grant
22
-
23
- Legacy (still supported):
24
- run402 grants create <project_id> <wallet> <capability> [...]
25
- run402 grants revoke <project_id> <grant_id>
24
+ Revoke a grant and every key minted against it
25
+ revoke-key <key_id> [--project <project_id>]
26
+ Revoke one grant key; the grant stays
27
+ rotate-key <key_id> [--project <project_id>]
28
+ Replace a lost key; the new token is printed ONCE
26
29
 
27
30
  Notes:
28
- - Grants let a non-member wallet (an agent or CI principal) act on ONE project,
29
- without making it a broad org member. Mutations require owner of the project's org.
31
+ - A grant is the permission row: this wallet may do this capability on this
32
+ project until this date. An agent with its own wallet needs only the grant.
33
+ - A grant key is a credential minted against exactly one grant: narrower than
34
+ it, spend-capped, expiring, revocable on its own, never an owner. Hand it to
35
+ an agent without a wallet: RUN402_GRANT_KEY=<token> run402 deploy ...
36
+ - Every subcommand requires owner of the project's org. Minting a key with a
37
+ sign-in session takes a fresh step-up.
38
+ - The key token is shown ONCE and cannot be read back. Store it immediately;
39
+ if you lose it, 'rotate-key' issues a new one.
30
40
  - capability examples: deploy, functions:write.
31
41
  - JSON in, JSON out.
32
42
 
33
43
  Examples:
34
44
  run402 grants create 0xf39Fd6...92266 --capability deploy --project prj_abc
35
- run402 grants create 0xf39Fd6...92266 --capability functions:write --expires 2026-12-31T00:00:00Z
36
- run402 grants revoke grt_xyz --project prj_abc
45
+ run402 grants create 0x90F3eB...F80a --capability deploy --key --project prj_abc
46
+ run402 grants list --project prj_abc
47
+ run402 grants revoke-key 5845f17b-... --project prj_abc
48
+ run402 grants revoke 1d86452e-... --project prj_abc
37
49
  `;
38
50
 
39
51
  const SUB_HELP = {
40
- create: `run402 grants create — issue a per-project capability grant
52
+ create: `run402 grants create — issue a per-project capability grant, optionally with a grant key
41
53
 
42
54
  Usage:
43
- run402 grants create <wallet> --capability <cap> [--project <project_id>] [--policy <json>] [--expires <iso8601>]
44
-
45
- Legacy (still supported):
46
- run402 grants create <project_id> <wallet> <capability> [options]
55
+ run402 grants create <wallet> --capability <cap> [--project <project_id>] [--policy <json>] [--expires-at <iso8601>]
56
+ [--key [--kind <kind>] [--scope <json>] [--spend-cap <json>]]
47
57
 
48
58
  Arguments:
49
- <wallet> EVM address or named wallet the grant is issued to
59
+ <wallet> EVM address or named wallet the grant is issued to
50
60
 
51
61
  Options:
52
- --project <project_id> Project to grant access to (defaults to the active project)
53
- --capability <cap> e.g. deploy, functions:write (alternative to the legacy positional)
54
- --policy <json> Capability-scoping policy object (gateway-interpreted)
55
- --expires <iso8601> Expiry timestamp; omit for a non-expiring grant
62
+ --project <project_id> Project to grant access to (defaults to the active project)
63
+ --capability <cap> e.g. deploy, functions:write
64
+ --policy <json> Capability-scoping policy object (gateway-interpreted)
65
+ --expires-at <iso8601> Expiry; omit for a non-expiring grant. With --key the
66
+ key takes the same expiry.
67
+ --key Also mint the grant's first grant key in the same
68
+ transaction. Its token is printed ONCE.
69
+ --kind <kind> Key kind (with --key). Default run402_agent_key, the
70
+ only kind that returns a bearer token.
71
+ --scope <json> Key scope (with --key), e.g. {"v":1,"capabilities":["deploy"]}.
72
+ Defaults to the grant's own capability; never wider.
73
+ --spend-cap <json> Key spend cap (with --key), e.g.
74
+ {"v":1,"currency":"usd_micros","per_period":5000000,"period":"month"}
56
75
 
57
76
  Requires you to be an owner of the project's org.
77
+ `,
78
+ list: `run402 grants list — list a project's grants with their grant keys
79
+
80
+ Usage:
81
+ run402 grants list [--project <project_id>]
82
+
83
+ Each grant carries its keys under "keys" (kind, scope, spend cap, expiry,
84
+ revocation). Never returns a token or secret material.
58
85
  `,
59
86
  revoke: `run402 grants revoke — revoke a per-project capability grant
60
87
 
61
88
  Usage:
62
89
  run402 grants revoke <grant_id> [--project <project_id>]
63
90
 
64
- Legacy (still supported):
65
- run402 grants revoke <project_id> <grant_id>
91
+ Revokes the grant and every grant key minted against it. Requires you to be an
92
+ owner of the project's org.
93
+ `,
94
+ "revoke-key": `run402 grants revoke-key — revoke one grant key
66
95
 
96
+ Usage:
97
+ run402 grants revoke-key <key_id> [--project <project_id>]
98
+
99
+ Takes effect for every subsequent request. The grant and its other keys stay.
67
100
  Requires you to be an owner of the project's org.
101
+ `,
102
+ "rotate-key": `run402 grants rotate-key — replace a grant key
103
+
104
+ Usage:
105
+ run402 grants rotate-key <key_id> [--project <project_id>]
106
+
107
+ Revokes the key and mints a fresh one against the same grant with the same
108
+ kind, scope, spend cap and expiry. The NEW token is printed once. Use this when
109
+ a token is lost or possibly exposed.
68
110
  `,
69
111
  };
70
112
 
71
- const CREATE_VALUE_FLAGS = ["--project", "--capability", "--policy", "--expires"];
113
+ const CREATE_VALUE_FLAGS = ["--project", "--capability", "--policy", "--expires-at", "--kind", "--scope", "--spend-cap"];
114
+ const KEY_ONLY_FLAGS = ["--kind", "--scope", "--spend-cap"];
115
+
116
+ function warnTokenOnce(key) {
117
+ if (!key?.token) return;
118
+ console.error("");
119
+ console.error("The grant key token above is shown ONCE and cannot be read back.");
120
+ console.error("Store it now, then use it as: RUN402_GRANT_KEY=<token>");
121
+ }
72
122
 
73
123
  async function create(args) {
74
124
  const a = normalizeArgv(args);
75
- assertKnownFlags(a, [...CREATE_VALUE_FLAGS, "--help", "-h"], CREATE_VALUE_FLAGS);
125
+ assertKnownFlags(a, [...CREATE_VALUE_FLAGS, "--key", "--help", "-h"], CREATE_VALUE_FLAGS);
76
126
  const policyRaw = flagValue(a, "--policy");
77
- const expiresAt = flagValue(a, "--expires");
78
- const capabilityFlag = flagValue(a, "--capability");
127
+ const expiresAt = flagValue(a, "--expires-at") || undefined;
128
+ const capability = flagValue(a, "--capability");
129
+ const wantsKey = a.includes("--key");
130
+ const kind = flagValue(a, "--kind") || undefined;
131
+ const scopeRaw = flagValue(a, "--scope");
132
+ const spendCapRaw = flagValue(a, "--spend-cap");
79
133
  const { projectId, rest } = resolveProjectSelector(a, { valueFlags: CREATE_VALUE_FLAGS });
80
- const expected = capabilityFlag ? 1 : 2;
81
- const pos = requirePositionalCount(rest, CREATE_VALUE_FLAGS, {
82
- min: expected,
83
- max: expected,
84
- command: "run402 grants create <wallet> --capability <cap> [--project <project_id>] [--policy <json>] [--expires <iso8601>]",
85
- missing: capabilityFlag ? "Missing <wallet>." : "Missing <wallet> and/or <capability>.",
134
+ const [wallet] = requirePositionalCount(rest, CREATE_VALUE_FLAGS, {
135
+ min: 1,
136
+ max: 1,
137
+ command: "run402 grants create <wallet> --capability <cap> [--project <project_id>] [--key]",
138
+ missing: "Missing <wallet>.",
86
139
  });
87
- const wallet = pos[0];
88
- const capability = capabilityFlag ?? pos[1];
140
+ if (!capability) {
141
+ fail({
142
+ code: "BAD_USAGE",
143
+ message: "Missing --capability <cap>.",
144
+ hint: "run402 grants create <wallet> --capability deploy [--project <project_id>]",
145
+ });
146
+ }
147
+ if (!wantsKey) {
148
+ const stray = KEY_ONLY_FLAGS.filter((f) => a.includes(f));
149
+ if (stray.length > 0) {
150
+ fail({
151
+ code: "BAD_USAGE",
152
+ message: `${stray.join(", ")} describe a grant key; add --key to mint one.`,
153
+ hint: "run402 grants create <wallet> --capability <cap> --key [--kind <kind>] [--scope <json>] [--spend-cap <json>]",
154
+ });
155
+ }
156
+ }
89
157
  const policy = policyRaw != null ? parseFlagJson("--policy", policyRaw) : undefined;
158
+ let key;
159
+ if (wantsKey) {
160
+ key = {};
161
+ if (kind) key.kind = kind;
162
+ if (scopeRaw != null) key.scope = parseFlagJson("--scope", scopeRaw);
163
+ if (spendCapRaw != null) key.spendCap = parseFlagJson("--spend-cap", spendCapRaw);
164
+ if (expiresAt) key.expiresAt = expiresAt;
165
+ }
90
166
  try {
91
167
  const res = await getSdk().grants.create(projectId, {
92
168
  wallet,
93
169
  capability,
94
170
  policy,
95
- expiresAt: expiresAt || undefined,
171
+ expiresAt,
172
+ key,
96
173
  });
97
174
  console.log(JSON.stringify(res, null, 2));
175
+ warnTokenOnce(res?.key);
98
176
  } catch (err) {
99
177
  reportSdkError(err);
100
178
  }
101
179
  }
102
180
 
103
- async function revoke(args) {
181
+ async function list(args) {
104
182
  const a = normalizeArgv(args);
105
183
  assertKnownFlags(a, ["--project", "--help", "-h"], ["--project"]);
106
184
  const { projectId, rest } = resolveProjectSelector(a, { valueFlags: ["--project"] });
107
- const [grantId] = requirePositionalCount(rest, ["--project"], {
108
- min: 1,
109
- max: 1,
110
- command: "run402 grants revoke <grant_id> [--project <project_id>]",
111
- missing: "Missing <grant_id>.",
185
+ requirePositionalCount(rest, ["--project"], {
186
+ min: 0,
187
+ max: 0,
188
+ command: "run402 grants list [--project <project_id>]",
189
+ missing: "",
112
190
  });
113
191
  try {
114
- console.log(JSON.stringify(await getSdk().grants.revoke(projectId, grantId), null, 2));
192
+ console.log(JSON.stringify(await getSdk().grants.list(projectId), null, 2));
115
193
  } catch (err) {
116
194
  reportSdkError(err);
117
195
  }
118
196
  }
119
197
 
198
+ function oneIdCommand({ verb, idName, method }) {
199
+ return async (args) => {
200
+ const a = normalizeArgv(args);
201
+ assertKnownFlags(a, ["--project", "--help", "-h"], ["--project"]);
202
+ const { projectId, rest } = resolveProjectSelector(a, { valueFlags: ["--project"] });
203
+ const [id] = requirePositionalCount(rest, ["--project"], {
204
+ min: 1,
205
+ max: 1,
206
+ command: `run402 grants ${verb} <${idName}> [--project <project_id>]`,
207
+ missing: `Missing <${idName}>.`,
208
+ });
209
+ try {
210
+ const res = await getSdk().grants[method](projectId, id);
211
+ console.log(JSON.stringify(res, null, 2));
212
+ warnTokenOnce(res?.key);
213
+ } catch (err) {
214
+ reportSdkError(err);
215
+ }
216
+ };
217
+ }
218
+
120
219
  export async function run(sub, args) {
121
220
  if (!sub || sub === "--help" || sub === "-h") {
122
221
  console.log(HELP);
@@ -128,7 +227,10 @@ export async function run(sub, args) {
128
227
  }
129
228
  switch (sub) {
130
229
  case "create": await create(args); break;
131
- case "revoke": await revoke(args); break;
230
+ case "list": await list(args); break;
231
+ case "revoke": await oneIdCommand({ verb: "revoke", idName: "grant_id", method: "revoke" })(args); break;
232
+ case "revoke-key": await oneIdCommand({ verb: "revoke-key", idName: "key_id", method: "revokeKey" })(args); break;
233
+ case "rotate-key": await oneIdCommand({ verb: "rotate-key", idName: "key_id", method: "rotateKey" })(args); break;
132
234
  default:
133
235
  failUnknownSubcommand("grants", sub);
134
236
  }