Files
stack/packages/cli/tests/other-tree.test.mjs
jason.woltje a8d9eecf65 organization: move packages/business to packages/organization (rename r2 stage B1)
git mv packages/business -> packages/organization (@mosaic/organization). The
old package stays as one-line re-export shims of each moved module, with
src/business.mjs re-exporting src/organization-config.mjs and src/cli.mjs
forwarding to the moved executable. BusinessError is OrganizationConfigError
(one constructor, name kept BusinessError); OrganizationError stays distinct.
The bus adapter gains organization-context.mjs (busOrganization), with
business.mjs (busBusiness) as the same function.

Import consumers, manifests, the lockfile, scripts/mosaic, stack-copy.sh
COPY_PATHS (both roots), seat sandbox RUNNER_FILES and the copy closure
walker (organization-imports.mjs, both roots required) move to the new path.
v1 serialization, v1 writers and the stage A fixtures are unchanged; the stage
A contract tests stay where they were and pass as before.
2026-11-09 11:47:48 -06:00

55 lines
2.9 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { OTHER_TREE, run } from "../src/cli.mjs";
import { humanTransport } from "../src/transport.mjs";
import { humanEnv, io, tmp } from "./helpers.mjs";
import { mkdirSync } from 'node:fs';
import { join } from 'node:path';
import { reserveOrg, activateOrg } from '../../organization/src/org-registry.mjs';
// Row 130 (#1625): the broker accepts the human and tester proofs only from
// the tree the bus runs from, so a refusal with human-required or
// tester-required gets one more stderr line naming the command that works.
// The spawn stands in for human-cli.mjs and tester-cli.mjs: it exits 1 with
// the code on stderr, and the real transport parses it.
const refusing = (code) => () => ({ status: 1, stdout: "", stderr: `${code}\n` });
const HINT = `mosaic: ${OTHER_TREE}\n`;
async function orgFixture(t) {
const root = tmp(t), dataRoot = join(root, 'data'), configDir = join(root, 'mosaic-test');
mkdirSync(dataRoot, { mode: 0o700 }); mkdirSync(configDir, { mode: 0o700 });
const ctx = { dataRoot, configDir, instance: 'test' };
await reserveOrg(ctx, 'demo'); await activateOrg(ctx, 'demo');
return { dataRoot, env: humanEnv({ MOSAIC_CONFIG: join(configDir, 'config.json') }) };
}
test("a human command refused with human-required prints the other-tree line and exits 3", async (t) => {
const x = io();
const transport = (business) => humanTransport({ socket: "/nonexistent/bus.sock", business, env: {}, spawn: refusing("human-required") });
const code = await run(["inbox", "--business", "demo"], x, { system: { dataRoot: tmp(t) }, transport });
assert.equal(code, 3);
assert.equal(x.err.text, `mosaic: human-required\n${HINT}`);
assert.equal(x.out.text, "");
});
test("a --tester command refused with tester-required prints the other-tree line and exits 3", async (t) => {
const f = await orgFixture(t), x = io({ ...f.env, CLAUDECODE: "1" });
const code = await run(["agents", "--tester", "--business", "demo"], x, { system: { dataRoot: f.dataRoot }, testerSpawn: refusing("tester-required") });
assert.equal(code, 3);
assert.equal(x.err.text, `mosaic: tester-required\n${HINT}`);
});
test("other exit-3 refusals print no other-tree line", async (t) => {
const f = await orgFixture(t), off = io({ ...f.env, CLAUDECODE: "1" });
assert.equal(await run(["agents", "--tester", "--business", "demo"], off, { system: { dataRoot: f.dataRoot }, testerSpawn: refusing("tester-off") }), 3);
assert.equal(off.err.text, "mosaic: tester-off\n");
const agent = io({ ...humanEnv(), CLAUDECODE: "1" });
assert.equal(await run(["inbox", "--business", "demo"], agent, { system: { dataRoot: tmp(t) } }), 3);
assert.match(agent.err.text, /^mosaic: refused: this runs only from a human shell/);
assert.doesNotMatch(agent.err.text, /tree it runs from/);
});
test("the line names no path", () => {
assert.doesNotMatch(OTHER_TREE, /\//);
});