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/deploy-v2.mjs CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
- * `run402 deploy apply` and `run402 deploy resume` — CLI wrappers over the
3
- * unified deploy primitive (`r.deploy.apply` / `r.deploy.resume`).
2
+ * `run402 deploy` (the deploy itself) and its family — `rehearse`, `promote`,
3
+ * `resume`, `status`, `list`, `events`, `verify`, `resolve`, `releases` — CLI
4
+ * wrappers over the unified deploy primitive (`r.project(id).apply` and its
5
+ * sub-methods). `run402 up` does missing setup first and then runs this same
6
+ * deploy.
4
7
  *
5
8
  * Manifest format mirrors the MCP `deploy` tool's input schema:
6
9
  * {
@@ -40,22 +43,42 @@ import {
40
43
  } from "#sdk/node";
41
44
  import { getSdk } from "./sdk.mjs";
42
45
  import { reportSdkError, fail } from "./sdk-errors.mjs";
43
- import { API, allowanceAuthHeaders, getActiveProjectId, resolveProjectId, isCoreApiTarget, updateProject } from "./config.mjs";
46
+ import { API, walletAuthHeaders, getActiveProjectId, resolveProjectId, isCoreApiTarget, updateProject } from "./config.mjs";
44
47
  import { delegateTokenFromEnv } from "#sdk/node";
45
48
  import { flagValue, normalizeArgv } from "./argparse.mjs";
46
49
  import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.js";
47
- import { withAutoApprove } from "./operator.mjs";
50
+ import { withAutoApprove } from "./sign-in.mjs";
48
51
  import { editRequestAction, nextAction, retryAction } from "./next-actions.mjs";
49
52
  import { createUpdateCheckScheduler, emitUpdateNotice } from "./update-check.mjs";
50
53
  import { sdkStats, printVerboseStats } from "./stats.mjs";
51
54
 
52
- const APPLY_HELP = `run402 deploy apply — Unified deploy primitive (v1.34+)
55
+ const DEPLOY_HELP = `run402 deploy — Deploy a release from a manifest (the unified deploy primitive)
53
56
 
54
57
  Usage:
55
- run402 deploy apply --manifest <path> [--project <id>] [--check|--print-spec|--print-manifest|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
56
- run402 deploy apply --spec '<json>' [--project <id>] [--check|--print-spec|--print-manifest|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
57
- run402 deploy apply --dir <build-output> [--manifest <path>] [--project <id>]
58
- cat spec.json | run402 deploy apply [--project <id>]
58
+ run402 deploy [--project <project_id>] [--check|--print-spec|--print-manifest|--plan|--require-plan <plan_id>] [--no-rehearse] [--quiet|--final-only] [--json]
59
+ run402 deploy --manifest <path> [--project <project_id>] [...same options]
60
+ run402 deploy --spec '<json>' [--project <project_id>] [...same options]
61
+ run402 deploy --dir <build-output> [--manifest <path>] [--project <project_id>]
62
+ cat spec.json | run402 deploy [--project <project_id>]
63
+ run402 deploy <subcommand> [options]
64
+
65
+ Without --manifest, --spec, --dir, or piped stdin, the manifest is discovered in
66
+ the current directory (run402.json, run402.deploy.json, app.json, or an
67
+ executable run402.deploy.{ts,mts,js,mjs}); when none is there the command fails
68
+ with MANIFEST_NOT_FOUND. \`run402 up\` does any missing setup (wallet, tier,
69
+ project, workspace link) and then runs this same deploy; \`run402 deploy\`
70
+ only deploys.
71
+
72
+ Subcommands:
73
+ rehearse <plan_id> Rehearse a persisted plan on a contained branch
74
+ promote <release_id> Point the live release at an existing release
75
+ resume <operation_id> Resume a stuck operation
76
+ status <operation_id> Fetch one deploy operation's snapshot
77
+ list [--project <project_id>] List recent deploy operations
78
+ events <operation_id> Fetch the event stream for an operation
79
+ verify <operation_id> Verify gateway and edge coherence
80
+ resolve <url> Explain what a public URL would serve
81
+ releases get|active|diff Inspect release inventory and diffs
59
82
 
60
83
  Manifest format mirrors the MCP \`deploy\` tool's ReleaseSpec:
61
84
  {
@@ -100,7 +123,7 @@ Options:
100
123
  database/secrets/subdomains/i18n in the manifest while
101
124
  the slice carries the build output. Requires
102
125
  @run402/astro installed in the project.
103
- --project <id> Override project_id from the manifest
126
+ --project <project_id> Override project_id from the manifest
104
127
  --check Validate and normalize locally. No gateway calls or uploads.
105
128
  --print-spec Advanced SDK-native inspection JSON, not authoring input.
106
129
  --print-manifest Export snake_case authoring JSON relative to the original manifest
@@ -110,7 +133,7 @@ Options:
110
133
  against a project with a live release is rehearsed on a contained
111
134
  branch and committed only on a passing report (result.rehearsal);
112
135
  a first deploy has nothing to protect and commits directly.
113
- --require-plan <id> Apply only if this reviewed plan still matches.
136
+ --require-plan <plan_id> Deploy only if this reviewed plan still matches.
114
137
  --json No-op compatibility flag; success output is always JSON.
115
138
  --quiet Suppress per-event JSON-line stderr (final result still on stdout)
116
139
  --final-only Alias for --quiet; final success/error envelope is still preserved
@@ -172,9 +195,9 @@ const EXECUTABLE_MANIFEST_EXTENSIONS = new Set([".ts", ".mts", ".cts", ".js", ".
172
195
  const RESUME_HELP = `run402 deploy resume — Resume a stuck deploy operation
173
196
 
174
197
  Usage:
175
- run402 deploy resume <operation_id> [--project <id>] [--quiet]
198
+ run402 deploy resume <operation_id> [--project <project_id>] [--quiet]
176
199
 
177
- Used when a previous \`deploy apply\` ended in \`activation_pending\` or
200
+ Used when a previous \`deploy\` ended in \`activation_pending\` or
178
201
  \`schema_settling\` (e.g. transient gateway failure between SQL commit and
179
202
  the pointer-swap activation). The gateway re-runs only the failed phase
180
203
  forward — SQL is never replayed.
@@ -184,13 +207,25 @@ Output:
184
207
  stderr: one JSON event per line (suppressed with --quiet)
185
208
  `;
186
209
 
210
+ const STATUS_HELP = `run402 deploy status — Fetch one deploy operation's snapshot
211
+
212
+ Usage:
213
+ run402 deploy status <operation_id> [--project <project_id>]
214
+
215
+ Options:
216
+ --project <project_id> Project ID that owns the operation (default: active project)
217
+
218
+ Output:
219
+ stdout: { "operation_id": "op_...", "status": "...", "release_id": "rel_..." | null, "urls": {...} | null, ... }
220
+ `;
221
+
187
222
  const LIST_HELP = `run402 deploy list — List recent deploy operations for a project
188
223
 
189
224
  Usage:
190
- run402 deploy list [--project <id>] [--limit <n>]
225
+ run402 deploy list [--project <project_id>] [--limit <n>]
191
226
 
192
227
  Options:
193
- --project <id> Project ID to list operations for (default: active project)
228
+ --project <project_id> Project ID to list operations for (default: active project)
194
229
  --limit <n> Maximum number of operations to return
195
230
 
196
231
  Output:
@@ -200,10 +235,10 @@ Output:
200
235
  const EVENTS_HELP = `run402 deploy events — Fetch the recorded event stream for a deploy operation
201
236
 
202
237
  Usage:
203
- run402 deploy events <operation_id> [--project <id>]
238
+ run402 deploy events <operation_id> [--project <project_id>]
204
239
 
205
240
  Options:
206
- --project <id> Project ID that owns the operation (default: active project)
241
+ --project <project_id> Project ID that owns the operation (default: active project)
207
242
 
208
243
  Output:
209
244
  stdout: { "events": [...] }
@@ -212,16 +247,16 @@ Output:
212
247
  const VERIFY_HELP = `run402 deploy verify — Verify gateway and edge coherence
213
248
 
214
249
  Usage:
215
- run402 deploy verify <operation_id> [--project <id>] [--wait] [--timeout <seconds>] [--json]
216
- run402 deploy verify --operation <operation_id> [--project <id>] [--wait] [--timeout <seconds>] [--json]
250
+ run402 deploy verify <operation_id> [--project <project_id>] [--wait] [--timeout <seconds>] [--json]
251
+ run402 deploy verify --operation <operation_id> [--project <project_id>] [--wait] [--timeout <seconds>] [--json]
217
252
 
218
253
  Checks that the gateway's live release and the edge pointers observed by
219
254
  Run402 agree for the deployment operation. Use --wait to poll until the report
220
255
  is coherent or the timeout elapses.
221
256
 
222
257
  Options:
223
- --operation <id> Operation id to verify. Equivalent to the positional id.
224
- --project <id> Project ID that owns the operation (default: active project)
258
+ --operation <operation_id> Operation id to verify. Equivalent to the positional id.
259
+ --project <project_id> Project ID that owns the operation (default: active project)
225
260
  --wait Poll until coherent or timeout
226
261
  --timeout <seconds> Maximum wait time with --wait (default 60)
227
262
  --json No-op compatibility flag; output is always JSON
@@ -236,10 +271,10 @@ Output:
236
271
  stderr: one JSON poll progress line per attempt when --wait is set
237
272
  `;
238
273
 
239
- const REHEARSE_HELP = `run402 deploy rehearse — Run a plan on a contained branch (ADVANCED; rehearsal is automatic in up / deploy apply)
274
+ const REHEARSE_HELP = `run402 deploy rehearse — Run a plan on a contained branch (ADVANCED; rehearsal is automatic in up / deploy)
240
275
 
241
276
  Usage:
242
- run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <id>] [--teardown on_pass|keep|always] [--json]
277
+ run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <project_id>] [--teardown on_pass|keep|always] [--json]
243
278
 
244
279
  Options:
245
280
  <plan_id> An already-persisted plan. Its bytes must be uploaded; when
@@ -254,18 +289,18 @@ Options:
254
289
  the current directory the same way run402 up does.
255
290
  --teardown <mode> on_pass (default: passed rehearsals delete their branch;
256
291
  failed rehearsals keep it), keep, always.
257
- --project <id> Project for operator-approval metadata and project resolution.
292
+ --project <project_id> Project for write-approval metadata and project resolution.
258
293
 
259
294
  Nothing is committed. The result carries the rehearsal report and the exact
260
- bound commit command (run402 deploy apply --require-plan <plan_id>).
295
+ bound commit command (run402 deploy --require-plan <plan_id>).
261
296
  `;
262
297
 
263
- const RELEASE_HELP = `run402 deploy release — Inspect deploy release inventory and diffs
298
+ const RELEASES_HELP = `run402 deploy releases — Inspect deploy release inventory and diffs
264
299
 
265
300
  Usage:
266
- run402 deploy release get <release_id> [--project <id>] [--site-limit <n>]
267
- run402 deploy release active [--project <id>] [--site-limit <n>]
268
- run402 deploy release diff --from <empty|active|release_id> --to <active|release_id> [--project <id>] [--limit <n>]
301
+ run402 deploy releases get <release_id> [--project <project_id>] [--site-limit <n>]
302
+ run402 deploy releases active [--project <project_id>] [--site-limit <n>]
303
+ run402 deploy releases diff --from <empty|active|release_id> --to <active|release_id> [--project <project_id>] [--limit <n>]
269
304
 
270
305
  Subcommands:
271
306
  get Fetch the inventory for a specific release id
@@ -277,94 +312,83 @@ Output:
277
312
  diff: { "diff": {...} } # includes route added/removed/changed diff buckets
278
313
  `;
279
314
 
280
- const RELEASE_GET_HELP = `run402 deploy release get — Fetch a release inventory by id
315
+ const RELEASES_GET_HELP = `run402 deploy releases get — Fetch a release inventory by id
281
316
 
282
317
  Usage:
283
- run402 deploy release get <release_id> [--project <id>] [--site-limit <n>]
318
+ run402 deploy releases get <release_id> [--project <project_id>] [--site-limit <n>]
284
319
 
285
320
  Options:
286
- --project <id> Project ID that owns the release (default: active project)
321
+ --project <project_id> Project ID that owns the release (default: active project)
287
322
  --site-limit <n> Maximum site path entries to include (gateway default: 5000)
288
323
 
289
324
  Output:
290
325
  stdout: { "release": {...} } # preserves full routes inventory and warnings
291
326
  `;
292
327
 
293
- const RELEASE_ACTIVE_HELP = `run402 deploy release active — Fetch the active release inventory
328
+ const RELEASES_ACTIVE_HELP = `run402 deploy releases active — Fetch the active release inventory
294
329
 
295
330
  Usage:
296
- run402 deploy release active [--project <id>] [--site-limit <n>]
331
+ run402 deploy releases active [--project <project_id>] [--site-limit <n>]
297
332
 
298
333
  Options:
299
- --project <id> Project ID to inspect (default: active project)
334
+ --project <project_id> Project ID to inspect (default: active project)
300
335
  --site-limit <n> Maximum site path entries to include (gateway default: 5000)
301
336
 
302
337
  Output:
303
338
  stdout: { "release": {...} } # preserves full routes inventory and warnings
304
339
  `;
305
340
 
306
- const RELEASE_DIFF_HELP = `run402 deploy release diff — Diff two release targets
341
+ const RELEASES_DIFF_HELP = `run402 deploy releases diff — Diff two release targets
307
342
 
308
343
  Usage:
309
- run402 deploy release diff --from <empty|active|release_id> --to <active|release_id> [--project <id>] [--limit <n>]
344
+ run402 deploy releases diff --from <empty|active|release_id> --to <active|release_id> [--project <project_id>] [--limit <n>]
310
345
 
311
346
  Options:
312
347
  --from <target> Diff source: empty, active, or rel_...
313
348
  --to <target> Diff target: active or rel_...
314
- --project <id> Project ID to inspect (default: active project)
349
+ --project <project_id> Project ID to inspect (default: active project)
315
350
  --limit <n> Maximum entries per site diff bucket (gateway default: 1000)
316
351
 
317
352
  Output:
318
353
  stdout: { "diff": {...} } # preserves routes.added/removed/changed
319
354
  `;
320
355
 
321
- const DIAGNOSE_HELP = `run402 deploy diagnose — Diagnose a Run402 public URL
356
+ const RESOLVE_HELP = `run402 deploy resolve — Explain what a Run402 public URL would serve
322
357
 
323
358
  Usage:
324
- run402 deploy diagnose --project <id> <url> [--method GET]
325
- run402 deploy diagnose <url> [--method GET] # uses active project
359
+ run402 deploy resolve <url> [--project <project_id>] [--method GET]
360
+ run402 deploy resolve --url <url> [--project <project_id>] [--method GET]
361
+ run402 deploy resolve --host <host> [--path /x] [--project <project_id>] [--method GET]
326
362
 
327
- Diagnoses how a project-owned Run402 subdomain or custom domain resolves
363
+ Resolves how a project-owned Run402 subdomain or custom domain would answer
328
364
  against the current live release. This is not an HTTP fetch, cache purge, or
329
365
  CAS URL lookup. Query strings and fragments in URL input are ignored for route
330
366
  resolution and reported in structured warnings.
331
367
 
332
368
  Options:
333
- --project <id> Project ID for local apikey lookup (default: active project)
334
- --method <method> HTTP method to diagnose (default: GET)
335
-
336
- Output:
337
- stdout: { "would_serve": true|false, "diagnostic_status": 200|404|..., "match": "...", "summary": "...", "request": {...}, "warnings": [...], "resolution": {...}, "next_steps": [...] }
338
- `;
339
-
340
- const RESOLVE_HELP = `run402 deploy resolve — Low-level deploy URL diagnostics
341
-
342
- Usage:
343
- run402 deploy resolve --project <id> --url <url> [--method GET]
344
- run402 deploy resolve --project <id> --host <host> [--path /x] [--method GET]
345
- run402 deploy resolve --url <url> [--method GET] # uses active project
346
-
347
- Options:
348
- --project <id> Project ID for local apikey lookup (default: active project)
349
- --url <url> Absolute HTTP(S) public URL to diagnose
369
+ --project <project_id> Project ID for local apikey lookup (default: active project)
370
+ --url <url> Absolute HTTP(S) public URL; same as the positional <url>
350
371
  --host <host> Clean hostname without scheme/path/query/fragment
351
372
  --path </path> Public URL path for host/path mode
352
- --method <method> HTTP method to diagnose (default: GET)
373
+ --method <method> HTTP method to resolve (default: GET)
353
374
 
354
- Do not combine --url with --host or --path. Successful diagnostic misses still
375
+ Do not combine --url (or a positional URL) with --host or --path. Misses still
355
376
  exit 0; inspect would_serve and diagnostic_status in the result payload.
377
+
378
+ Output:
379
+ stdout: { "would_serve": true|false, "diagnostic_status": 200|404|..., "match": "...", "summary": "...", "request": {...}, "warnings": [...], "resolution": {...}, "next_steps": [...] }
356
380
  `;
357
381
 
358
382
  export async function runDeployV2(sub, args) {
359
- if (sub === "apply") return await applyCmd(args);
383
+ if (sub === "deploy") return await deployCmd(args);
360
384
  if (sub === "rehearse") return await rehearseCmd(args);
361
385
  if (sub === "promote") return await promoteCmd(args);
362
386
  if (sub === "resume") return await resumeCmd(args);
387
+ if (sub === "status") return await statusCmd(args);
363
388
  if (sub === "list") return await listCmd(args);
364
389
  if (sub === "events") return await eventsCmd(args);
365
390
  if (sub === "verify") return await verifyCmd(args);
366
- if (sub === "release") return await releaseCmd(args);
367
- if (sub === "diagnose") return await diagnoseCmd(args);
391
+ if (sub === "releases") return await releasesCmd(args);
368
392
  if (sub === "resolve") return await resolveCmd(args);
369
393
  fail({
370
394
  code: "BAD_USAGE",
@@ -373,11 +397,11 @@ export async function runDeployV2(sub, args) {
373
397
  });
374
398
  }
375
399
 
376
- const REHEARSE_MANIFEST_CANDIDATES = ["run402.json", "run402.deploy.json", "app.json", "run402.deploy.ts", "run402.deploy.mts", "run402.deploy.js", "run402.deploy.mjs"];
400
+ const DEPLOY_MANIFEST_CANDIDATES = ["run402.json", "run402.deploy.json", "app.json", "run402.deploy.ts", "run402.deploy.mts", "run402.deploy.js", "run402.deploy.mjs"];
377
401
 
378
- /** The manifest `deploy rehearse` would plan from in `dir`, discovered the way `up` does, or null. */
379
- export function discoverRehearseManifest(dir = process.cwd()) {
380
- for (const name of REHEARSE_MANIFEST_CANDIDATES) {
402
+ /** The manifest `deploy` / `deploy rehearse` would plan from in `dir`, discovered the way `up` does, or null. */
403
+ export function discoverDeployManifest(dir = process.cwd()) {
404
+ for (const name of DEPLOY_MANIFEST_CANDIDATES) {
381
405
  const candidate = resolve(dir, name);
382
406
  if (existsSync(candidate)) return candidate;
383
407
  }
@@ -438,13 +462,13 @@ async function rehearseCmd(rawArgs) {
438
462
  positionals.push(arg);
439
463
  }
440
464
  if (positionals.length > 1) {
441
- fail({ code: "BAD_USAGE", message: "Usage: run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <id>] [--teardown on_pass|keep|always] [--json]" });
465
+ fail({ code: "BAD_USAGE", message: "Usage: run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <project_id>] [--teardown on_pass|keep|always] [--json]" });
442
466
  }
443
467
  const givenPlanId = positionals[0] ?? null;
444
468
  const explicitManifest = flagValue(args, "--manifest");
445
469
  const manifestPath = explicitManifest
446
470
  ? (isAbsolute(explicitManifest) ? explicitManifest : resolve(process.cwd(), explicitManifest))
447
- : discoverRehearseManifest();
471
+ : discoverDeployManifest();
448
472
  if (explicitManifest && !existsSync(manifestPath)) {
449
473
  fail({ code: "BAD_USAGE", message: `Manifest not found: ${manifestPath}`, details: { flag: "--manifest", path: explicitManifest } });
450
474
  }
@@ -452,7 +476,7 @@ async function rehearseCmd(rawArgs) {
452
476
  fail({
453
477
  code: "BAD_USAGE",
454
478
  message: "Nothing to rehearse: pass a <plan_id>, or run from a directory with a manifest (run402.json, run402.deploy.json, app.json), or pass --manifest <path>.",
455
- details: { searched: REHEARSE_MANIFEST_CANDIDATES },
479
+ details: { searched: DEPLOY_MANIFEST_CANDIDATES },
456
480
  });
457
481
  }
458
482
  // When --teardown is absent, omit it from the request body entirely — the
@@ -466,7 +490,7 @@ async function rehearseCmd(rawArgs) {
466
490
  // supports rehearsing with one (the route rejects only CI sessions).
467
491
  // Rehearsal is the SAFE path; never make it the harder one.
468
492
  if (!isCoreApiTarget() && !loadLiveControlPlaneSession() && !delegateTokenFromEnv()) {
469
- allowanceAuthHeaders(`/apply/v1/plans/${givenPlanId ?? "_"}/rehearse`);
493
+ walletAuthHeaders(`/apply/v1/plans/${givenPlanId ?? "_"}/rehearse`);
470
494
  }
471
495
  const sdk = getSdk();
472
496
  const emit = makeStderrEventWriter(false);
@@ -482,14 +506,14 @@ async function rehearseCmd(rawArgs) {
482
506
  });
483
507
  const planId = planned.plan.plan_id;
484
508
  if (!planId) {
485
- fail({ code: "DRY_RUN_PLAN_NOT_COMMITTABLE", message: "Rehearsal requires a persisted plan_id, but the plan response did not include one.", details: { project_id: normalized.spec.project } });
509
+ fail({ code: "DRY_RUN_PLAN_NOT_COMMITTABLE", message: "Rehearsal requires a persisted plan_id, but the plan response did not include one.", details: { project_id: normalized.spec.project_id } });
486
510
  }
487
511
  await sdk._applyEngine.upload(planned.plan, {
488
- project: normalized.spec.project,
512
+ project: normalized.spec.project_id,
489
513
  byteReaders: planned.byteReaders,
490
514
  onEvent: emit,
491
515
  });
492
- return { planId, plan: planned.plan, projectId: normalized.spec.project };
516
+ return { planId, plan: planned.plan, projectId: normalized.spec.project_id };
493
517
  }
494
518
 
495
519
  try {
@@ -521,7 +545,7 @@ async function rehearseCmd(rawArgs) {
521
545
  ...(manifestPath ? { manifest_path: manifestPath } : {}),
522
546
  ...(replanned ? { replanned } : {}),
523
547
  rehearsal,
524
- commit_command: `run402 deploy apply --require-plan ${planId}`,
548
+ commit_command: `run402 deploy --require-plan ${planId}`,
525
549
  }, null, 2));
526
550
  if (rehearsal.report.status !== "passed") process.exit(1);
527
551
  } catch (err) {
@@ -529,14 +553,14 @@ async function rehearseCmd(rawArgs) {
529
553
  }
530
554
  }
531
555
 
532
- const PROMOTE_HELP = `run402 deploy promote — Operator pointer-swap recovery (v1.58+)
556
+ const PROMOTE_HELP = `run402 deploy promote — Pointer-swap recovery (v1.58+)
533
557
 
534
558
  Usage:
535
- run402 deploy promote <release-id> [--project <id>] [--allow-warning <code>] [--allow-warnings] [--quiet]
559
+ run402 deploy promote <release_id> [--project <project_id>] [--allow-warning <code>] [--allow-warnings] [--quiet]
536
560
 
537
561
  Re-points the project's live release at an existing release row without
538
562
  re-running the apply pipeline. Designed for "oops on a real project ID"
539
- recovery — when an apply shipped content the operator regrets, promote
563
+ recovery — when an apply shipped content you regret, promote
540
564
  back to the prior release in seconds instead of re-deploying.
541
565
 
542
566
  Promotable statuses: ready, active, superseded. Releases with status
@@ -569,9 +593,9 @@ The result's edge.state reports convergence and edge.verify_url is the direct,
569
593
  operation-scoped HTTP verification endpoint.
570
594
 
571
595
  Options:
572
- <release-id> Required positional. The release to promote to.
596
+ <release_id> Required positional. The release to promote to.
573
597
  Format: rel_*
574
- --project <id> Project id. Falls back to active project, then
598
+ --project <project_id> Project id. Falls back to active project, then
575
599
  RUN402_PROJECT_ID env var.
576
600
  --allow-warning <code> Acknowledge a specific blocking warning
577
601
  (repeatable).
@@ -697,11 +721,11 @@ async function promoteCmd(args) {
697
721
  emitDeployUpdateNotice("promote", args, { quiet: opts.quiet });
698
722
  const projectId = opts.project ?? resolveProjectId(null);
699
723
 
700
- // Preserve the aggressive early-exit when no allowance is configured
724
+ // Preserve the aggressive early-exit when no local wallet is configured
701
725
  // — same as apply.
702
726
  // A delegate holds `deploy` and the gateway accepts it on this route; refusing
703
727
  // locally would tell a wallet-less holder to run `run402 init` (see 4.11.2).
704
- if (!delegateTokenFromEnv()) allowanceAuthHeaders("/apply/v1/releases");
728
+ if (!delegateTokenFromEnv()) walletAuthHeaders("/apply/v1/releases");
705
729
 
706
730
  try {
707
731
  // Call the engine directly (matches the pattern used by apply / resume
@@ -755,12 +779,12 @@ function makeStderrEventWriter(quiet) {
755
779
 
756
780
  function emitDeployUpdateNotice(subcommand, args, { quiet = false } = {}) {
757
781
  const scheduler = createUpdateCheckScheduler({
758
- command: ["run402", "deploy", subcommand, ...args],
782
+ command: ["run402", "deploy", ...(subcommand ? [subcommand] : []), ...args],
759
783
  });
760
784
  emitUpdateNotice(scheduler.cachedNotice, { quiet });
761
785
  }
762
786
 
763
- function parseApplyArgs(args) {
787
+ function parseDeployArgs(args) {
764
788
  const opts = {
765
789
  manifest: null,
766
790
  spec: null,
@@ -780,7 +804,7 @@ function parseApplyArgs(args) {
780
804
  for (let i = 0; i < args.length; i++) {
781
805
  const arg = args[i];
782
806
  if (arg === "--help" || arg === "-h") {
783
- console.log(APPLY_HELP);
807
+ console.log(DEPLOY_HELP);
784
808
  process.exit(0);
785
809
  }
786
810
  if (arg === "--manifest" || arg === "--spec" || arg === "--dir" || arg === "--project" || arg === "--allow-warning" || arg === "--require-plan" || arg === "--plan-fingerprint" || arg === "--teardown") {
@@ -844,13 +868,13 @@ function parseApplyArgs(args) {
844
868
  if (typeof arg === "string" && arg.startsWith("-")) {
845
869
  fail({
846
870
  code: "BAD_USAGE",
847
- message: `Unknown flag for deploy apply: ${arg}`,
871
+ message: `Unknown flag for deploy: ${arg}`,
848
872
  details: { flag: arg, allowed_flags: allowedFlags },
849
873
  });
850
874
  }
851
875
  fail({
852
876
  code: "BAD_USAGE",
853
- message: `Unexpected argument for deploy apply: ${arg}`,
877
+ message: `Unexpected argument for deploy: ${arg}`,
854
878
  details: { argument: arg },
855
879
  });
856
880
  }
@@ -878,7 +902,7 @@ function setApplyMode(opts, mode, flag) {
878
902
  if (opts.mode !== null) {
879
903
  fail({
880
904
  code: "BAD_USAGE",
881
- message: "Choose only one execution mode for deploy apply.",
905
+ message: "Choose only one execution mode for deploy.",
882
906
  details: { existing_mode: opts.mode, flag },
883
907
  });
884
908
  }
@@ -1052,7 +1076,7 @@ export function collectManifestSourceFiles(spec, baseDir) {
1052
1076
 
1053
1077
  /**
1054
1078
  * Persist an activated release's `deployment_id` into the local keystore.
1055
- * `run402 subdomains claim` reads it as an optimization only — the gateway
1079
+ * `run402 subdomains add` reads it as an optimization only — the gateway
1056
1080
  * binds the live release without it — so this must never throw.
1057
1081
  */
1058
1082
  export function rememberLastDeployment(projectId, deploymentId) {
@@ -1060,11 +1084,34 @@ export function rememberLastDeployment(projectId, deploymentId) {
1060
1084
  try { updateProject(projectId, { last_deployment_id: deploymentId }); } catch { /* best-effort cache */ }
1061
1085
  }
1062
1086
 
1063
- async function applyCmd(args) {
1064
- const opts = parseApplyArgs(args);
1065
- const { source, error: sourceError } = resolveApplySource(opts, hasStdinSource());
1087
+ async function deployCmd(args) {
1088
+ const opts = parseDeployArgs(args);
1089
+ const stdinPresent = hasStdinSource();
1090
+ if (opts.manifest === null && opts.spec === null && opts.dir === null && !stdinPresent) {
1091
+ // Bare `run402 deploy`: the manifest is the one in the current directory,
1092
+ // discovered the way `up` discovers it. None there is a typed refusal,
1093
+ // never a help page — `deploy` is a verb.
1094
+ const discovered = discoverDeployManifest();
1095
+ if (!discovered) {
1096
+ fail({
1097
+ code: "MANIFEST_NOT_FOUND",
1098
+ message: `No deploy manifest found in ${process.cwd()}. Add run402.json, run402.deploy.json or app.json here, or pass --manifest <path>.`,
1099
+ details: { dir: process.cwd(), candidates: DEPLOY_MANIFEST_CANDIDATES },
1100
+ next_actions: [
1101
+ {
1102
+ type: "create_manifest",
1103
+ path: "run402.json",
1104
+ content: JSON.stringify({ site: { replace: { "index.html": { path: "index.html" } } } }, null, 2),
1105
+ why: "Write a deploy manifest, then re-run `run402 deploy`. This minimal site manifest deploys as-is; add database/functions/routes slices later.",
1106
+ },
1107
+ ],
1108
+ });
1109
+ }
1110
+ opts.manifest = discovered;
1111
+ }
1112
+ const { source, error: sourceError } = resolveApplySource(opts, stdinPresent);
1066
1113
  if (sourceError) fail(sourceError);
1067
- emitDeployUpdateNotice("apply", args, { quiet: opts.quiet });
1114
+ emitDeployUpdateNotice(null, args, { quiet: opts.quiet });
1068
1115
 
1069
1116
  let raw;
1070
1117
  let manifestPath = null;
@@ -1121,11 +1168,11 @@ async function applyCmd(args) {
1121
1168
  }
1122
1169
 
1123
1170
  // Reject empty specs client-side. Without this guard,
1124
- // `run402 deploy apply --spec '{}'` (and `--manifest <empty>`) would silently
1171
+ // `run402 deploy --spec '{}'` (and `--manifest <empty>`) would silently
1125
1172
  // send an empty ReleaseSpec to /apply/v1/plans with no signal that nothing
1126
1173
  // was deployed.
1127
1174
  //
1128
- // `deploy apply` is v2-only — only meaningful keys are the v2 ReleaseSpec
1175
+ // `deploy` is v2-only — only meaningful keys are the v2 ReleaseSpec
1129
1176
  // shape (database, site, functions, secrets, subdomains, domains).
1130
1177
  // For object-typed sections the "container is non-empty" check isn't enough
1131
1178
  // — `site:{replace:{}}` has one key but ships nothing. We recurse one level
@@ -1203,11 +1250,11 @@ async function applyCmd(args) {
1203
1250
  target = await resolveDeploymentTarget({
1204
1251
  appRoot: applicationScope.app_root,
1205
1252
  manifestPath: manifestPath ?? undefined, projectId: opts.project || undefined, environmentProjectId: process.env.RUN402_PROJECT_ID || undefined,
1206
- manifestProjectId: manifestProject || (releaseSpec.project === "prj_up_preflight_placeholder" ? undefined : releaseSpec.project),
1253
+ manifestProjectId: manifestProject || (releaseSpec.project_id === "prj_up_preflight_placeholder" ? undefined : releaseSpec.project_id),
1207
1254
  targetKind: isCoreApiTarget() ? "core" : "cloud", apiBase: API,
1208
1255
  allowUnresolved: opts.mode === "check" || opts.mode === "printSpec" || opts.mode === "printManifest",
1209
1256
  });
1210
- if (target.project_id) releaseSpec.project = target.project_id;
1257
+ if (target.project_id) releaseSpec.project_id = target.project_id;
1211
1258
  } catch (err) { reportSdkError(err); }
1212
1259
  const idempotencyKey = normalizedManifest.idempotencyKey;
1213
1260
 
@@ -1233,7 +1280,7 @@ async function applyCmd(args) {
1233
1280
  ok: true,
1234
1281
  mode: "check",
1235
1282
  project_id: target.project_id,
1236
- ...describeLocalPreflight({ entryPoint: "deploy apply", appRoot: manifestPath ? dirname(manifestPath) : resolve(opts.dir || process.cwd()), manifestPath, authoring: normalizedManifest.manifest, spec: releaseSpec, target, apiBase: API }),
1283
+ ...describeLocalPreflight({ entryPoint: "deploy", appRoot: manifestPath ? dirname(manifestPath) : resolve(opts.dir || process.cwd()), manifestPath, authoring: normalizedManifest.manifest, spec: releaseSpec, target, apiBase: API }),
1237
1284
  }, null, 2));
1238
1285
  return;
1239
1286
  }
@@ -1242,7 +1289,7 @@ async function applyCmd(args) {
1242
1289
  return;
1243
1290
  }
1244
1291
  if (opts.mode === "printSpec") {
1245
- console.log(JSON.stringify({ ...releaseSpec, project: target.project_id ?? undefined }, null, 2));
1292
+ console.log(JSON.stringify({ ...releaseSpec, project_id: target.project_id ?? undefined }, null, 2));
1246
1293
  return;
1247
1294
  }
1248
1295
 
@@ -1251,22 +1298,22 @@ async function applyCmd(args) {
1251
1298
  const delegateToken = delegateTokenFromEnv();
1252
1299
  if (useGithubActionsOidc) {
1253
1300
  sdkOpts = {
1254
- credentials: githubActionsCredentials({ projectId: releaseSpec.project, apiBase: API }),
1301
+ credentials: githubActionsCredentials({ projectId: releaseSpec.project_id, apiBase: API }),
1255
1302
  disablePaidFetch: true,
1256
1303
  };
1257
1304
  } else if (delegateToken) {
1258
1305
  // A delegate is a complete, self-contained deploy credential: the owner
1259
1306
  // minted it with their wallet and handed it over, so this process needs no
1260
- // allowance of its own. Skipping the guard is the point — an agent that
1307
+ // wallet of its own. Skipping the guard is the point — an agent that
1261
1308
  // lost its local state (or never had a wallet) can still deploy. Paid fetch
1262
1309
  // is disabled for the same reason it is under CI: a delegate authorizes
1263
1310
  // deploys, not spending.
1264
1311
  sdkOpts = { delegateToken, disablePaidFetch: true };
1265
1312
  } else if (!isCoreApiTarget() && !loadLiveControlPlaneSession()) {
1266
- // Aggressive early exit when no allowance is configured — unless a
1267
- // wallet-less human is deploying via their operator (control-plane) session
1313
+ // Aggressive early exit when no local wallet is configured — unless a
1314
+ // wallet-less person is deploying via their sign-in session
1268
1315
  // or the active target is a self-hosted Core Gateway.
1269
- allowanceAuthHeaders("/apply/v1/plans");
1316
+ walletAuthHeaders("/apply/v1/plans");
1270
1317
  }
1271
1318
 
1272
1319
  try {
@@ -1302,14 +1349,14 @@ async function applyCmd(args) {
1302
1349
  target: isCoreApiTarget() ? "core" : "cloud",
1303
1350
  ...(opts.allowDirty ? { allowDirty: true } : {}),
1304
1351
  // The `gitvault_commit` line is printed ALWAYS, and to stderr, so
1305
- // `run402 deploy apply | jq` stays clean (the pipe contract).
1352
+ // `run402 deploy | jq` stays clean (the pipe contract).
1306
1353
  onCommitLine: (line) => { if (!opts.quiet) process.stderr.write(`${line}\n`); },
1307
1354
  }),
1308
1355
  );
1309
- // Cache the activated deployment id so `run402 subdomains claim` can
1356
+ // Cache the activated deployment id so `run402 subdomains add` can
1310
1357
  // pass it as an optimization (the gateway defaults to the live release
1311
1358
  // without it). Best-effort: a keystore hiccup never fails the deploy.
1312
- rememberLastDeployment(releaseSpec.project, outcome.deploy?.urls?.deployment_id);
1359
+ rememberLastDeployment(releaseSpec.project_id, outcome.deploy?.urls?.deployment_id);
1313
1360
  if (!outcome.gitvault) {
1314
1361
  console.log(JSON.stringify({ ...outcome.deploy, stats: sdkStats(sdk) }, null, 2));
1315
1362
  printVerboseStats(opts.verbose, sdk);
@@ -1420,7 +1467,7 @@ const CI_DEPLOY_ERROR_GUIDANCE = {
1420
1467
  hint: "The GitHub repository id in the OIDC token does not match the linked binding.",
1421
1468
  next_actions: [
1422
1469
  editRequestAction("run402 ci link github", "Re-link from the current repository."),
1423
- editRequestAction("run402 ci link github --repository-id <id>", "Pass the numeric GitHub repository id if automatic lookup fails."),
1470
+ editRequestAction("run402 ci link github --repository-id <repository_id>", "Pass the numeric GitHub repository id if automatic lookup fails."),
1424
1471
  ],
1425
1472
  },
1426
1473
  forbidden_spec_field: {
@@ -1435,14 +1482,14 @@ const CI_DEPLOY_ERROR_GUIDANCE = {
1435
1482
  next_actions: [
1436
1483
  editRequestAction("run402 ci link github --route-scope <pattern>", "Add a CI route scope for every exact or prefix path the workflow may deploy."),
1437
1484
  nextAction("edit_request", { why: "Use exact scopes such as --route-scope /admin or prefix scopes such as --route-scope /api/*." }),
1438
- editRequestAction("run402 deploy apply", "Run route changes locally when they are outside the CI delegation."),
1485
+ editRequestAction("run402 deploy", "Run route changes locally when they are outside the CI delegation."),
1439
1486
  ],
1440
1487
  },
1441
1488
  forbidden_plan: {
1442
1489
  hint: "The gateway rejected this deploy plan for CI. Keep CI deploys to the allowed resources and re-link if policy changed.",
1443
1490
  next_actions: [
1444
1491
  nextAction("edit_request", { why: "Inspect the gateway error details for the rejected resource." }),
1445
- editRequestAction("run402 deploy apply", "Run operations outside the CI allowlist locally."),
1492
+ editRequestAction("run402 deploy", "Run operations outside the CI allowlist locally."),
1446
1493
  ],
1447
1494
  },
1448
1495
  payment_required: {
@@ -1456,7 +1503,7 @@ const CI_DEPLOY_ERROR_GUIDANCE = {
1456
1503
 
1457
1504
  /**
1458
1505
  * The gateway's envelope for gitvault deploy errors — `upgrade_client` first,
1459
- * then `grandfather_policy` — is relayed untouched: `applyCmd` deploys
1506
+ * then `grandfather_policy` — is relayed untouched: `deployCmd` deploys
1460
1507
  * through `applyWithGitvault`, which declares `{capture_id,
1461
1508
  * snapshot_oid_hmac}` at plan time and presents an activation token at
1462
1509
  * commit, satisfying `gitvault_policy: required`, so no client-side rewrite
@@ -1493,8 +1540,8 @@ function enhanceDeployWarningError(err) {
1493
1540
  ? [code]
1494
1541
  : [];
1495
1542
  const allowWarningCommand = unacknowledgedCodes.length > 0
1496
- ? `run402 deploy apply ${unacknowledgedCodes.map((warningCode) => `--allow-warning ${warningCode}`).join(" ")}`
1497
- : "run402 deploy apply --allow-warning <code>";
1543
+ ? `run402 deploy ${unacknowledgedCodes.map((warningCode) => `--allow-warning ${warningCode}`).join(" ")}`
1544
+ : "run402 deploy --allow-warning <code>";
1498
1545
  const allowWarningAction = editRequestAction(
1499
1546
  allowWarningCommand,
1500
1547
  unacknowledgedCodes.length > 0
@@ -1505,9 +1552,9 @@ function enhanceDeployWarningError(err) {
1505
1552
  ...(affected.length > 0
1506
1553
  ? [editRequestAction("run402 secrets set <project> <KEY> --stdin", `Set or inspect affected secrets: ${Array.from(new Set(affected)).join(", ")}`)]
1507
1554
  : []),
1508
- retryAction("run402 deploy apply", "Retry after resolving warnings."),
1555
+ retryAction("run402 deploy", "Retry after resolving warnings."),
1509
1556
  allowWarningAction,
1510
- editRequestAction("run402 deploy apply --allow-warnings", "Use only when every warning was explicitly reviewed."),
1557
+ editRequestAction("run402 deploy --allow-warnings", "Use only when every warning was explicitly reviewed."),
1511
1558
  ];
1512
1559
  enhanced.body = {
1513
1560
  ...existingBody,
@@ -1516,7 +1563,7 @@ function enhanceDeployWarningError(err) {
1516
1563
  hint: existingBody.hint ||
1517
1564
  routeGuidance?.hint ||
1518
1565
  (code === "MISSING_REQUIRED_SECRET"
1519
- ? "Set the missing secret values with `run402 secrets set <project> <KEY> --stdin` or `--file <path>`, then retry deploy apply."
1566
+ ? "Set the missing secret values with `run402 secrets set <project> <KEY> --stdin` or `--file <path>`, then retry the deploy."
1520
1567
  : "Review the plan warnings, then retry with --allow-warning <code> for reviewed warnings if you intentionally accept them."),
1521
1568
  next_actions: Array.isArray(existingBody.next_actions) && existingBody.next_actions.length > 0
1522
1569
  ? existingBody.next_actions
@@ -1536,22 +1583,22 @@ const ROUTE_WARNING_GUIDANCE = {
1536
1583
  nextAction("edit_request", { why: "Review application auth and authorization in the routed function." }),
1537
1584
  nextAction("edit_request", { why: "Add CSRF protection for cookie-authenticated POST/PUT/PATCH/DELETE routes." }),
1538
1585
  nextAction("edit_request", { why: "Implement CORS and OPTIONS explicitly when cross-origin callers are intended." }),
1539
- retryAction("run402 deploy apply --allow-warning <code>", "Acknowledge only the warning that has requires_confirmation: true, after review."),
1586
+ retryAction("run402 deploy --allow-warning <code>", "Acknowledge only the warning that has requires_confirmation: true, after review."),
1540
1587
  ],
1541
1588
  },
1542
1589
  ROUTE_TARGET_CARRIED_FORWARD: {
1543
1590
  hint: "A carried-forward route still points at a base-release function target.",
1544
1591
  next_actions: [
1545
- editRequestAction("run402 deploy release active", "Inspect the active release."),
1546
- editRequestAction("run402 deploy apply --manifest <path>", "Deploy routes.replace if the target should change in this release."),
1592
+ editRequestAction("run402 deploy releases active", "Inspect the active release."),
1593
+ editRequestAction("run402 deploy --manifest <path>", "Deploy routes.replace if the target should change in this release."),
1547
1594
  ],
1548
1595
  },
1549
1596
  ROUTE_SHADOWS_STATIC_PATH: {
1550
1597
  hint: "A dynamic route shadows a static site path.",
1551
1598
  next_actions: [
1552
1599
  nextAction("edit_request", { why: "Inspect the warning details for affected static paths." }),
1553
- editRequestAction("run402 deploy release active", "Inspect live routes."),
1554
- retryAction("run402 deploy apply --allow-warnings", "Retry only when dynamic shadowing is intentional."),
1600
+ editRequestAction("run402 deploy releases active", "Inspect live routes."),
1601
+ retryAction("run402 deploy --allow-warnings", "Retry only when dynamic shadowing is intentional."),
1555
1602
  ],
1556
1603
  },
1557
1604
  WILDCARD_ROUTE_SHADOWS_STATIC_PATHS: {
@@ -1559,7 +1606,7 @@ const ROUTE_WARNING_GUIDANCE = {
1559
1606
  next_actions: [
1560
1607
  nextAction("edit_request", { why: "Review affected route/static path details." }),
1561
1608
  nextAction("edit_request", { why: "Split exact routes or move static paths if the shadowing is accidental." }),
1562
- retryAction("run402 deploy apply --allow-warnings", "Retry only when the wildcard shadowing is intentional."),
1609
+ retryAction("run402 deploy --allow-warnings", "Retry only when the wildcard shadowing is intentional."),
1563
1610
  ],
1564
1611
  },
1565
1612
  METHOD_SPECIFIC_ROUTE_ALLOWS_GET_STATIC_FALLBACK: {
@@ -1575,7 +1622,7 @@ const ROUTE_WARNING_GUIDANCE = {
1575
1622
  nextAction("edit_request", { why: "Add the mutation methods the routed function supports, such as POST." }),
1576
1623
  nextAction("edit_request", { why: "Omit methods to allow every supported method when the route is an API surface." }),
1577
1624
  nextAction("edit_request", { why: "Set acknowledge_readonly: true on an intentionally read-only GET/HEAD wildcard function route." }),
1578
- retryAction("run402 deploy apply --allow-warning WILDCARD_ROUTE_EXCLUDES_MUTATION_METHODS", "Use only as a reviewed CLI escape hatch."),
1625
+ retryAction("run402 deploy --allow-warning WILDCARD_ROUTE_EXCLUDES_MUTATION_METHODS", "Use only as a reviewed CLI escape hatch."),
1579
1626
  ],
1580
1627
  },
1581
1628
  ROUTE_TABLE_NEAR_LIMIT: {
@@ -1674,7 +1721,7 @@ function rejectLegacySecretManifest(spec, details) {
1674
1721
  if (Array.isArray(secrets) && secrets.length > 0) {
1675
1722
  fail({
1676
1723
  code: "UNSAFE_SECRET_MANIFEST",
1677
- message: "Deploy manifests must not contain secret values. Legacy secrets arrays are no longer supported by deploy apply.",
1724
+ message: "Deploy manifests must not contain secret values. Secrets arrays are not a deploy manifest shape.",
1678
1725
  hint: "Run `run402 secrets set <project> <KEY> --file <path>` first, then use `\"secrets\": { \"require\": [\"KEY\"] }` in the deploy manifest.",
1679
1726
  details: { ...details, field: "secrets", legacy_shape: "array" },
1680
1727
  });
@@ -1721,7 +1768,7 @@ async function resumeCmd(args) {
1721
1768
 
1722
1769
  // A delegate holds `deploy` and the gateway accepts it on this route; refusing
1723
1770
  // locally would tell a wallet-less holder to run `run402 init` (see 4.11.2).
1724
- if (!delegateTokenFromEnv()) allowanceAuthHeaders("/apply/v1/operations");
1771
+ if (!delegateTokenFromEnv()) walletAuthHeaders("/apply/v1/operations");
1725
1772
 
1726
1773
  try {
1727
1774
  const result = await getSdk({ disablePaidFetch: true })._applyEngine.resume(opts.operationId, {
@@ -1734,6 +1781,31 @@ async function resumeCmd(args) {
1734
1781
  }
1735
1782
  }
1736
1783
 
1784
+ async function statusCmd(args) {
1785
+ const parsed = parseDeploySubcommandArgs(args, {
1786
+ command: "deploy status",
1787
+ help: STATUS_HELP,
1788
+ valueFlags: ["--project"],
1789
+ });
1790
+ const [operationId] = expectPositionals(parsed.positionals, {
1791
+ command: "run402 deploy status <operation_id>",
1792
+ min: 1,
1793
+ max: 1,
1794
+ missing: "Missing <operation_id>.",
1795
+ });
1796
+ const project = resolveProjectId(parsed.flags["--project"] ?? null);
1797
+ // A delegate holds `deploy` and the gateway accepts it on this route; refusing
1798
+ // locally would tell a wallet-less holder to run `run402 init` (see 4.11.2).
1799
+ if (!delegateTokenFromEnv()) walletAuthHeaders("/apply/v1/operations");
1800
+
1801
+ try {
1802
+ const result = await getSdk()._applyEngine.status(operationId, { project });
1803
+ console.log(JSON.stringify(result, null, 2));
1804
+ } catch (err) {
1805
+ reportSdkError(err);
1806
+ }
1807
+ }
1808
+
1737
1809
  async function listCmd(args) {
1738
1810
  const parsed = parseDeploySubcommandArgs(args, {
1739
1811
  command: "deploy list",
@@ -1741,7 +1813,7 @@ async function listCmd(args) {
1741
1813
  valueFlags: ["--project", "--limit"],
1742
1814
  });
1743
1815
  expectPositionals(parsed.positionals, {
1744
- command: "run402 deploy list [--project <id>] [--limit <n>]",
1816
+ command: "run402 deploy list [--project <project_id>] [--limit <n>]",
1745
1817
  max: 0,
1746
1818
  });
1747
1819
  const opts = {
@@ -1757,21 +1829,21 @@ async function listCmd(args) {
1757
1829
  // ever widened, widen the ROUTE first, then this guard.
1758
1830
  //
1759
1831
  // The refusal is correct; the REMEDY must still be honest. Falling through
1760
- // to NO_ALLOWANCE would tell a delegate holder to run `run402 init`, which
1832
+ // to NO_WALLET would tell a delegate holder to run `run402 init`, which
1761
1833
  // is wrong for a credential that is wallet-less by design — the same
1762
1834
  // misleading-remedy shape removed from the payment path in 4.11.2.
1763
1835
  if (delegateTokenFromEnv()) {
1764
1836
  fail({
1765
1837
  code: "DELEGATE_SCOPE_INSUFFICIENT",
1766
1838
  message: "Listing deploy operations is not available to a delegate.",
1767
- hint: "Use `run402 deploy events <operation_id>` or `deploy verify <operation_id>` for a specific operation, which a delegate CAN read. A full listing needs the project apikey or the owner wallet.",
1839
+ hint: "Use `run402 deploy status <operation_id>`, `deploy events <operation_id>` or `deploy verify <operation_id>` for a specific operation, which a delegate CAN read. A full listing needs the project apikey or the owner wallet.",
1768
1840
  details: { command: "deploy list", credential: "delegate", route: "GET /apply/v1/operations" },
1769
1841
  next_actions: [
1770
- { type: "run_command", command: "run402 deploy events <operation_id>", why: "Per-operation reads are within a delegate's deploy scope." },
1842
+ { type: "run_command", command: "run402 deploy status <operation_id>", why: "Per-operation reads are within a delegate's deploy scope." },
1771
1843
  ],
1772
1844
  });
1773
1845
  }
1774
- allowanceAuthHeaders("/apply/v1/operations");
1846
+ walletAuthHeaders("/apply/v1/operations");
1775
1847
 
1776
1848
  try {
1777
1849
  const sdkOpts = { project };
@@ -1800,7 +1872,7 @@ async function eventsCmd(args) {
1800
1872
  const project = resolveProjectId(opts.project);
1801
1873
  // A delegate holds `deploy` and the gateway accepts it on this route; refusing
1802
1874
  // locally would tell a wallet-less holder to run `run402 init` (see 4.11.2).
1803
- if (!delegateTokenFromEnv()) allowanceAuthHeaders("/apply/v1/operations");
1875
+ if (!delegateTokenFromEnv()) walletAuthHeaders("/apply/v1/operations");
1804
1876
 
1805
1877
  try {
1806
1878
  const result = await getSdk()._applyEngine.events(opts.operationId, { project });
@@ -1818,7 +1890,7 @@ async function verifyCmd(args) {
1818
1890
  booleanFlags: ["--wait", "--json"],
1819
1891
  });
1820
1892
  const positionals = expectPositionals(parsed.positionals, {
1821
- command: "run402 deploy verify <operation_id> [--project <id>] [--wait]",
1893
+ command: "run402 deploy verify <operation_id> [--project <project_id>] [--wait]",
1822
1894
  max: 1,
1823
1895
  });
1824
1896
  const positionalOperationId = positionals[0] ?? null;
@@ -1835,7 +1907,7 @@ async function verifyCmd(args) {
1835
1907
  fail({
1836
1908
  code: "BAD_USAGE",
1837
1909
  message: "Missing <operation_id>.",
1838
- hint: "run402 deploy verify <operation_id> [--project <id>] [--wait]",
1910
+ hint: "run402 deploy verify <operation_id> [--project <project_id>] [--wait]",
1839
1911
  });
1840
1912
  }
1841
1913
  const project = resolveProjectId(parsed.flags["--project"] ?? null);
@@ -1846,7 +1918,7 @@ async function verifyCmd(args) {
1846
1918
 
1847
1919
  // A delegate holds `deploy` and the gateway accepts it on this route; refusing
1848
1920
  // locally would tell a wallet-less holder to run `run402 init` (see 4.11.2).
1849
- if (!delegateTokenFromEnv()) allowanceAuthHeaders("/apply/v1/operations");
1921
+ if (!delegateTokenFromEnv()) walletAuthHeaders("/apply/v1/operations");
1850
1922
 
1851
1923
  try {
1852
1924
  let result;
@@ -1906,30 +1978,30 @@ function summarizeEdgeCoherencePaths(paths) {
1906
1978
  }));
1907
1979
  }
1908
1980
 
1909
- async function releaseCmd(args) {
1981
+ async function releasesCmd(args) {
1910
1982
  const action = args[0];
1911
1983
  if (!action || action === "--help" || action === "-h") {
1912
- console.log(RELEASE_HELP);
1984
+ console.log(RELEASES_HELP);
1913
1985
  process.exit(0);
1914
1986
  }
1915
- if (action === "get") return await releaseGetCmd(args.slice(1));
1916
- if (action === "active") return await releaseActiveCmd(args.slice(1));
1917
- if (action === "diff") return await releaseDiffCmd(args.slice(1));
1987
+ if (action === "get") return await releasesGetCmd(args.slice(1));
1988
+ if (action === "active") return await releasesActiveCmd(args.slice(1));
1989
+ if (action === "diff") return await releasesDiffCmd(args.slice(1));
1918
1990
  fail({
1919
1991
  code: "BAD_USAGE",
1920
- message: `Unknown deploy release subcommand: ${action}`,
1992
+ message: `Unknown deploy releases subcommand: ${action}`,
1921
1993
  details: { subcommand: action },
1922
1994
  });
1923
1995
  }
1924
1996
 
1925
- async function releaseGetCmd(args) {
1997
+ async function releasesGetCmd(args) {
1926
1998
  const parsed = parseDeploySubcommandArgs(args, {
1927
- command: "deploy release get",
1928
- help: RELEASE_GET_HELP,
1999
+ command: "deploy releases get",
2000
+ help: RELEASES_GET_HELP,
1929
2001
  valueFlags: ["--project", "--site-limit"],
1930
2002
  });
1931
2003
  const [releaseId] = expectPositionals(parsed.positionals, {
1932
- command: "run402 deploy release get <release_id>",
2004
+ command: "run402 deploy releases get <release_id>",
1933
2005
  min: 1,
1934
2006
  max: 1,
1935
2007
  missing: "Missing <release_id>.",
@@ -1954,14 +2026,14 @@ async function releaseGetCmd(args) {
1954
2026
  }
1955
2027
  }
1956
2028
 
1957
- async function releaseActiveCmd(args) {
2029
+ async function releasesActiveCmd(args) {
1958
2030
  const parsed = parseDeploySubcommandArgs(args, {
1959
- command: "deploy release active",
1960
- help: RELEASE_ACTIVE_HELP,
2031
+ command: "deploy releases active",
2032
+ help: RELEASES_ACTIVE_HELP,
1961
2033
  valueFlags: ["--project", "--site-limit"],
1962
2034
  });
1963
2035
  expectPositionals(parsed.positionals, {
1964
- command: "run402 deploy release active [--project <id>] [--site-limit <n>]",
2036
+ command: "run402 deploy releases active [--project <project_id>] [--site-limit <n>]",
1965
2037
  max: 0,
1966
2038
  });
1967
2039
  const opts = {
@@ -1983,14 +2055,14 @@ async function releaseActiveCmd(args) {
1983
2055
  }
1984
2056
  }
1985
2057
 
1986
- async function releaseDiffCmd(args) {
2058
+ async function releasesDiffCmd(args) {
1987
2059
  const parsed = parseDeploySubcommandArgs(args, {
1988
- command: "deploy release diff",
1989
- help: RELEASE_DIFF_HELP,
2060
+ command: "deploy releases diff",
2061
+ help: RELEASES_DIFF_HELP,
1990
2062
  valueFlags: ["--project", "--from", "--to", "--limit"],
1991
2063
  });
1992
2064
  expectPositionals(parsed.positionals, {
1993
- command: "run402 deploy release diff --from <target> --to <target>",
2065
+ command: "run402 deploy releases diff --from <target> --to <target>",
1994
2066
  max: 0,
1995
2067
  });
1996
2068
  const opts = {
@@ -2003,7 +2075,7 @@ async function releaseDiffCmd(args) {
2003
2075
  fail({
2004
2076
  code: "BAD_USAGE",
2005
2077
  message: "Missing --from or --to release target.",
2006
- hint: "run402 deploy release diff --from empty --to active",
2078
+ hint: "run402 deploy releases diff --from empty --to active",
2007
2079
  });
2008
2080
  }
2009
2081
  if (opts.to === "empty") {
@@ -2026,41 +2098,6 @@ async function releaseDiffCmd(args) {
2026
2098
  }
2027
2099
  }
2028
2100
 
2029
- async function diagnoseCmd(args) {
2030
- const opts = { project: null, url: null, method: "GET" };
2031
- for (let i = 0; i < args.length; i++) {
2032
- const arg = args[i];
2033
- if (arg === "--help" || arg === "-h") { console.log(DIAGNOSE_HELP); process.exit(0); }
2034
- if (arg === "--json") { continue; }
2035
- if (arg === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
2036
- if (arg === "--method" && args[i + 1]) { opts.method = args[++i]; continue; }
2037
- if (arg?.startsWith("--project=")) { opts.project = arg.slice("--project=".length); continue; }
2038
- if (arg?.startsWith("--method=")) { opts.method = arg.slice("--method=".length); continue; }
2039
- if (arg?.startsWith("-")) {
2040
- fail({ code: "BAD_USAGE", message: `Unknown flag for deploy diagnose: ${arg}`, details: { flag: arg } });
2041
- }
2042
- if (!opts.url) {
2043
- opts.url = arg;
2044
- continue;
2045
- }
2046
- fail({
2047
- code: "BAD_USAGE",
2048
- message: "deploy diagnose accepts exactly one URL argument.",
2049
- hint: "run402 deploy diagnose --project prj_... https://example.com/path --method GET",
2050
- });
2051
- }
2052
- if (!opts.url) {
2053
- fail({
2054
- code: "BAD_USAGE",
2055
- message: "Missing <url>.",
2056
- hint: "run402 deploy diagnose --project prj_... https://example.com/path --method GET",
2057
- });
2058
- }
2059
-
2060
- const project = resolveProjectId(opts.project);
2061
- await printResolveEnvelope({ project, url: opts.url, method: opts.method });
2062
- }
2063
-
2064
2101
  async function resolveCmd(args) {
2065
2102
  const opts = { project: null, url: null, host: null, path: null, method: "GET" };
2066
2103
  for (let i = 0; i < args.length; i++) {
@@ -2077,21 +2114,32 @@ async function resolveCmd(args) {
2077
2114
  if (arg?.startsWith("--host=")) { opts.host = arg.slice("--host=".length); continue; }
2078
2115
  if (arg?.startsWith("--path=")) { opts.path = arg.slice("--path=".length); continue; }
2079
2116
  if (arg?.startsWith("--method=")) { opts.method = arg.slice("--method=".length); continue; }
2080
- fail({ code: "BAD_USAGE", message: `Unknown argument for deploy resolve: ${arg}`, details: { argument: arg } });
2117
+ if (arg?.startsWith("-")) {
2118
+ fail({ code: "BAD_USAGE", message: `Unknown flag for deploy resolve: ${arg}`, details: { flag: arg } });
2119
+ }
2120
+ if (opts.url) {
2121
+ fail({
2122
+ code: "BAD_USAGE",
2123
+ message: "deploy resolve accepts exactly one URL.",
2124
+ hint: "run402 deploy resolve https://example.com/path --project prj_... --method GET",
2125
+ details: { argument: arg, already_have: opts.url },
2126
+ });
2127
+ }
2128
+ opts.url = arg;
2081
2129
  }
2082
2130
 
2083
2131
  if (opts.url && (opts.host || opts.path)) {
2084
2132
  fail({
2085
2133
  code: "BAD_USAGE",
2086
- message: "Do not combine --url with --host or --path.",
2134
+ message: "Do not combine --url (or a positional URL) with --host or --path.",
2087
2135
  details: { url: Boolean(opts.url), host: Boolean(opts.host), path: Boolean(opts.path) },
2088
2136
  });
2089
2137
  }
2090
2138
  if (!opts.url && !opts.host) {
2091
2139
  fail({
2092
2140
  code: "BAD_USAGE",
2093
- message: "Missing resolve input. Pass --url <url> or --host <host> [--path /x].",
2094
- hint: "run402 deploy resolve --project prj_... --url https://example.com/",
2141
+ message: "Missing <url>. Pass a URL, --url <url>, or --host <host> [--path /x].",
2142
+ hint: "run402 deploy resolve https://example.com/ --project prj_...",
2095
2143
  });
2096
2144
  }
2097
2145