run402 4.97.0 → 4.99.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 +1 -1
- 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.test.mjs +13 -2
- package/lib/doctor.mjs +72 -811
- package/lib/init.mjs +35 -576
- package/lib/org-context.mjs +39 -376
- package/lib/orgs.mjs +22 -106
- package/lib/projects.mjs +1 -2
- package/lib/repos.mjs +6 -6
- package/lib/rooms.mjs +1 -2
- package/lib/sdk-errors.mjs +26 -0
- 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 +24 -2
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +44 -2
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts +18 -3
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +12 -1
- 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/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/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 +0 -23
- package/sdk/dist/namespaces/credentials.d.ts.map +1 -1
- package/sdk/dist/namespaces/credentials.js +29 -0
- package/sdk/dist/namespaces/credentials.js.map +1 -1
- package/sdk/dist/namespaces/escalations.d.ts.map +1 -1
- package/sdk/dist/namespaces/escalations.js +2 -0
- package/sdk/dist/namespaces/escalations.js.map +1 -1
- package/sdk/dist/namespaces/grants.d.ts.map +1 -1
- package/sdk/dist/namespaces/grants.js +4 -0
- package/sdk/dist/namespaces/grants.js.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.map +1 -1
- package/sdk/dist/namespaces/org.js +3 -0
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +5 -0
- 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 +5 -0
- package/sdk/dist/namespaces/repos.js.map +1 -1
- package/sdk/dist/namespaces/rooms.d.ts.map +1 -1
- package/sdk/dist/namespaces/rooms.js +3 -0
- 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 +9 -4
- package/sdk/dist/node/credentials.d.ts.map +1 -1
- package/sdk/dist/node/credentials.js +1 -1
- 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 +57 -5
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +36 -1
- 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/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/lightning-wallet.mjs +0 -115
package/lib/repos.mjs
CHANGED
|
@@ -21,7 +21,7 @@ import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
|
21
21
|
import { withAutoApprove } from "./sign-in.mjs";
|
|
22
22
|
import { walletAuthHeaders, isCoreApiTarget, readWallet, resolveProjectId } from "./config.mjs";
|
|
23
23
|
import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.js";
|
|
24
|
-
import { resolveOrgId
|
|
24
|
+
import { resolveOrgId } from "./org-context.mjs";
|
|
25
25
|
import { resolveVaultTarget } from "./vault-target.mjs";
|
|
26
26
|
import { nextAction, setOrgSlugAction, setRepoNameAction } from "./next-actions.mjs";
|
|
27
27
|
import { resolveHarnessLabels, resolveSessionKey, resolveTaskLabel, persistSessionKey } from "./harness-context.mjs";
|
|
@@ -845,7 +845,7 @@ async function printCreateResult({ sdk, projectId, vault, adopted, name, verbose
|
|
|
845
845
|
let address = null;
|
|
846
846
|
let orgSlug = null;
|
|
847
847
|
try {
|
|
848
|
-
const owningOrg = await
|
|
848
|
+
const owningOrg = await getSdk().orgs.owningOrgOf(projectId);
|
|
849
849
|
const orgRecord = owningOrg ? await sdk.org(owningOrg).get() : null;
|
|
850
850
|
orgSlug = orgRecord?.slug ?? null;
|
|
851
851
|
if (orgSlug && name) {
|
|
@@ -929,7 +929,7 @@ async function printCreateResult({ sdk, projectId, vault, adopted, name, verbose
|
|
|
929
929
|
|
|
930
930
|
async function createAdopt(projectId, dir, a) {
|
|
931
931
|
const sdk = getSdk();
|
|
932
|
-
const orgId = flagValue(a, "--org") ?? await
|
|
932
|
+
const orgId = flagValue(a, "--org") ?? await getSdk().orgs.owningOrgOf(projectId);
|
|
933
933
|
if (!orgId) {
|
|
934
934
|
fail({
|
|
935
935
|
code: "VAULT_ORG_UNRESOLVED",
|
|
@@ -1010,7 +1010,7 @@ async function createProvision(name, dir, a) {
|
|
|
1010
1010
|
}
|
|
1011
1011
|
}
|
|
1012
1012
|
|
|
1013
|
-
const effectiveOrgId = orgId ?? (await
|
|
1013
|
+
const effectiveOrgId = orgId ?? (await getSdk().orgs.owningOrgOf(provisioned.project_id));
|
|
1014
1014
|
if (!effectiveOrgId) {
|
|
1015
1015
|
fail({
|
|
1016
1016
|
code: "VAULT_ORG_UNRESOLVED",
|
|
@@ -1278,7 +1278,7 @@ async function rename(args) {
|
|
|
1278
1278
|
const result = await sdk.projects.setRepoName(projectId, repoName);
|
|
1279
1279
|
let address = null;
|
|
1280
1280
|
try {
|
|
1281
|
-
const owningOrg = await
|
|
1281
|
+
const owningOrg = await getSdk().orgs.owningOrgOf(projectId);
|
|
1282
1282
|
const orgSlug = owningOrg ? (await sdk.org(owningOrg).get()).slug : null;
|
|
1283
1283
|
if (orgSlug) address = vaultRemoteUrlForRepo(orgSlug, result.repo_name);
|
|
1284
1284
|
} catch {
|
|
@@ -1554,7 +1554,7 @@ async function capture(args) {
|
|
|
1554
1554
|
const repoDir = process.cwd();
|
|
1555
1555
|
const address = await detectSlugFormRemote(a, repoDir);
|
|
1556
1556
|
const target = address ? { repo_dir: repoDir } : await vaultTarget(a);
|
|
1557
|
-
const orgId = !address && !dryRun && target.project_id ? await
|
|
1557
|
+
const orgId = !address && !dryRun && target.project_id ? await getSdk().orgs.owningOrgOf(target.project_id) : null;
|
|
1558
1558
|
const opts = {
|
|
1559
1559
|
...target,
|
|
1560
1560
|
...(address ? { address } : {}),
|
package/lib/rooms.mjs
CHANGED
|
@@ -448,8 +448,7 @@ async function joinWithKey(key, a) {
|
|
|
448
448
|
// Arrival state (design D10) — best-effort throughout: the redemption
|
|
449
449
|
// already succeeded, and none of this may fail a completed join.
|
|
450
450
|
try {
|
|
451
|
-
|
|
452
|
-
setSelectedOrgId(result.org_id);
|
|
451
|
+
await getSdk().orgs.use(result.org_id);
|
|
453
452
|
} catch { /* best-effort */ }
|
|
454
453
|
|
|
455
454
|
const cwd = process.cwd();
|
package/lib/sdk-errors.mjs
CHANGED
|
@@ -44,6 +44,32 @@ export function fail({ message, code, hint, details, next_actions, field, retrya
|
|
|
44
44
|
process.exit(exit_code);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Report a refusal the Node SDK's local-state verbs threw (wallet selection,
|
|
49
|
+
* organization context, doctor/init argument checks): the same envelope
|
|
50
|
+
* `fail()` prints, fields taken from the error. Local refusals carry their
|
|
51
|
+
* own `hint` and `next_actions`; they never went through the HTTP-error
|
|
52
|
+
* rendering `reportSdkError` applies.
|
|
53
|
+
*/
|
|
54
|
+
export function failLocal(err) {
|
|
55
|
+
fail({
|
|
56
|
+
code: err?.code,
|
|
57
|
+
message: err?.message,
|
|
58
|
+
hint: err?.hint,
|
|
59
|
+
details: err?.details,
|
|
60
|
+
next_actions: err?.nextActions,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `failLocal` for a local refusal from a local-state verb, `reportSdkError`
|
|
66
|
+
* for anything else (a gateway error, a network error, a cache miss).
|
|
67
|
+
*/
|
|
68
|
+
export function reportLocalOrSdkError(err) {
|
|
69
|
+
if (err?.kind === "local_error" && err?.status === null && err?.code !== "PROJECT_CREDENTIAL_NOT_FOUND") failLocal(err);
|
|
70
|
+
reportSdkError(err);
|
|
71
|
+
}
|
|
72
|
+
|
|
47
73
|
/**
|
|
48
74
|
* Parse a JSON-bearing CLI flag value, naming the flag in the failure envelope.
|
|
49
75
|
*
|
package/lib/status.mjs
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
apiBaseSource,
|
|
8
|
-
apiTargetKind,
|
|
9
|
-
} from "./config.mjs";
|
|
1
|
+
/**
|
|
2
|
+
* run402 status — the CLI edge of `r.status()` (`@run402/sdk/node`), which
|
|
3
|
+
* assembles the local view (wallet, rail, balances, tier, projects, active
|
|
4
|
+
* project, API target). This module prints it: JSON by default, or the
|
|
5
|
+
* compact `--human` rendering.
|
|
6
|
+
*/
|
|
10
7
|
import { getSdk } from "./sdk.mjs";
|
|
11
|
-
import { fail } from "./sdk-errors.mjs";
|
|
8
|
+
import { fail, reportLocalOrSdkError } from "./sdk-errors.mjs";
|
|
12
9
|
import { assertKnownFlags, hasHelp, normalizeArgv } from "./argparse.mjs";
|
|
13
|
-
import { getActiveProfile } from "../core-dist/config.js";
|
|
14
|
-
import { readMeta } from "../core-dist/profiles.js";
|
|
15
10
|
|
|
16
11
|
const HELP = `run402 status — Show full organization state in one shot
|
|
17
12
|
|
|
@@ -35,63 +30,6 @@ Run402 Cloud status requires a wallet; Core target status can still report
|
|
|
35
30
|
local project state without one.
|
|
36
31
|
`;
|
|
37
32
|
|
|
38
|
-
// USDC / pathUSD constants (match wallet.mjs)
|
|
39
|
-
const USDC_ABI = [{ name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ name: "", type: "uint256" }] }];
|
|
40
|
-
const USDC_MAINNET = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
41
|
-
const USDC_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
42
|
-
const PATH_USD = "0x20c0000000000000000000000000000000000000";
|
|
43
|
-
const TEMPO_RPC = "https://rpc.moderato.tempo.xyz/";
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Read the on-chain wallet balance in USD micros for the current rail.
|
|
47
|
-
* For x402: read Base mainnet + Base Sepolia USDC and sum funded networks.
|
|
48
|
-
* For mpp: read pathUSD on Tempo Moderato.
|
|
49
|
-
* Returns null if every read fails (e.g. offline or RPC down).
|
|
50
|
-
*/
|
|
51
|
-
async function readWalletBalanceUsdMicros(rail, address) {
|
|
52
|
-
try {
|
|
53
|
-
const { createPublicClient, http, defineChain } = await import("viem");
|
|
54
|
-
if (rail === "mpp") {
|
|
55
|
-
const tempoModerato = defineChain({
|
|
56
|
-
id: 42431,
|
|
57
|
-
name: "Tempo Moderato",
|
|
58
|
-
nativeCurrency: { name: "pathUSD", symbol: "pathUSD", decimals: 6 },
|
|
59
|
-
rpcUrls: { default: { http: [TEMPO_RPC] } },
|
|
60
|
-
});
|
|
61
|
-
const client = createPublicClient({ chain: tempoModerato, transport: http() });
|
|
62
|
-
try {
|
|
63
|
-
const raw = await client.readContract({ address: PATH_USD, abi: USDC_ABI, functionName: "balanceOf", args: [address] });
|
|
64
|
-
return Number(raw);
|
|
65
|
-
} catch { return null; }
|
|
66
|
-
}
|
|
67
|
-
// x402 rail — read Base mainnet + Base Sepolia in parallel; sum any that succeed.
|
|
68
|
-
const { base, baseSepolia } = await import("viem/chains");
|
|
69
|
-
const mainnetClient = createPublicClient({ chain: base, transport: http() });
|
|
70
|
-
const sepoliaClient = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
71
|
-
const [mainnet, sepolia] = await Promise.all([
|
|
72
|
-
mainnetClient.readContract({ address: USDC_MAINNET, abi: USDC_ABI, functionName: "balanceOf", args: [address] }).then(Number).catch(() => null),
|
|
73
|
-
sepoliaClient.readContract({ address: USDC_SEPOLIA, abi: USDC_ABI, functionName: "balanceOf", args: [address] }).then(Number).catch(() => null),
|
|
74
|
-
]);
|
|
75
|
-
if (mainnet === null && sepolia === null) return null;
|
|
76
|
-
return (mainnet || 0) + (sepolia || 0);
|
|
77
|
-
} catch {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Normalize a project entry to the agreed-on shape: always expose `project_id`
|
|
84
|
-
* (matching `projects list`). The remote /wallets/v1/:wallet/projects endpoint
|
|
85
|
-
* returns entries keyed as `id`, so we map them here and drop the raw `id`
|
|
86
|
-
* field to avoid having two aliases for the same identity.
|
|
87
|
-
*/
|
|
88
|
-
function normalizeProject(raw) {
|
|
89
|
-
if (!raw || typeof raw !== "object") return raw;
|
|
90
|
-
const projectId = raw.project_id || raw.id;
|
|
91
|
-
const { id: _dropId, project_id: _dropPid, ...rest } = raw;
|
|
92
|
-
return { project_id: projectId, ...rest };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
33
|
export async function run(args = []) {
|
|
96
34
|
args = normalizeArgv(args);
|
|
97
35
|
if (hasHelp(args)) { console.log(HELP); process.exit(0); }
|
|
@@ -105,97 +43,19 @@ export async function run(args = []) {
|
|
|
105
43
|
hint: "JSON is the default; drop --json to keep it, or keep --human alone for the rendered view.",
|
|
106
44
|
});
|
|
107
45
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
};
|
|
114
|
-
if (!localWallet) {
|
|
115
|
-
const store = loadKeyStore();
|
|
116
|
-
const bare = {
|
|
117
|
-
wallet: null,
|
|
118
|
-
target,
|
|
119
|
-
projects: Object.keys(store.projects).map(id => ({ project_id: id })),
|
|
120
|
-
active_project: getActiveProjectId() || null,
|
|
121
|
-
hint: target.kind === "core" ? "Run: run402 projects provision --name my-app" : "Run: run402 init",
|
|
122
|
-
};
|
|
123
|
-
if (human) {
|
|
124
|
-
console.log(formatStatusHuman(bare));
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
console.log(JSON.stringify(bare));
|
|
46
|
+
let result;
|
|
47
|
+
try {
|
|
48
|
+
result = await getSdk().status();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
reportLocalOrSdkError(err);
|
|
128
51
|
return;
|
|
129
52
|
}
|
|
130
|
-
|
|
131
|
-
const wallet = localWallet.address.toLowerCase();
|
|
132
|
-
const rail = localWallet.rail || "x402";
|
|
133
|
-
|
|
134
|
-
// Parallel API calls: tier + allowance + server-side projects + on-chain wallet balance.
|
|
135
|
-
// projects.list() is the membership-scoped named inventory (project-findability);
|
|
136
|
-
// SIWX wallet auth is signed from the wallet. Best-effort — a missing
|
|
137
|
-
// wallet yields null and we fall back to the local keystore below.
|
|
138
|
-
const [status, walletBalance] = await Promise.all([
|
|
139
|
-
readRemoteStatus(getSdk(), wallet),
|
|
140
|
-
readWalletBalanceUsdMicros(rail, localWallet.address),
|
|
141
|
-
]);
|
|
142
|
-
const { tier, billing, remote } = status;
|
|
143
|
-
|
|
144
|
-
// Local keystore
|
|
145
|
-
const store = loadKeyStore();
|
|
146
|
-
const activeId = getActiveProjectId();
|
|
147
|
-
|
|
148
|
-
const projects = remote?.projects
|
|
149
|
-
? remote.projects.map(normalizeProject)
|
|
150
|
-
: Object.keys(store.projects).map(id => ({ project_id: id }));
|
|
151
|
-
|
|
152
|
-
// Which named wallet this state belongs to. `local_label` is the active
|
|
153
|
-
// profile (default for single-wallet installs); `server_label` is the
|
|
154
|
-
// cached server-side display name (null until set / when offline).
|
|
155
|
-
const walletName = getActiveProfile();
|
|
156
|
-
const walletMeta = readMeta(walletName);
|
|
157
|
-
|
|
158
|
-
// Balances are grouped under one object so the on-chain (wallet) and
|
|
159
|
-
// allowance numbers are unambiguous and rail-legible.
|
|
160
|
-
// - on_chain_usd_micros / on_chain_token: on-chain USDC (x402) or pathUSD
|
|
161
|
-
// (mpp) in the wallet, null if the RPC read failed
|
|
162
|
-
// - allowance_usd_micros / held_usd_micros: the organization's Run402-held
|
|
163
|
-
// allowance, rail-independent, null when no organization exists
|
|
164
|
-
const hasBilling = billing && billing.exists !== false;
|
|
165
|
-
const result = {
|
|
166
|
-
wallet: {
|
|
167
|
-
local_label: walletName,
|
|
168
|
-
server_label: walletMeta?.label ?? null,
|
|
169
|
-
address: localWallet.address,
|
|
170
|
-
},
|
|
171
|
-
rail,
|
|
172
|
-
remote_status: status.availability,
|
|
173
|
-
next_actions: status.next_actions,
|
|
174
|
-
projects_source: remote ? "remote" : "local_cache",
|
|
175
|
-
balances: {
|
|
176
|
-
on_chain_usd_micros: walletBalance,
|
|
177
|
-
on_chain_token: rail === "mpp" ? "pathUSD" : "USDC",
|
|
178
|
-
allowance_usd_micros: hasBilling ? billing.allowance_usd_micros : null,
|
|
179
|
-
held_usd_micros: hasBilling ? (billing.held_usd_micros ?? 0) : null,
|
|
180
|
-
},
|
|
181
|
-
tier: tier && tier.tier
|
|
182
|
-
? { name: tier.tier, status: tier.status, expires: tier.lease_perpetual === true ? null : tier.lease_expires_at }
|
|
183
|
-
: null,
|
|
184
|
-
// v1.57: lifecycle state and the per-organization escape hatch moved to the
|
|
185
|
-
// organization. Surface them at the top level so agents don't have to
|
|
186
|
-
// dig into the projects array to read them.
|
|
187
|
-
organization_lifecycle_state: tier?.organization_lifecycle_state ?? null,
|
|
188
|
-
lease_perpetual: tier?.lease_perpetual ?? null,
|
|
189
|
-
projects,
|
|
190
|
-
active_project: activeId || null,
|
|
191
|
-
target,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
53
|
if (human) {
|
|
195
54
|
console.log(formatStatusHuman(result));
|
|
196
55
|
return;
|
|
197
56
|
}
|
|
198
|
-
|
|
57
|
+
// The no-wallet view has always printed compact; the wallet view pretty.
|
|
58
|
+
console.log(result.wallet ? JSON.stringify(result, null, 2) : JSON.stringify(result));
|
|
199
59
|
}
|
|
200
60
|
|
|
201
61
|
function usdFromMicros(micros) {
|
package/lib/up.mjs
CHANGED
|
@@ -689,9 +689,8 @@ async function gitInitIfNeeded(dir) {
|
|
|
689
689
|
* never turn an otherwise-successful `up` into a failure.
|
|
690
690
|
*/
|
|
691
691
|
async function composeRepoPushStep({ sdk, workDir, projectId, createdRepository, nested = false }) {
|
|
692
|
-
const { resolveOwningOrgId } = await import("./org-context.mjs");
|
|
693
692
|
const { scaffoldVaultRemote } = await import("./vault-scaffold.mjs");
|
|
694
|
-
const orgId = await
|
|
693
|
+
const orgId = await getSdk().orgs.owningOrgOf(projectId);
|
|
695
694
|
// `--nested`: an app root INSIDE another repository (a monorepo workspace)
|
|
696
695
|
// becomes its own repository with the encrypted remote — the enclosing
|
|
697
696
|
// checkout only gains one local `.git/info/exclude` line. Without it the
|
package/lib/vault-scaffold.mjs
CHANGED
|
@@ -24,13 +24,12 @@
|
|
|
24
24
|
* throw.
|
|
25
25
|
*/
|
|
26
26
|
import { getSdk } from "./sdk.mjs";
|
|
27
|
-
import { resolveOwningOrgId } from "./org-context.mjs";
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* @param {object} options
|
|
31
30
|
* @param {string} [options.repoDir] Working tree to scaffold. Defaults to `process.cwd()`.
|
|
32
31
|
* @param {string} options.projectId The project the remote should point at.
|
|
33
|
-
* @param {string} [options.orgId] Explicit owning org. Resolved via `
|
|
32
|
+
* @param {string} [options.orgId] Explicit owning org. Resolved via `r.orgs.owningOrgOf` when omitted.
|
|
34
33
|
* @param {boolean} [options.createRepoIfMissing] Opt into `git init`-ing `repoDir` when it is not a repository yet.
|
|
35
34
|
* @param {boolean} [options.nested] Scaffold `repoDir` as its OWN repository even when it lies inside another one (`Repos.scaffoldRemote`'s `nested`).
|
|
36
35
|
* @param {string} [options.nestedCommand] The caller's own `--nested` spelling for the `create_nested_repo` next_action (default: the SDK's `run402 repos create --nested --project <project_id>`).
|
|
@@ -51,7 +50,7 @@ export async function scaffoldVaultRemote({ repoDir = process.cwd(), projectId,
|
|
|
51
50
|
out.vault_skipped = "not a git repository — re-run with --git-remote to create one and add the remote";
|
|
52
51
|
return out;
|
|
53
52
|
}
|
|
54
|
-
const resolvedOrgId = orgId ?? (await
|
|
53
|
+
const resolvedOrgId = orgId ?? (await getSdk().orgs.owningOrgOf(projectId));
|
|
55
54
|
if (!resolvedOrgId) {
|
|
56
55
|
out.reason = "org_unresolved";
|
|
57
56
|
out.vault_skipped = `could not resolve the owning org for ${projectId} — the run402 remote was not added`;
|
package/lib/vault-target.mjs
CHANGED
|
@@ -1,148 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* run402
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Targeting order for a verb run standing inside a git repository, highest
|
|
10
|
-
* first:
|
|
11
|
-
* 1. an explicit --repo/--project flag (owned by each call site — this
|
|
12
|
-
* module supplies only the fallback chain beneath it, plus the
|
|
13
|
-
* mismatch warning against tier 3)
|
|
14
|
-
* 2. the pinned `r402.repoId` in local git config — addresses the
|
|
15
|
-
* vault by repo_id directly, no network read at all
|
|
16
|
-
* 3. the repo's run402/origin remote address — id-form is parsed
|
|
17
|
-
* directly out of the address string (free, no network); slug-form is
|
|
18
|
-
* resolved via the SDK (one read-only network call — `resolveAddress`,
|
|
19
|
-
* never a pin, never a push-to-create; this is a TARGETING read, not a
|
|
20
|
-
* publish)
|
|
21
|
-
* 4. RUN402_PROJECT_ID env
|
|
22
|
-
* 5. the profile's active project
|
|
23
|
-
*
|
|
24
|
-
* Outside a repository (or when repo detection itself fails), only tiers 4
|
|
25
|
-
* and 5 apply.
|
|
26
|
-
*
|
|
27
|
-
* ARCHITECTURAL NOTE: this is CLI-edge policy (which flag/env/file wins),
|
|
28
|
-
* not vault protocol behavior — the same class of concern
|
|
29
|
-
* `wallet-context.mjs` owns for wallet selection. The protocol reads it
|
|
30
|
-
* composes (`readPinnedVaultRepo`, `resolveAddress`) already live once in
|
|
31
|
-
* the SDK; this module adds no protocol logic of its own.
|
|
2
|
+
* Vault verb targeting when standing inside a repository: the CLI edge of
|
|
3
|
+
* `resolveVaultTarget` (`@run402/sdk/node`), which owns the order — an
|
|
4
|
+
* explicit `--repo`/`--project` > this checkout's id-pin > its own
|
|
5
|
+
* `run402`/`origin` remote > `RUN402_PROJECT_ID` > the active project.
|
|
6
|
+
* `run402 repos view|snapshot|policy|mirror|fsck|gc|access` and the doctor's
|
|
7
|
+
* vault check compose it; a disagreeing explicit flag still wins, with one
|
|
8
|
+
* stderr warning naming both.
|
|
32
9
|
*/
|
|
33
|
-
import {
|
|
10
|
+
import { getSdk } from "./sdk.mjs";
|
|
11
|
+
import { repoOwnVaultTarget as sdkRepoOwnVaultTarget, resolveVaultTarget as sdkResolveVaultTarget } from "#sdk/node";
|
|
34
12
|
|
|
35
|
-
/**
|
|
36
|
-
* Tiers 4/5 (RUN402_PROJECT_ID env, then the active project) — deliberately
|
|
37
|
-
* NON-throwing, unlike `config.mjs#resolveProjectId`. `run402 doctor`'s
|
|
38
|
-
* vault check needs to report "skipped" gracefully when nothing resolves
|
|
39
|
-
* anywhere (its pre-existing, tested behavior); a `fail()`-triggered
|
|
40
|
-
* `process.exit()` here would abort doctor's ENTIRE report, not just this
|
|
41
|
-
* one check. Callers that DO want the historical PROJECT_REQUIRED failure
|
|
42
|
-
* (vault.mjs's own verbs) get it by falling back to `resolveProjectId`
|
|
43
|
-
* themselves when this returns `null` — see `vaultTarget` in vault.mjs.
|
|
44
|
-
*/
|
|
45
|
-
function envOrActiveProjectId() {
|
|
46
|
-
return (process.env.RUN402_PROJECT_ID || "").trim() || getActiveProjectId() || null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function isInsideGitRepo(repoDir) {
|
|
50
|
-
try {
|
|
51
|
-
const { hardenedGit } = await import("#sdk/node");
|
|
52
|
-
await hardenedGit(repoDir, ["rev-parse", "--git-dir"]);
|
|
53
|
-
return true;
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* The repo's OWN target, independent of any flag — the pin first, then the
|
|
61
|
-
* `run402`/`origin` remote (in that order, mirroring `scaffoldRemote`'s own
|
|
62
|
-
* naming precedence). `null` when the repo has neither, when this is not a
|
|
63
|
-
* repository at all, or (slug-form only) the remote fails to resolve over
|
|
64
|
-
* the network — a miss here is always ordinary, never thrown.
|
|
65
|
-
*/
|
|
13
|
+
/** This repository's OWN vault address (pin, else `run402`/`origin` remote), or null. */
|
|
66
14
|
export async function repoOwnVaultTarget(repoDir) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const { hardenedGit, readPinnedVaultRepo } = await import("#sdk/node");
|
|
70
|
-
const pinned = await readPinnedVaultRepo(repoDir);
|
|
71
|
-
if (pinned) return { repo_id: pinned.repo_id, project_id: null, source: "pin" };
|
|
72
|
-
|
|
73
|
-
const { parseVaultRemoteUrl, vaultRemoteAddressForm } = await import("#sdk");
|
|
74
|
-
for (const name of ["run402", "origin"]) {
|
|
75
|
-
let url;
|
|
76
|
-
try {
|
|
77
|
-
url = (await hardenedGit(repoDir, ["remote", "get-url", name])).text().trim();
|
|
78
|
-
} catch {
|
|
79
|
-
continue; // no such remote — try the other conventional name
|
|
80
|
-
}
|
|
81
|
-
if (!url) continue;
|
|
82
|
-
let address;
|
|
83
|
-
try {
|
|
84
|
-
address = parseVaultRemoteUrl(url);
|
|
85
|
-
} catch {
|
|
86
|
-
continue; // another scheme's remote — not a vault address
|
|
87
|
-
}
|
|
88
|
-
if (!address) continue; // exists, but isn't a run402 address — try the other name
|
|
89
|
-
if (vaultRemoteAddressForm(address) === "id") {
|
|
90
|
-
// id-form already carries both halves in the address string — no
|
|
91
|
-
// network read needed at all.
|
|
92
|
-
return { repo_id: null, project_id: address.project_id, source: "remote", remote_name: name };
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
const { getSdk } = await import("./sdk.mjs");
|
|
96
|
-
const resolved = await getSdk().repos.resolveAddress(address);
|
|
97
|
-
return { repo_id: resolved.repo_id, project_id: resolved.project_id, source: "remote", remote_name: name };
|
|
98
|
-
} catch {
|
|
99
|
-
// Offline, SLUG_RELEASED, not-found, ... — nothing to target from this
|
|
100
|
-
// rung; a caller falls through to env/active project.
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return null;
|
|
15
|
+
return sdkRepoOwnVaultTarget(getSdk().repos, repoDir);
|
|
105
16
|
}
|
|
106
17
|
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
* beats env beats active project, an explicit flag beats all of them.
|
|
111
|
-
* `explicitProjectId`/`explicitRepoId` are the already-parsed flag values
|
|
112
|
-
* (`undefined`/`null` when absent — this module owns no flag parsing), and
|
|
113
|
-
* either, neither, or both may be set (mirroring `--repo`/`--project`
|
|
114
|
-
* together being valid on the CLI today). `warn` receives the one-line
|
|
115
|
-
* mismatch note when an explicit flag disagrees with the repo's OWN target;
|
|
116
|
-
* the flag still wins either way. The pin carries no project_id to compare
|
|
117
|
-
* for free, so only `--repo` is checked against it; only the remote tier
|
|
118
|
-
* carries a project_id for free (id-form) or resolves one (slug-form), so
|
|
119
|
-
* only `--project` is checked against it — matching the task's own wording
|
|
120
|
-
* ("a mismatch between an explicit flag and the repo's remote").
|
|
121
|
-
*/
|
|
122
|
-
export async function resolveVaultTarget({
|
|
123
|
-
repoDir = process.cwd(),
|
|
124
|
-
explicitProjectId,
|
|
125
|
-
explicitRepoId,
|
|
126
|
-
warn = (line) => console.error(line),
|
|
127
|
-
} = {}) {
|
|
128
|
-
const needsOwn = explicitRepoId == null || explicitProjectId == null;
|
|
129
|
-
const own = needsOwn ? await repoOwnVaultTarget(repoDir) : null;
|
|
130
|
-
|
|
131
|
-
if (explicitRepoId != null && own?.source === "pin" && own.repo_id !== explicitRepoId) {
|
|
132
|
-
warn(`warning: --repo ${explicitRepoId} does not match this repo's pinned vault ${own.repo_id} — using --repo ${explicitRepoId}.`);
|
|
133
|
-
}
|
|
134
|
-
if (explicitProjectId != null && own?.source === "remote" && own.project_id && own.project_id !== explicitProjectId) {
|
|
135
|
-
warn(`warning: --project ${explicitProjectId} does not match this repo's '${own.remote_name}' remote project ${own.project_id} — using --project ${explicitProjectId}.`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (explicitRepoId != null || explicitProjectId != null) {
|
|
139
|
-
const result = {};
|
|
140
|
-
if (explicitRepoId != null) result.repo_id = explicitRepoId;
|
|
141
|
-
if (explicitProjectId != null) result.project_id = explicitProjectId;
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (own?.source === "pin") return { repo_id: own.repo_id };
|
|
146
|
-
if (own?.source === "remote" && own.project_id) return { project_id: own.project_id };
|
|
147
|
-
return { project_id: envOrActiveProjectId() };
|
|
18
|
+
/** The vault a verb addresses from `repoDir`: `{ repo_id }` or `{ project_id }`. */
|
|
19
|
+
export async function resolveVaultTarget(opts = {}) {
|
|
20
|
+
return sdkResolveVaultTarget(getSdk().repos, opts);
|
|
148
21
|
}
|