Files
stack/packages/cli/src/transport.mjs
T
jason.woltjeandClaude Opus 5.5 179697a8a3 bus: tester identity for PM tests (row 110, #1604)
A tester binds with a process proof from the bus's own tester-cli.mjs
when the business var bus.tester is true. It may send [mos test] messages
to a role, receive replies on the tester address and use the read verbs;
every other verb refuses. Messages store from_role tester and write no
human.input event. turnRequest() marks them as never Jason's instruction.
human.mjs is unchanged.

Candidate manifest bdaf7f476abd0b2b5095ab2f7f43e38540e6ba48ee14a02a4f4995a1469b79df
(Darkwing round 2, packet 9f1563ec1), BASE badfa52b9. Approved by Filbert
(comment 28360) and Sage (comment 28361). Sage gate rerun passed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 20:43:40 -05:00

88 lines
3.2 KiB
JavaScript

// The human transport (lead decision 70): run
// `packages/bus/src/human-cli.mjs <socket>` as a child, write
// `{business, verb, args}` on its stdin, read the JSON reply on its stdout,
// or one bus error code on its stderr. The bus does the proof: the child
// re-executes itself with a nonce and the broker checks the process and its
// ancestry for agent markers. Nothing here carries a capability.
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import { CliError } from "./errors.mjs";
export const HUMAN_CLI = fileURLToPath(new URL("../../bus/src/human-cli.mjs", import.meta.url));
export const TESTER_CLI = fileURLToPath(new URL("../../bus/src/tester-cli.mjs", import.meta.url));
// The broker's markers (packages/bus/src/human.mjs). The broker checks the
// whole ancestry; this check is only the clear early message for the case
// it would refuse anyway.
export const AGENT_MARKERS = Object.freeze([
"MOSAIC_BUS_CAP",
"MOSAIC_RUN_ID",
"MOSAIC_AGENT_RUN",
"CLAUDECODE",
"CLAUDE_CODE_ENTRYPOINT",
"CODEX_THREAD_ID",
"PI_AGENT_DIR",
]);
export function refuseInsideAgent(env = process.env) {
const found = AGENT_MARKERS.filter((k) => env[k]);
if (found.length > 0) {
throw new CliError(`refused: this runs only from a human shell, outside any agent run (found ${found.join(", ")} in the environment)`, 3);
}
}
// Exit codes by bus error code; anything else is invalid input (2).
const EXIT = {
"human-required": 3,
unauthenticated: 3,
"unknown-business": 3,
"read-only": 3,
"tester-required": 3,
"tester-off": 3,
"tester-refused": 3,
"outcome-unknown": 1,
"response-too-large": 1,
"invalid-response": 1,
};
export function busExit(code) {
return EXIT[code] ?? 2;
}
// Returns a call(verb, args) for one business. `cli` and `spawn` exist for
// the tests; the command line never sets them.
export function humanTransport({ socket, business, env = process.env, cli = HUMAN_CLI, spawn = spawnSync, timeoutMs = 30000 }) {
return async function call(verb, args = {}) {
const proc = spawn(process.execPath, [cli, socket], {
input: `${JSON.stringify({ business, verb, args })}\n`,
encoding: "utf8",
env,
timeout: timeoutMs,
maxBuffer: 8 * 1024 * 1024,
});
if (proc.error || proc.status === null) throw new CliError("outcome-unknown: the bus transport did not finish", 1);
if (proc.status !== 0) {
const code = String(proc.stderr ?? "").trim().split("\n").reverse().find((l) => /^[a-z-]{1,64}$/.test(l)) ?? "invalid-response";
const error = new CliError(code, busExit(code));
error.code = code;
throw error;
}
try {
return JSON.parse(proc.stdout);
} catch {
const error = new CliError("invalid-response", 1);
error.code = "invalid-response";
throw error;
}
};
}
// Row 110 (#1604): the tester's transport is the same exchange through
// tester-cli.mjs. It makes no agent check of its own: a tester runs from
// inside Mos or a T3 seat, and the broker refuses one under a managed run or
// while the business's bus.tester is off.
export function testerTransport(options) {
return humanTransport({ cli: TESTER_CLI, ...options });
}