run402 4.94.0 → 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 (131) hide show
  1. package/README.md +20 -20
  2. package/cli.mjs +7 -19
  3. package/gitvault-surface.json +2 -2
  4. package/lib/admin.mjs +5 -5
  5. package/lib/ai.mjs +5 -5
  6. package/lib/apps.mjs +9 -9
  7. package/lib/archives.mjs +371 -8
  8. package/lib/argparse.mjs +5 -5
  9. package/lib/assets.mjs +12 -12
  10. package/lib/auth.mjs +34 -34
  11. package/lib/branches.mjs +7 -7
  12. package/lib/buzz-doctor.mjs +1 -1
  13. package/lib/buzz-notifications.mjs +4 -4
  14. package/lib/buzz.mjs +2 -2
  15. package/lib/cache.mjs +1 -1
  16. package/lib/cdn.mjs +2 -2
  17. package/lib/ci.mjs +8 -8
  18. package/lib/claims.mjs +2 -2
  19. package/lib/command-manifest.mjs +35 -36
  20. package/lib/config.mjs +4 -4
  21. package/lib/contacts.mjs +3 -3
  22. package/lib/contracts.mjs +11 -11
  23. package/lib/credentials.mjs +31 -31
  24. package/lib/delegates.mjs +13 -13
  25. package/lib/deliveries.mjs +2 -2
  26. package/lib/deploy-v2.mjs +9 -9
  27. package/lib/dev.mjs +3 -3
  28. package/lib/doctor.mjs +6 -6
  29. package/lib/domains.mjs +27 -27
  30. package/lib/email.mjs +38 -38
  31. package/lib/errors.mjs +40 -24
  32. package/lib/escalations.mjs +4 -4
  33. package/lib/events.mjs +32 -25
  34. package/lib/feedback.mjs +2 -2
  35. package/lib/functions.mjs +34 -34
  36. package/lib/gitvault-scaffold.mjs +2 -2
  37. package/lib/gitvault.mjs +2 -2
  38. package/lib/grants.mjs +7 -7
  39. package/lib/image.mjs +7 -7
  40. package/lib/init.mjs +3 -3
  41. package/lib/jobs.mjs +15 -15
  42. package/lib/live.mjs +1 -1
  43. package/lib/logs.mjs +8 -8
  44. package/lib/messages.mjs +5 -5
  45. package/lib/next-actions.mjs +1 -1
  46. package/lib/org-context.mjs +13 -13
  47. package/lib/{org.mjs → orgs.mjs} +124 -163
  48. package/lib/projects.mjs +45 -56
  49. package/lib/repos.mjs +23 -23
  50. package/lib/rooms.mjs +2 -2
  51. package/lib/sdk-errors.mjs +1 -1
  52. package/lib/secrets.mjs +13 -13
  53. package/lib/sites.mjs +14 -14
  54. package/lib/snapshots.mjs +10 -10
  55. package/lib/subdomains.mjs +12 -12
  56. package/lib/subscriptions.mjs +2 -2
  57. package/lib/transfer.mjs +1 -1
  58. package/lib/up.mjs +7 -7
  59. package/lib/wallet-context.mjs +1 -1
  60. package/lib/wallets.mjs +1 -1
  61. package/lib/webhooks.mjs +8 -8
  62. package/lib/whoami.mjs +32 -5
  63. package/package.json +1 -1
  64. package/sdk/dist/actions.d.ts +3 -3
  65. package/sdk/dist/actions.d.ts.map +1 -1
  66. package/sdk/dist/app-up.d.ts +2 -2
  67. package/sdk/dist/app-up.d.ts.map +1 -1
  68. package/sdk/dist/config.d.ts +1 -2
  69. package/sdk/dist/config.d.ts.map +1 -1
  70. package/sdk/dist/config.js.map +1 -1
  71. package/sdk/dist/credentials.d.ts +1 -1
  72. package/sdk/dist/errors.d.ts +2 -2
  73. package/sdk/dist/errors.d.ts.map +1 -1
  74. package/sdk/dist/errors.js +1 -1
  75. package/sdk/dist/errors.js.map +1 -1
  76. package/sdk/dist/index.js +1 -1
  77. package/sdk/dist/index.js.map +1 -1
  78. package/sdk/dist/namespaces/admin.d.ts +1 -1
  79. package/sdk/dist/namespaces/admin.d.ts.map +1 -1
  80. package/sdk/dist/namespaces/ai.d.ts +1 -1
  81. package/sdk/dist/namespaces/ai.js +2 -2
  82. package/sdk/dist/namespaces/ai.js.map +1 -1
  83. package/sdk/dist/namespaces/assets.js +1 -1
  84. package/sdk/dist/namespaces/assets.js.map +1 -1
  85. package/sdk/dist/namespaces/ci.js +3 -3
  86. package/sdk/dist/namespaces/ci.js.map +1 -1
  87. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  88. package/sdk/dist/namespaces/deploy.js +26 -27
  89. package/sdk/dist/namespaces/deploy.js.map +1 -1
  90. package/sdk/dist/namespaces/deploy.types.d.ts +2 -2
  91. package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
  92. package/sdk/dist/namespaces/domains.d.ts +10 -2
  93. package/sdk/dist/namespaces/domains.d.ts.map +1 -1
  94. package/sdk/dist/namespaces/domains.js +10 -5
  95. package/sdk/dist/namespaces/domains.js.map +1 -1
  96. package/sdk/dist/namespaces/errors.js +1 -1
  97. package/sdk/dist/namespaces/functions.js +1 -1
  98. package/sdk/dist/namespaces/functions.js.map +1 -1
  99. package/sdk/dist/namespaces/gitvault.d.ts +2 -2
  100. package/sdk/dist/namespaces/gitvault.js +4 -4
  101. package/sdk/dist/namespaces/gitvault.js.map +1 -1
  102. package/sdk/dist/namespaces/tier.d.ts +1 -1
  103. package/sdk/dist/namespaces/transfers.d.ts +46 -15
  104. package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
  105. package/sdk/dist/namespaces/transfers.js.map +1 -1
  106. package/sdk/dist/node/actions-node.js +8 -8
  107. package/sdk/dist/node/actions-node.js.map +1 -1
  108. package/sdk/dist/node/assets-node.js +6 -6
  109. package/sdk/dist/node/assets-node.js.map +1 -1
  110. package/sdk/dist/node/ci.js +1 -1
  111. package/sdk/dist/node/ci.js.map +1 -1
  112. package/sdk/dist/node/credentials.d.ts +1 -1
  113. package/sdk/dist/node/credentials.js +1 -1
  114. package/sdk/dist/node/deploy-manifest.d.ts +3 -5
  115. package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
  116. package/sdk/dist/node/deploy-manifest.js +3 -12
  117. package/sdk/dist/node/deploy-manifest.js.map +1 -1
  118. package/sdk/dist/node/gitvault-apply.js +1 -1
  119. package/sdk/dist/node/gitvault-apply.js.map +1 -1
  120. package/sdk/dist/node/manifest-export.js +2 -2
  121. package/sdk/dist/node/manifest-export.js.map +1 -1
  122. package/sdk/dist/node/org-adopt.js +1 -1
  123. package/sdk/dist/node/org-adopt.js.map +1 -1
  124. package/sdk/dist/node/sites-node.js +1 -1
  125. package/sdk/dist/node/sites-node.js.map +1 -1
  126. package/sdk/dist/scoped.d.ts +8 -8
  127. package/sdk/dist/scoped.d.ts.map +1 -1
  128. package/sdk/dist/scoped.js +3 -3
  129. package/sdk/dist/scoped.js.map +1 -1
  130. package/lib/cloud.mjs +0 -256
  131. package/lib/core.mjs +0 -123
