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
@@ -24,46 +24,45 @@ import {
24
24
 
25
25
  const ROLE_LIST = "owner | admin | developer | billing | viewer";
26
26
 
27
- const HELP = `run402 org — organizations: create, label, membership, invites
27
+ const HELP = `run402 orgs — organizations: create, label, membership, invites
28
28
 
29
29
  Usage:
30
- run402 org create [--name <label>]
31
- run402 org list
32
- run402 org get [<org_id>]
33
- run402 org rename [<org_id>] --name <display_name> (or: --clear to remove the label)
34
- run402 org payout-wallet [<org_id>] <wallet_address> (or: --clear to remove the explicit default)
35
- run402 org slug <slug> [--org <org_id>]
36
- run402 org whoami
37
- run402 org whoami --set-name <name>
38
- run402 org use <org_id>
39
- run402 org current
40
- run402 org clear
41
- run402 org bind [--org <org_id>] [--room <key>]
42
- run402 org unbind
43
- run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
44
- run402 org member list [<org_id>]
45
- run402 org member add [<org_id>] <wallet_address> [--role <role>]
46
- run402 org member role [<org_id>] --principal <principal_id> --role <role>
47
- run402 org member rm [<org_id>] --principal <principal_id>
48
- run402 org member revoke-key [<org_id>] --principal <principal_id> [--reason <why>] (owner + step-up; revokes the member's gitvault encryption key — its next gitvault operation enrolls afresh)
49
- run402 org invite list [<org_id>]
50
- run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
51
- run402 org invite rm [<org_id>] --principal <principal_id>
30
+ run402 orgs create [--name <label>]
31
+ run402 orgs list
32
+ run402 orgs get [<org_id>]
33
+ run402 orgs rename [<org_id>] --name <display_name> (or: --clear to remove the label)
34
+ run402 orgs payout-wallet [<org_id>] <wallet_address> (or: --clear to remove the explicit default)
35
+ run402 orgs slug <slug> [--org <org_id>]
36
+ run402 orgs adopt [--org <org_id>] [--name <label>]
37
+ run402 orgs use <org_id>
38
+ run402 orgs current
39
+ run402 orgs clear
40
+ run402 orgs bind [--org <org_id>] [--room <key>]
41
+ run402 orgs unbind
42
+ run402 orgs audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
43
+ run402 orgs members list [<org_id>]
44
+ run402 orgs members add [<org_id>] <wallet_address> [--role <role>]
45
+ run402 orgs members role [<org_id>] --principal <principal_id> --role <role>
46
+ run402 orgs members rm [<org_id>] --principal <principal_id>
47
+ run402 orgs members revoke-key [<org_id>] --principal <principal_id> [--reason <why>] (owner + step-up; revokes the member's gitvault encryption key — its next gitvault operation enrolls afresh)
48
+ run402 orgs invite list [<org_id>]
49
+ run402 orgs invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
50
+ run402 orgs invite rm [<org_id>] --principal <principal_id>
52
51
 
53
52
  <org_id> is optional everywhere: a leading UUID positional addresses that org;
54
53
  omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
55
- binding, then 'run402 org use'. Inside a bound checkout two agents add each
56
- other with nothing to look up: run402 org member add <wallet_address> --role developer.
54
+ binding, then 'run402 orgs use'. Inside a bound checkout two agents add each
55
+ other with nothing to look up: run402 orgs members add <wallet_address> --role developer.
57
56
  A developer-or-above add REFUSES (GITVAULT_WRITER_NOT_ADMITTED) unless this session's key is an admitted writer on every vault of the org, so the new member can push at once; a current writer admits your key with run402 repos access sync.
58
- The second attribute may also be passed positionally (run402 org member add <wallet_address>).
57
+ The second attribute may also be passed positionally (run402 orgs members add <wallet_address>).
59
58
 
60
59
  Subcommands:
61
60
  create Create an empty org on the prototype tier (you become owner)
62
- list Orgs you are a member of
61
+ list Your orgs: role, tier, lifecycle, quotas, allowance, advisories
63
62
  get Read one org (label + tier/lease + your role)
64
63
  rename Set or clear an org's display label (owner-only)
65
64
  slug Claim or rename the org's globally-unique, address-form slug
66
- (owner-only). A genesis claim spends a one-time claim fee; a
65
+ (owner-only). A genesis set spends a one-time fee; a
67
66
  rename releases the old slug into a ~90-day cooldown.
68
67
  use Select the current org for this wallet profile
69
68
  current Report the resolved current org and where it came from
@@ -71,8 +70,7 @@ Subcommands:
71
70
  bind Write this checkout's org (+room) into .run402.json — commit it
72
71
  unbind Remove the org/room keys from .run402.json
73
72
  payout-wallet Set or clear the tenant route payout wallet (admin+)
74
- whoami Resolved principal + org memberships (GET /agent/v1/whoami)
75
- member Manage members (list, add, role, rm) — mutations require owner
73
+ members Manage members (list, add, role, rm) — mutations require owner
76
74
  invite Manage email invites (list, create, rm) — mutations require owner
77
75
  audit Control-plane audit trail for an org (admin+)
78
76
 
@@ -84,25 +82,25 @@ Notes:
84
82
  - JSON in, JSON out.
85
83
 
86
84
  Examples:
87
- run402 org create --name "Kychee"
88
- run402 org list
89
- run402 org get # the current org (binding / org use)
90
- run402 org get 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d
91
- run402 org rename --name "New Name"
92
- run402 org rename --clear
93
- run402 org payout-wallet 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
94
- run402 org payout-wallet --clear
95
- run402 org member add 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
96
- run402 org member add 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
97
- run402 org invite create dev@example.com --role developer
98
- run402 org audit --limit 50
85
+ run402 orgs create --name "Kychee"
86
+ run402 orgs list
87
+ run402 orgs get # the current org (binding / orgs use)
88
+ run402 orgs get 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d
89
+ run402 orgs rename --name "New Name"
90
+ run402 orgs rename --clear
91
+ run402 orgs payout-wallet 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
92
+ run402 orgs payout-wallet --clear
93
+ run402 orgs members add 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
94
+ run402 orgs members add 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
95
+ run402 orgs invite create dev@example.com --role developer
96
+ run402 orgs audit --limit 50
99
97
  `;
100
98
 
101
99
  const SUB_HELP = {
102
- create: `run402 org create — create an empty org (prototype tier; you become owner)
100
+ create: `run402 orgs create — create an empty org (prototype tier; you become owner)
103
101
 
104
102
  Usage:
105
- run402 org create [--name <label>]
103
+ run402 orgs create [--name <label>]
106
104
 
107
105
  The label is an optional free-text name (non-unique, not an id). Omit for an
108
106
  unlabeled org. There is no tier input at create; the response reports the
@@ -110,42 +108,51 @@ created org's prototype tier plus lease_started_at / lease_expires_at. Paid
110
108
  tiers are a separate flow. Step-up gated for control-plane sessions; the
111
109
  free-org cap may apply.
112
110
  `,
113
- list: `run402 org list — orgs you are a member of
111
+ list: `run402 orgs list — your orgs, with the account overview
114
112
 
115
113
  Usage:
116
- run402 org list
114
+ run402 orgs list
115
+
116
+ Lists every org you are a member of (GET /orgs/v1) and joins each row with
117
+ the account overview (GET /agent/v1/me/overview): tier, lifecycle state,
118
+ lease, quotas, allowance. The output also carries the overview's wallets,
119
+ rollup, and advisories, plus scope and session (the sign-in session's grade,
120
+ or null when a wallet reads). Both reads use the CLI's credential: the active
121
+ wallet when there is one, else the sign-in session from 'run402 login'. When the overview
122
+ read is refused (a grant key, for one), the memberships still print and
123
+ 'overview' is null.
117
124
  `,
118
- get: `run402 org get — read one org (label + tier/lease + your role)
125
+ get: `run402 orgs get — read one org (label + tier/lease + your role)
119
126
 
120
127
  Usage:
121
- run402 org get [<org_id>]
128
+ run402 orgs get [<org_id>]
122
129
 
123
130
  Any active member may read. A non-member (including a guessed id) gets the same
124
131
  non-revealing 403.
125
132
  `,
126
- rename: `run402 org rename — set or clear an org's display label (owner-only)
133
+ rename: `run402 orgs rename — set or clear an org's display label (owner-only)
127
134
 
128
135
  Usage:
129
- run402 org rename [<org_id>] --name <display_name>
130
- run402 org rename [<org_id>] --clear
136
+ run402 orgs rename [<org_id>] --name <display_name>
137
+ run402 orgs rename [<org_id>] --clear
131
138
 
132
139
  Legacy (still supported):
133
- run402 org rename [<org_id>] <display_name>
140
+ run402 orgs rename [<org_id>] <display_name>
134
141
 
135
142
  Owner-only + step-up gated. Pass --clear (or an empty display_name) to remove
136
143
  the label. Output includes the updated tier and lease timestamps.
137
144
  `,
138
- slug: `run402 org slug — claim or rename the org's address-form slug
145
+ slug: `run402 orgs slug — set or rename the org's address-form slug
139
146
 
140
147
  Usage:
141
- run402 org slug <slug> [--org <org_id>] [--idempotency-key <key>]
148
+ run402 orgs slug <slug> [--org <org_id>] [--idempotency-key <key>]
142
149
 
143
- The slug is a globally-unique, claimable, address-form handle for the org
150
+ The slug is a globally-unique, address-form handle for the org
144
151
  (repo-first-onramp design D6) — the <org-slug> half of a named repo address
145
152
  run402::<org-slug>/<name>. Grammar: lowercase [a-z0-9-], no leading/trailing/
146
153
  double hyphen, max 39 chars. Owner-only.
147
154
 
148
- A genesis claim (the org had no prior slug) spends a one-time claim fee off
155
+ A genesis set (the org had no prior slug) spends a one-time fee off
149
156
  the org's balance. A rename is free but releases the OLD slug into a ~90-day
150
157
  cooldown: it stops resolving, with a typed SLUG_RELEASED refusal naming the
151
158
  new slug as successor — there is no redirect, so update every remote and
@@ -155,14 +162,14 @@ This is a paid, side-effecting mutation and requires Idempotency-Key; the SDK
155
162
  generates one automatically unless --idempotency-key is passed, so a retried
156
163
  call after a dropped response can never double-bill.
157
164
  `,
158
- "payout-wallet": `run402 org payout-wallet — set or clear the tenant route payout wallet
165
+ "payout-wallet": `run402 orgs payout-wallet — set or clear the tenant route payout wallet
159
166
 
160
167
  Usage:
161
- run402 org payout-wallet [<org_id>] <wallet_address>
162
- run402 org payout-wallet [<org_id>] --clear
168
+ run402 orgs payout-wallet [<org_id>] <wallet_address>
169
+ run402 orgs payout-wallet [<org_id>] --clear
163
170
 
164
171
  Legacy (still supported):
165
- run402 org payout-wallet [<org_id>] <wallet_address>
172
+ run402 orgs payout-wallet [<org_id>] <wallet_address>
166
173
 
167
174
  Admin/owner-only + step-up gated. The wallet must already be active and linked
168
175
  to the same org. This wallet receives x402 settlement for function web routes
@@ -172,50 +179,39 @@ explicit default; a single active org wallet may still resolve automatically.
172
179
  The JSON response includes recovery.status, active_wallet_count, and
173
180
  next_actions for PAYOUT_WALLET_REQUIRED / PAYOUT_WALLET_AMBIGUOUS setup.
174
181
  `,
175
- whoami: `run402 org whoami — resolved principal + org memberships (and set your display name)
182
+ members: `run402 orgs members — manage org members
176
183
 
177
184
  Usage:
178
- run402 org whoami
179
-
180
- Calls GET /agent/v1/whoami (or PATCH /agent/v1/me with --set-name, 1-64 chars: the name promotion
181
- credit, \`run402 up\`'s room presence, and audit surfaces show for this principal — \`up\` sets a
182
- detected default when it is empty). Returns the control-plane principal (id/type/display_name/created_at),
183
- authenticator_id, and every org membership (org_id, display_name, role, status). REMOTE identity;
184
- for local wallet/profile state use 'run402 status'.
185
- `,
186
- member: `run402 org member — manage org members
187
-
188
- Usage:
189
- run402 org member list [<org_id>]
190
- run402 org member add [<org_id>] <wallet_address> [--role <role>]
191
- run402 org member role [<org_id>] --principal <principal_id> --role <role>
192
- run402 org member rm [<org_id>] --principal <principal_id>
193
- run402 org member revoke-key [<org_id>] --principal <principal_id> [--reason <why>] (owner + step-up; revokes the member's gitvault encryption key — its next gitvault operation enrolls afresh)
185
+ run402 orgs members list [<org_id>]
186
+ run402 orgs members add [<org_id>] <wallet_address> [--role <role>]
187
+ run402 orgs members role [<org_id>] --principal <principal_id> --role <role>
188
+ run402 orgs members rm [<org_id>] --principal <principal_id>
189
+ run402 orgs members revoke-key [<org_id>] --principal <principal_id> [--reason <why>] (owner + step-up; revokes the member's gitvault encryption key — its next gitvault operation enrolls afresh)
194
190
 
195
191
  Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
196
192
  Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
197
193
  `,
198
- invite: `run402 org invite — manage email invites
194
+ invite: `run402 orgs invite — manage email invites
199
195
 
200
196
  Usage:
201
- run402 org invite list [<org_id>]
202
- run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
203
- run402 org invite rm [<org_id>] --principal <principal_id>
197
+ run402 orgs invite list [<org_id>]
198
+ run402 orgs invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
199
+ run402 orgs invite rm [<org_id>] --principal <principal_id>
204
200
 
205
201
  <org_id> is optional everywhere: a leading UUID positional addresses that org;
206
202
  omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
207
- binding, then 'run402 org use'. Inside a bound checkout two agents add each
208
- other with nothing to look up: run402 org member add <wallet_address> --role developer.
203
+ binding, then 'run402 orgs use'. Inside a bound checkout two agents add each
204
+ other with nothing to look up: run402 orgs members add <wallet_address> --role developer.
209
205
  A developer-or-above add REFUSES (GITVAULT_WRITER_NOT_ADMITTED) unless this session's key is an admitted writer on every vault of the org, so the new member can push at once; a current writer admits your key with run402 repos access sync.
210
- The second attribute may also be passed positionally (run402 org member add <wallet_address>).
206
+ The second attribute may also be passed positionally (run402 orgs members add <wallet_address>).
211
207
 
212
208
  An invite is claimed at the recipient's first login. Mutations require an active owner
213
209
  (plus step-up when driven by a control-plane session).
214
210
  `,
215
- audit: `run402 org audit — control-plane audit trail
211
+ audit: `run402 orgs audit — control-plane audit trail
216
212
 
217
213
  Usage:
218
- run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
214
+ run402 orgs audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
219
215
 
220
216
  Requires an admin+ membership on the org. Newest-first. Page forward with --after
221
217
  (next_cursor from a prior page); --before is the legacy cursor. Returns
@@ -223,12 +219,12 @@ Requires an admin+ membership on the org. Newest-first. Page forward with --afte
223
219
  `,
224
220
  };
225
221
 
226
- // ── Top-level: create / list / get / rename / whoami / audit ────────────────────
222
+ // ── Top-level: create / list / get / rename / audit ────────────────────
227
223
 
228
224
 
229
225
  /**
230
226
  * gitvault-multi-writer (rev 47) task 6.3 / design D3 — decided 2026-09-03
231
- * (Tal): `org member add` REFUSES a writer-eligible add (developer or
227
+ * (Tal): `orgs members add` REFUSES a writer-eligible add (developer or
232
228
  * above) when this session's own key is not an admitted writer on EVERY
233
229
  * vault of the org, because a developer who cannot push is not the member
234
230
  * the caller meant, and a half-usable membership is exactly the silent
@@ -270,7 +266,7 @@ async function assertCallerCanAdmitWritersEverywhere(sdk, orgId, effectiveRole)
270
266
  }
271
267
 
272
268
  /**
273
- * `org member rm`'s inline epoch rotation (gitvault-multi-writer D6, the
269
+ * `orgs members rm`'s inline epoch rotation (gitvault-multi-writer D6, the
274
270
  * kygit-handoff member-removal decision): for every vault of the org where
275
271
  * this session's key is an admitted writer, drive
276
272
  * `rotateEpochForKeyRevocation(principalId)` — the one self-contained
@@ -317,7 +313,7 @@ async function create(args) {
317
313
  const a = normalizeArgv(args);
318
314
  const valueFlags = ["--name"];
319
315
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
320
- requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 org create [--name <label>]" });
316
+ requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 orgs create [--name <label>]" });
321
317
  const name = flagValue(a, "--name");
322
318
  try {
323
319
  console.log(JSON.stringify(await getSdk().orgs.create({ displayName: name ?? undefined }), null, 2));
@@ -329,36 +325,36 @@ async function create(args) {
329
325
  async function list(args) {
330
326
  const a = normalizeArgv(args);
331
327
  assertKnownFlags(a, ["--help", "-h"]);
332
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org list" });
328
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs list" });
329
+ const sdk = getSdk();
330
+ let orgs;
333
331
  try {
334
- console.log(JSON.stringify({ orgs: await getSdk().orgs.list() }, null, 2));
332
+ orgs = await sdk.orgs.list();
335
333
  } catch (err) {
336
- reportSdkError(err);
337
- }
338
- }
339
-
340
- async function whoami(args) {
341
- const a = normalizeArgv(args);
342
- assertKnownFlags(a, ["--help", "-h", "--set-name"], ["--set-name"]);
343
- requirePositionalCount(positionalArgs(a, ["--set-name"]), ["--set-name"], { min: 0, max: 0, command: "run402 org whoami" });
344
- const setName = flagValue(a, "--set-name");
345
- if (setName !== null && setName.trim() === "") {
346
- fail({
347
- code: "BAD_USAGE",
348
- message: "--set-name must not be empty.",
349
- details: { field: "--set-name" },
350
- hint: "Pass a 1-64 character display name.",
351
- });
334
+ return reportSdkError(err);
352
335
  }
336
+ // The account overview is the richer read, made with the same credential as
337
+ // the membership list; a caller the overview does not accept (a grant key)
338
+ // still gets its memberships.
339
+ let overview = null;
353
340
  try {
354
- // principal-display-name (first-deploy-agent-dx): `--set-name` is the
355
- // explicit setter (PATCH /agent/v1/me); the name is what promotion credit,
356
- // `up`'s room presence, and audit surfaces show for this principal.
357
- const me = setName !== null ? await getSdk().orgs.setDisplayName(setName.trim()) : await getSdk().orgs.whoami();
358
- console.log(JSON.stringify(me, null, 2));
359
- } catch (err) {
360
- reportSdkError(err);
341
+ overview = await sdk.me.overview();
342
+ } catch {
343
+ overview = null;
361
344
  }
345
+ const byId = new Map((overview?.organizations ?? []).map((o) => [o.id, o]));
346
+ console.log(JSON.stringify({
347
+ orgs: orgs.map((m) => (byId.has(m.org_id) ? { ...m, overview: byId.get(m.org_id) } : m)),
348
+ ...(overview
349
+ ? {
350
+ scope: overview.scope ?? null,
351
+ session: overview.session ?? null,
352
+ rollup: overview.rollup ?? null,
353
+ wallets: overview.wallets ?? [],
354
+ advisories: overview.advisories ?? [],
355
+ }
356
+ : { overview: null }),
357
+ }, null, 2));
362
358
  }
363
359
 
364
360
  // ── Current organization (add-cli-current-org) ─────────────────────────────────
@@ -372,7 +368,7 @@ async function use(args) {
372
368
  const a = normalizeArgv(args);
373
369
  assertKnownFlags(a, ["--help", "-h"]);
374
370
  requirePositionalCount(a, [], {
375
- min: 1, max: 1, command: "run402 org use <org_id>", missing: "<org_id>",
371
+ min: 1, max: 1, command: "run402 orgs use <org_id>", missing: "<org_id>",
376
372
  });
377
373
  const orgId = positionalArgs(a, [])[0];
378
374
  setSelectedOrgId(orgId);
@@ -382,7 +378,7 @@ async function use(args) {
382
378
  async function clear(args) {
383
379
  const a = normalizeArgv(args);
384
380
  assertKnownFlags(a, ["--help", "-h"]);
385
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org clear" });
381
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs clear" });
386
382
  const previous = getSelectedOrgId();
387
383
  clearSelectedOrgId();
388
384
  console.log(JSON.stringify({ org_id: null, selected: false, previous_org_id: previous ?? null }, null, 2));
@@ -415,7 +411,7 @@ async function bind(args) {
415
411
  const a = normalizeArgv(args);
416
412
  const valueFlags = ["--org", "--room"];
417
413
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
418
- requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 org bind [--org <org_id>] [--room <key>]" });
414
+ requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 orgs bind [--org <org_id>] [--room <key>]" });
419
415
 
420
416
  let orgId = flagValue(a, "--org");
421
417
  let picked = "flag";
@@ -432,7 +428,7 @@ async function bind(args) {
432
428
  fail({
433
429
  code: "NO_ORGS",
434
430
  message: "This wallet is a member of no organization yet.",
435
- hint: "Run 'run402 init' to provision one, or ask an owner to add you with 'run402 org member add'.",
431
+ hint: "Run 'run402 init' to provision one, or ask an owner to add you with 'run402 orgs members add'.",
436
432
  next_actions: [nextAction("initialize_wallet", { command: "run402 init", why: "Provision this wallet's organization, then retry." })],
437
433
  });
438
434
  }
@@ -440,9 +436,9 @@ async function bind(args) {
440
436
  fail({
441
437
  code: "AMBIGUOUS_ORG",
442
438
  message: `This wallet belongs to ${rows.length} organizations — name the one to bind.`,
443
- hint: "run402 org bind --org <org_id>",
439
+ hint: "run402 orgs bind --org <org_id>",
444
440
  details: { orgs: rows.map((o) => ({ org_id: o.org_id, display_name: o.display_name ?? null, role: o.role ?? null })) },
445
- next_actions: [nextAction("edit_request", { command: "run402 org bind --org <org_id>", why: "Name which organization this checkout coordinates in." })],
441
+ next_actions: [nextAction("edit_request", { command: "run402 orgs bind --org <org_id>", why: "Name which organization this checkout coordinates in." })],
446
442
  });
447
443
  }
448
444
  orgId = rows[0].org_id;
@@ -451,7 +447,7 @@ async function bind(args) {
451
447
 
452
448
  const room = flagValue(a, "--room") ?? roomKeyFromDir(process.cwd());
453
449
  const { contents, file } = updateBindingFile(process.cwd(), {
454
- org: requireOrgIdShape(orgId, picked === "flag" ? "--org" : "org list"),
450
+ org: requireOrgIdShape(orgId, picked === "flag" ? "--org" : "orgs list"),
455
451
  ...(room ? { room } : {}),
456
452
  });
457
453
  console.log(JSON.stringify({
@@ -470,7 +466,7 @@ async function bind(args) {
470
466
  async function unbind(args) {
471
467
  const a = normalizeArgv(args);
472
468
  assertKnownFlags(a, ["--help", "-h"]);
473
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org unbind" });
469
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs unbind" });
474
470
  const previous = readBindingFile(process.cwd());
475
471
  const { contents, removed } = updateBindingFile(process.cwd(), { org: null, room: null });
476
472
  console.log(JSON.stringify({
@@ -484,13 +480,13 @@ async function unbind(args) {
484
480
  async function current(args) {
485
481
  const a = normalizeArgv(args);
486
482
  assertKnownFlags(a, ["--help", "-h"]);
487
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org current" });
483
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs current" });
488
484
  try {
489
- // `cmd: "org"` exempts this from the ambiguity error on purpose: the
485
+ // `cmd: "orgs"` exempts this from the ambiguity error on purpose: the
490
486
  // command that reports the selection must stay usable while it is ambiguous.
491
487
  // `optional` keeps an empty selection an explicit null state rather than a
492
488
  // failure — reporting is not acting.
493
- const resolved = await resolveOrg([], { cmd: "org", optional: true });
489
+ const resolved = await resolveOrg([], { cmd: "orgs", optional: true });
494
490
  console.log(JSON.stringify({
495
491
  ...orgProvenance(resolved),
496
492
  selected_org_id: getSelectedOrgId() ?? null,
@@ -503,8 +499,8 @@ async function current(args) {
503
499
  async function get(args) {
504
500
  const a = normalizeArgv(args);
505
501
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
506
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
507
- requireRest(pos, { max: 0, command: "run402 org get [<org_id>]" });
502
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "orgs" });
503
+ requireRest(pos, { max: 0, command: "run402 orgs get [<org_id>]" });
508
504
  try {
509
505
  console.log(JSON.stringify(await getSdk().org(org).get(), null, 2));
510
506
  } catch (err) {
@@ -518,11 +514,11 @@ async function rename(args) {
518
514
  const clear = a.includes("--clear");
519
515
  const nameFlag = flagValue(a, "--name");
520
516
  const single = clear || nameFlag !== null;
521
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--name"], { cmd: "org" });
517
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--name"], { cmd: "orgs" });
522
518
  requireRest(pos, {
523
519
  min: single ? 0 : 1,
524
520
  max: single ? 0 : 1,
525
- command: "run402 org rename [<org_id>] --name <display_name>",
521
+ command: "run402 orgs rename [<org_id>] --name <display_name>",
526
522
  missing: "Missing <display_name> (use --name, or pass --clear).",
527
523
  });
528
524
  const displayName = clear ? null : (nameFlag ?? pos[0]);
@@ -539,11 +535,11 @@ async function payoutWallet(args) {
539
535
  const clear = a.includes("--clear");
540
536
  const walletFlag = flagValue(a, "--address");
541
537
  const single = clear || walletFlag !== null;
542
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--address"], { cmd: "org" });
538
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--address"], { cmd: "orgs" });
543
539
  requireRest(pos, {
544
540
  min: single ? 0 : 1,
545
541
  max: single ? 0 : 1,
546
- command: "run402 org payout-wallet [<org_id>] --address <wallet_address>",
542
+ command: "run402 orgs payout-wallet [<org_id>] --address <wallet_address>",
547
543
  missing: "Missing <wallet_address> (use --address, or pass --clear).",
548
544
  });
549
545
  const walletAddress = clear ? null : (walletFlag ?? pos[0]);
@@ -555,13 +551,65 @@ async function payoutWallet(args) {
555
551
  }
556
552
 
557
553
  /**
558
- * `run402 org slug <slug>` — claim or rename the org's address-form slug.
559
- * Owner-only, and a genesis claim spends a one-time claim fee — this is a
554
+ * `run402 orgs slug <slug>` — set or rename the org's address-form slug.
555
+ * Owner-only, and a genesis set spends a one-time fee — this is a
560
556
  * PAID, side-effecting mutation, so it
561
557
  * requires `Idempotency-Key`; the SDK generates one client-side when
562
558
  * `--idempotency-key` is omitted, so a retried call after a dropped response
563
559
  * can never double-bill.
564
560
  */
561
+ /**
562
+ * `run402 orgs adopt` — become the owner of the org your wallet's agent
563
+ * created (an ownership transfer on org memberships; the wallet stays on the
564
+ * agent, which is downgraded to developer). Dual proof: the write-capable
565
+ * sign-in session + a fresh signature from the active wallet over a server
566
+ * nonce. The Node convenience runs the whole dance (read session → challenge
567
+ * → sign → submit). Step-up failures and the multi-org `select_org`
568
+ * round-trip are surfaced here, not thrown at the user.
569
+ */
570
+ async function adopt(args) {
571
+ const a = normalizeArgv(args);
572
+ const valueFlags = ["--org", "--name"];
573
+ assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
574
+ requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 orgs adopt [--org <org_id>] [--name <label>]" });
575
+ const orgId = flagValue(a, "--org");
576
+ const name = flagValue(a, "--name");
577
+ try {
578
+ const { adoptOrg } = await import("#sdk/node");
579
+ const result = await adoptOrg(getSdk(), {
580
+ orgId: orgId ?? undefined,
581
+ displayName: name ?? undefined,
582
+ });
583
+ // CLI output contract (cli-output-shape): no top-level `status` envelope.
584
+ // The gateway's discriminator becomes an explicit `adopted` boolean.
585
+ if (result && result.status === "select_org") {
586
+ console.log(JSON.stringify({
587
+ adopted: false,
588
+ selectable_orgs: result.selectable_orgs,
589
+ hint: "Your wallet's agent owns more than one org. Re-run with --org <org_id> to adopt one.",
590
+ }, null, 2));
591
+ return;
592
+ }
593
+ console.log(JSON.stringify({
594
+ adopted: true,
595
+ org_id: result.org_id,
596
+ display_name: result.display_name,
597
+ role: result.role,
598
+ already_owned: result.already_owned ?? false,
599
+ }, null, 2));
600
+ } catch (err) {
601
+ const { isStepUpRequired } = await import("#sdk/node");
602
+ if (isStepUpRequired(err)) {
603
+ return fail({
604
+ code: "STEP_UP_REQUIRED",
605
+ message: "Adopting an org needs a fresh passkey step-up.",
606
+ hint: "Run 'run402 login' (a fresh passkey sign-in), then re-run 'run402 orgs adopt'.",
607
+ });
608
+ }
609
+ reportSdkError(err);
610
+ }
611
+ }
612
+
565
613
  async function slug(args) {
566
614
  const a = normalizeArgv(args);
567
615
  const valueFlags = ["--org", "--idempotency-key"];
@@ -569,23 +617,23 @@ async function slug(args) {
569
617
  const [newSlug] = requirePositionalCount(a, valueFlags, {
570
618
  min: 1,
571
619
  max: 1,
572
- command: "run402 org slug <slug> [--org <org_id>]",
620
+ command: "run402 orgs slug <slug> [--org <org_id>]",
573
621
  missing: "Missing <slug>.",
574
622
  });
575
- const org = await resolveOrg(a, { cmd: "org" });
623
+ const org = await resolveOrg(a, { cmd: "orgs" });
576
624
  if (!org) {
577
625
  fail({
578
626
  code: "ORG_UNRESOLVED",
579
- message: "Could not resolve which organization to claim this slug for.",
580
- hint: "Pass --org <org_id>, or select one first with `run402 org use <id>`.",
627
+ message: "Could not resolve which organization to set this slug for.",
628
+ hint: "Pass --org <org_id>, or select one first with `run402 orgs use <org_id>`.",
581
629
  });
582
630
  }
583
631
  const idempotencyKey = flagValue(a, "--idempotency-key");
584
632
  try {
585
- const result = await getSdk().org(org.orgId).claimSlug(newSlug, idempotencyKey != null ? { idempotencyKey } : {});
633
+ const result = await getSdk().org(org.orgId).setSlug(newSlug, idempotencyKey != null ? { idempotencyKey } : {});
586
634
  console.log(JSON.stringify(result, null, 2));
587
635
  if (result.created) {
588
- console.error(`slug "${result.slug}" claimed for ${org.orgId} — a one-time claim fee was debited from the org's balance.`);
636
+ console.error(`slug "${result.slug}" set for ${org.orgId} — a one-time fee was debited from the org's balance.`);
589
637
  } else if (result.previous_slug && result.previous_slug !== result.slug) {
590
638
  console.error(
591
639
  `org ${org.orgId} renamed from "${result.previous_slug}" to "${result.slug}" — no fee. ` +
@@ -603,8 +651,8 @@ async function audit(args) {
603
651
  const a = normalizeArgv(args);
604
652
  const valueFlags = ["--org", "--limit", "--after", "--before"];
605
653
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
606
- const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
607
- requireRest(pos, { max: 0, command: "run402 org audit [<org_id>]" });
654
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "orgs" });
655
+ requireRest(pos, { max: 0, command: "run402 orgs audit [<org_id>]" });
608
656
  const limitFlag = flagValue(a, "--limit");
609
657
  const after = flagValue(a, "--after");
610
658
  const before = flagValue(a, "--before");
@@ -627,19 +675,19 @@ async function runMember(args) {
627
675
  const memberAction = args[0];
628
676
  const rest = args.slice(1);
629
677
  if (!memberAction || memberAction === "--help" || memberAction === "-h") {
630
- console.log(SUB_HELP.member);
678
+ console.log(SUB_HELP.members);
631
679
  process.exit(memberAction ? 0 : 1);
632
680
  }
633
681
  if (rest.includes("--help") || rest.includes("-h")) {
634
- console.log(SUB_HELP.member);
682
+ console.log(SUB_HELP.members);
635
683
  process.exit(0);
636
684
  }
637
685
 
638
686
  if (memberAction === "list") {
639
687
  const a = normalizeArgv(rest);
640
688
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
641
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
642
- requireRest(pos, { max: 0, command: "run402 org member list [<org_id>]" });
689
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "orgs" });
690
+ requireRest(pos, { max: 0, command: "run402 orgs members list [<org_id>]" });
643
691
  try {
644
692
  console.log(JSON.stringify({ members: await getSdk().org(org).members.list() }, null, 2));
645
693
  } catch (err) {
@@ -654,9 +702,9 @@ async function runMember(args) {
654
702
  const role = flagValue(a, "--role");
655
703
  const walletFlag = flagValue(a, "--address");
656
704
  const count = walletFlag ? 0 : 1;
657
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--role", "--address"], { cmd: "org" });
705
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--role", "--address"], { cmd: "orgs" });
658
706
  requireRest(pos, {
659
- min: count, max: count, command: "run402 org member add [<org_id>] <wallet_address> [--role <role>]",
707
+ min: count, max: count, command: "run402 orgs members add [<org_id>] <wallet_address> [--role <role>]",
660
708
  missing: "Missing <wallet_address> (positional, or --address).",
661
709
  });
662
710
  const wallet = walletFlag ?? pos[0];
@@ -673,7 +721,7 @@ async function runMember(args) {
673
721
  // this org's vaults now have a pending writer candidate (D3: there is
674
722
  // no server-side writer admission — the client holds the keys) via a
675
723
  // `sync_writers` next_action carrying `vault_ids[]`. Run the ACTUAL
676
- // reconcile against each one now, so a single `org member add` finishes
724
+ // reconcile against each one now, so a single `orgs members add` finishes
677
725
  // the whole job when the caller can. `reconcile()` is ALREADY a
678
726
  // fast, network-free no-op per vault when this session's own key
679
727
  // isn't a writer there (task 5.7's own `eligible` gate). For a
@@ -721,9 +769,9 @@ async function runMember(args) {
721
769
  const principalFlag = flagValue(a, "--principal");
722
770
  const reason = flagValue(a, "--reason");
723
771
  const count = principalFlag ? 0 : 1;
724
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--reason"], { cmd: "org" });
772
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--reason"], { cmd: "orgs" });
725
773
  requireRest(pos, {
726
- min: count, max: count, command: "run402 org member revoke-key [<org_id>] --principal <principal_id> [--reason <why>]",
774
+ min: count, max: count, command: "run402 orgs members revoke-key [<org_id>] --principal <principal_id> [--reason <why>]",
727
775
  missing: "Missing <principal_id> (--principal).",
728
776
  });
729
777
  const principalId = principalFlag ?? pos[0];
@@ -741,9 +789,9 @@ async function runMember(args) {
741
789
  const principalFlag = flagValue(a, "--principal");
742
790
  const roleFlag = flagValue(a, "--role");
743
791
  const count = 2 - (principalFlag ? 1 : 0) - (roleFlag ? 1 : 0);
744
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--role"], { cmd: "org" });
792
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--role"], { cmd: "orgs" });
745
793
  requireRest(pos, {
746
- min: count, max: count, command: "run402 org member role [<org_id>] --principal <principal_id> --role <role>",
794
+ min: count, max: count, command: "run402 orgs members role [<org_id>] --principal <principal_id> --role <role>",
747
795
  missing: "Missing <principal_id> (--principal) and/or <role> (--role).",
748
796
  });
749
797
  const principalId = principalFlag ?? pos[0];
@@ -761,9 +809,9 @@ async function runMember(args) {
761
809
  assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
762
810
  const principalFlag = flagValue(a, "--principal");
763
811
  const count = principalFlag ? 0 : 1;
764
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "org" });
812
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "orgs" });
765
813
  requireRest(pos, {
766
- min: count, max: count, command: "run402 org member rm [<org_id>] --principal <principal_id>",
814
+ min: count, max: count, command: "run402 orgs members rm [<org_id>] --principal <principal_id>",
767
815
  missing: "Missing <principal_id> (use --principal).",
768
816
  });
769
817
  const principalId = principalFlag ?? pos[0];
@@ -792,7 +840,7 @@ async function runMember(args) {
792
840
  return;
793
841
  }
794
842
 
795
- fail({ code: "BAD_USAGE", message: `Unknown 'org member' action: ${memberAction}. Try list | add | role | rm.` });
843
+ fail({ code: "BAD_USAGE", message: `Unknown 'orgs members' action: ${memberAction}. Try list | add | role | rm.` });
796
844
  }
797
845
 
798
846
  // ── Invite group ─────────────────────────────────────────────────────────────────
@@ -812,8 +860,8 @@ async function runInvite(args) {
812
860
  if (inviteAction === "list") {
813
861
  const a = normalizeArgv(rest);
814
862
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
815
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
816
- requireRest(pos, { max: 0, command: "run402 org invite list [<org_id>]" });
863
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "orgs" });
864
+ requireRest(pos, { max: 0, command: "run402 orgs invite list [<org_id>]" });
817
865
  try {
818
866
  console.log(JSON.stringify({ invites: await getSdk().org(org).invites.list() }, null, 2));
819
867
  } catch (err) {
@@ -830,9 +878,9 @@ async function runInvite(args) {
830
878
  const ttlFlag = flagValue(a, "--ttl-hours");
831
879
  const emailFlag = flagValue(a, "--email");
832
880
  const count = emailFlag ? 0 : 1;
833
- const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
881
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "orgs" });
834
882
  requireRest(pos, {
835
- min: count, max: count, command: "run402 org invite create [<org_id>] --email <email> [--role <role>]",
883
+ min: count, max: count, command: "run402 orgs invite create [<org_id>] --email <email> [--role <role>]",
836
884
  missing: "Missing <email> (use --email).",
837
885
  });
838
886
  const email = emailFlag ?? pos[0];
@@ -851,9 +899,9 @@ async function runInvite(args) {
851
899
  assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
852
900
  const principalFlag = flagValue(a, "--principal");
853
901
  const count = principalFlag ? 0 : 1;
854
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "org" });
902
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "orgs" });
855
903
  requireRest(pos, {
856
- min: count, max: count, command: "run402 org invite rm [<org_id>] --principal <principal_id>",
904
+ min: count, max: count, command: "run402 orgs invite rm [<org_id>] --principal <principal_id>",
857
905
  missing: "Missing <principal_id> (use --principal).",
858
906
  });
859
907
  const principalId = principalFlag ?? pos[0];
@@ -865,7 +913,7 @@ async function runInvite(args) {
865
913
  return;
866
914
  }
867
915
 
868
- fail({ code: "BAD_USAGE", message: `Unknown 'org invite' action: ${inviteAction}. Try list | create | rm.` });
916
+ fail({ code: "BAD_USAGE", message: `Unknown 'orgs invite' action: ${inviteAction}. Try list | create | rm.` });
869
917
  }
870
918
 
871
919
  export async function run(sub, args) {
@@ -875,11 +923,11 @@ export async function run(sub, args) {
875
923
  }
876
924
  // Nested groups use `if (sub === ...)` (not `case`) so the sync test extracts
877
925
  // their leaf actions via the dedicated memberAction/inviteAction parsers.
878
- if (sub === "member" || sub === "members") {
926
+ if (sub === "members") {
879
927
  await runMember(args ?? []);
880
928
  return;
881
929
  }
882
- if (sub === "invite" || sub === "invites") {
930
+ if (sub === "invite") {
883
931
  await runInvite(args ?? []);
884
932
  return;
885
933
  }
@@ -894,7 +942,7 @@ export async function run(sub, args) {
894
942
  case "rename": await rename(args); break;
895
943
  case "payout-wallet": await payoutWallet(args); break;
896
944
  case "slug": await slug(args); break;
897
- case "whoami": await whoami(args); break;
945
+ case "adopt": await adopt(args); break;
898
946
  case "use": await use(args); break;
899
947
  case "current": await current(args); break;
900
948
  case "clear": await clear(args); break;
@@ -902,6 +950,6 @@ export async function run(sub, args) {
902
950
  case "unbind": await unbind(args); break;
903
951
  case "audit": await audit(args); break;
904
952
  default:
905
- failUnknownSubcommand("org", sub);
953
+ failUnknownSubcommand("orgs", sub);
906
954
  }
907
955
  }