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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Command-line interface for [Run402](https://run402.com) — provision Postgres databases, deploy static sites, run Node 22 serverless functions, host content-addressed CDN assets, send email, sign on-chain. Paid autonomously with x402 (USDC on Base) or MPP (pathUSD on Tempo, or sats over Bitcoin Lightning). **Prototype tier is free on testnet.**
6
6
 
7
- The CLI lets an agent act as its own first-class Run402 principal rather than borrowing a human account. Identity records who invoked an action; organization roles, grants, delegates, freshness, and spend policy determine what that principal may do. People remain first-class owners and collaborators without becoming routine CLI operators.
7
+ The CLI lets an agent act as its own first-class Run402 principal rather than borrowing a human account. Identity records who invoked an action; organization roles, grants, delegates, freshness, and spend policy determine what that principal may do. People remain first-class owners and members without having to run the CLI themselves.
8
8
 
9
9
  For the full CLI reference (every flag, every subcommand) start at **<https://docs.run402.com/llms-cli.txt>** — the index holds the first-deploy contract and links one fetchable `/llms-cli-<slice>.txt` per topic (deploy, commands, repos, orgs, functions, assets, ops, errors, frontend, platform); <https://docs.run402.com/llms-cli-full.txt> is the whole reference as one document.
10
10
 
@@ -25,8 +25,8 @@ npx -y run402@latest <command>
25
25
  ## 30-second start
26
26
 
27
27
  ```bash
28
- run402 up --name my-app -y # bootstrap allowance/tier/project/link, then deploy
29
- run402 subdomains claim my-app # → https://my-app.run402.com
28
+ run402 up --name my-app -y # bootstrap wallet/tier/project/link, then deploy
29
+ run402 subdomains add my-app # → https://my-app.run402.com
30
30
  ```
31
31
 
32
32
  That's a real Postgres database + a deployed static site, paid for autonomously with testnet USDC.
@@ -51,13 +51,13 @@ run402 up verify --project prj_...
51
51
  run402 up --nested -y # app root inside another repo: its own nested repo + run402 remote
52
52
  ```
53
53
 
54
- `up` is a thin CLI shim over the Node SDK action runner. It discovers `run402.json`, `run402.deploy.json`, then `app.json`. A `run402.json` carrying the app schema/app markers uses the app-install graph; a release-shaped `run402.json` is normalized through the same ReleaseSpec path as `deploy apply` for compatibility. It validates the deploy input before any mutation, resolves the project as `--project` → `.run402/project.json` → manifest `project_id` → approved creation from `--name` → approved active-project fallback, then applies the manifest. `--name` is creation/link metadata only; it is not a manifest field and never renames an existing project. When everything is already configured, plain `run402 up` deploys. Non-interactive recursive prerequisites/local writes require `-y/--yes`.
54
+ `up` is a thin CLI shim over the Node SDK action runner. It discovers `run402.json`, `run402.deploy.json`, then `app.json`. A `run402.json` carrying the app schema/app markers uses the app-install graph; a release-shaped `run402.json` is normalized through the same ReleaseSpec path as `run402 deploy` for compatibility. It validates the deploy input before any mutation, resolves the project as `--project` → `.run402/project.json` → manifest `project_id` → approved creation from `--name` → approved active-project fallback, then applies the manifest. `--name` is creation/link metadata only; it is not a manifest field and never renames an existing project. When everything is already configured, plain `run402 up` deploys. Non-interactive recursive prerequisites/local writes require `-y/--yes`.
55
55
 
56
56
  For app manifests with `verify.http[]`, `up` runs HTTP checks after deploy. Fresh Run402 edge sentinel misses (`x-run402-edge` or sentinel JSON bodies) become `propagation_pending` with diagnostics instead of hard failure while the host binding is still converging. Use `--propagation-budget-s <seconds>` to tune the default 120 second wait, `--no-propagation-wait` to return immediately, and `run402 up verify` to rerun the same checks without upload, deploy, project creation, or resource mutation.
57
57
 
58
- For typed `run402.deploy.ts` configs, pass `--manifest` explicitly because TypeScript/JavaScript configs execute local code. Use `--check` for local-only import/normalize/file validation, `--print-spec` to inspect the normalized `ReleaseSpec`, `--plan` for a gateway-reviewed non-deploying plan, and `--require-plan <plan_id>` to apply only that reviewed intent. Warning flags are not used with `--require-plan`; the reviewed plan binds the exact warning/destructive set. Run402 Core skips Cloud allowance/tier prerequisites and fails closed when no Core project is selected.
58
+ For typed `run402.deploy.ts` configs, pass `--manifest` explicitly because TypeScript/JavaScript configs execute local code. Use `--check` for local-only import/normalize/file validation, `--print-spec` to inspect the normalized `ReleaseSpec`, `--plan` for a gateway-reviewed non-deploying plan, and `--require-plan <plan_id>` to apply only that reviewed intent. Warning flags are not used with `--require-plan`; the reviewed plan binds the exact warning/destructive set. Run402 Core skips Cloud wallet/tier prerequisites and fails closed when no Core project is selected.
59
59
 
60
- Every mode (and `deploy apply`) verifies the files the manifest references before any gateway call: migration `sql_path`/`sql_file`, function `source`/`files`, site `{ path }` entries and `dir()` targets, `assets.put` sources. A missing one is `MANIFEST_FILE_MISSING` (`details.missing[]` = `{ field_path, path, kind }`, one `create_file` next action per file). With no manifest in the working directory, `UP_MANIFEST_REQUIRED` looks one directory down (`details.nearby_manifests[]`, a leading `run_in_directory` next action such as `run402 up --check --dir <dir>`); `--manifest <path>` to a missing file is a typed `MANIFEST_NOT_FOUND` with a `create_manifest` next action. An app root that lies inside another repository is never scaffolded into it: the skip carries a `create_nested_repo` next action, and `--nested` gives the app its own nested repository (`git init -b main`, the `run402` remote, the first push) plus exactly one line in the enclosing repository's local `.git/info/exclude`, nothing else touched. `up` also sets this principal's display name when it has none: `RUN402_AGENT_NAME` (overrides an existing name), else the detected client (`claude-code`, `codex`, `cursor`, `grok`, or `RUN402_CLIENT=<name>` for one with no marker), and `result.identity` reports `detected` plus `detection: { applied, reason }` either way.
60
+ Every mode (and `run402 deploy`) verifies the files the manifest references before any gateway call: migration `sql_path`/`sql_file`, function `source`/`files`, site `{ path }` entries and `dir()` targets, `assets.put` sources. A missing one is `MANIFEST_FILE_MISSING` (`details.missing[]` = `{ field_path, path, kind }`, one `create_file` next action per file). With no manifest in the working directory, `UP_MANIFEST_REQUIRED` looks one directory down (`details.nearby_manifests[]`, a leading `run_in_directory` next action such as `run402 up --check --dir <dir>`); `--manifest <path>` to a missing file is a typed `MANIFEST_NOT_FOUND` with a `create_manifest` next action. An app root that lies inside another repository is never scaffolded into it: the skip carries a `create_nested_repo` next action, and `--nested` gives the app its own nested repository (`git init -b main`, the `run402` remote, the first push) plus exactly one line in the enclosing repository's local `.git/info/exclude`, nothing else touched. `up` also sets this principal's display name when it has none: `RUN402_AGENT_NAME` (overrides an existing name), else the detected client (`claude-code`, `codex`, `cursor`, `grok`, or `RUN402_CLIENT=<name>` for one with no marker), and `result.identity` reports `detected` plus `detection: { applied, reason }` either way.
61
61
 
62
62
  ### repos — host-blind encrypted git repos (zero deploy ceremony)
63
63
 
@@ -78,19 +78,19 @@ run402 repos delete --project prj_xyz --force # refuses without --force while th
78
78
 
79
79
  A hosted git remote, encrypted before it leaves the machine — no deploy, no manifest, no app. `origin` is claimed additively — an existing `origin` is never touched, the run402 remote falls back to `run402` instead. A directory inside another repository is never scaffolded into that repository: the skip carries a `create_nested_repo` next action, `--nested` makes it its own nested repository (one line appended to the enclosing repository's local `.git/info/exclude`, nothing else touched), and `create` prints a `git push` next action only for a remote it actually added. Every mutating `repos` verb (`create`, `rename`, `delete`, `snapshot`, `policy`, `mirror`, `gc`, `handoff`, `resume`, `invite`, `join`) is CLI/OpenClaw-only by design — no MCP tool exists or will exist for them (one-shot recovery receipts, immutable generations, irreversible delete, single-use bearer keys). Three READ-ONLY tools do exist — `repos_view`, `repos_list_heads`, `repos_fsck` — teaching only `repos` spellings. See `run402 repos --help` for the full tiered surface (common: `create`/`view`/`list`; occasional: `snapshot`/`mirror`/`recover`/`handoff`/`resume`/`invite`/`join`; lifecycle: `rename`/`delete`; maintenance: `fsck`/`gc`/`access`/`policy`), and the CLI reference's `repos` section for the terminal-loss statement and the progressive backup warning.
80
80
 
81
- **Handoff / resume.** `run402 repos handoff [--note-file <path>]` captures the actual working tree (staged/unstaged/untracked, like `git stash push -u`) into the vault and mints a single-use bearer key (`kgh1_…`, printed to stdout exactly once); `run402 repos resume <kgh1_…>` claims it on another machine, clones fresh, and reapplies the exact dirty state with `git stash apply --index`. No shared keystore, no shared allowance — the key is the whole handoff. On a wallet with no active tier, `resume` first folds the same cold-start chain `create` does (allowance → faucet → one x402 prototype payment); `--no-init` opts out, and the claim itself never waits on it. Sensitive untracked files (`.env`, `*.pem`, SSH/AWS/GPG dirs, …) are excluded from capture by default (`--include-sensitive <glob>` re-admits one). See the reference `run402.com/llms-cli.txt` for the full note-schema and flag reference.
81
+ **Handoff / resume.** `run402 repos handoff [--note-file <path>]` captures the actual working tree (staged/unstaged/untracked, like `git stash push -u`) into the vault and mints a single-use bearer key (`kgh1_…`, printed to stdout exactly once); `run402 repos resume <kgh1_…>` claims it on another machine, clones fresh, and reapplies the exact dirty state with `git stash apply --index`. No shared keystore, no shared wallet — the key is the whole handoff. On a wallet with no active tier, `resume` first folds the same cold-start chain `create` does (wallet → faucet → one x402 prototype payment); `--no-init` opts out, and the claim itself never waits on it. Sensitive untracked files (`.env`, `*.pem`, SSH/AWS/GPG dirs, …) are excluded from capture by default (`--include-sensitive <glob>` re-admits one). See the reference `run402.com/llms-cli.txt` for the full note-schema and flag reference.
82
82
 
83
83
  **Invite / join.** The second claim kind beside handoff/resume: a Handoff passes the work on and the sender stops; an Invite grows the team while the sender keeps working. `run402 repos invite [--room <key>] [--note-file <path>]` captures the checkpoint exactly like `handoff` — the inviter's own worktree, index, branch, refs, and access are all untouched — registers the inviter's presence in a coordination room (the project's default room, or `--room <key>` for a named org room), mints a single-use bearer key (`kgi1_…`, printed to stdout exactly once), and posts ONE room message naming the checkpoint (never the key). `run402 repos join <kgi1_…>` folds the SAME cold-start chain `resume` does before the claim, clones fresh, restores the exact dirty state, pins the invite's room locally, registers its own presence, posts ONE arrival message, and reports the inviter (name, labels, liveness), the room's other live presences, and the last few messages. `run402 messages wait` is the room's blocking read from there — the agent's ear, never an error on silence. Neither `invite` nor `join` has an MCP tool, same reasoning as `handoff`/`resume`.
84
84
 
85
- **Named addressing.** `run402 org slug <slug>` (owner-only, small one-time fee) claims an org's globally-unique, address-form slug, after which `run402::<slug>/<name>` addresses any repo under it — `git push` to a name that doesn't exist yet push-to-creates it. `run402 repos rename <name> [--project <id>]` claims the per-org-unique `<name>` half explicitly (no fee); `repos create` claims one automatically, best-effort, when the org already has a slug. Also CLI/SDK-only — no MCP tool.
85
+ **Named addressing.** `run402 orgs slug <slug>` (owner-only, small one-time fee) sets an org's globally-unique, address-form slug, after which `run402::<slug>/<name>` addresses any repo under it — `git push` to a name that doesn't exist yet push-to-creates it. `run402 repos rename <name> [--project <project_id>]` claims the per-org-unique `<name>` half explicitly (no fee); `repos create` claims one automatically, best-effort, when the org already has a slug. Also CLI/SDK-only — no MCP tool.
86
86
 
87
- ### Allowance
87
+ ### Wallet
88
88
 
89
89
  ```bash
90
- run402 allowance create # generate the local allowance
91
- run402 allowance fund # request testnet USDC from the faucet
92
- run402 allowance balance # mainnet + testnet + billing balance
93
- run402 allowance export # print {"address":"0x..."} for funding
90
+ run402 wallets new default # generate the local wallet without funding it
91
+ run402 wallets fund # request testnet USDC from the faucet
92
+ run402 wallets balance # mainnet + testnet USDC, plus the organization's allowance
93
+ run402 wallets current # the active wallet's address (for funding), rail, and file path
94
94
  ```
95
95
 
96
96
  ### Promo codes
@@ -100,9 +100,9 @@ run402 redeem R402-K8F3-Q2W9 # any time, before or after `run402 init`
100
100
  run402 init --voucher R402-K8F3-Q2W9 # same redemption, folded into setup
101
101
  ```
102
102
 
103
- A promo code credits the organization with prepaid credit that settles tiers and
103
+ A promo code adds to the organization's allowance, which settles tiers and
104
104
  priced calls with no on-chain payment. Case-insensitive, hyphens optional.
105
- Retrying is safe — a repeat returns the original result and never credits twice.
105
+ Retrying is safe — a repeat returns the original result and never adds twice.
106
106
  A bad code never blocks `init`; it warns and records `voucher_error` in the JSON
107
107
  summary.
108
108
 
@@ -144,25 +144,25 @@ reconciliation.
144
144
  ### Database
145
145
 
146
146
  ```bash
147
- run402 projects sql <id> "CREATE TABLE items (id serial PRIMARY KEY, …)"
148
- run402 projects validate-expose <id> --file manifest.json # check auth manifest, no mutation
149
- run402 projects apply-expose <id> --file manifest.json # declare what's reachable
150
- run402 projects rest <id> items "select=*&order=id.desc&limit=10"
151
- run402 projects schema <id> # introspect tables + RLS
147
+ run402 projects sql <project_id> "CREATE TABLE items (id serial PRIMARY KEY, …)"
148
+ run402 projects validate-expose <project_id> --file manifest.json # check auth manifest, no mutation
149
+ run402 projects apply-expose <project_id> --file manifest.json # declare what's reachable
150
+ run402 projects rest <project_id> items "select=*&order=id.desc&limit=10"
151
+ run402 projects schema <project_id> # introspect tables + RLS
152
152
  ```
153
153
 
154
154
  ### Static sites
155
155
 
156
156
  ```bash
157
157
  run402 sites deploy-dir ./dist # incremental upload (plan/commit transport)
158
- run402 deploy apply --manifest app.json # one-call full stack deploy
159
- run402 apply --manifest app.json --rehearse --json
158
+ run402 deploy --manifest app.json # deploy only (`run402 up` does missing setup first, then this)
159
+ run402 deploy status op_... --project prj_...
160
160
  run402 deploy verify op_... --project prj_... --wait
161
- run402 deploy release active # inspect current-live release inventory
162
- run402 deploy release diff --from empty --to active
163
- run402 deploy diagnose --project prj_123 https://example.com/events --method GET
164
- run402 deploy resolve --project prj_123 --url https://example.com/events?utm=x#hero --method GET
165
- run402 subdomains claim my-app # → my-app.run402.com (auto-reassigns on next deploy)
161
+ run402 deploy releases active # inspect current-live release inventory
162
+ run402 deploy releases diff --from empty --to active
163
+ run402 deploy resolve https://example.com/events --project prj_123 --method GET
164
+ run402 deploy resolve --url https://example.com/events?utm=x#hero --project prj_123 --method GET
165
+ run402 subdomains add my-app # → my-app.run402.com (auto-reassigns on next deploy)
166
166
  ```
167
167
 
168
168
  For pointer-swap recovery, verify the returned operation before declaring the public rollback complete:
@@ -175,13 +175,13 @@ run402 deploy verify --operation OPERATION_ID --wait
175
175
  Promote success means the origin pointer is active; mutable public URLs may still be converging. The result's `edge.state` reports convergence, and `edge.verify_url` is the direct operation-scoped HTTP verification endpoint.
176
176
 
177
177
  `deploy-dir` hashes each file client-side and only uploads bytes the gateway doesn't already have. Re-deploying an unchanged tree returns immediately with `bytes_uploaded: 0`. Progress events stream to stderr.
178
- Release inspection commands print `{ release: ... }` or `{ diff: ... }` (raw payload, no envelope — see the "Output Contract" section in [llms-cli.txt](llms-cli.txt)); use them after deploys to compare release inventory without starting another mutation. `deploy verify` prints the canonical edge-coherence report and exits 2 when the report is valid but not yet coherent. Inventories include `release_generation`, `static_manifest_sha256`, and nullable `static_manifest_metadata`; diffs include `static_assets` counters such as unchanged/changed/added/removed and CAS byte reuse. `deploy diagnose` / `deploy resolve --url` print URL-first diagnostics with `would_serve`, `diagnostic_status`, `match`, warnings, `edge_propagation`, and next steps; host misses are successful diagnostic calls with `would_serve: false`. Stable-host resolve fields can include `authorization_result`, `cas_object`, `response_variant`, `allow`, `route_pattern`, `target_type`, `target_name`, `target_file`, and `edge_propagation` (`settled`, `propagating`, or `sync_pending`).
178
+ Release inspection commands print `{ release: ... }` or `{ diff: ... }` (raw payload, no envelope — see the "Output Contract" section in [llms-cli.txt](llms-cli.txt)); use them after deploys to compare release inventory without starting another mutation. `deploy verify` prints the canonical edge-coherence report and exits 2 when the report is valid but not yet coherent. Inventories include `release_generation`, `static_manifest_sha256`, and nullable `static_manifest_metadata`; diffs include `static_assets` counters such as unchanged/changed/added/removed and CAS byte reuse. `deploy resolve <url>` (or `--url` / `--host` + `--path`) prints URL diagnostics with `would_serve`, `diagnostic_status`, `match`, warnings, `edge_propagation`, and next steps; host misses are successful diagnostic calls with `would_serve: false`. Stable-host resolve fields can include `authorization_result`, `cas_object`, `response_variant`, `allow`, `route_pattern`, `target_type`, `target_name`, `target_file`, and `edge_propagation` (`settled`, `propagating`, or `sync_pending`).
179
179
 
180
- For database-bearing changes, use `run402 apply --manifest app.json --rehearse --json` before commit. It creates a contained branch, applies the candidate plan there, runs checks, and exits nonzero on a failed rehearsal. The automatic rehearsal inside `up` / `apply` reports `rehearsal: { status: "skipped", reason }` when there is nothing to protect: `no_live_release` on a first deploy, `no_migrations`, or `migrations_unchanged` when every migration is already applied with an identical checksum (a page-only redeploy that still carries its migrations ships in seconds). `PUBLIC_ROUTED_FUNCTION` is informational (`requires_confirmation: false`) and needs no `--allow-warning`; only warnings with `requires_confirmation: true` do. Manual restore points live under `run402 snapshots create|list|get|restore|delete`; temporary data branches live under `run402 branches create|list|renew|delete`.
180
+ For database-bearing changes, rehearsal happens before commit without a flag: `run402 deploy --manifest app.json --json` (or `run402 up`) creates a contained branch, applies the candidate plan there, runs checks, and stops on a failed rehearsal; `--no-rehearse` skips it and `run402 deploy rehearse <plan_id>` rehearses a persisted plan by hand. The automatic rehearsal inside `up` / `deploy` reports `rehearsal: { status: "skipped", reason }` when there is nothing to protect: `no_live_release` on a first deploy, `no_migrations`, or `migrations_unchanged` when every migration is already applied with an identical checksum (a page-only redeploy that still carries its migrations ships in seconds). `PUBLIC_ROUTED_FUNCTION` is informational (`requires_confirmation: false`) and needs no `--allow-warning`; only warnings with `requires_confirmation: true` do. Manual restore points live under `run402 snapshots create|list|get|restore|delete`; temporary data branches live under `run402 branches create|list|renew|delete`.
181
181
 
182
182
  ### GitHub Actions OIDC deploys
183
183
 
184
- Link once from a local shell that has your Run402 allowance, then commit the generated workflow and manifest:
184
+ Link once from a local shell that has your Run402 wallet, then commit the generated workflow and manifest:
185
185
 
186
186
  ```bash
187
187
  run402 ci link github --project prj_... --manifest run402.deploy.json
@@ -203,10 +203,10 @@ jobs:
203
203
  steps:
204
204
  - uses: actions/checkout@v4
205
205
  - name: Deploy to run402
206
- run: npx --yes run402@3.7.5 deploy apply --manifest 'run402.deploy.json' --project 'prj_...'
206
+ run: npx --yes run402@3.7.5 deploy --manifest 'run402.deploy.json' --project 'prj_...'
207
207
  ```
208
208
 
209
- CI deploys can ship `site`, `functions`, `database`, and absent/current `base` changes. Route declarations are allowed only when the binding was linked with covering `--route-scope` patterns (`/admin` exact, `/api/*` final wildcard); no scopes means no CI route authority. Keep secrets, domains, subdomains, checks, non-current base changes, and out-of-scope routes in a local `run402 deploy apply` where the full allowance-backed authority is present.
209
+ CI deploys can ship `site`, `functions`, `database`, and absent/current `base` changes. Route declarations are allowed only when the binding was linked with covering `--route-scope` patterns (`/admin` exact, `/api/*` final wildcard); no scopes means no CI route authority. Keep secrets, domains, subdomains, checks, non-current base changes, and out-of-scope routes in a local `run402 deploy` where the full wallet-backed authority is present.
210
210
 
211
211
  ### Storage (paste-and-go CDN assets)
212
212
 
@@ -223,18 +223,18 @@ The returned `cdn_url` is content-addressed (`pr-<public_id>.run402.com/_blob/<k
223
223
  ### Functions
224
224
 
225
225
  ```bash
226
- run402 functions deploy <id> my-fn --file fn.ts \
226
+ run402 functions deploy <project_id> my-fn --file fn.ts \
227
227
  --timeout 30 --memory 256 \
228
228
  --schedule "*/15 * * * *" \
229
229
  --deps "stripe,zod@^3"
230
- run402 functions logs <id> my-fn --tail 100 --request-id req_abc123 --follow
231
- run402 functions logs --request-id req_abc123 --project <id> # <name> optional with --request-id: every function is searched
232
- run402 functions logs my-fn --project <id> --all # include the Lambda INIT_START / REPORT lines
233
- run402 logs --request-id req_abc123 --project <id> # the x-run402-request-id response header, no function name needed
234
- run402 functions invoke my-fn --project <id> --body-file request.json
235
- run402 functions invoke paid-fn --project <id> --body-file request.json --idempotency-key paid:call:123 --wait
236
- run402 functions rebuild <id> my-fn # refresh ONE function onto the current runtime
237
- run402 functions rebuild <id> --all # refresh every function in the project
230
+ run402 functions logs <project_id> my-fn --tail 100 --request-id req_abc123 --follow
231
+ run402 functions logs --request-id req_abc123 --project <project_id> # <name> optional with --request-id: every function is searched
232
+ run402 functions logs my-fn --project <project_id> --all # include the Lambda INIT_START / REPORT lines
233
+ run402 logs --request-id req_abc123 --project <project_id> # the x-run402-request-id response header, no function name needed
234
+ run402 functions invoke my-fn --project <project_id> --body-file request.json
235
+ run402 functions invoke paid-fn --project <project_id> --body-file request.json --idempotency-key paid:call:123 --wait
236
+ run402 functions rebuild <project_id> my-fn # refresh ONE function onto the current runtime
237
+ run402 functions rebuild <project_id> --all # refresh every function in the project
238
238
  ```
239
239
 
240
240
  Log reads are app-first: every entry carries `origin: "app" | "platform"`, the Lambda runtime lines (INIT_START, START/END/REPORT RequestId, billed duration) are hidden by default (`--app`), `--platform` shows only them and `--all` the raw stream; `hidden` counts what was dropped and a `hint` explains an empty result. `--request-id` accepts `req_`, `fnrun_`, and `fnatt_` ids, `--since` takes an ISO timestamp or epoch ms, and `run402 logs` rejects unknown flags.
@@ -253,15 +253,15 @@ import { db, adminDb, auth, email, ai } from "@run402/functions";
253
253
 
254
254
  ### Same-origin web routes
255
255
 
256
- `run402 deploy apply` accepts `site.public_paths` for clean static browser URLs and `routes.replace` for function ingress or exact method-aware static aliases. Release asset paths such as `events.html` are distinct from public paths such as `/events`: prefer `{ "site": { "replace": { "events.html": { "data": "<h1>Events</h1>" } }, "public_paths": { "mode": "explicit", "replace": { "/events": { "asset": "events.html" } } } } }` for ordinary clean static URLs. In explicit mode `/events.html` is not public unless separately declared; `mode: "implicit"` restores filename-derived reachability and can widen access. `site.embedding.frame_ancestors` (catalog keys, e.g. `["localhost"]`, never raw origins) lets the named embedders put the site in an iframe: the gateway sends `Content-Security-Policy: frame-ancestors http://localhost:* http://127.0.0.1:*` and drops `X-Frame-Options` on every response of the host; omitted on a later apply carries the previous declaration forward, `null` returns to deny, unknown keys fail `INVALID_SPEC` naming the valid ones, and `/_run402/config.json` discloses the effective policy cross-origin so an embedder can check before framing. `routes.replace` is an array of route entries, not a path-keyed map. Use exact `/admin` plus final-wildcard `/admin/*` for a routed section root, narrow `/api/*` methods such as `["GET","POST","OPTIONS"]`, POST-only `/login` function routes, and exact static route targets like `{ "pattern": "/events", "methods": ["GET","HEAD"], "target": { "type": "static", "file": "events.html" } }` only for route-table alias behavior. Static route `file` is a release asset path, not a public path, URL, CAS hash, rewrite, or redirect. Recipe — static home page + SPA shell: a root alias `{ "pattern": "/", "target": { "type": "static", "file": "home.html" } }` (with `home.html` at the site root) serves real static bytes at `GET /` (`route_static_alias`) while unmatched app routes keep the `index.html` shell (`spa_fallback`); expect non-blocking `STATIC_ALIAS_SHADOWS_STATIC_PATH` (warn) / `STATIC_ALIAS_DUPLICATE_CANONICAL_URL` (info) plan lints and verify with `run402 deploy resolve --url https://<your-site>/ --method GET`. Routed functions use Node 22 Fetch Request -> Response; `req.url` is the full public URL on managed subdomains, deployment hosts, and verified custom domains. Direct `/functions/v1/:name` remains API-key protected. Known resolve literals include `host_missing`, `manifest_missing`, `active_release_missing`, `unsupported_manifest_version`, `path_error`, `none`, `static_exact`, `static_index`, `spa_fallback`, `spa_fallback_missing`, `route_function`, `route_static_alias`, and `route_method_miss`; known `authorization_result` values include `authorized`, `not_public`, `not_applicable`, `manifest_missing`, `target_missing`, `active_release_missing`, `unsupported_manifest_version`, `path_error`, `missing_cas_object`, `unfinalized_or_deleting_cas_object`, `size_mismatch`, and `unauthorized_cas_object`. Known `fallback_state` values include `active_release_missing`, `unsupported_manifest_version`, and `negative_cache_hit`; preserve unknown future strings. Release inventories may include `static_public_paths` with `public_path`, `asset_path`, `reachability_authority`, and `direct`; resolve may return the same reachability fields plus `authorization_result`, `cas_object`, `response_variant`, and route/static fields like `allow`, `route_pattern`, `target_type`, `target_name`, and `target_file`. Static route target warnings include `STATIC_ALIAS_SHADOWS_STATIC_PATH`, `STATIC_ALIAS_RELATIVE_ASSET_RISK`, `STATIC_ALIAS_DUPLICATE_CANONICAL_URL`, `STATIC_ALIAS_EXTENSIONLESS_NON_HTML`, and `STATIC_ALIAS_TABLE_NEAR_LIMIT`; inspect active routes, `static_public_paths`, and the backing `asset_path`. Runtime route failure codes to branch on: `ROUTE_MANIFEST_LOAD_FAILED`, `ROUTED_INVOKE_WORKER_SECRET_MISSING`, `ROUTED_INVOKE_AUTH_FAILED`, `ROUTED_ROUTE_STALE`, `ROUTE_METHOD_NOT_ALLOWED`, and `ROUTED_RESPONSE_TOO_LARGE`.
256
+ `run402 deploy` accepts `site.public_paths` for clean static browser URLs and `routes.replace` for function ingress or exact method-aware static aliases. Release asset paths such as `events.html` are distinct from public paths such as `/events`: prefer `{ "site": { "replace": { "events.html": { "data": "<h1>Events</h1>" } }, "public_paths": { "mode": "explicit", "replace": { "/events": { "asset": "events.html" } } } } }` for ordinary clean static URLs. In explicit mode `/events.html` is not public unless separately declared; `mode: "implicit"` restores filename-derived reachability and can widen access. `site.embedding.frame_ancestors` (catalog keys, e.g. `["localhost"]`, never raw origins) lets the named embedders put the site in an iframe: the gateway sends `Content-Security-Policy: frame-ancestors http://localhost:* http://127.0.0.1:*` and drops `X-Frame-Options` on every response of the host; omitted on a later apply carries the previous declaration forward, `null` returns to deny, unknown keys fail `INVALID_SPEC` naming the valid ones, and `/_run402/config.json` discloses the effective policy cross-origin so an embedder can check before framing. `routes.replace` is an array of route entries, not a path-keyed map. Use exact `/admin` plus final-wildcard `/admin/*` for a routed section root, narrow `/api/*` methods such as `["GET","POST","OPTIONS"]`, POST-only `/login` function routes, and exact static route targets like `{ "pattern": "/events", "methods": ["GET","HEAD"], "target": { "type": "static", "file": "events.html" } }` only for route-table alias behavior. Static route `file` is a release asset path, not a public path, URL, CAS hash, rewrite, or redirect. Recipe — static home page + SPA shell: a root alias `{ "pattern": "/", "target": { "type": "static", "file": "home.html" } }` (with `home.html` at the site root) serves real static bytes at `GET /` (`route_static_alias`) while unmatched app routes keep the `index.html` shell (`spa_fallback`); expect non-blocking `STATIC_ALIAS_SHADOWS_STATIC_PATH` (warn) / `STATIC_ALIAS_DUPLICATE_CANONICAL_URL` (info) plan lints and verify with `run402 deploy resolve --url https://<your-site>/ --method GET`. Routed functions use Node 22 Fetch Request -> Response; `req.url` is the full public URL on managed subdomains, deployment hosts, and verified custom domains. Direct `/functions/v1/:name` remains API-key protected. Known resolve literals include `host_missing`, `manifest_missing`, `active_release_missing`, `unsupported_manifest_version`, `path_error`, `none`, `static_exact`, `static_index`, `spa_fallback`, `spa_fallback_missing`, `route_function`, `route_static_alias`, and `route_method_miss`; known `authorization_result` values include `authorized`, `not_public`, `not_applicable`, `manifest_missing`, `target_missing`, `active_release_missing`, `unsupported_manifest_version`, `path_error`, `missing_cas_object`, `unfinalized_or_deleting_cas_object`, `size_mismatch`, and `unauthorized_cas_object`. Known `fallback_state` values include `active_release_missing`, `unsupported_manifest_version`, and `negative_cache_hit`; preserve unknown future strings. Release inventories may include `static_public_paths` with `public_path`, `asset_path`, `reachability_authority`, and `direct`; resolve may return the same reachability fields plus `authorization_result`, `cas_object`, `response_variant`, and route/static fields like `allow`, `route_pattern`, `target_type`, `target_name`, and `target_file`. Static route target warnings include `STATIC_ALIAS_SHADOWS_STATIC_PATH`, `STATIC_ALIAS_RELATIVE_ASSET_RISK`, `STATIC_ALIAS_DUPLICATE_CANONICAL_URL`, `STATIC_ALIAS_EXTENSIONLESS_NON_HTML`, and `STATIC_ALIAS_TABLE_NEAR_LIMIT`; inspect active routes, `static_public_paths`, and the backing `asset_path`. Runtime route failure codes to branch on: `ROUTE_MANIFEST_LOAD_FAILED`, `ROUTED_INVOKE_WORKER_SECRET_MISSING`, `ROUTED_INVOKE_AUTH_FAILED`, `ROUTED_ROUTE_STALE`, `ROUTE_METHOD_NOT_ALLOWED`, and `ROUTED_RESPONSE_TOO_LARGE`.
257
257
 
258
258
  ### Secrets
259
259
 
260
260
  ```bash
261
- run402 secrets set <id> OPENAI_API_KEY --file ./.secrets/openai-key
262
- printf %s "$OPENAI_API_KEY" | run402 secrets set <id> OPENAI_API_KEY --stdin
263
- run402 secrets list <id>
264
- run402 deploy apply --manifest run402.deploy.json # manifest uses secrets.require, not values
261
+ run402 secrets set <project_id> OPENAI_API_KEY --file ./.secrets/openai-key
262
+ printf %s "$OPENAI_API_KEY" | run402 secrets set <project_id> OPENAI_API_KEY --stdin
263
+ run402 secrets list <project_id>
264
+ run402 deploy --manifest run402.deploy.json # manifest uses secrets.require, not values
265
265
  ```
266
266
 
267
267
  Secret values are write-only. `list` returns keys and timestamps only; deploy manifests should declare dependencies with `secrets.require` and never contain values.
@@ -289,7 +289,7 @@ run402 email send --to user@example.com --subject "Welcome" --html "<h1>Hi</h1>"
289
289
  run402 email send --to user@example.com --template notification --var project_name="My App"
290
290
  ```
291
291
 
292
- For Run402 Core, use the same commands after `run402 init --api-base=http://my-core:4020`. The Core gateway operator must configure an outbound provider such as SES first; `run402 email mailboxes` surfaces `provider_readiness`, `can_send`, `send_blocked_reason`, and `next_actions` when setup is missing. Core's first email slice supports raw outbound mail with attachments; managed templates, inbound reply handling, sender-domain automation, and delivery operations may remain Cloud-only until the Core gateway adds those capabilities.
292
+ For Run402 Core, use the same commands after `run402 init --api-base=http://my-core:4020`. Whoever runs the Core gateway must configure an outbound provider such as SES first; `run402 email mailboxes` surfaces `provider_readiness`, `can_send`, `send_blocked_reason`, and `next_actions` when setup is missing. Core's first email slice supports raw outbound mail with attachments; managed templates, inbound reply handling, sender-domain automation, and delivery operations may remain Cloud-only until the Core gateway adds those capabilities.
293
293
 
294
294
  ### Image generation
295
295
 
@@ -323,18 +323,18 @@ run402 doctor # { ok, blocking[], warnings[], checks[] }
323
323
  run402 doctor --refresh # live npm check for a newer run402
324
324
  ```
325
325
 
326
- `ok` is structural: `true` exactly when `blocking[]` is empty. Every check carries `severity: "blocking" | "advisory" | "info"`; advisory findings (an unbound operator passkey, a degraded recovery posture on another org, a stale CLI, gitvault gaps) land in `warnings[]` without changing `ok` or the exit code. The `tier` check's `status` is a fixed vocabulary (`ok | inactive | frozen | past_due | dormant | purged | missing | unknown | error`, never a tier name; see `value.tier` / `value.lifecycle`), and a wallet whose own org holds no tier but can reach another org's projects reports `missing` as advisory (`TIER_MISSING_ON_OWN_ORG`).
326
+ `ok` is structural: `true` exactly when `blocking[]` is empty. Every check carries `severity: "blocking" | "advisory" | "info"`; advisory findings (an unbound contact passkey, a degraded recovery posture on another org, a stale CLI, gitvault gaps) land in `warnings[]` without changing `ok` or the exit code. The `tier` check's `status` is a fixed vocabulary (`ok | inactive | frozen | past_due | dormant | purged | missing | unknown | error`, never a tier name; see `value.tier` / `value.lifecycle`), and a wallet whose own org holds no tier but can reach another org's projects reports `missing` as advisory (`TIER_MISSING_ON_OWN_ORG`).
327
327
 
328
328
  ## State
329
329
 
330
330
  Local state lives at:
331
331
 
332
332
  - `~/.config/run402/projects.json` (`0600`) — project credentials (`anon_key`, `service_key`, `tier`, `lease_expires_at`)
333
- - `~/.config/run402/allowance.json` (`0600`) — wallet for x402 signing
333
+ - `~/.config/run402/wallet.json` (`0600`) — wallet for x402 signing
334
334
  - `~/.config/run402/config.json` (`0600`) — global default wallet pointer (`active_wallet`)
335
- - `~/.config/run402/profiles/<name>/` (`0700`) — named wallets, each with its own `allowance.json` + `projects.json` + non-secret `meta.json`
335
+ - `~/.config/run402/profiles/<name>/` (`0700`) — named wallets, each with its own `wallet.json` + `projects.json` + non-secret `meta.json`
336
336
 
337
- Override the base directory with `RUN402_CONFIG_DIR` or the allowance file with `RUN402_ALLOWANCE_PATH`. Override the API base with `RUN402_API_BASE`.
337
+ Override the base directory with `RUN402_CONFIG_DIR` or the wallet file with `RUN402_WALLET_PATH`. Override the API base with `RUN402_API_BASE`.
338
338
 
339
339
  ### Named wallets (profiles)
340
340
 
@@ -346,20 +346,22 @@ Hold several wallets on one machine and select between them:
346
346
 
347
347
  The CLI handles all x402 / MPP payment signing automatically — never ask the human for a private key or set up payment libraries by hand.
348
348
 
349
- ### Operator (human / email session)
349
+ ### Sign-in session (a person)
350
350
 
351
- The **operator** is YOU, the human, identified by email — distinct from the agent (your wallet). One browser login spans every wallet that verified your email, so the overview is a cross-wallet union. For a single wallet's account state, use `run402 status`.
351
+ A person signs in; the agent is your wallet (`run402 status` shows the wallet's own organization state). There is one sign-in session, graded by how it was minted.
352
352
 
353
- - `run402 operator login` — browser-delegated sign-in (device-authorization, RFC 8628, like `aws sso login`): magic-link or passkey in the browser, no WebAuthn in the CLI. Caches an email-scoped session at the base config dir (shared across named wallets).
354
- - `run402 operator overview` — account view across ALL wallets controlling your email (requires login; never falls back to a single wallet).
355
- - `run402 operator whoami` — show the cached session (email, wallets, expiry); local, no network.
356
- - `run402 operator logout` — revoke the session server-side and clear the local cache.
353
+ - `run402 login` — browser passkey sign-in over loopback PKCE (RFC 8252, like `aws sso login`): the CLI listens on `127.0.0.1`, the browser runs the ceremony, and the session (grade `loopback`: full, step-up-able) is cached at the base config dir (shared across named wallets). Signing in again is the step-up.
354
+ - `run402 login --device` — RFC 8628 device code for a terminal with no browser; approve it in the console. The session is grade `device`: read-only.
355
+ - `run402 whoami` — principal, memberships, `session.grade`, and the write approvals cached on this machine.
356
+ - `run402 approve --action <capability> (--org <org_id> | --project <project_id>)` — passkey-signed write approval for one action on one target; a person without a wallet needs it to provision, deploy, or write secrets (an interactive `provision`/`deploy` opens it for you).
357
+ - `run402 logout` — revoke the session server-side and clear it and every write approval locally.
358
+ - `run402 orgs list` — your orgs joined with the account overview (tier, lifecycle, quotas, allowance, advisories).
357
359
 
358
- Not exposed as MCP tools by design — MCP authenticates as the agent (wallet), and the human session must not be handed to it.
360
+ Not exposed as MCP tools by design — MCP authenticates as the agent (wallet), and a person's session must not become its ambient authority.
359
361
 
360
362
  ## Active project (sticky default)
361
363
 
362
- After `provision`, the new project becomes the active one. `run402 projects use <id>` switches it. Most commands that take `<id>` default to the active project when omitted.
364
+ After `provision`, the new project becomes the active one. `run402 projects use <project_id>` switches it. Most commands that take `<project_id>` default to the active project when omitted.
363
365
 
364
366
  ## Help
365
367
 
package/cli.mjs CHANGED
@@ -31,20 +31,18 @@ Usage:
31
31
  Commands, grouped by when you reach for them:
32
32
 
33
33
  SET UP — get an agent funded and entitled
34
- init Set up allowance, funding, and check tier status (x402 default)
34
+ init Set up the local wallet, funding, and check tier status (x402 default)
35
35
  init mpp Set up with MPP payment rail (Tempo Moderato testnet)
36
- wallets Manage multiple named wallets (list, new, use, rename, bind, import)
37
- allowance Manage your agent allowance (create, fund, balance, status)
38
- tier Manage tier subscription (status, set)
39
- redeem Redeem a promo code for run402 credit
36
+ wallets Manage local wallets (list, current, new, use, fund, balance, import)
37
+ tier Manage your tier and its lease (status, set)
38
+ redeem Redeem a promo code into your organization's allowance
40
39
  pay Call an arbitrary x402-priced URL with a bounded payment
41
40
 
42
41
  BUILD & SHIP — the app and everything it serves
43
42
  up Provision/link/deploy the current app with SDK orchestration
44
43
  projects Manage projects (provision, list, get, sql, delete)
45
44
  repos Host-blind encrypted git repos: create/view/list, snapshot/mirror/recover, fsck/gc/access/policy (repo aliases repos)
46
- deploy Unified deploy operations (requires active tier)
47
- apply Alias for deploy apply; supports --rehearse for migration rehearsal
45
+ deploy Deploy a release; subcommands inspect and steer deploys (requires active tier)
48
46
  functions Manage serverless functions (deploy, invoke, logs, list, delete)
49
47
  secrets Manage project secrets (set, list, delete)
50
48
  sites Deploy static sites
@@ -57,7 +55,7 @@ OPERATE — what happened, and is it healthy
57
55
  live Change hints for live tables as NDJSON (SSE; --once for one held read)
58
56
  errors Grouped error fingerprints + a promote/revert verdict (release-baselined)
59
57
  logs Fetch function logs by request id (--request-id req_...)
60
- status Show full account state (allowance, balance, tier, projects)
58
+ status Show full account state (wallet, allowance, tier, projects)
61
59
  doctor Health and config diagnostics (JSON by default; includes --buzz preflight)
62
60
  service Run402 service health and availability (status, health)
63
61
  snapshots Create/list/restore/delete project data snapshots
@@ -74,17 +72,20 @@ AUTHORITY — who may act, and with what credential
74
72
  credentials Manage local credential material (project-keys)
75
73
  delegates Scoped deploy credentials for agents (create, list, revoke, rotate)
76
74
  grants Per-project capability grants for agent/CI principals (create, revoke)
77
- org Org membership, invites & audit (whoami, list, member, invite, audit)
75
+ orgs Organizations, members, invites & audit (list, get, members, invite, audit)
78
76
  identity Public proof-backed external agent identity links
79
77
  auth Manage project user authentication (magic link, passwords, settings)
80
78
  ci Link GitHub Actions OIDC deploy bindings
81
- operator Operator (human/email) session — login, then overview across your wallets
79
+ login Sign in as a person (browser passkey; --device for a read-only session)
80
+ logout End your sign-in session and clear it from this machine
81
+ whoami Who this CLI acts as: principal, memberships, session grade (--set-name sets your name)
82
+ approve Write approval for one action on one target (provision, deploy, secrets)
82
83
 
83
84
  DELIVER — reach a human when something happens
84
85
  deliveries Did a notification actually land (list, get)
85
86
  contacts Where a human is reachable — paging ladder + Telegram (list, add, connect, rm, preferences)
86
87
  subscriptions Which events go where (add, list, rm)
87
- webhook-secret Rotate the operator webhook signing secret
88
+ webhook-secret Rotate your webhook signing secret
88
89
  email Send template-based emails from your project
89
90
 
90
91
  PLATFORM — everything else, and the things still finding a home
@@ -92,9 +93,8 @@ PLATFORM — everything else, and the things still finding a home
92
93
  billing Email organizations, Stripe tier checkout, email packs
93
94
  contracts KMS signers ($0.04/day rental + $0.000005/sign)
94
95
  jobs Submit and inspect platform-managed jobs
95
- transfer Two-party project transfer (init, preview, list, accept, cancel)
96
- cloud Cloud portability archive export (archives create/download/status)
97
- archives Inspect and verify portable project archives locally
96
+ transfer Project transfer to a wallet, an email, or an owned org (init, preview, list, accept, cancel)
97
+ archives Portable project archives (create, status, download --target cloud; inspect, verify; import --target core)
98
98
  gitvault RETIRED — moved to repos (repo-surface-consolidation); every spelling answers COMMAND_MOVED/COMMAND_REMOVED
99
99
  source-access RETIRED — moved into repos (recovery-bundle + access); every spelling answers COMMAND_MOVED
100
100
  buzz Buzz human/community/agent control-plane workflows
@@ -104,7 +104,6 @@ PLATFORM — everything else, and the things still finding a home
104
104
  cdn CloudFront CDN diagnostics (wait-fresh) for public asset URLs
105
105
  cache Inspect and invalidate the SSR origin cache (inspect, invalidate)
106
106
  agent Manage agent identity (contact info)
107
- core Local Run402 Core import helpers
108
107
  dev Run Astro dev with Run402 env + credentials in scope
109
108
 
110
109
  Global options (any command):
@@ -115,15 +114,14 @@ Run 'run402 <command> --help' for detailed usage of each command.
115
114
 
116
115
  Examples:
117
116
  run402 up --name my-app -y
118
- run402 allowance create
119
- run402 allowance fund
117
+ run402 init
118
+ run402 wallets fund
120
119
  run402 pay https://seller.example/resource --max-usd 0.05
121
- run402 deploy apply --manifest app.json
122
- run402 apply --manifest app.json --rehearse --json
120
+ run402 deploy --manifest app.json
123
121
  run402 snapshots list --project prj_...
124
122
  run402 branches create --project prj_... --ttl-days 7 --json
125
- run402 cloud archives create --project prj_... --wait --output ./project.r402ar --json
126
- run402 core projects import ./project.r402ar --name imported-project --env-file ./required.env --json
123
+ run402 archives create --project <project_id> --target cloud --wait --output ./project.r402ar --json
124
+ run402 archives import ./project.r402ar --target core --name imported-project --env-file ./required.env --json
127
125
  run402 jobs submit --file job.json
128
126
  run402 projects list
129
127
  run402 projects sql "SELECT * FROM users LIMIT 5" --project <project_id>
@@ -134,7 +132,7 @@ Examples:
134
132
  Getting started:
135
133
  run402 init Set up with x402 (Base Sepolia)
136
134
  run402 init mpp Set up with MPP (Tempo Moderato)
137
- run402 tier set prototype Subscribe to a tier
135
+ run402 tier set prototype Set a tier (prototype is free)
138
136
  run402 up --name my-app -y Create and deploy this app (explicit destination)
139
137
  run402 ci link github --project prj_... --manifest run402.deploy.json
140
138
  `;
@@ -219,11 +217,6 @@ switch (cmd) {
219
217
  await run(sub, rest);
220
218
  break;
221
219
  }
222
- case "allowance": {
223
- const { run } = await import("./lib/allowance.mjs");
224
- await run(sub, rest);
225
- break;
226
- }
227
220
  case "tier": {
228
221
  const { run } = await import("./lib/tier.mjs");
229
222
  await run(sub, rest);
@@ -247,11 +240,6 @@ switch (cmd) {
247
240
  await run(sub, rest);
248
241
  break;
249
242
  }
250
- case "apply": {
251
- const { runDeployV2 } = await import("./lib/deploy-v2.mjs");
252
- await runDeployV2("apply", [sub, ...rest].filter(Boolean));
253
- break;
254
- }
255
243
  case "snapshots": {
256
244
  const { run } = await import("./lib/snapshots.mjs");
257
245
  await run(sub, rest);
@@ -267,21 +255,11 @@ switch (cmd) {
267
255
  await run(sub, rest);
268
256
  break;
269
257
  }
270
- case "cloud": {
271
- const { run } = await import("./lib/cloud.mjs");
272
- await run(sub, rest);
273
- break;
274
- }
275
258
  case "archives": {
276
259
  const { run } = await import("./lib/archives.mjs");
277
260
  await run(sub, rest);
278
261
  break;
279
262
  }
280
- case "core": {
281
- const { run } = await import("./lib/core.mjs");
282
- await run(sub, rest);
283
- break;
284
- }
285
263
  case "deploy": {
286
264
  const { run } = await import("./lib/deploy.mjs");
287
265
  await run([sub, ...rest].filter(Boolean));
@@ -297,8 +275,8 @@ switch (cmd) {
297
275
  await run(sub, rest);
298
276
  break;
299
277
  }
300
- case "org": {
301
- const { run } = await import("./lib/org.mjs");
278
+ case "orgs": {
279
+ const { run } = await import("./lib/orgs.mjs");
302
280
  await run(sub, rest);
303
281
  break;
304
282
  }
@@ -450,9 +428,24 @@ switch (cmd) {
450
428
  await run(sub, rest);
451
429
  break;
452
430
  }
453
- case "operator": {
454
- const { run } = await import("./lib/operator.mjs");
455
- await run(sub, rest);
431
+ case "login": {
432
+ const { run } = await import("./lib/login.mjs");
433
+ await run([sub, ...rest].filter(Boolean));
434
+ break;
435
+ }
436
+ case "logout": {
437
+ const { run } = await import("./lib/logout.mjs");
438
+ await run([sub, ...rest].filter(Boolean));
439
+ break;
440
+ }
441
+ case "whoami": {
442
+ const { run } = await import("./lib/whoami.mjs");
443
+ await run([sub, ...rest].filter(Boolean));
444
+ break;
445
+ }
446
+ case "approve": {
447
+ const { run } = await import("./lib/approve.mjs");
448
+ await run([sub, ...rest].filter(Boolean));
456
449
  break;
457
450
  }
458
451
  case "source-access": {
@@ -1,6 +1,6 @@
1
1
  import { homedir } from "node:os";
2
2
  import { dirname, join } from "node:path";
3
- import { existsSync, renameSync, mkdirSync, chmodSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { existsSync, renameSync, mkdirSync, chmodSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { describeRejectedValue } from "./redact.js";
6
6
  export const DEFAULT_API_BASE = "https://api.run402.com";
@@ -118,7 +118,7 @@ export function getProfilesDir() {
118
118
  * The effective config directory for the *active* wallet. The `default` wallet
119
119
  * resolves to the base dir (zero migration for existing single-wallet
120
120
  * installs); any named wallet resolves to `{base}/profiles/<name>`. Because
121
- * keystore, allowance, and meta paths all derive from this, switching the
121
+ * keystore, wallet, and meta paths all derive from this, switching the
122
122
  * profile env var moves the whole wallet bundle atomically — and the SDK/MCP
123
123
  * inherit profile selection for free.
124
124
  */
@@ -232,27 +232,61 @@ export function isCoreApiTarget() {
232
232
  return true;
233
233
  return false;
234
234
  }
235
- export function getAllowancePath() {
236
- if (process.env.RUN402_ALLOWANCE_PATH)
237
- return process.env.RUN402_ALLOWANCE_PATH;
238
- const dir = getConfigDir();
239
- const newPath = join(dir, "allowance.json");
240
- const oldPath = join(dir, "wallet.json");
241
- // Auto-migrate from wallet.json → allowance.json. renameSync preserves the
242
- // source file's mode, so a legacy world-readable wallet.json (mode 0644)
243
- // would otherwise carry that mode forward and leave the private key
244
- // world-readable on a shared machine. Tighten to 0600 after the rename.
245
- if (!existsSync(newPath) && existsSync(oldPath)) {
246
- mkdirSync(dir, { recursive: true });
247
- renameSync(oldPath, newPath);
235
+ /**
236
+ * The file that holds a wallet's key, in the base config dir (the `default`
237
+ * wallet) and in each `profiles/<name>/` directory.
238
+ */
239
+ export const WALLET_FILE_NAME = "wallet.json";
240
+ /** The name the wallet key file had before it was `wallet.json`. */
241
+ const PREVIOUS_WALLET_FILE_NAME = "allowance.json";
242
+ const walletFilesMovedFor = new Set();
243
+ /**
244
+ * One-time local move of the wallet key file to its current name: in the base
245
+ * config dir and every `profiles/<name>/` directory, `allowance.json` is
246
+ * renamed to `wallet.json` (an atomic same-directory rename) when
247
+ * `wallet.json` is absent, then tightened to 0600. A directory that already
248
+ * holds `wallet.json` is left untouched. Runs once per base dir per process;
249
+ * nothing reads the previous name afterwards.
250
+ */
251
+ export function moveWalletFiles() {
252
+ const base = getConfigBaseDir();
253
+ if (walletFilesMovedFor.has(base))
254
+ return;
255
+ walletFilesMovedFor.add(base);
256
+ const dirs = [base];
257
+ try {
258
+ for (const entry of readdirSync(join(base, "profiles"), { withFileTypes: true })) {
259
+ if (entry.isDirectory())
260
+ dirs.push(join(base, "profiles", entry.name));
261
+ }
262
+ }
263
+ catch {
264
+ // No profiles directory yet.
265
+ }
266
+ for (const dir of dirs) {
267
+ const from = join(dir, PREVIOUS_WALLET_FILE_NAME);
268
+ const to = join(dir, WALLET_FILE_NAME);
269
+ if (existsSync(to) || !existsSync(from))
270
+ continue;
271
+ try {
272
+ renameSync(from, to);
273
+ }
274
+ catch {
275
+ continue;
276
+ }
248
277
  try {
249
- chmodSync(newPath, 0o600);
278
+ chmodSync(to, 0o600);
250
279
  }
251
280
  catch {
252
281
  // Best-effort (e.g. Windows / exotic filesystems). Read-time self-heal
253
- // in readAllowance() is the backstop.
282
+ // in readWallet() is the backstop.
254
283
  }
255
284
  }
256
- return newPath;
285
+ }
286
+ export function getWalletPath() {
287
+ if (process.env.RUN402_WALLET_PATH)
288
+ return process.env.RUN402_WALLET_PATH;
289
+ moveWalletFiles();
290
+ return join(getConfigDir(), WALLET_FILE_NAME);
257
291
  }
258
292
  //# sourceMappingURL=config.js.map