# 🚀 CodeBuddy Code v2.97.0 发布

## ✨ 新功能

### 完整快捷键系统

参考同类工具架构实现快捷键系统，支持上下文条件、弦序列（如 Ctrl+X Ctrl+K）、用户自定义覆盖。

- 配置文件：`~/.codebuddy/keybindings.json`
- 16 个上下文（Global / Chat / Terminal / Autocomplete 等）、60+ 个动作
- `/keybindings` 斜杠命令快速管理
- Web UI 新增可视化配置（按上下文分组、搜索、录制、实时冲突检测）
- REST API：`/api/v1/keybindings`（GET/PUT/POST reset/POST validate）

### Skill / Subagent Frontmatter Hooks

支持在 `.codebuddy/agents/*.md` 与 `.codebuddy/skills/*/SKILL.md` 的 YAML frontmatter 中配置 `hooks:` 字段，子代理 / fork skill 生命周期内自动注册和清理。

- 支持 `command` / `prompt` / `agent` / `http` 四种 hook 类型
- `once: true` 自动移除、event matcher 语义
- **默认安全闸门**：非 product 内置来源的 frontmatter hooks 默认禁用（含本地与插件市场），需在 `settings.json` 中开启 `allowUntrustedFrontmatterHooks: true` 才生效

### Hook 事件全面增强

新增 20+ 个 hook 事件覆盖工具失败、子代理生命周期、任务管理、权限审批、文件监视等场景：

- **生命周期**：PostToolUseFailure / SubagentStart / StopFailure / PostCompact / ConfigChange / InstructionsLoaded
- **权限与任务**：PermissionRequest / PermissionDenied（可拦截审批）、TaskCreated / TaskCompleted、TeammateIdle、Setup
- **文件监视**：FileChanged（声明 watchPaths）、CwdChanged（cwd 变化触发）
- **新增 hook 类型**：`http`（POST 任意 URL）、`agent`（复用 prompt 路径）
- **新增字段**：`if`（按工具名/参数匹配）、`shell`（切 PowerShell）、`once`（成功后不再触发）、`asyncRewake`、`allowedEnvVars`、`statusMessage`
- **异步协议**：hook 输出 `{"async": true, "asyncTimeout": N}` 立即放行 fire-and-forget

### Skills / 命令 / Subagent 变量占位符

`.md` 文件中支持变量占位符替换：`${CODEBUDDY_PLUGIN_ROOT}` / `${CODEBUDDY_SKILL_DIR}` / `${CODEBUDDY_SESSION_ID}` 以及任意大写环境变量，支持 `${MY_ENV_VAR:-默认值}` 默认值语法。未设置的占位符原样保留，避免静默丢失配置。

### 第三方插件市场自动更新

新增 `autoUpdateThirdPartyMarketplaces` 产品配置和 `CODEBUDDY_AUTO_UPDATE_THIRD_PARTY_MARKETPLACES` 环境变量，支持全局启用第三方插件市场自动更新。市场配置项新增 `autoUpdate` 可选字段，可单独控制。

### Remote Gateway 任务超时可配置

`/api/v1/runs` 端点默认超时从 10 分钟提升到 **30 分钟**，长任务不再被强制中断：

- 新增 `gateway.runTimeoutMs` settings 配置（毫秒）
- 新增 HTTP header `X-Codebuddy-Run-Timeout` 单次覆盖
- 设为 0 或负数关闭超时保护

### Web UI PWA 自动检测新版本

发布新版本后，已打开的 Web UI tab 不再需要手动强制刷新：

- 每 15 分钟自动询问后端是否有新 Service Worker
- 对话空闲时自动刷新切到新版本
- 对话进行中弹 toast 保留"立即刷新"按钮，订阅运行状态在 Agent 空闲后自动刷新

### UE 项目自动排除大仓噪声目录

在 cwd 检测到 `*.uproject` 时，Grep / Glob 自动叠加 `!Intermediate/` `!DerivedDataCache/` `!Saved/` `!Binaries/` `!Build/` `!.vs/` 排除，避免 Unreal Engine 项目（典型 10W+ 源码 / 300W+ 总文件）的编译产物污染搜索结果；可通过 `settings.disableUEAutoExclude: true` 关闭。Grep 内容搜索新增 `--max-columns 500` 避免单行 MB 级内容打爆 stdout。