@@ -24,39 +24,37 @@ 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 adopt [--org <org_id>] [--name <label>]
37
- run402 org whoami
38
- run402 org whoami --set-name <name>
39
- run402 org use <org_id>
40
- run402 org current
41
- run402 org clear
42
- run402 org bind [--org <org_id>] [--room <key>]
43
- run402 org unbind
44
- run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
45
- run402 org member list [<org_id>]
46
- run402 org member add [<org_id>] <wallet_address> [--role <role>]
47
- run402 org member role [<org_id>] --principal <principal_id> --role <role>
48
- run402 org member rm [<org_id>] --principal <principal_id>
49
- 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)
50
- run402 org invite list [<org_id>]
51
- run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
52
- 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>
53
51
 
54
52
  <org_id> is optional everywhere: a leading UUID positional addresses that org;
55
53
  omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
56
- binding, then 'run402 org use'. Inside a bound checkout two agents add each
57
- 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.
58
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.
59
- 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>).
60
58
 
61
59
  Subcommands:
62
60
  create Create an empty org on the prototype tier (you become owner)
@@ -72,8 +70,7 @@ Subcommands:
72
70
  bind Write this checkout's org (+room) into .run402.json — commit it
73
71
  unbind Remove the org/room keys from .run402.json
74
72
  payout-wallet Set or clear the tenant route payout wallet (admin+)
