diff --git a/packages/mosaic/src/commands/comms.spec.ts b/packages/mosaic/src/commands/comms.spec.ts index df5b2711..a20a85aa 100644 --- a/packages/mosaic/src/commands/comms.spec.ts +++ b/packages/mosaic/src/commands/comms.spec.ts @@ -68,7 +68,7 @@ describe('registerCommsCommand routing', () => { ); writeFileSync( join(repo, 'tools', 'comms-send.sh'), - `#!/usr/bin/env bash\nprintf '%s\\n' "$*" >> ${JSON.stringify(commsLog)}\nexit 5\n`, + `#!/usr/bin/env bash\nprintf '%s\\n' "$*" >> ${JSON.stringify(commsLog)}\nprintf 'FLEET_COMMS_REPO=%s FLEET_COMMS_SITE=%s\\n' "$FLEET_COMMS_REPO" "$FLEET_COMMS_SITE" >> ${JSON.stringify(commsLog)}\nexit 5\n`, ); chmodSync(join(brain, 'tools', 'tmux', 'agent-send.sh'), 0o755); chmodSync(join(repo, 'tools', 'comms-send.sh'), 0o755); @@ -112,7 +112,13 @@ describe('registerCommsCommand routing', () => { { from: 'user' }, ); expect(process.exitCode).toBe(5); - expect(readFileSync(f.commsLog, 'utf8').trim()).toBe('-t usc/fred -c human -m hello there'); + expect(readFileSync(f.commsLog, 'utf8').split('\n')[0]?.trim()).toBe( + '-t usc/fred -c human -m hello there', + ); + // The sender must bind comms-send.sh to the SELECTED repo (codex 9c8b6ebf). + expect(readFileSync(f.commsLog, 'utf8')).toContain( + `FLEET_COMMS_REPO=${f.repo} FLEET_COMMS_SITE=usc`, + ); expect(existsSync(f.tmuxLog)).toBe(false); // same-host tool never invoked }); diff --git a/packages/mosaic/src/commands/comms.ts b/packages/mosaic/src/commands/comms.ts index ae164cdb..cb6cada7 100644 --- a/packages/mosaic/src/commands/comms.ts +++ b/packages/mosaic/src/commands/comms.ts @@ -105,7 +105,11 @@ export function registerCommsCommand(program: Command): void { process.exitCode = 2; // invocation defect: fixable by the caller return; } - const env = { ...process.env, FLEET_COMMS_SITE: opts.site }; + // comms-send.sh locates its working repo via FLEET_COMMS_REPO + // (default $HOME/src/fleet-comms); without this, --comms-repo + // would select the executable but not the repository it operates + // on (codex review of 9c8b6ebf). + const env = { ...process.env, FLEET_COMMS_SITE: opts.site, FLEET_COMMS_REPO: repo }; const result = spawnSync(tool, fleetCommsSendArgs(opts.site, target, message, opts), { stdio: 'inherit', env, diff --git a/packages/mosaic/src/commands/q.spec.ts b/packages/mosaic/src/commands/q.spec.ts index 9cd9a132..e86a7550 100644 --- a/packages/mosaic/src/commands/q.spec.ts +++ b/packages/mosaic/src/commands/q.spec.ts @@ -57,6 +57,10 @@ describe('registerQCommand usage + dispatch', () => { process.exitCode = undefined; await program.parseAsync(['q', 'bogus'], { from: 'user' }); expect(process.exitCode).toBe(2); + process.exitCode = undefined; + // Reserved property names must not leak through the record lookup. + await program.parseAsync(['q', 'toString'], { from: 'user' }); + expect(process.exitCode).toBe(2); }); it('execs the brain tool with pass-through args and exit code', async () => { diff --git a/packages/mosaic/src/commands/q.ts b/packages/mosaic/src/commands/q.ts index d7f3f667..0bcfb8bb 100644 --- a/packages/mosaic/src/commands/q.ts +++ b/packages/mosaic/src/commands/q.ts @@ -44,7 +44,7 @@ export function registerQCommand(program: Command): void { const home = mosaicHome ?? DEFAULT_MOSAIC_HOME; const sub = args[0]; - if (!sub || !(sub in SUBCOMMANDS)) { + if (!sub || !Object.hasOwn(SUBCOMMANDS, sub)) { console.error('mosaic q: expected a subcommand:'); for (const [name, entry] of Object.entries(SUBCOMMANDS)) { console.error(` mosaic q ${name} ${entry.help}`); diff --git a/packages/mosaic/src/commands/watch.ts b/packages/mosaic/src/commands/watch.ts index 68ce927e..a507b011 100644 --- a/packages/mosaic/src/commands/watch.ts +++ b/packages/mosaic/src/commands/watch.ts @@ -28,6 +28,10 @@ export function registerWatchCommand(program: Command): void { // surface without the CLI needing passThroughOptions (which would // force enablePositionalOptions fleet-wide on the root program). .allowUnknownOption() + // The tool owns help too: without this, commander would intercept + // --help and answer with wrapper help instead of agent-watch's own + // (codex review of 18f3dd49). + .helpOption(false) .argument('[args...]', 'args passed through to agent-watch.sh') .action(async (args: string[], _opts: unknown, command: Command) => { // --mosaic-home is not global in this CLI; walk parents for it and