### 桌面文件系统 ACP 方法

在 ACP StreamManager 中实现完整 `fs/*` 方法（list / read / write / exists / makeDir / remove / rename / getInfo / watchDir / unwatch），使 WorkBuddy Desktop"全部文件"标签页正常工作。

## 🔧 改进优化

- **PowerShell 安全多层防御**：CLM 类型白名单（~90 类型）、Git 安全防护（裸仓库 / NTFS 8.3 / archive 提取器）、危险 Cmdlet 分类（7 集合 + 120+ 别名）、破坏性命令 UI 警告（16 种模式）、Unicode 破折号支持
- **ACP 连接稳定性**：GET SSE 连接 30 秒心跳防止反向代理（cloudflared / nginx）回收；连接关闭时等待历史写入完成防止 JSONL 日志被截断
- **Bash 工具 timeout 提示动态化**:工具描述中"最大 timeout"原先写死 600000ms，现动态注入与运行时实际 clamp 值保持一致
- **TUI Ctrl+F / Ctrl+B 光标导航**:支持 bash readline 风格的左右移动一字符,与已有 Ctrl+A / Ctrl+E / Ctrl+K / Ctrl+U 一致,emoji 多字节字符移动正确
- **Web UI 画布内嵌终端文字选择**:tile 聚焦后遮罩透传 pointerdown 给 xterm,支持选中复制;中键 / 右键 / Space + 左键仍走画布平移
- **Channel 权限 deny_and_exit_plan**:微信 / 企微用户可通过回复 `q` 退出计划模式;ExitPlanMode 工具新增专用提示
- **Request Purpose 标记**:新增 `X-Agent-Purpose` HTTP header 为不同类型 LLM 请求打分类标签,供 Langfuse 进行 trace 分析
- **图片压缩拦截器**:对用户发送的 base64 图片统一进行长边 2000px 压缩,确保 ACP / TUI / plugin-chat 各来源图片都经过尺寸优化
- **Worktree 目录切换**:创建或复用 worktree 后尽量保持进入与当前目录对应的相对子目录
- **Session API 统一**:合并 `listWorkspaces` 和 `listAcrossProjects` 为统一的 `GET /api/v1/sessions` 端点,支持 `cwd` 查询参数
- **模型权限错误自动恢复**:后端返回"模型不可用"时自动刷新产品配置并展示最新可用模型列表
- **下架历史模型并刷新积分系数**:下掉 HY 2.0 系列(3 个)和 GPT-5.2/5.1 共 4 个旧模型;按最新官方定价表刷新模型积分(iOA / 国内版 / 云托管版)
- **插件加载并发与缓存**:为市场插件列表 / 元数据 / 组件加载引入并发上限避免启动抖动;新增市场插件列表缓存与加载去重
- **自动化任务 Langfuse 标签**:定时任务触发的请求自动携带 `automation` 标签便于筛选

## 🐛 问题修复

### ACP 协议与稳定性

- **`/clear` 分隔符在重启后丢失**:修复 CBC / WorkBuddy Desktop 会话里插入的 `/clear` 分隔符在重启或 loadSession 回放后消失,以及随之出现的 400 错误
- **`/compact` 在 IM 场景下生效**:WorkBuddy Desktop IM 的 `/compact`/`/总结`原先无效,现通过 `_meta` 短路调用压缩
- **Cancel Barrier**:cancel 完成瞬间若有新 `session/prompt` 到达会被当作新对话启动,新增 500ms cancel barrier
- **取消标记泄漏**:prompt 终态与 `session/cancel` 同时发生时 pending cancellation 标记未被消费导致后续轮次 AskUserQuestion 被误判为取消
- **流式回复重复输出思考内容**:修复 WorkBuddy 对话流式回复重复输出思考内容
- **AskUserQuestion 显示"未回答"**:ACP 模式下用户回答 AskUserQuestion 后 UI 显示"未回答"
- **AskUserQuestion 误判为"拒绝回答"**:审批信号抢在工具执行路径建立等待者前到达导致答案被丢弃
- **会话查找竞态**:`session/prompt` 改用 `getRuntimeSession` 优先查询活跃会话避免"Session not found"
- **会话继承 CLI 启动参数**:`--serve` 模式下 ACP 创建的会话未继承 `--permission-mode` / `--model` 等参数
- **`session/load` 超时**:部分 Windows 环境下出现超时,在协议入口层增加 25s 兜底
- **模型切换不生效**:`unstable_setSessionModel` 立即把新模型写入 runtime session 不再只依赖订阅副作用
- **不再把内置命令当 skill 暴露**:`/clear` `/help` `/model` `/theme` `/status` `/resume` `/rename` 不再混入 `Skill` 工具列表

