feat: add smart respawn integration and priority todos (Phase 2)

Smart Respawn Integration (2.5):
- Check circuit breaker OPEN state before respawn (blocks cycle)
- Check RALPH_STATUS EXIT_SIGNAL=true to stop respawn
- Check STATUS=BLOCKED to pause respawn for human intervention
- Use RECOMMENDATION from RALPH_STATUS in update prompt
- Emit respawn:blocked SSE event with reason and details
- Show notification when respawn is blocked
- Visual blocked state with pulsing red indicator

Priority-based Todos (part of 2.3):
- Add RalphTodoPriority type (P0/P1/P2/null)
- Parse priority from todo content (P0:, Critical:, High Priority, etc.)
- Add priority field to RalphTodoItem interface
- Update frontend to display priority badges with colors
- Sort todos by priority (P0 > P1 > P2) then by status
- Add CSS for priority badges and highlighted cards

Bump version to 0.1391

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-27 00:54:02 +01:00
co-authored by Claude Opus 4.5
parent 59b22337a5
commit 925ea09cca
8 changed files with 217 additions and 23 deletions
+38 -1
View File
@@ -18,6 +18,7 @@ import {
RalphTrackerState,
RalphTodoItem,
RalphTodoStatus,
RalphTodoPriority,
RalphStatusBlock,
RalphStatusValue,
RalphTestsStatus,
@@ -1375,6 +1376,31 @@ export class RalphTracker extends EventEmitter {
}
}
/**
* Parse priority from todo content.
* Looks for patterns like: "P0:", "P1:", "P2:", "(P0)", "(P1)", "(P2)",
* "Critical:", "Blocker:", "High Priority:", etc.
*
* @param content - Todo content text
* @returns Parsed priority level or null
*/
private parsePriority(content: string): RalphTodoPriority {
const upper = content.toUpperCase();
// Direct P0/P1/P2 patterns
if (/\bP0\b|^\(P0\)|:?\s*P0\s*:|\bCRITICAL\b|\bBLOCKER\b/.test(upper)) {
return 'P0';
}
if (/\bP1\b|^\(P1\)|:?\s*P1\s*:|\bHIGH\s*PRIORITY\b/.test(upper)) {
return 'P1';
}
if (/\bP2\b|^\(P2\)|:?\s*P2\s*:|\bNICE\s*TO\s*HAVE\b|\bLOW\s*PRIORITY\b/.test(upper)) {
return 'P2';
}
return null;
}
/**
* Add a new todo item or update an existing one.
*
@@ -1382,6 +1408,7 @@ export class RalphTracker extends EventEmitter {
* - Content is cleaned (ANSI removed, whitespace collapsed)
* - Content under 5 chars is skipped
* - ID is generated from normalized content (stable hash)
* - Priority is parsed from content (P0/P1/P2, Critical, High Priority, etc.)
* - Existing item: Updates status and timestamp
* - New item: Adds to map, evicts oldest if at MAX_TODO_ITEMS
*
@@ -1399,6 +1426,9 @@ export class RalphTracker extends EventEmitter {
.trim();
if (cleanContent.length < 5) return; // Skip very short content
// Parse priority from content
const priority = this.parsePriority(cleanContent);
// Generate a stable ID from normalized content
const id = this.generateTodoId(cleanContent);
@@ -1407,6 +1437,8 @@ export class RalphTracker extends EventEmitter {
// Update existing todo
existing.status = status;
existing.detectedAt = Date.now();
// Update priority if parsed (don't overwrite with null)
if (priority) existing.priority = priority;
} else {
// Add new todo
if (this._todos.size >= MAX_TODO_ITEMS) {
@@ -1422,6 +1454,7 @@ export class RalphTracker extends EventEmitter {
content: cleanContent,
status,
detectedAt: Date.now(),
priority,
});
}
}
@@ -1699,7 +1732,11 @@ export class RalphTracker extends EventEmitter {
};
this._todos.clear();
for (const todo of todos) {
this._todos.set(todo.id, { ...todo });
// Backwards compatibility: ensure priority field exists
this._todos.set(todo.id, {
...todo,
priority: todo.priority ?? null,
});
}
}