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

175 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 安装流程
本文档是 NanoClaw 端到端脚本化安装的契约
`bash nanoclaw.sh``pnpm 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"。
- 状态为以下之一:`success``skipped``failed``aborted`
- 字段是步骤特定的,但**必须**是短标量值。无 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` | 日志记录原语(`logStep`、`logUserInput`、`logComplete`、`stepRawLog`、`initSetupLog`)。级别 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` 的结构化输出。** 交互式步骤目前不发出机器可读状态。未来可以在交互后添加一个状态块,注明使用的方法。