run402 4.93.2 → 4.94.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 +43 -41
- package/cli.mjs +34 -29
- 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 +1 -1
- package/lib/admin.mjs +1 -1
- package/lib/agent.mjs +20 -18
- package/lib/approve.mjs +81 -0
- package/lib/apps.mjs +3 -3
- package/lib/assets.mjs +2 -2
- package/lib/billing.mjs +6 -6
- package/lib/buzz-doctor.mjs +1 -1
- package/lib/buzz-notifications.mjs +1 -1
- package/lib/buzz.mjs +1 -1
- package/lib/buzz.test.mjs +1 -1
- package/lib/ci.mjs +4 -4
- package/lib/cold-start.mjs +21 -21
- package/lib/command-manifest.mjs +20 -34
- package/lib/config.mjs +24 -24
- package/lib/contacts.mjs +13 -13
- package/lib/contracts.mjs +1 -1
- package/lib/credentials.mjs +2 -2
- package/lib/daemon-path.mjs +1 -1
- package/lib/delegates.mjs +1 -1
- package/lib/deliveries.mjs +4 -4
- package/lib/deploy-rehearse-discovery.test.mjs +7 -7
- package/lib/deploy-v2.mjs +232 -184
- package/lib/deploy.mjs +21 -53
- package/lib/doctor-source-scan.mjs +1 -1
- package/lib/doctor.mjs +57 -57
- package/lib/escalations.mjs +1 -1
- package/lib/feedback.mjs +10 -10
- package/lib/gitvault-daemon.mjs +1 -1
- package/lib/image.mjs +3 -3
- package/lib/init.mjs +66 -66
- package/lib/lightning-wallet.mjs +28 -28
- package/lib/login.mjs +207 -0
- package/lib/logout.mjs +53 -0
- package/lib/next-actions.mjs +15 -15
- package/lib/org.mjs +100 -13
- package/lib/pay.mjs +1 -1
- package/lib/projects.mjs +26 -29
- package/lib/redeem.mjs +7 -8
- package/lib/remote-helper-session.mjs +12 -12
- package/lib/repos.mjs +62 -62
- package/lib/rooms.mjs +103 -67
- package/lib/sdk-errors.mjs +9 -4
- package/lib/sdk.mjs +3 -3
- package/lib/service.mjs +5 -5
- package/lib/session-proofs.mjs +21 -0
- package/lib/sign-in.mjs +296 -0
- package/lib/sites.mjs +8 -8
- package/lib/stats.mjs +2 -2
- package/lib/status.mjs +25 -25
- package/lib/subdomains.mjs +19 -19
- package/lib/subscriptions.mjs +8 -8
- package/lib/tier.mjs +29 -22
- package/lib/transfer.mjs +58 -85
- package/lib/up.mjs +7 -7
- package/lib/wallet-context.mjs +3 -3
- package/lib/wallet-context.test.mjs +3 -3
- package/lib/wallets.mjs +196 -31
- package/lib/webhook-secret.mjs +6 -6
- package/lib/whoami.mjs +75 -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 +1 -1
- package/sdk/dist/actions.d.ts.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 +19 -19
- package/sdk/dist/credentials.d.ts.map +1 -1
- package/sdk/dist/credentials.js +1 -1
- package/sdk/dist/errors.d.ts +24 -26
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +34 -37
- 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 +29 -16
- 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 +51 -120
- 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 +1 -1
- package/sdk/dist/namespaces/ai.js +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/credentials.types.d.ts +1 -1
- package/sdk/dist/namespaces/deploy.d.ts +1 -1
- package/sdk/dist/namespaces/deploy.js +5 -5
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +4 -4
- 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 +1 -1
- package/sdk/dist/namespaces/gitvault.crypto.d.ts +1 -1
- package/sdk/dist/namespaces/gitvault.d.ts +24 -24
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +109 -109
- 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 +43 -20
- 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 +74 -71
- 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 +36 -36
- package/sdk/dist/node/actions-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 +17 -16
- package/sdk/dist/node/credentials.d.ts.map +1 -1
- package/sdk/dist/node/credentials.js +28 -27
- package/sdk/dist/node/credentials.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-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/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/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 +3 -3
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +2 -2
- package/sdk/dist/scoped.js.map +1 -1
- package/core-dist/operator-session.js +0 -154
- package/lib/allowance.mjs +0 -355
- 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/init.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readWallet, saveWallet, loadKeyStore, configDir, configureApiBase, getActiveProjectId } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { fail } from "./sdk-errors.mjs";
|
|
4
4
|
import { upDeployAction, deployAction } from "./next-actions.mjs";
|
|
@@ -13,7 +13,7 @@ const USDC_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
|
13
13
|
const PATH_USD = "0x20c0000000000000000000000000000000000000";
|
|
14
14
|
const TEMPO_RPC = "https://rpc.moderato.tempo.xyz/";
|
|
15
15
|
|
|
16
|
-
const HELP = `run402 init — Set up
|
|
16
|
+
const HELP = `run402 init — Set up wallet, funding, and check tier status
|
|
17
17
|
|
|
18
18
|
Usage:
|
|
19
19
|
run402 init Set up with x402 (Base Sepolia) — default
|
|
@@ -21,19 +21,19 @@ Usage:
|
|
|
21
21
|
Configure a Run402 Core/API target for the active
|
|
22
22
|
profile without setting up Cloud payment.
|
|
23
23
|
run402 init mpp Set up with MPP (Tempo Moderato)
|
|
24
|
-
run402 init lightning Set up the Lightning
|
|
24
|
+
run402 init lightning Set up the Lightning wallet: a budgeted wallet
|
|
25
25
|
minted on Run402's Hub (custody: Run402), plus the
|
|
26
|
-
Base
|
|
26
|
+
Base wallet as the x402 fallback. Lightning
|
|
27
27
|
becomes the default rail for paid calls.
|
|
28
28
|
run402 init <rail> --switch-rail
|
|
29
29
|
Switch the persisted payment rail to <rail>.
|
|
30
|
-
Required when
|
|
30
|
+
Required when a wallet already exists on
|
|
31
31
|
the other rail; protects scripted re-runs from
|
|
32
32
|
silently flipping billing networks.
|
|
33
33
|
|
|
34
34
|
Options:
|
|
35
|
-
--voucher <code> Redeem a promo code after setup
|
|
36
|
-
organization. Never blocks setup: if the code is invalid,
|
|
35
|
+
--voucher <code> Redeem a promo code after setup into this
|
|
36
|
+
organization's allowance. Never blocks setup: if the code is invalid,
|
|
37
37
|
expired, already used, or the call fails, init warns and
|
|
38
38
|
finishes normally with 'voucher_error' in the summary.
|
|
39
39
|
Equivalent to running 'run402 redeem <code>' afterwards.
|
|
@@ -41,7 +41,7 @@ Options:
|
|
|
41
41
|
for a self-hosted Run402 Core Gateway, e.g.
|
|
42
42
|
http://my-core:4020.
|
|
43
43
|
--switch-rail Confirm switching the persisted payment rail. Re-running
|
|
44
|
-
init with the SAME rail as the existing
|
|
44
|
+
init with the SAME rail as the existing wallet is always
|
|
45
45
|
idempotent and does not need this flag.
|
|
46
46
|
--name <name> Set this principal's display name (1-64 chars) — what promotion
|
|
47
47
|
credit, \`run402 up\`'s room presence, and audit surfaces show
|
|
@@ -60,7 +60,7 @@ Options:
|
|
|
60
60
|
Output:
|
|
61
61
|
Stdout is a JSON summary { config_dir, wallet, rail, network, balances,
|
|
62
62
|
tier, projects_saved, active_project_id, next_step }. Progress lines
|
|
63
|
-
(Config /
|
|
63
|
+
(Config / Wallet / Balance / Tier / Next) go to stderr so a human
|
|
64
64
|
re-running interactively sees what's happening while a script piping stdout
|
|
65
65
|
to jq stays clean. The summary also carries { gitvault } (the scaffolded
|
|
66
66
|
remote), or { gitvault: null, gitvault_skipped } naming why no remote was
|
|
@@ -74,12 +74,12 @@ Output:
|
|
|
74
74
|
|
|
75
75
|
Steps (idempotent when re-run with the same rail; pass --switch-rail to change rails):
|
|
76
76
|
1. Creates config directory (~/.config/run402)
|
|
77
|
-
2. Creates agent
|
|
77
|
+
2. Creates agent wallet if none exists
|
|
78
78
|
3. Checks on-chain balance; requests faucet if zero
|
|
79
|
-
4. Shows current tier
|
|
79
|
+
4. Shows current tier and lease status
|
|
80
80
|
5. Lists local project count
|
|
81
|
-
6. Suggests next step (run402 up -y when no tier is held yet — it
|
|
82
|
-
the prototype tier as part of the first deploy — or deploy
|
|
81
|
+
6. Suggests next step (run402 up -y when no tier is held yet — it sets
|
|
82
|
+
the prototype tier as part of the first deploy — or run402 deploy)
|
|
83
83
|
|
|
84
84
|
Run this once to get started, or again to check your setup.
|
|
85
85
|
`;
|
|
@@ -246,7 +246,7 @@ export async function run(args = []) {
|
|
|
246
246
|
// scaffolder's help, not the rail-setup help. The rest of init's
|
|
247
247
|
// payment-rail setup is intentionally orthogonal — agents typically
|
|
248
248
|
// run `run402 init astro <dir>` to scaffold AND `run402 init` once
|
|
249
|
-
// to set up
|
|
249
|
+
// to set up wallet / tier.
|
|
250
250
|
if (args[0] === "astro") {
|
|
251
251
|
const { runInitAstro } = await import("./init-astro.mjs");
|
|
252
252
|
await runInitAstro(args.slice(1));
|
|
@@ -286,7 +286,7 @@ export async function run(args = []) {
|
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
// This branch configures a Core/API target and returns without setting up
|
|
289
|
-
//
|
|
289
|
+
// a wallet — there is no organization here to credit, and promo
|
|
290
290
|
// vouchers are a Run402 Cloud concept. Say so instead of accepting the
|
|
291
291
|
// flag and silently dropping it.
|
|
292
292
|
if (voucherCode) {
|
|
@@ -350,12 +350,12 @@ export async function run(args = []) {
|
|
|
350
350
|
const requestedRail = isLightning ? "lightning" : isMpp ? "mpp" : "x402";
|
|
351
351
|
const switchRailConfirmed = args.includes("--switch-rail");
|
|
352
352
|
|
|
353
|
-
const
|
|
354
|
-
if (
|
|
353
|
+
const existingWallet = readWallet();
|
|
354
|
+
if (existingWallet?.rail && existingWallet.rail !== requestedRail && !switchRailConfirmed) {
|
|
355
355
|
fail({
|
|
356
356
|
code: "RAIL_SWITCH_REQUIRES_CONFIRM",
|
|
357
|
-
message: `Already on rail '${
|
|
358
|
-
details: { current_rail:
|
|
357
|
+
message: `Already on rail '${existingWallet.rail}'. Pass --switch-rail to switch to '${requestedRail}'.`,
|
|
358
|
+
details: { current_rail: existingWallet.rail, requested_rail: requestedRail },
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
|
|
@@ -387,28 +387,28 @@ export async function run(args = []) {
|
|
|
387
387
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
388
388
|
line("Config", CONFIG_DIR);
|
|
389
389
|
|
|
390
|
-
// 2.
|
|
391
|
-
let
|
|
392
|
-
const previousRail =
|
|
393
|
-
if (!
|
|
390
|
+
// 2. Wallet
|
|
391
|
+
let localWallet = existingWallet;
|
|
392
|
+
const previousRail = localWallet?.rail;
|
|
393
|
+
if (!localWallet) {
|
|
394
394
|
const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
|
|
395
395
|
const privateKey = generatePrivateKey();
|
|
396
396
|
const account = privateKeyToAccount(privateKey);
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
line("
|
|
397
|
+
localWallet = { address: account.address, privateKey, created: new Date().toISOString(), funded: false, rail: requestedRail };
|
|
398
|
+
saveWallet(localWallet);
|
|
399
|
+
line("Wallet", `${short(localWallet.address)} (created)`);
|
|
400
400
|
} else {
|
|
401
401
|
// Update rail if switching (a wallet leaving Lightning keeps its pairing on disk until revoked).
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
|
|
402
|
+
if (localWallet.rail !== requestedRail) {
|
|
403
|
+
localWallet = { ...localWallet, rail: requestedRail };
|
|
404
|
+
saveWallet(localWallet);
|
|
405
405
|
}
|
|
406
|
-
line("
|
|
406
|
+
line("Wallet", short(localWallet.address));
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
const walletName = getActiveProfile();
|
|
410
410
|
const walletMeta = readMeta(walletName);
|
|
411
|
-
summary.wallet = { local_label: walletName, server_label: walletMeta?.label ?? null, address:
|
|
411
|
+
summary.wallet = { local_label: walletName, server_label: walletMeta?.label ?? null, address: localWallet.address };
|
|
412
412
|
summary.network = isLightning ? "bitcoin-mainnet" : isMpp ? "tempo-moderato" : "base-sepolia";
|
|
413
413
|
summary.rail = requestedRail;
|
|
414
414
|
|
|
@@ -432,7 +432,7 @@ export async function run(args = []) {
|
|
|
432
432
|
const client = createPublicClient({ chain: tempoModerato, transport: http() });
|
|
433
433
|
|
|
434
434
|
try {
|
|
435
|
-
const raw = await client.readContract({ address: PATH_USD, abi: USDC_ABI, functionName: "balanceOf", args: [
|
|
435
|
+
const raw = await client.readContract({ address: PATH_USD, abi: USDC_ABI, functionName: "balanceOf", args: [localWallet.address] });
|
|
436
436
|
balance = Number(raw);
|
|
437
437
|
} catch {}
|
|
438
438
|
|
|
@@ -442,7 +442,7 @@ export async function run(args = []) {
|
|
|
442
442
|
const res = await fetch(TEMPO_RPC, {
|
|
443
443
|
method: "POST",
|
|
444
444
|
headers: { "Content-Type": "application/json" },
|
|
445
|
-
body: JSON.stringify({ jsonrpc: "2.0", method: "tempo_fundAddress", params: [
|
|
445
|
+
body: JSON.stringify({ jsonrpc: "2.0", method: "tempo_fundAddress", params: [localWallet.address], id: 1 }),
|
|
446
446
|
});
|
|
447
447
|
const data = await res.json();
|
|
448
448
|
if (data.result) {
|
|
@@ -452,12 +452,12 @@ export async function run(args = []) {
|
|
|
452
452
|
for (let i = 0; i < 30; i++) {
|
|
453
453
|
await new Promise(r => setTimeout(r, 1000));
|
|
454
454
|
try {
|
|
455
|
-
const raw = await client.readContract({ address: PATH_USD, abi: USDC_ABI, functionName: "balanceOf", args: [
|
|
455
|
+
const raw = await client.readContract({ address: PATH_USD, abi: USDC_ABI, functionName: "balanceOf", args: [localWallet.address] });
|
|
456
456
|
balance = Number(raw);
|
|
457
457
|
if (balance > 0) break;
|
|
458
458
|
} catch {}
|
|
459
459
|
}
|
|
460
|
-
|
|
460
|
+
saveWallet({ ...localWallet, funded: true, lastFaucet: new Date().toISOString() });
|
|
461
461
|
if (balance > 0) {
|
|
462
462
|
line("Balance", `${(balance / 1e6).toFixed(2)} pathUSD (funded)`);
|
|
463
463
|
} else {
|
|
@@ -482,24 +482,24 @@ export async function run(args = []) {
|
|
|
482
482
|
const client = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
483
483
|
|
|
484
484
|
try {
|
|
485
|
-
const raw = await client.readContract({ address: USDC_SEPOLIA, abi: USDC_ABI, functionName: "balanceOf", args: [
|
|
485
|
+
const raw = await client.readContract({ address: USDC_SEPOLIA, abi: USDC_ABI, functionName: "balanceOf", args: [localWallet.address] });
|
|
486
486
|
balance = Number(raw);
|
|
487
487
|
} catch {}
|
|
488
488
|
|
|
489
489
|
if (balance === 0) {
|
|
490
490
|
line("Balance", "0 USDC — requesting faucet...");
|
|
491
491
|
try {
|
|
492
|
-
await getSdk().
|
|
492
|
+
await getSdk().wallets.faucet(localWallet.address);
|
|
493
493
|
// Poll for up to 30s
|
|
494
494
|
for (let i = 0; i < 30; i++) {
|
|
495
495
|
await new Promise(r => setTimeout(r, 1000));
|
|
496
496
|
try {
|
|
497
|
-
const raw = await client.readContract({ address: USDC_SEPOLIA, abi: USDC_ABI, functionName: "balanceOf", args: [
|
|
497
|
+
const raw = await client.readContract({ address: USDC_SEPOLIA, abi: USDC_ABI, functionName: "balanceOf", args: [localWallet.address] });
|
|
498
498
|
balance = Number(raw);
|
|
499
499
|
if (balance > 0) break;
|
|
500
500
|
} catch {}
|
|
501
501
|
}
|
|
502
|
-
|
|
502
|
+
saveWallet({ ...localWallet, funded: true, lastFaucet: new Date().toISOString() });
|
|
503
503
|
if (balance > 0) {
|
|
504
504
|
line("Balance", `${(balance / 1e6).toFixed(2)} USDC (funded)`);
|
|
505
505
|
} else {
|
|
@@ -517,8 +517,8 @@ export async function run(args = []) {
|
|
|
517
517
|
|
|
518
518
|
// 3b. Promo code, when one was handed to us.
|
|
519
519
|
//
|
|
520
|
-
// This runs BEFORE the balance read below so the
|
|
521
|
-
// `
|
|
520
|
+
// This runs BEFORE the balance read below so the redeemed amount shows up in
|
|
521
|
+
// `allowance_usd_micros` without a second round-trip, and AFTER the
|
|
522
522
|
// wallet exists so the redemption authenticates as this agent.
|
|
523
523
|
//
|
|
524
524
|
// NOTHING here may fail init. An advertised gift that dead-ends a build is
|
|
@@ -530,12 +530,12 @@ export async function run(args = []) {
|
|
|
530
530
|
if (voucherCode) {
|
|
531
531
|
try {
|
|
532
532
|
const redemption = await getSdk().vouchers.redeem(voucherCode);
|
|
533
|
-
const
|
|
533
|
+
const redeemed = (redemption.amount_usd_micros / 1_000_000).toFixed(2);
|
|
534
534
|
line(
|
|
535
535
|
"Voucher",
|
|
536
536
|
redemption.already_redeemed
|
|
537
|
-
? `$${
|
|
538
|
-
: `$${
|
|
537
|
+
? `$${redeemed} already added to the allowance (not added twice)`
|
|
538
|
+
: `$${redeemed} added to the allowance`,
|
|
539
539
|
);
|
|
540
540
|
summary.voucher = {
|
|
541
541
|
voucher_id: redemption.voucher_id,
|
|
@@ -544,12 +544,12 @@ export async function run(args = []) {
|
|
|
544
544
|
next_actions: Array.isArray(redemption.next_actions) ? redemption.next_actions : [],
|
|
545
545
|
};
|
|
546
546
|
// Relate the gift to what it buys, in the gateway's own words: its
|
|
547
|
-
// `set_tier` next action names the largest tier the
|
|
548
|
-
// that purchase settles from
|
|
547
|
+
// `set_tier` next action names the largest tier the allowance covers, and
|
|
548
|
+
// that purchase settles from the allowance — no wallet funding step between.
|
|
549
549
|
const covers = summary.voucher.next_actions.find((a) => a?.type === "set_tier" && typeof a.cli === "string");
|
|
550
550
|
if (covers) {
|
|
551
551
|
const tierName = covers.highest_affordable_tier ?? covers.cli.replace(/^run402 tier set\s+/, "");
|
|
552
|
-
line("
|
|
552
|
+
line("Allowance", `$${redeemed} covers ${tierName} — ${covers.cli} (settles from the allowance; no wallet funds needed)`);
|
|
553
553
|
}
|
|
554
554
|
} catch (err) {
|
|
555
555
|
// Faithful: name what failed and keep going. `voucher_error` is a
|
|
@@ -564,15 +564,15 @@ export async function run(args = []) {
|
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
// Balances mirror `run402 status`: the on-chain figure above plus the
|
|
568
|
-
// Run402-held
|
|
569
|
-
// best-effort so a billing read failure never blocks setup.
|
|
570
|
-
const billing = await getSdk().billing.checkBalance(
|
|
567
|
+
// Balances mirror `run402 status`: the on-chain wallet figure above plus the
|
|
568
|
+
// organization's Run402-held allowance (rail-independent). The allowance is
|
|
569
|
+
// fetched best-effort so a billing read failure never blocks setup.
|
|
570
|
+
const billing = await getSdk().billing.checkBalance(localWallet.address).catch(() => null);
|
|
571
571
|
const hasBilling = billing && billing.exists !== false;
|
|
572
572
|
summary.balances = {
|
|
573
573
|
on_chain_usd_micros: balance,
|
|
574
574
|
on_chain_token: isMpp ? "pathUSD" : "USDC",
|
|
575
|
-
|
|
575
|
+
allowance_usd_micros: hasBilling ? billing.allowance_usd_micros : null,
|
|
576
576
|
held_usd_micros: hasBilling ? (billing.held_usd_micros ?? 0) : null,
|
|
577
577
|
};
|
|
578
578
|
|
|
@@ -582,7 +582,7 @@ export async function run(args = []) {
|
|
|
582
582
|
line("Note", `Switched from ${previousRail} — ${prev} balance still available if you switch back`);
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
-
// 3b. The Lightning
|
|
585
|
+
// 3b. The Lightning wallet (mpp-lightning-over-nwc): a budgeted wallet
|
|
586
586
|
// on Run402's Hub, minted by the platform, its pairing kept beside the
|
|
587
587
|
// Base key. Never printed. A Hub that is not configured leaves the rail
|
|
588
588
|
// on Lightning with x402 as the live fallback, and says so.
|
|
@@ -591,14 +591,14 @@ export async function run(args = []) {
|
|
|
591
591
|
try {
|
|
592
592
|
const { ensureLightningWallet, describeLightning, readLightningBalance } = await import("./lightning-wallet.mjs");
|
|
593
593
|
const result = await ensureLightningWallet();
|
|
594
|
-
|
|
594
|
+
localWallet = result.localWallet;
|
|
595
595
|
const settled = result.outcome === "stored" || result.outcome === "present";
|
|
596
|
-
const balance = settled ? await readLightningBalance(
|
|
597
|
-
summary.lightning = { ...(describeLightning(
|
|
596
|
+
const balance = settled ? await readLightningBalance(localWallet) : null;
|
|
597
|
+
summary.lightning = { ...(describeLightning(localWallet, result.wallet, balance) ?? {}), outcome: result.outcome };
|
|
598
598
|
if (result.outcome === "stored") {
|
|
599
599
|
line("Lightning", `wallet minted on Run402's Hub (${result.wallet.budget_sats} sats budget, ${result.wallet.starter_sats} starter)`);
|
|
600
600
|
} else if (result.outcome === "present") {
|
|
601
|
-
line("Lightning", `wallet ${
|
|
601
|
+
line("Lightning", `wallet ${localWallet.lightning.wallet_id}${balance ? ` — ${balance.balance_sats} sats` : ""}`);
|
|
602
602
|
} else if (result.outcome === "minting") {
|
|
603
603
|
line("Lightning", "the platform is still minting the wallet — rerun `run402 init lightning` in a few seconds");
|
|
604
604
|
} else if (result.outcome === "unavailable") {
|
|
@@ -751,7 +751,7 @@ export async function run(args = []) {
|
|
|
751
751
|
summary.funding = fundingRecovery(fundingError, fundingPending);
|
|
752
752
|
const fundingBlocked = fundingBlocksBootstrap(summary.funding, {
|
|
753
753
|
activeTier: !tierMissing, onChainBalance: balance,
|
|
754
|
-
|
|
754
|
+
allowanceBalance: summary.balances.allowance_usd_micros,
|
|
755
755
|
lightningBalance: summary.lightning?.balance_sats,
|
|
756
756
|
});
|
|
757
757
|
summary.next_actions = [tierMissing ? upDeployAction() : deployAction()];
|
|
@@ -759,7 +759,7 @@ export async function run(args = []) {
|
|
|
759
759
|
const quotedWallet = `'${walletName.replaceAll("'", "'\\''")}'`;
|
|
760
760
|
summary.next_actions = summary.funding.next_actions.map(action => ({ ...action,
|
|
761
761
|
...(["retry", "check_balance"].includes(action.type) ? {
|
|
762
|
-
command: `run402 --wallet ${quotedWallet}
|
|
762
|
+
command: `run402 --wallet ${quotedWallet} wallets ${action.type === "retry" ? "fund" : "balance"}`,
|
|
763
763
|
} : {}),
|
|
764
764
|
}));
|
|
765
765
|
}
|
|
@@ -769,19 +769,19 @@ export async function run(args = []) {
|
|
|
769
769
|
write(` ${summary.next_actions[0].why}`);
|
|
770
770
|
if (summary.next_step) write(` Next: ${summary.next_step}`);
|
|
771
771
|
} else if (tierMissing) {
|
|
772
|
-
// `up -y`
|
|
772
|
+
// `up -y` sets the prototype tier itself as part of the first
|
|
773
773
|
// deploy; `init` never buys the tier, so the one command that finishes
|
|
774
774
|
// the cold start is `up`, with `tier set` named as the standalone option.
|
|
775
|
-
const
|
|
775
|
+
const allowanceCovers = summary.voucher?.next_actions?.find((a) => a?.type === "set_tier" && typeof a.cli === "string");
|
|
776
776
|
write(" Next: run402 up -y");
|
|
777
|
-
write(" Deploy with run402 up -y — it
|
|
778
|
-
if (
|
|
779
|
-
write(` Your
|
|
777
|
+
write(" Deploy with run402 up -y — it sets the prototype tier (free on testnet) as part of the first deploy.");
|
|
778
|
+
if (allowanceCovers) {
|
|
779
|
+
write(` Your allowance covers ${allowanceCovers.highest_affordable_tier ?? "a larger tier"}: ${allowanceCovers.cli} — then run402 up -y.`);
|
|
780
780
|
} else {
|
|
781
|
-
write(" Or
|
|
781
|
+
write(" Or set it separately: run402 tier set prototype.");
|
|
782
782
|
}
|
|
783
783
|
} else {
|
|
784
|
-
write(" Ready to deploy. Run: run402 deploy
|
|
784
|
+
write(" Ready to deploy. Run: run402 deploy --manifest app.json");
|
|
785
785
|
}
|
|
786
786
|
write("");
|
|
787
787
|
|
package/lib/lightning-wallet.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Lightning
|
|
3
|
-
* Run402's Hub, keep its pairing in the active profile's
|
|
2
|
+
* The Lightning wallet on the CLI: mint the agent's budgeted wallet on
|
|
3
|
+
* Run402's Hub, keep its pairing in the active profile's wallet.json
|
|
4
4
|
* beside the Base key, report its balance, revoke it. Shared by
|
|
5
5
|
* `run402 init lightning`, `run402 wallets lightning …`, and
|
|
6
|
-
* `run402
|
|
6
|
+
* `run402 wallets current`. The pairing secret is never printed.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { readWallet, saveWallet } from "../core-dist/wallet.js";
|
|
9
9
|
import { getSdk } from "./sdk.mjs";
|
|
10
10
|
|
|
11
11
|
export const LIGHTNING_MINT_TIMEOUT_MS = 45_000;
|
|
12
12
|
|
|
13
13
|
/** Public facts only: never the pairing. */
|
|
14
|
-
export function describeLightning(
|
|
15
|
-
const local =
|
|
14
|
+
export function describeLightning(localWallet, wallet = null, balance = null) {
|
|
15
|
+
const local = localWallet?.lightning ?? null;
|
|
16
16
|
if (!local && !wallet) return null;
|
|
17
17
|
return {
|
|
18
18
|
wallet_id: wallet?.wallet_id ?? local?.wallet_id ?? null,
|
|
@@ -29,8 +29,8 @@ export function describeLightning(allowance, wallet = null, balance = null) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** Balance and remaining budget over NWC, best-effort (null on any failure). */
|
|
32
|
-
export async function readLightningBalance(
|
|
33
|
-
const nwc =
|
|
32
|
+
export async function readLightningBalance(localWallet) {
|
|
33
|
+
const nwc = localWallet?.lightning?.nwc;
|
|
34
34
|
if (!nwc) return null;
|
|
35
35
|
try {
|
|
36
36
|
const { NwcWallet, closeNwcConnections } = await import("#sdk/node");
|
|
@@ -46,9 +46,9 @@ export async function readLightningBalance(allowance) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function storePairing(
|
|
49
|
+
function storePairing(localWallet, wallet) {
|
|
50
50
|
const next = {
|
|
51
|
-
...
|
|
51
|
+
...localWallet,
|
|
52
52
|
rail: "lightning",
|
|
53
53
|
lightning: {
|
|
54
54
|
wallet_id: wallet.wallet_id,
|
|
@@ -60,46 +60,46 @@ function storePairing(allowance, wallet) {
|
|
|
60
60
|
minted_at: wallet.activated_at ?? new Date().toISOString(),
|
|
61
61
|
},
|
|
62
62
|
};
|
|
63
|
-
|
|
63
|
+
saveWallet(next);
|
|
64
64
|
return next;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Ensure the active profile holds an active Lightning wallet. Returns
|
|
69
|
-
* `{
|
|
69
|
+
* `{ localWallet, wallet, outcome }` where outcome is `stored` (pairing just
|
|
70
70
|
* saved), `present` (already held locally), `minting` (the platform is still
|
|
71
71
|
* minting; rerun later), `unavailable` (no Hub on this gateway), or
|
|
72
72
|
* `pairing_lost` (the wallet is active but its one-time pairing was handed to
|
|
73
73
|
* another machine; revoke and mint again).
|
|
74
74
|
*/
|
|
75
75
|
export async function ensureLightningWallet(options = {}) {
|
|
76
|
-
let
|
|
77
|
-
if (!
|
|
78
|
-
if (
|
|
76
|
+
let localWallet = readWallet();
|
|
77
|
+
if (!localWallet) throw new Error("no local wallet configured; run `run402 init` first");
|
|
78
|
+
if (localWallet.lightning?.nwc) {
|
|
79
79
|
let wallet = null;
|
|
80
80
|
try { wallet = await getSdk().agent.lightningWallet.get(); } catch { /* offline read is fine */ }
|
|
81
|
-
if (wallet && wallet.status !== "active") return {
|
|
82
|
-
return {
|
|
81
|
+
if (wallet && wallet.status !== "active") return { localWallet, wallet, outcome: wallet.status };
|
|
82
|
+
return { localWallet, wallet, outcome: "present" };
|
|
83
83
|
}
|
|
84
84
|
let wallet;
|
|
85
85
|
try {
|
|
86
86
|
wallet = await getSdk().agent.lightningWallet.mint({ timeoutMs: options.timeoutMs ?? LIGHTNING_MINT_TIMEOUT_MS });
|
|
87
87
|
} catch (err) {
|
|
88
88
|
const code = err?.body?.code ?? err?.code;
|
|
89
|
-
if (code === "LIGHTNING_WALLET_NOT_AVAILABLE") return {
|
|
90
|
-
if (code === "LIGHTNING_WALLET_STILL_MINTING") return {
|
|
89
|
+
if (code === "LIGHTNING_WALLET_NOT_AVAILABLE") return { localWallet, wallet: null, outcome: "unavailable", error: err };
|
|
90
|
+
if (code === "LIGHTNING_WALLET_STILL_MINTING") return { localWallet, wallet: null, outcome: "minting", error: err };
|
|
91
91
|
throw err;
|
|
92
92
|
}
|
|
93
|
-
if (wallet.status === "minting") return {
|
|
94
|
-
if (wallet.status !== "active") return {
|
|
95
|
-
if (typeof wallet.pairing !== "string") return {
|
|
96
|
-
|
|
97
|
-
return {
|
|
93
|
+
if (wallet.status === "minting") return { localWallet, wallet, outcome: "minting" };
|
|
94
|
+
if (wallet.status !== "active") return { localWallet, wallet, outcome: wallet.status };
|
|
95
|
+
if (typeof wallet.pairing !== "string") return { localWallet, wallet, outcome: "pairing_lost" };
|
|
96
|
+
localWallet = storePairing(localWallet, wallet);
|
|
97
|
+
return { localWallet, wallet, outcome: "stored" };
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** Revoke on the platform and forget the pairing locally; the rail returns to x402. */
|
|
101
101
|
export async function revokeLightningWallet() {
|
|
102
|
-
const
|
|
102
|
+
const localWallet = readWallet();
|
|
103
103
|
let wallet = null;
|
|
104
104
|
try {
|
|
105
105
|
wallet = await getSdk().agent.lightningWallet.revoke();
|
|
@@ -107,9 +107,9 @@ export async function revokeLightningWallet() {
|
|
|
107
107
|
const code = err?.body?.code ?? err?.code;
|
|
108
108
|
if (code !== "LIGHTNING_WALLET_NOT_FOUND") throw err;
|
|
109
109
|
}
|
|
110
|
-
if (
|
|
111
|
-
const { lightning: _dropped, ...rest } =
|
|
112
|
-
|
|
110
|
+
if (localWallet) {
|
|
111
|
+
const { lightning: _dropped, ...rest } = localWallet;
|
|
112
|
+
saveWallet({ ...rest, rail: rest.rail === "lightning" ? "x402" : rest.rail });
|
|
113
113
|
}
|
|
114
114
|
return wallet;
|
|
115
115
|
}
|