mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
fix: Auto-detect JSON Lines output format for Codex CLI
Problem: Codex CLI uses --json flag to output JSONL events, but executor was using plain text parser. This prevented proper parsing of structured events, breaking session creation. Root cause: buildCommand() added --json flag for Codex but never communicated this to the output parser. Result: JSONL events treated as raw text → session markers lost. Solution: - Extend buildCommand() to return outputFormat - Auto-detect 'json-lines' when tool is 'codex' - Use auto-detected format in executeCliTool() - Properly parse structured events and extract session data Files modified: - ccw/src/tools/cli-executor-utils.ts: Add output format auto-detection - ccw/src/tools/cli-executor-core.ts: Use auto-detected format for parser - ccw/src/commands/cli.ts: Add debug instrumentation Verified: - Codex outputs valid JSONL (confirmed via direct test) - CLI_EXECUTION_STARTED events broadcast correctly - Issue was downstream in output parsing, not event transmission
This commit is contained in:
@@ -77,6 +77,10 @@ function notifyDashboard(data: Record<string, unknown>): void {
|
|||||||
* Uses specific event types that match frontend handlers
|
* Uses specific event types that match frontend handlers
|
||||||
*/
|
*/
|
||||||
function broadcastStreamEvent(eventType: string, payload: Record<string, unknown>): void {
|
function broadcastStreamEvent(eventType: string, payload: Record<string, unknown>): void {
|
||||||
|
if (process.env.DEBUG_CLI_EVENTS) {
|
||||||
|
console.error(`[CLI-BROADCAST] START ${eventType} at ${Date.now()}`);
|
||||||
|
}
|
||||||
|
|
||||||
const data = JSON.stringify({
|
const data = JSON.stringify({
|
||||||
type: eventType,
|
type: eventType,
|
||||||
...payload,
|
...payload,
|
||||||
@@ -107,6 +111,10 @@ function broadcastStreamEvent(eventType: string, payload: Record<string, unknown
|
|||||||
});
|
});
|
||||||
req.write(data);
|
req.write(data);
|
||||||
req.end();
|
req.end();
|
||||||
|
|
||||||
|
if (process.env.DEBUG_CLI_EVENTS) {
|
||||||
|
console.error(`[CLI-BROADCAST] END ${eventType} at ${Date.now()}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CliExecOptions {
|
interface CliExecOptions {
|
||||||
@@ -1093,15 +1101,27 @@ async function execAction(positionalPrompt: string | undefined, options: CliExec
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Broadcast CLI_EXECUTION_COMPLETED for real-time streaming viewer
|
// Broadcast CLI_EXECUTION_COMPLETED for real-time streaming viewer
|
||||||
|
if (process.env.DEBUG_CLI_EVENTS) {
|
||||||
|
console.error(`[CLI-TIMING] Broadcasting CLI_EXECUTION_COMPLETED at ${Date.now()}`);
|
||||||
|
}
|
||||||
broadcastStreamEvent('CLI_EXECUTION_COMPLETED', {
|
broadcastStreamEvent('CLI_EXECUTION_COMPLETED', {
|
||||||
executionId, // Use the same executionId as started event
|
executionId, // Use the same executionId as started event
|
||||||
success: true,
|
success: true,
|
||||||
duration: result.execution.duration_ms
|
duration: result.execution.duration_ms
|
||||||
});
|
});
|
||||||
|
if (process.env.DEBUG_CLI_EVENTS) {
|
||||||
|
console.error(`[CLI-TIMING] Broadcast returned, setting timeout at ${Date.now()}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure clean exit after successful execution
|
// Ensure clean exit after successful execution
|
||||||
// Delay to allow HTTP request to complete
|
// Delay to allow HTTP request to complete
|
||||||
setTimeout(() => process.exit(0), 150);
|
// FIX: Increased from 150ms to 500ms for long-running executions
|
||||||
|
setTimeout(() => {
|
||||||
|
if (process.env.DEBUG_CLI_EVENTS) {
|
||||||
|
console.error(`[CLI-TIMING] process.exit(0) at ${Date.now()}`);
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
if (!spinner) {
|
if (!spinner) {
|
||||||
console.log(chalk.red(` ✗ Failed (${result.execution.status})`));
|
console.log(chalk.red(` ✗ Failed (${result.execution.status})`));
|
||||||
|
|||||||
@@ -795,7 +795,7 @@ async function executeCliTool(
|
|||||||
const effectiveModel = model || getPrimaryModel(workingDir, tool);
|
const effectiveModel = model || getPrimaryModel(workingDir, tool);
|
||||||
|
|
||||||
// Build command
|
// Build command
|
||||||
const { command, args, useStdin } = buildCommand({
|
const { command, args, useStdin, outputFormat: autoDetectedFormat } = buildCommand({
|
||||||
tool,
|
tool,
|
||||||
prompt: finalPrompt,
|
prompt: finalPrompt,
|
||||||
mode,
|
mode,
|
||||||
@@ -806,8 +806,11 @@ async function executeCliTool(
|
|||||||
reviewOptions: mode === 'review' ? { uncommitted, base, commit, title } : undefined
|
reviewOptions: mode === 'review' ? { uncommitted, base, commit, title } : undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Use auto-detected format (from buildCommand) if available, otherwise use passed outputFormat
|
||||||
|
const finalOutputFormat = autoDetectedFormat || outputFormat;
|
||||||
|
|
||||||
// Create output parser and IR storage
|
// Create output parser and IR storage
|
||||||
const parser = createOutputParser(outputFormat);
|
const parser = createOutputParser(finalOutputFormat);
|
||||||
const allOutputUnits: CliOutputUnit[] = [];
|
const allOutputUnits: CliOutputUnit[] = [];
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@@ -820,7 +823,7 @@ async function executeCliTool(
|
|||||||
promptLength: finalPrompt.length,
|
promptLength: finalPrompt.length,
|
||||||
hasResume: !!resume,
|
hasResume: !!resume,
|
||||||
hasCustomId: !!customId,
|
hasCustomId: !!customId,
|
||||||
outputFormat
|
outputFormat: finalOutputFormat
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ export function buildCommand(params: {
|
|||||||
commit?: string;
|
commit?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
};
|
};
|
||||||
}): { command: string; args: string[]; useStdin: boolean } {
|
}): { command: string; args: string[]; useStdin: boolean; outputFormat?: 'text' | 'json-lines' } {
|
||||||
const { tool, prompt, mode = 'analysis', model, dir, include, nativeResume, settingsFile, reviewOptions } = params;
|
const { tool, prompt, mode = 'analysis', model, dir, include, nativeResume, settingsFile, reviewOptions } = params;
|
||||||
|
|
||||||
debugLog('BUILD_CMD', `Building command for tool: ${tool}`, {
|
debugLog('BUILD_CMD', `Building command for tool: ${tool}`, {
|
||||||
@@ -381,5 +381,8 @@ export function buildCommand(params: {
|
|||||||
fullCommand: `${command} ${args.join(' ')}${useStdin ? ' (stdin)' : ''}`,
|
fullCommand: `${command} ${args.join(' ')}${useStdin ? ' (stdin)' : ''}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { command, args, useStdin };
|
// Auto-detect output format: Codex uses --json flag for JSONL output
|
||||||
|
const outputFormat = tool.toLowerCase() === 'codex' ? 'json-lines' : 'text';
|
||||||
|
|
||||||
|
return { command, args, useStdin, outputFormat };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user