Files
nanoclaw/docs/zh/setup-flow.md
2026-05-12 13:14:17 +00:00

9.4 KiB
Raw Permalink Blame History

安装流程

本文档是 NanoClaw 端到端脚本化安装的契约 bash nanoclaw.shpnpm run setup:auto)。在添加新步骤、修复回退或更改输出渲染方式之前,请阅读本文档。

三个输出级别

每个安装步骤在三个不同级别产生输出。它们面向 不同的受众,输出到不同的位置,并以不同的格式呈现。 不要混淆它们。

级别 受众 目的地 格式
1. 面向用户 运行安装的操作者 终端(通过 clack 品牌化的、简洁的、信息性的——"产品内容"
2. 进度 未来调试者、审查失败运行的 AI agent、发布支持 logs/setup.log(一个文件,仅追加) 结构化的每个步骤块,线性时间顺序,人类和机器可读
3. 原始 正在深度调试特定步骤的人 logs/setup-steps/NN-step-name.log(每个步骤一个文件) 完整的原始子进程 stdout + stderr逐字记录

可以这样理解:用户看到的是摘要,进度日志是 带关键事实的索引,原始日志是证据

级别 1面向用户clack

setup/auto.ts 通过 @clack/prompts 渲染。这是我们的产品 界面——每行都应读起来像是我们为第一天遇到的陌生人设计的一样。

  • 使用 clack spinner 表示进行中的工作。显示经过的时间。
  • p.log.success / p.log.step / p.log.warn 用于永久状态标记。
  • p.note 用于多行信息(配对码、下一步)。
  • p.text / p.select / p.password 用于提示。
  • 品牌调色板:setup/auto.ts 中的 brand() / brandBold() / brandChip() 辅助函数。当终端支持时使用真彩色,否则回退到 16 色青色,管道输出 / NO_COLOR 时使用纯文本。

规则:

  • 无中断。 每个子步骤属于同一个视觉流程。唯一的例外是 Anthropic 凭据注册(见下文)。
  • 无原始子进程输出。 永远不要对输出内容非我们所编写的子进程使用 stdio: 'inherit'。捕获它,仅在失败时显示。
  • 无调试样式前缀[add-telegram] …INFO …、时间戳)。这些属于级别 2 和 3。
  • 无 emoji,除非 clack 图形需要。

级别 2进度日志

logs/setup.log——每次安装运行一个文件,仅追加,跨多次运行安装累积 (如果某次运行中途失败并被重新尝试,新条目会追加)。这是你在操作者报告安装 bug 时 会要求他们粘贴的东西,也是 AI agent 会阅读以了解发生了什么的东西。

条目格式:

=== [2026-04-22T22:14:12Z] bootstrap [45.1s] → success ===
  platform: linux
  is_wsl: false
  node_version: 22.22.2
  deps_ok: true
  native_ok: true
  raw: logs/setup-steps/01-bootstrap.log

=== [2026-04-22T22:14:57Z] environment [2.3s] → success ===
  docker: running
  apple_container: not_found
  raw: logs/setup-steps/02-environment.log

=== [2026-04-22T22:15:00Z] container [92.4s] → success ===
  runtime: docker
  image: nanoclaw-agent:latest
  build_ok: true
  raw: logs/setup-steps/03-container.log

设计约束:

  • 开始行带有起始时间戳UTCISO-8601使 grep 能给出顺序。

  • 持续时间以秒为单位,保留一位小数——快速步骤读作 "0.5s",而非 "0ms"。

  • 状态为以下之一:successskippedfailedaborted

  • 字段是步骤特定的,但必须是短标量值。无 JSON无多行。如果值很长放在原始日志中并引用它。

  • 始终输出一个 raw: 指针,即使在成功时——使调试第二次失败更容易。

  • 用户选择是其自己的条目,不嵌套在步骤中:

    === [2026-04-22T22:17:44Z] user-input → display_name ===
      value: gav
    
    === [2026-04-22T22:17:51Z] user-input → channel_choice ===
      value: telegram
    

    这些很重要,因为通过安装流程的路径取决于它们。

日志以标识运行的头部块开始,以完成块结束:

## 2026-04-22T22:14:12Z · setup:auto 已启动
  user: exedev
  cwd: /home/exedev/nanoclaw
  branch: branded-setup
  commit: 6e0d742

… (步骤条目) …

## 2026-04-22T22:18:54Z · 已完成 (总计 4m42s)

失败时完成块会指出失败的步骤及其错误:

## 2026-04-22T22:16:40Z · 在 container 处中止 (err=cache_miss)

级别 3原始按步骤日志

logs/setup-steps/NN-step-name.log——每个步骤一个文件,按执行顺序编号(两位零填充前缀以支持自然排序)。来自子进程的完整逐字 stdout + stderr。每次运行时截断并重写非追加

内容为步骤输出的任何内容apt 输出、docker 构建层、pnpm install 内容、curl 响应体等。这是证据层面——"shell 实际看到了什么?"不过滤任何内容。

