33c898ff9a
The async startJob previously relied on Node.js event listeners in the CLI process to capture child output and finalize the job file. But the CLI process exits immediately after returning the job ID, killing the event loop before the close handler fires — leaving jobs stuck at 'running' forever. Fix: startJob now spawns a companion watcher process (job-watcher.ts) that is itself detached and outlives the CLI. The watcher: - Spawns the actual client (codex/claude/opencode) - Captures stdout/stderr - Writes the final job record to disk on child exit - Has its own 10-minute timeout safety net The CLI returns the job ID immediately. The watcher independently finalizes the job. The CLI no longer needs to stay alive. Also updates tests to mock the watcher spawn via injectable spawnWatcher option.