run402 4.93.2 → 4.95.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 (316) hide show
  1. package/README.md +61 -59
  2. package/cli.mjs +40 -47
  3. package/core-dist/config.js +52 -18
  4. package/core-dist/control-plane-session.js +31 -6
  5. package/core-dist/keystore.js +7 -7
  6. package/core-dist/profiles.js +9 -7
  7. package/core-dist/{allowance-auth.js → wallet-auth.js} +15 -15
  8. package/{sdk/core-dist/allowance.js → core-dist/wallet.js} +20 -20
  9. package/{sdk/core-dist/write-auth-session.js → core-dist/write-approvals.js} +19 -19
  10. package/gitvault-surface.json +2 -2
  11. package/lib/admin.mjs +6 -6
  12. package/lib/agent.mjs +20 -18
  13. package/lib/ai.mjs +5 -5
  14. package/lib/approve.mjs +81 -0
  15. package/lib/apps.mjs +12 -12
  16. package/lib/archives.mjs +371 -8
  17. package/lib/argparse.mjs +5 -5
  18. package/lib/assets.mjs +14 -14
  19. package/lib/auth.mjs +34 -34
  20. package/lib/billing.mjs +6 -6
  21. package/lib/branches.mjs +7 -7
  22. package/lib/buzz-doctor.mjs +2 -2
  23. package/lib/buzz-notifications.mjs +5 -5
  24. package/lib/buzz.mjs +3 -3
  25. package/lib/buzz.test.mjs +1 -1
  26. package/lib/cache.mjs +1 -1
  27. package/lib/cdn.mjs +2 -2
  28. package/lib/ci.mjs +12 -12
  29. package/lib/claims.mjs +2 -2
  30. package/lib/cold-start.mjs +21 -21
  31. package/lib/command-manifest.mjs +55 -70
  32. package/lib/config.mjs +28 -28
  33. package/lib/contacts.mjs +16 -16
  34. package/lib/contracts.mjs +12 -12
  35. package/lib/credentials.mjs +33 -33
  36. package/lib/daemon-path.mjs +1 -1
  37. package/lib/delegates.mjs +14 -14
  38. package/lib/deliveries.mjs +6 -6
  39. package/lib/deploy-rehearse-discovery.test.mjs +7 -7
  40. package/lib/deploy-v2.mjs +241 -193
  41. package/lib/deploy.mjs +21 -53
  42. package/lib/dev.mjs +3 -3
  43. package/lib/doctor-source-scan.mjs +1 -1
  44. package/lib/doctor.mjs +63 -63
  45. package/lib/domains.mjs +27 -27
  46. package/lib/email.mjs +38 -38
  47. package/lib/errors.mjs +40 -24
  48. package/lib/escalations.mjs +5 -5
  49. package/lib/events.mjs +32 -25
  50. package/lib/feedback.mjs +12 -12
  51. package/lib/functions.mjs +34 -34
  52. package/lib/gitvault-daemon.mjs +1 -1
  53. package/lib/gitvault-scaffold.mjs +2 -2
  54. package/lib/gitvault.mjs +2 -2
  55. package/lib/grants.mjs +7 -7
  56. package/lib/image.mjs +10 -10
  57. package/lib/init.mjs +69 -69
  58. package/lib/jobs.mjs +15 -15
  59. package/lib/lightning-wallet.mjs +28 -28
  60. package/lib/live.mjs +1 -1
  61. package/lib/login.mjs +207 -0
  62. package/lib/logout.mjs +53 -0
  63. package/lib/logs.mjs +8 -8
  64. package/lib/messages.mjs +5 -5
  65. package/lib/next-actions.mjs +16 -16
  66. package/lib/org-context.mjs +13 -13
  67. package/lib/{org.mjs → orgs.mjs} +215 -167
  68. package/lib/pay.mjs +1 -1
  69. package/lib/projects.mjs +70 -84
  70. package/lib/redeem.mjs +7 -8
  71. package/lib/remote-helper-session.mjs +12 -12
  72. package/lib/repos.mjs +83 -83
  73. package/lib/rooms.mjs +105 -69
  74. package/lib/sdk-errors.mjs +10 -5
  75. package/lib/sdk.mjs +3 -3
  76. package/lib/secrets.mjs +13 -13
  77. package/lib/service.mjs +5 -5
  78. package/lib/session-proofs.mjs +21 -0
  79. package/lib/sign-in.mjs +296 -0
  80. package/lib/sites.mjs +22 -22
  81. package/lib/snapshots.mjs +10 -10
  82. package/lib/stats.mjs +2 -2
  83. package/lib/status.mjs +25 -25
  84. package/lib/subdomains.mjs +30 -30
  85. package/lib/subscriptions.mjs +10 -10
  86. package/lib/tier.mjs +29 -22
  87. package/lib/transfer.mjs +59 -86
  88. package/lib/up.mjs +14 -14
  89. package/lib/wallet-context.mjs +4 -4
  90. package/lib/wallet-context.test.mjs +3 -3
  91. package/lib/wallets.mjs +197 -32
  92. package/lib/webhook-secret.mjs +6 -6
  93. package/lib/webhooks.mjs +8 -8
  94. package/lib/whoami.mjs +102 -0
  95. package/package.json +1 -1
  96. package/sdk/core-dist/config.js +52 -18
  97. package/sdk/core-dist/control-plane-session.js +31 -6
  98. package/sdk/core-dist/keystore.js +7 -7
  99. package/sdk/core-dist/profiles.js +9 -7
  100. package/sdk/core-dist/{allowance-auth.js → wallet-auth.js} +15 -15
  101. package/{core-dist/allowance.js → sdk/core-dist/wallet.js} +20 -20
  102. package/{core-dist/write-auth-session.js → sdk/core-dist/write-approvals.js} +19 -19
  103. package/sdk/dist/actions.d.ts +4 -4
  104. package/sdk/dist/actions.d.ts.map +1 -1
  105. package/sdk/dist/app-up.d.ts +2 -2
  106. package/sdk/dist/app-up.d.ts.map +1 -1
  107. package/sdk/dist/config.d.ts +1 -2
  108. package/sdk/dist/config.d.ts.map +1 -1
  109. package/sdk/dist/config.js.map +1 -1
  110. package/sdk/dist/control-plane-credentials.d.ts +8 -8
  111. package/sdk/dist/control-plane-credentials.js +7 -7
  112. package/sdk/dist/credentials.d.ts +20 -20
  113. package/sdk/dist/credentials.d.ts.map +1 -1
  114. package/sdk/dist/credentials.js +1 -1
  115. package/sdk/dist/errors.d.ts +26 -28
  116. package/sdk/dist/errors.d.ts.map +1 -1
  117. package/sdk/dist/errors.js +35 -38
  118. package/sdk/dist/errors.js.map +1 -1
  119. package/sdk/dist/index.d.ts +29 -16
  120. package/sdk/dist/index.d.ts.map +1 -1
  121. package/sdk/dist/index.js +30 -17
  122. package/sdk/dist/index.js.map +1 -1
  123. package/sdk/dist/kernel.d.ts +1 -1
  124. package/sdk/dist/kernel.d.ts.map +1 -1
  125. package/sdk/dist/kernel.js +10 -9
  126. package/sdk/dist/kernel.js.map +1 -1
  127. package/sdk/dist/namespaces/admin.d.ts +52 -121
  128. package/sdk/dist/namespaces/admin.d.ts.map +1 -1
  129. package/sdk/dist/namespaces/admin.js +41 -45
  130. package/sdk/dist/namespaces/admin.js.map +1 -1
  131. package/sdk/dist/namespaces/agent.d.ts +2 -2
  132. package/sdk/dist/namespaces/agent.d.ts.map +1 -1
  133. package/sdk/dist/namespaces/agent.js +2 -2
  134. package/sdk/dist/namespaces/agent.js.map +1 -1
  135. package/sdk/dist/namespaces/ai.d.ts +2 -2
  136. package/sdk/dist/namespaces/ai.js +3 -3
  137. package/sdk/dist/namespaces/ai.js.map +1 -1
  138. package/sdk/dist/namespaces/assets.js +1 -1
  139. package/sdk/dist/namespaces/assets.js.map +1 -1
  140. package/sdk/dist/namespaces/billing.d.ts +6 -3
  141. package/sdk/dist/namespaces/billing.d.ts.map +1 -1
  142. package/sdk/dist/namespaces/billing.js.map +1 -1
  143. package/sdk/dist/namespaces/buzz-notifications.types.d.ts +1 -1
  144. package/sdk/dist/namespaces/buzz.d.ts +2 -2
  145. package/sdk/dist/namespaces/buzz.d.ts.map +1 -1
  146. package/sdk/dist/namespaces/buzz.js +2 -2
  147. package/sdk/dist/namespaces/buzz.js.map +1 -1
  148. package/sdk/dist/namespaces/buzz.types.d.ts +2 -2
  149. package/sdk/dist/namespaces/buzz.types.d.ts.map +1 -1
  150. package/sdk/dist/namespaces/ci.js +3 -3
  151. package/sdk/dist/namespaces/ci.js.map +1 -1
  152. package/sdk/dist/namespaces/credentials.types.d.ts +1 -1
  153. package/sdk/dist/namespaces/deploy.d.ts +1 -1
  154. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  155. package/sdk/dist/namespaces/deploy.js +31 -32
  156. package/sdk/dist/namespaces/deploy.js.map +1 -1
  157. package/sdk/dist/namespaces/deploy.types.d.ts +6 -6
  158. package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
  159. package/sdk/dist/namespaces/domains.d.ts +10 -2
  160. package/sdk/dist/namespaces/domains.d.ts.map +1 -1
  161. package/sdk/dist/namespaces/domains.js +10 -5
  162. package/sdk/dist/namespaces/domains.js.map +1 -1
  163. package/sdk/dist/namespaces/errors.js +1 -1
  164. package/sdk/dist/namespaces/escalations.d.ts +1 -1
  165. package/sdk/dist/namespaces/escalations.js +1 -1
  166. package/sdk/dist/namespaces/escalations.types.d.ts +2 -2
  167. package/sdk/dist/namespaces/escalations.types.d.ts.map +1 -1
  168. package/sdk/dist/namespaces/events.types.d.ts +1 -1
  169. package/sdk/dist/namespaces/functions.d.ts +1 -1
  170. package/sdk/dist/namespaces/functions.js +2 -2
  171. package/sdk/dist/namespaces/functions.js.map +1 -1
  172. package/sdk/dist/namespaces/gitvault.crypto.d.ts +1 -1
  173. package/sdk/dist/namespaces/gitvault.d.ts +26 -26
  174. package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
  175. package/sdk/dist/namespaces/gitvault.js +113 -113
  176. package/sdk/dist/namespaces/gitvault.js.map +1 -1
  177. package/sdk/dist/namespaces/me.d.ts +120 -0
  178. package/sdk/dist/namespaces/me.d.ts.map +1 -0
  179. package/sdk/dist/namespaces/me.js +34 -0
  180. package/sdk/dist/namespaces/me.js.map +1 -0
  181. package/sdk/dist/namespaces/org.d.ts +108 -6
  182. package/sdk/dist/namespaces/org.d.ts.map +1 -1
  183. package/sdk/dist/namespaces/org.js +63 -7
  184. package/sdk/dist/namespaces/org.js.map +1 -1
  185. package/sdk/dist/namespaces/org.types.d.ts +29 -9
  186. package/sdk/dist/namespaces/org.types.d.ts.map +1 -1
  187. package/sdk/dist/namespaces/pay.js +3 -3
  188. package/sdk/dist/namespaces/pay.js.map +1 -1
  189. package/sdk/dist/namespaces/projects.d.ts +9 -9
  190. package/sdk/dist/namespaces/projects.js +15 -15
  191. package/sdk/dist/namespaces/projects.js.map +1 -1
  192. package/sdk/dist/namespaces/projects.types.d.ts +28 -12
  193. package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
  194. package/sdk/dist/namespaces/rooms.d.ts +7 -7
  195. package/sdk/dist/namespaces/rooms.js +17 -17
  196. package/sdk/dist/namespaces/rooms.js.map +1 -1
  197. package/sdk/dist/namespaces/rooms.types.d.ts +9 -9
  198. package/sdk/dist/namespaces/rooms.types.d.ts.map +1 -1
  199. package/sdk/dist/namespaces/service.d.ts +1 -1
  200. package/sdk/dist/namespaces/service.js +1 -1
  201. package/sdk/dist/namespaces/{operator-session.d.ts → session.d.ts} +135 -51
  202. package/sdk/dist/namespaces/session.d.ts.map +1 -0
  203. package/sdk/dist/namespaces/{operator-session.js → session.js} +118 -30
  204. package/sdk/dist/namespaces/session.js.map +1 -0
  205. package/sdk/dist/namespaces/subdomains.d.ts +5 -5
  206. package/sdk/dist/namespaces/subdomains.d.ts.map +1 -1
  207. package/sdk/dist/namespaces/subdomains.js +6 -6
  208. package/sdk/dist/namespaces/subdomains.js.map +1 -1
  209. package/sdk/dist/namespaces/tier.d.ts +44 -21
  210. package/sdk/dist/namespaces/tier.d.ts.map +1 -1
  211. package/sdk/dist/namespaces/tier.js +7 -7
  212. package/sdk/dist/namespaces/tier.js.map +1 -1
  213. package/sdk/dist/namespaces/transfers.d.ts +119 -85
  214. package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
  215. package/sdk/dist/namespaces/transfers.js +31 -38
  216. package/sdk/dist/namespaces/transfers.js.map +1 -1
  217. package/sdk/dist/namespaces/vouchers.d.ts +9 -10
  218. package/sdk/dist/namespaces/vouchers.d.ts.map +1 -1
  219. package/sdk/dist/namespaces/vouchers.js +4 -5
  220. package/sdk/dist/namespaces/vouchers.js.map +1 -1
  221. package/sdk/dist/namespaces/wallets.d.ts +72 -3
  222. package/sdk/dist/namespaces/wallets.d.ts.map +1 -1
  223. package/sdk/dist/namespaces/wallets.js +141 -3
  224. package/sdk/dist/namespaces/wallets.js.map +1 -1
  225. package/sdk/dist/namespaces/write-approval.d.ts +101 -0
  226. package/sdk/dist/namespaces/write-approval.d.ts.map +1 -0
  227. package/sdk/dist/namespaces/write-approval.js +62 -0
  228. package/sdk/dist/namespaces/write-approval.js.map +1 -0
  229. package/sdk/dist/node/actions-node.d.ts +3 -3
  230. package/sdk/dist/node/actions-node.d.ts.map +1 -1
  231. package/sdk/dist/node/actions-node.js +44 -44
  232. package/sdk/dist/node/actions-node.js.map +1 -1
  233. package/sdk/dist/node/assets-node.js +6 -6
  234. package/sdk/dist/node/assets-node.js.map +1 -1
  235. package/sdk/dist/node/{bearer-claim-key.d.ts → bearer-redeem-key.d.ts} +12 -12
  236. package/sdk/dist/node/bearer-redeem-key.d.ts.map +1 -0
  237. package/sdk/dist/node/{bearer-claim-key.js → bearer-redeem-key.js} +21 -21
  238. package/sdk/dist/node/bearer-redeem-key.js.map +1 -0
  239. package/sdk/dist/node/ci.d.ts +1 -1
  240. package/sdk/dist/node/ci.d.ts.map +1 -1
  241. package/sdk/dist/node/ci.js +6 -6
  242. package/sdk/dist/node/ci.js.map +1 -1
  243. package/sdk/dist/node/credentials.d.ts +18 -17
  244. package/sdk/dist/node/credentials.d.ts.map +1 -1
  245. package/sdk/dist/node/credentials.js +29 -28
  246. package/sdk/dist/node/credentials.js.map +1 -1
  247. package/sdk/dist/node/deploy-manifest.d.ts +3 -5
  248. package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
  249. package/sdk/dist/node/deploy-manifest.js +3 -12
  250. package/sdk/dist/node/deploy-manifest.js.map +1 -1
  251. package/sdk/dist/node/funding-recovery.d.ts +1 -1
  252. package/sdk/dist/node/funding-recovery.d.ts.map +1 -1
  253. package/sdk/dist/node/funding-recovery.js +1 -1
  254. package/sdk/dist/node/funding-recovery.js.map +1 -1
  255. package/sdk/dist/node/gitvault-apply.d.ts +1 -1
  256. package/sdk/dist/node/gitvault-apply.d.ts.map +1 -1
  257. package/sdk/dist/node/gitvault-apply.js +1 -1
  258. package/sdk/dist/node/gitvault-apply.js.map +1 -1
  259. package/sdk/dist/node/gitvault-handoff.d.ts +22 -22
  260. package/sdk/dist/node/gitvault-handoff.d.ts.map +1 -1
  261. package/sdk/dist/node/gitvault-handoff.js +45 -45
  262. package/sdk/dist/node/gitvault-handoff.js.map +1 -1
  263. package/sdk/dist/node/gitvault-prewarm.js +7 -7
  264. package/sdk/dist/node/gitvault-prewarm.js.map +1 -1
  265. package/sdk/dist/node/gitvault-restore.d.ts +1 -1
  266. package/sdk/dist/node/gitvault-restore.js +1 -1
  267. package/sdk/dist/node/index.d.ts +16 -16
  268. package/sdk/dist/node/index.d.ts.map +1 -1
  269. package/sdk/dist/node/index.js +15 -15
  270. package/sdk/dist/node/index.js.map +1 -1
  271. package/sdk/dist/node/manifest-export.js +2 -2
  272. package/sdk/dist/node/manifest-export.js.map +1 -1
  273. package/sdk/dist/node/org-adopt.d.ts +49 -0
  274. package/sdk/dist/node/org-adopt.d.ts.map +1 -0
  275. package/sdk/dist/node/org-adopt.js +77 -0
  276. package/sdk/dist/node/org-adopt.js.map +1 -0
  277. package/sdk/dist/node/paid-fetch.d.ts +7 -7
  278. package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
  279. package/sdk/dist/node/paid-fetch.js +54 -54
  280. package/sdk/dist/node/paid-fetch.js.map +1 -1
  281. package/sdk/dist/node/preflight.d.ts +1 -1
  282. package/sdk/dist/node/preflight.d.ts.map +1 -1
  283. package/sdk/dist/node/preflight.js +1 -1
  284. package/sdk/dist/node/preflight.js.map +1 -1
  285. package/sdk/dist/node/sites-node.js +1 -1
  286. package/sdk/dist/node/sites-node.js.map +1 -1
  287. package/sdk/dist/node/source-scan.d.ts +1 -1
  288. package/sdk/dist/node/source-scan.js +2 -2
  289. package/sdk/dist/node/source-scan.js.map +1 -1
  290. package/sdk/dist/scoped.d.ts +11 -11
  291. package/sdk/dist/scoped.d.ts.map +1 -1
  292. package/sdk/dist/scoped.js +5 -5
  293. package/sdk/dist/scoped.js.map +1 -1
  294. package/core-dist/operator-session.js +0 -154
  295. package/lib/allowance.mjs +0 -355
  296. package/lib/cloud.mjs +0 -256
  297. package/lib/core.mjs +0 -123
  298. package/lib/operator-proofs.mjs +0 -22
  299. package/lib/operator.mjs +0 -771
  300. package/sdk/core-dist/operator-session.js +0 -154
  301. package/sdk/dist/namespaces/allowance.d.ts +0 -79
  302. package/sdk/dist/namespaces/allowance.d.ts.map +0 -1
  303. package/sdk/dist/namespaces/allowance.js +0 -149
  304. package/sdk/dist/namespaces/allowance.js.map +0 -1
  305. package/sdk/dist/namespaces/operator-session.d.ts.map +0 -1
  306. package/sdk/dist/namespaces/operator-session.js.map +0 -1
  307. package/sdk/dist/namespaces/operator.d.ts +0 -359
  308. package/sdk/dist/namespaces/operator.d.ts.map +0 -1
  309. package/sdk/dist/namespaces/operator.js +0 -272
  310. package/sdk/dist/namespaces/operator.js.map +0 -1
  311. package/sdk/dist/node/bearer-claim-key.d.ts.map +0 -1
  312. package/sdk/dist/node/bearer-claim-key.js.map +0 -1
  313. package/sdk/dist/node/operator-claim.d.ts +0 -49
  314. package/sdk/dist/node/operator-claim.d.ts.map +0 -1
  315. package/sdk/dist/node/operator-claim.js +0 -77
  316. package/sdk/dist/node/operator-claim.js.map +0 -1