75
- whoami Resolved principal + org memberships (GET /agent/v1/whoami)
76
- member Manage members (list, add, role, rm) — mutations require owner
73
+ members Manage members (list, add, role, rm) — mutations require owner
77
74
  invite Manage email invites (list, create, rm) — mutations require owner
78
75
  audit Control-plane audit trail for an org (admin+)
79
76
 
@@ -85,25 +82,25 @@ Notes:
85
82
  - JSON in, JSON out.
86
83
 
87
84
  Examples:
88
- run402 org create --name "Kychee"
89
- run402 org list
90
- run402 org get # the current org (binding / org use)
91
- run402 org get 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d
92
- run402 org rename --name "New Name"
93
- run402 org rename --clear
94
- run402 org payout-wallet 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
95
- run402 org payout-wallet --clear
96
- run402 org member add 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
97
- run402 org member add 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
98
- run402 org invite create dev@example.com --role developer
99
- 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
100
97
  `;
101
98
 
102
99
  const SUB_HELP = {
103
- 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)
104
101
 
105
102
  Usage:
106
- run402 org create [--name <label>]
103
+ run402 orgs create [--name <label>]
107
104
 
108
105
  The label is an optional free-text name (non-unique, not an id). Omit for an
109
106
  unlabeled org. There is no tier input at create; the response reports the
@@ -111,10 +108,10 @@ created org's prototype tier plus lease_started_at / lease_expires_at. Paid
111
108
  tiers are a separate flow. Step-up gated for control-plane sessions; the
112
109
  free-org cap may apply.
113
110
  `,
114
- list: `run402 org list — your orgs, with the account overview
111
+ list: `run402 orgs list — your orgs, with the account overview
115
112
 
116
113
  Usage:
117
- run402 org list
114
+ run402 orgs list
118
115
 
119
116
  Lists every org you are a member of (GET /orgs/v1) and joins each row with
120
117
  the account overview (GET /agent/v1/me/overview): tier, lifecycle state,
@@ -125,30 +122,30 @@ wallet when there is one, else the sign-in session from 'run402 login'. When the
125
122
  read is refused (a grant key, for one), the memberships still print and
126
123
  'overview' is null.
127
124
  `,
128
- 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)
129
126
 
130
127
  Usage:
131
- run402 org get [<org_id>]
128
+ run402 orgs get [<org_id>]
132
129
 
133
130
  Any active member may read. A non-member (including a guessed id) gets the same
134
131
  non-revealing 403.
135
132
  `,
136
- 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)
137
134
 
138
135
  Usage:
139
- run402 org rename [<org_id>] --name <display_name>
140
- run402 org rename [<org_id>] --clear
136
+ run402 orgs rename [<org_id>] --name <display_name>
137
+ run402 orgs rename [<org_id>] --clear
141
138
 
142
139
  Legacy (still supported):
143
- run402 org rename [<org_id>] <display_name>
140
+ run402 orgs rename [<org_id>] <display_name>
144
141
 
145
142
  Owner-only + step-up gated. Pass --clear (or an empty display_name) to remove
146
143
  the label. Output includes the updated tier and lease timestamps.
147
144
  `,
148
- slug: `run402 org slug — set or rename the org's address-form slug
145
+ slug: `run402 orgs slug — set or rename the org's address-form slug
149
146
 
150
147
  Usage:
151
- run402 org slug <slug> [--org <org_id>] [--idempotency-key <key>]
148
+ run402 orgs slug <slug> [--org <org_id>] [--idempotency-key <key>]
152
149
 
153
150
  The slug is a globally-unique, address-form handle for the org
154
151
  (repo-first-onramp design D6) — the <org-slug> half of a named repo address
@@ -165,14 +162,14 @@ This is a paid, side-effecting mutation and requires Idempotency-Key; the SDK
165
162
  generates one automatically unless --idempotency-key is passed, so a retried
166
163
  call after a dropped response can never double-bill.
167
164
  `,
168
- "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
169
166
 
170
167
  Usage:
171
- run402 org payout-wallet [<org_id>] <wallet_address>
172
- run402 org payout-wallet [<org_id>] --clear
168
+ run402 orgs payout-wallet [<org_id>] <wallet_address>
169
+ run402 orgs payout-wallet [<org_id>] --clear
173
170
 
