run402 4.68.3 → 4.69.1
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.
- package/cli.mjs +2 -2
- package/core-dist/allowance-auth.js +1 -1
- package/core-dist/allowance.js +1 -1
- package/core-dist/config.js +4 -4
- package/core-dist/keystore.js +7 -7
- package/core-dist/profiles.js +1 -1
- package/core-dist/redact.js +6 -7
- package/git-remote-run402.mjs +2 -2
- package/gitvault-surface.json +2 -1
- package/lib/agent.mjs +1 -1
- package/lib/allowance.mjs +3 -4
- package/lib/argparse.mjs +7 -9
- package/lib/billing.mjs +33 -35
- package/lib/buzz-notifications.mjs +3 -2
- package/lib/buzz.mjs +14 -8
- package/lib/buzz.test.mjs +1 -1
- package/lib/command-manifest.mjs +38 -20
- package/lib/config.mjs +1 -1
- package/lib/deploy-v2.mjs +3 -3
- package/lib/doctor-source-scan.mjs +1 -1
- package/lib/doctor.mjs +42 -25
- package/lib/email.mjs +2 -3
- package/lib/harness-context.mjs +1 -2
- package/lib/init.mjs +1 -1
- package/lib/next-actions.mjs +1 -1
- package/lib/org-context.mjs +83 -2
- package/lib/org.mjs +231 -114
- package/lib/projects.mjs +2 -2
- package/lib/remote-helper-session.mjs +26 -32
- package/lib/repos.mjs +117 -15
- package/lib/rooms-context.mjs +5 -5
- package/lib/sdk-errors.mjs +1 -2
- package/lib/status.mjs +1 -1
- package/lib/update-check.test.mjs +1 -1
- package/lib/wallet-context.mjs +10 -10
- package/lib/wallet-context.test.mjs +6 -7
- package/lib/wallets.mjs +2 -2
- package/lib/webhooks.mjs +2 -2
- package/package.json +1 -1
- package/sdk/core-dist/allowance-auth.js +1 -1
- package/sdk/core-dist/allowance.js +1 -1
- package/sdk/core-dist/config.js +4 -4
- package/sdk/core-dist/keystore.js +7 -7
- package/sdk/core-dist/profiles.js +1 -1
- package/sdk/core-dist/redact.js +6 -7
- package/sdk/dist/delegate-credentials.d.ts +1 -1
- package/sdk/dist/delegate-credentials.js +1 -1
- package/sdk/dist/errors.d.ts +10 -4
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +2 -3
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/kernel.js +1 -1
- package/sdk/dist/kernel.js.map +1 -1
- package/sdk/dist/namespaces/allowance.d.ts +1 -1
- package/sdk/dist/namespaces/allowance.js +1 -1
- package/sdk/dist/namespaces/allowance.js.map +1 -1
- package/sdk/dist/namespaces/assets.js +1 -1
- package/sdk/dist/namespaces/assets.js.map +1 -1
- package/sdk/dist/namespaces/assets.types.d.ts +1 -1
- package/sdk/dist/namespaces/ci.d.ts.map +1 -1
- package/sdk/dist/namespaces/ci.js +4 -6
- package/sdk/dist/namespaces/ci.js.map +1 -1
- package/sdk/dist/namespaces/deploy.js +7 -8
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/gitvault.crypto.d.ts +86 -3
- package/sdk/dist/namespaces/gitvault.crypto.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.crypto.js +102 -3
- package/sdk/dist/namespaces/gitvault.crypto.js.map +1 -1
- package/sdk/dist/namespaces/gitvault.d.ts +197 -17
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +698 -58
- package/sdk/dist/namespaces/gitvault.js.map +1 -1
- package/sdk/dist/namespaces/gitvault.types.d.ts +91 -3
- package/sdk/dist/namespaces/gitvault.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.types.js.map +1 -1
- package/sdk/dist/namespaces/operator.d.ts +1 -1
- package/sdk/dist/namespaces/operator.js +1 -1
- package/sdk/dist/namespaces/org.d.ts +14 -1
- package/sdk/dist/namespaces/org.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.js +15 -0
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/namespaces/org.types.d.ts +30 -0
- package/sdk/dist/namespaces/org.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.types.d.ts +1 -1
- package/sdk/dist/namespaces/subdomains.js +1 -1
- package/sdk/dist/namespaces/subdomains.js.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts +3 -4
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +1 -2
- package/sdk/dist/namespaces/transfers.js.map +1 -1
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +3 -4
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +2 -2
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
- package/sdk/dist/node/gitvault-address.js +2 -2
- package/sdk/dist/node/gitvault-address.js.map +1 -1
- package/sdk/dist/node/gitvault-creation-journal.d.ts +1 -1
- package/sdk/dist/node/gitvault-creation-journal.js +2 -2
- package/sdk/dist/node/gitvault-creation-journal.js.map +1 -1
- package/sdk/dist/node/gitvault-deploy.d.ts +2 -2
- package/sdk/dist/node/gitvault-deploy.js +2 -2
- package/sdk/dist/node/gitvault-handoff.d.ts +140 -1
- package/sdk/dist/node/gitvault-handoff.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-handoff.js +226 -22
- package/sdk/dist/node/gitvault-handoff.js.map +1 -1
- package/sdk/dist/node/gitvault-keystore.d.ts +78 -3
- package/sdk/dist/node/gitvault-keystore.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-keystore.js +46 -5
- package/sdk/dist/node/gitvault-keystore.js.map +1 -1
- package/sdk/dist/node/gitvault-mirror.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-mirror.js +3 -5
- package/sdk/dist/node/gitvault-mirror.js.map +1 -1
- package/sdk/dist/node/gitvault-profile-scan.js +1 -1
- package/sdk/dist/node/gitvault-publication.d.ts +379 -21
- package/sdk/dist/node/gitvault-publication.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-publication.js +664 -41
- package/sdk/dist/node/gitvault-publication.js.map +1 -1
- package/sdk/dist/node/gitvault-recover.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-recover.js +7 -10
- package/sdk/dist/node/gitvault-recover.js.map +1 -1
- package/sdk/dist/node/gitvault-restore.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-restore.js +5 -2
- package/sdk/dist/node/gitvault-restore.js.map +1 -1
- package/sdk/dist/node/gitvault-snapshot.d.ts +16 -2
- package/sdk/dist/node/gitvault-snapshot.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-snapshot.js +23 -2
- package/sdk/dist/node/gitvault-snapshot.js.map +1 -1
- package/sdk/dist/node/gitvault-writer-state.d.ts +201 -0
- package/sdk/dist/node/gitvault-writer-state.d.ts.map +1 -0
- package/sdk/dist/node/gitvault-writer-state.js +357 -0
- package/sdk/dist/node/gitvault-writer-state.js.map +1 -0
- package/sdk/dist/node/index.d.ts +5 -1
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +21 -2
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
- package/sdk/dist/node/paid-fetch.js +3 -4
- package/sdk/dist/node/paid-fetch.js.map +1 -1
- package/sdk/dist/node/sites-node.js +1 -1
- package/sdk/dist/node/sites-node.js.map +1 -1
package/lib/org.mjs
CHANGED
|
@@ -5,6 +5,8 @@ import { nextAction } from "./next-actions.mjs";
|
|
|
5
5
|
import {
|
|
6
6
|
requireOrgIdShape,
|
|
7
7
|
resolveOrg,
|
|
8
|
+
takeOrgPositional,
|
|
9
|
+
requireRest,
|
|
8
10
|
orgProvenance,
|
|
9
11
|
getSelectedOrgId,
|
|
10
12
|
setSelectedOrgId,
|
|
@@ -27,9 +29,9 @@ const HELP = `run402 org — organizations: create, label, membership, invites
|
|
|
27
29
|
Usage:
|
|
28
30
|
run402 org create [--name <label>]
|
|
29
31
|
run402 org list
|
|
30
|
-
run402 org get <org_id>
|
|
31
|
-
run402 org rename <org_id> --name <display_name> (or: --clear to remove the label)
|
|
32
|
-
run402 org payout-wallet <org_id>
|
|
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)
|
|
33
35
|
run402 org slug <slug> [--org <org_id>]
|
|
34
36
|
run402 org whoami
|
|
35
37
|
run402 org use <org_id>
|
|
@@ -37,17 +39,22 @@ Usage:
|
|
|
37
39
|
run402 org clear
|
|
38
40
|
run402 org bind [--org <org_id>] [--room <key>]
|
|
39
41
|
run402 org unbind
|
|
40
|
-
run402 org audit <org_id> [--limit N] [--after <cursor>] [--before <cursor>]
|
|
41
|
-
run402 org member list <org_id>
|
|
42
|
-
run402 org member add <org_id>
|
|
43
|
-
run402 org member role <org_id> --principal <principal_id> --role <role>
|
|
44
|
-
run402 org member rm <org_id> --principal <principal_id>
|
|
45
|
-
run402 org
|
|
46
|
-
run402 org invite
|
|
47
|
-
run402 org invite
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
|
|
43
|
+
run402 org member list [<org_id>]
|
|
44
|
+
run402 org member add [<org_id>] <wallet_address> [--role <role>]
|
|
45
|
+
run402 org member role [<org_id>] --principal <principal_id> --role <role>
|
|
46
|
+
run402 org member rm [<org_id>] --principal <principal_id>
|
|
47
|
+
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)
|
|
48
|
+
run402 org invite list [<org_id>]
|
|
49
|
+
run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
|
|
50
|
+
run402 org invite rm [<org_id>] --principal <principal_id>
|
|
51
|
+
|
|
52
|
+
<org_id> is optional everywhere: a leading UUID positional addresses that org;
|
|
53
|
+
omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
|
|
54
|
+
binding, then 'run402 org use'. Inside a bound checkout two agents add each
|
|
55
|
+
other with nothing to look up: run402 org member add <wallet_address> --role developer.
|
|
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.
|
|
57
|
+
The second attribute may also be passed positionally (run402 org member add <wallet_address>).
|
|
51
58
|
|
|
52
59
|
Subcommands:
|
|
53
60
|
create Create an empty org on the prototype tier (you become owner)
|
|
@@ -78,14 +85,16 @@ Notes:
|
|
|
78
85
|
Examples:
|
|
79
86
|
run402 org create --name "Kychee"
|
|
80
87
|
run402 org list
|
|
81
|
-
run402 org get
|
|
82
|
-
run402 org
|
|
83
|
-
run402 org rename
|
|
84
|
-
run402 org
|
|
85
|
-
run402 org payout-wallet
|
|
86
|
-
run402 org
|
|
87
|
-
run402 org
|
|
88
|
-
run402 org
|
|
88
|
+
run402 org get # the current org (binding / org use)
|
|
89
|
+
run402 org get 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d
|
|
90
|
+
run402 org rename --name "New Name"
|
|
91
|
+
run402 org rename --clear
|
|
92
|
+
run402 org payout-wallet 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
|
|
93
|
+
run402 org payout-wallet --clear
|
|
94
|
+
run402 org member add 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
|
|
95
|
+
run402 org member add 8f14e45f-ceea-4b7a-9d3c-0b2a6e6f1c2d 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
|
|
96
|
+
run402 org invite create dev@example.com --role developer
|
|
97
|
+
run402 org audit --limit 50
|
|
89
98
|
`;
|
|
90
99
|
|
|
91
100
|
const SUB_HELP = {
|
|
@@ -108,7 +117,7 @@ Usage:
|
|
|
108
117
|
get: `run402 org get — read one org (label + tier/lease + your role)
|
|
109
118
|
|
|
110
119
|
Usage:
|
|
111
|
-
run402 org get <org_id>
|
|
120
|
+
run402 org get [<org_id>]
|
|
112
121
|
|
|
113
122
|
Any active member may read. A non-member (including a guessed id) gets the same
|
|
114
123
|
non-revealing 403.
|
|
@@ -116,11 +125,11 @@ non-revealing 403.
|
|
|
116
125
|
rename: `run402 org rename — set or clear an org's display label (owner-only)
|
|
117
126
|
|
|
118
127
|
Usage:
|
|
119
|
-
run402 org rename <org_id> --name <display_name>
|
|
120
|
-
run402 org rename <org_id> --clear
|
|
128
|
+
run402 org rename [<org_id>] --name <display_name>
|
|
129
|
+
run402 org rename [<org_id>] --clear
|
|
121
130
|
|
|
122
131
|
Legacy (still supported):
|
|
123
|
-
run402 org rename <org_id> <display_name>
|
|
132
|
+
run402 org rename [<org_id>] <display_name>
|
|
124
133
|
|
|
125
134
|
Owner-only + step-up gated. Pass --clear (or an empty display_name) to remove
|
|
126
135
|
the label. Output includes the updated tier and lease timestamps.
|
|
@@ -148,11 +157,11 @@ call after a dropped response can never double-bill.
|
|
|
148
157
|
"payout-wallet": `run402 org payout-wallet — set or clear the tenant route payout wallet
|
|
149
158
|
|
|
150
159
|
Usage:
|
|
151
|
-
run402 org payout-wallet <org_id>
|
|
152
|
-
run402 org payout-wallet <org_id> --clear
|
|
160
|
+
run402 org payout-wallet [<org_id>] <wallet_address>
|
|
161
|
+
run402 org payout-wallet [<org_id>] --clear
|
|
153
162
|
|
|
154
163
|
Legacy (still supported):
|
|
155
|
-
run402 org payout-wallet <org_id> <wallet_address>
|
|
164
|
+
run402 org payout-wallet [<org_id>] <wallet_address>
|
|
156
165
|
|
|
157
166
|
Admin/owner-only + step-up gated. The wallet must already be active and linked
|
|
158
167
|
to the same org. This wallet receives x402 settlement for function web routes
|
|
@@ -174,10 +183,11 @@ for local wallet/profile state use 'run402 status'.
|
|
|
174
183
|
member: `run402 org member — manage org members
|
|
175
184
|
|
|
176
185
|
Usage:
|
|
177
|
-
run402 org member list <org_id>
|
|
178
|
-
run402 org member add <org_id>
|
|
179
|
-
run402 org member role <org_id> --principal <principal_id> --role <role>
|
|
180
|
-
run402 org member rm <org_id> --principal <principal_id>
|
|
186
|
+
run402 org member list [<org_id>]
|
|
187
|
+
run402 org member add [<org_id>] <wallet_address> [--role <role>]
|
|
188
|
+
run402 org member role [<org_id>] --principal <principal_id> --role <role>
|
|
189
|
+
run402 org member rm [<org_id>] --principal <principal_id>
|
|
190
|
+
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)
|
|
181
191
|
|
|
182
192
|
Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
|
|
183
193
|
Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
|
|
@@ -185,12 +195,16 @@ Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
|
|
|
185
195
|
invite: `run402 org invite — manage email invites
|
|
186
196
|
|
|
187
197
|
Usage:
|
|
188
|
-
run402 org invite list <org_id>
|
|
189
|
-
run402 org invite create <org_id> --email <email> [--role <role>] [--ttl-hours N]
|
|
190
|
-
run402 org invite rm <org_id> --principal <principal_id>
|
|
198
|
+
run402 org invite list [<org_id>]
|
|
199
|
+
run402 org invite create [<org_id>] --email <email> [--role <role>] [--ttl-hours N]
|
|
200
|
+
run402 org invite rm [<org_id>] --principal <principal_id>
|
|
191
201
|
|
|
192
|
-
|
|
193
|
-
|
|
202
|
+
<org_id> is optional everywhere: a leading UUID positional addresses that org;
|
|
203
|
+
omit it and the org comes from --org, then RUN402_ORG, then the .run402.json
|
|
204
|
+
binding, then 'run402 org use'. Inside a bound checkout two agents add each
|
|
205
|
+
other with nothing to look up: run402 org member add <wallet_address> --role developer.
|
|
206
|
+
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.
|
|
207
|
+
The second attribute may also be passed positionally (run402 org member add <wallet_address>).
|
|
194
208
|
|
|
195
209
|
An invite is claimed at the recipient's first login. Mutations require an active owner
|
|
196
210
|
(plus step-up when driven by a control-plane session).
|
|
@@ -198,7 +212,7 @@ An invite is claimed at the recipient's first login. Mutations require an active
|
|
|
198
212
|
audit: `run402 org audit — control-plane audit trail
|
|
199
213
|
|
|
200
214
|
Usage:
|
|
201
|
-
run402 org audit <org_id> [--limit N] [--after <cursor>] [--before <cursor>]
|
|
215
|
+
run402 org audit [<org_id>] [--limit N] [--after <cursor>] [--before <cursor>]
|
|
202
216
|
|
|
203
217
|
Requires an admin+ membership on the org. Newest-first. Page forward with --after
|
|
204
218
|
(next_cursor from a prior page); --before is the legacy cursor. Returns
|
|
@@ -208,6 +222,50 @@ Requires an admin+ membership on the org. Newest-first. Page forward with --afte
|
|
|
208
222
|
|
|
209
223
|
// ── Top-level: create / list / get / rename / whoami / audit ────────────────────
|
|
210
224
|
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* gitvault-multi-writer (rev 47) task 6.3 / design D3 — decided 2026-09-03
|
|
228
|
+
* (Tal): `org member add` REFUSES a writer-eligible add (developer or
|
|
229
|
+
* above) when this session's own key is not an admitted writer on EVERY
|
|
230
|
+
* vault of the org, because a developer who cannot push is not the member
|
|
231
|
+
* the caller meant, and a half-usable membership is exactly the silent
|
|
232
|
+
* failure the multi-writer change exists to end. No warn path, no escape
|
|
233
|
+
* flag: the fix is for a current writer of the named vault(s) to admit this
|
|
234
|
+
* key (`run402 repos access sync`, or any push) and re-run — or to run
|
|
235
|
+
* the add themselves. Viewer/billing adds never reach this gate; an org
|
|
236
|
+
* with no vaults has nothing to admit; a vault in the read-only terminal
|
|
237
|
+
* state (its last writer gone) is skipped, since nobody can admit there.
|
|
238
|
+
* Every read failure REFUSES too (an unverifiable gate is not a passed one).
|
|
239
|
+
*/
|
|
240
|
+
async function assertCallerCanAdmitWritersEverywhere(sdk, orgId, effectiveRole) {
|
|
241
|
+
const listing = await sdk.gitvault.listByOrg(orgId);
|
|
242
|
+
const vaults = listing?.vaults ?? [];
|
|
243
|
+
const blocked = [];
|
|
244
|
+
for (const v of vaults) {
|
|
245
|
+
const st = await sdk.gitvault.status({ repo_id: v.repo_id, reconcile: "forbidden" });
|
|
246
|
+
const vault = st?.vault ?? null;
|
|
247
|
+
if (!vault || vault.read_only_terminal) continue;
|
|
248
|
+
const me = st?.keystore?.identity_fingerprint ?? null;
|
|
249
|
+
const writers = vault.writer_set?.writers ?? [];
|
|
250
|
+
if (!me || !writers.some((w) => w.writer_key_id === me)) blocked.push({ repo_id: v.repo_id, repo_name: v.repo_name ?? null, project_id: v.project_id ?? null });
|
|
251
|
+
}
|
|
252
|
+
if (blocked.length > 0) {
|
|
253
|
+
fail({
|
|
254
|
+
code: "GITVAULT_WRITER_NOT_ADMITTED",
|
|
255
|
+
message: `refusing to add a ${effectiveRole}: this session's key is not an admitted writer on ${blocked.length} of this org's ${vaults.length} vault(s), so the new member could not push there`,
|
|
256
|
+
details: { role: effectiveRole, vaults: blocked, checked: vaults.length },
|
|
257
|
+
next_actions: [
|
|
258
|
+
{
|
|
259
|
+
type: "request_writer_sync",
|
|
260
|
+
why: "A current writer of the named vault(s) admits YOUR key by running `run402 repos access sync` there (any push does it too); then re-run this command — or have that writer run it.",
|
|
261
|
+
safe_to_auto_execute: false,
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return { checked: vaults.length };
|
|
267
|
+
}
|
|
268
|
+
|
|
211
269
|
async function create(args) {
|
|
212
270
|
const a = normalizeArgv(args);
|
|
213
271
|
const valueFlags = ["--name"];
|
|
@@ -384,10 +442,9 @@ async function current(args) {
|
|
|
384
442
|
|
|
385
443
|
async function get(args) {
|
|
386
444
|
const a = normalizeArgv(args);
|
|
387
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
});
|
|
445
|
+
assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
|
|
446
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
|
|
447
|
+
requireRest(pos, { max: 0, command: "run402 org get [<org_id>]" });
|
|
391
448
|
try {
|
|
392
449
|
console.log(JSON.stringify(await getSdk().org(org).get(), null, 2));
|
|
393
450
|
} catch (err) {
|
|
@@ -397,18 +454,18 @@ async function get(args) {
|
|
|
397
454
|
|
|
398
455
|
async function rename(args) {
|
|
399
456
|
const a = normalizeArgv(args);
|
|
400
|
-
assertKnownFlags(a, ["--name", "--clear", "--help", "-h"], ["--name"]);
|
|
457
|
+
assertKnownFlags(a, ["--org", "--name", "--clear", "--help", "-h"], ["--org", "--name"]);
|
|
401
458
|
const clear = a.includes("--clear");
|
|
402
459
|
const nameFlag = flagValue(a, "--name");
|
|
403
460
|
const single = clear || nameFlag !== null;
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
461
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--name"], { cmd: "org" });
|
|
462
|
+
requireRest(pos, {
|
|
463
|
+
min: single ? 0 : 1,
|
|
464
|
+
max: single ? 0 : 1,
|
|
465
|
+
command: "run402 org rename [<org_id>] --name <display_name>",
|
|
466
|
+
missing: "Missing <display_name> (use --name, or pass --clear).",
|
|
409
467
|
});
|
|
410
|
-
const
|
|
411
|
-
const displayName = clear ? null : (nameFlag ?? positionals[1]);
|
|
468
|
+
const displayName = clear ? null : (nameFlag ?? pos[0]);
|
|
412
469
|
try {
|
|
413
470
|
console.log(JSON.stringify(await getSdk().org(org).rename(displayName), null, 2));
|
|
414
471
|
} catch (err) {
|
|
@@ -418,18 +475,18 @@ async function rename(args) {
|
|
|
418
475
|
|
|
419
476
|
async function payoutWallet(args) {
|
|
420
477
|
const a = normalizeArgv(args);
|
|
421
|
-
assertKnownFlags(a, ["--
|
|
478
|
+
assertKnownFlags(a, ["--org", "--address", "--clear", "--help", "-h"], ["--org", "--address"]);
|
|
422
479
|
const clear = a.includes("--clear");
|
|
423
|
-
const walletFlag = flagValue(a, "--
|
|
480
|
+
const walletFlag = flagValue(a, "--address");
|
|
424
481
|
const single = clear || walletFlag !== null;
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
482
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--address"], { cmd: "org" });
|
|
483
|
+
requireRest(pos, {
|
|
484
|
+
min: single ? 0 : 1,
|
|
485
|
+
max: single ? 0 : 1,
|
|
486
|
+
command: "run402 org payout-wallet [<org_id>] --address <wallet_address>",
|
|
487
|
+
missing: "Missing <wallet_address> (use --address, or pass --clear).",
|
|
430
488
|
});
|
|
431
|
-
const
|
|
432
|
-
const walletAddress = clear ? null : (walletFlag ?? positionals[1]);
|
|
489
|
+
const walletAddress = clear ? null : (walletFlag ?? pos[0]);
|
|
433
490
|
try {
|
|
434
491
|
console.log(JSON.stringify(await getSdk().org(org).setPayoutWallet({ walletAddress }), null, 2));
|
|
435
492
|
} catch (err) {
|
|
@@ -484,14 +541,10 @@ async function slug(args) {
|
|
|
484
541
|
|
|
485
542
|
async function audit(args) {
|
|
486
543
|
const a = normalizeArgv(args);
|
|
487
|
-
const valueFlags = ["--limit", "--after", "--before"];
|
|
544
|
+
const valueFlags = ["--org", "--limit", "--after", "--before"];
|
|
488
545
|
assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
max: 1,
|
|
492
|
-
command: "run402 org audit <org_id>",
|
|
493
|
-
missing: "Missing <org_id>.",
|
|
494
|
-
});
|
|
546
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
|
|
547
|
+
requireRest(pos, { max: 0, command: "run402 org audit [<org_id>]" });
|
|
495
548
|
const limitFlag = flagValue(a, "--limit");
|
|
496
549
|
const after = flagValue(a, "--after");
|
|
497
550
|
const before = flagValue(a, "--before");
|
|
@@ -524,10 +577,9 @@ async function runMember(args) {
|
|
|
524
577
|
|
|
525
578
|
if (memberAction === "list") {
|
|
526
579
|
const a = normalizeArgv(rest);
|
|
527
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
});
|
|
580
|
+
assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
|
|
581
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
|
|
582
|
+
requireRest(pos, { max: 0, command: "run402 org member list [<org_id>]" });
|
|
531
583
|
try {
|
|
532
584
|
console.log(JSON.stringify({ members: await getSdk().org(org).members.list() }, null, 2));
|
|
533
585
|
} catch (err) {
|
|
@@ -538,19 +590,85 @@ async function runMember(args) {
|
|
|
538
590
|
|
|
539
591
|
if (memberAction === "add") {
|
|
540
592
|
const a = normalizeArgv(rest);
|
|
541
|
-
assertKnownFlags(a, ["--role", "--
|
|
593
|
+
assertKnownFlags(a, ["--org", "--role", "--address", "--help", "-h"], ["--org", "--role", "--address"]);
|
|
542
594
|
const role = flagValue(a, "--role");
|
|
543
|
-
const walletFlag = flagValue(a, "--
|
|
544
|
-
const count = walletFlag ?
|
|
545
|
-
const pos =
|
|
546
|
-
|
|
547
|
-
|
|
595
|
+
const walletFlag = flagValue(a, "--address");
|
|
596
|
+
const count = walletFlag ? 0 : 1;
|
|
597
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--role", "--address"], { cmd: "org" });
|
|
598
|
+
requireRest(pos, {
|
|
599
|
+
min: count, max: count, command: "run402 org member add [<org_id>] <wallet_address> [--role <role>]",
|
|
600
|
+
missing: "Missing <wallet_address> (positional, or --address).",
|
|
548
601
|
});
|
|
549
|
-
const
|
|
550
|
-
const wallet = walletFlag ?? pos[1];
|
|
602
|
+
const wallet = walletFlag ?? pos[0];
|
|
551
603
|
try {
|
|
552
|
-
const
|
|
553
|
-
|
|
604
|
+
const sdk = getSdk();
|
|
605
|
+
// The gateway's own default role for a wallet add is developer — a
|
|
606
|
+
// writer-eligible role — so an add with no --role is gated too.
|
|
607
|
+
const effectiveRole = role || "developer";
|
|
608
|
+
if (["owner", "admin", "developer"].includes(effectiveRole)) {
|
|
609
|
+
await assertCallerCanAdmitWritersEverywhere(sdk, org, effectiveRole);
|
|
610
|
+
}
|
|
611
|
+
const res = await sdk.org(org).members.add({ wallet, role: role || undefined });
|
|
612
|
+
// gitvault-multi-writer (rev 47) task 6.3 — the gateway names which of
|
|
613
|
+
// this org's vaults now have a pending writer candidate (D3: there is
|
|
614
|
+
// no server-side writer admission — the client holds the keys) via a
|
|
615
|
+
// `sync_writers` next_action carrying `vault_ids[]`. Run the ACTUAL
|
|
616
|
+
// reconcile against each one now, so a single `org member add` finishes
|
|
617
|
+
// the whole job when the caller can. `reconcile()` is ALREADY a
|
|
618
|
+
// fast, network-free no-op per vault when this session's own key
|
|
619
|
+
// isn't a writer there (task 5.7's own `eligible` gate). For a
|
|
620
|
+
// writer-eligible add the gate above already proved this session IS
|
|
621
|
+
// a writer on every vault, so `not_eligible` here can only name a
|
|
622
|
+
// vault that changed under us in the meantime — reported, never
|
|
623
|
+
// silently dropped.
|
|
624
|
+
const syncTarget = res.next_actions?.find((n) => n?.type === "sync_writers");
|
|
625
|
+
let writerSync = null;
|
|
626
|
+
if (syncTarget?.vault_ids?.length > 0) {
|
|
627
|
+
const admitted = [];
|
|
628
|
+
const notEligible = [];
|
|
629
|
+
const errors = [];
|
|
630
|
+
for (const vaultId of syncTarget.vault_ids) {
|
|
631
|
+
try {
|
|
632
|
+
const r = await sdk.gitvault.reconcile({ repo_id: vaultId });
|
|
633
|
+
if (!r.eligible) notEligible.push(vaultId);
|
|
634
|
+
else if (r.admitted.length > 0) admitted.push({ repo_id: vaultId, admitted: r.admitted });
|
|
635
|
+
} catch (err) {
|
|
636
|
+
errors.push({ repo_id: vaultId, error: err?.message ?? String(err) });
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
writerSync = { attempted: syncTarget.vault_ids.length, admitted, not_eligible: notEligible, errors };
|
|
640
|
+
}
|
|
641
|
+
console.log(JSON.stringify(writerSync ? { ...res, writer_sync: writerSync } : res, null, 2));
|
|
642
|
+
if (writerSync?.not_eligible.length > 0) {
|
|
643
|
+
console.error(`writer sync: this session is not (yet) a writer on ${writerSync.not_eligible.length} vault(s) — the new member is a pending writer candidate there until a CURRENT writer's next gitvault operation admits them.`);
|
|
644
|
+
}
|
|
645
|
+
if (writerSync?.errors.length > 0) {
|
|
646
|
+
for (const e of writerSync.errors) console.error(`writer sync: ${e.repo_id} — ${e.error}`);
|
|
647
|
+
}
|
|
648
|
+
} catch (err) {
|
|
649
|
+
reportSdkError(err);
|
|
650
|
+
}
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (memberAction === "revoke-key") {
|
|
655
|
+
// gitvault-agent-envelopes D3: owner + step-up revokes a member's current
|
|
656
|
+
// gitvault encryption key — the ONLY rotation path for a member that shares
|
|
657
|
+
// an org with another custodian (a lost/rebuilt keystore fails
|
|
658
|
+
// GITVAULT_KEY_ROTATION_REQUIRED and points here). Adapter only.
|
|
659
|
+
const a = normalizeArgv(rest);
|
|
660
|
+
assertKnownFlags(a, ["--org", "--principal", "--reason", "--help", "-h"], ["--org", "--principal", "--reason"]);
|
|
661
|
+
const principalFlag = flagValue(a, "--principal");
|
|
662
|
+
const reason = flagValue(a, "--reason");
|
|
663
|
+
const count = principalFlag ? 0 : 1;
|
|
664
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--reason"], { cmd: "org" });
|
|
665
|
+
requireRest(pos, {
|
|
666
|
+
min: count, max: count, command: "run402 org member revoke-key [<org_id>] --principal <principal_id> [--reason <why>]",
|
|
667
|
+
missing: "Missing <principal_id> (--principal).",
|
|
668
|
+
});
|
|
669
|
+
const principalId = principalFlag ?? pos[0];
|
|
670
|
+
try {
|
|
671
|
+
console.log(JSON.stringify(await getSdk().org(org).members.revokeEncryptionKey(principalId, reason ? { reason } : {}), null, 2));
|
|
554
672
|
} catch (err) {
|
|
555
673
|
reportSdkError(err);
|
|
556
674
|
}
|
|
@@ -559,17 +677,17 @@ async function runMember(args) {
|
|
|
559
677
|
|
|
560
678
|
if (memberAction === "role") {
|
|
561
679
|
const a = normalizeArgv(rest);
|
|
562
|
-
assertKnownFlags(a, ["--principal", "--role", "--help", "-h"], ["--principal", "--role"]);
|
|
680
|
+
assertKnownFlags(a, ["--org", "--principal", "--role", "--help", "-h"], ["--org", "--principal", "--role"]);
|
|
563
681
|
const principalFlag = flagValue(a, "--principal");
|
|
564
682
|
const roleFlag = flagValue(a, "--role");
|
|
565
|
-
const count =
|
|
566
|
-
const pos =
|
|
567
|
-
|
|
568
|
-
|
|
683
|
+
const count = 2 - (principalFlag ? 1 : 0) - (roleFlag ? 1 : 0);
|
|
684
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal", "--role"], { cmd: "org" });
|
|
685
|
+
requireRest(pos, {
|
|
686
|
+
min: count, max: count, command: "run402 org member role [<org_id>] --principal <principal_id> --role <role>",
|
|
687
|
+
missing: "Missing <principal_id> (--principal) and/or <role> (--role).",
|
|
569
688
|
});
|
|
570
|
-
const
|
|
571
|
-
const
|
|
572
|
-
const role = roleFlag ?? (principalFlag ? pos[1] : pos[2]);
|
|
689
|
+
const principalId = principalFlag ?? pos[0];
|
|
690
|
+
const role = roleFlag ?? (principalFlag ? pos[0] : pos[1]);
|
|
573
691
|
try {
|
|
574
692
|
console.log(JSON.stringify(await getSdk().org(org).members.setRole(principalId, { role }), null, 2));
|
|
575
693
|
} catch (err) {
|
|
@@ -580,15 +698,15 @@ async function runMember(args) {
|
|
|
580
698
|
|
|
581
699
|
if (memberAction === "rm") {
|
|
582
700
|
const a = normalizeArgv(rest);
|
|
583
|
-
assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
|
|
701
|
+
assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
|
|
584
702
|
const principalFlag = flagValue(a, "--principal");
|
|
585
|
-
const count = principalFlag ?
|
|
586
|
-
const pos =
|
|
587
|
-
|
|
588
|
-
|
|
703
|
+
const count = principalFlag ? 0 : 1;
|
|
704
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "org" });
|
|
705
|
+
requireRest(pos, {
|
|
706
|
+
min: count, max: count, command: "run402 org member rm [<org_id>] --principal <principal_id>",
|
|
707
|
+
missing: "Missing <principal_id> (use --principal).",
|
|
589
708
|
});
|
|
590
|
-
const
|
|
591
|
-
const principalId = principalFlag ?? pos[1];
|
|
709
|
+
const principalId = principalFlag ?? pos[0];
|
|
592
710
|
try {
|
|
593
711
|
console.log(JSON.stringify(await getSdk().org(org).members.revoke(principalId), null, 2));
|
|
594
712
|
} catch (err) {
|
|
@@ -616,10 +734,9 @@ async function runInvite(args) {
|
|
|
616
734
|
|
|
617
735
|
if (inviteAction === "list") {
|
|
618
736
|
const a = normalizeArgv(rest);
|
|
619
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
});
|
|
737
|
+
assertKnownFlags(a, ["--org", "--help", "-h"], ["--org"]);
|
|
738
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org"], { cmd: "org" });
|
|
739
|
+
requireRest(pos, { max: 0, command: "run402 org invite list [<org_id>]" });
|
|
623
740
|
try {
|
|
624
741
|
console.log(JSON.stringify({ invites: await getSdk().org(org).invites.list() }, null, 2));
|
|
625
742
|
} catch (err) {
|
|
@@ -630,18 +747,18 @@ async function runInvite(args) {
|
|
|
630
747
|
|
|
631
748
|
if (inviteAction === "create") {
|
|
632
749
|
const a = normalizeArgv(rest);
|
|
633
|
-
const valueFlags = ["--role", "--ttl-hours", "--email"];
|
|
750
|
+
const valueFlags = ["--org", "--role", "--ttl-hours", "--email"];
|
|
634
751
|
assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
|
|
635
752
|
const role = flagValue(a, "--role");
|
|
636
753
|
const ttlFlag = flagValue(a, "--ttl-hours");
|
|
637
754
|
const emailFlag = flagValue(a, "--email");
|
|
638
|
-
const count = emailFlag ?
|
|
639
|
-
const pos =
|
|
640
|
-
|
|
641
|
-
|
|
755
|
+
const count = emailFlag ? 0 : 1;
|
|
756
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, valueFlags, { cmd: "org" });
|
|
757
|
+
requireRest(pos, {
|
|
758
|
+
min: count, max: count, command: "run402 org invite create [<org_id>] --email <email> [--role <role>]",
|
|
759
|
+
missing: "Missing <email> (use --email).",
|
|
642
760
|
});
|
|
643
|
-
const
|
|
644
|
-
const email = emailFlag ?? pos[1];
|
|
761
|
+
const email = emailFlag ?? pos[0];
|
|
645
762
|
const inviteTtlHours = ttlFlag === null ? undefined : parseIntegerFlag("--ttl-hours", ttlFlag, { min: 1, max: 8760 });
|
|
646
763
|
try {
|
|
647
764
|
const res = await getSdk().org(org).invites.create({ email, role: role || "developer", inviteTtlHours });
|
|
@@ -654,15 +771,15 @@ async function runInvite(args) {
|
|
|
654
771
|
|
|
655
772
|
if (inviteAction === "rm") {
|
|
656
773
|
const a = normalizeArgv(rest);
|
|
657
|
-
assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
|
|
774
|
+
assertKnownFlags(a, ["--org", "--principal", "--help", "-h"], ["--org", "--principal"]);
|
|
658
775
|
const principalFlag = flagValue(a, "--principal");
|
|
659
|
-
const count = principalFlag ?
|
|
660
|
-
const pos =
|
|
661
|
-
|
|
662
|
-
|
|
776
|
+
const count = principalFlag ? 0 : 1;
|
|
777
|
+
const { orgId: org, rest: pos } = await takeOrgPositional(a, ["--org", "--principal"], { cmd: "org" });
|
|
778
|
+
requireRest(pos, {
|
|
779
|
+
min: count, max: count, command: "run402 org invite rm [<org_id>] --principal <principal_id>",
|
|
780
|
+
missing: "Missing <principal_id> (use --principal).",
|
|
663
781
|
});
|
|
664
|
-
const
|
|
665
|
-
const principalId = principalFlag ?? pos[1];
|
|
782
|
+
const principalId = principalFlag ?? pos[0];
|
|
666
783
|
try {
|
|
667
784
|
console.log(JSON.stringify(await getSdk().org(org).invites.revoke(principalId), null, 2));
|
|
668
785
|
} catch (err) {
|
package/lib/projects.mjs
CHANGED
|
@@ -319,7 +319,7 @@ async function provision(args) {
|
|
|
319
319
|
for (let i = 0; i < args.length; i++) {
|
|
320
320
|
if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
|
|
321
321
|
// Use !== undefined so an empty-string value is captured (and rejected
|
|
322
|
-
// below) rather than silently dropped by the falsy-check pattern
|
|
322
|
+
// below) rather than silently dropped by the falsy-check pattern.
|
|
323
323
|
if (args[i] === "--name" && args[i + 1] !== undefined) opts.name = args[++i];
|
|
324
324
|
// --org targets an EXISTING org (v1.82); caller needs developer+ on it.
|
|
325
325
|
// Omitted = cold-start. Tier is org-governed, so --tier is irrelevant here
|
|
@@ -345,7 +345,7 @@ async function provision(args) {
|
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
347
|
// Validate --name when provided. Omitted --name lets the server pick a
|
|
348
|
-
// default. The same envelope should also be enforced server-side
|
|
348
|
+
// default. The same envelope should also be enforced server-side.
|
|
349
349
|
if (opts.name !== undefined) {
|
|
350
350
|
if (opts.name === "") {
|
|
351
351
|
fail({
|