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, packet9f1563ec1), BASEbadfa52b9. Approved by Filbert (comment 28360) and Sage (comment 28361). Sage gate rerun passed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
88 lines
3.2 KiB
JavaScript
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 });
|
|
}
|