#!/usr/bin/env node /** * 离线测试替身:模拟"外部编码 CLI agent"(真实子进程,非函数 mock)。 * 接受 codex 风格 argv:exec [flags...] -C ,stdin 立即 EOF。 * 从 prompt 中解析"建议文件名 ",在 workdir 真实落盘一个确定性产物,exit 0。 * 仅用于 GW_ORCH_OFFLINE=1 的离线 e2e;REAL 模式永远走真实 codex。 */ import { mkdirSync, writeFileSync } from "node:fs"; import { resolve, dirname, join } from "node:path"; const argv = process.argv.slice(2); let workdir = process.cwd(); for (let i = 0; i < argv.length; i++) { if (argv[i] === "-C" || argv[i] === "--cd" || argv[i] === "--cwd") { workdir = argv[++i]; } } const prompt = argv.filter((a) => !a.startsWith("-") && a !== "exec").join(" "); const m = prompt.match(/建议文件名\s+([^\s))]+)/); const fname = m ? m[1] : "solution.mjs"; const fabs = resolve(workdir, fname); mkdirSync(dirname(fabs), { recursive: true }); let body; if (/\.(mjs|js)$/i.test(fname)) { body = [ "#!/usr/bin/env node", "// fixture 外部 CLI 生成的确定性实现(离线 e2e 用;REAL 模式由真实 codex 生成)", "import { readFileSync } from 'node:fs';", "const args = Object.fromEntries(process.argv.slice(2).map((a) => { const [k, v] = a.replace(/^--/, '').split('='); return [k, v]; }));", "const top = Number(args.top || 5);", "const file = process.argv.slice(2).find((a) => !a.startsWith('--'));", "if (!file) { console.error('usage: node wordcount.mjs [--top=N] '); process.exit(1); }", "const text = readFileSync(file, 'utf8');", "const words = text.toLowerCase().match(/[a-z0-9]+|[\u4e00-\u9fa5]{1,2}/g) || [];", "const freq = new Map();", "for (const w of words) freq.set(w, (freq.get(w) || 0) + 1);", "const ranked = [...freq.entries()].sort((a, b) => b[1] - a[1]).slice(0, top);", "for (const [w, c] of ranked) console.log(`${w}\t${c}`);", "", ].join("\n"); } else { body = `# fixture 产物(${fname})\n\n由离线替身 CLI 依据子任务目标生成:\n\n${prompt.slice(0, 400)}\n`; } writeFileSync(fabs, body, "utf8"); // 若建议文件名是 README,再补一个最小占位,保证目录非空 if (/readme/i.test(fname)) writeFileSync(join(workdir, "USAGE.txt"), `usage fixture: node solution.mjs --top=5 samples/sample.txt\n`, "utf8"); console.log(`fixture-agent: wrote ${fname} (${body.length}B) into ${workdir}`); process.exit(0);