Files
Codeman/src/respawn-patterns.ts
T
arkonandClaude Opus 4.6 e7a9cbe442 refactor: split god files into focused modules (phase 4, steps 2-4)
Split 3 large files into 11 focused sub-modules via composition:

ralph-tracker.ts (3,868 → ~2,400 LOC):
- ralph-plan-tracker.ts: plan task tracking, checkpoints, history
- ralph-fix-plan-watcher.ts: @fix_plan.md file watching
- ralph-stall-detector.ts: iteration stall detection
- ralph-status-parser.ts: RALPH_STATUS block parsing, circuit breaker

respawn-controller.ts (3,611 → ~3,200 LOC):
- respawn-patterns.ts: pure pattern detection functions
- respawn-adaptive-timing.ts: adaptive timing with percentile calc
- respawn-metrics.ts: cycle metrics tracking + aggregation
- respawn-health.ts: pure health scoring functions

session.ts (2,418 → ~1,800 LOC):
- session-cli-builder.ts: CLI argument construction
- session-auto-ops.ts: auto-compact/clear automation
- session-task-cache.ts: task description LRU cache

All external APIs preserved via delegation. Events forwarded
through parent classes. Zero behavioral changes — all 436 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 04:04:35 +01:00

132 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @fileoverview Pure utility functions for terminal pattern detection in respawn controller.
*
* Extracted from respawn-controller.ts for modularity. These are stateless functions
* and constants used to detect completion messages, working patterns, and token counts
* in terminal output.
*
* @module respawn-patterns
*/
import { TOKEN_PATTERN } from './utils/index.js';
// ========== Constants ==========
/**
* Pattern to detect completion messages from Claude Code.
* Requires "Worked for" prefix to avoid false positives from bare time durations
* in regular text (e.g., "wait for 5s", "run for 2m").
*
* Matches: "Worked for 2m 46s", "Worked for 46s", "Worked for 1h 2m 3s"
* Does NOT match: "wait for 5s", "run for 2m", "for 3s the system..."
*/
const COMPLETION_TIME_PATTERN = /\bWorked\s+for\s+\d+[hms](\s*\d+[hms])*/i;
/**
* Patterns indicating Claude is ready for input (legacy fallback).
* Used as secondary signals, not primary detection.
*/
export const PROMPT_PATTERNS = [
'❯', // Standard prompt
'\u276f', // Unicode variant
'⏵', // Claude Code prompt variant
];
/**
* Patterns indicating Claude is actively working.
* When detected, resets all idle detection timers.
* Note: ✻ and ✽ removed - they appear in completion messages too.
*/
export const WORKING_PATTERNS = [
'Thinking',
'Writing',
'Reading',
'Running',
'Searching',
'Editing',
'Creating',
'Deleting',
'Analyzing',
'Executing',
'Synthesizing',
'Brewing', // Claude's processing indicators
'Compiling',
'Building',
'Installing',
'Fetching',
'Downloading',
'Processing',
'Generating',
'Loading',
'Starting',
'Updating',
'Checking',
'Validating',
'Testing',
'Formatting',
'Linting',
'⠋',
'⠙',
'⠹',
'⠸',
'⠼',
'⠴',
'⠦',
'⠧',
'⠇',
'⠏', // Spinner chars
'◐',
'◓',
'◑',
'◒', // Alternative spinners
'⣾',
'⣽',
'⣻',
'⢿',
'⡿',
'⣟',
'⣯',
'⣷', // Braille spinners
];
/**
* Check if data contains a completion message pattern.
* Matches "Worked for Xh Xm Xs" time duration patterns.
*
* @param data - Raw terminal output data
* @returns True if completion message pattern is found
*/
export function isCompletionMessage(data: string): boolean {
return COMPLETION_TIME_PATTERN.test(data);
}
/**
* Check if a rolling window of terminal output contains working patterns.
* The rolling window catches patterns split across chunks (e.g., "Thin" + "king").
*
* @param window - Rolling window of recent terminal output (already includes current data)
* @returns True if any working pattern is found in the window
*/
export function hasWorkingPattern(window: string): boolean {
return WORKING_PATTERNS.some((pattern) => window.includes(pattern));
}
/**
* Extract token count from data if present.
* Parses patterns like "123.4k tokens" or "1.5M tokens".
*
* @param data - Raw terminal output data
* @returns Parsed token count, or null if no token pattern found
*/
export function extractTokenCount(data: string): number | null {
const match = data.match(TOKEN_PATTERN);
if (!match) return null;
let count = parseFloat(match[1]);
const suffix = match[2]?.toLowerCase();
if (suffix === 'k') count *= 1000;
else if (suffix === 'm') count *= 1000000;
return Math.round(count);
}