174
171
  Legacy (still supported):
175
- run402 org payout-wallet [<org_id>] <wallet_address>
172
+ run402 orgs payout-wallet [<org_id>] <wallet_address>
176
173
 
177
174
  Admin/owner-only + step-up gated. The wallet must already be active and linked
178
175
  to the same org. This wallet receives x402 settlement for function web routes
@@ -182,50 +179,39 @@ explicit default; a single active org wallet may still resolve automatically.
182
179
  The JSON response includes recovery.status, active_wallet_count, and
183
180
  next_actions for PAYOUT_WALLET_REQUIRED / PAYOUT_WALLET_AMBIGUOUS setup.
184
181
  `,
185
- whoami: `run402 org whoami — resolved principal + org memberships (and set your display name)
182
+ members: `run402 orgs members — manage org members
186
183
 
187
184
  Usage:
188
- run402 org whoami
189
-
190
- Calls GET /agent/v1/whoami (or PATCH /agent/v1/me with --set-name, 1-64 chars: the name promotion
191
- credit, \`run402 up\`'s room presence, and audit surfaces show for this principal — \`up\` sets a
192
- detected default when it is empty). Returns the control-plane principal (id/type/display_name/created_at),
193
- authenticator_id, and every org membership (org_id, display_name, role, status). REMOTE identity;
194
- for local wallet/profile state use 'run402 status'.
195
- `,
196
- member: `run402 org member — manage org members
197
-
198
- Usage:
199
- run402 org member list [<org_id>]
200
- run402 org member add [<org_id>] <wallet_address> [--role <role>]
201
- run402 org member role [<org_id>] --principal <principal_id> --role <role>
202
- run402 org member rm [<org_id>] --principal <principal_id>
203
- 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)
204
190
 
205
191
  Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
206
192
  Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
207
193
  `,
208
- invite: `run402 org invite — manage email invites
194
+ invite: `run402 orgs invite — manage email invites
209
195
 
210
196
  Usage:
211
- run402 org invite list [<org_id>]
212
- run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
213
- 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>
214
200
 
215
201
  <org_id> is optional everywhere: a leading UUID positional addresses that org;
216
202
  omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
217
- binding, then 'run402 org use'. Inside a bound checkout two agents add each
218
- 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.
219
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.
220
- 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>).
221
207
 
222
208
  An invite is claimed at the recipient's first login. Mutations require an active owner
223
209
  (plus step-up when driven by a control-plane session).
224
210
  `,
225
- audit: `run402 org audit — control-plane audit trail
211
+ audit: `run402 orgs audit — control-plane audit trail
226
212
 
227
213
  Usage:
228
- run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
214
+ run402 orgs audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
229
215
 
230
216
  Requires an admin+ membership on the org. Newest-first. Page forward with --after
231
217
  (next_cursor from a prior page); --before is the legacy cursor. Returns
@@ -233,12 +219,12 @@ Requires an admin+ membership on the org. Newest-first. Page forward with --afte
233
219
  `,
234
220
  };
235
221
 
236
- // ── Top-level: create / list / get / rename / whoami / audit ────────────────────
222
+ // ── Top-level: create / list / get / rename / audit ────────────────────
237
223
 
238
224
 
