输出与错误码
区分结构化结果与子进程日志,按当前输出字段和错误码处理自动化。
One 自己的结果支持 -o json;stdout 不是 TTY 时默认输出 JSON。帮助和 one mise、one hk 的透传输出保留各自格式,one exec 的子进程输出也保持原样。自动化应先区分命令结果与子进程日志,再按对应字段处理。
1. 输出格式自动判定
# 终端里人类格式:
one templates list
# 管道时自动 JSON(或显式 -o json):
one templates list -o json | jq
one templates list | tee templates.json # 管道 → JSON
自动判定看 stdout 是不是 TTY。显式控制:
one templates list -o json # 强制 JSON
one templates list -o yaml # 强制 YAML
one templates list -o text # 强制人类格式
2. 成功输出
输出结构按命令区分。下面是 one templates -o json 的节选:
{
"schema": "one-cli/templates/v1",
"templates": [
{
"id": "nestjs-api",
"name": "NestJS API",
"toolchain": "node",
"category": "backend"
}
]
}
schema 是结果类型标识,不是网页地址。按对应命令的实际字段解析:
| 命令 | 结果字段 |
|---|---|
one templates | schema、total、templates[] |
one add | schema、subproject_name、target_path、template_id、toolchain |
one whoami | loggedIn、expired,以及可用时的账号信息;没有 schema 或 profiles |
one run <task> | schema、status、exit_code、entries、tasks |
不要假定所有结果有同一层包络。模板名称和说明跟随 CLI 语言,脚本应使用稳定的 ID。
3. 错误包络
One 自己的结构化错误通过 stderr 输出,使用以下包络。子进程失败也可能直接返回原始日志和退出码:
{
"schema": "one-cli/error/v1",
"error": {
"code": "TEMPLATE_NOT_FOUND",
"message": "Template 'nestjs-api-typescript' not found.",
"context": {
"requested_template": "nestjs-api-typescript",
"available_templates": ["nestjs-api", "go-api", "nextjs-app", "..."]
}
}
}
三条规则:
- 按
error.code分流,永远不要按error.message分流。message 是给人看的,会随用户locale(zh-CN vs en-US)变。 - 读
error.context取结构化细节。可用字段取决于失败位置;错误码含义见错误码大全。 - 先看退出码和输出来源。成功结果通常在 stdout,One 的错误在 stderr。
one run的 JSON 模式把子进程日志送到 stderr,可能与错误信息混合;one exec保留子进程输出。
4. shell 里的分流写法
保存 stdout 和 stderr,保留日志。只有 stderr 是可解析的错误包络时,才按错误码分流;否则显示原始错误。
error_file=$(mktemp)
trap 'rm -f "$error_file"' EXIT
if output=$(one add nestjs-api --name api -o json --yes 2>"$error_file"); then
printf '%s\n' "$output" | jq '.subproject_name'
cat "$error_file" >&2
else
exit_code=$?
if code=$(jq -er '.error.code' "$error_file" 2>/dev/null); then
case "$code" in
TARGET_EXISTS) printf '%s\n' "项目目录已存在,请选择其他名称。" >&2 ;;
NOT_ONE_PROJECT) printf '%s\n' "请先进入已有工作区,或创建工作区。" >&2 ;;
*) printf '%s: %s\n' "未处理的错误" "$code" >&2 ;;
esac
fi
cat "$error_file" >&2
exit "$exit_code"
fi
解析时注意:
- message 文本因 i18n 变动
- 未来新增的错误码(
*兜底) - 带有
schema的结果应按命令检查支持的类型
5. agent 的同款模式
读取 One 结构化结果时显式加
-o json。错误包络中读error.code。永远不要解析error.message— 它随用户 locale 变。
实际中,"加一个叫 user-api 的 NestJS 服务"的 agent 会:
- 跑
one add nestjs-api --name user-api -o json --yes - 退出码 0 → 解析成功包络、确认
error.code == "TARGET_EXISTS"→ 试user-api-2,或问用户error.code == "NOT_ONE_PROJECT"→ 先one create或问用户
agent 可以直接根据命令的结构化输出使用这些恢复模式。
6. 关键错误码组
优先处理与你的操作有关的错误,其他错误保留原始原因。常用分组如下:
| 组 | 例子 | 典型处理 |
|---|---|---|
| 工作区状态 | NOT_ONE_PROJECT、WORKSPACE_NESTED_FORBIDDEN、MANIFEST_MISSING_OR_EMPTY | "从工作区根跑"或"先 one create" |
| 模板 | TEMPLATE_NOT_FOUND、TEMPLATE_REQUIRED、INVALID_NAME | 从 error.context 列出可用模板 |
| 工具与任务 | MISE_INSTALL_FAILED、MISE_CONFIG_CONFLICT、RUNTIME_TASK_NOT_FOUND | 检查下载或配置错误,使用 one run 查看任务 |
| Infisical | INFISICAL_NOT_CONFIGURED、INFISICAL_AUTH_MISSING、INFISICAL_AUTH_FAILED | 登录后保存首个变量以绑定工作区;会话失效时重新登录 |
| 环境变量 | ENV_UNKNOWN_ENVIRONMENT、ENV_SET_OVERWRITE_REQUIRED | 选择已声明环境,或确认覆盖后传 --yes |
| Serve | SERVE_PORT_BUSY、SERVE_BIND_FORBIDDEN | 修改 host 或 port flag 后重启 |
当前错误码及恢复说明:错误码大全。
7. JSON 输出作为 CI 契约
CI 中显式指定 -o json,并通过 ONE_VERSION 固定 CLI 版本。将示例版本替换为团队使用的发布版本:
- run: curl -fsSL https://1cli.dev/install.sh | ONE_VERSION=v0.1.0 bash
- run: one -o json add nestjs-api --name api --yes
常见踩坑
| 现象 | 原因 | 修法 |
|---|---|---|
| CI 里拿到人类格式的表格而非 JSON | stdout 是 TTY(CI runner 偶尔会) | 显式传 -o json |
jq 无法解析 | 把日志和结构化结果合并了,或命令透传原始输出 | 分开保存 stdout / stderr;无法解析时保留原始日志 |
不同机器的 error.message 不一样 | 用户 locale 不同 | 正常,按 code 分流即可 |
schema 字段缺失 | 并非每个命令都提供该字段 | 按命令参考解析;例如 whoami 使用 loggedIn |
下一步
- 浏览所有错误码 → 错误码参考