mosaic dispatch: codex review fixes (comms repo binding, q lookup, watch help)
ci/woodpecker/pr/ci Pipeline was successful

- comms: bind comms-send.sh to the SELECTED repository via
  FLEET_COMMS_REPO in the spawned env; without it, --comms-repo chose
  the executable but the tool still operated on the default checkout
  (codex on 9c8b6ebf). Spec asserts the stub observes the binding.
- q: Object.hasOwn subcommand lookup (reserved property names like
  toString must not leak through the record); spec arm added.
- watch: .helpOption(false) — the tool owns help too; --help now passes
  through to agent-watch.sh instead of commander's wrapper help
  (verified against dist).
This commit is contained in:
2026-08-28 17:50:39 -05:00
parent 9c8b6ebfe1
commit e858f1bc62
5 changed files with 22 additions and 4 deletions
+8 -2
View File
@@ -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
});
+5 -1
View File
@@ -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,
+4
View File
@@ -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 () => {
+1 -1
View File
@@ -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}`);
+4
View File
@@ -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