### 上下文压缩(Compact)

- **自动取消循环**:压缩在某些场景出现"自动取消"假象后立刻又被重复触发,压缩调用等待上限从 60 秒放宽到 20 分钟
- **残留 XML 标签**:任务异常结束时残留 `</conversation_history_summary>` 标签
- **摘要与用户消息错位**:请求级自动预压缩场景下压缩摘要与用户原始消息在历史中错位
- **退化摘要**:长会话自动压缩后缺少有效新增内容时仍可能再次压缩生成无效摘要
- **失败卡住历史视图**:失败/取消后再次触发压缩仍被卡住
- **超时死锁与取消**:子 Agent compact 超时后状态机卡死;用户主动取消时取消信号被吞掉
- **自定义模型自动压缩窗口**:未配 `maxInputTokens` 时退回到 `CODEBUDDY_AUTO_COMPACT_WINDOW` 兜底窗口
- **SDK 模式自动压缩断联**:SDK / headless 模式下压缩输出泄露到 stdout 导致断联
- **自动压缩渲染裸 XML**:聊天界面被渲染为裸 `<conversation_history_summary>` 标签,与 `/compact` 走同一套渲染
- **失败保留用户消息**:发送前自动压缩失败后会保存用户消息并展示明确失败提示
- **历史 `Unknown content` 错误**:从历史会话继续对话时可能报 `Unknown content` 导致中断

### 模型与请求处理

- **PTL 上下文超长恢复**:新增按 API 轮次精确截断历史的兜底机制,覆盖主流模型错误文案
- **空流自动重试**:识别上游网关只发占位/心跳帧后断开的"空流"场景,自动恢复
- **请求体超限恢复**:axios 显式设 `maxBodyLength: Infinity`,避免 follow-redirects 默认 10MB 上限本地拦截
- **`Tool X not found` 错误处理**:错误不再带产品实现细节的 agent 名;`ModelBehaviorError` 不再弹客户端错误框,走 `end_turn` 结束本轮
- **自定义模型 Gzip 检测**:`custom-local:` 前缀剥离导致无法匹配 product.models 配置的问题
- **自定义模型加载 400**:支持顶级数组和对象包裹两种 models.json 格式

### 历史与会话

- **首条用户消息丢失**:含隐藏上下文的用户首条消息在 UI 中消失
- **Model error 渲染为助手回复**:因模型报错(6004/429)中断的轮次被当普通回答渲染
- **Orphaned tool_call 回放**:对中断的工具调用跳过回放并注入系统通知
- **老会话任务列表展示**:旧版本迁移的会话恢复后任务列表渲染为空
- **图片消息标题污染**:在历史回放和会话标题生成场景中泄漏本地图片路径
- **Plan 模式权限恢复**:从 Desktop 端启动 plan 模式时 `prePlanPermissionMode` 未正确传递

### 工具与权限

- **恢复 Grep/Glob 工具注册**:之前误将 Grep/Glob 从 5 份 product.json 中删除导致降级为 Bash+rg
- **`--disallowedTools` 子命令规则**:带子命令的规则(如 `Bash(pkill:*)`)整个工具被移除
- **工具过滤绕过漏洞**:ToolSearch lookup 模式和 DeferExecuteTool 不检查工具可用性
- **Glob/Grep 空结果提示**:返回有意义的文本提示替代空数组
- **rm 批量删除风险等级**:从 MEDIUM 提升至 HIGH 确保 IM 侧批量删除触发用户确认
- **沙箱 strip_write 假成功**:静默丢弃写入/删除时不触发提权 UI

