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.
91 lines • 4.28 kB
JavaScript
/**
* `r.status()` — the organization's state in one read, owned by the Node
* SDK: the active wallet (`local_label`, `server_label`, address), its rail,
* on-chain and allowance balances, the tier and its lease, the projects
* (server-side, falling back to the local key cache), the active project, and
* the API target. This is the LOCAL view — which wallet this machine acts as —
* combined with the reads that wallet can make; it never returns key material.
*
* With no local wallet the answer is the bare local state (`wallet: null`,
* the locally known projects, the active project, the target) plus the next
* command; Run402 Core targets can still report it without a wallet.
* `run402 status` is a shim over this.
*/
import { getActiveProfile, getApiBase, getApiBaseSource, getApiTargetKind, } from "../../core-dist/config.js";
import { readLocalWallet } from "./wallets.js";
import { getActiveProjectId, loadKeyStore } from "../../core-dist/keystore.js";
import { readMeta } from "../../core-dist/profiles.js";
import { readRemoteStatus } from "./remote-status.js";
import { railBalanceKeys, readOnChainBalances, sumOnChainBalances } from "./onchain-balances.js";
/** Always expose `project_id` (the remote listing keys entries as `id`), never both. */
function normalizeProject(raw) {
if (!raw || typeof raw !== "object")
return raw;
const projectId = (raw.project_id || raw.id);
const { id: _dropId, project_id: _dropPid, ...rest } = raw;
return { project_id: projectId, ...rest };
}
export async function runStatus(r) {
const localWallet = readLocalWallet();
const target = {
api_base: getApiBase(),
api_base_source: getApiBaseSource(),
kind: getApiTargetKind(),
};
if (!localWallet) {
const store = loadKeyStore();
return {
wallet: null,
target,
projects: Object.keys(store.projects).map((id) => ({ project_id: id })),
active_project: getActiveProjectId() || null,
hint: target.kind === "core" ? "Run: run402 projects provision --name my-app" : "Run: run402 init",
};
}
const wallet = localWallet.address.toLowerCase();
const rail = localWallet.rail || "x402";
// Tier, allowance, and the membership-scoped project inventory, beside the
// on-chain balance, all best-effort.
const balanceKeys = railBalanceKeys(rail);
const [status, onChainByNetwork] = await Promise.all([
readRemoteStatus(r, wallet),
readOnChainBalances(localWallet.address, balanceKeys),
]);
const { tier, billing, remote } = status;
const store = loadKeyStore();
const activeId = getActiveProjectId();
const projects = remote?.projects
? remote.projects.map(normalizeProject)
: Object.keys(store.projects).map((id) => ({ project_id: id }));
const walletName = getActiveProfile();
const walletMeta = readMeta(walletName);
const hasBilling = billing && billing.exists !== false;
return {
wallet: {
local_label: walletName,
server_label: walletMeta?.label ?? null,
address: localWallet.address,
},
rail,
remote_status: status.availability,
next_actions: status.next_actions,
projects_source: remote ? "remote" : "local_cache",
balances: {
on_chain_usd_micros: sumOnChainBalances(onChainByNetwork, balanceKeys),
on_chain_by_network: onChainByNetwork,
on_chain_token: rail === "mpp" ? "pathUSD" : "USDC",
allowance_usd_micros: hasBilling ? billing.allowance_usd_micros : null,
held_usd_micros: hasBilling ? (billing.held_usd_micros ?? 0) : null,
},
tier: tier && tier.tier
? { name: tier.tier, status: tier.status, expires: tier.lease_perpetual === true ? null : tier.lease_expires_at }
: null,
// Lifecycle and the perpetual flag live on the organization; surfaced at the top.
organization_lifecycle_state: tier?.organization_lifecycle_state ?? null,
lease_perpetual: tier?.lease_perpetual ?? null,
projects,
active_project: activeId || null,
target,
};
}
//# sourceMappingURL=status.js.map