fix: rock-solid idle detection in respawn controller

- Add 300-char rolling window to catch working patterns split across PTY chunks
- Check completion message BEFORE working patterns (priority fix)
- Clear rolling window on completion message (transition point)
- Increase working pattern absence threshold from 3s to 8s
- Add Session.isWorking safety check before confirming idle
- Add 20+ more working patterns (Compiling, Building, Processing, etc.)
- Make AI idle checker prompt more conservative (err toward WORKING)
- Update documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-26 00:55:29 +01:00
co-authored by Claude Opus 4.5
parent 5b87a41aac
commit 9aa5973970
21 changed files with 2561 additions and 360 deletions
+49 -2
View File
@@ -21,13 +21,14 @@ import { existsSync } from 'node:fs';
import { dirname } from 'node:path';
import { v4 as uuidv4 } from 'uuid';
import * as pty from 'node-pty';
import { SessionState, SessionStatus, SessionConfig, ScreenSession, RalphTrackerState, RalphTodoItem } from './types.js';
import { SessionState, SessionStatus, SessionConfig, ScreenSession, RalphTrackerState, RalphTodoItem, ActiveBashTool } from './types.js';
import { TaskTracker, type BackgroundTask } from './task-tracker.js';
import { RalphTracker } from './ralph-tracker.js';
import { BashToolParser } from './bash-tool-parser.js';
import { ScreenManager } from './screen-manager.js';
export type { BackgroundTask } from './task-tracker.js';
export type { RalphTrackerState, RalphTodoItem } from './types.js';
export type { RalphTrackerState, RalphTodoItem, ActiveBashTool } from './types.js';
export { withTimeout };
// ============================================================================
@@ -292,6 +293,12 @@ export interface SessionEvents {
ralphTodoUpdate: (todos: RalphTodoItem[]) => void;
/** Ralph completion phrase detected */
ralphCompletionDetected: (phrase: string) => void;
/** Bash tool with file paths started */
bashToolStart: (tool: ActiveBashTool) => void;
/** Bash tool completed */
bashToolEnd: (tool: ActiveBashTool) => void;
/** Active Bash tools list updated */
bashToolsUpdate: (tools: ActiveBashTool[]) => void;
}
/**
@@ -410,6 +417,14 @@ export class Session extends EventEmitter {
completionDetected: (phrase: string) => void;
} | null = null;
// Bash tool tracking (file paths for live log viewing)
private _bashToolParser: BashToolParser;
private _bashToolHandlers: {
toolStart: (tool: ActiveBashTool) => void;
toolEnd: (tool: ActiveBashTool) => void;
toolsUpdate: (tools: ActiveBashTool[]) => void;
} | null = null;
constructor(config: Partial<SessionConfig> & {
workingDir: string;
mode?: SessionMode;
@@ -453,6 +468,17 @@ export class Session extends EventEmitter {
this._ralphTracker.on('todoUpdate', this._ralphHandlers.todoUpdate);
this._ralphTracker.on('completionDetected', this._ralphHandlers.completionDetected);
// Initialize Bash tool parser and forward events (store handlers for cleanup)
this._bashToolParser = new BashToolParser({ sessionId: this.id });
this._bashToolHandlers = {
toolStart: (tool) => this.emit('bashToolStart', tool),
toolEnd: (tool) => this.emit('bashToolEnd', tool),
toolsUpdate: (tools) => this.emit('bashToolsUpdate', tools),
};
this._bashToolParser.on('toolStart', this._bashToolHandlers.toolStart);
this._bashToolParser.on('toolEnd', this._bashToolHandlers.toolEnd);
this._bashToolParser.on('toolsUpdate', this._bashToolHandlers.toolsUpdate);
}
get status(): SessionStatus {
@@ -540,6 +566,15 @@ export class Session extends EventEmitter {
return this._ralphTracker.getTodoStats();
}
// Bash tool tracking getters
get bashToolParser(): BashToolParser {
return this._bashToolParser;
}
get activeTools(): ActiveBashTool[] {
return this._bashToolParser.activeTools;
}
get parentAgentId(): string | null {
return this._parentAgentId;
}
@@ -852,6 +887,9 @@ export class Session extends EventEmitter {
// Forward to Ralph tracker to detect Ralph loops and todos
this._ralphTracker.processTerminalData(data);
// Forward to Bash tool parser to detect file-viewing commands
this._bashToolParser.processTerminalData(data);
// Parse token count from status line (e.g., "123.4k tokens" or "5234 tokens")
this.parseTokensFromStatusLine(data);
@@ -1503,6 +1541,15 @@ export class Session extends EventEmitter {
this._ralphHandlers = null;
}
// Remove BashToolParser handlers
if (this._bashToolHandlers) {
this._bashToolParser.off('toolStart', this._bashToolHandlers.toolStart);
this._bashToolParser.off('toolEnd', this._bashToolHandlers.toolEnd);
this._bashToolParser.off('toolsUpdate', this._bashToolHandlers.toolsUpdate);
this._bashToolHandlers = null;
}
this._bashToolParser.destroy();
}
/**