Files
Claude-Code-Workflow/ccw/tests/cli-output-command-final.test.js
catlog22 5a4b18d9b1 feat: enhance search, ranking, reranker and CLI tooling across ccw and codex-lens
Major improvements to smart-search, chain-search cascade, ranking pipeline,
reranker factory, CLI history store, codex-lens integration, and uv-manager.
Simplify command-generator skill by inlining phases. Add comprehensive tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:35:08 +08:00

226 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ccw cli output --final regression tests
*
* Verifies strict final-result behavior for cached executions.
*/
import { after, afterEach, before, describe, it, mock } from 'node:test';
import assert from 'node:assert/strict';
import { existsSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const TEST_CCW_HOME = mkdtempSync(join(tmpdir(), 'ccw-cli-output-final-home-'));
const cliCommandPath = new URL('../dist/commands/cli.js', import.meta.url).href;
const historyStorePath = new URL('../dist/tools/cli-history-store.js', import.meta.url).href;
function createTestProjectRoot() {
const dirPath = mkdtempSync(join(tmpdir(), 'ccw-cli-output-final-project-'));
if (!existsSync(dirPath)) {
mkdirSync(dirPath, { recursive: true });
}
return dirPath;
}
function createConversation({ id, stdoutFull = '', parsedOutput, finalOutput }) {
return {
id,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
tool: 'codex',
model: 'default',
mode: 'analysis',
category: 'user',
total_duration_ms: 100,
turn_count: 1,
latest_status: 'success',
turns: [
{
turn: 1,
timestamp: new Date().toISOString(),
prompt: 'test prompt',
duration_ms: 100,
status: 'success',
exit_code: 0,
output: {
stdout: stdoutFull,
stderr: '',
truncated: false,
cached: true,
stdout_full: stdoutFull,
stderr_full: '',
parsed_output: parsedOutput,
final_output: finalOutput,
},
},
],
};
}
describe('ccw cli output --final', async () => {
let cliModule;
let historyStoreModule;
before(async () => {
process.env.CCW_DATA_DIR = TEST_CCW_HOME;
cliModule = await import(cliCommandPath);
historyStoreModule = await import(historyStorePath);
});
afterEach(() => {
mock.restoreAll();
try {
historyStoreModule?.closeAllStores?.();
} catch {
// ignore
}
});
after(() => {
try {
historyStoreModule?.closeAllStores?.();
} catch {
// ignore
}
rmSync(TEST_CCW_HOME, { recursive: true, force: true });
});
it('reconstructs the final agent message from raw JSONL when final_output is missing', async () => {
const projectRoot = createTestProjectRoot();
const store = new historyStoreModule.CliHistoryStore(projectRoot);
const stdoutFull = [
JSON.stringify({ type: 'thread.started', thread_id: 'THREAD-1' }),
JSON.stringify({ type: 'turn.started' }),
JSON.stringify({ type: 'item.completed', item: { id: 'item_0', type: 'agent_message', text: 'Running `pwd` now.' } }),
JSON.stringify({ type: 'item.completed', item: { id: 'item_1', type: 'command_execution', command: 'pwd', aggregated_output: 'D:\\Claude_dms3\\ccw', exit_code: 0, status: 'completed' } }),
JSON.stringify({ type: 'item.completed', item: { id: 'item_2', type: 'agent_message', text: 'Waiting for the command output, then Ill return it verbatim.' } }),
JSON.stringify({ type: 'item.completed', item: { id: 'item_3', type: 'agent_message', text: 'D:\\Claude_dms3\\ccw' } }),
JSON.stringify({ type: 'turn.completed', usage: { input_tokens: 1, output_tokens: 1 } }),
'',
].join('\n');
try {
store.saveConversation(createConversation({
id: 'EXEC-RECONSTRUCT-FINAL',
stdoutFull,
parsedOutput: 'Running `pwd` now.\nWaiting for the command output, then Ill return it verbatim.\nD:\\Claude_dms3\\ccw',
finalOutput: undefined,
}));
const logs = [];
mock.method(console, 'log', (...args) => {
logs.push(args.map(String).join(' '));
});
mock.method(console, 'error', () => {});
await cliModule.cliCommand('output', ['EXEC-RECONSTRUCT-FINAL'], { final: true, project: projectRoot });
assert.deepEqual(logs, ['D:\\Claude_dms3\\ccw']);
} finally {
store.close();
rmSync(projectRoot, { recursive: true, force: true });
}
});
it('loads cached output from another registered project without --project', async () => {
const projectRoot = createTestProjectRoot();
const unrelatedCwd = createTestProjectRoot();
const previousCwd = process.cwd();
const store = new historyStoreModule.CliHistoryStore(projectRoot);
try {
store.saveConversation(createConversation({
id: 'EXEC-CROSS-PROJECT-OUTPUT',
stdoutFull: 'cross project raw output',
parsedOutput: 'cross project parsed output',
finalOutput: 'cross project final output',
}));
process.chdir(unrelatedCwd);
const logs = [];
mock.method(console, 'log', (...args) => {
logs.push(args.map(String).join(' '));
});
mock.method(console, 'error', () => {});
await cliModule.cliCommand('output', ['EXEC-CROSS-PROJECT-OUTPUT'], {});
assert.equal(logs.at(-1), 'cross project final output');
} finally {
process.chdir(previousCwd);
store.close();
rmSync(projectRoot, { recursive: true, force: true });
rmSync(unrelatedCwd, { recursive: true, force: true });
}
});
it('fails fast for explicit --final when no final agent result can be recovered', async () => {
const projectRoot = createTestProjectRoot();
const store = new historyStoreModule.CliHistoryStore(projectRoot);
try {
store.saveConversation(createConversation({
id: 'EXEC-NO-FINAL',
stdoutFull: 'plain stdout without JSONL final message',
parsedOutput: 'INTERMEDIATE_STATUS_LINE',
finalOutput: undefined,
}));
const logs = [];
const errors = [];
const exitCodes = [];
mock.method(console, 'log', (...args) => {
logs.push(args.map(String).join(' '));
});
mock.method(console, 'error', (...args) => {
errors.push(args.map(String).join(' '));
});
mock.method(process, 'exit', (code) => {
exitCodes.push(code);
});
await cliModule.cliCommand('output', ['EXEC-NO-FINAL'], { final: true, project: projectRoot });
assert.deepEqual(logs, []);
assert.deepEqual(exitCodes, [1]);
assert.ok(errors.some((line) => line.includes('No final agent result found in cached output.')));
} finally {
store.close();
rmSync(projectRoot, { recursive: true, force: true });
}
});
it('prints CCW execution ID guidance when output cannot find the requested execution', async () => {
const projectRoot = createTestProjectRoot();
const previousCwd = process.cwd();
try {
process.chdir(projectRoot);
const errors = [];
const exitCodes = [];
mock.method(console, 'log', () => {});
mock.method(console, 'error', (...args) => {
errors.push(args.map(String).join(' '));
});
mock.method(process, 'exit', (code) => {
exitCodes.push(code);
});
await cliModule.cliCommand('output', ['rebuttal-structure-analysis'], {});
assert.deepEqual(exitCodes, [1]);
assert.ok(errors.some((line) => line.includes('real CCW execution ID')));
assert.ok(errors.some((line) => line.includes('CCW_EXEC_ID')));
assert.ok(errors.some((line) => line.includes('ccw cli show or ccw cli history')));
} finally {
process.chdir(previousCwd);
rmSync(projectRoot, { recursive: true, force: true });
}
});
});