239
225
  /**
240
226
  * gitvault-multi-writer (rev 47) task 6.3 / design D3 — decided 2026-09-03
241
- * (Tal): `org member add` REFUSES a writer-eligible add (developer or
227
+ * (Tal): `orgs members add` REFUSES a writer-eligible add (developer or
242
228
  * above) when this session's own key is not an admitted writer on EVERY
243
229
  * vault of the org, because a developer who cannot push is not the member
244
230
  * the caller meant, and a half-usable membership is exactly the silent
@@ -280,7 +266,7 @@ async function assertCallerCanAdmitWritersEverywhere(sdk, orgId, effectiveRole)
280
266
  }
281
267
 
282
268
  /**
283
- * `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
284
270
  * kygit-handoff member-removal decision): for every vault of the org where
285
271
  * this session's key is an admitted writer, drive
286
272
  * `rotateEpochForKeyRevocation(principalId)` — the one self-contained
@@ -327,7 +313,7 @@ async function create(args) {
327
313
  const a = normalizeArgv(args);
328
314
  const valueFlags = ["--name"];
329
315
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
330
- 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>]" });
331
317
  const name = flagValue(a, "--name");
332
318
  try {
333
319
  console.log(JSON.stringify(await getSdk().orgs.create({ displayName: name ?? undefined }), null, 2));
@@ -339,7 +325,7 @@ async function create(args) {
339
325
  async function list(args) {
340
326
  const a = normalizeArgv(args);
341
327
  assertKnownFlags(a, ["--help", "-h"]);
342
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org list" });
328
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs list" });
343
329
  const sdk = getSdk();
344
330
  let orgs;
345
331
  try {
@@ -371,30 +357,6 @@ async function list(args) {
371
357
  }, null, 2));
372
358
  }
373
359
 
374
- async function whoami(args) {
375
- const a = normalizeArgv(args);
376
- assertKnownFlags(a, ["--help", "-h", "--set-name"], ["--set-name"]);
377
- requirePositionalCount(positionalArgs(a, ["--set-name"]), ["--set-name"], { min: 0, max: 0, command: "run402 org whoami" });
378
- const setName = flagValue(a, "--set-name");
379
- if (setName !== null && setName.trim() === "") {
380
- fail({
381
- code: "BAD_USAGE",
382
- message: "--set-name must not be empty.",
383
- details: { field: "--set-name" },
384
- hint: "Pass a 1-64 character display name.",
385
- });
386
- }
387
- try {
388
- // principal-display-name (first-deploy-agent-dx): `--set-name` is the
389
- // explicit setter (PATCH /agent/v1/me); the name is what promotion credit,
390
- // `up`'s room presence, and audit surfaces show for this principal.
391
- const me = setName !== null ? await getSdk().orgs.setDisplayName(setName.trim()) : await getSdk().orgs.whoami();
392
- console.log(JSON.stringify(me, null, 2));
393
- } catch (err) {
394
- reportSdkError(err);
395
- }
396
- }
397
-
398
360
  // ── Current organization (add-cli-current-org) ─────────────────────────────────
399
361
  //
400
362
  // The selection is per WALLET PROFILE, not global: the chain is
@@ -406,7 +368,7 @@ async function use(args) {
406
368
  const a = normalizeArgv(args);
407
369
  assertKnownFlags(a, ["--help", "-h"]);
408
370
  requirePositionalCount(a, [], {
409
- 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>",
410
372
  });
411
373
  const orgId = positionalArgs(a, [])[0];
412
374
  setSelectedOrgId(orgId);
@@ -416,7 +378,7 @@ async function use(args) {
416
378
  async function clear(args) {
417
379
  const a = normalizeArgv(args);
418
380
  assertKnownFlags(a, ["--help", "-h"]);
419
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org clear" });
381
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs clear" });
420
382
  const previous = getSelectedOrgId();
421
383
  clearSelectedOrgId();
422
384
  console.log(JSON.stringify({ org_id: null, selected: false, previous_org_id: previous ?? null }, null, 2));
@@ -449,7 +411,7 @@ async function bind(args) {
449
411
  const a = normalizeArgv(args);
450
412
  const valueFlags = ["--org", "--room"];
451
413
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
452
- 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>]" });
453
415
 
454
416
  let orgId = flagValue(a, "--org");
455
417
  let picked = "flag";
@@ -466,7 +428,7 @@ async function bind(args) {
466
428
  fail({
467
429
  code: "NO_ORGS",
468
430
  message: "This wallet is a member of no organization yet.",
469
- 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'.",
470
432
  next_actions: [nextAction("initialize_wallet", { command: "run402 init", why: "Provision this wallet's organization, then retry." })],
471
433
  });
472
434
  }
@@ -474,9 +436,9 @@ async function bind(args) {
474
436
  fail({
475
437
  code: "AMBIGUOUS_ORG",
476
438
  message: `This wallet belongs to ${rows.length} organizations — name the one to bind.`,
477
- hint: "run402 org bind --org <org_id>",
439
+ hint: "run402 orgs bind --org <org_id>",
478
440
  details: { orgs: rows.map((o) => ({ org_id: o.org_id, display_name: o.display_name ?? null, role: o.role ?? null })) },
479
- 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." })],
480
442
  });
481
443
  }
482
444
  orgId = rows[0].org_id;
@@ -485,7 +447,7 @@ async function bind(args) {
485
447
 
486
448
  const room = flagValue(a, "--room") ?? roomKeyFromDir(process.cwd());
487
449
  const { contents, file } = updateBindingFile(process.cwd(), {
488
- org: requireOrgIdShape(orgId, picked === "flag" ? "--org" : "org list"),
450
+ org: requireOrgIdShape(orgId, picked === "flag" ? "--org" : "orgs list"),
489
451
  ...(room ? { room } : {}),
490
452
  });
491
453
  console.log(JSON.stringify({
@@ -504,7 +466,7 @@ async function bind(args) {
504
466
  async function unbind(args) {
505
467
  const a = normalizeArgv(args);
506
468
  assertKnownFlags(a, ["--help", "-h"]);
507
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org unbind" });
469
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs unbind" });
508
470
  const previous = readBindingFile(process.cwd());
509
471
  const { contents, removed } = updateBindingFile(process.cwd(), { org: null, room: null });
510
472
  console.log(JSON.stringify({
@@ -518,13 +480,13 @@ async function unbind(args) {
518
480
  async function current(args) {
519
481
  const a = normalizeArgv(args);
520
482
  assertKnownFlags(a, ["--help", "-h"]);
521
- requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 org current" });
483
+ requirePositionalCount(a, [], { min: 0, max: 0, command: "run402 orgs current" });
522
484
  try {
523
- // `cmd: "org"` exempts this from the ambiguity error on purpose: the
485
+ // `cmd: "orgs"` exempts this from the ambiguity error on purpose: the
524
486
  // command that reports the selection must stay usable while it is ambiguous.
525
487
  // `optional` keeps an empty selection an explicit null state rather than a
526
488
  // failure — reporting is not acting.
527
- const resolved = await resolveOrg([], { cmd: "org", optional: true });
489
+ const resolved = await resolveOrg([], { cmd: "orgs", optional: true });
528
490
  console.log(JSON.stringify({
529
491
  ...orgProvenance(resolved),
530
492
  selected_org_id: getSelectedOrgId() ?? null,
@@ -537,8 +499,8 @@ async function current(args) {
537
499
  async function get(args) {
538
500
  const a = normalizeArgv(args);
539
501
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
540
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
541
- 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>]" });
542
504
  try {
543
505
  console.log(JSON.stringify(await getSdk().org(org).get(), null, 2));
544
506
  } catch (err) {
@@ -552,11 +514,11 @@ async function rename(args) {
552
514
  const clear = a.includes("--clear");
553
515
  const nameFlag = flagValue(a, "--name");
554
516
  const single = clear || nameFlag !== null;
555
- 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" });
556
518
  requireRest(pos, {
557
519
  min: single ? 0 : 1,
558
520
  max: single ? 0 : 1,
559
- command: "run402 org rename [<org_id>] --name <display_name>",
521
+ command: "run402 orgs rename [<org_id>] --name <display_name>",
560
522
  missing: "Missing <display_name> (use --name, or pass --clear).",
561
523
  });
562
524
  const displayName = clear ? null : (nameFlag ?? pos[0]);
@@ -573,11 +535,11 @@ async function payoutWallet(args) {
573
535
  const clear = a.includes("--clear");
574
536
  const walletFlag = flagValue(a, "--address");
575
537
  const single = clear || walletFlag !== null;
576
- 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" });
577
539
  requireRest(pos, {
578
540
  min: single ? 0 : 1,
579
541
  max: single ? 0 : 1,
580
- command: "run402 org payout-wallet [<org_id>] --address <wallet_address>",
542
+ command: "run402 orgs payout-wallet [<org_id>] --address <wallet_address>",
581
543
  missing: "Missing <wallet_address> (use --address, or pass --clear).",
582
544
  });
583
545
  const walletAddress = clear ? null : (walletFlag ?? pos[0]);
@@ -589,7 +551,7 @@ async function payoutWallet(args) {
589
551
  }
590
552
 
591
553
  /**
592
- * `run402 org slug <slug>` — set or rename the org's address-form slug.
554
+ * `run402 orgs slug <slug>` — set or rename the org's address-form slug.
593
555
  * Owner-only, and a genesis set spends a one-time fee — this is a
594
556
  * PAID, side-effecting mutation, so it
595
557
  * requires `Idempotency-Key`; the SDK generates one client-side when
@@ -597,7 +559,7 @@ async function payoutWallet(args) {
597
559
  * can never double-bill.
598
560
  */