package/lib/ai.mjs CHANGED
@@ -24,7 +24,7 @@ Examples:
24
24
 
25
25
  Notes:
26
26
  - [project_id] defaults to the active project when omitted (set with
27
- 'run402 projects use <id>'). Project IDs start with 'prj_'; any first
27
+ 'run402 projects use <project_id>'). Project IDs start with 'prj_'; any first
28
28
  positional that doesn't is treated as the next argument instead.
29
29
  - translate requires the AI Translation add-on on the project
30
30
  - moderate is free for all projects
@@ -47,7 +47,7 @@ Options:
47
47
  --to <lang> Target language code (required, e.g. es, ja, fr)
48
48
  --from <lang> Source language code (optional; auto-detected if omitted)
49
49
  --context <hint> Optional translation hint (e.g. "formal business email")
50
- --project <id> Project ID (alternative to the positional argument)
50
+ --project <project_id> Project ID (alternative to the positional argument)
51
51
 
52
52
  Notes:
53
53
  - Requires the AI Translation add-on on the project
@@ -71,7 +71,7 @@ Arguments:
71
71
  <text> Text to check (quote it to preserve spaces)
72
72
 
73
73
  Options:
74
- --project <id> Project ID (alternative to the positional argument)
74
+ --project <project_id> Project ID (alternative to the positional argument)
75
75
 
