让 AI 修命令行工具:报错还得让 CI 变红
把错误文本和退出码分别验收。

脚本遇到坏输入,打印了「导入失败」,CI 却给出绿灯。终端用户看到一行字,上游命令通常依靠退出码判断成功与否。两者需要一起设计。
交给编码助手的任务
把会被脚本调用的导入工具交给助手,约定成功时 stdout 只输出 JSON,失败信息放 stderr,退出码非零。让它用子进程跑入口,分别捕获两个流和实际状态码。

让退出码带出真正结果
把业务失败转换成非零退出码,把给人的提示写到标准错误。正常输出仍走标准输出,便于后续命令读取。Node 中可以设置 process.exitCode 让进程在剩余工作完成后自然退出。
直接调用 process.exit() 会终止进程,某些异步输出可能来不及写完。先用一条失败输入检查返回码和错误流,再用成功输入确认标准输出仍适合机器解析。
如果交付文档要给自动化使用,把成功与失败的约定写在命令示例旁边。
先准备一个对照样例
用 node import.mjs good.json 和同一入口的坏文件做对照。核对三项结果:stdout 的 JSON、stderr 的错误消息、进程返回值。验收方可以直接把成功输出管给下游读取,避免把人为日志当数据。
用这些结果验收
- 正常文件输出可解析 JSON 且退出 0。
- 坏文件非零退出,错误流含可辨认提示。
- 把结果放进 CI 脚本时,失败不会被当成通过。
审查时容易漏掉什么
如果日志与 JSON 共用 stdout,机器消费者可能解析失败。让 Node 以 exitCode 自然结束时,还应确认没有忘记关闭文件句柄或定时器。终端测试只验证承诺的格式,不绑定无关日志。
让助手跑一条真正的调用链,例如执行脚本后用上游读取状态码,再解析 stdout。若脚本通过管道串起来,还要确认外层如何观察失败。失败场景可用命令行参数错误和文件解析错误两种,防止只在其中一处设置退出码。
这是入口的输出约定。导入函数应明确区分业务失败与允许忽略的输入。
try {
const result = await importFile(process.argv[2]);
process.stdout.write(JSON.stringify(result) + '\n');
} catch (error) {
console.error('导入失败:' + error.message);
process.exitCode = 1;
}
