diff --git a/src/ai-idle-checker.ts b/src/ai-idle-checker.ts index 87c1440a..3bcb1696 100644 --- a/src/ai-idle-checker.ts +++ b/src/ai-idle-checker.ts @@ -29,6 +29,7 @@ import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { EventEmitter } from 'node:events'; +import { getAugmentedPath } from './session.js'; // ========== Types ========== @@ -323,8 +324,9 @@ export class AiIdleChecker extends EventEmitter { // Build the command - escape the prompt for shell const escapedPrompt = prompt.replace(/'/g, "'\\''"); const modelArg = `--model ${this.config.model}`; + const augmentedPath = getAugmentedPath(); const claudeCmd = `claude -p ${modelArg} --output-format text '${escapedPrompt}'`; - const fullCmd = `${claudeCmd} > "${this.checkTempFile}" 2>&1; echo "${DONE_MARKER}" >> "${this.checkTempFile}"`; + const fullCmd = `export PATH="${augmentedPath}"; ${claudeCmd} > "${this.checkTempFile}" 2>&1; echo "${DONE_MARKER}" >> "${this.checkTempFile}"`; // Spawn screen try { diff --git a/src/respawn-controller.ts b/src/respawn-controller.ts index 174e5182..819214fe 100644 --- a/src/respawn-controller.ts +++ b/src/respawn-controller.ts @@ -579,6 +579,10 @@ export class RespawnController extends EventEmitter { this.aiChecker.on('cooldownEnded', () => { this.emit('aiCheckCooldown', false, null); + // Restart pre-filter timer when cooldown expires so a new check can be triggered + if (this._state === 'watching') { + this.startPreFilterTimer(); + } }); this.aiChecker.on('disabled', (reason: string) => { @@ -772,6 +776,14 @@ export class RespawnController extends EventEmitter { this.completionMessageTime = null; this.hasReceivedOutput = false; + // Seed the terminal buffer from the session's existing output. + // This gives the AI checker context even if no new output arrives. + const existingBuffer = this.session.terminalBuffer; + if (existingBuffer) { + this.terminalBuffer.clear(); + this.terminalBuffer.append(existingBuffer); + } + this.aiChecker.reset(); this.setState('watching'); this.setupTerminalListener(); @@ -1329,10 +1341,16 @@ export class RespawnController extends EventEmitter { this.emit('aiCheckCompleted', result); this.setState('watching'); this.log(`AI check says WORKING, returning to watching with ${this.config.aiIdleCheckCooldownMs}ms cooldown`); + // Restart timers so the controller retries after cooldown expires + this.startNoOutputTimer(); + this.startPreFilterTimer(); } else { // ERROR verdict this.emit('aiCheckFailed', result.reasoning); this.setState('watching'); + // Restart timers to allow retry + this.startNoOutputTimer(); + this.startPreFilterTimer(); } }).catch((err) => { if (this._state === 'ai_checking') { @@ -1340,6 +1358,9 @@ export class RespawnController extends EventEmitter { this.emit('aiCheckFailed', errorMsg); this.setState('watching'); this.log(`AI check error: ${errorMsg}`); + // Restart timers to allow retry + this.startNoOutputTimer(); + this.startPreFilterTimer(); } }); } diff --git a/src/session.ts b/src/session.ts index 56ab895b..d9b46651 100644 --- a/src/session.ts +++ b/src/session.ts @@ -87,7 +87,7 @@ let _augmentedPath: string | null = null; * prepends its directory to the current PATH if not already present. * Result is cached for subsequent calls. */ -function getAugmentedPath(): string { +export function getAugmentedPath(): string { if (_augmentedPath) return _augmentedPath; const currentPath = process.env.PATH || '';