599
561
  /**
600
- * `run402 org adopt` — become the owner of the org your wallet's agent
562
+ * `run402 orgs adopt` — become the owner of the org your wallet's agent
601
563
  * created (an ownership transfer on org memberships; the wallet stays on the
602
564
  * agent, which is downgraded to developer). Dual proof: the write-capable
603
565
  * sign-in session + a fresh signature from the active wallet over a server
@@ -609,7 +571,7 @@ async function adopt(args) {
609
571
  const a = normalizeArgv(args);
610
572
  const valueFlags = ["--org", "--name"];
611
573
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
612
- requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 org adopt [--org <org_id>] [--name <label>]" });
574
+ requirePositionalCount(a, valueFlags, { min: 0, max: 0, command: "run402 orgs adopt [--org <org_id>] [--name <label>]" });
613
575
  const orgId = flagValue(a, "--org");
614
576
  const name = flagValue(a, "--name");
615
577
  try {
@@ -641,7 +603,7 @@ async function adopt(args) {
641
603
  return fail({
642
604
  code: "STEP_UP_REQUIRED",
643
605
  message: "Adopting an org needs a fresh passkey step-up.",
644
- hint: "Run 'run402 login' (a fresh passkey sign-in), then re-run 'run402 org adopt'.",
606
+ hint: "Run 'run402 login' (a fresh passkey sign-in), then re-run 'run402 orgs adopt'.",
645
607
  });
646
608
  }
647
609
  reportSdkError(err);
@@ -655,15 +617,15 @@ async function slug(args) {
655
617
  const [newSlug] = requirePositionalCount(a, valueFlags, {
656
618
  min: 1,
657
619
  max: 1,
658
- command: "run402 org slug <slug> [--org <org_id>]",
620
+ command: "run402 orgs slug <slug> [--org <org_id>]",
659
621
  missing: "Missing <slug>.",
660
622
  });
661
- const org = await resolveOrg(a, { cmd: "org" });
623
+ const org = await resolveOrg(a, { cmd: "orgs" });
662
624
  if (!org) {
663
625
  fail({
664
626
  code: "ORG_UNRESOLVED",
665
627
  message: "Could not resolve which organization to set this slug for.",
666
- hint: "Pass --org <org_id>, or select one first with `run402 org use <id>`.",
628
+ hint: "Pass --org <org_id>, or select one first with `run402 orgs use <org_id>`.",
667
629
  });
668
630
  }
669
631
  const idempotencyKey = flagValue(a, "--idempotency-key");
@@ -689,8 +651,8 @@ async function audit(args) {
689
651
  const a = normalizeArgv(args);
690
652
  const valueFlags = ["--org", "--limit", "--after", "--before"];
691
653
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
692
- const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
693
- 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>]" });
694
656
  const limitFlag = flagValue(a, "--limit");
695
657
  const after = flagValue(a, "--after");
696
658
  const before = flagValue(a, "--before");
@@ -713,19 +675,19 @@ async function runMember(args) {
713
675
  const memberAction = args[0];
714
676
  const rest = args.slice(1);
715
677
  if (!memberAction || memberAction === "--help" || memberAction === "-h") {
716
- console.log(SUB_HELP.member);
678
+ console.log(SUB_HELP.members);
717
679
  process.exit(memberAction ? 0 : 1);
718
680
  }
719
681
  if (rest.includes("--help") || rest.includes("-h")) {
720
- console.log(SUB_HELP.member);
682
+ console.log(SUB_HELP.members);
721
683
  process.exit(0);
722
684
  }
723
685
 
724
686
  if (memberAction === "list") {
725
687
  const a = normalizeArgv(rest);
726
688
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
727
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
728
- 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>]" });
729
691
  try {
730
692
  console.log(JSON.stringify({ members: await getSdk().org(org).members.list() }, null, 2));
731
693
  } catch (err) {
@@ -740,9 +702,9 @@ async function runMember(args) {
740
702
  const role = flagValue(a, "--role");
741
703
  const walletFlag = flagValue(a, "--address");
742
704
  const count = walletFlag ? 0 : 1;
743
- 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" });
744
706
  requireRest(pos, {
745
- 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>]",
746
708
  missing: "Missing <wallet_address> (positional, or --address).",
747
709
  });
748
710
  const wallet = walletFlag ?? pos[0];
@@ -759,7 +721,7 @@ async function runMember(args) {
759
721
  // this org's vaults now have a pending writer candidate (D3: there is
760
722
  // no server-side writer admission — the client holds the keys) via a
761
723
  // `sync_writers` next_action carrying `vault_ids[]`. Run the ACTUAL
762
- // 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
763
725
  // the whole job when the caller can. `reconcile()` is ALREADY a
764
726
  // fast, network-free no-op per vault when this session's own key
765
727
  // isn't a writer there (task 5.7's own `eligible` gate). For a
@@ -807,9 +769,9 @@ async function runMember(args) {
807
769
  const principalFlag = flagValue(a, "--principal");
808
770
  const reason = flagValue(a, "--reason");
809
771
  const count = principalFlag ? 0 : 1;
810
- 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" });
811
773
  requireRest(pos, {
812
- 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>]",
813
775
  missing: "Missing <principal_id> (--principal).",
814
776
  });
815
777
  const principalId = principalFlag ?? pos[0];
@@ -827,9 +789,9 @@ async function runMember(args) {
827
789
  const principalFlag = flagValue(a, "--principal");
828
790
  const roleFlag = flagValue(a, "--role");
829
791
  const count = 2 - (principalFlag ? 1 : 0) - (roleFlag ? 1 : 0);
830
- 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" });
831
793
  requireRest(pos, {
832
- 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>",
833
795
  missing: "Missing <principal_id> (--principal) and/or <role> (--role).",
834
796
  });
835
797
  const principalId = principalFlag ?? pos[0];
@@ -847,9 +809,9 @@ async function runMember(args) {
847
809
  assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
848
810
  const principalFlag = flagValue(a, "--principal");
849
811
  const count = principalFlag ? 0 : 1;
850
- 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" });
851
813
  requireRest(pos, {
852
- 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>",
853
815
  missing: "Missing <principal_id> (use --principal).",
854
816
  });
855
817
  const principalId = principalFlag ?? pos[0];
@@ -878,7 +840,7 @@ async function runMember(args) {
878
840
  return;
879
841
  }
880
842
 
881
- 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.` });
882
844
  }
883
845
 
884
846
  // ── Invite group ─────────────────────────────────────────────────────────────────
@@ -898,8 +860,8 @@ async function runInvite(args) {
898
860
  if (inviteAction === "list") {
899
861
  const a = normalizeArgv(rest);
900
862
  assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
901
- const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
902
- 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>]" });
903
865
  try {
904
866
  console.log(JSON.stringify({ invites: await getSdk().org(org).invites.list() }, null, 2));
905
867
  } catch (err) {
@@ -916,9 +878,9 @@ async function runInvite(args) {
916
878
  const ttlFlag = flagValue(a, "--ttl-hours");
917
879
  const emailFlag = flagValue(a, "--email");
918
880
  const count = emailFlag ? 0 : 1;
919
- const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
881
+ const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "orgs" });
920
882
  requireRest(pos, {
921
- 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>]",
922
884
  missing: "Missing <email> (use --email).",
923
885
  });
924
886
  const email = emailFlag ?? pos[0];
@@ -937,9 +899,9 @@ async function runInvite(args) {
937
899
  assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
938
900
  const principalFlag = flagValue(a, "--principal");
939
901
  const count = principalFlag ? 0 : 1;
940
- 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" });
941
903
  requireRest(pos, {
942
- 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>",
943
905
  missing: "Missing <principal_id> (use --principal).",
944
906
  });
945
907
  const principalId = principalFlag ?? pos[0];
@@ -951,7 +913,7 @@ async function runInvite(args) {
951
913
  return;
952
914
  }
953
915
 
954
- 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.` });
955
917
  }
956
918
 
957
919
  export async function run(sub, args) {
@@ -961,11 +923,11 @@ export async function run(sub, args) {
961
923
  }
962
924
  // Nested groups use `if (sub === ...)` (not `case`) so the sync test extracts
963
925
  // their leaf actions via the dedicated memberAction/inviteAction parsers.
964
- if (sub === "member" || sub === "members") {
926
+ if (sub === "members") {
965
927
  await runMember(args ?? []);
966
928
  return;
967
929
  }
968
- if (sub === "invite" || sub === "invites") {
930
+ if (sub === "invite") {
969
931
  await runInvite(args ?? []);
970
932
  return;
971
933
  }
@@ -981,7 +943,6 @@ export async function run(sub, args) {
981
943
  case "payout-wallet": await payoutWallet(args); break;
982
944
  case "slug": await slug(args); break;
983
945
  case "adopt": await adopt(args); break;
984
- case "whoami": await whoami(args); break;
985
946
  case "use": await use(args); break;
986
947
  case "current": await current(args); break;
987
948
  case "clear": await clear(args); break;
@@ -989,6 +950,6 @@ export async function run(sub, args) {
989
950
  case "unbind": await unbind(args); break;
990
951
  case "audit": await audit(args); break;
991
952
  default:
992
- failUnknownSubcommand("org", sub);
953
+ failUnknownSubcommand("orgs", sub);
993
954
  }
994
955
  }