run402 4.68.3 → 4.69.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.
- 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-snapshot.d.ts +1 -2
- package/sdk/dist/node/gitvault-snapshot.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-snapshot.js +1 -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 +4 -0
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +20 -1
- 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/cli.mjs
CHANGED
|
@@ -533,8 +533,8 @@ switch (cmd) {
|
|
|
533
533
|
]);
|
|
534
534
|
const closest = typeof cmd === "string" ? closestWord(cmd, [...families]) : null;
|
|
535
535
|
// `cmd` is the first bare positional — could be anything a script passes
|
|
536
|
-
// by mistake
|
|
537
|
-
//
|
|
536
|
+
// by mistake, and a secret is a demonstrated risk for this shape of
|
|
537
|
+
// value, so it must not be echoed verbatim.
|
|
538
538
|
const shownCmd = describeRejectedValue(cmd);
|
|
539
539
|
fail({
|
|
540
540
|
code: "UNKNOWN_COMMAND",
|
|
@@ -115,7 +115,7 @@ export function buildSIWxAuthHeaders(opts) {
|
|
|
115
115
|
* @param path - API path (e.g. "/projects/v1") used to build the SIWE uri field.
|
|
116
116
|
*/
|
|
117
117
|
export function getAllowanceAuthHeaders(path, allowancePath) {
|
|
118
|
-
//
|
|
118
|
+
// readAllowance throws on a malformed-shape allowance file. The
|
|
119
119
|
// CLI's higher-level readAllowance wrapper surfaces this as a structured
|
|
120
120
|
// BAD_ALLOWANCE_FILE envelope; here we preserve the public contract that
|
|
121
121
|
// this helper returns SIWxAuthHeaders | null. Re-throw so callers above
|
package/core-dist/allowance.js
CHANGED
|
@@ -14,7 +14,7 @@ const PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
|
14
14
|
* - the file exists but is not parseable JSON (preserve existing UX —
|
|
15
15
|
* consumers print "no_allowance" and tell the user to run init)
|
|
16
16
|
*
|
|
17
|
-
* Throws a structured `Error`
|
|
17
|
+
* Throws a structured `Error` when the file parses as JSON but the
|
|
18
18
|
* shape is wrong (missing/wrong-type/wrong-length fields). Without this guard
|
|
19
19
|
* downstream callers crash with raw stack traces:
|
|
20
20
|
* - `cli/lib/status.mjs` reaches for `allowance.address.toLowerCase()`
|
package/core-dist/config.js
CHANGED
|
@@ -83,10 +83,10 @@ function assertSafeProfileName(name) {
|
|
|
83
83
|
return;
|
|
84
84
|
if (!isValidProfileName(name)) {
|
|
85
85
|
// A value that failed this check is a value we know nothing about — the
|
|
86
|
-
// most likely mistake is a typo, but
|
|
87
|
-
//
|
|
88
|
-
// the raw value
|
|
89
|
-
//
|
|
86
|
+
// most likely mistake is a typo, but a Base-mainnet private key pasted
|
|
87
|
+
// into RUN402_WALLET (a NAME field) is a demonstrated case, and echoing
|
|
88
|
+
// the raw value propagates it into terminals, logs, and session
|
|
89
|
+
// transcripts.
|
|
90
90
|
// describeRejectedValue() shows short/plain values in full (useful for
|
|
91
91
|
// an actual typo) and redacts anything long or hex-shaped enough to be
|
|
92
92
|
// a secret instead of a name.
|
package/core-dist/keystore.js
CHANGED
|
@@ -190,15 +190,15 @@ export function removeProject(projectId, path) {
|
|
|
190
190
|
* bucket, not "unknown") and PERMANENTLY shadows every later wallet-scoped
|
|
191
191
|
* activation for every caller that reads through this module: `resolveProjectId`
|
|
192
192
|
* / `resolveProject` (cli/lib/config.mjs), `projects current`, and every
|
|
193
|
-
* gitvault-verb target resolution.
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
193
|
+
* gitvault-verb target resolution. The failure it causes: `repos create`
|
|
194
|
+
* calls `projects.provision`, whose `creds.setActiveProject` correctly
|
|
195
|
+
* persists the new project under the real wallet's scoped bucket AND the
|
|
196
|
+
* flat fallback, yet every CLI read of "the active project" resolves the
|
|
197
|
+
* stale "unknown"-bucket entry first and never falls through to the
|
|
198
|
+
* freshly-updated flat value.
|
|
199
199
|
*
|
|
200
200
|
* Best-effort: an unreadable/malformed allowance degrades to `null` (the
|
|
201
|
-
*
|
|
201
|
+
* "unknown" bucket callers tolerate), never a
|
|
202
202
|
* throw — this is a read-scoping concern, not an allowance-validity one.
|
|
203
203
|
*/
|
|
204
204
|
function currentPrincipal() {
|
package/core-dist/profiles.js
CHANGED
|
@@ -154,7 +154,7 @@ export function removeProfile(name) {
|
|
|
154
154
|
*/
|
|
155
155
|
export function renameProfile(oldName, newName) {
|
|
156
156
|
if (!isValidProfileName(newName)) {
|
|
157
|
-
// See describeRejectedValue()'s doc comment
|
|
157
|
+
// See describeRejectedValue()'s doc comment:
|
|
158
158
|
// a rejected value may be a secret pasted into a name field, so it is
|
|
159
159
|
// never safe to echo verbatim here.
|
|
160
160
|
throw new Error(`Invalid wallet name ${JSON.stringify(describeRejectedValue(newName))}.`);
|
package/core-dist/redact.js
CHANGED
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
* A value rejected by a format/existence check is a value we know nothing
|
|
5
5
|
* about — the CLI has only established what it is NOT. The likeliest
|
|
6
6
|
* failure is an ordinary typo, but the second likeliest, demonstrated in
|
|
7
|
-
* practice, is a credential pasted into the wrong slot:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* a session transcript.
|
|
7
|
+
* practice, is a credential pasted into the wrong slot: a Base-mainnet
|
|
8
|
+
* private key holding real funds lands in `RUN402_WALLET` (which takes a
|
|
9
|
+
* wallet NAME, not a key), fails the name check, and is printed verbatim to
|
|
10
|
+
* a terminal, a log, and a session transcript.
|
|
12
11
|
*
|
|
13
12
|
* `describeRejectedValue` is the one place that decides what a rejected
|
|
14
13
|
* value is safe to show, so every call site — wallet names, org ids, room
|
|
@@ -35,11 +34,11 @@
|
|
|
35
34
|
// canonical shape of an org id, and *itself* a public, harmless-to-echo
|
|
36
35
|
// identifier even when it's the "wrong" one in a conflict, not a secret).
|
|
37
36
|
// Secrets that land in the wrong slot (private keys, API tokens, JWTs) are
|
|
38
|
-
// almost always well past it —
|
|
37
|
+
// almost always well past it — a private key runs 64-66 characters.
|
|
39
38
|
const MAX_SAFE_ECHO_LENGTH = 40;
|
|
40
39
|
// A contiguous hex run (with or without a `0x` prefix) reads as key
|
|
41
40
|
// material or a hash rather than a human-typed identifier, even when short
|
|
42
|
-
// enough to pass the length check above
|
|
41
|
+
// enough to pass the length check above.
|
|
43
42
|
const HEX_RUN_RE = /^(0x)?[0-9a-fA-F]{16,}$/;
|
|
44
43
|
function looksSecretShaped(str) {
|
|
45
44
|
return str.length > MAX_SAFE_ECHO_LENGTH || HEX_RUN_RE.test(str);
|
package/git-remote-run402.mjs
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
* builtins + `./lib/daemon-path.mjs` only, pinned by a source-level
|
|
21
21
|
* gate test (design D7). The heavy graph loads only on fallback.
|
|
22
22
|
* - `RUN402_DAEMON=0` disables the daemon entirely (dev/CI toggle,
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* positively named, default on, only "0" disables); any other value
|
|
24
|
+
* behaves as unset.
|
|
25
25
|
*
|
|
26
26
|
* The remote-helper doctrine (fail-closed repository resolution, wallet
|
|
27
27
|
* selection, protocol semantics) lives with the session implementation in
|
package/gitvault-surface.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"surface_version": "4.
|
|
2
|
+
"surface_version": "4.69.0",
|
|
3
3
|
"verbs": [
|
|
4
4
|
"repos create",
|
|
5
5
|
"repos list",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"repos access repair",
|
|
18
18
|
"repos access revoke-key",
|
|
19
19
|
"repos access declare-exposure",
|
|
20
|
+
"repos access sync",
|
|
20
21
|
"repos recover",
|
|
21
22
|
"repos recovery-bundle"
|
|
22
23
|
],
|
package/lib/agent.mjs
CHANGED
|
@@ -93,7 +93,7 @@ async function contact(args) {
|
|
|
93
93
|
if (!name) {
|
|
94
94
|
fail({ code: "BAD_USAGE", message: "Missing --name <name>" });
|
|
95
95
|
}
|
|
96
|
-
//
|
|
96
|
+
// validate webhook scheme locally BEFORE the allowance check so
|
|
97
97
|
// bad URLs fail fast even without an allowance configured. No-op when
|
|
98
98
|
// --webhook is omitted (it's optional).
|
|
99
99
|
validateWebhookUrl(webhook, "--webhook");
|
package/lib/allowance.mjs
CHANGED
|
@@ -92,10 +92,9 @@ async function status() {
|
|
|
92
92
|
address: data.address,
|
|
93
93
|
created: data.created,
|
|
94
94
|
configured: data.configured,
|
|
95
|
-
//
|
|
96
|
-
// faucet invocation, not
|
|
97
|
-
//
|
|
98
|
-
// now" check, use `run402 allowance balance`.
|
|
95
|
+
// `faucet_used` is named for what it is: an on-disk marker that
|
|
96
|
+
// tracks faucet invocation, not pay-readiness. For a true "can this
|
|
97
|
+
// account pay right now" check, use `run402 allowance balance`.
|
|
99
98
|
faucet_used: !!data.faucet_used,
|
|
100
99
|
rail: w?.rail || "x402",
|
|
101
100
|
path: data.path ?? allowanceFile(),
|
package/lib/argparse.mjs
CHANGED
|
@@ -141,9 +141,8 @@ export function validateEvmAddress(value, fieldName = "address") {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
// A rejected positional could be anything the caller typed or piped in
|
|
145
|
-
// core-dist/redact.js's doc comment
|
|
146
|
-
// is never safe to echo verbatim.
|
|
144
|
+
// A rejected positional could be anything the caller typed or piped in (see
|
|
145
|
+
// core-dist/redact.js's doc comment), so it is never safe to echo verbatim.
|
|
147
146
|
export function failBadProjectId(value) {
|
|
148
147
|
fail({
|
|
149
148
|
code: "BAD_PROJECT_ID",
|
|
@@ -156,7 +155,7 @@ export function failBadProjectId(value) {
|
|
|
156
155
|
/**
|
|
157
156
|
* Validate a webhook URL: parse it locally and reject non-https:// schemes.
|
|
158
157
|
*
|
|
159
|
-
* Scope
|
|
158
|
+
* Scope: scheme-only validation. Reject `javascript:`, `file:`,
|
|
160
159
|
* `http:`, `data:`, `ftp:`, etc. before the request leaves the CLI process.
|
|
161
160
|
* Server-side SSRF defenses (private-IP filtering, DNS rebinding, IMDS
|
|
162
161
|
* blocking) live on the gateway, not here — this helper is the cheap
|
|
@@ -198,9 +197,8 @@ export function validateWebhookUrl(url, fieldName = "--url") {
|
|
|
198
197
|
|
|
199
198
|
/**
|
|
200
199
|
* Validate that a CLI flag pointing at a filesystem path resolves to an
|
|
201
|
-
* existing regular file.
|
|
202
|
-
*
|
|
203
|
-
* and `projects apply-expose` (GH-233).
|
|
200
|
+
* existing regular file. Shared by `functions deploy`, `secrets set`,
|
|
201
|
+
* `projects sql`, and `projects apply-expose`.
|
|
204
202
|
*
|
|
205
203
|
* Without this guard, `readFileSync` against a missing path leaks a raw
|
|
206
204
|
* `node:fs` ENOENT/EISDIR stack to stderr (with the V8 source pointer),
|
|
@@ -439,8 +437,8 @@ export function failUnknownSubcommand(family, sub, { hint, label, extraSubcomman
|
|
|
439
437
|
const known = [...new Set([...knownSubcommands(family), ...extraSubcommands])].sort();
|
|
440
438
|
// closestWord() itself never echoes — it only ever returns one of the
|
|
441
439
|
// known, safe `known` candidates — but `sub` is an arbitrary positional
|
|
442
|
-
// (could be anything piped or mistyped in
|
|
443
|
-
//
|
|
440
|
+
// (could be anything piped or mistyped in, a leaked secret included),
|
|
441
|
+
// so the ECHO of `sub` below still needs
|
|
444
442
|
// redaction even though the matching runs on the raw value.
|
|
445
443
|
const closest = typeof sub === "string" ? closestWord(sub, known) : null;
|
|
446
444
|
const shownSub = describeRejectedValue(sub);
|
package/lib/billing.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getSdk } from "./sdk.mjs";
|
|
2
2
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
3
|
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
|
|
4
|
+
import { takeOrgPositional, requireRest } from "./org-context.mjs";
|
|
4
5
|
|
|
5
6
|
const HELP = `run402 billing — Email organizations and org checkouts
|
|
6
7
|
|
|
@@ -9,9 +10,9 @@ Usage:
|
|
|
9
10
|
|
|
10
11
|
Subcommands:
|
|
11
12
|
create-email <email> Create an email organization
|
|
12
|
-
link-wallet <org_id> <wallet_address>
|
|
13
|
+
link-wallet [<org_id>] <wallet_address> Link a wallet to an email organization
|
|
13
14
|
checkout <identifier> --product <p> Create an org checkout
|
|
14
|
-
auto-recharge <org_id> <on|off> [--threshold <n>]
|
|
15
|
+
auto-recharge [<org_id>] <on|off> [--threshold <n>]
|
|
15
16
|
balance <identifier> Balance by organization id (UUID), wallet (0x...), or email
|
|
16
17
|
history <identifier> [--limit <n>] Ledger history by organization id (UUID), wallet, or email
|
|
17
18
|
|
|
@@ -47,7 +48,7 @@ Examples:
|
|
|
47
48
|
"auto-recharge": `run402 billing auto-recharge — Toggle email-pack auto-recharge
|
|
48
49
|
|
|
49
50
|
Usage:
|
|
50
|
-
run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]
|
|
51
|
+
run402 billing auto-recharge [<org_id>] <on|off> [--threshold <n>]
|
|
51
52
|
|
|
52
53
|
Arguments:
|
|
53
54
|
<org_id> Organization ID
|
|
@@ -114,7 +115,7 @@ Examples:
|
|
|
114
115
|
"link-wallet": `run402 billing link-wallet — Link a wallet to an email organization
|
|
115
116
|
|
|
116
117
|
Usage:
|
|
117
|
-
run402 billing link-wallet <org_id> <wallet_address>
|
|
118
|
+
run402 billing link-wallet [<org_id>] <wallet_address>
|
|
118
119
|
|
|
119
120
|
Arguments:
|
|
120
121
|
<org_id> Organization ID (e.g. org_abc123)
|
|
@@ -232,22 +233,16 @@ async function createEmail(args) {
|
|
|
232
233
|
|
|
233
234
|
async function linkWallet(args) {
|
|
234
235
|
const parsedArgs = normalizeArgv(args);
|
|
235
|
-
assertKnownFlags(parsedArgs, ["--
|
|
236
|
-
const walletFlag = flagValue(parsedArgs, "--
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
fail({
|
|
246
|
-
code: "BAD_USAGE",
|
|
247
|
-
message: "Missing <org_id> and/or <wallet_address>.",
|
|
248
|
-
hint: "run402 billing link-wallet <org_id> --wallet <wallet_address>",
|
|
249
|
-
});
|
|
250
|
-
}
|
|
236
|
+
assertKnownFlags(parsedArgs, ["--org", "--address", "--help", "-h"], ["--org", "--address"]);
|
|
237
|
+
const walletFlag = flagValue(parsedArgs, "--address");
|
|
238
|
+
const { orgId: organizationId, rest } = await takeOrgPositional(parsedArgs, ["--org", "--address"], { cmd: "billing" });
|
|
239
|
+
const count = walletFlag ? 0 : 1;
|
|
240
|
+
requireRest(rest, {
|
|
241
|
+
min: count, max: count,
|
|
242
|
+
command: "run402 billing link-wallet [<org_id>] <wallet_address>",
|
|
243
|
+
missing: "Missing <wallet_address> (positional, or --address).",
|
|
244
|
+
});
|
|
245
|
+
const wallet = walletFlag ?? rest[0];
|
|
251
246
|
try {
|
|
252
247
|
const data = await getSdk().billing.linkWallet(organizationId, wallet);
|
|
253
248
|
const output = {
|
|
@@ -264,27 +259,30 @@ async function linkWallet(args) {
|
|
|
264
259
|
|
|
265
260
|
async function autoRecharge(args) {
|
|
266
261
|
const parsedArgs = normalizeArgv(args);
|
|
267
|
-
const valueFlags = ["--threshold", "--state"];
|
|
262
|
+
const valueFlags = ["--org", "--threshold", "--state"];
|
|
268
263
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
269
264
|
const stateFlag = flagValue(parsedArgs, "--state");
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const state = stateFlag ?? positionals[1];
|
|
273
|
-
const max = stateFlag ? 1 : 2;
|
|
274
|
-
if (positionals.length > max) {
|
|
275
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing auto-recharge: ${positionals[max]}` });
|
|
276
|
-
}
|
|
277
|
-
if (!organizationId || !state || !["on", "off"].includes(state)) {
|
|
278
|
-
fail({
|
|
279
|
-
code: "BAD_USAGE",
|
|
280
|
-
message: "Missing <org_id> and/or <on|off>.",
|
|
281
|
-
hint: "run402 billing auto-recharge <org_id> --state <on|off> [--threshold <n>]",
|
|
282
|
-
});
|
|
283
|
-
}
|
|
265
|
+
// Local validation FIRST — a malformed --threshold is refused before any org
|
|
266
|
+
// resolution (which may cost a network hop via --project).
|
|
284
267
|
const thresholdStr = flagValue(parsedArgs, "--threshold");
|
|
285
268
|
const threshold = parsedArgs.includes("--threshold")
|
|
286
269
|
? parseIntegerFlag("--threshold", thresholdStr, { min: 0 })
|
|
287
270
|
: undefined;
|
|
271
|
+
const { orgId: organizationId, rest } = await takeOrgPositional(parsedArgs, valueFlags, { cmd: "billing" });
|
|
272
|
+
const count = stateFlag ? 0 : 1;
|
|
273
|
+
requireRest(rest, {
|
|
274
|
+
min: count, max: count,
|
|
275
|
+
command: "run402 billing auto-recharge [<org_id>] --state <on|off> [--threshold <n>]",
|
|
276
|
+
missing: "Missing <on|off> (positional, or --state).",
|
|
277
|
+
});
|
|
278
|
+
const state = stateFlag ?? rest[0];
|
|
279
|
+
if (!["on", "off"].includes(state)) {
|
|
280
|
+
fail({
|
|
281
|
+
code: "BAD_USAGE",
|
|
282
|
+
message: `Expected on|off, got ${JSON.stringify(state)}.`,
|
|
283
|
+
hint: "run402 billing auto-recharge [<org_id>] --state <on|off> [--threshold <n>]",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
288
286
|
try {
|
|
289
287
|
await getSdk().billing.setAutoRecharge({
|
|
290
288
|
organizationId: organizationId,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { getSdk } from "./sdk.mjs";
|
|
9
9
|
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
10
|
+
import { resolveOrgId } from "./org-context.mjs";
|
|
10
11
|
import {
|
|
11
12
|
normalizeArgv,
|
|
12
13
|
hasHelp,
|
|
@@ -129,7 +130,7 @@ async function configure(args) {
|
|
|
129
130
|
const eventTypes = flagValues(a, "--event-type");
|
|
130
131
|
const eventClasses = flagValues(a, "--event-class");
|
|
131
132
|
try {
|
|
132
|
-
const created = await getSdk().buzz.notifications.createRoute(
|
|
133
|
+
const created = await getSdk().buzz.notifications.createRoute(await resolveOrgId(a, { cmd: "buzz" }), {
|
|
133
134
|
installationId: requiredFlag(a, "--installation"),
|
|
134
135
|
routeName: requiredFlag(a, "--name"),
|
|
135
136
|
buzzChannelId: requiredFlag(a, "--channel"),
|
|
@@ -161,7 +162,7 @@ async function status(args) {
|
|
|
161
162
|
out(await sdk.buzz.notifications.get(positionals[0]));
|
|
162
163
|
return;
|
|
163
164
|
}
|
|
164
|
-
const routes = await sdk.buzz.notifications.list(
|
|
165
|
+
const routes = await sdk.buzz.notifications.list(await resolveOrgId(a, { cmd: "buzz" }));
|
|
165
166
|
out({ buzz_project_event_routes: routes });
|
|
166
167
|
} catch (err) {
|
|
167
168
|
reportSdkError(err);
|
package/lib/buzz.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
4
|
+
import { resolveOrgId } from "./org-context.mjs";
|
|
4
5
|
import {
|
|
5
6
|
assertKnownFlags,
|
|
6
7
|
failUnknownSubcommand,
|
|
@@ -130,7 +131,8 @@ async function adopt(args) {
|
|
|
130
131
|
const a = normalizeArgv(rest);
|
|
131
132
|
assertKnownFlags(a, ["--org"], ["--org"]);
|
|
132
133
|
requirePositionalCount(a, ["--org"], { min: 0, max: 0, command: "run402 buzz adopt list --org <org_id>" });
|
|
133
|
-
|
|
134
|
+
const orgId = await resolveOrgId(a, { cmd: "buzz" });
|
|
135
|
+
return invoke(() => getSdk().buzz.humanAdoptions.list(orgId));
|
|
134
136
|
}
|
|
135
137
|
if (operation === "show") {
|
|
136
138
|
const a = normalizeArgv(rest);
|
|
@@ -143,9 +145,10 @@ async function adopt(args) {
|
|
|
143
145
|
const a = normalizeArgv(directArgs);
|
|
144
146
|
const values = ["--org", "--identity-link", "--idempotency-key"];
|
|
145
147
|
assertKnownFlags(a, values, values);
|
|
146
|
-
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz adopt direct --org <org_id> --identity-link <idlnk_id>" });
|
|
148
|
+
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz adopt direct [--org <org_id>] --identity-link <idlnk_id>" });
|
|
149
|
+
const organizationId = await resolveOrgId(a, { cmd: "buzz" });
|
|
147
150
|
return invoke(() => getSdk({ authMode: "wallet" }).buzz.adopt({
|
|
148
|
-
organizationId
|
|
151
|
+
organizationId,
|
|
149
152
|
identityLinkId: requiredFlag(a, "--identity-link"),
|
|
150
153
|
idempotencyKey: flagValue(a, "--idempotency-key") ?? undefined,
|
|
151
154
|
}));
|
|
@@ -169,8 +172,9 @@ async function adoptionOffer(args) {
|
|
|
169
172
|
const a = normalizeArgv(args);
|
|
170
173
|
const values = ["--org", "--identity-link", "--deployment-context-file", "--idempotency-key"];
|
|
171
174
|
assertKnownFlags(a, values, values);
|
|
172
|
-
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz adopt offer --org <org_id> --identity-link <idlnk_id>" });
|
|
175
|
+
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz adopt offer [--org <org_id>] --identity-link <idlnk_id>" });
|
|
173
176
|
const deploymentPath = flagValue(a, "--deployment-context-file");
|
|
177
|
+
const organizationId = await resolveOrgId(a, { cmd: "buzz" });
|
|
174
178
|
return invoke(async () => {
|
|
175
179
|
const client = getSdk({ authMode: "wallet" });
|
|
176
180
|
const status = await client.buzz.status();
|
|
@@ -183,7 +187,7 @@ async function adoptionOffer(args) {
|
|
|
183
187
|
});
|
|
184
188
|
}
|
|
185
189
|
return client.buzz.offerAdoption({
|
|
186
|
-
organizationId
|
|
190
|
+
organizationId,
|
|
187
191
|
identityLinkId: requiredFlag(a, "--identity-link"),
|
|
188
192
|
deploymentContext: deploymentPath ? readJsonFile(deploymentPath, "--deployment-context-file") : undefined,
|
|
189
193
|
idempotencyKey: flagValue(a, "--idempotency-key") ?? undefined,
|
|
@@ -227,7 +231,8 @@ async function install(args) {
|
|
|
227
231
|
const a = normalizeArgv(rest);
|
|
228
232
|
assertKnownFlags(a, ["--org"], ["--org"]);
|
|
229
233
|
requirePositionalCount(a, ["--org"], { min: 0, max: 0, command: "run402 buzz install list --org <org_id>" });
|
|
230
|
-
|
|
234
|
+
const orgId = await resolveOrgId(a, { cmd: "buzz" });
|
|
235
|
+
return invoke(() => getSdk().buzz.communityInstallations.list(orgId));
|
|
231
236
|
}
|
|
232
237
|
if (operation === "discover") {
|
|
233
238
|
const a = normalizeArgv(rest);
|
|
@@ -247,10 +252,11 @@ async function install(args) {
|
|
|
247
252
|
const a = normalizeArgv(args);
|
|
248
253
|
const values = ["--org", "--community", "--authority", "--policy-file", "--idempotency-key"];
|
|
249
254
|
assertKnownFlags(a, values, values);
|
|
250
|
-
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz install --org <org_id> --community <subject> --authority <hex>" });
|
|
255
|
+
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz install [--org <org_id>] --community <subject> --authority <hex>" });
|
|
251
256
|
const policyFile = flagValue(a, "--policy-file");
|
|
257
|
+
const organizationId = await resolveOrgId(a, { cmd: "buzz" });
|
|
252
258
|
return invoke(() => getSdk().buzz.install({
|
|
253
|
-
organizationId
|
|
259
|
+
organizationId,
|
|
254
260
|
buzzCommunitySubject: requiredFlag(a, "--community"),
|
|
255
261
|
buzzCommunityAuthoritySubject: requiredFlag(a, "--authority"),
|
|
256
262
|
enrollmentPolicy: policyFile ? readJsonFile(policyFile, "--policy-file") : undefined,
|
package/lib/buzz.test.mjs
CHANGED
|
@@ -92,7 +92,7 @@ describe("run402 buzz CLI", () => {
|
|
|
92
92
|
try {
|
|
93
93
|
await run("adopt", [
|
|
94
94
|
"offer",
|
|
95
|
-
"--org",
|
|
95
|
+
"--org", "22222222-2222-4222-8222-222222222222",
|
|
96
96
|
"--identity-link", `idlnk_${"3".repeat(32)}`,
|
|
97
97
|
"--deployment-context-file", contextPath,
|
|
98
98
|
"--idempotency-key", "offer-after-demo-1",
|
package/lib/command-manifest.mjs
CHANGED
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* projectScoped command operates on a project and accepts
|
|
16
16
|
* `--project <id>` (precedence: --project > legacy
|
|
17
17
|
* leading prj_ positional > active project)
|
|
18
|
+
* orgScoped command acts ON an organization and resolves it
|
|
19
|
+
* through the ONE shared chain (cli-org-context):
|
|
20
|
+
* an optional leading <org_id> positional, else
|
|
21
|
+
* --org, else RUN402_ORG, else the .run402.json
|
|
22
|
+
* binding, else `org use`. The gate drives every
|
|
23
|
+
* such entry through --org AND RUN402_ORG with no
|
|
24
|
+
* positional and fails on any "Missing <org_id>".
|
|
25
|
+
* Any entry with an `org_id` positional MUST be
|
|
26
|
+
* orgScoped and that positional MUST be optional.
|
|
18
27
|
* legacyPositionalProject still accepts the legacy leading `prj_...`
|
|
19
28
|
* positional project selector (compat, no warning)
|
|
20
29
|
* minimalArgs args (beyond path) that satisfy LOCAL validation
|
|
@@ -40,6 +49,14 @@
|
|
|
40
49
|
|
|
41
50
|
const p = (name, { required = true, variadic = false } = {}) => ({ name, required, variadic });
|
|
42
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The org id the gate uses for every orgScoped entry — a well-formed UUID so
|
|
54
|
+
* the shared resolver accepts it from any rung (positional, --org, RUN402_ORG).
|
|
55
|
+
* The behavioral org-scope gate strips it from minimalArgs and re-supplies the
|
|
56
|
+
* org through each rung in turn.
|
|
57
|
+
*/
|
|
58
|
+
export const GATE_ORG = "11111111-2222-3333-4444-555555555555";
|
|
59
|
+
|
|
43
60
|
export const COMMAND_MANIFEST = [
|
|
44
61
|
// ── external agent identity links ────────────────────────────────────────
|
|
45
62
|
{ path: ["identity", "link", "nostr", "begin"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--pubkey", "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa", "--visibility", "public"], skipBehavioral: "requires a live wallet and gateway challenge" },
|
|
@@ -50,16 +67,16 @@ export const COMMAND_MANIFEST = [
|
|
|
50
67
|
|
|
51
68
|
// ── Buzz community ↔ Run402 control plane ───────────────────────────────
|
|
52
69
|
{ path: ["buzz", "status"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [], skipBehavioral: "requires live principal authentication" },
|
|
53
|
-
{ path: ["buzz", "adopt", "offer"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--
|
|
54
|
-
{ path: ["buzz", "adopt", "direct"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--
|
|
55
|
-
{ path: ["buzz", "install"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--
|
|
70
|
+
{ path: ["buzz", "adopt", "offer"], positionals: [], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: ["--identity-link", "idlnk_11111111111111111111111111111111"], skipBehavioral: "requires eligible sole agent owner, live Buzz identity, and offer-capable gateway" },
|
|
71
|
+
{ path: ["buzz", "adopt", "direct"], positionals: [], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: ["--identity-link", "idlnk_11111111111111111111111111111111"], skipBehavioral: "advanced compatibility flow requiring eligible sole agent owner and live Buzz identity" },
|
|
72
|
+
{ path: ["buzz", "install"], positionals: [], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: ["--community", "buzz:community:relay.example", "--authority", "11".repeat(32)], skipBehavioral: "requires owner step-up and a compatible live Buzz relay" },
|
|
56
73
|
{ path: ["buzz", "enroll"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--installation", "buzzci_11111111111111111111111111111111", "--identity-link", "idlnk_11111111111111111111111111111111", "--grants-file", "__FIXTURE_FILE__", "--expires-at", "2026-08-01T00:00:00.000Z"], skipBehavioral: "requires live relay membership evidence and a grant fixture" },
|
|
57
74
|
{ path: ["buzz", "approve"], positionals: [p("buzz_agent_enrollment_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["buzzae_11111111111111111111111111111111", "--grants-file", "__FIXTURE_FILE__", "--descriptor-revision", "1", "--policy-revision", "1"], skipBehavioral: "requires owner step-up and a live pending enrollment" },
|
|
58
75
|
{ path: ["buzz", "deny"], positionals: [p("buzz_agent_enrollment_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["buzzae_11111111111111111111111111111111"], skipBehavioral: "requires owner step-up and a live pending enrollment" },
|
|
59
76
|
{ path: ["buzz", "revoke"], positionals: [p("buzz_agent_enrollment_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["buzzae_11111111111111111111111111111111"], skipBehavioral: "requires a live enrollment" },
|
|
60
77
|
// Project-event routing into a Buzz channel (add-buzz-project-event-routing).
|
|
61
78
|
// org ids on this surface are BARE dashed UUIDs, never org_-prefixed.
|
|
62
|
-
{ path: ["buzz", "notifications", "configure"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--
|
|
79
|
+
{ path: ["buzz", "notifications", "configure"], positionals: [], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: ["--installation", "buzzci_11111111111111111111111111111111", "--name", "deploys", "--channel", "22222222-2222-4222-8222-222222222222"], skipBehavioral: "requires live owner authentication and an active Buzz installation (and its repeatable --project scope flag is reserved by the gate)" },
|
|
63
80
|
{ path: ["buzz", "notifications", "status"], positionals: [p("buzz_project_event_route_id", { required: false })], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--org", "11111111-1111-4111-8111-111111111111"], skipBehavioral: "requires live owner authentication" },
|
|
64
81
|
{ path: ["buzz", "notifications", "test"], positionals: [p("buzz_project_event_route_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["buzzper_11111111111111111111111111111111"], skipBehavioral: "requires live owner authentication and a live route" },
|
|
65
82
|
{ path: ["buzz", "notifications", "deliveries"], positionals: [p("buzz_project_event_route_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["buzzper_11111111111111111111111111111111"], skipBehavioral: "requires live owner authentication and a live route" },
|
|
@@ -194,28 +211,28 @@ export const COMMAND_MANIFEST = [
|
|
|
194
211
|
// ── org ──────────────────────────────────────────────────────────────────
|
|
195
212
|
{ path: ["org", "create"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
196
213
|
{ path: ["org", "list"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
197
|
-
{ path: ["org", "get"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
198
|
-
{ path: ["org", "rename"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
199
|
-
{ path: ["org", "payout-wallet"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
214
|
+
{ path: ["org", "get"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG] },
|
|
215
|
+
{ path: ["org", "rename"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--name", "Gate"] },
|
|
216
|
+
{ path: ["org", "payout-wallet"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "0x1111111111111111111111111111111111111111"] },
|
|
200
217
|
// `--org` (not a positional org_id
|
|
201
218
|
// like rename/payout-wallet above) goes through resolveOrg's SHAPE
|
|
202
219
|
// validation (a real UUID) — "org_gate1" fails that locally, so this needs
|
|
203
220
|
// the same UUID-shaped fixture `org use` below already established.
|
|
204
221
|
{ path: ["org", "slug"], positionals: [p("slug")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["acme", "--org", "11111111-2222-3333-4444-555555555555"] },
|
|
205
222
|
{ path: ["org", "whoami"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
206
|
-
{ path: ["org", "audit"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
223
|
+
{ path: ["org", "audit"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG] },
|
|
207
224
|
{ path: ["org", "use"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["11111111-2222-3333-4444-555555555555"] },
|
|
208
225
|
{ path: ["org", "current"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
209
226
|
{ path: ["org", "clear"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
210
227
|
{ path: ["org", "bind"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["--org", "11111111-2222-3333-4444-555555555555"] },
|
|
211
228
|
{ path: ["org", "unbind"], positionals: [], projectScoped: false, legacyPositionalProject: false, minimalArgs: [] },
|
|
212
|
-
{ path: ["org", "member", "list"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
213
|
-
{ path: ["org", "member", "add"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
214
|
-
{ path: ["org", "member", "role"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
215
|
-
{ path: ["org", "member", "rm"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
216
|
-
{ path: ["org", "invite", "list"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
217
|
-
{ path: ["org", "invite", "create"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
218
|
-
{ path: ["org", "invite", "rm"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
229
|
+
{ path: ["org", "member", "list"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG] },
|
|
230
|
+
{ path: ["org", "member", "add"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "0x1111111111111111111111111111111111111111"] },
|
|
231
|
+
{ path: ["org", "member", "role"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--principal", "prn_gate1", "--role", "viewer"] },
|
|
232
|
+
{ path: ["org", "member", "rm"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--principal", "prn_gate1"] },
|
|
233
|
+
{ path: ["org", "invite", "list"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG] },
|
|
234
|
+
{ path: ["org", "invite", "create"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--email", "gate@example.com"] },
|
|
235
|
+
{ path: ["org", "invite", "rm"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--principal", "prn_gate1"] },
|
|
219
236
|
|
|
220
237
|
// ── grants ───────────────────────────────────────────────────────────────
|
|
221
238
|
{ path: ["grants", "create"], positionals: [p("wallet")], projectScoped: true, legacyPositionalProject: true, minimalArgs: ["0x1111111111111111111111111111111111111111", "--capability", "deploy"] },
|
|
@@ -285,13 +302,14 @@ export const COMMAND_MANIFEST = [
|
|
|
285
302
|
{ path: ["repos", "mirror"], positionals: [p("destination", { required: false })], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "reads/writes mirror destination config beside the keystore and may move real bytes into a customer-owned bucket" },
|
|
286
303
|
{ path: ["repos", "fsck"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "walks the live head chain and materializes the ref map against the keystore's local pins" },
|
|
287
304
|
{ path: ["repos", "gc"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "publishes a checkpoint under a maintenance lease and materializes the live vault head to enumerate retention roots" },
|
|
288
|
-
// `access repair`/`revoke-key`/`declare-exposure` are nested
|
|
289
|
-
// literals — one manifest entry each, all dispatched through the
|
|
290
|
-
// `run("access", ...)` case in repos.mjs.
|
|
305
|
+
// `access repair`/`revoke-key`/`declare-exposure`/`sync` are nested
|
|
306
|
+
// sub-verb literals — one manifest entry each, all dispatched through the
|
|
307
|
+
// ONE `run("access", ...)` case in repos.mjs.
|
|
291
308
|
{ path: ["repos", "access"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "reads the live org encryption-key directory + vault envelope recipients" },
|
|
292
309
|
{ path: ["repos", "access", "repair"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["--recipient-state-version", "0", "--recipient-revocation-version", "0"], runStyle: "sub", skipBehavioral: "owner+step-up-gated epoch rotation (D193-D203, rev 42) — samples a fresh epoch key and re-seals a live vault's recipients" },
|
|
293
310
|
{ path: ["repos", "access", "revoke-key"], positionals: [p("principal_id")], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["prin_00000000000000000000000000000000"], runStyle: "sub", skipBehavioral: "owner+step-up-gated: declares a recipient's key revoked (org-scoped watermark) and drives a real epoch rotation off it" },
|
|
294
311
|
{ path: ["repos", "access", "declare-exposure"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "owner+step-up-gated: declares this vault's epoch secret exposed, forcing every subsequent ordinary push to refuse until a rotation lands" },
|
|
312
|
+
{ path: ["repos", "access", "sync"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "sub", skipBehavioral: "gitvault-multi-writer (rev 47): on-demand writer-admission reconcile — resolves pending candidates' signing keys via the live org encryption-key directory and publishes a real add_writer_key head per candidate" },
|
|
295
313
|
{ path: ["repos", "recover"], positionals: [p("source")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["s3://example-mirror-bucket", "--out", "__SCRATCH_DIR__/recover-out"], runStyle: "sub", skipBehavioral: "materializes a git repository from a mirror source, offline, with no server call" },
|
|
296
314
|
// Principal-scoped (one bundle covers every vault you can read), so no
|
|
297
315
|
// --project — deliberately unlike its eleven vault-scoped siblings.
|
|
@@ -424,9 +442,9 @@ export const COMMAND_MANIFEST = [
|
|
|
424
442
|
|
|
425
443
|
// ── billing ──────────────────────────────────────────────────────────────
|
|
426
444
|
{ path: ["billing", "create-email"], positionals: [p("email")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
427
|
-
{ path: ["billing", "link-wallet"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
445
|
+
{ path: ["billing", "link-wallet"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "0x1111111111111111111111111111111111111111"] },
|
|
428
446
|
{ path: ["billing", "checkout"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["00000000-0000-4000-8000-000000000001", "--product", "email-pack"] },
|
|
429
|
-
{ path: ["billing", "auto-recharge"], positionals: [p("org_id")], projectScoped: false, legacyPositionalProject: false, minimalArgs: [
|
|
447
|
+
{ path: ["billing", "auto-recharge"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--state", "on"] },
|
|
430
448
|
{ path: ["billing", "balance"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
431
449
|
{ path: ["billing", "history"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
432
450
|
|
package/lib/config.mjs
CHANGED
|
@@ -55,7 +55,7 @@ export const API = getApiBase();
|
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Wraps core's `readAllowance()` and converts the malformed-shape throw
|
|
58
|
-
*
|
|
58
|
+
* into the canonical CLI failure envelope. Without this guard, every
|
|
59
59
|
* CLI subcommand that touches the allowance leaks a Node stack trace and
|
|
60
60
|
* source paths the moment a user has a malformed `allowance.json`.
|
|
61
61
|
*
|