wip: [01-stabilize] paused at task 1/1 - OCR Hallucination Immune logic via Semantic delta window and fret-isolation
This commit is contained in:
256
.agent/services/claude-mem/scripts/clear-failed-queue.ts
Normal file
256
.agent/services/claude-mem/scripts/clear-failed-queue.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Clear messages from the queue
|
||||
*
|
||||
* Usage:
|
||||
* bun scripts/clear-failed-queue.ts # Clear failed messages (interactive)
|
||||
* bun scripts/clear-failed-queue.ts --all # Clear ALL messages (pending, processing, failed)
|
||||
* bun scripts/clear-failed-queue.ts --force # Non-interactive - clear without prompting
|
||||
*/
|
||||
|
||||
const WORKER_URL = 'http://localhost:37777';
|
||||
|
||||
interface QueueMessage {
|
||||
id: number;
|
||||
session_db_id: number;
|
||||
message_type: string;
|
||||
tool_name: string | null;
|
||||
status: 'pending' | 'processing' | 'failed';
|
||||
retry_count: number;
|
||||
created_at_epoch: number;
|
||||
project: string | null;
|
||||
}
|
||||
|
||||
interface QueueResponse {
|
||||
queue: {
|
||||
messages: QueueMessage[];
|
||||
totalPending: number;
|
||||
totalProcessing: number;
|
||||
totalFailed: number;
|
||||
stuckCount: number;
|
||||
};
|
||||
recentlyProcessed: QueueMessage[];
|
||||
sessionsWithPendingWork: number[];
|
||||
}
|
||||
|
||||
interface ClearResponse {
|
||||
success: boolean;
|
||||
clearedCount: number;
|
||||
}
|
||||
|
||||
async function checkWorkerHealth(): Promise<boolean> {
|
||||
try {
|
||||
const res = await fetch(`${WORKER_URL}/api/health`);
|
||||
return res.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getQueueStatus(): Promise<QueueResponse> {
|
||||
const res = await fetch(`${WORKER_URL}/api/pending-queue`);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to get queue status: ${res.status}`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function clearFailedQueue(): Promise<ClearResponse> {
|
||||
const res = await fetch(`${WORKER_URL}/api/pending-queue/failed`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to clear failed queue: ${res.status}`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function clearAllQueue(): Promise<ClearResponse> {
|
||||
const res = await fetch(`${WORKER_URL}/api/pending-queue/all`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to clear queue: ${res.status}`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function formatAge(epochMs: number): string {
|
||||
const ageMs = Date.now() - epochMs;
|
||||
const minutes = Math.floor(ageMs / 60000);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
if (days > 0) return `${days}d ${hours % 24}h ago`;
|
||||
if (hours > 0) return `${hours}h ${minutes % 60}m ago`;
|
||||
return `${minutes}m ago`;
|
||||
}
|
||||
|
||||
async function prompt(question: string): Promise<string> {
|
||||
// Check if we have a TTY for interactive input
|
||||
if (!process.stdin.isTTY) {
|
||||
console.log(question + '(no TTY, use --force flag for non-interactive mode)');
|
||||
return 'n';
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
process.stdout.write(question);
|
||||
process.stdin.setRawMode(false);
|
||||
process.stdin.resume();
|
||||
process.stdin.once('data', (data) => {
|
||||
process.stdin.pause();
|
||||
resolve(data.toString().trim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// Help flag
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
console.log(`
|
||||
Claude-Mem Queue Clearer
|
||||
|
||||
Clear messages from the observation queue.
|
||||
|
||||
Usage:
|
||||
bun scripts/clear-failed-queue.ts [options]
|
||||
|
||||
Options:
|
||||
--help, -h Show this help message
|
||||
--all Clear ALL messages (pending, processing, and failed)
|
||||
--force Clear without prompting for confirmation
|
||||
|
||||
Examples:
|
||||
# Clear failed messages interactively
|
||||
bun scripts/clear-failed-queue.ts
|
||||
|
||||
# Clear ALL messages (pending, processing, failed)
|
||||
bun scripts/clear-failed-queue.ts --all
|
||||
|
||||
# Clear without confirmation (non-interactive)
|
||||
bun scripts/clear-failed-queue.ts --force
|
||||
|
||||
# Clear all messages without confirmation
|
||||
bun scripts/clear-failed-queue.ts --all --force
|
||||
|
||||
What is this for?
|
||||
Failed messages are observations that exceeded the maximum retry count.
|
||||
Processing/pending messages may be stuck or unwanted.
|
||||
This command removes them to clean up the queue.
|
||||
|
||||
--all is useful for a complete reset when you want to start fresh.
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const force = args.includes('--force');
|
||||
const clearAll = args.includes('--all');
|
||||
|
||||
console.log(clearAll
|
||||
? '\n=== Claude-Mem Queue Clearer (ALL) ===\n'
|
||||
: '\n=== Claude-Mem Queue Clearer (Failed) ===\n');
|
||||
|
||||
// Check worker health
|
||||
const healthy = await checkWorkerHealth();
|
||||
if (!healthy) {
|
||||
console.log('Worker is not running. Start it with:');
|
||||
console.log(' cd ~/.claude/plugins/marketplaces/thedotmack && npm run worker:start\n');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('Worker status: Running\n');
|
||||
|
||||
// Get queue status
|
||||
const status = await getQueueStatus();
|
||||
const { queue } = status;
|
||||
|
||||
console.log('Queue Summary:');
|
||||
console.log(` Pending: ${queue.totalPending}`);
|
||||
console.log(` Processing: ${queue.totalProcessing}`);
|
||||
console.log(` Failed: ${queue.totalFailed}`);
|
||||
console.log('');
|
||||
|
||||
// Check if there are messages to clear
|
||||
const totalToClear = clearAll
|
||||
? queue.totalPending + queue.totalProcessing + queue.totalFailed
|
||||
: queue.totalFailed;
|
||||
|
||||
if (totalToClear === 0) {
|
||||
console.log(clearAll
|
||||
? 'No messages in queue. Nothing to clear.\n'
|
||||
: 'No failed messages in queue. Nothing to clear.\n');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Show details about messages to clear
|
||||
const messagesToShow = clearAll ? queue.messages : queue.messages.filter(m => m.status === 'failed');
|
||||
if (messagesToShow.length > 0) {
|
||||
console.log(clearAll ? 'Messages to Clear:' : 'Failed Messages:');
|
||||
console.log('─'.repeat(80));
|
||||
|
||||
// Group by session
|
||||
const bySession = new Map<number, QueueMessage[]>();
|
||||
for (const msg of messagesToShow) {
|
||||
const list = bySession.get(msg.session_db_id) || [];
|
||||
list.push(msg);
|
||||
bySession.set(msg.session_db_id, list);
|
||||
}
|
||||
|
||||
for (const [sessionId, messages] of bySession) {
|
||||
const project = messages[0].project || 'unknown';
|
||||
const oldest = Math.min(...messages.map(m => m.created_at_epoch));
|
||||
|
||||
if (clearAll) {
|
||||
const statuses = {
|
||||
pending: messages.filter(m => m.status === 'pending').length,
|
||||
processing: messages.filter(m => m.status === 'processing').length,
|
||||
failed: messages.filter(m => m.status === 'failed').length
|
||||
};
|
||||
console.log(` Session ${sessionId} (${project})`);
|
||||
console.log(` Messages: ${messages.length} total (${statuses.pending} pending, ${statuses.processing} processing, ${statuses.failed} failed)`);
|
||||
console.log(` Age: ${formatAge(oldest)}`);
|
||||
} else {
|
||||
console.log(` Session ${sessionId} (${project})`);
|
||||
console.log(` Messages: ${messages.length} failed`);
|
||||
console.log(` Age: ${formatAge(oldest)}`);
|
||||
}
|
||||
}
|
||||
console.log('─'.repeat(80));
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Confirm before clearing
|
||||
const clearMessage = clearAll
|
||||
? `Clear ${totalToClear} messages (pending, processing, and failed)?`
|
||||
: `Clear ${queue.totalFailed} failed messages?`;
|
||||
|
||||
if (force) {
|
||||
console.log(`${clearMessage.replace('?', '')}...\n`);
|
||||
} else {
|
||||
const answer = await prompt(`${clearMessage} [y/N]: `);
|
||||
if (answer.toLowerCase() !== 'y') {
|
||||
console.log('\nCancelled. Run with --force to skip confirmation.\n');
|
||||
process.exit(0);
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Clear the queue
|
||||
const result = clearAll ? await clearAllQueue() : await clearFailedQueue();
|
||||
|
||||
console.log('Clearing Result:');
|
||||
console.log(` Messages cleared: ${result.clearedCount}`);
|
||||
console.log(` Status: ${result.success ? 'Success' : 'Failed'}\n`);
|
||||
|
||||
if (result.success && result.clearedCount > 0) {
|
||||
console.log(clearAll
|
||||
? 'All messages have been removed from the queue.\n'
|
||||
: 'Failed messages have been removed from the queue.\n');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Error:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user