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/ai.mjs
CHANGED
|
@@ -24,7 +24,7 @@ Examples:
|
|
|
24
24
|
|
|
25
25
|
Notes:
|
|
26
26
|
- [project_id] defaults to the active project when omitted (set with
|
|
27
|
-
'run402 projects use <
|
|
27
|
+
'run402 projects use <project_id>'). Project IDs start with 'prj_'; any first
|
|
28
28
|
positional that doesn't is treated as the next argument instead.
|
|
29
29
|
- translate requires the AI Translation add-on on the project
|
|
30
30
|
- moderate is free for all projects
|
|
@@ -47,7 +47,7 @@ Options:
|
|
|
47
47
|
--to <lang> Target language code (required, e.g. es, ja, fr)
|
|
48
48
|
--from <lang> Source language code (optional; auto-detected if omitted)
|
|
49
49
|
--context <hint> Optional translation hint (e.g. "formal business email")
|
|
50
|
-
--project <
|
|
50
|
+
--project <project_id> Project ID (alternative to the positional argument)
|
|
51
51
|
|
|
52
52
|
Notes:
|
|
53
53
|
- Requires the AI Translation add-on on the project
|
|
@@ -71,7 +71,7 @@ Arguments:
|
|
|
71
71
|
<text> Text to check (quote it to preserve spaces)
|
|
72
72
|
|
|
73
73
|
Options:
|
|
74
|
-
--project <
|
|
74
|
+
--project <project_id> Project ID (alternative to the positional argument)
|
|
75
75
|
|
|
76
76
|
Notes:
|
|
77
77
|
- Free for all projects; uses the project's service key
|
|
@@ -91,7 +91,7 @@ Arguments:
|
|
|
91
91
|
Must start with 'prj_'; any other first positional is an error.
|
|
92
92
|
|
|
93
93
|
Options:
|
|
94
|
-
--project <
|
|
94
|
+
--project <project_id> Project ID (alternative to the positional argument)
|
|
95
95
|
|
|
96
96
|
Notes:
|
|
97
97
|
- Reports translation word quota and usage; only meaningful with the
|
|
@@ -111,7 +111,7 @@ async function translate(args) {
|
|
|
111
111
|
args = normalizeArgv(args);
|
|
112
112
|
assertKnownFlags(args, TRANSLATE_VALUE_FLAGS, TRANSLATE_VALUE_FLAGS);
|
|
113
113
|
|
|
114
|
-
// --project <
|
|
114
|
+
// --project <project_id> wins over positional, mirroring previous behavior.
|
|
115
115
|
const projectOpt = flagValue(args, "--project");
|
|
116
116
|
const to = flagValue(args, "--to");
|
|
117
117
|
const from = flagValue(args, "--from");
|
package/lib/approve.mjs
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `run402 approve --action <capability> (--org <org_id> | --project <project_id>)`
|
|
3
|
+
* — mint a passkey-signed write approval scoped to one (action, target) so a
|
|
4
|
+
* person signed in without a wallet can provision, deploy, or write secrets.
|
|
5
|
+
* See sign-in.mjs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { fail } from "./sdk-errors.mjs";
|
|
9
|
+
import { normalizeArgv, hasHelp, assertKnownFlags, flagValue, positionalArgs } from "./argparse.mjs";
|
|
10
|
+
import { APPROVAL_ACTIONS, mintApproval } from "./sign-in.mjs";
|
|
11
|
+
|
|
12
|
+
const HELP = `run402 approve — mint a write approval for one action on one target
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
run402 approve --action <capability> (--org <org_id> | --project <project_id>) [--no-open]
|
|
16
|
+
|
|
17
|
+
A person signed in with 'run402 login' (no wallet) needs a write approval to
|
|
18
|
+
provision a project, deploy, or write secrets. It is signed with your passkey,
|
|
19
|
+
covers one action on one org or project, lasts 30 minutes idle (4 hours at
|
|
20
|
+
most), and dies with the sign-in session. It never counts as a step-up.
|
|
21
|
+
From an interactive terminal the CLI opens this ceremony for you when a write
|
|
22
|
+
needs it; agents and CI relay the command instead.
|
|
23
|
+
|
|
24
|
+
Actions:
|
|
25
|
+
org.project.create --org <org_id>
|
|
26
|
+
project.deploy --project <project_id>
|
|
27
|
+
project.secret.write --project <project_id>
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--no-open Do not open the browser; print the URL only.
|
|
31
|
+
|
|
32
|
+
Notes:
|
|
33
|
+
- Requires 'run402 login' (a device-grade session cannot approve).
|
|
34
|
+
- 'run402 whoami' lists the approvals cached on this machine.
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export async function run(args = []) {
|
|
38
|
+
args = normalizeArgv(args);
|
|
39
|
+
if (hasHelp(args)) {
|
|
40
|
+
console.log(HELP);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
const valueFlags = ["--action", "--org", "--project"];
|
|
44
|
+
assertKnownFlags(args, ["--help", "-h", "--no-open", ...valueFlags], valueFlags);
|
|
45
|
+
const extra = positionalArgs(args, valueFlags);
|
|
46
|
+
if (extra.length > 0) {
|
|
47
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for approve: ${extra[0]}`, hint: "Use `run402 approve --action <capability> (--org <org_id> | --project <project_id>)`." });
|
|
48
|
+
}
|
|
49
|
+
const action = flagValue(args, "--action");
|
|
50
|
+
const org = flagValue(args, "--org");
|
|
51
|
+
const project = flagValue(args, "--project");
|
|
52
|
+
|
|
53
|
+
if (!action || !APPROVAL_ACTIONS[action]) {
|
|
54
|
+
fail({
|
|
55
|
+
code: "BAD_FLAG",
|
|
56
|
+
message: `--action must be one of: ${Object.keys(APPROVAL_ACTIONS).join(", ")}`,
|
|
57
|
+
details: { flag: "--action", value: action, allowed: Object.keys(APPROVAL_ACTIONS) },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const scope = APPROVAL_ACTIONS[action];
|
|
61
|
+
if (scope === "org" && !org) fail({ code: "BAD_FLAG", message: `--org <org_id> is required for --action ${action}` });
|
|
62
|
+
if (scope === "project" && !project) fail({ code: "BAD_FLAG", message: `--project <project_id> is required for --action ${action}` });
|
|
63
|
+
if (scope === "org" && project) fail({ code: "BAD_FLAG", message: `--project is not valid for org-scoped --action ${action}; use --org` });
|
|
64
|
+
if (scope === "project" && org) fail({ code: "BAD_FLAG", message: `--org is not valid for project-scoped --action ${action}; use --project` });
|
|
65
|
+
|
|
66
|
+
const approval = await mintApproval({
|
|
67
|
+
action,
|
|
68
|
+
orgId: org ?? undefined,
|
|
69
|
+
projectId: project ?? undefined,
|
|
70
|
+
noOpen: args.includes("--no-open"),
|
|
71
|
+
});
|
|
72
|
+
console.log(
|
|
73
|
+
JSON.stringify({
|
|
74
|
+
approved: true,
|
|
75
|
+
action,
|
|
76
|
+
...(org ? { org_id: org } : {}),
|
|
77
|
+
...(project ? { project_id: project } : {}),
|
|
78
|
+
expires_at: new Date(approval.expires_at).toISOString(),
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
package/lib/apps.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { walletAuthHeaders, saveProject } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
import { assertAllowedValue, assertKnownFlags, flagValue, normalizeArgv, positionalArgs, resolveProjectSelector, failUnknownSubcommand } from "./argparse.mjs";
|
|
@@ -12,13 +12,13 @@ Subcommands:
|
|
|
12
12
|
browse [--tag <tag>] Browse public apps
|
|
13
13
|
fork <version_id> --name <name> [--subdomain <name>]
|
|
14
14
|
Fork a published app into your own project
|
|
15
|
-
publish [--project <
|
|
15
|
+
publish [--project <project_id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed]
|
|
16
16
|
Publish a project as an app
|
|
17
|
-
versions [--project <
|
|
17
|
+
versions [--project <project_id>] List published versions of a project
|
|
18
18
|
inspect <version_id> Inspect a published app version
|
|
19
|
-
update <version_id> [--project <
|
|
19
|
+
update <version_id> [--project <project_id>] [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed] [--no-fork]
|
|
20
20
|
Update a published version
|
|
21
|
-
delete <version_id> [--project <
|
|
21
|
+
delete <version_id> [--project <project_id>] Delete a published version
|
|
22
22
|
|
|
23
23
|
Legacy (still supported): the old positional forms keep working, e.g.
|
|
24
24
|
run402 apps fork <version_id> <name>
|
|
@@ -72,13 +72,13 @@ Examples:
|
|
|
72
72
|
publish: `run402 apps publish — Publish a project as an app
|
|
73
73
|
|
|
74
74
|
Usage:
|
|
75
|
-
run402 apps publish [--project <
|
|
75
|
+
run402 apps publish [--project <project_id>] [options]
|
|
76
76
|
|
|
77
77
|
Legacy (still supported):
|
|
78
78
|
run402 apps publish <project_id> [options]
|
|
79
79
|
|
|
80
80
|
Options (project):
|
|
81
|
-
--project <
|
|
81
|
+
--project <project_id> Project ID to publish (defaults to the active project)
|
|
82
82
|
|
|
83
83
|
Options:
|
|
84
84
|
--description <d> Human-readable description of the app
|
|
@@ -93,7 +93,7 @@ Examples:
|
|
|
93
93
|
update: `run402 apps update — Update a published version's metadata
|
|
94
94
|
|
|
95
95
|
Usage:
|
|
96
|
-
run402 apps update <version_id> [--project <
|
|
96
|
+
run402 apps update <version_id> [--project <project_id>] [options]
|
|
97
97
|
|
|
98
98
|
Legacy (still supported):
|
|
99
99
|
run402 apps update <project_id> <version_id> [options]
|
|
@@ -127,7 +127,7 @@ Examples:
|
|
|
127
127
|
versions: `run402 apps versions — List published versions of a project
|
|
128
128
|
|
|
129
129
|
Usage:
|
|
130
|
-
run402 apps versions [--project <
|
|
130
|
+
run402 apps versions [--project <project_id>]
|
|
131
131
|
|
|
132
132
|
Legacy (still supported):
|
|
133
133
|
run402 apps versions <project_id>
|
|
@@ -138,7 +138,7 @@ Examples:
|
|
|
138
138
|
delete: `run402 apps delete — Delete a published version
|
|
139
139
|
|
|
140
140
|
Usage:
|
|
141
|
-
run402 apps delete <version_id> [--project <
|
|
141
|
+
run402 apps delete <version_id> [--project <project_id>]
|
|
142
142
|
|
|
143
143
|
Legacy (still supported):
|
|
144
144
|
run402 apps delete <project_id> <version_id>
|
|
@@ -185,8 +185,8 @@ async function fork(versionId, name, args) {
|
|
|
185
185
|
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps fork: ${positionals[expected]}` });
|
|
186
186
|
}
|
|
187
187
|
const opts = { subdomain: flagValue(parsedArgs, "--subdomain") ?? undefined };
|
|
188
|
-
// Preserve the aggressive early exit when no
|
|
189
|
-
|
|
188
|
+
// Preserve the aggressive early exit when no local wallet is configured.
|
|
189
|
+
walletAuthHeaders("/fork/v1");
|
|
190
190
|
|
|
191
191
|
try {
|
|
192
192
|
const data = await getSdk().apps.fork({
|
package/lib/archives.mjs
CHANGED
|
@@ -1,18 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { assertKnownFlags, hasHelp, normalizeArgv, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
import { importArchiveToCore, inspectArchive, verifyArchive } from "#sdk/node";
|
|
5
|
+
import { getSdk } from "./sdk.mjs";
|
|
6
|
+
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
7
|
+
import { assertAllowedValue, assertKnownFlags, flagValue, hasHelp, normalizeArgv, parseIntegerFlag, positionalArgs, resolveProjectSelector, failUnknownSubcommand } from "./argparse.mjs";
|
|
8
|
+
|
|
9
|
+
const HELP = `run402 archives — portable Run402 project archives
|
|
6
10
|
|
|
7
11
|
Usage:
|
|
8
|
-
run402 archives
|
|
9
|
-
run402 archives
|
|
12
|
+
run402 archives create [<project_id>] [--project <project_id>] [--target cloud] [options]
|
|
13
|
+
run402 archives status [<project_id>] <archive_id> [--project <project_id>] [--target cloud] [--json]
|
|
14
|
+
run402 archives download [<project_id>] <archive_id> --output <file> [--project <project_id>] [--target cloud] [--json]
|
|
15
|
+
run402 archives inspect <archive_path> [--json]
|
|
16
|
+
run402 archives verify <archive_path> [--json]
|
|
17
|
+
run402 archives import <archive_path> --name <project_name> [--target core] [options]
|
|
18
|
+
|
|
19
|
+
--target names the Run402 deployment the command talks to: create, status, and
|
|
20
|
+
download export from Run402 Cloud (--target cloud, the default); import loads an
|
|
21
|
+
archive into a local Run402 Core (--target core, the default). inspect and verify
|
|
22
|
+
are local and offline and take no target. A leading prj_... positional selects
|
|
23
|
+
the project; --project defaults to the active project.
|
|
24
|
+
|
|
25
|
+
Canonical agent path:
|
|
26
|
+
run402 archives create <project_id> --target cloud \\
|
|
27
|
+
--scope portable-runtime-v1 --auth stubs --consistency pause-writes \\
|
|
28
|
+
--wait --output ./project.r402ar --json
|
|
29
|
+
run402 archives verify ./project.r402ar --json
|
|
30
|
+
run402 archives import ./project.r402ar --target core --name imported-project --env-file ./required.env --json
|
|
31
|
+
|
|
32
|
+
Options for create:
|
|
33
|
+
--scope <scope> Archive scope. v1 supports portable-runtime-v1.
|
|
34
|
+
--auth <mode> Auth export mode: stubs (default) or none.
|
|
35
|
+
--consistency <mode> pause-writes (default) or cloud_write_pause_v1.
|
|
36
|
+
--idempotency-key <key> Retry-safe creation key.
|
|
37
|
+
--wait Poll until the archive is ready.
|
|
38
|
+
--output <file> Save archive bytes. Implies --wait.
|
|
39
|
+
--poll-interval <ms> Poll interval while waiting (default 1000).
|
|
40
|
+
--timeout <ms> Wait timeout (default 600000).
|
|
41
|
+
--json Emit final JSON on stdout.
|
|
42
|
+
--json-stream Emit NDJSON progress events on stdout.
|
|
43
|
+
|
|
44
|
+
Options for import:
|
|
45
|
+
--name <name> New Core project name (default imported-project)
|
|
46
|
+
--env-file <path> Env file satisfying required archive secrets.
|
|
47
|
+
--secret KEY=VALUE Inline secret value; repeatable. Overrides --env-file.
|
|
48
|
+
--core-url <url> Core gateway URL (default RUN402_CORE_URL or http://127.0.0.1:4020)
|
|
49
|
+
--dry-run Verify and plan without creating a Core project.
|
|
50
|
+
--require-runnable Block import unless required secrets are supplied.
|
|
51
|
+
--json Emit final JSON.
|
|
52
|
+
--json-stream Emit NDJSON progress events and final result event.
|
|
10
53
|
|
|
11
54
|
Notes:
|
|
12
55
|
- Verification is local and offline. It does not require Cloud credentials.
|
|
13
56
|
- Archives are untrusted input; verify checks integrity and compatibility, not trust.
|
|
14
57
|
`;
|
|
15
58
|
|
|
59
|
+
const TARGETS = ["cloud", "core"];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Read --target and require the one deployment kind this verb talks to:
|
|
63
|
+
* Run402 Cloud exports archives, Run402 Core imports them.
|
|
64
|
+
*/
|
|
65
|
+
function requireTarget(args, verb, expected) {
|
|
66
|
+
const target = flagValue(args, "--target") ?? expected;
|
|
67
|
+
assertAllowedValue(target, TARGETS, "--target");
|
|
68
|
+
if (target !== expected) {
|
|
69
|
+
fail({
|
|
70
|
+
code: "BAD_FLAG",
|
|
71
|
+
message: `archives ${verb} runs against --target ${expected}; --target ${target} does not ${expected === "cloud" ? "export archives" : "import archives"}.`,
|
|
72
|
+
details: { flag: "--target", value: target, expected },
|
|
73
|
+
hint: expected === "cloud"
|
|
74
|
+
? "Export with --target cloud, then load the file with: run402 archives import <archive_path> --target core"
|
|
75
|
+
: "Import into Run402 Core with --target core; export from Run402 Cloud with: run402 archives create --target cloud",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return target;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const CREATE_FLAG_VALUES = [
|
|
82
|
+
"--project",
|
|
83
|
+
"--target",
|
|
84
|
+
"--scope",
|
|
85
|
+
"--auth",
|
|
86
|
+
"--consistency",
|
|
87
|
+
"--idempotency-key",
|
|
88
|
+
"--output",
|
|
89
|
+
"--poll-interval",
|
|
90
|
+
"--timeout",
|
|
91
|
+
];
|
|
92
|
+
const CREATE_FLAGS = new Set([
|
|
93
|
+
...CREATE_FLAG_VALUES,
|
|
94
|
+
"--wait",
|
|
95
|
+
"--json",
|
|
96
|
+
"--json-stream",
|
|
97
|
+
"--help",
|
|
98
|
+
"-h",
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
const IMPORT_FLAG_VALUES = ["--target", "--name", "--env-file", "--secret", "--core-url"];
|
|
102
|
+
const IMPORT_FLAGS = new Set([...IMPORT_FLAG_VALUES, "--dry-run", "--require-runnable", "--json", "--json-stream", "--help", "-h"]);
|
|
103
|
+
|
|
16
104
|
export async function run(sub, rawArgs = []) {
|
|
17
105
|
const all = [sub, ...rawArgs].filter(Boolean);
|
|
18
106
|
if (hasHelp(all)) {
|
|
@@ -20,18 +108,206 @@ export async function run(sub, rawArgs = []) {
|
|
|
20
108
|
return;
|
|
21
109
|
}
|
|
22
110
|
switch (sub) {
|
|
111
|
+
case "create": return create(rawArgs);
|
|
112
|
+
case "status": return status(rawArgs);
|
|
113
|
+
case "download": return download(rawArgs);
|
|
23
114
|
case "inspect": return inspect(rawArgs);
|
|
24
115
|
case "verify": return verify(rawArgs);
|
|
116
|
+
case "import": return importProject(rawArgs);
|
|
25
117
|
default:
|
|
26
118
|
failUnknownSubcommand("archives", sub);
|
|
27
119
|
}
|
|
28
120
|
}
|
|
29
121
|
|
|
122
|
+
async function create(rawArgs) {
|
|
123
|
+
const args = normalizeArgv(rawArgs);
|
|
124
|
+
assertKnownFlags(args, [...CREATE_FLAGS], CREATE_FLAG_VALUES);
|
|
125
|
+
requireTarget(args, "create", "cloud");
|
|
126
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: CREATE_FLAG_VALUES });
|
|
127
|
+
const extraPos = positionalArgs(rest, CREATE_FLAG_VALUES);
|
|
128
|
+
if (extraPos.length > 0) {
|
|
129
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for archives create: ${extraPos[0]}` });
|
|
130
|
+
}
|
|
131
|
+
const scope = flagValue(args, "--scope") ?? "portable-runtime-v1";
|
|
132
|
+
const auth = flagValue(args, "--auth") ?? "stubs";
|
|
133
|
+
const consistency = flagValue(args, "--consistency") ?? "pause-writes";
|
|
134
|
+
assertAllowedValue(scope, ["portable-runtime-v1"], "--scope");
|
|
135
|
+
assertAllowedValue(auth, ["stubs", "none"], "--auth");
|
|
136
|
+
assertAllowedValue(consistency, ["pause-writes", "cloud_write_pause_v1"], "--consistency");
|
|
137
|
+
|
|
138
|
+
const output = flagValue(args, "--output");
|
|
139
|
+
const wait = args.includes("--wait") || Boolean(output);
|
|
140
|
+
const jsonStream = args.includes("--json-stream");
|
|
141
|
+
const idempotencyKey = flagValue(args, "--idempotency-key") ?? undefined;
|
|
142
|
+
const pollIntervalMs = parseIntegerFlag("--poll-interval", flagValue(args, "--poll-interval"), { min: 100, def: 1000 });
|
|
143
|
+
const timeoutMs = parseIntegerFlag("--timeout", flagValue(args, "--timeout"), { min: 1000, def: 600000 });
|
|
144
|
+
const emit = (event) => {
|
|
145
|
+
if (jsonStream) console.log(JSON.stringify(event));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const sdk = getSdk();
|
|
150
|
+
const created = await sdk.archives.create(projectId, {
|
|
151
|
+
scope,
|
|
152
|
+
auth,
|
|
153
|
+
consistency,
|
|
154
|
+
idempotencyKey,
|
|
155
|
+
});
|
|
156
|
+
emit(progressEvent("archive_export_created", "create", projectId, created));
|
|
157
|
+
|
|
158
|
+
let archive = created;
|
|
159
|
+
let outputPath = null;
|
|
160
|
+
let bytesWritten = 0;
|
|
161
|
+
if (wait) {
|
|
162
|
+
archive = created.status === "ready"
|
|
163
|
+
? created
|
|
164
|
+
: await sdk.archives.wait(projectId, created.archive_id, {
|
|
165
|
+
pollIntervalMs,
|
|
166
|
+
timeoutMs,
|
|
167
|
+
onProgress: emit,
|
|
168
|
+
});
|
|
169
|
+
if (archive.status !== "ready") {
|
|
170
|
+
const result = finalCreateResult({ projectId, created, archive, outputPath, bytesWritten });
|
|
171
|
+
printJson(result, jsonStream);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
if (output) {
|
|
175
|
+
const download = await sdk.archives.download(projectId, archive.archive_id);
|
|
176
|
+
outputPath = resolve(output);
|
|
177
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
178
|
+
writeFileSync(outputPath, download.bytes);
|
|
179
|
+
bytesWritten = download.bytes.byteLength;
|
|
180
|
+
emit({
|
|
181
|
+
...progressEvent("archive_export_downloaded", "download", projectId, archive),
|
|
182
|
+
context: { output_path: outputPath, bytes_written: bytesWritten },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = finalCreateResult({ projectId, created, archive, outputPath, bytesWritten });
|
|
188
|
+
if (jsonStream) {
|
|
189
|
+
console.log(JSON.stringify({
|
|
190
|
+
event: "archive_export_complete",
|
|
191
|
+
stage: "complete",
|
|
192
|
+
resource_type: "project_archive",
|
|
193
|
+
resource_id: archive.archive_id,
|
|
194
|
+
project_id: projectId,
|
|
195
|
+
status: archive.status === "ready" ? "complete" : archive.status,
|
|
196
|
+
completed_units: archive.status === "ready" ? 1 : 0,
|
|
197
|
+
total_units: 1,
|
|
198
|
+
code: null,
|
|
199
|
+
message: archive.status === "ready" ? "Archive export complete." : "Archive export did not complete.",
|
|
200
|
+
next_action: archive.next_action,
|
|
201
|
+
retryable: false,
|
|
202
|
+
result,
|
|
203
|
+
}));
|
|
204
|
+
} else {
|
|
205
|
+
console.log(JSON.stringify(result, null, 2));
|
|
206
|
+
}
|
|
207
|
+
if (archive.status !== "ready") process.exit(1);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
reportSdkError(err);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function download(rawArgs) {
|
|
214
|
+
const args = normalizeArgv(rawArgs);
|
|
215
|
+
assertKnownFlags(args, ["--project", "--target", "--output", "--json", "--help", "-h"], ["--project", "--target", "--output"]);
|
|
216
|
+
requireTarget(args, "download", "cloud");
|
|
217
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project", "--target", "--output"] });
|
|
218
|
+
const pos = positionalArgs(rest, ["--project", "--target", "--output"]);
|
|
219
|
+
const [archiveId] = pos;
|
|
220
|
+
const output = flagValue(args, "--output");
|
|
221
|
+
if (!archiveId || pos.length > 1 || !output) {
|
|
222
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 archives download [<project_id>] <archive_id> --output <file> [--project <project_id>] [--target cloud] [--json]" });
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const download = await getSdk().archives.download(projectId, archiveId);
|
|
226
|
+
const outputPath = resolve(output);
|
|
227
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
228
|
+
writeFileSync(outputPath, download.bytes);
|
|
229
|
+
console.log(JSON.stringify({
|
|
230
|
+
ok: true,
|
|
231
|
+
project_id: projectId,
|
|
232
|
+
archive_id: archiveId,
|
|
233
|
+
output_path: outputPath,
|
|
234
|
+
bytes_written: download.bytes.byteLength,
|
|
235
|
+
sha256: download.archive.sha256,
|
|
236
|
+
verify_command: `run402 archives verify ${JSON.stringify(outputPath)} --json`,
|
|
237
|
+
import_command: `run402 archives import ${JSON.stringify(outputPath)} --target core --name imported-project --env-file ./required.env --json`,
|
|
238
|
+
archive: download.archive,
|
|
239
|
+
}, null, 2));
|
|
240
|
+
} catch (err) {
|
|
241
|
+
reportSdkError(err);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function status(rawArgs) {
|
|
246
|
+
const args = normalizeArgv(rawArgs);
|
|
247
|
+
assertKnownFlags(args, ["--project", "--target", "--json", "--help", "-h"], ["--project", "--target"]);
|
|
248
|
+
requireTarget(args, "status", "cloud");
|
|
249
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project", "--target"] });
|
|
250
|
+
const pos = positionalArgs(rest, ["--project", "--target"]);
|
|
251
|
+
const [archiveId] = pos;
|
|
252
|
+
if (!archiveId || pos.length > 1) {
|
|
253
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 archives status [<project_id>] <archive_id> [--project <project_id>] [--target cloud] [--json]" });
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const archive = await getSdk().archives.get(projectId, archiveId);
|
|
257
|
+
console.log(JSON.stringify({ archive }, null, 2));
|
|
258
|
+
} catch (err) {
|
|
259
|
+
reportSdkError(err);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function finalCreateResult({ projectId, created, archive, outputPath, bytesWritten }) {
|
|
264
|
+
return {
|
|
265
|
+
ok: archive.status === "ready",
|
|
266
|
+
project_id: projectId,
|
|
267
|
+
archive_id: archive.archive_id,
|
|
268
|
+
operation_id: archive.operation_id,
|
|
269
|
+
created_archive_id: created.archive_id,
|
|
270
|
+
archive_status: archive.status,
|
|
271
|
+
output_path: outputPath,
|
|
272
|
+
bytes_written: bytesWritten,
|
|
273
|
+
sha256: archive.sha256,
|
|
274
|
+
byte_count: archive.byte_count,
|
|
275
|
+
expires_at: archive.expires_at,
|
|
276
|
+
verify_command: outputPath ? `run402 archives verify ${JSON.stringify(outputPath)} --json` : null,
|
|
277
|
+
import_command: outputPath ? `run402 archives import ${JSON.stringify(outputPath)} --target core --name imported-project --env-file ./required.env --json` : null,
|
|
278
|
+
next_action: archive.next_action,
|
|
279
|
+
portability_report: archive.portability_report,
|
|
280
|
+
export_report: archive.export_report,
|
|
281
|
+
archive,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function progressEvent(event, stage, projectId, archive) {
|
|
286
|
+
return {
|
|
287
|
+
event,
|
|
288
|
+
stage,
|
|
289
|
+
resource_type: "project_archive",
|
|
290
|
+
resource_id: archive.archive_id,
|
|
291
|
+
project_id: projectId,
|
|
292
|
+
status: archive.status,
|
|
293
|
+
completed_units: archive.status === "ready" || archive.status === "failed" || archive.status === "expired" ? 1 : 0,
|
|
294
|
+
total_units: 1,
|
|
295
|
+
code: archive.status === "failed" ? archive.error?.code ?? "ARCHIVE_EXPORT_FAILED" : null,
|
|
296
|
+
message: `Archive export status: ${archive.status}`,
|
|
297
|
+
next_action: archive.next_action,
|
|
298
|
+
retryable: archive.status === "running",
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function printJson(result, alreadyStreamed) {
|
|
303
|
+
if (!alreadyStreamed) console.log(JSON.stringify(result, null, 2));
|
|
304
|
+
}
|
|
305
|
+
|
|
30
306
|
async function inspect(rawArgs) {
|
|
31
307
|
const args = normalizeArgv(rawArgs);
|
|
32
308
|
assertKnownFlags(args, ["--json", "--help", "-h"], []);
|
|
33
309
|
const archivePath = positionalArgs(args, [])[0];
|
|
34
|
-
if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives inspect <
|
|
310
|
+
if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives inspect <archive_path> [--json]" });
|
|
35
311
|
try {
|
|
36
312
|
const result = await inspectArchive(archivePath);
|
|
37
313
|
console.log(JSON.stringify({ archive: result }, null, 2));
|
|
@@ -44,7 +320,7 @@ async function verify(rawArgs) {
|
|
|
44
320
|
const args = normalizeArgv(rawArgs);
|
|
45
321
|
assertKnownFlags(args, ["--json", "--help", "-h"], []);
|
|
46
322
|
const archivePath = positionalArgs(args, [])[0];
|
|
47
|
-
if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives verify <
|
|
323
|
+
if (!archivePath) fail({ code: "BAD_USAGE", message: "Usage: run402 archives verify <archive_path> [--json]" });
|
|
48
324
|
try {
|
|
49
325
|
const result = await verifyArchive(archivePath);
|
|
50
326
|
console.log(JSON.stringify({ ok: result.ok, verified: result.ok, archive: result }, null, 2));
|
|
@@ -53,3 +329,90 @@ async function verify(rawArgs) {
|
|
|
53
329
|
reportSdkError(err);
|
|
54
330
|
}
|
|
55
331
|
}
|
|
332
|
+
|
|
333
|
+
async function importProject(rawArgs) {
|
|
334
|
+
const args = normalizeArgv(rawArgs);
|
|
335
|
+
assertKnownFlags(args, [...IMPORT_FLAGS], IMPORT_FLAG_VALUES);
|
|
336
|
+
requireTarget(args, "import", "core");
|
|
337
|
+
const archivePath = positionalArgs(args, IMPORT_FLAG_VALUES)[0];
|
|
338
|
+
if (!archivePath) {
|
|
339
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 archives import <archive_path> --name <project_name> [--target core] [options]" });
|
|
340
|
+
}
|
|
341
|
+
const jsonStream = args.includes("--json-stream");
|
|
342
|
+
const secretValues = parseSecrets(args);
|
|
343
|
+
const name = flagValue(args, "--name") ?? "imported-project";
|
|
344
|
+
const coreUrl = flagValue(args, "--core-url") ?? undefined;
|
|
345
|
+
const startedEvent = {
|
|
346
|
+
event: "core_archive_import_started",
|
|
347
|
+
stage: "verify",
|
|
348
|
+
resource_type: "project_archive",
|
|
349
|
+
resource_id: archivePath,
|
|
350
|
+
status: "running",
|
|
351
|
+
completed_units: 0,
|
|
352
|
+
total_units: 1,
|
|
353
|
+
code: null,
|
|
354
|
+
message: "Verifying archive locally before Core import.",
|
|
355
|
+
next_action: { type: "none" },
|
|
356
|
+
retryable: false,
|
|
357
|
+
context: { archive_path: archivePath, core_url: coreUrl ?? null, project_name: name },
|
|
358
|
+
};
|
|
359
|
+
if (jsonStream) console.log(JSON.stringify(startedEvent));
|
|
360
|
+
try {
|
|
361
|
+
const result = await importArchiveToCore({
|
|
362
|
+
archivePath,
|
|
363
|
+
name,
|
|
364
|
+
coreUrl,
|
|
365
|
+
envFile: flagValue(args, "--env-file") ?? undefined,
|
|
366
|
+
secretValues,
|
|
367
|
+
dryRun: args.includes("--dry-run"),
|
|
368
|
+
requireRunnable: args.includes("--require-runnable"),
|
|
369
|
+
});
|
|
370
|
+
if (jsonStream) {
|
|
371
|
+
console.log(JSON.stringify({
|
|
372
|
+
event: "core_archive_import_complete",
|
|
373
|
+
stage: "complete",
|
|
374
|
+
resource_type: "project_archive",
|
|
375
|
+
resource_id: archivePath,
|
|
376
|
+
status: result.status,
|
|
377
|
+
completed_units: result.status === "imported" || result.status === "dry_run" ? 1 : 0,
|
|
378
|
+
total_units: 1,
|
|
379
|
+
code: firstDiagnosticCode(result),
|
|
380
|
+
message: `Core archive import status: ${result.status}`,
|
|
381
|
+
next_action: result.next_action,
|
|
382
|
+
retryable: result.status === "failed" && result.diagnostics.some((d) => d.retryable),
|
|
383
|
+
result,
|
|
384
|
+
}));
|
|
385
|
+
} else {
|
|
386
|
+
console.log(JSON.stringify({ ok: result.status === "imported" || result.status === "dry_run", import: result }, null, 2));
|
|
387
|
+
}
|
|
388
|
+
if (result.status !== "imported" && result.status !== "dry_run") process.exit(1);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
reportSdkError(err);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function parseSecrets(args) {
|
|
395
|
+
const out = {};
|
|
396
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
397
|
+
if (args[i] !== "--secret") continue;
|
|
398
|
+
const value = args[i + 1];
|
|
399
|
+
if (!value || value.startsWith("--")) {
|
|
400
|
+
fail({ code: "BAD_FLAG", message: "--secret requires KEY=VALUE" });
|
|
401
|
+
}
|
|
402
|
+
const eq = value.indexOf("=");
|
|
403
|
+
if (eq <= 0) {
|
|
404
|
+
fail({ code: "BAD_FLAG", message: "--secret requires KEY=VALUE", details: { value } });
|
|
405
|
+
}
|
|
406
|
+
const key = value.slice(0, eq);
|
|
407
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
408
|
+
fail({ code: "BAD_FLAG", message: `Invalid secret env var name: ${key}` });
|
|
409
|
+
}
|
|
410
|
+
out[key] = value.slice(eq + 1);
|
|
411
|
+
i += 1;
|
|
412
|
+
}
|
|
413
|
+
return out;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function firstDiagnosticCode(result) {
|
|
417
|
+
return result.diagnostics.find((d) => d.severity === "blocking")?.code ?? null;
|
|
418
|
+
}
|
package/lib/argparse.mjs
CHANGED
|
@@ -318,11 +318,11 @@ export function resolvePositionalProject(args, opts = {}) {
|
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
// Resolve the project id for a project-scoped command from BOTH accepted
|
|
321
|
-
// forms — the canonical `--project <
|
|
321
|
+
// forms — the canonical `--project <project_id>` flag and the legacy leading
|
|
322
322
|
// positional `prj_...` — with active-project fallback (CLI-wide convention).
|
|
323
323
|
//
|
|
324
324
|
// Precedence:
|
|
325
|
-
// 1. explicit `--project <
|
|
325
|
+
// 1. explicit `--project <project_id>` (canonical)
|
|
326
326
|
// 2. a leading positional starting with "prj_" (legacy compat, no warning)
|
|
327
327
|
// 3. the active project (`resolveProjectId(null)`)
|
|
328
328
|
//
|
|
@@ -338,7 +338,7 @@ export function resolvePositionalProject(args, opts = {}) {
|
|
|
338
338
|
// requireRestPositional: only treat a leading `prj_` positional as the
|
|
339
339
|
// project selector when at least one more bare positional follows (counted
|
|
340
340
|
// with opts.valueFlags). Needed by commands whose OWN attribute is itself a
|
|
341
|
-
// project id (e.g. `branches renew <
|
|
341
|
+
// project id (e.g. `branches renew <branch_project_id>`).
|
|
342
342
|
export function resolveProjectSelector(args, opts = {}) {
|
|
343
343
|
const list = Array.isArray(args) ? [...args] : [];
|
|
344
344
|
let flagProject = null;
|
|
@@ -361,7 +361,7 @@ export function resolveProjectSelector(args, opts = {}) {
|
|
|
361
361
|
fail({
|
|
362
362
|
code: "BAD_USAGE",
|
|
363
363
|
message: `Conflicting project ids: --project ${flagProject} vs positional ${first}`,
|
|
364
|
-
hint: "Pass the project once — prefer --project <
|
|
364
|
+
hint: "Pass the project once — prefer --project <project_id>.",
|
|
365
365
|
details: { project_flag: flagProject, positional: first },
|
|
366
366
|
});
|
|
367
367
|
}
|
|
@@ -405,7 +405,7 @@ function closestFlag(flag, candidates) {
|
|
|
405
405
|
/**
|
|
406
406
|
* Known subcommands of a command family, derived from COMMAND_MANIFEST
|
|
407
407
|
* (never hand-maintained). `family` may be multi-word for nested groups
|
|
408
|
-
* (e.g. "
|
|
408
|
+
* (e.g. "deploy releases", "email webhooks").
|
|
409
409
|
*/
|
|
410
410
|
export function knownSubcommands(family) {
|
|
411
411
|
const familyWords = String(family).split(" ").filter(Boolean);
|