// The manager's scheduled run (novox/hq ADR 0050/0053). It is the whole of the carve-out in one // place, and it runs on the MANAGER NODE, never in the control plane: // // 1. read the refresh token as CLEARTEXT — the host unsealed the stored box with THIS node's private // key and mounted it at the module's bound secret path, exactly as it delivers any credential. // This module holds no node key and opens nothing itself; // 2. call the vendor's OAuth token endpoint to mint a fresh access token (and maybe a rotated // refresh token); // 3. if the vendor rotated the refresh token, SEAL the new one to this node's PUBLIC sealing key // (delivered in the bound facts) with the same anonymous box the mesh seals every credential with; // 4. hand the control plane back ONLY the access token in the clear + the opaque re-sealed box — // never the refresh token — which it seals per consumer holder and stores; // 5. poll usage with the fresh access token and record the licence-grain reading. // // mesh-controller receives the products of steps 3–4 through `licence submit-refresh` (access token + // sealed box). The refresh token never leaves this process except as ciphertext, and it never had to // be opened here at all — the host did that. // // This runs as `mesh-tools run`, which connects no broker, so the outputs are written to files the // host mounts; the submit itself (the transport to mesh-controller) is done by the caller invoking // `mesh-controller licence submit-refresh`. In the lab that caller is the scenario; in production it is // an authenticated call the manager node makes. The transport is the one part stubbed here — FLAGGED // — because a cross-node authenticated command surface is out of this module's scope. import { readFileSync, writeFileSync, renameSync, mkdirSync } from "node:fs"; import { dirname } from "node:path"; import { readEnv } from "@novox/mesh-sdk/primitives"; import { seal } from "../sealedbox.js"; import { managerPublicKey, writeSealedGrant } from "../grantfile.js"; import { refreshGrant, grantFromRefresh, readUsage, flattenUsage, type UsageReading } from "../client.js"; /** The vendor-neutral usage row ADR 0054 fixes — the shape the model-usage store upserts. Kept local * to the producer (the normalisation lives in the adapter), so nothing here couples to the SDK. */ interface UsageRow { licence: string; consumer: string; period: string; metric: string; value: number; } /** Normalise a licence-grain reading into ADR 0054 rows: one utilization row per window, a row * omitted when its percentage is absent. `consumer` is the holding module — the licence grain. */ function licenceRows(licence: string, consumer: string, reading: UsageReading): UsageRow[] { const rows: UsageRow[] = []; const add = (period: string, pct: number | null): void => { if (pct !== null && pct !== undefined && Number.isFinite(pct)) { rows.push({ licence, consumer, period, metric: "utilization", value: pct }); } }; add("5h", reading.sessionPct); add("7d", reading.weeklyPct); add("extra", reading.extraPct); return rows; } function required(name: string): string { const v = process.env[name]; if (!v) throw new Error(`${name} is not set — the manager runtime was deployed without it`); return v; } function atomicWrite(path: string, content: string): void { mkdirSync(dirname(path), { recursive: true }); const tmp = `${path}.tmp`; writeFileSync(tmp, content, { mode: 0o600 }); renameSync(tmp, path); } async function main(): Promise { const licence = process.env.MESH_ANTHROPIC_LICENCE ?? "unknown"; // Step 1: the refresh token as cleartext, unsealed and mounted by the HOST. No open here. const refreshToken = readFileSync(required("MESH_MODEL_ACCESS_SECRET_FILE"), "utf8").trim(); if (!refreshToken) { // Nothing was delivered — the manager has not adopted a refresh token yet, or the push has not // landed. Said rather than treated as an empty token the vendor would reject obscurely. throw new Error("[anthropic-manager] no refresh token was delivered; adopt one first"); } // The node's PUBLIC sealing key, to re-seal a rotated refresh token. Public, delivered in the facts. const nodePub = managerPublicKey(required("MESH_MODEL_ACCESS_BIND_FILE")); // Step 2: the vendor call. const refreshed = await refreshGrant(refreshToken); if (!refreshed) { // A dead endpoint or a rejected token: nothing to publish, and we do not clobber a good grant. throw new Error(`[anthropic-manager] the refresh of ${licence} produced no grant`); } const grant = grantFromRefresh(refreshed, Date.now()); if (!grant) { throw new Error(`[anthropic-manager] the refresh of ${licence} returned no access token`); } // Step 3: re-seal the rotated refresh token, if the vendor rotated it. Nothing to store otherwise. if (grant.rotatedRefresh) { const sealed = seal(new Uint8Array(Buffer.from(grant.rotatedRefresh, "utf8")), nodePub); if (process.env.MESH_ANTHROPIC_GRANT_OUT) { writeSealedGrant(process.env.MESH_ANTHROPIC_GRANT_OUT, sealed, nodePub); } } // Step 4: the access token in the clear, for the control plane to seal per consumer holder. This is // all it ever receives that is not ciphertext. atomicWrite(required("MESH_ANTHROPIC_ACCESS_OUT"), grant.access.accessToken); console.error( `[anthropic-manager] refreshed ${licence}: access token minted` + (grant.rotatedRefresh ? ", refresh token rotated and re-sealed" : ", refresh token unchanged"), ); // Step 5: licence-grain usage, best-effort — a usage read failing must not fail the refresh. try { const usage = await readUsage(grant.access.accessToken); if (usage) { const reading = flattenUsage(usage); if (process.env.MESH_ANTHROPIC_USAGE_OUT) { atomicWrite( process.env.MESH_ANTHROPIC_USAGE_OUT, JSON.stringify({ licence, grain: "licence", ...reading }), ); } // Emit ADR-0054 rows, not a vendor-shaped body: the consumer of module.*.usage.* is the // vendor-neutral model-usage store, so the normalisation is done HERE. The node names the // holding module; with MESH_NODE unset the consumer is the module alone. const node = readEnv("MESH_NODE", ""); const consumer = node ? `${node}/anthropic-manager` : "anthropic-manager"; await emitUsage({ rows: licenceRows(licence, consumer, reading), raw: usage }); } } catch (err) { console.error(`[anthropic-manager] usage poll for ${licence} failed: ${err}`); } } /** * Emit a usage event best-effort by shelling out to the sibling mesh-tools `emit` primitive, which * is the one path that wires a broker from a run-once/scheduled step (which itself connects none). * A broker hiccup must never fail a refresh that already happened. */ async function emitUsage(body: Record): Promise { const main = process.env.MESH_TOOLS_MAIN ?? "/app/dist/main.js"; const { spawn } = await import("node:child_process"); await new Promise((resolve) => { const child = spawn(process.execPath, [main, "emit", "usage.read", JSON.stringify(body)], { stdio: "inherit", }); child.on("exit", () => resolve()); child.on("error", (err) => { console.error(`[anthropic-manager] could not emit usage: ${err}`); resolve(); }); }); } await main();