mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-12 17:21:19 +08:00
feat: Implement DeepWiki generator and CLI integration
- Added `deepwiki_generator.py` for generating documentation from source code. - Integrated symbol extraction and markdown generation for supported file types. - Implemented database migration for legacy timestamp formats in DeepWikiStore. - Enhanced debug logging for better traceability during conversation and store operations. - Updated dependencies in `PKG-INFO` and `requires.txt` for compatibility. - Added new tests for the DeepWiki generator and storage functionalities. - Refactored existing code for improved readability and maintainability.
This commit is contained in:
@@ -35,22 +35,31 @@ import {
|
||||
saveConversation
|
||||
} from './cli-executor-state.js';
|
||||
|
||||
// Track all running child processes for cleanup on interruption (multi-process support)
|
||||
const runningChildProcesses = new Set<ChildProcess>();
|
||||
|
||||
// Debug logging for parallel execution testing
|
||||
// Debug logging for history save investigation (Iteration 4)
|
||||
const DEBUG_SESSION_ID = 'DBG-parallel-ccw-cli-test-2026-03-07';
|
||||
const DEBUG_LOG_PATH = path.join(process.cwd(), '.workflow', '.debug', DEBUG_SESSION_ID, 'debug.log');
|
||||
const DEBUG_LOG_PATH = path.join(process.cwd(), '.workflow', '.debug', DEBUG_SESSION_ID, 'debug-save.log');
|
||||
|
||||
// Ensure debug log directory exists
|
||||
try {
|
||||
const debugDir = path.dirname(DEBUG_LOG_PATH);
|
||||
if (!fs.existsSync(debugDir)) {
|
||||
fs.mkdirSync(debugDir, { recursive: true });
|
||||
}
|
||||
} catch (err) {
|
||||
// Ignore directory creation errors
|
||||
}
|
||||
|
||||
function writeDebugLog(event: string, data: Record<string, any>): void {
|
||||
try {
|
||||
const logEntry = JSON.stringify({ event, ...data, timestamp: new Date().toISOString() }) + '\n';
|
||||
fs.appendFileSync(DEBUG_LOG_PATH, logEntry, 'utf8');
|
||||
} catch (err) {
|
||||
// Silently ignore logging errors to avoid disrupting execution
|
||||
// Silently ignore logging errors
|
||||
}
|
||||
}
|
||||
|
||||
// Track all running child processes for cleanup on interruption (multi-process support)
|
||||
const runningChildProcesses = new Set<ChildProcess>();
|
||||
|
||||
/**
|
||||
* Kill all running CLI child processes
|
||||
@@ -58,16 +67,14 @@ function writeDebugLog(event: string, data: Record<string, any>): void {
|
||||
*/
|
||||
export function killAllCliProcesses(): boolean {
|
||||
if (runningChildProcesses.size === 0) return false;
|
||||
writeDebugLog('KILL_ALL_START', { initial_set_size: runningChildProcesses.size });
|
||||
|
||||
const processesToKill = Array.from(runningChildProcesses);
|
||||
debugLog('KILL', `Killing ${processesToKill.length} child process(es)`, { pids: processesToKill.map(p => p.pid) });
|
||||
writeDebugLog('KILL_ALL_COPY', { pids_to_kill: processesToKill.map(p => p.pid) });
|
||||
|
||||
// 1. SIGTERM for graceful shutdown
|
||||
for (const child of processesToKill) {
|
||||
if (!child.killed) {
|
||||
try { child.kill('SIGTERM'); } catch (e: any) { writeDebugLog('KILL_SIGTERM_ERROR', { pid: child.pid, error: e.message }); }
|
||||
try { child.kill('SIGTERM'); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,13 +82,12 @@ export function killAllCliProcesses(): boolean {
|
||||
const killTimeout = setTimeout(() => {
|
||||
for (const child of processesToKill) {
|
||||
if (!child.killed) {
|
||||
try { child.kill('SIGKILL'); } catch (e: any) { writeDebugLog('KILL_SIGKILL_ERROR', { pid: child.pid, error: e.message }); }
|
||||
try { child.kill('SIGKILL'); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
killTimeout.unref();
|
||||
|
||||
writeDebugLog('KILL_ALL_CLEAR', { set_size_before: runningChildProcesses.size, pids_in_set: Array.from(runningChildProcesses).map(p => p.pid) });
|
||||
runningChildProcesses.clear();
|
||||
return true;
|
||||
}
|
||||
@@ -257,7 +263,6 @@ async function executeClaudeWithSettings(params: ClaudeWithSettingsParams): Prom
|
||||
|
||||
// Track child process for cleanup (multi-process support)
|
||||
runningChildProcesses.add(child);
|
||||
writeDebugLog('PROCESS_ADD', { pid: child.pid, set_size_after: runningChildProcesses.size, function: 'executeClaudeWithSettings' });
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
@@ -297,7 +302,6 @@ async function executeClaudeWithSettings(params: ClaudeWithSettingsParams): Prom
|
||||
|
||||
child.on('close', (code) => {
|
||||
runningChildProcesses.delete(child);
|
||||
writeDebugLog('PROCESS_DELETE', { pid: child.pid, exit_code: code, set_size_after: runningChildProcesses.size, function: 'executeClaudeWithSettings', handler: 'close' });
|
||||
|
||||
const endTime = Date.now();
|
||||
const duration = endTime - startTime;
|
||||
@@ -338,10 +342,8 @@ async function executeClaudeWithSettings(params: ClaudeWithSettingsParams): Prom
|
||||
|
||||
// Save to history
|
||||
try {
|
||||
writeDebugLog('SAVE_CONVERSATION_START', { conversationId: conversation.id, pid: child.pid, function: 'executeClaudeWithSettings' });
|
||||
saveConversation(workingDir, conversation);
|
||||
} catch (err) {
|
||||
writeDebugLog('SAVE_CONVERSATION_ERROR', { conversationId: conversation.id, pid: child.pid, error: (err as Error).message, stack: (err as Error).stack, function: 'executeClaudeWithSettings' });
|
||||
console.error('[CLI Executor] Failed to save CLI封装 history:', (err as Error).message);
|
||||
}
|
||||
|
||||
@@ -356,7 +358,6 @@ async function executeClaudeWithSettings(params: ClaudeWithSettingsParams): Prom
|
||||
|
||||
child.on('error', (error) => {
|
||||
runningChildProcesses.delete(child);
|
||||
writeDebugLog('PROCESS_DELETE', { pid: child.pid, set_size_after: runningChildProcesses.size, function: 'executeClaudeWithSettings', handler: 'error' });
|
||||
reject(new Error(`Failed to spawn claude: ${error.message}`));
|
||||
});
|
||||
});
|
||||
@@ -391,6 +392,30 @@ type BuiltinCliTool = typeof BUILTIN_CLI_TOOLS[number];
|
||||
*/
|
||||
export type TransactionId = string;
|
||||
|
||||
/**
|
||||
* Generate a readable execution ID for CLI executions
|
||||
* Format: {prefix}-{HHmmss}-{rand4} → e.g. gem-143022-x7k2
|
||||
* @param tool - CLI tool name (gemini, qwen, codex, claude, opencode, litellm, etc.)
|
||||
* @returns Short, human-readable execution ID
|
||||
*/
|
||||
export function generateExecutionId(tool: string): string {
|
||||
const prefixMap: Record<string, string> = {
|
||||
gemini: 'gem',
|
||||
qwen: 'qwn',
|
||||
codex: 'cdx',
|
||||
claude: 'cld',
|
||||
opencode: 'opc',
|
||||
litellm: 'llm',
|
||||
};
|
||||
const prefix = prefixMap[tool] || tool.slice(0, 3);
|
||||
const now = new Date();
|
||||
const time = [now.getHours(), now.getMinutes(), now.getSeconds()]
|
||||
.map(n => String(n).padStart(2, '0'))
|
||||
.join('');
|
||||
const rand = Math.random().toString(36).slice(2, 6);
|
||||
return `${prefix}-${time}-${rand}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique transaction ID for the current execution
|
||||
* @param conversationId - CCW conversation ID
|
||||
@@ -526,7 +551,7 @@ async function executeCliTool(
|
||||
const duration = endTime - startTime;
|
||||
|
||||
const execution: ExecutionRecord = {
|
||||
id: customId || `${Date.now()}-litellm`,
|
||||
id: customId || generateExecutionId('litellm'),
|
||||
timestamp: new Date(startTime).toISOString(),
|
||||
tool: 'litellm',
|
||||
model: result.model,
|
||||
@@ -676,7 +701,7 @@ async function executeCliTool(
|
||||
const duration = endTime - startTime;
|
||||
|
||||
const execution: ExecutionRecord = {
|
||||
id: customId || `${Date.now()}-litellm`,
|
||||
id: customId || generateExecutionId('litellm'),
|
||||
timestamp: new Date(startTime).toISOString(),
|
||||
tool: toolName,
|
||||
model: result.model, // Use effective model from result (reflects any override)
|
||||
@@ -789,11 +814,11 @@ async function executeCliTool(
|
||||
existingConversation = loadConversation(workingDir, conversationId);
|
||||
} else {
|
||||
// No previous conversation, create new
|
||||
conversationId = `${Date.now()}-${tool}`;
|
||||
conversationId = generateExecutionId(tool);
|
||||
}
|
||||
} else {
|
||||
// New conversation with auto-generated ID
|
||||
conversationId = `${Date.now()}-${tool}`;
|
||||
conversationId = generateExecutionId(tool);
|
||||
}
|
||||
|
||||
// Generate transaction ID for concurrent session disambiguation
|
||||
@@ -1019,7 +1044,6 @@ async function executeCliTool(
|
||||
|
||||
// Track child process for cleanup on interruption (multi-process support)
|
||||
runningChildProcesses.add(child);
|
||||
writeDebugLog('PROCESS_ADD', { pid: child.pid, set_size_after: runningChildProcesses.size, function: 'executeCliTool', tool });
|
||||
|
||||
debugLog('SPAWN', `Process spawned`, { pid: child.pid });
|
||||
|
||||
@@ -1071,7 +1095,6 @@ async function executeCliTool(
|
||||
child.on('close', async (code) => {
|
||||
// Remove from running processes
|
||||
runningChildProcesses.delete(child);
|
||||
writeDebugLog('PROCESS_DELETE', { pid: child.pid, exit_code: code, set_size_after: runningChildProcesses.size, function: 'executeCliTool', handler: 'close', tool });
|
||||
|
||||
// Flush remaining buffer from parser
|
||||
const remainingUnits = parser.flush();
|
||||
@@ -1200,11 +1223,9 @@ async function executeCliTool(
|
||||
// Save all source conversations
|
||||
try {
|
||||
for (const conv of savedConversations) {
|
||||
writeDebugLog('SAVE_CONVERSATION_START', { conversationId: conv.id, pid: child.pid, function: 'executeCliTool', context: 'merge-loop', tool });
|
||||
saveConversation(workingDir, conv);
|
||||
}
|
||||
} catch (err) {
|
||||
writeDebugLog('SAVE_CONVERSATION_ERROR', { pid: child.pid, error: (err as Error).message, stack: (err as Error).stack, function: 'executeCliTool', context: 'merge-loop', tool });
|
||||
console.error('[CLI Executor] Failed to save merged histories:', (err as Error).message);
|
||||
}
|
||||
} else if (isMerge && mergeResult && customId) {
|
||||
@@ -1244,10 +1265,8 @@ async function executeCliTool(
|
||||
};
|
||||
// Save merged conversation
|
||||
try {
|
||||
writeDebugLog('SAVE_CONVERSATION_START', { conversationId: conversation.id, pid: child.pid, function: 'executeCliTool', context: 'merge-with-id', tool });
|
||||
saveConversation(workingDir, conversation);
|
||||
} catch (err) {
|
||||
writeDebugLog('SAVE_CONVERSATION_ERROR', { conversationId: conversation.id, pid: child.pid, error: (err as Error).message, stack: (err as Error).stack, function: 'executeCliTool', context: 'merge-with-id', tool });
|
||||
console.error('[CLI Executor] Failed to save merged conversation:', (err as Error).message);
|
||||
}
|
||||
} else {
|
||||
@@ -1277,10 +1296,11 @@ async function executeCliTool(
|
||||
};
|
||||
// Try to save conversation to history
|
||||
try {
|
||||
writeDebugLog('SAVE_CONVERSATION_START', { conversationId: conversation.id, pid: child.pid, function: 'executeCliTool', context: 'normal', tool });
|
||||
writeDebugLog('BEFORE_SAVE_CONV', { conversationId: conversation.id, workingDir, tool });
|
||||
saveConversation(workingDir, conversation);
|
||||
writeDebugLog('AFTER_SAVE_CONV', { conversationId: conversation.id, workingDir, tool });
|
||||
} catch (err) {
|
||||
writeDebugLog('SAVE_CONVERSATION_ERROR', { conversationId: conversation.id, pid: child.pid, error: (err as Error).message, stack: (err as Error).stack, function: 'executeCliTool', context: 'normal', tool });
|
||||
writeDebugLog('SAVE_CONV_OUTER_ERROR', { conversationId: conversation.id, workingDir, tool, error: (err as Error).message, stack: (err as Error).stack });
|
||||
// Non-fatal: continue even if history save fails
|
||||
console.error('[CLI Executor] Failed to save history:', (err as Error).message);
|
||||
}
|
||||
@@ -1341,7 +1361,6 @@ async function executeCliTool(
|
||||
child.on('error', (error) => {
|
||||
// Remove from running processes
|
||||
runningChildProcesses.delete(child);
|
||||
writeDebugLog('PROCESS_DELETE', { pid: child.pid, set_size_after: runningChildProcesses.size, function: 'executeCliTool', handler: 'error', tool });
|
||||
|
||||
errorLog('SPAWN', `Failed to spawn process`, error, {
|
||||
tool,
|
||||
|
||||
Reference in New Issue
Block a user