diff --git a/docs/command-hq.md b/docs/command-hq.md index 99ac2f37..5a482d22 100644 --- a/docs/command-hq.md +++ b/docs/command-hq.md @@ -494,6 +494,19 @@ so a commander open in the panel at the moment this fires keeps showing the old navigation or reload. The grid's cards do not have this problem — `GET /commanders` is already polled every 15s. Flagged rather than fixed; worth a `refetch()` hook if it turns out to matter in practice. +**"(no output yet)" on that same google.com watcher, traced to the actual running process on this +machine rather than guessed at.** The tray's live-log-tail (`BackgroundTaskTray` → `useTaskDetail` → +`GET /chat/tasks/:id` → `loadBackgroundTask`/`tailFile`) is a general `/chat` feature Command HQ gets for +free — nothing to build there, and it was already working correctly. The task's `.output` file was +genuinely empty: the agent had written `timeout 8 ping -c 1 -W 5 google.com >/dev/null 2>&1`, silencing +`ping`'s own output entirely and only ever `echo`ing on a FAILED ping — correct per "let me know if it goes +down," but it means a healthy watcher shows nothing at all, indistinguishable at a glance from a stuck one. +Fixed at the source rather than in the tray: `background-job-prompt.ts` gained an unconditional rule (every +job, not only watchers — number 4, 5 or 8 depending on which rules already preceded it in that particular +prompt) telling the agent not to discard a command's own output. The tray already shows whatever reaches +the log file live; the gap was that jobs were routinely told, by habit rather than by this prompt, to send +that output to `/dev/null`. + **A real bug, caught by tracing rather than by the compiler, worth stating plainly.** When the cost-tracking schema changed `recordCommandHqWatcherFired`'s signature from `(userId, sessionId)` to `(sessionRowId, taskId)`, the ONE existing call site was not updated in the same pass — and `bunx tsgo` stayed clean, because diff --git a/src/workspaces/officerdev/src/apps/Chat/background-job-prompt.ts b/src/workspaces/officerdev/src/apps/Chat/background-job-prompt.ts index 19072d9e..681d3b0c 100644 --- a/src/workspaces/officerdev/src/apps/Chat/background-job-prompt.ts +++ b/src/workspaces/officerdev/src/apps/Chat/background-job-prompt.ts @@ -83,8 +83,10 @@ function fireRule(onFire: FireBehavior): string { const exitLines = [ `7. EXIT when it fires — the exit IS the notification. A loop that prints and continues has`, - ` told no one. Stay silent until then: everything printed lands in context at once on exit.`, - ` Report what fired.`, + ` told no one. Add no narration of your own until then — no "still checking", no progress`, + ` commentary: everything YOU print lands in my context at once on exit, so keep that part`, + ` quiet. That is not the same as the command's own output, which stays visible the whole`, + ` time regardless — see the output rule below. Report what fired.`, ]; return onFire === 'handoff' @@ -139,6 +141,21 @@ export function buildBackgroundJobPrompt(spec: BackgroundJobSpec): string { ); } + // Unconditional — every shape of job gets this, not only watchers. `watching`/`spec.mode` only decide + // which number it lands on, matching whichever rules already came before it in this particular prompt. + const outputRuleNumber = watching ? 8 : spec.mode === 'command' ? 5 : 4; + rules.push( + ``, + `${outputRuleNumber}. Do not throw away the command's own output — no \`>/dev/null\`, no \`2>&1\` into a`, + ` sink, no piping into something that swallows it, even for a check you only care about the`, + ` exit code of. Whatever it would print in a terminal is what I want to see, live, in this`, + ` job's log: a ping's own reply lines, a build's own progress, whatever the command already`, + ` says on its way. I can watch that file the same way I could watch a terminal — redirect`, + ` only what is genuinely noise (a spinner repainting one line), never the signal. This is`, + ` separate from anything you narrate yourself about the job's status: that is your voice;`, + ` this is the command's, and I want to hear both.`, + ); + return [ `Start a background job. The mechanics below are load-bearing; follow them exactly.`, ``,