76
76
  Notes:
77
77
  - Free for all projects; uses the project's service key
@@ -91,7 +91,7 @@ Arguments:
91
91
  Must start with 'prj_'; any other first positional is an error.
92
92
 
93
93
  Options:
94
- --project <id> Project ID (alternative to the positional argument)
94
+ --project <project_id> Project ID (alternative to the positional argument)
95
95
 
96
96
  Notes:
97
97
  - Reports translation word quota and usage; only meaningful with the
@@ -111,7 +111,7 @@ async function translate(args) {
111
111
  args = normalizeArgv(args);
112
112
  assertKnownFlags(args, TRANSLATE_VALUE_FLAGS, TRANSLATE_VALUE_FLAGS);
113
113
 
114
- // --project <id> wins over positional, mirroring previous behavior.
114
+ // --project <project_id> wins over positional, mirroring previous behavior.
115
115
  const projectOpt = flagValue(args, "--project");
116
116
  const to = flagValue(args, "--to");
117
117
  const from = flagValue(args, "--from");
@@ -0,0 +1,81 @@
1
+ /**
2
+ * `run402 approve --action <capability> (--org <org_id> | --project <project_id>)`
3
+ * — mint a passkey-signed write approval scoped to one (action, target) so a
4
+ * person signed in without a wallet can provision, deploy, or write secrets.
5
+ * See sign-in.mjs.
6
+ */
7
+
8
+ import { fail } from "./sdk-errors.mjs";
9
+ import { normalizeArgv, hasHelp, assertKnownFlags, flagValue, positionalArgs } from "./argparse.mjs";
10
+ import { APPROVAL_ACTIONS, mintApproval } from "./sign-in.mjs";
11
+
12
+ const HELP = `run402 approve — mint a write approval for one action on one target
13
+
14
+ Usage:
15
+ run402 approve --action <capability> (--org <org_id> | --project <project_id>) [--no-open]
16
+
17
+ A person signed in with 'run402 login' (no wallet) needs a write approval to
18
+ provision a project, deploy, or write secrets. It is signed with your passkey,
19
+ covers one action on one org or project, lasts 30 minutes idle (4 hours at
20
+ most), and dies with the sign-in session. It never counts as a step-up.
21
+ From an interactive terminal the CLI opens this ceremony for you when a write
22
+ needs it; agents and CI relay the command instead.
23
+
24
+ Actions:
25
+ org.project.create --org <org_id>
26
+ project.deploy --project <project_id>
27
+ project.secret.write --project <project_id>
28
+
29
+ Options:
30
+ --no-open Do not open the browser; print the URL only.
31
+
32
+ Notes:
33
+ - Requires 'run402 login' (a device-grade session cannot approve).
34
+ - 'run402 whoami' lists the approvals cached on this machine.
35
+ `;
36
+
37
+ export async function run(args = []) {
38
+ args = normalizeArgv(args);
39
+ if (hasHelp(args)) {
40
+ console.log(HELP);
41
+ process.exit(0);
42
+ }
43
+ const valueFlags = ["--action", "--org", "--project"];
44
+ assertKnownFlags(args, ["--help", "-h", "--no-open", ...valueFlags], valueFlags);
45
+ const extra = positionalArgs(args, valueFlags);
46
+ if (extra.length > 0) {
47
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for approve: ${extra[0]}`, hint: "Use `run402 approve --action <capability> (--org <org_id> | --project <project_id>)`." });
48
+ }
49
+ const action = flagValue(args, "--action");
50
+ const org = flagValue(args, "--org");
51
+ const project = flagValue(args, "--project");
52
+
53
+ if (!action || !APPROVAL_ACTIONS[action]) {
54
+ fail({
55
+ code: "BAD_FLAG",
56
+ message: `--action must be one of: ${Object.keys(APPROVAL_ACTIONS).join(", ")}`,
57
+ details: { flag: "--action", value: action, allowed: Object.keys(APPROVAL_ACTIONS) },
58
+ });
59
+ }
60
+ const scope = APPROVAL_ACTIONS[action];
61
+ if (scope === "org" && !org) fail({ code: "BAD_FLAG", message: `--org <org_id> is required for --action ${action}` });
62
+ if (scope === "project" && !project) fail({ code: "BAD_FLAG", message: `--project <project_id> is required for --action ${action}` });
63
+ if (scope === "org" && project) fail({ code: "BAD_FLAG", message: `--project is not valid for org-scoped --action ${action}; use --org` });
64
+ if (scope === "project" && org) fail({ code: "BAD_FLAG", message: `--org is not valid for project-scoped --action ${action}; use --project` });
65
+
66
+ const approval = await mintApproval({
67
+ action,
68
+ orgId: org ?? undefined,
69
+ projectId: project ?? undefined,
70
+ noOpen: args.includes("--no-open"),
71
+ });
72
+ console.log(
73
+ JSON.stringify({
74
+ approved: true,
75
+ action,
76
+ ...(org ? { org_id: org } : {}),
77
+ ...(project ? { project_id: project } : {}),
78
+ expires_at: new Date(approval.expires_at).toISOString(),
79
+ }),
80
+ );
81
+ }
package/lib/apps.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { allowanceAuthHeaders, saveProject } from "./config.mjs";
1
+ import { walletAuthHeaders, saveProject } from "./config.mjs";
2
2
  import { getSdk } from "./sdk.mjs";
3
3
  import { reportSdkError, fail } from "./sdk-errors.mjs";
4
4
  import { assertAllowedValue, assertKnownFlags, flagValue, normalizeArgv, positionalArgs, resolveProjectSelector, failUnknownSubcommand } from "./argparse.mjs";
@@ -12,13 +12,13 @@ Subcommands:
12
12
  browse [--tag <tag>] Browse public apps
13
13
  fork <version_id> --name <name> [--subdomain <name>]
14
14
  Fork a published app into your own project
15
- publish [--project <id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed]
15
+ publish [--project <project_id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed]
16
16
  Publish a project as an app
17
- versions [--project <id>] List published versions of a project
17
+ versions [--project <project_id>] List published versions of a project
18
18
  inspect <version_id> Inspect a published app version
19
- update <version_id> [--project <id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed] [--no-fork]
19
+ update <version_id> [--project <project_id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed] [--no-fork]
20
20
  Update a published version
21
- delete <version_id> [--project <id>] Delete a published version
21
+ delete <version_id> [--project <project_id>] Delete a published version
22
22
 
23
23
  Legacy (still supported): the old positional forms keep working, e.g.
24
24
  run402 apps fork <version_id> <name>
@@ -72,13 +72,13 @@ Examples:
72
72
  publish: `run402 apps publish — Publish a project as an app
73
73
 
74
74
  Usage:
75
- run402 apps publish [--project <id>] [options]
75
+ run402 apps publish [--project <project_id>] [options]
76
76
 
77
77
  Legacy (still supported):
78
78
  run402 apps publish <project_id> [options]
79
79
 
80
80
  Options (project):
81
- --project <id> Project ID to publish (defaults to the active project)
81
+ --project <project_id> Project ID to publish (defaults to the active project)
82
82
 
83
83
  Options:
84
84
  --description <d> Human-readable description of the app
@@ -93,7 +93,7 @@ Examples:
93
93
  update: `run402 apps update — Update a published version's metadata
94
94
 
95
95
  Usage:
96
- run402 apps update <version_id> [--project <id>] [options]
96
+ run402 apps update <version_id> [--project <project_id>] [options]
97
97
 
98
98
  Legacy (still supported):
99
99
  run402 apps update <project_id> <version_id> [options]
@@ -127,7 +127,7 @@ Examples:
127
127
  versions: `run402 apps versions — List published versions of a project
128
128
 
129
129
  Usage:
130
- run402 apps versions [--project <id>]
130
+ run402 apps versions [--project <project_id>]
131
131
 
132
132
  Legacy (still supported):
133
133
  run402 apps versions <project_id>
@@ -138,7 +138,7 @@ Examples:
138
138
  delete: `run402 apps delete — Delete a published version
139
139
 
140
140
  Usage:
141
- run402 apps delete <version_id> [--project <id>]
141
+ run402 apps delete <version_id> [--project <project_id>]
142
142
 
143
143
  Legacy (still supported):
144
144
  run402 apps delete <project_id> <version_id>
@@ -185,8 +185,8 @@ async function fork(versionId, name, args) {
185
185
  fail({ code: "BAD_USAGE", message: `Unexpected argument for apps fork: ${positionals[expected]}` });
186
186
  }
187
187
  const opts = { subdomain: flagValue(parsedArgs, "--subdomain") ?? undefined };
188
- // Preserve the aggressive early exit when no allowance is configured.
189
- allowanceAuthHeaders("/fork/v1");
188
+ // Preserve the aggressive early exit when no local wallet is configured.
189
+ walletAuthHeaders("/fork/v1");
190
190
 
191
191
  try {
192
192
  const data = await getSdk().apps.fork({
package/lib/archives.mjs CHANGED
@@ -1,18 +1,106 @@
1
- import { inspectArchive, verifyArchive } from "#sdk/node";
2
- import { reportSdkError, fail } from "./sdk-errors.mjs";
3
- import { assertKnownFlags, hasHelp, normalizeArgv, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
4
3
 
5
- const HELP = `run402 archives — Inspect and verify portable Run402 project archives
4
+ import { importArchiveToCore, inspectArchive, verifyArchive } from "#sdk/node";
5
+ import { getSdk } from "./sdk.mjs";
6
+ import { fail, reportSdkError } from "./sdk-errors.mjs";
7
+ import { assertAllowedValue, assertKnownFlags, flagValue, hasHelp, normalizeArgv, parseIntegerFlag, positionalArgs, resolveProjectSelector, failUnknownSubcommand } from "./argparse.mjs";
8
+
9
+ const HELP = `run402 archives — portable Run402 project archives
6
10
 
7
11
  Usage:
8
- run402 archives inspect <archive-path> [--json]
9
- run402 archives verify <archive-path> [--json]
12
+ run402 archives create [<project_id>] [--project <project_id>] [--target cloud] [options]
13
+ run402 archives status [<project_id>] <archive_id> [--project <project_id>] [--target cloud] [--json]
14
+ run402 archives download [<project_id>] <archive_id> --output <file> [--project <project_id>] [--target cloud] [--json]
15
+ run402 archives inspect <archive_path> [--json]
16
+ run402 archives verify <archive_path> [--json]
17
+ run402 archives import <archive_path> --name <project_name> [--target core] [options]
18
+
19
+ --target names the Run402 deployment the command talks to: create, status, and
20
+ download export from Run402 Cloud (--target cloud, the default); import loads an
21
+ archive into a local Run402 Core (--target core, the default). inspect and verify
22
+ are local and offline and take no target. A leading prj_... positional selects
23
+ the project; --project defaults to the active project.
24
+
25
+ Canonical agent path:
26
+ run402 archives create <project_id> --target cloud \\
27
+ --scope portable-runtime-v1 --auth stubs --consistency pause-writes \\
28
+ --wait --output ./project.r402ar --json
29
+ run402 archives verify ./project.r402ar --json
30
+ run402 archives import ./project.r402ar --target core --name imported-project --env-file ./required.env --json
31
+
32
+ Options for create:
33
+ --scope <scope> Archive scope. v1 supports portable-runtime-v1.
34
+ --auth <mode> Auth export mode: stubs (default) or none.
35
+ --consistency <mode> pause-writes (default) or cloud_write_pause_v1.
36
+ --idempotency-key <key> Retry-safe creation key.
37
+ --wait Poll until the archive is ready.
38
+ --output <file> Save archive bytes. Implies --wait.
39
+ --poll-interval <ms> Poll interval while waiting (default 1000).
40
+ --timeout <ms> Wait timeout (default 600000).
41
+ --json Emit final JSON on stdout.
42
+ --json-stream Emit NDJSON progress events on stdout.
43
+
44
+ Options for import:
45
+ --name <name> New Core project name (default imported-project)
46
+ --env-file <path> Env file satisfying required archive secrets.
47
+ --secret KEY=VALUE Inline secret value; repeatable. Overrides --env-file.
48
+ --core-url <url> Core gateway URL (default RUN402_CORE_URL or http://127.0.0.1:4020)
49
+ --dry-run Verify and plan without creating a Core project.
50
+ --require-runnable Block import unless required secrets are supplied.
51
+ --json Emit final JSON.
52
+ --json-stream Emit NDJSON progress events and final result event.
10
53
 
11
54
  Notes:
12
55
  - Verification is local and offline. It does not require Cloud credentials.
13
56
  - Archives are untrusted input; verify checks integrity and compatibility, not trust.
14
57
  `;
15
58
 
59
+ const TARGETS = ["cloud", "core"];
60
+
61
+ /**
62
+ * Read --target and require the one deployment kind this verb talks to:
63
+ * Run402 Cloud exports archives, Run402 Core imports them.
64
+ */
65
+ function requireTarget(args, verb, expected) {
66
+ const target = flagValue(args, "--target") ?? expected;
67
+ assertAllowedValue(target, TARGETS, "--target");
68
+ if (target !== expected) {
69
+ fail({
70
+ code: "BAD_FLAG",
71
+ message: `archives ${verb} runs against --target ${expected}; --target ${target} does not ${expected === "cloud" ? "export archives" : "import archives"}.`,
72
+ details: { flag: "--target", value: target, expected },
73
+ hint: expected === "cloud"
74
+ ? "Export with --target cloud, then load the file with: run402 archives import <archive_path> --target core"
75
+ : "Import into Run402 Core with --target core; export from Run402 Cloud with: run402 archives create --target cloud",
76
+ });
77
+ }
78
+ return target;
79
+ }
80
+
81
+ const CREATE_FLAG_VALUES = [
82
+ "--project",
83
+ "--target",
84
+ "--scope",
85
+ "--auth",
86
+ "--consistency",
87
+ "--idempotency-key",
88
+ "--output",
89
+ "--poll-interval",
90
+ "--timeout",
91
+ ];
92
+ const CREATE_FLAGS = new Set([
93
+ ...CREATE_FLAG_VALUES,
94
+ "--wait",
95
+ "--json",
96
+ "--json-stream",
97
+ "--help",
98
+ "-h",
99
+ ]);
100
+
101
+ const IMPORT_FLAG_VALUES = ["--target", "--name", "--env-file", "--secret", "--core-url"];
102
+ const IMPORT_FLAGS = new Set([...IMPORT_FLAG_VALUES, "--dry-run", "--require-runnable", "--json", "--json-stream", "--help", "-h"]);
103
+
16
104
  export async function run(sub, rawArgs = []) {
17
105
  const all = [sub, ...rawArgs].filter(Boolean);
18
106
  if (hasHelp(all)) {
@@ -20,18 +108,206 @@ export async function run(sub, rawArgs = []) {
20
108
  return;
21
109
  }
22
110
  switch (sub) {
111
+ case "create": return create(rawArgs);
112
+ case "status": return status(rawArgs);
113
+ case "download": return download(rawArgs);
23
114
  case "inspect": return inspect(rawArgs);
24
115
  case "verify": return verify(rawArgs);
116
+ case "import": return importProject(rawArgs);
25
117
  default:
26
118
  failUnknownSubcommand("archives", sub);
27
119
  }
28
120
  }
29
121
 
122
+ async function create(rawArgs) {
123
+ const args = normalizeArgv(rawArgs);
124
+ assertKnownFlags(args, [...CREATE_FLAGS], CREATE_FLAG_VALUES);
125
+ requireTarget(args, "create", "cloud");
126
+ const { projectId, rest } = resolveProjectSelector(args, { valueFlags: CREATE_FLAG_VALUES });
127
+ const extraPos = positionalArgs(rest, CREATE_FLAG_VALUES);
128
+ if (extraPos.length > 0) {
129
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for archives create: ${extraPos[0]}` });
130
+ }
131
+ const scope = flagValue(args, "--scope") ?? "portable-runtime-v1";
132
+ const auth = flagValue(args, "--auth") ?? "stubs";
133
+ const consistency = flagValue(args, "--consistency") ?? "pause-writes";
134
+ assertAllowedValue(scope, ["portable-runtime-v1"], "--scope");
135
+ assertAllowedValue(auth, ["stubs", "none"], "--auth");
136
+ assertAllowedValue(consistency, ["pause-writes", "cloud_write_pause_v1"], "--consistency");
137
+
138
+ const output = flagValue(args, "--output");
139
+ const wait = args.includes("--wait") || Boolean(output);
140
+ const jsonStream = args.includes("--json-stream");
141
+ const idempotencyKey = flagValue(args, "--idempotency-key") ?? undefined;
142
+ const pollIntervalMs = parseIntegerFlag("--poll-interval", flagValue(args, "--poll-interval"), { min: 100, def: 1000 });
143
+ const timeoutMs = parseIntegerFlag("--timeout", flagValue(args, "--timeout"), { min: 1000, def: 600000 });
144
+ const emit = (event) => {
145
+ if (jsonStream) console.log(JSON.stringify(event));
146
+ };
147
+
148
+ try {
149
+ const sdk = getSdk();
150
+ const created = await sdk.archives.create(projectId, {
151
+ scope,
152
+ auth,
153
+ consistency,
154
+ idempotencyKey,
155
+ });
156
+ emit(progressEvent("archive_export_created", "create", projectId, created));
157
+
158
+ let archive = created;
159
+ let outputPath = null;
160
+ let bytesWritten = 0;
161
+ if (wait) {
162
+ archive = created.status === "ready"
163
+ ? created
164
+ : await sdk.archives.wait(projectId, created.archive_id, {
165
+ pollIntervalMs,
166
+ timeoutMs,
167
+ onProgress: emit,
168
+ });
169
+ if (archive.status !== "ready") {
170
+ const result = finalCreateResult({ projectId, created, archive, outputPath, bytesWritten });
171
+ printJson(result, jsonStream);
172
+ process.exit(1);
173
+ }
174
+ if (output) {
175
+ const download = await sdk.archives.download(projectId, archive.archive_id);
176
+ outputPath = resolve(output);
177
+ mkdirSync(dirname(outputPath), { recursive: true });
178
+ writeFileSync(outputPath, download.bytes);
179
+ bytesWritten = download.bytes.byteLength;
180
+ emit({
181
+ ...progressEvent("archive_export_downloaded", "download", projectId, archive),
182
+ context: { output_path: outputPath, bytes_written: bytesWritten },
183
+ });
184
+ }
185
+ }
186
+
187
+ const result = finalCreateResult({ projectId, created, archive, outputPath, bytesWritten });
188
+ if (jsonStream) {
189
+ console.log(JSON.stringify({
190
+ event: "archive_export_complete",
191
+ stage: "complete",
192
+ resource_type: "project_archive",
193
+ resource_id: archive.archive_id,
194
+ project_id: projectId,
195
+ status: archive.status === "ready" ? "complete" : archive.status,
196
+ completed_units: archive.status === "ready" ? 1 : 0,
197
+ total_units: 1,
198
+ code: null,
199
+ message: archive.status === "ready" ? "Archive export complete." : "Archive export did not complete.",
200
+ next_action: archive.next_action,
201
+ retryable: false,
202
+ result,
203
+ }));
204
+ } else {
205
+ console.log(JSON.stringify(result, null, 2));
206
+ }
207
+ if (archive.status !== "ready") process.exit(1);
208
+ } catch (err) {
209
+ reportSdkError(err);
210
+ }
211
+ }
212
+
213
+ async function download(rawArgs) {
214
+ const args = normalizeArgv(rawArgs);
215
+ assertKnownFlags(args, ["--project", "--target", "--output", "--json", "--help", "-h"], ["--project", "--target", "--output"]);
216
+ requireTarget(args, "download", "cloud");
217
+ const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project", "--target", "--output"] });
218
+ const pos = positionalArgs(rest, ["--project", "--target", "--output"]);
219
+ const [archiveId] = pos;
220
+ const output = flagValue(args, "--output");
221
+ if (!archiveId || pos.length > 1 || !output) {
222
+ fail({ code: "BAD_USAGE", message: "Usage: run402 archives download [<project_id>] <archive_id> --output <file> [--project <project_id>] [--target cloud] [--json]" });
223
+ }
224
+ try {
225
+ const download = await getSdk().archives.download(projectId, archiveId);
226
+ const outputPath = resolve(output);
227
+ mkdirSync(dirname(outputPath), { recursive: true });
228
+ writeFileSync(outputPath, download.bytes);
229
+ console.log(JSON.stringify({
230
+ ok: true,
231
+ project_id: projectId,
232
+ archive_id: archiveId,
233
+ output_path: outputPath,
234
+ bytes_written: download.bytes.byteLength,
235
+ sha256: download.archive.sha256,
236
+ verify_command: `run402 archives verify ${JSON.stringify(outputPath)} --json`,
237
+ import_command: `run402 archives import ${JSON.stringify(outputPath)} --target core --name imported-project --env-file ./required.env --json`,
238
+ archive: download.archive,
239
+ }, null, 2));
240
+ } catch (err) {
241
+ reportSdkError(err);
242
+ }
243
+ }
244
+
245
+ async function status(rawArgs) {
246
+ const args = normalizeArgv(rawArgs);
247
+ assertKnownFlags(args, ["--project", "--target", "--json", "--help", "-h"], ["--project", "--target"]);
248
+ requireTarget(args, "status", "cloud");
249
+ const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project", "--target"] });
250
+ const pos = positionalArgs(rest, ["--project", "--target"]);
251
+ const [archiveId] = pos;
252
+ if (!archiveId || pos.length > 1) {
253
+ fail({ code: "BAD_USAGE", message: "Usage: run402 archives status [<project_id>] <archive_id> [--project <project_id>] [--target cloud] [--json]" });
254
+ }
255
+ try {
256
+ const archive = await getSdk().archives.get(projectId, archiveId);
257
+ console.log(JSON.stringify({ archive }, null, 2));
258
+ } catch (err) {
259
+ reportSdkError(err);
260
+ }
261
+ }
262
+
263
+ function finalCreateResult({ projectId, created, archive, outputPath, bytesWritten }) {
264
+ return {
265
+ ok: archive.status === "ready",
266
+ project_id: projectId,
267
+ archive_id: archive.archive_id,
268
+ operation_id: archive.operation_id,
269
+ created_archive_id: created.archive_id,
270
+ archive_status: archive.status,
271
+ output_path: outputPath,
272
+ bytes_written: bytesWritten,
273
+ sha256: archive.sha256,
274
+ byte_count: archive.byte_count,
275
+ expires_at: archive.expires_at,
276
+ verify_command: outputPath ? `run402 archives verify ${JSON.stringify(outputPath)} --json` : null,
277
+ import_command: outputPath ? `run402 archives import ${JSON.stringify(outputPath)} --target core --name imported-project --env-file ./required.env --json` : null,
278
+ next_action: archive.next_action,
279
+ portability_report: archive.portability_report,
280
+ export_report: archive.export_report,
281
+ archive,
282
+ };
283
+ }
284
+
285
+ function progressEvent(event, stage, projectId, archive) {
286
+ return {
287
+ event,
288
+ stage,
289
+ resource_type: "project_archive",
290
+ resource_id: archive.archive_id,
291
+ project_id: projectId,
292
+ status: archive.status,
293
+ completed_units: archive.status === "ready" || archive.status === "failed" || archive.status === "expired" ? 1 : 0,
294
+ total_units: 1,
295
+ code: archive.status === "failed" ? archive.error?.code ?? "ARCHIVE_EXPORT_FAILED" : null,
296
+ message: `Archive export status: ${archive.status}`,
297
+ next_action: archive.next_action,
298
+ retryable: archive.status === "running",
299
+ };
300
+ }
301
+
302
+ function printJson(result, alreadyStreamed) {
303
+ if (!alreadyStreamed) console.log(JSON.stringify(result, null, 2));
304
+ }
305
+
30
306
  async function inspect(rawArgs) {
31
307
  const args = normalizeArgv(rawArgs);
32
308
  assertKnownFlags(args, ["--json", "--help", "-h"], []);
33
309
  const archivePath = positionalArgs(args, [])[0];
34
- if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives inspect <archive-path> [--json]" });
310
+ if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives inspect <archive_path> [--json]" });
35
311
  try {
36
312
  const result = await inspectArchive(archivePath);
37
313
  console.log(JSON.stringify({ archive: result }, null, 2));
@@ -44,7 +320,7 @@ async function verify(rawArgs) {
44
320
  const args = normalizeArgv(rawArgs);
45
321
  assertKnownFlags(args, ["--json", "--help", "-h"], []);
46
322
  const archivePath = positionalArgs(args, [])[0];
47
- if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives verify <archive-path> [--json]" });
323
+ if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives verify <archive_path> [--json]" });
48
324
  try {
49
325
  const result = await verifyArchive(archivePath);
50
326
  console.log(JSON.stringify({ ok: result.ok, verified: result.ok, archive: result }, null, 2));
@@ -53,3 +329,90 @@ async function verify(rawArgs) {
53
329
  reportSdkError(err);
54
330
  }
55
331
  }
332
+
333
+ async function importProject(rawArgs) {
334
+ const args = normalizeArgv(rawArgs);
335
+ assertKnownFlags(args, [...IMPORT_FLAGS], IMPORT_FLAG_VALUES);
336
+ requireTarget(args, "import", "core");
337
+ const archivePath = positionalArgs(args, IMPORT_FLAG_VALUES)[0];
338
+ if (!archivePath) {
339
+ fail({ code: "BAD_USAGE", message: "Usage: run402 archives import <archive_path> --name <project_name> [--target core] [options]" });
340
+ }
341
+ const jsonStream = args.includes("--json-stream");
342
+ const secretValues = parseSecrets(args);
343
+ const name = flagValue(args, "--name") ?? "imported-project";
344
+ const coreUrl = flagValue(args, "--core-url") ?? undefined;
345
+ const startedEvent = {
346
+ event: "core_archive_import_started",
347
+ stage: "verify",
348
+ resource_type: "project_archive",
349
+ resource_id: archivePath,
350
+ status: "running",
351
+ completed_units: 0,
352
+ total_units: 1,
353
+ code: null,
354
+ message: "Verifying archive locally before Core import.",
355
+ next_action: { type: "none" },
356
+ retryable: false,
357
+ context: { archive_path: archivePath, core_url: coreUrl ?? null, project_name: name },
358
+ };
359
+ if (jsonStream) console.log(JSON.stringify(startedEvent));
360
+ try {
361
+ const result = await importArchiveToCore({
362
+ archivePath,
363
+ name,
364
+ coreUrl,
365
+ envFile: flagValue(args, "--env-file") ?? undefined,
366
+ secretValues,
367
+ dryRun: args.includes("--dry-run"),
368
+ requireRunnable: args.includes("--require-runnable"),
369
+ });
370
+ if (jsonStream) {
371
+ console.log(JSON.stringify({
372
+ event: "core_archive_import_complete",
373
+ stage: "complete",
374
+ resource_type: "project_archive",
375
+ resource_id: archivePath,
376
+ status: result.status,
377
+ completed_units: result.status === "imported" || result.status === "dry_run" ? 1 : 0,
378
+ total_units: 1,
379
+ code: firstDiagnosticCode(result),
380
+ message: `Core archive import status: ${result.status}`,
381
+ next_action: result.next_action,
382
+ retryable: result.status === "failed" && result.diagnostics.some((d) => d.retryable),
383
+ result,
384
+ }));
385
+ } else {
386
+ console.log(JSON.stringify({ ok: result.status === "imported" || result.status === "dry_run", import: result }, null, 2));
387
+ }
388
+ if (result.status !== "imported" && result.status !== "dry_run") process.exit(1);
389
+ } catch (err) {
390
+ reportSdkError(err);
391
+ }
392
+ }
393
+
394
+ function parseSecrets(args) {
395
+ const out = {};
396
+ for (let i = 0; i < args.length; i += 1) {
397
+ if (args[i] !== "--secret") continue;
398
+ const value = args[i + 1];
399
+ if (!value || value.startsWith("--")) {
400
+ fail({ code: "BAD_FLAG", message: "--secret requires KEY=VALUE" });
401
+ }
402
+ const eq = value.indexOf("=");
403
+ if (eq <= 0) {
404
+ fail({ code: "BAD_FLAG", message: "--secret requires KEY=VALUE", details: { value } });
405
+ }
406
+ const key = value.slice(0, eq);
407
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
408
+ fail({ code: "BAD_FLAG", message: `Invalid secret env var name: ${key}` });
409
+ }
410
+ out[key] = value.slice(eq + 1);
411
+ i += 1;
412
+ }
413
+ return out;
414
+ }
415
+
416
+ function firstDiagnosticCode(result) {
417
+ return result.diagnostics.find((d) => d.severity === "blocking")?.code ?? null;
418
+ }
package/lib/argparse.mjs CHANGED
@@ -318,11 +318,11 @@ export function resolvePositionalProject(args, opts = {}) {
318
318
  }
319
319
 
320
320
  // Resolve the project id for a project-scoped command from BOTH accepted
321
- // forms — the canonical `--project <id>` flag and the legacy leading
321
+ // forms — the canonical `--project <project_id>` flag and the legacy leading
322
322
  // positional `prj_...` — with active-project fallback (CLI-wide convention).
323
323
  //
324
324
  // Precedence:
325
- // 1. explicit `--project <id>` (canonical)
325
+ // 1. explicit `--project <project_id>` (canonical)
326
326
  // 2. a leading positional starting with "prj_" (legacy compat, no warning)
327
327
  // 3. the active project (`resolveProjectId(null)`)
328
328
  //
@@ -338,7 +338,7 @@ export function resolvePositionalProject(args, opts = {}) {
338
338
  // requireRestPositional: only treat a leading `prj_` positional as the
339
339
  // project selector when at least one more bare positional follows (counted
340
340
  // with opts.valueFlags). Needed by commands whose OWN attribute is itself a
341
- // project id (e.g. `branches renew <branch-project-id>`).
341
+ // project id (e.g. `branches renew <branch_project_id>`).
342
342
  export function resolveProjectSelector(args, opts = {}) {
343
343
  const list = Array.isArray(args) ? [...args] : [];
344
344
  let flagProject = null;
@@ -361,7 +361,7 @@ export function resolveProjectSelector(args, opts = {}) {
361
361
  fail({
362
362
  code: "BAD_USAGE",
363
363
  message: `Conflicting project ids: --project ${flagProject} vs positional ${first}`,
364
- hint: "Pass the project once — prefer --project <id>.",
364
+ hint: "Pass the project once — prefer --project <project_id>.",
365
365
  details: { project_flag: flagProject, positional: first },
366
366
  });
367
367
  }
@@ -405,7 +405,7 @@ function closestFlag(flag, candidates) {
405
405
  /**
406
406
  * Known subcommands of a command family, derived from COMMAND_MANIFEST
407
407
  * (never hand-maintained). `family` may be multi-word for nested groups
408
- * (e.g. "cloud archives", "email webhooks").
408
+ * (e.g. "deploy releases", "email webhooks").
409
409
  */
410
410
  export function knownSubcommands(family) {
411
411
  const familyWords = String(family).split(" ").filter(Boolean);