| 1 | # Codewhale 架构 |
| 2 | |
| 3 | > 英文原文:[ARCHITECTURE.md](../ARCHITECTURE.md)。 |
| 4 | > 最后与英文同步日期(last synced with English revision):2026-09-29。 |
| 5 | |
| 6 | 本文面向开发者和贡献者,概览 Codewhale 的架构。 |
| 7 | |
| 8 | 当前边界说明(工作区版本以 `Cargo.toml` 为准;该边界自 v0.9.1 起保持不变): |
| 9 | - `crates/tui` 仍是 TUI、运行时 API、任务管理器和工具执行循环的现行终端用户运行时。 |
| 10 | - 其他工作区 crate 正在逐步拆出,但它们还不是唯一的权威运行时。 |
| 11 | - 运行时正按照 `docs/design/TUI_DECONSTRUCTION.md` 记录的顺序迁往 `crates/runtime` |
| 12 | (`codewhale-runtime`):引擎、工具、配置、客户端与各存储一起迁移,绝不迁进 |
| 13 | `crates/core`,而 TUI 始终是唯一写终端的 crate。在某个模块迁走之前, |
| 14 | 它仍位于 `crates/tui/src` 下的原路径。 |
| 15 | - LSP 子系统(`crates/tui/src/lsp/`)已完整接入引擎的工具执行后路径 |
| 16 | (`core/engine/lsp_hooks.rs`),在 `File` 写入、编辑和补丁动作之后提供内联诊断。 |
| 17 | - swarm 智能体(agent)系统已在 v0.8.5 移除。当前生效的子智能体(sub-agent)接口面 |
| 18 | 是单一的 `agent` 工具;持久化 RLM 会话可通过延迟加载的 `rlm` 动作族使用。 |
| 19 | 现行代码库中不再保留任何模型可见的 swarm 工具。 |
| 20 | |
| 21 | ## 高层概览 |
| 22 | |
| 23 | ``` |
| 24 | ┌─────────────────────────────────────────────────────────────────┐ |
| 25 | │ User Interface │ |
| 26 | │ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────┐ │ |
| 27 | │ │ TUI (ratatui) │ │ One-shot Mode │ │ Config/CLI │ │ |
| 28 | │ └────────┬────────┘ └────────┬────────┘ └────────┬───────┘ │ |
| 29 | └───────────┼─────────────────────┼────────────────────┼──────────┘ |
| 30 | │ │ │ |
| 31 | ▼ ▼ ▼ |
| 32 | ┌─────────────────────────────────────────────────────────────────┐ |
| 33 | │ Core Engine │ |
| 34 | │ ┌─────────────────────────────────────────────────────────┐ │ |
| 35 | │ │ Agent Loop (core/engine.rs) │ │ |
| 36 | │ │ ┌─────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │ |
| 37 | │ │ │ Session │ │ Turn Mgmt │ │ Tool Orchestration │ │ │ |
| 38 | │ │ └─────────┘ └─────────────┘ └──────────────────────┘ │ │ |
| 39 | │ └─────────────────────────────────────────────────────────┘ │ |
| 40 | └─────────────────────────────────────────────────────────────────┘ |
| 41 | │ │ │ |
| 42 | ▼ ▼ ▼ |
| 43 | ┌─────────────────────────────────────────────────────────────────┐ |
| 44 | │ Tool & Extension Layer │ |
| 45 | │ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌────────────────┐ │ |
| 46 | │ │ Tools │ │ Skills │ │ Hooks │ │ MCP Servers │ │ |
| 47 | │ │ (shell, │ │ (plugins)│ │ (pre/ │ │ (external) │ │ |
| 48 | │ │ file) │ │ │ │ post) │ │ │ │ |
| 49 | │ └──────────┘ └──────────┘ └─────────┘ └────────────────┘ │ |
| 50 | └─────────────────────────────────────────────────────────────────┘ |
| 51 | │ │ │ |
| 52 | ▼ ▼ ▼ |
| 53 | ┌─────────────────────────────────────────────────────────────────┐ |
| 54 | │ Runtime API + Task Management │ |
| 55 | │ ┌─────────────────────────────┐ ┌──────────────────────────┐ │ |
| 56 | │ │ HTTP/SSE Runtime API │ │ Persistent Task Manager │ │ |
| 57 | │ │ (runtime_api.rs) │ │ (task_manager.rs) │ │ |
| 58 | │ └─────────────────────────────┘ └──────────────────────────┘ │ |
| 59 | └─────────────────────────────────────────────────────────────────┘ |
| 60 | │ │ |
| 61 | ▼ ▼ |
| 62 | ┌─────────────────────────────────────────────────────────────────┐ |
| 63 | │ LLM Layer │ |
| 64 | │ ┌──────────────────────────────────────────────────────────┐ │ |
| 65 | │ │ LLM Client Layer (client.rs) │ │ |
| 66 | │ │ ┌──────────────────┐ ┌─────────────────────────────┐ │ │ |
| 67 | │ │ │ OpenAI-compatible │ │ Anthropic / Responses │ │ │ |
| 68 | │ │ │ (chat adapter) │ │ (adapters) │ │ │ |
| 69 | │ │ └──────────────────┘ └─────────────────────────────┘ │ │ |
| 70 | │ └──────────────────────────────────────────────────────────┘ │ |
| 71 | └─────────────────────────────────────────────────────────────────┘ |
| 72 | ``` |
| 73 | |
| 74 | ## 模块组织 |
| 75 | |
| 76 | ### 入口点 |
| 77 | |
| 78 | - **`crates/cli/src/main.rs`** - 唯一可执行程序的入口。`crates/cli/src/lib.rs` 拥有命令接口;终端和无头运行时通过 `crates/tui/src/lib.rs` 中的 `codewhale_tui` 库在同一进程内启动。 |
| 79 | |
| 80 | ### 核心组件 |
| 81 | |
| 82 | - **`core/`** - 主要引擎组件 |
| 83 | - `engine.rs` - 引擎状态、操作处理、消息处理 |
| 84 | - `engine/turn_loop.rs` - 流式回合循环与工具执行编排 |
| 85 | - `session.rs` - 会话状态管理 |
| 86 | - `turn.rs` - 基于回合的对话处理 |
| 87 | - `events.rs` - 用于 UI 更新的事件系统 |
| 88 | - `ops.rs` - 核心操作 |
| 89 | |
| 90 | ### 配置 |
| 91 | |
| 92 | - **`config.rs`** - 配置加载、profile、环境变量 |
| 93 | - **`settings.rs`** - 运行时设置管理 |
| 94 | |
| 95 | ### 工作区 crate |
| 96 | |
| 97 | - **`crates/cli`** - 唯一的 `codewhale` 可执行程序及命令接口。它自身拥有 |
| 98 | `auth`、`metrics`、`update` 等命令,并通过 `codewhale_tui::run(RuntimeOptions, args)` |
| 99 | 在同一进程内启动终端和无头模式(`run`、`exec`、`doctor`、`sessions`……)。 |
| 100 | `crates/tui` 是库;`codew` 和旧发布文件名的别名包含相同的可执行程序。 |
| 101 | - **`crates/tools`** - 共享的工具调用原语,包括 TUI 运行时使用的工具结果/错误/能力类型。 |
| 102 | - **`crates/agent`** - 模型/提供商(provider)注册表(ModelRegistry),用于把模型 ID |
| 103 | 解析到提供商端点。 |
| 104 | - **`crates/app-server`** - 用于无头智能体工作流的 HTTP/SSE + JSON-RPC 应用服务器 |
| 105 | 传输层。唯一的可执行程序将 `app-server --http`/`--mobile` 在同一进程内 |
| 106 | 路由到由 `codewhale_tui` 库承载的运行时 API。 |
| 107 | - **`crates/config`** - 配置加载、profile、环境变量优先级、CLI 运行时覆盖。 |
| 108 | - **`crates/cloud-facts`** - 拉取已签名的 Codewhale 云端事实信道(`facts/v1`), |
| 109 | 校验其 Ed25519 信封,并维护一份已验证的磁盘缓存;从不是启动依赖。 |
| 110 | - **`crates/command-contract`** - 为分阶段抽离 TUI 命令而设的命令能力与分发形态 |
| 111 | 原型;仅是形态,还不是生产分发路径。 |
| 112 | - **`crates/core`** - 提供商中立的请求构造(`request.rs`)、有界上下文片段、 |
| 113 | 工具调用解析器,以及线程/会话类型。它**不**拥有智能体循环:现行回合循环是 |
| 114 | `crates/tui/src/core/engine/turn_loop.rs` 里的 `Engine::run_turn`,而 |
| 115 | `crates/tui/src/core/` 是 TUI crate 内部的模块,不是这个 crate 的。这里曾有一棵 |
| 116 | 占位的 `engine/` 目录树让人误解——它没有任何调用方,还会在不接触模型的情况下 |
| 117 | 发出 `TurnComplete`——已在 v0.9.11 移除。 |
| 118 | 递归 RLM 和普通 Python RPC 现在使用同一个 Engine 生产者与 Session;RLM |
| 119 | 不再有独立循环。Python 保存上下文与变量,每轮只借用调用方已捕获的路由、 |
| 120 | Native 选择、原有代码审批、取消信号和截止时间。任务指导有界且追加到 Core |
| 121 | 策略;递归历史完整保留,超过预算时拒绝而不压缩。持久 `rlm` 上下文只属于 |
| 122 | 调用方会话,`share_session=true` 明确拒绝。子智能体也以已捕获的准入事实 |
| 123 | 使用同一个 Engine;两种嵌套宿主都不再保留独立循环例外。 |
| 124 | - **`crates/execpolicy`** - 用于工具执行决策的审批(approval)/沙箱(sandbox)策略引擎。 |
| 125 | - **`crates/hooks`** - 响应、工具、作业和审批生命周期事件的事件接收端(sink:stdout、 |
| 126 | JSONL 文件、webhook、Unix socket),外加可选启用的 lifecycle outbox。 |
| 127 | 用户在工具调用前后运行命令的自定义 shell 钩子(hook)是 `crates/tui/src/hooks.rs` |
| 128 | 里的另一套系统。 |
| 129 | - **`crates/localization`** - 面向用户的 UI 界面字符串的语言环境注册表 |
| 130 | (`crates/localization/locales/*.json`);它从不改变提示词(prompt)或模型 |
| 131 | 输出语言。 |
| 132 | - **`crates/mcp`** - 用于 Model Context Protocol 工具服务器的 MCP 客户端 + stdio 服务器。 |
| 133 | - **`crates/memory`** - 本地、带作用域、带来源信息的记忆(memory)与可恢复状态 |
| 134 | (是一个库,不是第二个智能体循环)。 |
| 135 | - **`crates/models`** - 提供商的请求/响应模型,以及离线模型元数据目录。 |
| 136 | - **`crates/palette`** - 终端 UI 的颜色 token、主题和对比度计算。它的 `ratatui` |
| 137 | feature(默认开启)门控所有渲染相关代码;主题 id、设置规范化和十六进制解析 |
| 138 | 在不开该 feature 时也能编译,运行时就是这样链接它的。 |
| 139 | - **`crates/paths`** - 用户作用域的运行时路径权威(`CODEWHALE_HOME` 与平台 home 解析)。 |
| 140 | - **`crates/protocol`** - 请求/响应分帧与协议类型。 |
| 141 | - **`crates/runtime`** - `codewhale-runtime`,正在从 `crates/tui` 拆出的无头运行时 |
| 142 | (`docs/design/TUI_DECONSTRUCTION.md`)。目前它承载最先迁走的叶子模块(重试状态、 |
| 143 | 安全标签、休眠守卫、会话树……)以及 `host_terminal`——运行时代码通过这唯一的 |
| 144 | 端口向终端 UI 索取终端效果。它从不依赖 TUI、`ratatui` 或 `crossterm`; |
| 145 | `scripts/check-command-crate-boundaries.py` 强制这一点,并对 `crates/tui` 中 |
| 146 | 残留的 runtime -> UI 引用做棘轮式收敛。 |
| 147 | - **`crates/secrets`** - API key 存储用的 OS 密钥环集成,外加 UI 与运行时代码共用的 |
| 148 | 输出净化器(`sanitize`)和脱敏(`redact`)。 |
| 149 | - **`crates/state`** - SQLite 线程/会话持久化层。 |
| 150 | - **`crates/telemetry`** - 匿名、用户可关闭的聚合使用计数;唯一被允许构建或发送 |
| 151 | 遥测载荷的 crate(`docs/TELEMETRY.md`)。 |
| 152 | - **`crates/workflow`** / **`crates/workflow-js`** - 工作流(workflow)引擎及其 |
| 153 | QuickJS 脚本层(由 whaleflow 系列 crate 更名而来)。 |
| 154 | - **`crates/lane`** - Lane 运行时:Fleet/Workflow 工作的持久化、可挂接运行实例 |
| 155 | (`codewhale lane list/status/attach/logs/stop`)。 |
| 156 | - **`crates/release`** / **`crates/build-support`** - 发布检查与构建链路。 |
| 157 | |
| 158 | ### LLM 集成 |
| 159 | |
| 160 | - **`client.rs`** - 现行 HTTP 客户端层:OpenAI 兼容、Anthropic 和 Responses |
| 161 | 线格式适配器、DeepSeek 请求边界处理、重试策略和流式传输。提供商路由经共享的 |
| 162 | 配置与目录层落到这里。 |
| 163 | - **`llm_client/`** - LLM 客户端 trait、重试逻辑和错误分类(`LlmClient`、 |
| 164 | `RetryConfig`、`with_retry`),由 `client.rs` 使用;`mock.rs` 仅用于测试 |
| 165 | (`#[cfg(test)]`)。 |
| 166 | - **`crates/models`**(`codewhale_models`)- API 请求/响应的数据结构; |
| 167 | TUI crate 没有本地的 `models.rs`。 |
| 168 | |
| 169 | #### DeepSeek API 端点 |
| 170 | |
| 171 | DeepSeek 暴露 OpenAI 兼容端点。第一方路由使用: |
| 172 | - `https://api.deepseek.com/beta` - 默认的 DeepSeek base URL(`provider_defaults.rs`) |
| 173 | - `https://api.deepseek.com/beta/models` - 实时模型发现与健康检查 |
| 174 | |
| 175 | 为了兼容 OpenAI SDK,也接受 `https://api.deepseek.com/v1`,并且仍可显式配置它, |
| 176 | 以退出仅有 beta 提供的功能,例如严格工具模式、聊天前缀补全和 FIM 补全。 |
| 177 | DeepSeek 的公开文档并未记录这条工作流可用的 Responses API 路径;引擎通过 |
| 178 | Chat Completions 驱动回合。 |
| 179 | |
| 180 | ### 工具系统 |
| 181 | |
| 182 | - **`tools/`** - 内置工具实现 |
| 183 | - `mod.rs` - 工具注册表与通用类型 |
| 184 | - `shell.rs` - shell 命令执行 |
| 185 | - `file.rs` - 文件读写操作 |
| 186 | - `todo.rs` - 清单工具以及遗留的 todo 别名 |
| 187 | - `tasks.rs` - 模型可见的持久化任务、门禁、后台 shell 和 PR 尝试工具 |
| 188 | - `git.rs` - 只读的 `git_status` / `git_diff` 检查包装 |
| 189 | - `git_tool.rs` - 规范化的基于动作的 `Git` 工具(`status | diff | log | show | blame`);按动作划分的遗留别名已在 v0.9.3 移除 |
| 190 | - `git_history.rs` - 只读的 `git_log` / `git_show` / `git_blame` |
| 191 | - `github/` - 统一的 `github` 工具族(只读上下文,加上由 `gh` 支撑的受控 |
| 192 | 评论/关闭动作);默认延迟加载,可通过 `tool_search` 发现 |
| 193 | - `automation.rs` - 基于 `AutomationManager` 的模型可见调度工具 |
| 194 | - `plan.rs` - 规划工具 |
| 195 | - `subagent/` - 子智能体启动与监督。`agent` 是唯一的创建接口面; |
| 196 | `subagent/coord.rs` 在既有管理器之上补上一组窄口径协调工具(`agents/list`、 |
| 197 | `agents/message`、`agents/followup`、`agents/interrupt`、`agents/wait`、 |
| 198 | `agents/coordinate`)。`agent_open`/`agent_eval`/`agent_close` 生命周期接口面 |
| 199 | 已退役(见 `subagent/coord.rs` 模块文档) |
| 200 | - `spec.rs` - 工具规格 |
| 201 | - `rlm.rs` - 持久化的递归语言模型(RLM)会话——持久的本地 Python REPL 子进程 |
| 202 | (清理过环境变量,但没有操作系统级沙箱),支持语义化辅助调用和 `var_handle` 输出 |
| 203 | |
| 204 | ### 扩展系统 |
| 205 | |
| 206 | - **`mcp.rs`** - 面向外部工具服务器的 Model Context Protocol 客户端 |
| 207 | - **`skills/`** - 针对本地 `SKILL.md` 文件的技能(skill)发现与注册表,外加安装与审计 |
| 208 | - **`hooks.rs`** - 带条件的执行前/后钩子 |
| 209 | |
| 210 | ### 用户界面 |
| 211 | |
| 212 | - **`tui/`** - 终端 UI 组件(基于 ratatui;这是代表性列表,并非穷尽——该模块 |
| 213 | 已增长到 80 多个专一职责的文件): |
| 214 | - `app.rs` - 应用状态与消息处理 |
| 215 | - `ui.rs` - 事件处理、流式状态与渲染逻辑 |
| 216 | - `approval.rs` - 工具审批对话框 |
| 217 | - `clipboard.rs` - 剪贴板处理 |
| 218 | - `underwater.rs` - 主 shell 界面:状态标签(chip)、模式标签、阶段导轨 |
| 219 | |
| 220 | ### LSP 集成 |
| 221 | |
| 222 | - **`lsp/`** - 编辑后诊断注入(#136) |
| 223 | - `mod.rs` - `LspManager` ——按语言惰性创建的传输池 + 配置 |
| 224 | - `client.rs` - `StdioLspTransport` ——基于 stdio 的 JSON-RPC,支持 `didOpen`/`didChange`/`publishDiagnostics` |
| 225 | - `diagnostics.rs` - 诊断类型、严重级别和 HTML 块渲染器 |
| 226 | - `registry.rs` - 语言检测与默认服务器映射:`rust-analyzer`、 |
| 227 | `gopls`、`pyright-langserver`、`typescript-language-server`、`jdtls`、 |
| 228 | `intelephense`(PHP)、`vue-language-server`、`clangd`(`lsp/registry.rs:98-110`) |
| 229 | - 通过 `core/engine/lsp_hooks.rs` 接入引擎——每次成功编辑后调用 |
| 230 | |
| 231 | ### 安全 |
| 232 | |
| 233 | - **`sandbox/`** - 平台沙箱策略准备与拒绝上报 |
| 234 | - `mod.rs` - 沙箱类型定义 |
| 235 | - `backend.rs` - 可插拔的沙箱后端抽象(把 shell 执行路由到远程服务, |
| 236 | 例如 Alibaba OpenSandbox) |
| 237 | - `policy.rs` - 沙箱策略配置 |
| 238 | - `opensandbox.rs` - Alibaba OpenSandbox HTTP 后端适配器 |
| 239 | - `seatbelt.rs` - macOS Seatbelt 配置生成 |
| 240 | - `bwrap.rs` - 可选启用的 Linux bubblewrap 命令包装器 |
| 241 | - `seccomp.rs` - 休眠中的 Linux seccomp 实现;未接入命令执行 |
| 242 | - `process_hardening.rs` - 针对 TUI 进程自身的 Linux 内核级加固 |
| 243 | (纵深防御;不是子命令沙箱) |
| 244 | - `windows.rs` - Windows 辅助程序契约;在存在 Job Object 进程围栏辅助程序 |
| 245 | 之前不予宣称 |
| 246 | |
| 247 | ### 实用工具 |
| 248 | |
| 249 | - **`utils.rs`** - 通用工具 |
| 250 | - **`logging.rs`** - 日志基础设施 |
| 251 | - **`compaction.rs`** - 长对话的上下文压缩 |
| 252 | - **`purge.rs`** - 智能体驱动的上下文清除(精确移除/改写个别消息) |
| 253 | - **`pricing.rs`** - 成本估算 |
| 254 | - **`prompts.rs`** - 系统提示词模板 |
| 255 | - **`runtime_api.rs`** - HTTP/SSE 运行时 API(`codewhale serve --http`) |
| 256 | - **`runtime_threads.rs`** - 持久化线程/回合/条目存储 + 可回放的事件时间线 |
| 257 | - **`task_manager.rs`** - 持久化队列、worker 池、任务时间线和产物(artifact) |
| 258 | |
| 259 | ## 数据流 |
| 260 | |
| 261 | ### 交互式会话 |
| 262 | |
| 263 | 1. TUI 接收用户输入 |
| 264 | 2. 输入由 `core/engine.rs` 处理 |
| 265 | 3. 消息通过 `client.rs` 发送给 LLM |
| 266 | 4. 响应流式返回,在 `client.rs` 中解析 |
| 267 | 5. 提取工具调用并通过 `tools/` 执行 |
| 268 | 6. 工具执行前后触发钩子 |
| 269 | 7. 结果聚合后送回 LLM |
| 270 | 8. 最终响应在 TUI 中渲染 |
| 271 | |
| 272 | ### 崩溃恢复 + 离线队列 |
| 273 | |
| 274 | 1. 发送用户输入之前,TUI 会把检查点(checkpoint)快照写入 `~/.codewhale/sessions/checkpoints/latest.json` |
| 275 | 2. 启动默认从新会话开始;此前的会话通过 `--resume`/`--continue`(或 TUI 里的 `Ctrl+R`)显式恢复 |
| 276 | 3. 降级/离线期间,新的提示词在内存中排队,并镜像到 `~/.codewhale/sessions/checkpoints/offline_queue.json` |
| 277 | 4. 队列编辑(`/queue ...`)持续持久化,草稿和已排队的提示词可跨重启保留 |
| 278 | 5. 回合成功完成后清除当前检查点,并写入一份持久会话快照 |
| 279 | 6. 具备动作能力的回合还会在 `~/.codewhale/snapshots/<project_hash>/<worktree_hash>/.git` 下生成回合前/后的 side-git 工作区快照;`/restore N` 和 `revert_turn` 恢复文件状态,但不改动对话历史或用户的 `.git` |
| 280 | |
| 281 | ### 工具执行 |
| 282 | |
| 283 | 1. LLM 通过 `tool_use` 内容块请求工具 |
| 284 | 2. 工具注册表查找处理器 |
| 285 | 3. 执行前钩子运行 |
| 286 | 4. 当生效的权限姿态(posture)与策略要求时,请求审批 |
| 287 | 5. 执行工具(在 macOS 上可能被 Seatbelt 包装,在 Linux 上可能被可选启用的 bubblewrap 包装) |
| 288 | 6. 执行后钩子运行 |
| 289 | 7. 结果元数据保留在运行时条目记录上 |
| 290 | 8. **LSP 编辑后钩子**:在 `File` 的写入、编辑或补丁动作之后(包括仅用于回放的遗留别名),当 LSP 启用时,引擎会运行 `run_post_edit_lsp_hook()` 以收集诊断 |
| 291 | 9. **诊断刷写**:在下一次 API 请求之前,`flush_pending_lsp_diagnostics()` 会把已收集的错误作为一条合成用户消息注入 |
| 292 | 10. 结果返回给智能体循环 |
| 293 | |
| 294 | ### 后台任务 |
| 295 | |
| 296 | 1. 客户端入队任务(`/task add ...` 或 `POST /v1/tasks`) |
| 297 | 2. `task_manager.rs` 在 `~/.codewhale/tasks` 下持久化任务 + 队列条目 |
| 298 | 3. 有界 worker 池中的 worker 领取排队任务,状态转为 `running` |
| 299 | 4. 任务创建/使用一个运行时线程,并启动一个运行时回合 |
| 300 | 5. `runtime_threads.rs` 持久化线程/回合/条目记录 + 单调递增的事件序列 |
| 301 | 6. 时间线/工具摘要/产物引用增量持久化 |
| 302 | 7. 清单状态、验证器门禁、PR 尝试和受控的 GitHub 事件,从工具元数据应用到当前任务 |
| 303 | 8. 最终状态(`completed|failed|canceled`)是持久的,可通过 TUI/API 查询 |
| 304 | |
| 305 | 模型可见的持久化任务工具是同一个管理器之上的一个接口面。它们不引入并行的工作 |
| 306 | 体系:`task_create` 入队普通任务,`checklist_*` 更新任务本地进度,`task_gate_run` |
| 307 | 和已完成的 `task_shell_wait` 附加验证证据,自动化运行也入队普通的持久化任务。 |
| 308 | |
| 309 | ### 运行时线程/回合时间线 |
| 310 | |
| 311 | 1. API/TUI 创建或恢复线程(`/v1/threads*`) |
| 312 | 2. 在线程上启动回合(`/v1/threads/{id}/turns`) |
| 313 | 3. 引擎事件被映射为条目生命周期事件(`item.started|item.delta|item.completed`) |
| 314 | 4. 中断/引导操作只作用于当前回合 |
| 315 | 5. 压缩(自动/手动)以 `context_compaction` 条目生命周期形式发出 |
| 316 | 6. 清除(智能体驱动)以 `context_purge` 条目生命周期形式发出 |
| 317 | 7. 客户端回放历史,并用 `/v1/threads/{id}/events?since_seq=<n>` 续接 |
| 318 | |
| 319 | ### 持久化 schema 门禁 |
| 320 | |
| 321 | - `session_manager.rs`、`runtime_threads.rs` 和 `task_manager.rs` 在持久化记录中内嵌 `schema_version`。 |
| 322 | - 加载时,若 schema 版本更新则显式报错拒绝,而不是静默截断/覆盖数据。 |
| 323 | - 这样既能安全地向前迁移,也能在二进制与存储状态不同步时防止损坏。 |
| 324 | |
| 325 | ## 扩展点 |
| 326 | |
| 327 | ### 新增一个工具 |
| 328 | |
| 329 | 1. 在 `tools/` 中创建处理器 |
| 330 | 2. 在 `tools/registry.rs` 中注册 |
| 331 | 3. 添加工具规格(名称、描述、输入 schema) |
| 332 | |
| 333 | ### 新增一个 MCP 服务器 |
| 334 | |
| 335 | 1. 在 `~/.codewhale/mcp.json` 中配置 |
| 336 | 2. 启动时自动发现服务器 |
| 337 | 3. 工具自动暴露给 LLM |
| 338 | |
| 339 | ### 创建一个技能 |
| 340 | |
| 341 | 1. 创建带 `SKILL.md` 的技能目录 |
| 342 | 2. 定义技能提示词和可选脚本 |
| 343 | 3. 放入 Codewhale 拥有的根目录(`~/.codewhale/skills/` 或 |
| 344 | `<workspace>/.codewhale/skills/`),或通过 `/skills` 从兼容的 harness 根目录导入 |
| 345 | |
| 346 | 关于技能管理器、审计清单,以及“兼容根目录(`.claude`、`.agents` 等)绝不被原地 |
| 347 | 修改”这条规则,见 [SKILLS.md](SKILLS.md)。 |
| 348 | |
| 349 | ### 新增钩子 |
| 350 | |
| 351 | 在 `~/.codewhale/config.toml` 中配置: |
| 352 | |
| 353 | ```toml |
| 354 | [[hooks]] |
| 355 | event = "tool_call_before" |
| 356 | command = "echo 'Running tool: $TOOL_NAME'" |
| 357 | ``` |
| 358 | |
| 359 | ## 关键设计决策 |
| 360 | |
| 361 | 1. **流式优先**:所有 LLM 响应都流式返回,以保证响应速度 |
| 362 | 2. **工具安全**:Ask 和 Auto-Review 会依据工具与托管策略要求审批;Full Access |
| 363 | 去掉常规提示,但不会去掉硬性安全闸。有副作用的 MCP 工具走同一条边界。 |
| 364 | 3. **可扩展性**:MCP、技能和钩子让定制无需改动代码 |
| 365 | 4. **跨平台**:核心可在 Linux/macOS/Windows 上工作。沙箱保证因平台而异: |
| 366 | macOS 在可用时使用 Seatbelt;Linux 仅在显式启用时使用已安装的 bubblewrap |
| 367 | 可执行文件;Windows 没有对外宣称的操作系统命令沙箱。Seccomp 和 Windows |
| 368 | 辅助程序契约未接入命令执行。 |
| 369 | 5. **最小依赖**:为构建速度谨慎选择依赖 |
| 370 | 6. **本地优先的运行时 API**:HTTP/SSE 端点面向受信任的 localhost 访问, |
| 371 | 目前由 `crates/tui` 运行时提供 |
| 372 | 7. **锁中毒**:默认失败即停。锁中毒意味着某个持有者在改到一半时 panic, |
| 373 | 因此标准做法是 `.expect()` 并附上指明该锁的消息——绝不对外提供只更新了 |
| 374 | 一半的状态。只有在状态过期是安全的场景(缓存、幂等重建)才用 `into_inner()` |
| 375 | 恢复,并加注释说明原因。 |
| 376 | |
| 377 | ## 配置文件 |
| 378 | |
| 379 | - `~/.codewhale/config.toml` - 主配置(`~/.deepseek/config.toml` 仍作为遗留回退被读取) |
| 380 | - `/etc/deepseek/managed_config.toml` - 可选的托管默认值层(Unix) |
| 381 | - `/etc/deepseek/requirements.toml` - 可选的允许策略约束(Unix) |
| 382 | - `~/.codewhale/mcp.json` - MCP 服务器配置 |
| 383 | - `~/.codewhale/skills/` - 用户技能目录 |
| 384 | - `~/.codewhale/sessions/` - 会话历史 |
| 385 | - `~/.codewhale/sessions/checkpoints/` - 崩溃检查点 + 离线队列持久化 |
| 386 | - `~/.codewhale/snapshots/` - 供 `/restore` 和 `revert_turn` 使用的 side-git 回合前/后工作区快照 |
| 387 | - `~/.codewhale/tasks/` - 后台任务记录、队列、时间线、产物 |
| 388 | - `~/.codewhale/audit.log` - 仅追加的安全事件:凭据的保存与清除、钩子环境变量的键名、压缩过程、目标完成、终端的审批路由、Auto-Review 裁决,以及开启 `[network]` 审计时的出站网络决定。它不是操作记录:不包含命令或文件改动,app 或 `serve` 回合也不会在这里写入审批。一个会话做了什么,见 `docs/RECEIPTS.md` |
| 389 | - `~/.codewhale/sessions/<id>/approval_receipts.jsonl` - 一个会话的每一次审批请求与决定,包括由谁决定 |
| 390 |