// Row 65 (REQ-PLUG-2, Q156): the two harness modules load through the loader with every export // the kind names, answer the questions core used to answer by name, and no core source names a // harness outside the exceptions the brief lists. import test from "node:test"; import assert from "node:assert/strict"; import { chmodSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, relative, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { spawnSync } from "node:child_process"; import { createLoader } from "../src/loader.mjs"; import { KINDS } from "../src/kinds.mjs"; const REPO = resolve(fileURLToPath(new URL("../../../", import.meta.url))); async function load(name) { const logged = []; const loader = createLoader({ log: entry => logged.push(entry) }); const result = await loader.load({ harness: [name] }); assert.deepEqual(result.refused, [], name); assert.deepEqual(logged, [], name); const [module] = loader.modules("harness"); return module; } function scratch(t) { const root = mkdtempSync(join(tmpdir(), "mosaic-harness-plugin-")); t.after(() => rmSync(root, { recursive: true, force: true })); return root; } test("row 65 both harness modules load through the loader with every export the kind names", async () => { for (const name of ["pi", "claude-code"]) { const module = await load(name); for (const key of KINDS.harness.exports) assert.equal(typeof module[key], "function", `${name} ${key}`); assert.equal(module.interfaceVersion, 1); } }); test("row 65 each module answers for its own harness: adapter, levels, account, web, turn end and session files", async () => { const pi = await load("pi"), claude = await load("claude-code"); assert.equal(pi.adapter(), join(REPO, "adapters", "pi", "adapter.sh")); assert.equal(claude.adapter(), join(REPO, "adapters", "claude", "adapter.sh")); // pi 0.85.1 --thinking and claude 2.1.302 --effort, as probed (BUILD.md); claude has no off or minimal. assert.deepEqual([...pi.levels()], ["off", "minimal", "low", "medium", "high", "xhigh", "max"]); assert.deepEqual([...claude.levels()], ["low", "medium", "high", "xhigh", "max"]); assert.deepEqual([pi.countsAccount(), claude.countsAccount()], [false, true]); assert.deepEqual([pi.builtinWeb(), claude.builtinWeb()], [false, true]); assert.deepEqual([pi.turnEnd(), claude.turnEnd()], ["marker", "exit"]); assert.deepEqual([pi.outputPolicy({ proxy: true }), pi.outputPolicy({ proxy: false }), claude.outputPolicy({ proxy: true }), claude.outputPolicy({ proxy: false })], ["non-newline-stdout", "stdout", "adapter", "adapter"]); assert.deepEqual([pi.typedName("list_tasks"), claude.typedName("list_tasks")], ["list_tasks", "mcp__mosaic__list_tasks"]); assert.equal(pi.gateTimeout(), null); assert.deepEqual(claude.gateTimeout(), { n: 10, k: 2, hook: 20 }); assert.equal(pi.transcript({ runDir: "/r" }), "/r/session"); assert.equal(claude.transcript({ runDir: "/r" }), "/r/home/.claude/projects"); assert.equal(pi.transcript({ runDir: "/r", store: { session: "/s", projects: "/p" } }), "/s"); assert.equal(claude.transcript({ runDir: "/r", store: { session: "/s", projects: "/p" } }), "/p"); assert.equal(pi.reliesOn().length, 5); assert.equal(claude.reliesOn().length, 5); }); test("row 65 claude-code preflight: a missing credential, then a missing or relative binary, each refuse with their code", async t => { const claude = await load("claude-code"); const root = scratch(t); const bin = join(root, "claude"); writeFileSync(bin, "#!/bin/sh\necho 2.1.302\n"); chmodSync(bin, 0o755); const token = { CLAUDE_CODE_OAUTH_TOKEN: "fixture" }; assert.equal(claude.preflight({ env: { MOSAIC_CLAUDE_BIN: bin } }).code, "no-session-credential"); assert.equal(claude.preflight({ env: { ...token, PATH: join(root, "none") } }).code, "harness-binary-missing"); assert.equal(claude.preflight({ env: { ...token, MOSAIC_CLAUDE_BIN: "claude" } }).code, "harness-binary-missing"); assert.equal(claude.preflight({ env: { ...token, MOSAIC_CLAUDE_BIN: bin } }), null); assert.equal(claude.preflight({ env: { ...token, PATH: root } }), null); assert.equal(claude.version({ env: { MOSAIC_CLAUDE_BIN: bin, PATH: process.env.PATH } }), "2.1.302"); // The pinned binary outside /usr is mounted where the adapter looks for it, and the unslop hook's // files where the hook commands name them (row 66). const unslop = ["claude-hook.js", "unslop-check.js", "lists.json"].map(f => [join(REPO, "tools", "unslop-hook", f), undefined]); assert.deepEqual(claude.mounts({ env: { MOSAIC_CLAUDE_BIN: bin } }).map(m => [m.src, m.dest]), [[bin, bin], ...unslop, [join(REPO, "adapters/claude/stream.mjs"), undefined]]); assert.deepEqual(claude.mounts({ env: {} }).map(m => [m.src, m.dest]), [...unslop, [join(REPO, "adapters/claude/stream.mjs"), undefined]]); }); // Row 68's claudeVersion precedence, moved here with the version (row 65): the manifest records // what the binary sessions run answers. test("row 65 claude-code version asks MOSAIC_CLAUDE_BIN when set, else claude on PATH, else null", async t => { const claude = await load("claude-code"); const dir = scratch(t); mkdirSync(join(dir, "bin")); const stand = (p, v) => { writeFileSync(p, `#!/bin/sh\necho "${v} (Claude Code)"\n`); chmodSync(p, 0o755); return p; }; stand(join(dir, "bin", "claude"), "1.0.0"); const pinned = stand(join(dir, "pinned"), "9.9.9"); const PATH = join(dir, "bin"); assert.equal(claude.version({ env: { PATH, MOSAIC_CLAUDE_BIN: pinned } }), "9.9.9 (Claude Code)"); assert.equal(claude.version({ env: { PATH } }), "1.0.0 (Claude Code)"); assert.equal(claude.version({ env: { PATH: join(dir, "none") } }), null); }); test("row 65 pi preflight refuses missing credentials, and its version is the package pin", async () => { const pi = await load("pi"); assert.equal(pi.preflight({ env: {} }).code, "no-session-credential"); const pkg = JSON.parse(readFileSync(join(REPO, "package.json"), "utf8")); assert.equal(pi.version({ env: {} }), pkg.dependencies?.["@earendil-works/pi-coding-agent"] ?? pkg.devDependencies?.["@earendil-works/pi-coding-agent"]); // Row 66: the unslop extension's files, bound read-only at their own paths. assert.deepEqual(pi.mounts({ env: {} }).map(m => m.dest ?? m.src), [join(REPO, "packages/plugins/harness/pi/model-stream.mjs"), join(REPO, "node_modules"), ...["extension.ts", "unslop-check.js", "lists.json"].map(f => join(REPO, "tools", "unslop-hook", f))]); }); test("row 65 env passes the thinking level to both adapters, and claude-code's bundle writes its hook and MCP files", async t => { const pi = await load("pi"), claude = await load("claude-code"); const session = { provider: "fixture", model: "m", thinking: "high", toolSocket: "/run/tools.sock" }; const piEnv = pi.env({ policy: { tools: ["read"] }, tools: [{ name: "list_tasks" }], session }); assert.equal(piEnv.PI_OFFLINE, "1", "pi avoids startup network operations"); assert.deepEqual([piEnv.MOSAIC_THINKING, piEnv.PI_MODEL, piEnv.MOSAIC_TOOLS], ["high", "m", "read,list_tasks"]); assert.equal(piEnv.MOSAIC_MODEL_ACTIVITY_SOURCE, undefined, "Pi retains stdout fallback for paths without streaming activity"); // Row 66: pi loads the unslop check as its second extension. assert.deepEqual(piEnv.MOSAIC_EXTENSIONS.split(","), [join(REPO, "packages", "harness", "src", "pi-extension.mjs"), join(REPO, "tools", "unslop-hook", "extension.ts")]); const dir = scratch(t); const written = []; const write = (name, text) => { writeFileSync(join(dir, name), text); written.push(name); return [name, "0".repeat(64)]; }; const quote = path => { assert.ok(!path.includes("'")); return `'${path}'`; }; const out = claude.bundle({ dir, files: { policy: join(dir, "policy.json"), tools: join(dir, "tools.json") }, session, write, quote }); assert.deepEqual(written, ["settings.json", "mcp.json"]); const settings = JSON.parse(readFileSync(join(dir, "settings.json"), "utf8")); assert.match(settings.hooks.PreToolUse[0].hooks[0].command, /^timeout -k 2 10 .* \|\| exit 2$/); assert.equal(settings.hooks.PreToolUse[0].hooks[0].timeout, 20); // Row 66: the unslop hooks can't block: each command ends with `; exit 0`. assert.match(settings.hooks.Stop[0].hooks[0].command, /^timeout -k 2 10 .*claude-hook\.js' stop; exit 0$/); assert.match(settings.hooks.UserPromptSubmit[0].hooks[0].command, /^timeout -k 2 10 .*claude-hook\.js' prompt; exit 0$/); assert.equal(JSON.parse(readFileSync(join(dir, "mcp.json"), "utf8")).mcpServers.mosaic.args.at(-1), "/run/tools.sock"); const claudeEnv = claude.env({ files: out.files, policy: { tools: ["read"], typed: [] }, session }); assert.equal(claudeEnv.MOSAIC_MODEL_ACTIVITY_SOURCE, "adapter"); assert.deepEqual([claudeEnv.MOSAIC_THINKING, claudeEnv.MOSAIC_CLAUDE_SETTINGS, claudeEnv.MOSAIC_CLAUDE_MCP_CONFIG], ["high", out.files.settings, out.files.mcp]); }); // The level a route names reaches the harness binary as its flag: each module's env() feeds the // real adapter, and a stand-in pi or claude records the argv it was given (dewey B3). test("row 65 a route's thinking reaches pi as --thinking and claude as --effort, through each module's env and adapter", async t => { const pi = await load("pi"), claude = await load("claude-code"); const dir = scratch(t); mkdirSync(join(dir, "bin")); for (const name of ["pi", "claude"]) { writeFileSync(join(dir, "bin", name), '#!/bin/sh\nprintf "%s\\n" "$@" > "$ARGV_OUT"\necho \'{"type":"result","subtype":"success","result":"ok"}\'\n'); chmodSync(join(dir, "bin", name), 0o755); } for (const f of ["prompt.md", "settings.json", "mcp.json"]) writeFileSync(join(dir, f), "{}"); const run = (adapter, moduleEnv) => { const out = join(dir, "argv"); rmSync(out, { force: true }); const r = spawnSync("/bin/sh", [join(REPO, "adapters", adapter, "adapter.sh")], { encoding: "utf8", env: { PATH: `${join(dir, "bin")}:/usr/bin:/bin`, ARGV_OUT: out, MOSAIC_SYSTEM_PROMPT_FILE: join(dir, "prompt.md"), MOSAIC_REQUEST: "x", MOSAIC_WORKSPACE: join(dir, "ws"), MOSAIC_SESSION_DIR: join(dir, "session"), MOSAIC_MODEL: "m", ...moduleEnv, }, }); assert.equal(r.status, 0, r.stderr); return readFileSync(out, "utf8").split("\n"); }; const flag = (argv, name) => { assert.equal(argv.filter(a => a === name).length, 1, argv.join(" ")); return argv[argv.indexOf(name) + 1]; }; for (const thinking of ["xhigh", "low"]) { const session = { provider: "fixture", model: "m", thinking, toolSocket: "/run/tools.sock" }; assert.equal(flag(run("pi", pi.env({ policy: { tools: ["read"] }, tools: [], session })), "--thinking"), thinking); const files = { settings: join(dir, "settings.json"), mcp: join(dir, "mcp.json") }; assert.equal(flag(run("claude", claude.env({ files, policy: { tools: ["read"], typed: [] }, session })), "--effort"), thinking); } }); // A harness name in core: a quoted "pi" or "claude-code", or either inside a regex alternation. const NAMED = /["'`](?:pi|claude-code)["'`]|[(|](?:pi|claude-code)[|)]/; // The brief's Out of scope list: the tool-policy gate, the human-proof check, the engines that // start pi directly, and the process scan. Each must still name a harness, so the list stays true. const EXCEPT = [ "packages/harness/src/gate.mjs", "packages/harness/src/claude-gate.mjs", "packages/harness/src/pi-extension.mjs", "packages/bus/src/human.mjs", "packages/conversation/src/", "packages/discord/src/", "packages/control-board/src/scan.mjs", ]; function sources(dir, out = []) { for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); if (entry.isDirectory()) { if (entry.name !== "node_modules" && entry.name !== "third_party") sources(path, out); } else if (/\.(?:mjs|js)$/.test(entry.name)) out.push(path); } return out; } test("row 65 no core source outside packages/plugins names a harness, apart from the listed exceptions", () => { const named = []; const hit = new Set(); for (const pkg of readdirSync(join(REPO, "packages"))) { if (pkg === "plugins") continue; let files; try { files = sources(join(REPO, "packages", pkg, "src")); } catch (e) { if (e.code === "ENOENT") continue; throw e; } for (const file of files) { const rel = relative(REPO, file); readFileSync(file, "utf8").split("\n").forEach((line, i) => { if (!NAMED.test(line)) return; const exception = EXCEPT.find(e => (e.endsWith("/") ? rel.startsWith(e) : rel === e)); if (exception) hit.add(exception); else named.push(`${rel}:${i + 1}: ${line.trim()}`); }); } } assert.deepEqual(named, []); assert.deepEqual([...hit].sort(), [...EXCEPT].sort(), "every exception still names a harness"); // human.mjs keeps one: the human-proof regex that refuses any agent harness binary. const human = readFileSync(join(REPO, "packages", "bus", "src", "human.mjs"), "utf8").split("\n").filter(line => NAMED.test(line)); assert.deepEqual(human.map(line => line.trim()), ["/^(pi|claude|claude-code|codex)(?:\\.js)?$/.test(command) ||"]); }); test("row 65 the grep's pattern catches a quoted name and a regex alternation, and not a word in prose", () => { for (const line of ['if (harness === "pi")', "x = 'claude-code';", "/^(pi|codex)$/", "/^(codex|claude-code)$/", "if (harness !== 'pi')", "['pi', 'claude-code'].includes(harness)"]) assert.ok(NAMED.test(line), line); for (const line of ["// pi runs the bundle", "const piModel = 1;", "pipeline"]) assert.ok(!NAMED.test(line), line); }); test('pi materializes module-declared compatibility without a provider-specific switch', async t => { const pi=await load('pi'),root=scratch(t),dir=join(root,'bundle');mkdirSync(dir); const entry={provider:'fixture',model:'fixture-id'},compat={thinkingFormat:'openai',zaiToolStream:false}; const out=pi.bundle({dir,models:{fixture:entry},proxy:{baseUrl:'http://127.0.0.1:9999',key:'fixture-secret'},transports:{fixture:{piProvider:'fixture',endpoint:'v1',api:'openai-completions',compat}}}); assert.deepEqual(JSON.parse(readFileSync(out.files.proxyModels,'utf8')).providers.fixture.compat,compat); });