run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
73 lines • 3.47 kB
JavaScript
/**
* vault — cross-profile repo-key scan.
*
* A keystore-miss refusal (`KEYSTORE_MISSING`, `VAULT_REPO_STATE_MISSING`,
* or the non-holder half of a `VAULT_CREATION_CONFLICT` reconciliation
* attempt — see `vault-creation-journal.ts`) is read against the ACTIVE
* wallet profile only. When the repo's key actually lives under a DIFFERENT
* local profile — the common dogfood shape: the active wallet changed
* outside a bound workspace, or `--wallet`/`RUN402_WALLET` was never set for
* this shell — the refusal named a remedy ("restore the keystore") that did
* not apply, and said nothing about the faster one that did.
*
* This module is a PURELY LOCAL, READ-ONLY directory + filename scan: it
* lists `profiles/` and checks whether `repos/<repo_id>.json` EXISTS under
* each one. It never opens, parses, or reads the CONTENTS of any file it
* finds — a profile "holds" the key when the filename is present, nothing
* more — so it can never leak key material into an error message.
*
* Shared by every keystore-miss enrichment point (`vault-publication.ts`'s
* `Vault.repoFile()`, and `vault-creation-journal.ts`'s
* conflict-reconciliation non-holder path) so the hint text and the two
* named selection mechanisms (`--wallet` / `RUN402_WALLET`) are written once.
*/
import { existsSync } from "node:fs";
import { join } from "node:path";
import { listProfileNames, profileDir } from "../../core-dist/profiles.js";
import { VAULT_SRC_RE } from "../namespaces/vault.crypto.js";
/**
* Which local profiles hold a repo-key FILE for `repoId` — a directory
* listing plus a filename check, nothing more. Built on `core/src/profiles.ts`'s
* own `listProfileNames`/`profileDir` — the SAME "wallets on this machine"
* enumeration `run402 wallets list` uses — rather than a second copy of that
* logic. Never throws: an unreadable profiles directory, a permissions
* error, or a malformed `repoId` all resolve to "found nothing" rather than
* failing the refusal path this feeds into.
*/
export function findLocalProfilesHoldingVaultRepo(repoId, options = {}) {
if (!VAULT_SRC_RE.test(repoId))
return [];
const found = [];
for (const profile of listProfileNames()) {
if (options.excludeProfile && profile === options.excludeProfile)
continue;
try {
const repoPath = join(profileDir(profile), "vault", "repos", `${repoId}.json`);
if (existsSync(repoPath))
found.push(profile);
}
catch {
// treat as absent — this is a diagnostic hint, never a hard failure
}
}
return found;
}
/**
* Build the `next_actions` entries naming the profile(s) found and the two
* selection mechanisms every keystore-miss refusal points at. `[]` when the
* scan finds nothing local to point at — callers append this to whatever
* refusal-specific remedies they already carry, never replacing them.
*/
export function crossProfileVaultHint(repoId, options = {}) {
const profiles = findLocalProfilesHoldingVaultRepo(repoId, options);
if (profiles.length === 0)
return [];
const named = profiles.map((p) => `'${p}'`).join(", ");
return [
{
action: `this repo's key exists under wallet ${named} on this machine — ` +
`run with --wallet <name> or set RUN402_WALLET=<name> to select it`,
},
];
}
//# sourceMappingURL=vault-profile-scan.js.map