新步骤的契约

当你添加一个步骤(无论是 setup/<name>.ts 中的 TS 步骤还是从 auto.ts 调用的 bash 安装程序),它必须:

  1. 从调用方接收一个原始日志路径。 将所有 stdout + stderr 写入那里。不要直接写入终端。

  2. 在结束时输出单个终端状态块,包含 STATUS: success|skipped|failed 和任何步骤特定字段:

    === NANOCLAW SETUP: STEP_NAME ===
    STATUS: success
    KEY: value
    KEY: value
    === END ===
    

    字段名使用 UPPER_SNAKE_CASE。值是短标量值。

  3. 如果是一个长时间运行的步骤,可选择在中途发出子状态块auto.ts 实时解析它们,并可以渲染中间 UI正如 pair-telegram 使用 PAIR_TELEGRAM_CODE / PAIR_TELEGRAM_ATTEMPT 所做的那样)。

  4. 在硬失败时以非零退出,以便 auto.ts 可以区分"步骤运行完成并报告失败"与"步骤崩溃"。

驱动程序处理其余部分:级别 1 中的 spinner级别 2 中的结构化追加,级别 3 中的原始捕获。

Anthropic 例外

Anthropic 凭据注册(setup/register-claude-token.sh)是视觉流程中唯一允许的中断。原因:

  • claude setup-token 打开浏览器,运行自己的 OAuth 提示,并打印 token。它通过 script(1) 拥有 TTY。
  • 我们不想自己重新实现 OAuth 设备流程。
  • 我们不想拦截/镜像 token它已经出现在用户终端——镜像它会增加攻击面

因此在此步骤期间:

  • clack 流程显式暂停(一个 p.log.step 标记说"这部分是交互式的,你正在移交给 Anthropic")。
  • 子进程完全继承 stdio。
  • 当控制返回时clack 在下一行恢复,带有一个成功标记。

级别 2 日志仍然获得一个条目(auth [interactive] → success 带有方法——subscription / oauth-token / api-key。级别 3 的捕获在这里是可选的;镜像 script -q 输出很棘手,将 token 泄露到磁盘的风险超过了调试价值。

文件参考

文件 角色
nanoclaw.sh 顶层封装。阶段 1bootstrap和阶段 2setup:auto编排。写入 bootstrap 的原始日志 + 进度条目。
setup.sh 阶段 1 bootstrapNode、pnpm、原生模块验证。发出自己的 BOOTSTRAP 状态块(历史上打印到 stdout现在输出到 bootstrap 原始日志)。
setup/auto.ts 阶段 2 驱动程序。编排 clack UI、步骤执行、用户提示并为其启动的每个步骤写入所有三个日志级别。
setup/logs.ts 日志记录原语(logSteplogUserInputlogCompletestepRawLoginitSetupLog)。级别 2/3 格式和文件路径的唯一真源。
setup/<step>.ts 各个步骤的实现。必须输出一个终端状态块;不能直接写入终端。
setup/register-claude-token.sh Anthropic 例外。继承 stdio打印自己的 UI向驱动程序返回状态。
setup/add-telegram.sh 非交互式适配器安装程序。从 env 读取 TELEGRAM_BOT_TOKEN;从不提示。面向用户的部分驻留在 auto.ts 中。
setup/pair-telegram.ts 发出 PAIR_TELEGRAM_CODE / PAIR_TELEGRAM_ATTEMPT / PAIR_TELEGRAM 状态块。从不打印 UI。驱动程序通过 clack notes 渲染。

常见陷阱

  • 在步骤内部打印调试输出。 开发时诱人;检入代码时禁止。所有运行时消息都通过状态块(级别 2或原始日志写入级别 3
  • 添加一个"仅此一次"输出到终端的 console.log 它会破坏 clack 流程——spinner 行会被撕裂。改用 src/log.ts 中的 log.info / log.error(写入原始日志)。
  • 对非例外子进程使用 stdio: 'inherit' 见上文 Anthropic。其他任何情况都需要 pipe + 显式捕获。
  • Tee 到 stderr。 Clack 的 spinner 在一个步骤期间拥有终端。即使是 stderr 写入也会撕裂框架。管道传输一切,然后选择要暴露的内容。
  • bash $VAR… 位置中的 UTF-8。 Bash 的词法分析器可能将多字节字符的第一个字节拉入变量名,触发 set -u。始终加花括号:${VAR}…

未来工作(尚未实现)

  • 进度日志轮转。 今天的实现在每次运行时截断。未来:将之前的运行滚动到 logs/setup.log.1.2 等。
  • 多次运行安装的原始日志轮转。 目前每次运行会覆盖。目前可以接受;如果支持需要比较连续尝试,则重新审视。
  • register-claude-token.sh 的结构化输出。 交互式步骤目前不发出机器可读状态。未来可以在交互后添加一个状态块,注明使用的方法。