50 lines
3.1 KiB
JavaScript
50 lines
3.1 KiB
JavaScript
// No network: a Claude CLI stand-in that distinguishes text and stream modes.
|
|
import { writeFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
const args = process.argv.slice(2);
|
|
const mode = process.env.FAKE_CLAUDE_MODE ?? 'tool';
|
|
const answer = mode === 'failed' || mode === 'failed-success-subtype' || mode === 'failed-zero-exit'
|
|
? 'API Error: 400 fixture-error' : ' Answer é 🦆\nsecond line\n';
|
|
writeFileSync(join(process.env.MOSAIC_WORKSPACE, 'cli-pid'), String(process.pid));
|
|
const emit = item => process.stdout.write(JSON.stringify(item) + '\n');
|
|
if (args[args.indexOf('--output-format') + 1] === 'text') {
|
|
process.stdout.write(answer.endsWith('\n') ? answer : answer + '\n');
|
|
} else {
|
|
if (!args.includes('--verbose') || !args.includes('--include-partial-messages')) process.exit(9);
|
|
emit({ type: 'system', subtype: 'init', private: 'credential-canary' });
|
|
emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', content: 'local work' }] } });
|
|
emit({ type: 'assistant', error: 'api_error', message: { role: 'assistant', model: '<synthetic>', content: [{ type: 'text', text: 'local CLI error' }] } });
|
|
// Local file writes and diagnostic text must never cancel the watchdog.
|
|
writeFileSync(join(process.env.MOSAIC_WORKSPACE, 'draft'), 'workspace-canary');
|
|
process.stderr.write('fixture diagnostic\n');
|
|
if (mode === 'malformed') {
|
|
process.stdout.write('invalid credential-canary\n');
|
|
} else if (mode === 'missing') {
|
|
// Exit 0 without a result still fails the adapter.
|
|
} else if (['failed', 'failed-success-subtype', 'failed-zero-exit', 'nonzero-success'].includes(mode)) {
|
|
emit({ type: 'result', subtype: mode === 'failed-success-subtype' || mode === 'nonzero-success' ? 'success' : 'error_during_execution',
|
|
is_error: mode === 'failed-success-subtype', result: answer, errors: ['credential-canary'] });
|
|
process.exitCode = mode === 'failed-zero-exit' ? 0 : 7;
|
|
} else if (['malformed-after-result', 'oversized', 'truncated'].includes(mode)) {
|
|
// A complete answer before corrupt trailing data must still be withheld.
|
|
emit({ type: 'result', subtype: 'success', result: answer });
|
|
process.stdout.write(mode === 'oversized' ? 'x'.repeat(16 * 1024 * 1024 + 1)
|
|
: mode === 'truncated' ? '{"type":"result"' : 'invalid credential-canary\n');
|
|
} else {
|
|
if (mode !== 'silent') {
|
|
const event = mode === 'thinking'
|
|
? { type: 'content_block_delta', delta: { type: 'thinking_delta', thinking: 'private reasoning' } }
|
|
: mode === 'header'
|
|
? { type: 'message_start', message: { role: 'assistant' } }
|
|
: mode === 'assistant'
|
|
? null
|
|
: { type: 'content_block_start', content_block: { type: 'tool_use', id: 'tool-1', name: 'Write', input: {} } };
|
|
if (event) emit({ type: 'stream_event', event });
|
|
else emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: 'private draft' }] } });
|
|
}
|
|
setTimeout(() => {
|
|
emit({ type: 'result', subtype: 'success', is_error: false, result: answer });
|
|
}, mode === 'interrupt' || mode === 'silent' ? 30_000 : Number(process.env.FAKE_CLAUDE_DELAY ?? 100));
|
|
}
|
|
}
|