run402 4.96.0 → 4.98.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 +3 -3
- package/cli.mjs +1 -7
- package/core-dist/binding-file.js +28 -1
- package/core-dist/wallet.js +3 -3
- package/lib/auth.mjs +1 -2
- package/lib/buzz-doctor.mjs +21 -806
- package/lib/buzz-doctor.test.mjs +7 -6
- package/lib/buzz.mjs +1 -1
- package/lib/buzz.test.mjs +13 -2
- package/lib/command-manifest.mjs +3 -6
- package/lib/credentials.mjs +4 -4
- package/lib/deploy-v2.mjs +27 -27
- package/lib/doctor.mjs +72 -811
- package/lib/errors.mjs +1 -1
- package/lib/events.mjs +1 -1
- package/lib/grants.mjs +148 -46
- package/lib/init.mjs +35 -576
- package/lib/logs.mjs +1 -1
- package/lib/org-context.mjs +39 -376
- package/lib/orgs.mjs +22 -106
- package/lib/projects.mjs +2 -3
- package/lib/repos.mjs +6 -6
- package/lib/rooms.mjs +1 -2
- package/lib/sdk-errors.mjs +26 -0
- package/lib/sites.mjs +5 -5
- package/lib/status.mjs +14 -154
- package/lib/up.mjs +1 -2
- package/lib/vault-scaffold.mjs +2 -3
- package/lib/vault-target.mjs +14 -141
- package/lib/wallet-context.mjs +61 -227
- package/lib/wallets.mjs +47 -310
- package/package.json +1 -2
- package/sdk/core-dist/binding-file.js +28 -1
- package/sdk/core-dist/wallet.js +3 -3
- package/sdk/dist/errors.d.ts +25 -3
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +46 -4
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/grant-key-credentials.d.ts +38 -0
- package/sdk/dist/grant-key-credentials.d.ts.map +1 -0
- package/sdk/dist/grant-key-credentials.js +42 -0
- package/sdk/dist/grant-key-credentials.js.map +1 -0
- package/sdk/dist/index.d.ts +25 -17
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +18 -14
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/kernel.d.ts +34 -0
- package/sdk/dist/kernel.d.ts.map +1 -1
- package/sdk/dist/kernel.js +15 -1
- package/sdk/dist/kernel.js.map +1 -1
- package/sdk/dist/namespaces/admin.d.ts.map +1 -1
- package/sdk/dist/namespaces/admin.js +8 -0
- 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 +4 -0
- package/sdk/dist/namespaces/agent.js.map +1 -1
- package/sdk/dist/namespaces/agent.types.d.ts +5 -0
- package/sdk/dist/namespaces/agent.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/apps.d.ts.map +1 -1
- package/sdk/dist/namespaces/apps.js +2 -0
- package/sdk/dist/namespaces/apps.js.map +1 -1
- package/sdk/dist/namespaces/auth.d.ts.map +1 -1
- package/sdk/dist/namespaces/auth.js +9 -0
- package/sdk/dist/namespaces/auth.js.map +1 -1
- package/sdk/dist/namespaces/billing.d.ts +1 -1
- package/sdk/dist/namespaces/billing.js +1 -1
- package/sdk/dist/namespaces/branches.d.ts.map +1 -1
- package/sdk/dist/namespaces/branches.js +2 -0
- package/sdk/dist/namespaces/branches.js.map +1 -1
- package/sdk/dist/namespaces/buzz.js +1 -1
- package/sdk/dist/namespaces/buzz.js.map +1 -1
- package/sdk/dist/namespaces/ci.d.ts.map +1 -1
- package/sdk/dist/namespaces/ci.js +2 -0
- package/sdk/dist/namespaces/ci.js.map +1 -1
- package/sdk/dist/namespaces/credentials.d.ts +4 -27
- package/sdk/dist/namespaces/credentials.d.ts.map +1 -1
- package/sdk/dist/namespaces/credentials.js +33 -4
- package/sdk/dist/namespaces/credentials.js.map +1 -1
- package/sdk/dist/namespaces/deploy.js +5 -5
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/domains.d.ts +1 -1
- package/sdk/dist/namespaces/domains.js +1 -1
- package/sdk/dist/namespaces/errors.d.ts +1 -1
- package/sdk/dist/namespaces/errors.js +2 -2
- package/sdk/dist/namespaces/escalations.d.ts +2 -2
- package/sdk/dist/namespaces/escalations.d.ts.map +1 -1
- package/sdk/dist/namespaces/escalations.js +4 -2
- package/sdk/dist/namespaces/escalations.js.map +1 -1
- package/sdk/dist/namespaces/escalations.types.d.ts +3 -3
- package/sdk/dist/namespaces/escalations.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/events.d.ts +1 -1
- package/sdk/dist/namespaces/events.js +1 -1
- package/sdk/dist/namespaces/functions.js +1 -1
- package/sdk/dist/namespaces/functions.js.map +1 -1
- package/sdk/dist/namespaces/grants.d.ts +43 -9
- package/sdk/dist/namespaces/grants.d.ts.map +1 -1
- package/sdk/dist/namespaces/grants.js +103 -10
- package/sdk/dist/namespaces/grants.js.map +1 -1
- package/sdk/dist/namespaces/grants.types.d.ts +120 -15
- package/sdk/dist/namespaces/grants.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/grants.types.js +12 -3
- package/sdk/dist/namespaces/grants.types.js.map +1 -1
- package/sdk/dist/namespaces/identity-links.types.d.ts +2 -2
- package/sdk/dist/namespaces/identity-links.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/live.d.ts +0 -16
- package/sdk/dist/namespaces/live.d.ts.map +1 -1
- package/sdk/dist/namespaces/live.js +19 -0
- package/sdk/dist/namespaces/live.js.map +1 -1
- package/sdk/dist/namespaces/me.d.ts.map +1 -1
- package/sdk/dist/namespaces/me.js +3 -0
- package/sdk/dist/namespaces/me.js.map +1 -1
- package/sdk/dist/namespaces/org.d.ts +1 -1
- package/sdk/dist/namespaces/org.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.js +4 -1
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts +1 -1
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +6 -1
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/namespaces/repos.d.ts.map +1 -1
- package/sdk/dist/namespaces/repos.js +7 -2
- package/sdk/dist/namespaces/repos.js.map +1 -1
- package/sdk/dist/namespaces/rooms.d.ts +3 -3
- package/sdk/dist/namespaces/rooms.d.ts.map +1 -1
- package/sdk/dist/namespaces/rooms.js +6 -3
- package/sdk/dist/namespaces/rooms.js.map +1 -1
- package/sdk/dist/namespaces/session.d.ts.map +1 -1
- package/sdk/dist/namespaces/session.js +18 -0
- package/sdk/dist/namespaces/session.js.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +3 -0
- package/sdk/dist/namespaces/transfers.js.map +1 -1
- package/sdk/dist/namespaces/wallets.d.ts.map +1 -1
- package/sdk/dist/namespaces/wallets.js +2 -0
- package/sdk/dist/namespaces/wallets.js.map +1 -1
- package/sdk/dist/namespaces/write-approval.d.ts.map +1 -1
- package/sdk/dist/namespaces/write-approval.js +3 -0
- package/sdk/dist/namespaces/write-approval.js.map +1 -1
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +3 -0
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/buzz-doctor-contract.d.ts +155 -0
- package/sdk/dist/node/buzz-doctor-contract.d.ts.map +1 -0
- package/sdk/dist/node/buzz-doctor-contract.js +385 -0
- package/sdk/dist/node/buzz-doctor-contract.js.map +1 -0
- package/sdk/dist/node/buzz-doctor.d.ts +155 -0
- package/sdk/dist/node/buzz-doctor.d.ts.map +1 -0
- package/sdk/dist/node/buzz-doctor.js +810 -0
- package/sdk/dist/node/buzz-doctor.js.map +1 -0
- package/sdk/dist/node/credentials.d.ts +18 -13
- package/sdk/dist/node/credentials.d.ts.map +1 -1
- package/sdk/dist/node/credentials.js +13 -13
- package/sdk/dist/node/credentials.js.map +1 -1
- package/sdk/dist/node/diagnostics.d.ts +45 -0
- package/sdk/dist/node/diagnostics.d.ts.map +1 -0
- package/sdk/dist/node/diagnostics.js +67 -0
- package/sdk/dist/node/diagnostics.js.map +1 -0
- package/sdk/dist/node/doctor.d.ts +101 -0
- package/sdk/dist/node/doctor.d.ts.map +1 -0
- package/sdk/dist/node/doctor.js +618 -0
- package/sdk/dist/node/doctor.js.map +1 -0
- package/sdk/dist/node/index.d.ts +61 -9
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +37 -2
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/init.d.ts +137 -0
- package/sdk/dist/node/init.d.ts.map +1 -0
- package/sdk/dist/node/init.js +507 -0
- package/sdk/dist/node/init.js.map +1 -0
- package/sdk/dist/node/lightning-wallet.d.ts +61 -0
- package/sdk/dist/node/lightning-wallet.d.ts.map +1 -0
- package/sdk/dist/node/lightning-wallet.js +126 -0
- package/sdk/dist/node/lightning-wallet.js.map +1 -0
- package/sdk/dist/node/local-actions.d.ts +23 -0
- package/sdk/dist/node/local-actions.d.ts.map +1 -0
- package/sdk/dist/node/local-actions.js +38 -0
- package/sdk/dist/node/local-actions.js.map +1 -0
- package/sdk/dist/node/org-context.d.ts +169 -0
- package/sdk/dist/node/org-context.d.ts.map +1 -0
- package/sdk/dist/node/org-context.js +403 -0
- package/sdk/dist/node/org-context.js.map +1 -0
- package/sdk/dist/node/status.d.ts +62 -0
- package/sdk/dist/node/status.d.ts.map +1 -0
- package/sdk/dist/node/status.js +132 -0
- package/sdk/dist/node/status.js.map +1 -0
- package/sdk/dist/node/vault-target.d.ts +49 -0
- package/sdk/dist/node/vault-target.d.ts.map +1 -0
- package/sdk/dist/node/vault-target.js +109 -0
- package/sdk/dist/node/vault-target.js.map +1 -0
- package/sdk/dist/node/wallets.d.ts +242 -0
- package/sdk/dist/node/wallets.d.ts.map +1 -0
- package/sdk/dist/node/wallets.js +484 -0
- package/sdk/dist/node/wallets.js.map +1 -0
- package/sdk/dist/project-auth-classification.d.ts +8 -8
- package/sdk/dist/project-auth-classification.d.ts.map +1 -1
- package/sdk/dist/project-auth-classification.js +7 -7
- package/sdk/dist/project-auth-classification.js.map +1 -1
- package/sdk/dist/scoped.d.ts +6 -14
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +10 -21
- package/sdk/dist/scoped.js.map +1 -1
- package/sdk/dist/secret-gate.d.ts +377 -0
- package/sdk/dist/secret-gate.d.ts.map +1 -0
- package/sdk/dist/secret-gate.js +273 -0
- package/sdk/dist/secret-gate.js.map +1 -0
- package/vault-surface.json +1 -1
- package/fixtures/buzz-v0.5.2-cli-capabilities.json +0 -92
- package/fixtures/run402-buzz-doctor-v1-contract.json +0 -140
- package/lib/buzz-doctor-contract.mjs +0 -97
- package/lib/buzz-doctor-contract.test.mjs +0 -134
- package/lib/delegates.mjs +0 -189
- package/lib/lightning-wallet.mjs +0 -115
- package/sdk/dist/delegate-credentials.d.ts +0 -37
- package/sdk/dist/delegate-credentials.d.ts.map +0 -1
- package/sdk/dist/delegate-credentials.js +0 -41
- package/sdk/dist/delegate-credentials.js.map +0 -1
- package/sdk/dist/namespaces/delegates.d.ts +0 -50
- package/sdk/dist/namespaces/delegates.d.ts.map +0 -1
- package/sdk/dist/namespaces/delegates.js +0 -99
- package/sdk/dist/namespaces/delegates.js.map +0 -1
- package/sdk/dist/namespaces/delegates.types.d.ts +0 -88
- package/sdk/dist/namespaces/delegates.types.d.ts.map +0 -1
- package/sdk/dist/namespaces/delegates.types.js +0 -10
- package/sdk/dist/namespaces/delegates.types.js.map +0 -1
package/lib/wallet-context.mjs
CHANGED
|
@@ -1,51 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The `--wallet` edge of the CLI: what has to happen before any subcommand
|
|
3
|
+
* module (and so before `cli/lib/config.mjs` snapshots credential paths) is
|
|
4
|
+
* loaded, and how a wallet-selection refusal is reported.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 5. "default" (root wallet)
|
|
18
|
-
*
|
|
19
|
-
* The flag is also the conflict resolver: when env and binding name different
|
|
20
|
-
* wallets and no flag is given, that is a hard error (not a silent pick).
|
|
6
|
+
* The selection itself — the precedence chain (flag, RUN402_WALLET, the
|
|
7
|
+
* nearest .run402(.local).json binding, the global `wallets use` default,
|
|
8
|
+
* `default`), the env-vs-binding conflict, and the fail-closed existence
|
|
9
|
+
* check — is the Node SDK's (`resolveWalletSelection`, `assertWalletExists`,
|
|
10
|
+
* `selectWallet`). This module adds only:
|
|
11
|
+
* - reading `--wallet` / `--profile` off argv (`splitWalletFlag`);
|
|
12
|
+
* - which commands must keep working while selection is ambiguous or names
|
|
13
|
+
* a wallet that does not exist yet (the wallet-management group, `init`,
|
|
14
|
+
* `doctor`);
|
|
15
|
+
* - translating a `WalletSelectionError` into `fail()` for the CLI, while
|
|
16
|
+
* `git-remote-run402` (which must never `process.exit()` mid-stream)
|
|
17
|
+
* catches the same error and reports it through its own channel;
|
|
18
|
+
* - the opt-in stderr provenance line.
|
|
21
19
|
*/
|
|
22
20
|
|
|
23
|
-
import { existsSync, rmSync, writeFileSync } from "node:fs";
|
|
24
21
|
import { join } from "node:path";
|
|
25
22
|
import { fail } from "./sdk-errors.mjs";
|
|
26
|
-
import {
|
|
27
|
-
import { getDefaultWallet, profileExists, readMeta, profileDir } from "../core-dist/profiles.js";
|
|
23
|
+
import { profileDir, readMeta } from "../core-dist/profiles.js";
|
|
28
24
|
import { readWallet } from "../core-dist/wallet.js";
|
|
29
|
-
import { describeRejectedValue } from "../core-dist/redact.js";
|
|
30
|
-
// The binding file is a CHECKOUT-LEVEL CONTRACT read by more than one surface,
|
|
31
|
-
// so its reader lives in core — `run402-mcp` ships core/dist but not cli/, and
|
|
32
|
-
// two readers of one file format is exactly the drift worth not having.
|
|
33
|
-
// Re-exported here under the names the rest of the CLI already imports.
|
|
34
25
|
import {
|
|
35
26
|
findBindingKey,
|
|
36
27
|
bindingFilePath,
|
|
37
28
|
readBindingFile,
|
|
38
|
-
|
|
29
|
+
updateBindingFile,
|
|
39
30
|
} from "../core-dist/binding-file.js";
|
|
31
|
+
import {
|
|
32
|
+
WalletSelectionError,
|
|
33
|
+
assertWalletExists,
|
|
34
|
+
findWalletBinding,
|
|
35
|
+
resolveWalletSelection,
|
|
36
|
+
selectWallet,
|
|
37
|
+
} from "#sdk/node";
|
|
40
38
|
|
|
41
|
-
export { findBindingKey, bindingFilePath, readBindingFile };
|
|
39
|
+
export { findBindingKey, bindingFilePath, readBindingFile, updateBindingFile, WalletSelectionError };
|
|
42
40
|
|
|
43
41
|
const DEFAULT = "default";
|
|
44
42
|
const GLOBAL_FLAGS = new Set(["--wallet", "--profile"]);
|
|
45
43
|
// `repos` owns `--profile` itself (the AWS credential profile for a BYO
|
|
46
44
|
// destination, a mirror, or a recovery source), so under that command only
|
|
47
45
|
// `--wallet` selects the wallet; RUN402_WALLET and the directory binding still
|
|
48
|
-
// apply.
|
|
46
|
+
// apply.
|
|
49
47
|
const OWNS_PROFILE_FLAG = new Set(["repos"]);
|
|
50
48
|
// The `wallets` group is the management + escape surface — it must work even
|
|
51
49
|
// when selection is ambiguous (so you can `wallets unbind`), and it validates
|
|
@@ -57,10 +55,10 @@ const EXISTENCE_EXEMPT = new Set(["wallets", "init", "doctor"]);
|
|
|
57
55
|
/**
|
|
58
56
|
* Split the global --wallet/--profile flag (and its value) out of argv so the
|
|
59
57
|
* subcommand never sees it — except `--profile` under a command that owns the
|
|
60
|
-
* flag (OWNS_PROFILE_FLAG), which is passed through untouched. Pure
|
|
58
|
+
* flag (OWNS_PROFILE_FLAG), which is passed through untouched. Pure. Returns
|
|
61
59
|
* the cleaned argv and the selected flag (`{ flag, value }` or null). Last
|
|
62
|
-
* occurrence wins. A missing value is left as `value: undefined` for
|
|
63
|
-
*
|
|
60
|
+
* occurrence wins. A missing value is left as `value: undefined` for the
|
|
61
|
+
* resolver to reject with a precise error.
|
|
64
62
|
*/
|
|
65
63
|
export function splitWalletFlag(rawArgv = []) {
|
|
66
64
|
const argv = [];
|
|
@@ -99,201 +97,46 @@ export function splitWalletFlag(rawArgv = []) {
|
|
|
99
97
|
return { argv, walletFlag: flag };
|
|
100
98
|
}
|
|
101
99
|
|
|
102
|
-
/**
|
|
103
|
-
* MERGE keys into a directory's binding file. A `null` value removes its key;
|
|
104
|
-
* a file left with no keys is deleted rather than committed empty.
|
|
105
|
-
*
|
|
106
|
-
* The file is shared by tiers (`wallet` from `wallets bind`, `org`/`room` from
|
|
107
|
-
* `orgs bind`) and unknown keys are preserved, so one tier can never clobber
|
|
108
|
-
* another's binding — which a whole-file write did until this existed.
|
|
109
|
-
*/
|
|
110
|
-
export function updateBindingFile(dir, patch) {
|
|
111
|
-
const file = bindingFilePath(dir);
|
|
112
|
-
const next = { ...readBindingFile(dir) };
|
|
113
|
-
for (const [k, v] of Object.entries(patch)) {
|
|
114
|
-
if (v === null || v === undefined) delete next[k];
|
|
115
|
-
else next[k] = v;
|
|
116
|
-
}
|
|
117
|
-
if (Object.keys(next).length === 0) {
|
|
118
|
-
const existed = existsSync(file);
|
|
119
|
-
if (existed) rmSync(file, { force: true });
|
|
120
|
-
return { file, contents: null, removed: existed };
|
|
121
|
-
}
|
|
122
|
-
writeFileSync(file, JSON.stringify(next, null, 2) + "\n");
|
|
123
|
-
return { file, contents: next, removed: false };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
100
|
/** Nearest wallet binding walking up from `startDir` to the filesystem root. */
|
|
127
101
|
export function findBinding(startDir) {
|
|
128
|
-
|
|
129
|
-
return hit ? { wallet: hit.value, file: hit.file } : null;
|
|
102
|
+
return findWalletBinding(startDir);
|
|
130
103
|
}
|
|
131
104
|
|
|
132
105
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* the top of `cli.mjs`, before any protocol stream has started) does
|
|
137
|
-
* `fail(err)` verbatim, and a caller that CANNOT (`git-remote-run402` — see
|
|
138
|
-
* that file's own header: `process.exit()` mid-stream can truncate a
|
|
139
|
-
* pending stdout write on a pipe) catches it and reports through its own
|
|
140
|
-
* non-exiting error path instead.
|
|
106
|
+
* The SDK's selection for command `cmd` (a non-CLI caller passes none), throwing
|
|
107
|
+
* {@link WalletSelectionError}. `git-remote-run402` composes this directly so a
|
|
108
|
+
* refusal never exits mid-protocol.
|
|
141
109
|
*/
|
|
142
|
-
export
|
|
143
|
-
|
|
144
|
-
super(message);
|
|
145
|
-
this.name = "WalletSelectionError";
|
|
146
|
-
this.code = code;
|
|
147
|
-
this.hint = hint;
|
|
148
|
-
this.details = details;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// A rejected name is a value we know nothing about — the most likely
|
|
153
|
-
// mistake is a typo, but a live Base-mainnet private key pasted into
|
|
154
|
-
// RUN402_WALLET (a NAME field, not a key field) is a demonstrated case, and
|
|
155
|
-
// echoing the raw value prints it to a terminal, a log, and a session
|
|
156
|
-
// transcript. Route it
|
|
157
|
-
// through describeRejectedValue() so a short/plain typo still shows in
|
|
158
|
-
// full (that's what makes the error useful) while anything long or
|
|
159
|
-
// hex-shaped enough to be a secret is redacted instead.
|
|
160
|
-
function assertValidNameCore(name, origin) {
|
|
161
|
-
if (name === DEFAULT || isValidProfileName(name)) return;
|
|
162
|
-
throw new WalletSelectionError({
|
|
163
|
-
code: "BAD_WALLET_NAME",
|
|
164
|
-
message: `Invalid wallet name ${JSON.stringify(describeRejectedValue(name))} (from ${origin}).`,
|
|
165
|
-
hint: "Wallet names must match /^[a-z0-9][a-z0-9_-]{0,63}$/ (lowercase letters, digits, '_' and '-'). If a private key or other secret ended up here, it does not belong in a NAME field — see `run402 wallets import` — and should be treated as compromised.",
|
|
166
|
-
details: { name: describeRejectedValue(name), origin },
|
|
167
|
-
});
|
|
110
|
+
export function resolveWalletCore({ walletFlag, env = {}, cwd = process.cwd(), cmd } = {}) {
|
|
111
|
+
return resolveWalletSelection({ walletFlag, env, cwd, allowConflict: CONFLICT_EXEMPT.has(cmd) });
|
|
168
112
|
}
|
|
169
113
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (err instanceof WalletSelectionError) fail(err);
|
|
175
|
-
throw err;
|
|
176
|
-
}
|
|
114
|
+
/** Fail closed on a missing wallet unless `cmd` creates or manages wallets; throws {@link WalletSelectionError}. */
|
|
115
|
+
export function enforceWalletExistsCore(resolved, cmd) {
|
|
116
|
+
if (EXISTENCE_EXEMPT.has(cmd)) return;
|
|
117
|
+
assertWalletExists(resolved);
|
|
177
118
|
}
|
|
178
119
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
* `{ name, source, sourceDetail }` or throws {@link WalletSelectionError}.
|
|
183
|
-
*
|
|
184
|
-
* Shared verbatim by `resolveWallet` below (the CLI wrapper: `--wallet` flag
|
|
185
|
-
* layered on top, failures routed through `fail()`) AND by
|
|
186
|
-
* `git-remote-run402` (no flag layer — the helper has no argv flags at all
|
|
187
|
-
* — failures routed through its own protocol-safe error reporting). Calling
|
|
188
|
-
* `getSdk()` directly instead would run no wallet selection at all, so a
|
|
189
|
-
* `.run402.json` binding — and even the global `wallets use` default —
|
|
190
|
-
* would silently never reach the helper; only the `RUN402_WALLET` env layer
|
|
191
|
-
* would work.
|
|
192
|
-
*
|
|
193
|
-
* Precedence beneath an optional flag (highest first): `RUN402_WALLET` /
|
|
194
|
-
* `RUN402_PROFILE` env > nearest `.run402.local.json`/`.run402.json` binding
|
|
195
|
-
* (walked from `cwd`, which callers choose deliberately — see this file's
|
|
196
|
-
* own module doc and `git-remote-run402`'s "WHICH REPOSITORY" note: the
|
|
197
|
-
* binding walk must start from the REPOSITORY directory when one is
|
|
198
|
-
* resolvable, cwd only for repository-free commands) > `wallets use` global
|
|
199
|
-
* default > `"default"`. env-vs-binding disagreement is a hard error unless
|
|
200
|
-
* `cmd` is conflict-exempt (`wallets`) — same rule for every caller.
|
|
201
|
-
*/
|
|
202
|
-
export function resolveWalletCore({ walletFlag, env = {}, cwd = process.cwd(), cmd } = {}) {
|
|
203
|
-
if (walletFlag) {
|
|
204
|
-
if (walletFlag.value === undefined || walletFlag.value === "") {
|
|
205
|
-
throw new WalletSelectionError({ code: "BAD_FLAG", message: `${walletFlag.flag} requires a value`, details: { flag: walletFlag.flag } });
|
|
206
|
-
}
|
|
207
|
-
assertValidNameCore(walletFlag.value, walletFlag.flag);
|
|
208
|
-
return { name: walletFlag.value, source: "flag", sourceDetail: walletFlag.flag };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const envRaw = env.RUN402_WALLET ?? env.RUN402_PROFILE;
|
|
212
|
-
const envName = typeof envRaw === "string" && envRaw.trim() ? envRaw.trim() : null;
|
|
213
|
-
const binding = findBinding(cwd);
|
|
214
|
-
|
|
215
|
-
if (envName && binding && envName !== binding.wallet && !CONFLICT_EXEMPT.has(cmd)) {
|
|
216
|
-
// This conflict check runs BEFORE assertValidNameCore below, so an
|
|
217
|
-
// unvalidated (possibly secret-shaped)
|
|
218
|
-
// RUN402_WALLET reaches here first whenever a directory binding exists
|
|
219
|
-
// (routine per this repo's own fleet-coordination convention). Redact
|
|
220
|
-
// the env side the same way the format check would; `binding.wallet`
|
|
221
|
-
// comes from a committed .run402.json, which by convention never holds
|
|
222
|
-
// a secret (`wallets bind` validates the name before writing it).
|
|
223
|
-
throw new WalletSelectionError({
|
|
224
|
-
code: "WALLET_SELECTION_CONFLICT",
|
|
225
|
-
message: `Ambiguous wallet: RUN402_WALLET=${describeRejectedValue(envName)} but ${binding.file} selects '${binding.wallet}'.`,
|
|
226
|
-
hint: "Resolve with one of: pass --wallet <name>, unset RUN402_WALLET, or run402 wallets unbind.",
|
|
227
|
-
details: { env_wallet: describeRejectedValue(envName), binding_wallet: binding.wallet, binding_file: binding.file },
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (envName) {
|
|
232
|
-
assertValidNameCore(envName, "RUN402_WALLET");
|
|
233
|
-
return { name: envName, source: "env", sourceDetail: "RUN402_WALLET" };
|
|
234
|
-
}
|
|
235
|
-
if (binding) {
|
|
236
|
-
assertValidNameCore(binding.wallet, binding.file);
|
|
237
|
-
return { name: binding.wallet, source: "binding", sourceDetail: binding.file };
|
|
238
|
-
}
|
|
239
|
-
const def = getDefaultWallet();
|
|
240
|
-
if (def && def !== DEFAULT) return { name: def, source: "config", sourceDetail: "wallets use" };
|
|
241
|
-
return { name: DEFAULT, source: "default", sourceDetail: null };
|
|
120
|
+
function failSelection(err) {
|
|
121
|
+
if (err instanceof WalletSelectionError) fail(err);
|
|
122
|
+
throw err;
|
|
242
123
|
}
|
|
243
124
|
|
|
244
|
-
/**
|
|
125
|
+
/** {@link resolveWalletCore}, `fail()` on a refusal. */
|
|
245
126
|
export function resolveWallet(opts) {
|
|
246
127
|
try {
|
|
247
128
|
return resolveWalletCore(opts);
|
|
248
129
|
} catch (err) {
|
|
249
|
-
|
|
250
|
-
throw err;
|
|
130
|
+
return failSelection(err);
|
|
251
131
|
}
|
|
252
132
|
}
|
|
253
133
|
|
|
254
|
-
|
|
255
|
-
return typeof s === "string" && /^0x[a-fA-F0-9]{40}$/.test(s);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Fail-closed check that a non-default, non-exempt selection names a wallet
|
|
260
|
-
* that actually exists locally — pure, throws {@link WalletSelectionError}.
|
|
261
|
-
* `cmd` is `undefined` for a non-CLI caller (`git-remote-run402`), which
|
|
262
|
-
* matches neither `EXISTENCE_EXEMPT` entry, so the check always runs there.
|
|
263
|
-
*/
|
|
264
|
-
export function enforceWalletExistsCore({ name, source }, cmd) {
|
|
265
|
-
if (name === DEFAULT) return;
|
|
266
|
-
if (EXISTENCE_EXEMPT.has(cmd)) return;
|
|
267
|
-
if (profileExists(name)) return;
|
|
268
|
-
// `name` already passed the format check (assertValidNameCore), which
|
|
269
|
-
// constrains it to lowercase/digits/'_'/'-' — but a bare 64-hex private
|
|
270
|
-
// key with no "0x" prefix satisfies that charset too, so this "not found"
|
|
271
|
-
// path can still see raw key material. looksLikeAddress() is safe to echo
|
|
272
|
-
// (an address is public); anything else goes through describeRejectedValue(),
|
|
273
|
-
// which leaves a short/plain name untouched but redacts anything shaped
|
|
274
|
-
// like a secret — so only the untouched case gets a "create it" command
|
|
275
|
-
// that's actually safe (and sensible) to suggest re-typing.
|
|
276
|
-
const shown = describeRejectedValue(name);
|
|
277
|
-
const hint = looksLikeAddress(name)
|
|
278
|
-
? `'${name}' looks like an address. For billing use: run402 billing ... --wallet-address ${name}`
|
|
279
|
-
: shown === name
|
|
280
|
-
? `Run 'run402 wallets list' to see wallets, or 'run402 wallets new ${name}' to create it.`
|
|
281
|
-
: "Run 'run402 wallets list' to see wallets. This value was not shown because it looks like a secret rather than a wallet name — if a private key or other credential landed here, treat it as compromised.";
|
|
282
|
-
throw new WalletSelectionError({
|
|
283
|
-
code: "WALLET_NOT_FOUND",
|
|
284
|
-
message: `No local wallet named '${shown}'.`,
|
|
285
|
-
hint,
|
|
286
|
-
details: { wallet: shown, source },
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/** CLI wrapper over {@link enforceWalletExistsCore}: identical check, `fail()` on error. */
|
|
134
|
+
/** {@link enforceWalletExistsCore}, `fail()` on a refusal. */
|
|
291
135
|
export function enforceWalletExists(resolved, cmd) {
|
|
292
136
|
try {
|
|
293
137
|
enforceWalletExistsCore(resolved, cmd);
|
|
294
138
|
} catch (err) {
|
|
295
|
-
|
|
296
|
-
throw err;
|
|
139
|
+
failSelection(err);
|
|
297
140
|
}
|
|
298
141
|
}
|
|
299
142
|
|
|
@@ -328,31 +171,22 @@ export function emitProvenance({ name, source, sourceDetail }, { cmd, quiet, sho
|
|
|
328
171
|
}
|
|
329
172
|
|
|
330
173
|
/**
|
|
331
|
-
*
|
|
332
|
-
*
|
|
174
|
+
* Resolve, fail closed, and publish the selection to the environment (the
|
|
175
|
+
* SDK's `selectWallet`), then the optional provenance line.
|
|
333
176
|
*/
|
|
334
177
|
export function applyWalletSelection({ walletFlag, cmd, cwd = process.cwd(), env = process.env, quiet = false } = {}) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
env.RUN402_ACTIVE_WALLET_JSON = JSON.stringify({
|
|
348
|
-
name: resolved.name,
|
|
349
|
-
source: resolved.source,
|
|
350
|
-
sourceDetail: resolved.sourceDetail,
|
|
351
|
-
binding: binding ? { wallet: binding.wallet, file: binding.file } : null,
|
|
352
|
-
envName,
|
|
353
|
-
diverged: !!(envName && binding && envName !== binding.wallet),
|
|
354
|
-
});
|
|
355
|
-
|
|
178
|
+
let resolved;
|
|
179
|
+
try {
|
|
180
|
+
resolved = selectWallet({
|
|
181
|
+
walletFlag,
|
|
182
|
+
env,
|
|
183
|
+
cwd,
|
|
184
|
+
allowConflict: CONFLICT_EXEMPT.has(cmd),
|
|
185
|
+
allowMissing: EXISTENCE_EXEMPT.has(cmd),
|
|
186
|
+
});
|
|
187
|
+
} catch (err) {
|
|
188
|
+
failSelection(err);
|
|
189
|
+
}
|
|
356
190
|
emitProvenance(resolved, {
|
|
357
191
|
cmd,
|
|
358
192
|
quiet,
|