### 配置目录

- **Bash Sandbox 配置目录路径**:`CODEBUDDY_CONFIG_DIR` 自定义目录下 Bash 沙箱白名单失效
- **Prompt 模板硬编码路径**:TeamCreate / TeamDelete / statusline-setup 工具描述模板通过 `{{codebuddyHome}}` 渲染实际目录
- **UI 面板硬编码路径**:Permissions / Agents / Skills / Memory 面板显示真实路径
- **沙盒开关存储层级**:Desktop 端沙盒开关从持久化改为内存层(session 级别)避免污染工作区目录

### 插件市场

- **MCP 静态 Authorization 被 OAuth 覆盖**:在 `headers.Authorization` 显式配置时仍触发 OAuth 流程的问题
- **Marketplace 同名重复**:撞名出现两条同名套件且无法删除
- **Marketplace 重复添加报错**:改为自动触发更新流程
- **Marketplace 更新缓存未刷新**:`updateMarketplace` 后 `lastUpdated` 时间不更新
- **GithubMarketplace 目录名对齐**:非标准仓库 URL 目录名与 manifest.name 不一致
- **Git 不可用 ZIP 回退**:未安装 Git 的 Windows 环境下添加插件市场失败
- **内置套件市场 ZIP 分发**:默认套件市场无内容、添加市场失败
- **插件子代理描述刷新**:加载或切换插件子代理后描述未及时刷新
- **Skill 扫描悬空符号链接**:之前会让整个目录扫描中断

### Windows 兼容性

- **PowerShell Office Automation**:Excel / Word / PowerPoint / Outlook 创建被安全策略误拦截
- **PowerShell 命令行包装**:`rawCommand=true` 时跳过 bash 包装避免反斜杠/反引号被吞
- **黑窗弹出**:`--bg` 后台会话以及 daemon 启动期间弹出 conhost / Git Bash 黑窗
- **插件 commands 不显示**:`CODEBUDDY_PLUGIN_DIRS` 改用 `path.delimiter` 避免盘符被当分隔符
- **Bash 工具中文乱码**:跨 chunk 拼回 UTF-8 多字节序列;Windows 注入 `PYTHONUTF8=1`

### 其他

- **Daemon 端口竞态**:重启时 `EADDRINUSE` 启动失败或长连接阻塞
- **MessageQueueDeferredDispatch(Mode B)**:Agent 队列消息无法成功发送、"立刻发送"消息丢失
- **Team 消息实时投递**:队长忙碌期间队员 SendMessage 卡在消息队列不被消费
- **Playbook Team Spinner**:任务完成后左侧 agent 持续转圈
- **专家内置 Skill 不可见**:`rebuildAgents` 完成后未失效 Skill / SlashCommand / ToolSearch 工具描述缓存
- **会话标题与摘要触发**:确保标题更新、内容摘要、压缩前刷新按预期生效
- **ImageGen / ImageEdit 取消支持**:取消后图片生成请求仍继续执行
- **私有化部署检测**:配置企业端点但实际为云托管时错误标记为 Self-Hosted
- **`anydev` 远程 IDE `/ide` 命令**:新增 `CODEBUDDY_IDE_PORT` / `CODEBUDDY_IDE_HOST` / `CODEBUDDY_IDE_SKIP_VALID_CHECK` 环境变量
- **Web UI 编辑器保存清空文件**:`writeFile` 前端未显式设 Content-Type 被 body-parser 消费
- **Gateway CORS 静态资源**:开启 CORS 白名单时同源 IP 访问静态资源被误拦
- **Read 工具图片返回格式**:返回 image content block 格式
- **Worktree 相对 cwd**:复用 worktree 时未正确进入相对目录

## 📝 文档更新

- **下线 sandboxing.md 文档**:相关链接指向 bash-sandboxing.md
