mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
feat: add issue discovery by prompt command with Gemini planning
- Introduced `/issue:discover-by-prompt` command for user-driven issue discovery. - Implemented multi-agent exploration with iterative feedback loops. - Added ACE semantic search for context gathering and cross-module comparison capabilities. - Enhanced user experience with natural language input and adaptive exploration strategies. feat: implement memory update queue tool for batching updates - Created `memory-update-queue.js` for managing CLAUDE.md updates. - Added functionality for queuing paths, deduplication, and auto-flushing based on thresholds and timeouts. - Implemented methods for queue status retrieval, flushing, and timeout checks. - Configured to store queue data persistently in `~/.claude/.memory-queue.json`.
This commit is contained in:
@@ -1256,5 +1256,89 @@ RULES: Be concise. Focus on practical understanding. Include function signatures
|
||||
return true;
|
||||
}
|
||||
|
||||
// API: Memory Queue - Add path to queue
|
||||
if (pathname === '/api/memory/queue/add' && req.method === 'POST') {
|
||||
handlePostRequest(req, res, async (body) => {
|
||||
const { path: modulePath, tool = 'gemini', strategy = 'single-layer' } = body;
|
||||
|
||||
if (!modulePath) {
|
||||
return { error: 'path is required', status: 400 };
|
||||
}
|
||||
|
||||
try {
|
||||
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
||||
const result = await memoryQueueTool.execute({
|
||||
action: 'add',
|
||||
path: modulePath,
|
||||
tool,
|
||||
strategy
|
||||
}) as { queueSize?: number; willFlush?: boolean; flushed?: boolean };
|
||||
|
||||
// Broadcast queue update event
|
||||
broadcastToClients({
|
||||
type: 'MEMORY_QUEUE_UPDATED',
|
||||
payload: {
|
||||
action: 'add',
|
||||
path: modulePath,
|
||||
queueSize: result.queueSize || 0,
|
||||
willFlush: result.willFlush || false,
|
||||
flushed: result.flushed || false,
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
|
||||
return { success: true, ...result };
|
||||
} catch (error: unknown) {
|
||||
return { error: (error as Error).message, status: 500 };
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// API: Memory Queue - Get queue status
|
||||
if (pathname === '/api/memory/queue/status' && req.method === 'GET') {
|
||||
try {
|
||||
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
||||
const result = await memoryQueueTool.execute({ action: 'status' }) as Record<string, unknown>;
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ success: true, ...result }));
|
||||
} catch (error: unknown) {
|
||||
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: (error as Error).message }));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// API: Memory Queue - Flush queue immediately
|
||||
if (pathname === '/api/memory/queue/flush' && req.method === 'POST') {
|
||||
handlePostRequest(req, res, async () => {
|
||||
try {
|
||||
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
||||
const result = await memoryQueueTool.execute({ action: 'flush' }) as {
|
||||
processed?: number;
|
||||
success?: boolean;
|
||||
errors?: unknown[];
|
||||
};
|
||||
|
||||
// Broadcast queue flushed event
|
||||
broadcastToClients({
|
||||
type: 'MEMORY_QUEUE_FLUSHED',
|
||||
payload: {
|
||||
processed: result.processed || 0,
|
||||
success: result.success || false,
|
||||
errors: result.errors?.length || 0,
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
|
||||
return { success: true, ...result };
|
||||
} catch (error: unknown) {
|
||||
return { error: (error as Error).message, status: 500 };
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,15 @@ import { getCliToolsStatus } from '../../tools/cli-executor.js';
|
||||
import { checkVenvStatus, checkSemanticStatus } from '../../tools/codex-lens.js';
|
||||
import type { RouteContext } from './types.js';
|
||||
|
||||
// Performance logging helper
|
||||
const PERF_LOG_ENABLED = process.env.CCW_PERF_LOG === '1' || true; // Enable by default for debugging
|
||||
function perfLog(label: string, startTime: number, extra?: Record<string, unknown>): void {
|
||||
if (!PERF_LOG_ENABLED) return;
|
||||
const duration = Date.now() - startTime;
|
||||
const extraStr = extra ? ` | ${JSON.stringify(extra)}` : '';
|
||||
console.log(`[PERF][Status] ${label}: ${duration}ms${extraStr}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check CCW installation status
|
||||
* Verifies that required workflow files are installed in user's home directory
|
||||
@@ -62,16 +71,39 @@ export async function handleStatusRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
|
||||
// API: Aggregated Status (all statuses in one call)
|
||||
if (pathname === '/api/status/all') {
|
||||
const totalStart = Date.now();
|
||||
console.log('[PERF][Status] === /api/status/all START ===');
|
||||
|
||||
try {
|
||||
// Check CCW installation status (sync, fast)
|
||||
const ccwStart = Date.now();
|
||||
const ccwInstallStatus = checkCcwInstallStatus();
|
||||
perfLog('checkCcwInstallStatus', ccwStart);
|
||||
|
||||
// Execute all status checks in parallel with individual timing
|
||||
const cliStart = Date.now();
|
||||
const codexStart = Date.now();
|
||||
const semanticStart = Date.now();
|
||||
|
||||
// Execute all status checks in parallel
|
||||
const [cliStatus, codexLensStatus, semanticStatus] = await Promise.all([
|
||||
getCliToolsStatus(),
|
||||
checkVenvStatus(),
|
||||
getCliToolsStatus().then(result => {
|
||||
perfLog('getCliToolsStatus', cliStart, { toolCount: Object.keys(result).length });
|
||||
return result;
|
||||
}),
|
||||
checkVenvStatus().then(result => {
|
||||
perfLog('checkVenvStatus', codexStart, { ready: result.ready });
|
||||
return result;
|
||||
}),
|
||||
// Always check semantic status (will return available: false if CodexLens not ready)
|
||||
checkSemanticStatus().catch(() => ({ available: false, backend: null }))
|
||||
checkSemanticStatus()
|
||||
.then(result => {
|
||||
perfLog('checkSemanticStatus', semanticStart, { available: result.available });
|
||||
return result;
|
||||
})
|
||||
.catch(() => {
|
||||
perfLog('checkSemanticStatus (error)', semanticStart);
|
||||
return { available: false, backend: null };
|
||||
})
|
||||
]);
|
||||
|
||||
const response = {
|
||||
@@ -82,10 +114,13 @@ export async function handleStatusRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
perfLog('=== /api/status/all TOTAL ===', totalStart);
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(response));
|
||||
return true;
|
||||
} catch (error) {
|
||||
perfLog('=== /api/status/all ERROR ===', totalStart);
|
||||
console.error('[Status Routes] Error fetching aggregated status:', error);
|
||||
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: (error as Error).message }));
|
||||
|
||||
@@ -42,6 +42,10 @@ import { randomBytes } from 'crypto';
|
||||
// Import health check service
|
||||
import { getHealthCheckService } from './services/health-check-service.js';
|
||||
|
||||
// Import status check functions for warmup
|
||||
import { checkSemanticStatus, checkVenvStatus } from '../tools/codex-lens.js';
|
||||
import { getCliToolsStatus } from '../tools/cli-executor.js';
|
||||
|
||||
import type { ServerConfig } from '../types/config.js';
|
||||
import type { PostRequestHandler } from './routes/types.js';
|
||||
|
||||
@@ -290,6 +294,56 @@ function setCsrfCookie(res: http.ServerResponse, token: string, maxAgeSeconds: n
|
||||
appendSetCookie(res, attributes.join('; '));
|
||||
}
|
||||
|
||||
/**
|
||||
* Warmup function to pre-populate caches on server startup
|
||||
* This runs asynchronously and non-blocking after the server starts
|
||||
*/
|
||||
async function warmupCaches(initialPath: string): Promise<void> {
|
||||
console.log('[WARMUP] Starting cache warmup...');
|
||||
const startTime = Date.now();
|
||||
|
||||
// Run all warmup tasks in parallel for faster startup
|
||||
const warmupTasks = [
|
||||
// Warmup semantic status cache (Python process startup - can be slow first time)
|
||||
(async () => {
|
||||
const taskStart = Date.now();
|
||||
try {
|
||||
const semanticStatus = await checkSemanticStatus();
|
||||
console.log(`[WARMUP] Semantic status: ${semanticStatus.available ? 'available' : 'not available'} (${Date.now() - taskStart}ms)`);
|
||||
} catch (err) {
|
||||
console.warn(`[WARMUP] Semantic status check failed: ${(err as Error).message}`);
|
||||
}
|
||||
})(),
|
||||
|
||||
// Warmup venv status cache
|
||||
(async () => {
|
||||
const taskStart = Date.now();
|
||||
try {
|
||||
const venvStatus = await checkVenvStatus();
|
||||
console.log(`[WARMUP] Venv status: ${venvStatus.ready ? 'ready' : 'not ready'} (${Date.now() - taskStart}ms)`);
|
||||
} catch (err) {
|
||||
console.warn(`[WARMUP] Venv status check failed: ${(err as Error).message}`);
|
||||
}
|
||||
})(),
|
||||
|
||||
// Warmup CLI tools status cache
|
||||
(async () => {
|
||||
const taskStart = Date.now();
|
||||
try {
|
||||
const cliStatus = await getCliToolsStatus();
|
||||
const availableCount = Object.values(cliStatus).filter(s => s.available).length;
|
||||
const totalCount = Object.keys(cliStatus).length;
|
||||
console.log(`[WARMUP] CLI tools status: ${availableCount}/${totalCount} available (${Date.now() - taskStart}ms)`);
|
||||
} catch (err) {
|
||||
console.warn(`[WARMUP] CLI tools status check failed: ${(err as Error).message}`);
|
||||
}
|
||||
})()
|
||||
];
|
||||
|
||||
await Promise.allSettled(warmupTasks);
|
||||
console.log(`[WARMUP] Cache warmup complete (${Date.now() - startTime}ms total)`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate dashboard HTML with embedded CSS and JS
|
||||
*/
|
||||
@@ -650,6 +704,14 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
|
||||
console.warn('[Server] Failed to start health check service:', err);
|
||||
}
|
||||
|
||||
// Start cache warmup asynchronously (non-blocking)
|
||||
// Uses setImmediate to not delay server startup response
|
||||
setImmediate(() => {
|
||||
warmupCaches(initialPath).catch((err) => {
|
||||
console.warn('[WARMUP] Cache warmup failed:', err);
|
||||
});
|
||||
});
|
||||
|
||||
resolve(server);
|
||||
});
|
||||
server.on('error', reject);
|
||||
|
||||
Reference in New Issue
Block a user