434 lines
18 KiB
Markdown
434 lines
18 KiB
Markdown
# 故障排查
|
||
|
||
## `/sf doctor`
|
||
|
||
内置诊断工具会校验 `.sf/` 的完整性:
|
||
|
||
```
|
||
/sf doctor
|
||
```
|
||
|
||
它会检查:
|
||
|
||
- 文件结构和命名约定
|
||
- roadmap ↔ slice ↔ task 的引用完整性
|
||
- 完成状态是否一致
|
||
- Git worktree 健康状态(仅 worktree 和 branch 模式;none 模式跳过)
|
||
- 过期锁文件和孤儿运行时记录
|
||
|
||
## 常见问题
|
||
|
||
### 自动模式在同一个单元上循环
|
||
|
||
**症状:** 同一个工作单元(例如 `research-slice` 或 `plan-slice`)被反复派发,直到触发 dispatch 上限。
|
||
|
||
**原因:**
|
||
|
||
- 崩溃后的缓存过期:内存中的文件列表没有反映新产物
|
||
- LLM 没有生成预期的 artifact 文件
|
||
|
||
**解决:** 先运行 `/sf doctor` 修复状态,然后执行 `/sf autonomous` 恢复。如果问题持续存在,检查预期 artifact 文件是否确实已经写到磁盘。
|
||
|
||
### 自动模式因 “Loop detected” 停止
|
||
|
||
**原因:** 同一个单元连续两次没有生成预期 artifact。
|
||
|
||
**解决:** 检查 task plan 是否足够清晰。如果 plan 存在歧义,先手动澄清,再执行 `/sf autonomous` 恢复。
|
||
|
||
### Worktree 中出现了错误文件
|
||
|
||
**症状:** Planning 产物或代码被写到了错误目录。
|
||
|
||
**原因:** LLM 把内容写回了主仓库,而不是 worktree。
|
||
|
||
**解决:** 该问题已在 v2.14+ 修复。如果你仍在旧版本,请更新。现在 dispatch prompt 已包含明确的工作目录指令。
|
||
|
||
### 安装后出现 `command not found: sf`
|
||
|
||
**症状:** `npm install -g singularity-forge` 成功,但系统找不到 `sf`。
|
||
|
||
**原因:** npm 的全局 bin 目录没有加入 shell 的 `$PATH`。
|
||
|
||
**解决:**
|
||
|
||
```bash
|
||
# 找出 npm 安装二进制的目录
|
||
npm prefix -g
|
||
# 输出:/opt/homebrew(Apple Silicon)或 /usr/local(Intel Mac)
|
||
|
||
# 如果缺失,把 bin 目录加入 PATH
|
||
echo 'export PATH="$(npm prefix -g)/bin:$PATH"' >> ~/.zshrc
|
||
source ~/.zshrc
|
||
```
|
||
|
||
**临时方案:** 直接执行 `npx singularity-forge`,或使用 `$(npm prefix -g)/bin/sf`。
|
||
|
||
**常见原因:**
|
||
|
||
- **Homebrew Node**:理论上 `/opt/homebrew/bin` 应该在 PATH 里,但如果 shell profile 没有初始化 Homebrew,就可能缺失
|
||
- **版本管理器(nvm、fnm、mise)**:全局 bin 路径是按版本区分的,需确保版本管理器正确初始化
|
||
- **oh-my-zsh**:`gitfast` 插件会把 `sf` alias 到 `git svn dcommit`。可通过 `alias sf` 检查,并在需要时取消 alias
|
||
|
||
### `npm install -g singularity-forge` 失败
|
||
|
||
**常见原因:**
|
||
|
||
- 缺少 workspace packages:已在 v2.10.4+ 修复
|
||
- Linux 上 `postinstall` 卡住(Playwright `--with-deps` 触发 sudo):已在 v2.3.6+ 修复
|
||
- Node.js 版本过低:要求 ≥ 24.0.0
|
||
|
||
### 自动模式中的 provider 错误
|
||
|
||
**症状:** 自动模式因为 provider 错误暂停(限流、服务端错误、认证失败)。
|
||
|
||
**SF 的处理方式(v2.26):**
|
||
|
||
| 错误类型 | 自动恢复? | 延迟 |
|
||
|----------|------------|------|
|
||
| Rate limit(429、`too many requests`) | ✅ 是 | `retry-after` 头或默认 60 秒 |
|
||
| Server error(500、502、503、`overloaded`) | ✅ 是 | 30 秒 |
|
||
| Auth / billing(`unauthorized`、`invalid key`) | ❌ 否 | 需要手动恢复 |
|
||
|
||
对于瞬时错误,SF 会短暂停顿后自动继续。对于永久性错误,建议配置 fallback models:
|
||
|
||
```yaml
|
||
models:
|
||
execution:
|
||
model: claude-sonnet-4-6
|
||
fallbacks:
|
||
- openrouter/minimax/minimax-m2.5
|
||
```
|
||
|
||
**Headless 模式:** `sf headless autonomous` 在进程崩溃时会自动重启整个进程(默认 3 次,带指数退避)。与 provider 错误自动恢复配合后,能支持真正的夜间无人值守运行。
|
||
|
||
常见的 provider 配置问题(role 错误、streaming 错误、model ID 不匹配)见 [Provider 设置指南:常见坑点](./providers.md#common-pitfalls)。
|
||
|
||
### 达到预算上限
|
||
|
||
**症状:** 自动模式因 “Budget ceiling reached” 暂停。
|
||
|
||
**解决:** 提高偏好设置中的 `budget_ceiling`,或者切换到 `budget` token profile 降低每个工作单元成本,然后再执行 `/sf autonomous` 恢复。
|
||
|
||
### 过期锁文件
|
||
|
||
**症状:** 自动模式无法启动,提示另一个会话正在运行。
|
||
|
||
**解决:** SF 会自动检测过期锁:如果持有锁的 PID 已死亡,则在下次 `/sf autonomous` 时清理并重新获取锁。它也会处理 `proper-lockfile` 崩溃后遗留的 `.sf.lock/` 目录。如果自动恢复失败,可手动删除 `.sf/auto.lock` 和 `.sf.lock/`:
|
||
|
||
```bash
|
||
rm -f .sf/auto.lock
|
||
rm -rf "$(dirname .sf)/.sf.lock"
|
||
```
|
||
|
||
### Git merge 冲突
|
||
|
||
**症状:** Worktree merge 在 `.sf/` 文件上失败。
|
||
|
||
**解决:** SF 会自动解决 `.sf/` 运行时文件上的冲突。对于代码文件的内容冲突,LLM 会先获得一次 fix-merge 会话进行自动修复;若失败,则需要手动解决。
|
||
|
||
### Pre-dispatch 提示 milestone integration branch 已不存在
|
||
|
||
**症状:** 自动模式或 `/sf doctor` 报告某个 milestone 记录的 integration branch 已经不在 git 中。
|
||
|
||
**这意味着什么:** 该 milestone 的 `.sf/milestones/<MID>/<MID>-META.json` 里仍然记录着启动时的 branch,但该 branch 之后被重命名或删除了。
|
||
|
||
**当前行为:**
|
||
|
||
- 如果 SF 能确定性地恢复到一个安全 branch,就不会再直接 hard-stop 自动模式
|
||
- 安全回退的顺序是:
|
||
- 显式配置且存在的 `git.main_branch`
|
||
- 仓库自动检测到的默认 integration branch(例如 `main` 或 `master`)
|
||
- 在这种情况下,`/sf doctor` 会给出 warning,而 `/sf doctor fix` 会把过期的 metadata 改写为当前有效 branch
|
||
- 如果无法确定安全回退 branch,SF 仍会阻止继续运行
|
||
|
||
**解决:**
|
||
|
||
- 先执行 `/sf doctor fix`,在安全回退很明显时自动改写过期 metadata
|
||
- 如果 SF 仍然阻塞,则请重新创建缺失 branch,或更新 git 偏好设置,让 `git.main_branch` 指向一个真实存在的 branch
|
||
|
||
### 写 `.sf/` 文件时出现瞬时 `EBUSY` / `EPERM` / `EACCES`
|
||
|
||
**症状:** 在 Windows 上,自动模式或 doctor 在更新 `.sf/` 文件时偶发 `EBUSY`、`EPERM` 或 `EACCES`。
|
||
|
||
**原因:** 杀毒软件、索引器、编辑器或文件监视器可能会在 SF 执行原子 rename 的瞬间,短暂锁住目标文件或临时文件。
|
||
|
||
**当前行为:** SF 现在会对这类瞬时 rename 失败做短时、有上界的退避重试;这样既能覆盖短暂锁竞争,也不会因为真正的文件系统问题而无限挂起。
|
||
|
||
**解决:**
|
||
|
||
- 重新执行操作;大多数瞬时锁竞争会很快自行解除
|
||
- 如果错误持续,关闭可能占用该文件的工具后再试
|
||
- 如果反复失败,运行 `/sf doctor`,确认仓库状态依旧健康,并记录具体路径与错误码
|
||
|
||
### Node v24 Web 启动失败
|
||
|
||
**症状:** 在 Node v24 上执行 `sf --web` 时,报 `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`。
|
||
|
||
**原因:** Node v24 修改了对 `node_modules` 的 type stripping 行为,导致 Next.js Web 构建失败。
|
||
|
||
**解决:** 已在 v2.42.0+ 修复(#1864)。升级到最新版本。
|
||
|
||
### 孤儿 Web server 进程
|
||
|
||
**症状:** `sf --web` 因端口 3000 已被占用而失败,但实际上并没有运行中的 SF 会话。
|
||
|
||
**原因:** 上一次 Web server 退出时未能清理进程。
|
||
|
||
**解决:** 已在 v2.42.0+ 修复。现在 SF 会自动清理过期的 Web server 进程。如果你还在旧版本,可手动终止孤儿进程:`lsof -ti:3000 | xargs kill`。
|
||
|
||
### 非 JS 项目被 worktree health check 阻挡
|
||
|
||
**症状:** 在不使用 Node.js 的项目(例如 Rust、Go、Python)中,worktree health check 失败或阻塞自动模式。
|
||
|
||
**原因:** 在 v2.42.0 之前,worktree health check 只识别 JavaScript 生态。
|
||
|
||
**解决:** 已在 v2.42.0+ 修复(#1860)。现在 health check 已支持 17+ 生态。升级到最新版本。
|
||
|
||
### 德语 / 非英语 locale 下的 git 错误
|
||
|
||
**症状:** 当系统 locale 不是英语(例如德语)时,Git 命令失败或输出异常。
|
||
|
||
**原因:** SF 之前假设 git 输出永远是英文。
|
||
|
||
**解决:** 已在 v2.42.0+ 修复。现在所有 git 命令都会强制 `LC_ALL=C`,从而无论系统 locale 如何,都保证 git 输出一致为英文。
|
||
|
||
## MCP Client 问题
|
||
|
||
### `mcp_servers` 显示没有已配置 servers
|
||
|
||
**症状:** `mcp_servers` 报告没有配置任何 server。
|
||
|
||
**常见原因:**
|
||
|
||
- 当前项目里不存在 `.mcp.json` 或 `.sf/mcp.json`
|
||
- 配置文件不是合法 JSON
|
||
- 你是在另一个项目目录中配置的 server,但当前启动 SF 的目录不同
|
||
|
||
**解决:**
|
||
|
||
- 把 server 配置加到 `.mcp.json` 或 `.sf/mcp.json`
|
||
- 确认文件能被正常解析为 JSON
|
||
- 重新执行 `mcp_servers(refresh=true)`
|
||
|
||
### `mcp_discover` 超时
|
||
|
||
**症状:** `mcp_discover` 因超时失败。
|
||
|
||
**常见原因:**
|
||
|
||
- Server 进程启动了,但没有完成 MCP 握手
|
||
- 配置的命令指向一个启动时会卡住的脚本
|
||
- Server 正在等待某个不可用依赖或后端服务
|
||
|
||
**解决:**
|
||
|
||
- 在 SF 外部直接运行该命令,确认 server 能真正启动
|
||
- 检查后端 URL 或依赖服务是否可达
|
||
- 如果是本地自定义 server,确认它使用的是 MCP SDK 或正确的 stdio 协议实现
|
||
|
||
### `mcp_discover` 报 connection closed
|
||
|
||
**症状:** `mcp_discover` 立即失败,并提示连接被关闭。
|
||
|
||
**常见原因:**
|
||
|
||
- 可执行文件路径错误
|
||
- 脚本路径错误
|
||
- 缺失运行时依赖
|
||
- Server 在响应前就崩溃了
|
||
|
||
**解决:**
|
||
|
||
- 确认 `command` 和 `args` 路径正确且尽量使用绝对路径
|
||
- 手动运行命令,查看导入 / 运行时错误
|
||
- 检查配置中的解释器或运行时在当前机器上是否存在
|
||
|
||
### `mcp_call` 因缺少必填参数失败
|
||
|
||
**症状:** MCP tool 已成功发现,但调用时因缺少必填字段而校验失败。
|
||
|
||
**常见原因:**
|
||
|
||
- 调用形状写错了
|
||
- 目标 server 的 tool schema 已更新
|
||
- 你调用的是旧 server 定义或旧分支构建
|
||
|
||
**解决:**
|
||
|
||
- 重新执行 `mcp_discover(server="name")`,确认实际要求的参数名
|
||
- 按 `mcp_call(server="name", tool="tool_name", args={...})` 的形式调用
|
||
- 如果你正在开发 SF 本身,在 schema 变更后重新执行 `npm run build`
|
||
|
||
### 本地 stdio server 手动可用,但在 SF 中不可用
|
||
|
||
**症状:** 手动执行 server 命令没有问题,但 SF 连接不上。
|
||
|
||
**常见原因:**
|
||
|
||
- Server 依赖某些 SF 不会继承的 shell 状态
|
||
- 相对路径只有在另一个 working directory 中才成立
|
||
- 需要的环境变量存在于你的 shell 中,但没有写进 MCP 配置
|
||
|
||
**解决:**
|
||
|
||
- 对 `command` 和脚本参数都使用绝对路径
|
||
- 把所需环境变量写进 MCP 配置的 `env` 块
|
||
- 有必要时,在 server 定义里显式设置 `cwd`
|
||
|
||
### Session lock 被另一个终端中的 `/sf` 抢走
|
||
|
||
**症状:** 在第二个终端运行 `/sf`(step mode)时,正在运行的自动模式会话失去了锁。
|
||
|
||
**解决:** 已在 v2.36.0 修复。现在裸 `/sf` 不会再从运行中的自动模式会话手里抢 session lock。升级到最新版本。
|
||
|
||
### Worktree 中的提交落到了 main,而不是 `milestone/<MID>` 分支
|
||
|
||
**症状:** 自动模式在 worktree 中提交时,最终落在了 `main`,而不是 `milestone/<MID>`。
|
||
|
||
**解决:** 已在 v2.37.1 修复。现在 dispatch 前会重新校正 CWD,并在失败时清理过期 merge 状态。升级到最新版本。
|
||
|
||
### Extension loader 因 subpath export 错误而失败
|
||
|
||
**症状:** 扩展加载时报 `Cannot find module`,并且错误信息引用了 npm subpath exports。
|
||
|
||
**原因:** Extension loader 中的动态导入过去无法解析 npm subpath exports(例如 `@pkg/foo/bar`)。
|
||
|
||
**解决:** 已在 v2.38+ 修复。现在 extension loader 会自动解析 npm subpath exports,并为动态导入创建 `node_modules` symlink。升级到最新版本。
|
||
|
||
## 恢复流程
|
||
|
||
### 重置自动模式状态
|
||
|
||
```bash
|
||
rm .sf/auto.lock
|
||
rm .sf/completed-units.json
|
||
```
|
||
|
||
然后执行 `/sf autonomous`,从当前磁盘状态重新开始。
|
||
|
||
### 重置路由历史
|
||
|
||
如果自适应模型路由给出了糟糕的结果,可以清空路由历史:
|
||
|
||
```bash
|
||
rm .sf/routing-history.json
|
||
```
|
||
|
||
### 完整重建状态
|
||
|
||
```
|
||
/sf doctor
|
||
```
|
||
|
||
Doctor 会从磁盘上的 plan 和 roadmap 文件重建 `STATE.md`,并修复检测到的不一致项。
|
||
|
||
## 获取帮助
|
||
|
||
- **GitHub Issues:** [github.com/singularity-ng/singularity-forge/issues](https://github.com/singularity-ng/singularity-forge/issues)
|
||
- **Dashboard:** `Ctrl+Alt+G` 或 `/sf status`,查看实时诊断信息
|
||
- **Forensics:** `/sf forensics`,用于对自动模式失败做结构化事后分析
|
||
- **Session logs:** `.sf/activity/` 中包含用于崩溃取证的 JSONL 会话转储
|
||
|
||
## iTerm2 专属问题
|
||
|
||
### Ctrl+Alt 快捷键触发了错误动作(例如 Ctrl+Alt+G 打开了外部编辑器,而不是 SF dashboard)
|
||
|
||
**症状:** 按下 Ctrl+Alt+G 后,会触发外部编辑器提示(Ctrl+G),而不是 SF dashboard。其它 Ctrl+Alt 快捷键也表现得像它们对应的 Ctrl-only 快捷键。
|
||
|
||
**原因:** iTerm2 默认的 Left Option Key 设置是 “Normal”,这会吞掉 Ctrl+Alt 组合中的 Alt 修饰键。终端实际只收到了 Ctrl,所以 Ctrl+Alt+G 最终变成 Ctrl+G。
|
||
|
||
**解决:** 在 iTerm2 中进入 **Profiles → Keys → General**,把 **Left Option Key** 改成 **Esc+**。这样 Alt / Option 会发送 escape 前缀,终端应用就能正确识别 Ctrl+Alt 快捷键。
|
||
|
||
## Windows 专属问题
|
||
|
||
### Windows 上 LSP 返回 ENOENT(MSYS2 / Git Bash)
|
||
|
||
**症状:** LSP 初始化因 `ENOENT` 失败,或者把 `/c/Users/...` 这类 POSIX 路径错误地解析为 `C:\Users\...`。
|
||
|
||
**原因:** MSYS2 / Git Bash 中的 `which` 命令返回的是 POSIX 风格路径,而 Node.js 的 `spawn()` 无法正确解析。
|
||
|
||
**解决:** 已在 v2.29+ 修复,Windows 现在改用 `where.exe`。升级到最新版本。
|
||
|
||
### 构建 WXT / 浏览器扩展时出现 EBUSY
|
||
|
||
**症状:** 构建浏览器扩展时出现 `EBUSY: resource busy or locked, rmdir .output/chrome-mv3`。
|
||
|
||
**原因:** Chromium 浏览器仍然从构建输出目录加载着该扩展,导致目录无法删除。
|
||
|
||
**解决:** 关闭浏览器中的该扩展,或者在 WXT 配置里使用不同的 `outDirTemplate`,避开被锁住的目录。
|
||
|
||
## 数据库问题
|
||
|
||
### “SF database is not available”
|
||
|
||
**症状:** `sf_decision_save`、`sf_requirement_update` 或 `sf_summary_save` 报这个错误。
|
||
|
||
**原因:** SQLite 数据库未初始化。这个问题会出现在 v2.29 之前的手动 `/sf` 会话(非自动模式)中。
|
||
|
||
**解决:** 已在 v2.29+ 修复。现在数据库会在第一次 tool call 时自动初始化。升级到最新版本。
|
||
|
||
## Verification 问题
|
||
|
||
### Verification gate 因 shell 语法错误失败
|
||
|
||
**症状:** 在 verification 阶段出现 `stderr: /bin/sh: 1: Syntax error: "(" unexpected`。
|
||
|
||
**原因:** 某个描述性字符串(例如 `All 10 checks pass (build, lint)`)被误当成 shell 命令执行。这通常发生在 task plans 的 `verify:` 字段里写了 prose,而不是实际命令。
|
||
|
||
**解决:** 已在 v2.29+ 修复,现在偏好命令会先通过 `isLikelyCommand()` 过滤。请确保偏好中的 `verification_commands` 只包含合法 shell 命令,而不是文字描述。
|
||
|
||
## LSP(Language Server Protocol)
|
||
|
||
### “LSP isn't available in this workspace”
|
||
|
||
SF 会根据项目文件自动检测 language servers(例如 `package.json` → TypeScript、`Cargo.toml` → Rust、`go.mod` → Go)。如果没有检测到 server,agent 会跳过 LSP 功能。
|
||
|
||
**查看状态:**
|
||
|
||
```
|
||
lsp status
|
||
```
|
||
|
||
它会显示哪些 servers 已经激活;如果一个都没找到,也会说明原因,包括发现了哪些项目标记、但缺失了哪些 server 命令。
|
||
|
||
**常见修复方式:**
|
||
|
||
| 项目类型 | 安装命令 |
|
||
|----------|----------|
|
||
| TypeScript / JavaScript | `npm install -g typescript-language-server typescript` |
|
||
| Python | `pip install pyright` 或 `pip install python-lsp-server` |
|
||
| Rust | `rustup component add rust-analyzer` |
|
||
| Go | `go install golang.org/x/tools/gopls@latest` |
|
||
|
||
安装完成后,执行 `lsp reload` 即可重新检测,无需重启 SF。
|
||
|
||
## Notifications
|
||
|
||
<a id="notifications-not-appearing-on-macos"></a>
|
||
### macOS 上通知不显示
|
||
|
||
**症状:** 偏好中已设置 `notifications.enabled: true`,但自动模式期间没有任何桌面通知(没有 milestone 完成提示、预算预警或错误通知),同时日志里也没有报错。
|
||
|
||
**原因:** SF 在 macOS 上会把 `osascript display notification` 作为回退方案。这个命令的通知归属你的终端应用(Ghostty、iTerm2、Alacritty、Kitty、Warp 等)。如果该终端应用在 System Settings → Notifications 中没有权限,macOS 会静默丢弃通知,而 `osascript` 仍然返回 0,不会报错。
|
||
|
||
很多终端应用只有在成功送出过至少一条通知后,才会出现在通知设置面板里,这就形成了“先能通知,系统才给你配置通知”的鸡生蛋蛋生鸡问题。
|
||
|
||
**推荐修复方式:** 安装 `terminal-notifier`,它会注册为独立的 Notification Center 应用:
|
||
|
||
```bash
|
||
brew install terminal-notifier
|
||
```
|
||
|
||
SF 在检测到 `terminal-notifier` 可用时会自动优先使用它。首次使用时,macOS 会弹出通知权限请求,这是预期行为。
|
||
|
||
**替代修复方式:** 进入 **System Settings → Notifications**,为你的终端应用启用通知。如果终端应用不在列表中,可以先在 Terminal.app 中手动发送一条测试通知,注册出 “Script Editor”:
|
||
|
||
```bash
|
||
osascript -e 'display notification "test" with title "SF"'
|
||
```
|
||
|
||
**验证:** 完成任一修复后,用下面命令测试:
|
||
|
||
```bash
|
||
terminal-notifier -title "SF" -message "working!" -sound Glass
|
||
```
|