run402 4.93.2 → 4.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -59
- package/cli.mjs +40 -47
- package/core-dist/config.js +52 -18
- package/core-dist/control-plane-session.js +31 -6
- package/core-dist/keystore.js +7 -7
- package/core-dist/profiles.js +9 -7
- package/core-dist/{allowance-auth.js → wallet-auth.js} +15 -15
- package/{sdk/core-dist/allowance.js → core-dist/wallet.js} +20 -20
- package/{sdk/core-dist/write-auth-session.js → core-dist/write-approvals.js} +19 -19
- package/gitvault-surface.json +2 -2
- package/lib/admin.mjs +6 -6
- package/lib/agent.mjs +20 -18
- package/lib/ai.mjs +5 -5
- package/lib/approve.mjs +81 -0
- package/lib/apps.mjs +12 -12
- package/lib/archives.mjs +371 -8
- package/lib/argparse.mjs +5 -5
- package/lib/assets.mjs +14 -14
- package/lib/auth.mjs +34 -34
- package/lib/billing.mjs +6 -6
- package/lib/branches.mjs +7 -7
- package/lib/buzz-doctor.mjs +2 -2
- package/lib/buzz-notifications.mjs +5 -5
- package/lib/buzz.mjs +3 -3
- package/lib/buzz.test.mjs +1 -1
- package/lib/cache.mjs +1 -1
- package/lib/cdn.mjs +2 -2
- package/lib/ci.mjs +12 -12
- package/lib/claims.mjs +2 -2
- package/lib/cold-start.mjs +21 -21
- package/lib/command-manifest.mjs +55 -70
- package/lib/config.mjs +28 -28
- package/lib/contacts.mjs +16 -16
- package/lib/contracts.mjs +12 -12
- package/lib/credentials.mjs +33 -33
- package/lib/daemon-path.mjs +1 -1
- package/lib/delegates.mjs +14 -14
- package/lib/deliveries.mjs +6 -6
- package/lib/deploy-rehearse-discovery.test.mjs +7 -7
- package/lib/deploy-v2.mjs +241 -193
- package/lib/deploy.mjs +21 -53
- package/lib/dev.mjs +3 -3
- package/lib/doctor-source-scan.mjs +1 -1
- package/lib/doctor.mjs +63 -63
- package/lib/domains.mjs +27 -27
- package/lib/email.mjs +38 -38
- package/lib/errors.mjs +40 -24
- package/lib/escalations.mjs +5 -5
- package/lib/events.mjs +32 -25
- package/lib/feedback.mjs +12 -12
- package/lib/functions.mjs +34 -34
- package/lib/gitvault-daemon.mjs +1 -1
- package/lib/gitvault-scaffold.mjs +2 -2
- package/lib/gitvault.mjs +2 -2
- package/lib/grants.mjs +7 -7
- package/lib/image.mjs +10 -10
- package/lib/init.mjs +69 -69
- package/lib/jobs.mjs +15 -15
- package/lib/lightning-wallet.mjs +28 -28
- package/lib/live.mjs +1 -1
- package/lib/login.mjs +207 -0
- package/lib/logout.mjs +53 -0
- package/lib/logs.mjs +8 -8
- package/lib/messages.mjs +5 -5
- package/lib/next-actions.mjs +16 -16
- package/lib/org-context.mjs +13 -13
- package/lib/{org.mjs → orgs.mjs} +215 -167
- package/lib/pay.mjs +1 -1
- package/lib/projects.mjs +70 -84
- package/lib/redeem.mjs +7 -8
- package/lib/remote-helper-session.mjs +12 -12
- package/lib/repos.mjs +83 -83
- package/lib/rooms.mjs +105 -69
- package/lib/sdk-errors.mjs +10 -5
- package/lib/sdk.mjs +3 -3
- package/lib/secrets.mjs +13 -13
- package/lib/service.mjs +5 -5
- package/lib/session-proofs.mjs +21 -0
- package/lib/sign-in.mjs +296 -0
- package/lib/sites.mjs +22 -22
- package/lib/snapshots.mjs +10 -10
- package/lib/stats.mjs +2 -2
- package/lib/status.mjs +25 -25
- package/lib/subdomains.mjs +30 -30
- package/lib/subscriptions.mjs +10 -10
- package/lib/tier.mjs +29 -22
- package/lib/transfer.mjs +59 -86
- package/lib/up.mjs +14 -14
- package/lib/wallet-context.mjs +4 -4
- package/lib/wallet-context.test.mjs +3 -3
- package/lib/wallets.mjs +197 -32
- package/lib/webhook-secret.mjs +6 -6
- package/lib/webhooks.mjs +8 -8
- package/lib/whoami.mjs +102 -0
- package/package.json +1 -1
- package/sdk/core-dist/config.js +52 -18
- package/sdk/core-dist/control-plane-session.js +31 -6
- package/sdk/core-dist/keystore.js +7 -7
- package/sdk/core-dist/profiles.js +9 -7
- package/sdk/core-dist/{allowance-auth.js → wallet-auth.js} +15 -15
- package/{core-dist/allowance.js → sdk/core-dist/wallet.js} +20 -20
- package/{core-dist/write-auth-session.js → sdk/core-dist/write-approvals.js} +19 -19
- package/sdk/dist/actions.d.ts +4 -4
- package/sdk/dist/actions.d.ts.map +1 -1
- package/sdk/dist/app-up.d.ts +2 -2
- package/sdk/dist/app-up.d.ts.map +1 -1
- package/sdk/dist/config.d.ts +1 -2
- package/sdk/dist/config.d.ts.map +1 -1
- package/sdk/dist/config.js.map +1 -1
- package/sdk/dist/control-plane-credentials.d.ts +8 -8
- package/sdk/dist/control-plane-credentials.js +7 -7
- package/sdk/dist/credentials.d.ts +20 -20
- package/sdk/dist/credentials.d.ts.map +1 -1
- package/sdk/dist/credentials.js +1 -1
- package/sdk/dist/errors.d.ts +26 -28
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +35 -38
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts +29 -16
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +30 -17
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/kernel.d.ts +1 -1
- package/sdk/dist/kernel.d.ts.map +1 -1
- package/sdk/dist/kernel.js +10 -9
- package/sdk/dist/kernel.js.map +1 -1
- package/sdk/dist/namespaces/admin.d.ts +52 -121
- package/sdk/dist/namespaces/admin.d.ts.map +1 -1
- package/sdk/dist/namespaces/admin.js +41 -45
- package/sdk/dist/namespaces/admin.js.map +1 -1
- package/sdk/dist/namespaces/agent.d.ts +2 -2
- package/sdk/dist/namespaces/agent.d.ts.map +1 -1
- package/sdk/dist/namespaces/agent.js +2 -2
- package/sdk/dist/namespaces/agent.js.map +1 -1
- package/sdk/dist/namespaces/ai.d.ts +2 -2
- package/sdk/dist/namespaces/ai.js +3 -3
- package/sdk/dist/namespaces/ai.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/billing.d.ts +6 -3
- package/sdk/dist/namespaces/billing.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.js.map +1 -1
- package/sdk/dist/namespaces/buzz-notifications.types.d.ts +1 -1
- package/sdk/dist/namespaces/buzz.d.ts +2 -2
- package/sdk/dist/namespaces/buzz.d.ts.map +1 -1
- package/sdk/dist/namespaces/buzz.js +2 -2
- package/sdk/dist/namespaces/buzz.js.map +1 -1
- package/sdk/dist/namespaces/buzz.types.d.ts +2 -2
- package/sdk/dist/namespaces/buzz.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/ci.js +3 -3
- package/sdk/dist/namespaces/ci.js.map +1 -1
- package/sdk/dist/namespaces/credentials.types.d.ts +1 -1
- package/sdk/dist/namespaces/deploy.d.ts +1 -1
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +31 -32
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +6 -6
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/domains.d.ts +10 -2
- package/sdk/dist/namespaces/domains.d.ts.map +1 -1
- package/sdk/dist/namespaces/domains.js +10 -5
- package/sdk/dist/namespaces/domains.js.map +1 -1
- package/sdk/dist/namespaces/errors.js +1 -1
- package/sdk/dist/namespaces/escalations.d.ts +1 -1
- package/sdk/dist/namespaces/escalations.js +1 -1
- package/sdk/dist/namespaces/escalations.types.d.ts +2 -2
- package/sdk/dist/namespaces/escalations.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/events.types.d.ts +1 -1
- package/sdk/dist/namespaces/functions.d.ts +1 -1
- package/sdk/dist/namespaces/functions.js +2 -2
- package/sdk/dist/namespaces/functions.js.map +1 -1
- package/sdk/dist/namespaces/gitvault.crypto.d.ts +1 -1
- package/sdk/dist/namespaces/gitvault.d.ts +26 -26
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +113 -113
- package/sdk/dist/namespaces/gitvault.js.map +1 -1
- package/sdk/dist/namespaces/me.d.ts +120 -0
- package/sdk/dist/namespaces/me.d.ts.map +1 -0
- package/sdk/dist/namespaces/me.js +34 -0
- package/sdk/dist/namespaces/me.js.map +1 -0
- package/sdk/dist/namespaces/org.d.ts +108 -6
- package/sdk/dist/namespaces/org.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.js +63 -7
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/namespaces/org.types.d.ts +29 -9
- package/sdk/dist/namespaces/org.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/pay.js +3 -3
- package/sdk/dist/namespaces/pay.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts +9 -9
- package/sdk/dist/namespaces/projects.js +15 -15
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/namespaces/projects.types.d.ts +28 -12
- package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/rooms.d.ts +7 -7
- package/sdk/dist/namespaces/rooms.js +17 -17
- package/sdk/dist/namespaces/rooms.js.map +1 -1
- package/sdk/dist/namespaces/rooms.types.d.ts +9 -9
- package/sdk/dist/namespaces/rooms.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/service.d.ts +1 -1
- package/sdk/dist/namespaces/service.js +1 -1
- package/sdk/dist/namespaces/{operator-session.d.ts → session.d.ts} +135 -51
- package/sdk/dist/namespaces/session.d.ts.map +1 -0
- package/sdk/dist/namespaces/{operator-session.js → session.js} +118 -30
- package/sdk/dist/namespaces/session.js.map +1 -0
- package/sdk/dist/namespaces/subdomains.d.ts +5 -5
- package/sdk/dist/namespaces/subdomains.d.ts.map +1 -1
- package/sdk/dist/namespaces/subdomains.js +6 -6
- package/sdk/dist/namespaces/subdomains.js.map +1 -1
- package/sdk/dist/namespaces/tier.d.ts +44 -21
- package/sdk/dist/namespaces/tier.d.ts.map +1 -1
- package/sdk/dist/namespaces/tier.js +7 -7
- package/sdk/dist/namespaces/tier.js.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts +119 -85
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +31 -38
- package/sdk/dist/namespaces/transfers.js.map +1 -1
- package/sdk/dist/namespaces/vouchers.d.ts +9 -10
- package/sdk/dist/namespaces/vouchers.d.ts.map +1 -1
- package/sdk/dist/namespaces/vouchers.js +4 -5
- package/sdk/dist/namespaces/vouchers.js.map +1 -1
- package/sdk/dist/namespaces/wallets.d.ts +72 -3
- package/sdk/dist/namespaces/wallets.d.ts.map +1 -1
- package/sdk/dist/namespaces/wallets.js +141 -3
- package/sdk/dist/namespaces/wallets.js.map +1 -1
- package/sdk/dist/namespaces/write-approval.d.ts +101 -0
- package/sdk/dist/namespaces/write-approval.d.ts.map +1 -0
- package/sdk/dist/namespaces/write-approval.js +62 -0
- package/sdk/dist/namespaces/write-approval.js.map +1 -0
- package/sdk/dist/node/actions-node.d.ts +3 -3
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +44 -44
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/assets-node.js +6 -6
- package/sdk/dist/node/assets-node.js.map +1 -1
- package/sdk/dist/node/{bearer-claim-key.d.ts → bearer-redeem-key.d.ts} +12 -12
- package/sdk/dist/node/bearer-redeem-key.d.ts.map +1 -0
- package/sdk/dist/node/{bearer-claim-key.js → bearer-redeem-key.js} +21 -21
- package/sdk/dist/node/bearer-redeem-key.js.map +1 -0
- package/sdk/dist/node/ci.d.ts +1 -1
- package/sdk/dist/node/ci.d.ts.map +1 -1
- package/sdk/dist/node/ci.js +6 -6
- package/sdk/dist/node/ci.js.map +1 -1
- package/sdk/dist/node/credentials.d.ts +18 -17
- package/sdk/dist/node/credentials.d.ts.map +1 -1
- package/sdk/dist/node/credentials.js +29 -28
- package/sdk/dist/node/credentials.js.map +1 -1
- package/sdk/dist/node/deploy-manifest.d.ts +3 -5
- package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +3 -12
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
- package/sdk/dist/node/funding-recovery.d.ts +1 -1
- package/sdk/dist/node/funding-recovery.d.ts.map +1 -1
- package/sdk/dist/node/funding-recovery.js +1 -1
- package/sdk/dist/node/funding-recovery.js.map +1 -1
- package/sdk/dist/node/gitvault-apply.d.ts +1 -1
- package/sdk/dist/node/gitvault-apply.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-apply.js +1 -1
- package/sdk/dist/node/gitvault-apply.js.map +1 -1
- package/sdk/dist/node/gitvault-handoff.d.ts +22 -22
- package/sdk/dist/node/gitvault-handoff.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-handoff.js +45 -45
- package/sdk/dist/node/gitvault-handoff.js.map +1 -1
- package/sdk/dist/node/gitvault-prewarm.js +7 -7
- package/sdk/dist/node/gitvault-prewarm.js.map +1 -1
- package/sdk/dist/node/gitvault-restore.d.ts +1 -1
- package/sdk/dist/node/gitvault-restore.js +1 -1
- package/sdk/dist/node/index.d.ts +16 -16
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +15 -15
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/manifest-export.js +2 -2
- package/sdk/dist/node/manifest-export.js.map +1 -1
- package/sdk/dist/node/org-adopt.d.ts +49 -0
- package/sdk/dist/node/org-adopt.d.ts.map +1 -0
- package/sdk/dist/node/org-adopt.js +77 -0
- package/sdk/dist/node/org-adopt.js.map +1 -0
- package/sdk/dist/node/paid-fetch.d.ts +7 -7
- package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
- package/sdk/dist/node/paid-fetch.js +54 -54
- package/sdk/dist/node/paid-fetch.js.map +1 -1
- package/sdk/dist/node/preflight.d.ts +1 -1
- package/sdk/dist/node/preflight.d.ts.map +1 -1
- package/sdk/dist/node/preflight.js +1 -1
- package/sdk/dist/node/preflight.js.map +1 -1
- package/sdk/dist/node/sites-node.js +1 -1
- package/sdk/dist/node/sites-node.js.map +1 -1
- package/sdk/dist/node/source-scan.d.ts +1 -1
- package/sdk/dist/node/source-scan.js +2 -2
- package/sdk/dist/node/source-scan.js.map +1 -1
- package/sdk/dist/scoped.d.ts +11 -11
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +5 -5
- package/sdk/dist/scoped.js.map +1 -1
- package/core-dist/operator-session.js +0 -154
- package/lib/allowance.mjs +0 -355
- package/lib/cloud.mjs +0 -256
- package/lib/core.mjs +0 -123
- package/lib/operator-proofs.mjs +0 -22
- package/lib/operator.mjs +0 -771
- package/sdk/core-dist/operator-session.js +0 -154
- package/sdk/dist/namespaces/allowance.d.ts +0 -79
- package/sdk/dist/namespaces/allowance.d.ts.map +0 -1
- package/sdk/dist/namespaces/allowance.js +0 -149
- package/sdk/dist/namespaces/allowance.js.map +0 -1
- package/sdk/dist/namespaces/operator-session.d.ts.map +0 -1
- package/sdk/dist/namespaces/operator-session.js.map +0 -1
- package/sdk/dist/namespaces/operator.d.ts +0 -359
- package/sdk/dist/namespaces/operator.d.ts.map +0 -1
- package/sdk/dist/namespaces/operator.js +0 -272
- package/sdk/dist/namespaces/operator.js.map +0 -1
- package/sdk/dist/node/bearer-claim-key.d.ts.map +0 -1
- package/sdk/dist/node/bearer-claim-key.js.map +0 -1
- package/sdk/dist/node/operator-claim.d.ts +0 -49
- package/sdk/dist/node/operator-claim.d.ts.map +0 -1
- package/sdk/dist/node/operator-claim.js +0 -77
- package/sdk/dist/node/operator-claim.js.map +0 -1
package/lib/login.mjs
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `run402 login [--device] [--no-open]` — sign a person in. See sign-in.mjs.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
6
|
+
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
7
|
+
import { getSdk } from "./sdk.mjs";
|
|
8
|
+
import { normalizeArgv, hasHelp, assertKnownFlags, positionalArgs } from "./argparse.mjs";
|
|
9
|
+
import {
|
|
10
|
+
saveControlPlaneSession,
|
|
11
|
+
controlPlaneSessionFromTokenResponse,
|
|
12
|
+
clearRetiredSessionCaches,
|
|
13
|
+
} from "../core-dist/control-plane-session.js";
|
|
14
|
+
import { clearApprovals } from "../core-dist/write-approvals.js";
|
|
15
|
+
import { openBrowser, pkce, sessionView, startLoopbackServer } from "./sign-in.mjs";
|
|
16
|
+
|
|
17
|
+
const HELP = `run402 login — sign in as a person (your sign-in session)
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
run402 login [--no-open] browser passkey sign-in (full session)
|
|
21
|
+
run402 login --device [--no-open] device code for a terminal with no browser (read-only)
|
|
22
|
+
|
|
23
|
+
A person signs in; an agent's wallet is a separate identity ('run402 status').
|
|
24
|
+
'run402 login' opens the browser, where you sign in with your passkey, and
|
|
25
|
+
catches the redirect on a 127.0.0.1 port. The session it caches can write,
|
|
26
|
+
and step-up works on it. 'run402 login --device' prints a code you approve in
|
|
27
|
+
the console from any device; that session can only read (every write answers
|
|
28
|
+
SESSION_READ_ONLY).
|
|
29
|
+
|
|
30
|
+
Provisioning, deploying, and writing secrets without a wallet also need a
|
|
31
|
+
write approval: 'run402 approve --action <capability> (--org <org_id> |
|
|
32
|
+
--project <project_id>)'. From a terminal the CLI opens it for you.
|
|
33
|
+
|
|
34
|
+
Options:
|
|
35
|
+
--device Use the device-code flow (RFC 8628) instead of the browser redirect.
|
|
36
|
+
--no-open Do not open the browser; print the URL only.
|
|
37
|
+
|
|
38
|
+
Notes:
|
|
39
|
+
- The session is cached at the base config dir, shared across named wallets.
|
|
40
|
+
- JSON to stdout; the URL and code to open go to stderr.
|
|
41
|
+
- 'run402 whoami' shows the session's grade; 'run402 logout' ends it.
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const CLIENT_NAME = "run402 CLI";
|
|
45
|
+
|
|
46
|
+
/** Cache a freshly minted session; a new session invalidates every approval bound to the old one. */
|
|
47
|
+
function cacheSession(tokenResponse) {
|
|
48
|
+
const cached = controlPlaneSessionFromTokenResponse(tokenResponse);
|
|
49
|
+
clearApprovals();
|
|
50
|
+
clearRetiredSessionCaches();
|
|
51
|
+
saveControlPlaneSession(cached);
|
|
52
|
+
return cached;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Best-effort: surface org memberships (auto-redeemed invites land here). Never fails the login. */
|
|
56
|
+
async function attachMemberships(view, token) {
|
|
57
|
+
try {
|
|
58
|
+
const who = await getSdk().session.whoami({ token });
|
|
59
|
+
const memberships = Array.isArray(who?.memberships) ? who.memberships : [];
|
|
60
|
+
view.memberships = memberships;
|
|
61
|
+
if (memberships.length) {
|
|
62
|
+
process.stderr.write(
|
|
63
|
+
`Member of ${memberships.length} org(s):\n` +
|
|
64
|
+
memberships.map((m) => ` - ${m.display_name || m.org_id || "unknown"} (${m.role}, ${m.status})`).join("\n") +
|
|
65
|
+
"\n",
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
/* best-effort — the session is valid regardless of the whoami result */
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function loopbackLogin({ noOpen }) {
|
|
74
|
+
const sdk = getSdk();
|
|
75
|
+
const { codeVerifier, codeChallenge, state, nonce } = pkce();
|
|
76
|
+
const { ready, codePromise, close } = startLoopbackServer({ expectedState: state, timeoutMs: 300_000 });
|
|
77
|
+
|
|
78
|
+
let port;
|
|
79
|
+
try {
|
|
80
|
+
port = await ready;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
close();
|
|
83
|
+
return fail({ code: "LOOPBACK_FAILED", message: `Could not start the loopback server: ${err.message}` });
|
|
84
|
+
}
|
|
85
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
86
|
+
const authorizeUrl = sdk.session.buildCliAuthorizeUrl({ redirectUri, codeChallenge, state, nonce });
|
|
87
|
+
|
|
88
|
+
process.stderr.write(`\nTo sign in, open:\n ${authorizeUrl}\n\n`);
|
|
89
|
+
if (!noOpen && process.stderr.isTTY) {
|
|
90
|
+
openBrowser(authorizeUrl);
|
|
91
|
+
process.stderr.write("(opening your browser…)\n\n");
|
|
92
|
+
}
|
|
93
|
+
process.stderr.write("Waiting for approval…\n");
|
|
94
|
+
|
|
95
|
+
let code;
|
|
96
|
+
try {
|
|
97
|
+
code = await codePromise;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
close();
|
|
100
|
+
return fail({ code: "LOGIN_FAILED", message: err.message, hint: "Run 'run402 login' to try again." });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let session;
|
|
104
|
+
try {
|
|
105
|
+
session = await sdk.session.exchangeCliToken({ code, codeVerifier, redirectUri, state });
|
|
106
|
+
} catch (err) {
|
|
107
|
+
close();
|
|
108
|
+
return reportSdkError(err);
|
|
109
|
+
}
|
|
110
|
+
// The loopback server has done its job. Tear it down (destroying any
|
|
111
|
+
// keep-alive socket) so Node's event loop drains and the CLI exits instead
|
|
112
|
+
// of hanging until Ctrl+C.
|
|
113
|
+
close();
|
|
114
|
+
|
|
115
|
+
const cached = cacheSession(session);
|
|
116
|
+
process.stderr.write(`\nSigned in (grade: ${cached.grade}).\n`);
|
|
117
|
+
const view = sessionView(cached);
|
|
118
|
+
await attachMemberships(view, session.control_plane_session_token);
|
|
119
|
+
console.log(JSON.stringify(view));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function deviceLogin({ noOpen }) {
|
|
123
|
+
const sdk = getSdk();
|
|
124
|
+
let start;
|
|
125
|
+
try {
|
|
126
|
+
start = await sdk.session.deviceStart();
|
|
127
|
+
} catch (err) {
|
|
128
|
+
return reportSdkError(err);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Human-in-the-loop prompt → stderr, so stdout stays clean for the final JSON.
|
|
132
|
+
const target = start.verification_uri_complete || start.verification_uri;
|
|
133
|
+
process.stderr.write(
|
|
134
|
+
`\nTo authorize the ${CLIENT_NAME}, open:\n ${start.verification_uri}\n` +
|
|
135
|
+
`and enter the code: ${start.user_code}\n\n`,
|
|
136
|
+
);
|
|
137
|
+
if (!noOpen && process.stderr.isTTY) {
|
|
138
|
+
openBrowser(target);
|
|
139
|
+
process.stderr.write("(opening your browser…)\n\n");
|
|
140
|
+
}
|
|
141
|
+
process.stderr.write("Waiting for approval…\n");
|
|
142
|
+
|
|
143
|
+
// Poll loop — honor the server interval, back off on slow_down, and stop at
|
|
144
|
+
// the device-code deadline. if/else (not switch) so the sync scanner doesn't
|
|
145
|
+
// mistake the poll states for CLI subcommands.
|
|
146
|
+
let intervalMs = Math.max(1, Number(start.interval) || 5) * 1000;
|
|
147
|
+
const deadline = Date.now() + Math.max(1, Number(start.expires_in) || 600) * 1000;
|
|
148
|
+
|
|
149
|
+
while (Date.now() < deadline) {
|
|
150
|
+
await sleep(intervalMs);
|
|
151
|
+
let result;
|
|
152
|
+
try {
|
|
153
|
+
result = await sdk.session.devicePoll(start.device_code);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return reportSdkError(err);
|
|
156
|
+
}
|
|
157
|
+
if (result.kind === "approved") {
|
|
158
|
+
const cached = cacheSession(result.session);
|
|
159
|
+
process.stderr.write(`\nSigned in (grade: ${cached.grade}, read-only).\n`);
|
|
160
|
+
const view = sessionView(cached);
|
|
161
|
+
await attachMemberships(view, result.session.control_plane_session_token);
|
|
162
|
+
console.log(JSON.stringify(view));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (result.kind === "authorization_pending") continue;
|
|
166
|
+
if (result.kind === "slow_down") {
|
|
167
|
+
intervalMs += 5000;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (result.kind === "access_denied") {
|
|
171
|
+
fail({
|
|
172
|
+
code: "LOGIN_DENIED",
|
|
173
|
+
message: "Authorization was denied in the browser.",
|
|
174
|
+
hint: "Run 'run402 login --device' to try again.",
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (result.kind === "expired_token") {
|
|
178
|
+
fail({
|
|
179
|
+
code: "LOGIN_EXPIRED",
|
|
180
|
+
message: "The device code expired before approval.",
|
|
181
|
+
hint: "Run 'run402 login --device' to get a fresh code.",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
fail({ code: "LOGIN_FAILED", message: `Unexpected device poll result: ${result.kind}` });
|
|
185
|
+
}
|
|
186
|
+
fail({
|
|
187
|
+
code: "LOGIN_TIMEOUT",
|
|
188
|
+
message: "Timed out waiting for browser approval.",
|
|
189
|
+
hint: "Run 'run402 login --device' to try again.",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function run(args = []) {
|
|
194
|
+
args = normalizeArgv(args);
|
|
195
|
+
if (hasHelp(args)) {
|
|
196
|
+
console.log(HELP);
|
|
197
|
+
process.exit(0);
|
|
198
|
+
}
|
|
199
|
+
assertKnownFlags(args, ["--help", "-h", "--no-open", "--device"]);
|
|
200
|
+
const extra = positionalArgs(args, []);
|
|
201
|
+
if (extra.length > 0) {
|
|
202
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for login: ${extra[0]}`, hint: "Use `run402 login [--device] [--no-open]`." });
|
|
203
|
+
}
|
|
204
|
+
const noOpen = args.includes("--no-open");
|
|
205
|
+
if (args.includes("--device")) return deviceLogin({ noOpen });
|
|
206
|
+
return loopbackLogin({ noOpen });
|
|
207
|
+
}
|
package/lib/logout.mjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `run402 logout` — end the sign-in session server-side and clear the local
|
|
3
|
+
* session and write-approval caches. See sign-in.mjs.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { fail } from "./sdk-errors.mjs";
|
|
7
|
+
import { getSdk } from "./sdk.mjs";
|
|
8
|
+
import { normalizeArgv, hasHelp, assertKnownFlags, positionalArgs } from "./argparse.mjs";
|
|
9
|
+
import {
|
|
10
|
+
loadLiveControlPlaneSession,
|
|
11
|
+
clearControlPlaneSession,
|
|
12
|
+
clearRetiredSessionCaches,
|
|
13
|
+
} from "../core-dist/control-plane-session.js";
|
|
14
|
+
import { clearApprovals } from "../core-dist/write-approvals.js";
|
|
15
|
+
|
|
16
|
+
const HELP = `run402 logout — end your sign-in session
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
run402 logout
|
|
20
|
+
|
|
21
|
+
Revokes the cached sign-in session on the gateway, then deletes it and every
|
|
22
|
+
cached write approval from this machine. The local cache is cleared even when
|
|
23
|
+
the revoke cannot reach the gateway. A wallet is not affected.
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export async function run(args = []) {
|
|
27
|
+
args = normalizeArgv(args);
|
|
28
|
+
if (hasHelp(args)) {
|
|
29
|
+
console.log(HELP);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
assertKnownFlags(args, ["--help", "-h"]);
|
|
33
|
+
const extra = positionalArgs(args, []);
|
|
34
|
+
if (extra.length > 0) {
|
|
35
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for logout: ${extra[0]}`, hint: "Use `run402 logout`." });
|
|
36
|
+
}
|
|
37
|
+
const session = loadLiveControlPlaneSession();
|
|
38
|
+
let revoked = false;
|
|
39
|
+
if (session) {
|
|
40
|
+
try {
|
|
41
|
+
await getSdk().session.revoke({ token: session.control_plane_session_token });
|
|
42
|
+
revoked = true;
|
|
43
|
+
} catch {
|
|
44
|
+
// Best-effort: a failed server revoke (expired token, offline) must not
|
|
45
|
+
// block clearing the local cache. The local token is removed regardless.
|
|
46
|
+
revoked = false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
clearControlPlaneSession();
|
|
50
|
+
clearApprovals();
|
|
51
|
+
clearRetiredSessionCaches();
|
|
52
|
+
console.log(JSON.stringify({ revoked, cleared: true }));
|
|
53
|
+
}
|
package/lib/logs.mjs
CHANGED
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
const HELP = `run402 logs — Fetch function logs by request id
|
|
34
34
|
|
|
35
35
|
Usage:
|
|
36
|
-
run402 logs --request-id <
|
|
37
|
-
run402 logs --function <name> [--project <
|
|
36
|
+
run402 logs --request-id <request_id> [<function> | --function <name>] [--project <project_id>] [options]
|
|
37
|
+
run402 logs --function <name> [--project <project_id>] [options]
|
|
38
38
|
|
|
39
39
|
Required (one of):
|
|
40
|
-
--request-id <
|
|
40
|
+
--request-id <request_id> A req_... id (the x-run402-request-id response header),
|
|
41
41
|
or a fnrun_... / fnatt_... durable-run id. Without
|
|
42
42
|
--function, every function in the project is scanned.
|
|
43
43
|
--function <name> Limit to one function. Alone (no --request-id) this
|
|
@@ -45,7 +45,7 @@ Required (one of):
|
|
|
45
45
|
<function> means the same thing.
|
|
46
46
|
|
|
47
47
|
Optional:
|
|
48
|
-
--project <
|
|
48
|
+
--project <project_id> Project id (default: \$RUN402_PROJECT_ID, else the active project)
|
|
49
49
|
--tail <n> Max entries per function BEFORE the origin filter (default 100, max 1000)
|
|
50
50
|
--since <ts> ISO timestamp or epoch ms; only entries at or after this
|
|
51
51
|
--app Only the function's own output (default). Lambda runtime
|
|
@@ -77,7 +77,7 @@ Tip: the request id appears in:
|
|
|
77
77
|
- The 'x-run402-request-id' response header on every function response
|
|
78
78
|
- The 'requestId' field of any R402_SSR_RUNTIME_ERROR envelope
|
|
79
79
|
- The 'request_id' field in deploy / cache invalidate result envelopes
|
|
80
|
-
- The 'samples' of 'run402 errors' (each sample names a runnable logs command)
|
|
80
|
+
- The 'samples' of 'run402 errors list' (each sample names a runnable logs command)
|
|
81
81
|
`;
|
|
82
82
|
|
|
83
83
|
const VALUE_FLAGS = ["--request-id", "--function", "--project", "--tail", "--since"];
|
|
@@ -103,7 +103,7 @@ export async function run(sub, args = []) {
|
|
|
103
103
|
fail({
|
|
104
104
|
code: "BAD_USAGE",
|
|
105
105
|
message: `Unexpected argument: ${positionals[1]}`,
|
|
106
|
-
hint: "run402 logs [<function>] --request-id <
|
|
106
|
+
hint: "run402 logs [<function>] --request-id <request_id> [--project <project_id>]",
|
|
107
107
|
details: { argument: positionals[1] },
|
|
108
108
|
});
|
|
109
109
|
}
|
|
@@ -119,7 +119,7 @@ export async function run(sub, args = []) {
|
|
|
119
119
|
if (!requestId && !fnName) {
|
|
120
120
|
fail({
|
|
121
121
|
code: "BAD_USAGE",
|
|
122
|
-
message: "Missing --request-id <
|
|
122
|
+
message: "Missing --request-id <request_id> (or --function <name> for a plain tail).",
|
|
123
123
|
hint: "Pass the request id from the 'x-run402-request-id' response header.",
|
|
124
124
|
});
|
|
125
125
|
}
|
|
@@ -130,7 +130,7 @@ export async function run(sub, args = []) {
|
|
|
130
130
|
fail({
|
|
131
131
|
code: "BAD_USAGE",
|
|
132
132
|
message: "Missing project id.",
|
|
133
|
-
hint: "Pass --project <
|
|
133
|
+
hint: "Pass --project <project_id>, set RUN402_PROJECT_ID, or 'run402 projects use <project_id>'.",
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
|
package/lib/messages.mjs
CHANGED
|
@@ -42,15 +42,15 @@ const ROOM_FLAGS = ["--project", "--org", "--room"];
|
|
|
42
42
|
const HELP = `run402 messages — room-visible messages between agents
|
|
43
43
|
|
|
44
44
|
Usage:
|
|
45
|
-
run402 messages send <body> [--to <names>] [--ack] [--thread <
|
|
46
|
-
run402 messages list [--unread] [--cursor <mcr_...>] [--thread <
|
|
47
|
-
run402 messages wait [--addressed-to me] [--thread <
|
|
45
|
+
run402 messages send <body> [--to <names>] [--ack] [--thread <thread>]
|
|
46
|
+
run402 messages list [--unread] [--cursor <mcr_...>] [--thread <thread>]
|
|
47
|
+
run402 messages wait [--addressed-to me] [--thread <thread>] [--timeout <s>] [--cursor <mcr_...>]
|
|
48
48
|
run402 messages get <message_id>
|
|
49
49
|
run402 messages ack <message_id>
|
|
50
50
|
|
|
51
51
|
Addressing (all subcommands):
|
|
52
|
-
--project <
|
|
53
|
-
--org <
|
|
52
|
+
--project <project_id> That project's DEFAULT room (the room key IS the project id)
|
|
53
|
+
--org <org_id> --room <key> A named org room
|
|
54
54
|
(omit both) Resolved from RUN402_ROOM, a .run402.json binding, or the
|
|
55
55
|
wallet profile's selected org
|
|
56
56
|
|
package/lib/next-actions.mjs
CHANGED
|
@@ -35,7 +35,7 @@ export function retryAction(command, why) {
|
|
|
35
35
|
export function initializeWalletAction() {
|
|
36
36
|
return nextAction("initialize_wallet", {
|
|
37
37
|
command: "run402 init",
|
|
38
|
-
why: "Create and fund
|
|
38
|
+
why: "Create and fund a local wallet, then retry.",
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -56,54 +56,54 @@ export function selectProjectAction() {
|
|
|
56
56
|
export function setTierAction(tier = "prototype") {
|
|
57
57
|
return nextAction("renew_tier", {
|
|
58
58
|
command: `run402 tier set ${tier}`,
|
|
59
|
-
why: "
|
|
59
|
+
why: "Set a tier for the organization (prototype is free), then retry.",
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function deployAction() {
|
|
64
64
|
return nextAction("deploy", {
|
|
65
|
-
command: "run402 deploy
|
|
66
|
-
why: "
|
|
65
|
+
command: "run402 deploy --manifest app.json",
|
|
66
|
+
why: "Deploy your release manifest.",
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* The cold-start deploy when the account holds no tier yet: `run402 up -y`
|
|
72
|
-
*
|
|
72
|
+
* sets the prototype tier itself as part of the first deploy, so `init`
|
|
73
73
|
* hands the agent ONE command instead of `tier set` + a separate deploy.
|
|
74
74
|
* `tier set prototype` stays named as the standalone alternative.
|
|
75
75
|
*/
|
|
76
76
|
export function upDeployAction() {
|
|
77
77
|
return nextAction("deploy", {
|
|
78
78
|
command: "run402 up -y",
|
|
79
|
-
why: "Deploy with run402 up -y — it
|
|
79
|
+
why: "Deploy with run402 up -y — it sets the prototype tier (free on testnet) as part of the first deploy. Or set it separately: run402 tier set prototype.",
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* `repos create` (and `gitvault init`) on an org with no
|
|
84
|
+
* `repos create` (and `gitvault init`) on an org with no slug set: the
|
|
85
85
|
* response's `address: null` had no pointer to WHY, or to the named-addressing
|
|
86
86
|
* feature at all. Owner-only. Wording deliberately
|
|
87
87
|
* omits a price: the first slug per org is free, and renames/re-claims cost
|
|
88
88
|
* $1 — a gateway change lands the fee separately, so this stays true under
|
|
89
89
|
* both the old and new pricing rule.
|
|
90
90
|
*/
|
|
91
|
-
export function
|
|
92
|
-
return nextAction("
|
|
93
|
-
command: "run402
|
|
94
|
-
why: "This organization has no
|
|
91
|
+
export function setOrgSlugAction() {
|
|
92
|
+
return nextAction("set_org_slug", {
|
|
93
|
+
command: "run402 orgs slug <slug>",
|
|
94
|
+
why: "This organization has no slug set yet, so its repos have no run402::<slug>/<name> address. Owner-only.",
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* The org already has a slug, but this project's address-form repo name was
|
|
100
|
-
* not
|
|
101
|
-
* some other reason) — point at the explicit
|
|
100
|
+
* not set this time (a collision, or the best-effort set failed for
|
|
101
|
+
* some other reason) — point at the explicit set verb instead of leaving
|
|
102
102
|
* `address: null` unexplained.
|
|
103
103
|
*/
|
|
104
|
-
export function
|
|
105
|
-
return nextAction("
|
|
104
|
+
export function setRepoNameAction(projectId) {
|
|
105
|
+
return nextAction("set_repo_name", {
|
|
106
106
|
command: `run402 repos name <name> --project ${projectId}`,
|
|
107
|
-
why: "The owning organization has a slug, but this project has no
|
|
107
|
+
why: "The owning organization has a slug, but this project has no address-form name set yet.",
|
|
108
108
|
});
|
|
109
109
|
}
|
package/lib/org-context.mjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* organization named directly outranks one derived from a project named in that
|
|
12
12
|
* same class:
|
|
13
13
|
*
|
|
14
|
-
* 1. flag --org <org_id> else --project <
|
|
14
|
+
* 1. flag --org <org_id> else --project <project_id> -> its org
|
|
15
15
|
* 2. environment RUN402_ORG, else the org else RUN402_PROJECT_ID -> its org
|
|
16
16
|
* half of RUN402_ROOM
|
|
17
17
|
* 3. binding the `org` key of the nearest .run402(.local).json
|
|
@@ -57,7 +57,7 @@ export const ROOM_ENV = "RUN402_ROOM";
|
|
|
57
57
|
export const PROJECT_ENV = "RUN402_PROJECT_ID";
|
|
58
58
|
|
|
59
59
|
/** Command groups that must stay usable while selection is ambiguous. */
|
|
60
|
-
const CONFLICT_EXEMPT = new Set(["
|
|
60
|
+
const CONFLICT_EXEMPT = new Set(["orgs", "wallets", "doctor"]);
|
|
61
61
|
|
|
62
62
|
/** `org_id` is a UUID at every API boundary (`uuidParam` on every route). */
|
|
63
63
|
const ORG_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
@@ -78,7 +78,7 @@ function assertOrgIdShape(orgId, origin) {
|
|
|
78
78
|
fail({
|
|
79
79
|
code: "BAD_ORG_ID",
|
|
80
80
|
message: `Invalid organization id ${JSON.stringify(describeRejectedValue(orgId))} (from ${origin}).`,
|
|
81
|
-
hint: "An org_id is a UUID. Run 'run402
|
|
81
|
+
hint: "An org_id is a UUID. Run 'run402 orgs list' to see the organizations you belong to.",
|
|
82
82
|
details: { org_id: describeRejectedValue(orgId), origin },
|
|
83
83
|
next_actions: [listOrgsAction()],
|
|
84
84
|
});
|
|
@@ -118,7 +118,7 @@ async function readGitvaultPinnedOrgId(cwd) {
|
|
|
118
118
|
|
|
119
119
|
function listOrgsAction() {
|
|
120
120
|
return nextAction("edit_request", {
|
|
121
|
-
command: "run402
|
|
121
|
+
command: "run402 orgs list",
|
|
122
122
|
why: "List the organizations this wallet belongs to.",
|
|
123
123
|
});
|
|
124
124
|
}
|
|
@@ -126,7 +126,7 @@ function listOrgsAction() {
|
|
|
126
126
|
function orgRequiredActions() {
|
|
127
127
|
return [
|
|
128
128
|
nextAction("edit_request", {
|
|
129
|
-
command: "run402
|
|
129
|
+
command: "run402 orgs use <org_id>",
|
|
130
130
|
why: "Select a current organization for this wallet profile.",
|
|
131
131
|
}),
|
|
132
132
|
listOrgsAction(),
|
|
@@ -266,7 +266,7 @@ export async function resolveOrg(input = {}, opts = {}) {
|
|
|
266
266
|
// --- Class 4: profile state ----------------------------------------------
|
|
267
267
|
const selected = trimmed(coreGetActiveOrgId());
|
|
268
268
|
if (selected) {
|
|
269
|
-
return { orgId: assertOrgIdShape(selected, "
|
|
269
|
+
return { orgId: assertOrgIdShape(selected, "orgs use"), source: "profile", sourceDetail: "orgs use" };
|
|
270
270
|
}
|
|
271
271
|
const activeProject = trimmed(getActiveProjectId());
|
|
272
272
|
if (activeProject) {
|
|
@@ -278,7 +278,7 @@ export async function resolveOrg(input = {}, opts = {}) {
|
|
|
278
278
|
fail({
|
|
279
279
|
code: "ORG_REQUIRED",
|
|
280
280
|
message: "No organization specified and no current organization set.",
|
|
281
|
-
hint: `Pass --org <org_id>, set ${ORG_ENV}, bind this directory in .run402.json, or run: run402
|
|
281
|
+
hint: `Pass --org <org_id>, set ${ORG_ENV}, bind this directory in .run402.json, or run: run402 orgs use <org_id>`,
|
|
282
282
|
next_actions: orgRequiredActions(),
|
|
283
283
|
});
|
|
284
284
|
return null; // unreachable — fail() exits
|
|
@@ -301,17 +301,17 @@ export async function resolveOrgId(a, opts = {}) {
|
|
|
301
301
|
* Every Org-Scoped Command").
|
|
302
302
|
*
|
|
303
303
|
* `<org_id>` is optional sugar on every verb that acts on an organization —
|
|
304
|
-
* `
|
|
304
|
+
* `orgs get`, `orgs members add`, `billing link-wallet`, … A leading positional
|
|
305
305
|
* that IS an org id (a UUID) addresses that org; anything else is the verb's
|
|
306
306
|
* own next positional (a wallet, an email, a principal) and the org comes from
|
|
307
307
|
* the shared chain: `--org`, then `RUN402_ORG`, then the `.run402.json`
|
|
308
|
-
* binding, then `
|
|
309
|
-
* `run402
|
|
308
|
+
* binding, then `orgs use`. So inside a bound checkout the two-agent case reads
|
|
309
|
+
* `run402 orgs members add 0xB… --role developer` with nothing else to know.
|
|
310
310
|
*
|
|
311
311
|
* Naming the org twice with different values (positional AND `--org`) is
|
|
312
312
|
* `AMBIGUOUS_ORG`, never a silent pick — the same refusal the env-vs-binding
|
|
313
313
|
* pair gets. A non-org first positional with no chain answer fails
|
|
314
|
-
* `ORG_REQUIRED` and NAMES the rejected value, so `
|
|
314
|
+
* `ORG_REQUIRED` and NAMES the rejected value, so `orgs get foo` says why `foo`
|
|
315
315
|
* did not count rather than reporting a bare "no organization".
|
|
316
316
|
*
|
|
317
317
|
* Returns the org id with provenance plus the REMAINING positionals; bound
|
|
@@ -350,7 +350,7 @@ export async function takeOrgPositional(a, valueFlags = [], opts = {}) {
|
|
|
350
350
|
message: typeof first === "string"
|
|
351
351
|
? `No organization specified and no current organization set (${JSON.stringify(first)} is not an org_id — an org_id is a UUID).`
|
|
352
352
|
: "No organization specified and no current organization set.",
|
|
353
|
-
hint: `Pass --org <org_id> (or a leading <org_id> positional), set ${ORG_ENV}, bind this directory in .run402.json, or run: run402
|
|
353
|
+
hint: `Pass --org <org_id> (or a leading <org_id> positional), set ${ORG_ENV}, bind this directory in .run402.json, or run: run402 orgs use <org_id>`,
|
|
354
354
|
...(typeof first === "string" ? { details: { rejected_positional: first } } : {}),
|
|
355
355
|
next_actions: orgRequiredActions(),
|
|
356
356
|
});
|
|
@@ -388,7 +388,7 @@ export function getSelectedOrgId() {
|
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
/** Record the profile's selected organization. */
|
|
391
|
-
export function setSelectedOrgId(orgId, origin = "
|
|
391
|
+
export function setSelectedOrgId(orgId, origin = "orgs use") {
|
|
392
392
|
coreSetActiveOrgId(assertOrgIdShape(orgId, origin));
|
|
393
393
|
}
|
|
394
394
|
|