Change Log
August 12, 2026 · View on GitHub
[Unreleased]
(暂无未发布改动)
[1.7.16] - 2026-08-12
Added:自动更新面板可选下载版本(auto / 便携版 / 安装版)
- 背景:此前下载形态只按运行形态自动判定(便携版/安装版),便携版标识缺失或判定失效时便携用户也会被拉进安装版(污染系统环境);且 UI 无显式选择入口。
- 实现:更新面板(设置 → 通用 → 自动更新)新增「下载版本」下拉——auto(跟随当前运行形态,默认)/ 便携版(GrayCode-Portable)/ 安装版(GrayCode.Setup);后端 UpdateChecker 增加 resolveInstallerKind 纯函数,检查/下载时按用户选择解析资产(auto 回退运行时形态判定);新设置键 graycode.updateInstallerKind(可 Settings Sync);切换后提示重新检查;三语 i18n。
Changed:更新提醒弹窗不再直接下载——主按钮改为跳转「通用-自动更新」面板
- 发现新版本弹窗保留版本号与 Release 说明展示,主按钮改为「前往更新设置」跳转到设置 → 通用 → 自动更新,由用户在面板选择版本并手动完成更新;移除弹窗内下载/安装流程。
Changed:下载完成不再自动打开安装器——提示更新包位置,用户手动完成更新
- 下载完成后不再调用 openExternal 自动启动安装器(此前便携版/安装版都自动打开,安装流程不可控);弹窗说明更新包位于 <数据目录>\update(便携版为 <便携外层目录>\data\update),并提供「打开文件夹」入口,由用户手动进行接下来的更新流程(便携版运行 GrayCode-Portable 安装包,安装版运行 GrayCode.Setup 安装包);UpdateChecker 新增 getUpdateDir 公开方法。
Fixed:webview 消息通道阻塞 handler 30s 超时兜底(渲染层挂起场景通道冻结)
- 背景:消息通道对普通消息严格串行(messageHandlingQueue),若某个阻塞 handler 永不回复(渲染层/后端重负荷后挂起),后续 cancel/delete/新消息全部排队,webview 通道整体冻结(渲染进程僵死诊断报告 B.4 项)。
- 实现:MessageRouter 对阻塞 handler 增加 30s 超时(BLOCKING_HANDLER_TIMEOUT_MS)——超时释放路由映射并回传 HANDLER_TIMEOUT 错误,队列继续处理后续消息;handler 本身无法中断,其迟到响应走 sendRoutedResponse 回退路径(requestId 已删除 → 主聊天),无害。
[1.7.15] - 2026-08-12
Added:无限制模式工具循环墙钟时限可配置——新增 graycode.maxToolLoopWallclockMinutes
- 背景:-1 无限制模式(maxToolIterations = -1)的墙钟兜底此前硬编码 30 分钟(MAX_TOOL_LOOP_WALLCLOCK_MS),用户无法调节。
- 实现:新增全局设置
maxToolLoopWallclockMinutes(默认 30 分钟,-1 = 不设墙钟时限,仅保留迭代硬上限兜底); ToolIterationLoopService 的ToolIterationLoopConfig.maxToolLoopWallclockMs接受该值(流式/非流式两条循环路径, 有限迭代模式语义零变化——墙钟兜底只作用于 -1 无限制模式);工具设置页新增「无限制模式工具循环墙钟时限(分钟)」输入框, 明确标注「仅在最大工具调用次数 = -1(无限制)时生效,-1 表示不设墙钟时限」;VSCode 配置键同步注册(可 Settings Sync), 远控设置页(schema 驱动)同步镜像该字段;三语 i18n + package.json contributes.configuration 同步。 - 伴生修复:maxToolLoopWallclockMs = -1(不设墙钟时限)时 deadline 计算为 0,原 guard 判断 Date.now() > 0 恒真会立即误触发
TOOL_LOOP_WALLCLOCK_LIMIT——guard 条件已补
wallclockMs !== -1。 - 测试:toolLoopWallclockLimit 3 例(小墙钟时限触发 / -1 不触发 / 有限模式不参与)。
Fixed:上翻历史过多时消息窗口无限增长导致界面卡死——上翻路径窗口有界化(滑动裁剪 + 回到最新入口)
- 根因:底部追加路径由 trimWindowFromTop 在 MAX_WINDOW_MESSAGES 内折叠,上翻路径(loadOlderMessagesPage)从不裁剪, allMessages 与虚拟窗口 visibleCount 随上翻无限增长 → 尾部切片渲染(resolveLoadedVisibleMessages)的 DOM 节点、 消息索引/缓存重建随轮次线性膨胀,消息轮次高时渲染线程被压垮,界面无法交互。
- 修复:上翻路径窗口超过 MAX_WINDOW_MESSAGES 时从底部(最新侧)裁剪到上限——窗口整体随上翻滑动,仍可逐页翻完整历史; 流式/等待响应期间不裁剪(防误裁在途消息);发送前若窗口末尾落后于真实最新(缺口),先重载最后一页对齐 backendIndex (否则新消息索引错位导致删除/重试定位错误);新增底部「回到最新」入口(hasNewerMessages),一键重载最后一页并滚动到底。
- 测试:conversationActions 全量回归通过。
Fixed:滚动条在底部时自动贴底失效——粘性底部状态自愈
- 根因:内容增长瞬间的 scroll 事件用中间态布局把 wasAtBottom 误判为 false,且程序贴底写入目标(programmaticScrollTop) 陈旧时,用户滚回底部恰好命中该值会被当成「程序写入」而跳过 wasAtBottom 更新——陈旧 false 永久保留,自动贴底不再跟随。
- 修复:updateLayout 跟随条件放宽为
wasAtBottom || isAtBottom()(用户当前在底部即跟随),跟随执行后恢复 wasAtBottom=true; handleScroll 命中程序写入目标时同样置 wasAtBottom=true(等价于贴底意图);上拉功能不受影响(滚离底部时两条件均为 false 不跟随)。 - 测试:CustomScrollbarSticky 扩至 6 例(新增「陈旧 programmaticScrollTop 吞掉贴底滚动事件后恢复吸底」)。
Fixed:后台任务完成回执/任务小气泡收不到——taskEvent 推送格式与前端订阅契约不符
- 根因:PUSH_MESSAGE_NAMES 契约规定 taskEvent 是 command 信封内的命令名 ({ type: 'command', command: 'taskEvent', data }),前端 backgroundTaskStore 也按此订阅 (onExtensionCommand('taskEvent'));但 VSCode 版 ChatViewProvider 与桌面版 BackendHost 实际都用 postMessage 直发(type: 'taskEvent'),两宿主与契约不符—— 后台任务(execute_command background / 后台 subagent / 图片生成)完成事件到不了任务条/回执链路: BackgroundTaskBar 小气泡永不出现、完成回执不回流对话,用户收不到后台任务完成的通知。 (仅 App.vue 的声音提醒走 message.type === 'taskEvent' 直发匹配,恰好能收到,掩盖了问题。)
- 修复:ChatViewProvider.handleTaskEvent 改走 sendCommand(与 terminalOutput/dependencyProgress 等推送一致,含 ready 队列);桌面版 BackendHost 改 postToRenderer('command', 'taskEvent', event); App.vue 声音提醒改匹配 command 信封(保留旧直发格式兼容)。
- 测试:backgroundTaskEventRouting 5 例(start→running、complete→completed 等)+ 全量 typecheck 通过。
Merged:合入上游 7df7be8c..e12da760 共 8 个 commits(PR#37 链路补齐/通知聚焦/Windows toast/diff 预热/settings 存储/tool-loop)
- PR#37 链路补齐(e12da760):list 回显 + updateGlobalConfig 校验(-1 或正整数)+ 工具描述兜底跟随全局动态读取——适配到本地 defaultMaxRuntime 命名(不引入上游 defaultMaxRuntimeSeconds);
- 通知系列:点击通知后聚焦 VS Code 窗口 + toast 使用扩展自带图标(7e61d608);Win32Focus.FocusWindow 组合拳绕过前台锁(c139b653);换回 node-notifier 实现 Windows 系统 toast(c6491788);
- diff 预热增强(8e9eb585):预热扩展到虚拟原文档 + 写入就绪共享屏障 + pending 时序前置;
- VSCodeSettingsStorage 修复(f65edbb8):读侧保持 VS Code 合并值语义(workspaceFolder > workspace > global),save 写入目标层级跟随(workspace 已有显式值写 Workspace 层,否则写 Global)——冲突合并保留本地 remoteControl 字段;
- tool-loop(7e548b69):移除早启动工具等待超时兜底,恢复 abort race + 无限等待落定——与本地 PR#36 实现等价,合并保留本地实现;
Merged:合入上游 e12da760..e42da40d 共 5 个 commits(diff 审查异步化重构/子代理全局配置 2×2 布局/i18n 修正/版本同步;fast-tavern 与 nightly 相关本批无)
- refactor(diff)(13c74fa9):diff 审查状态前移与异步化——writeReady 屏障真实化、自动保存倒计时展示同步、diff.accept/reject 非阻塞执行(protocol.ts 将 diff.accept/reject 纳入 NON_BLOCKING_MESSAGE_TYPES,避免一次点击占住主 Webview 串行队列,后续设置/焦点/保存请求全部排队)、前端 diff 逻辑抽离为 diffReviewController(ToolMessage.vue 大幅精简);ChatViewProvider diff 状态载荷补 writeReady/autoSaveAt/autoSaveDelay/isProcessing 字段;本地 diffManager 的锁冲突恢复/终态快照/等待超时上限等增强与上游 writeReady 屏障机制并存(diffManager.ts 自动合并无冲突);
- style(subagents)(e42da40d):子代理设置「全局配置」四参数由一行四列改为 2×2 网格布局——「并发数/迭代次数」与「队列超时/运行时长」各占一行,窄面板下 label 与提示文字不再挤成多行(.global-config-row 双类选择器,不影响 agent 配置区 .form-row 布局);
- fix(i18n)(657a28b9):移除 defaultMaxIterations 提示中过时的 1~200 范围说明——实际校验无上限(-1 或 >=1),文案与行为保持一致(en/ja/zh-CN 三语同步);
- chore(release)(347bc26a/ba030791):上游版本号整理至 1.5.2 并同步 frontend 包版本——本地版本体系独立,根 package.json 保持 1.7.15dev(publisher czocelot、中文 description 保留),frontend 包版本按上游口径同步至 1.5.2;上游 1.5.x 版本小节不并入本地 CHANGELOG 版本体系(沿用既有约定)。
Fixed:手动总结多轮对话 STALE_RANGE 失败 + 自动总结在长工具轮下永远回退
- 修复手动总结失败(用户报告「总结失败: 对话历史在总结期间发生变化」):多轮对话且最后一轮超预算(工具长回合)时,规划器轮内截断的切点必然位于最后一条真实用户消息之后,落盘侧
markAndInsertSummarizedAtomically只对「唯一真实用户回合」放行、多轮一律判 STALE_RANGE 放弃写入——工具用得越多越容易复现。手动总结是用户主动行为(前端在等待响应期间禁止触发,无进行中的回合需要保护),放行开关扩展为对所有手动总结生效:允许把「最后一轮的前半段」纳入总结(首条用户消息锚点保护与越界保护不变,并发缩短历史仍 STALE 不落盘); - 修复自动总结在长工具轮下必败回退:auto 模式当前轮是进行中的回合,规划器却仍开放「当前轮内部」的细粒度切点(末轮超预算时切点深入当前轮,必然吞掉当前用户消息)→ 落盘侧判 STALE_RANGE,白费一次总结请求后每次都回退细粒度裁剪。规划器改为 auto 模式不开放当前轮内部切点:切点停在当前轮轮首,总结旧轮、保留当前轮整体(预算为软目标);manual 模式保持轮内切点(配合上方放行);
- 测试:新增多轮 + 末轮超预算手动总结放行(2 例)、auto 大窗口末轮超预算成功 + 单超大轮仍 STALE(3 例)、规划器 auto/manual 轮内切点分叉(2 例)、fallback 轮边界优先裁剪与紧预算轮内裁剪(2 例);更新原「多轮仍 STALE」用例为新语义;后端 273 套件/3094 例 + 前端 102 文件/1000 例 + typecheck 全绿。
Merged:合入上游 main 至 7df7be8c(15 个 commit;fast-tavern 相关 commit 按项目决策不引入)
- 合入上游 2ffa0fc2..7df7be8c 共 15 个 commits(含 PR #33/#34/#35 合并提交):
- chore:添加 .editorconfig 与 VS Code 编码设置,强制源码 UTF-8 防编码漂移;
- fix(memory):记忆配置全局共享——全局与工作区实例统一读写
<dataPath>/memory/config(记忆数据仍按作用域隔离); - fix(tools/terminal):execute_command 超时不再误报用户取消——超时错误如实回传 LLM 继续对话而非自动暂停;
- fix(summarize):自动总结不再白烧 AI 调用(auto 切点钳制到当前回合、收缩后无新消息直接放弃、确定性失败不重试、手动总结多轮放行;本地 1a445158 已有等价实现,冲突按本地口径收敛);
- fix(ci):toolMeta 生成物跨平台行尾漂移——生成脚本规范化 CRLF/CR 换行,重新生成 toolMeta.ts 清除 \r 污染;
- perf(diff):目标文档预热消除首次 diff 预览卡顿——prewarmDocument 与 hunk 应用并行打开文档,showDiffView 复用预热结果;
- docs:README 新增衍生项目章节,收录 Code Desktop 社区桌面版;
- fix:全仓扫描修复批次(安全数据一致性/流式挂起/设置/前端);
- feat(subagents):子代理排队超时可配置 + 最大并发数支持 -1(新增全局
queueTimeoutSeconds,-1 无限制); - fix:PR #34/#35 合并审查修复——排队超时定时器 clamp 上限 + toolResponseCache 覆盖更新误淘汰;
- fix(PR #36):回退 ToolIterationLoopService 早启动工具等待超时兜底(PR #35 引入)——该兜底在流式结束后把 3 秒窗口内未落定的早启动工具强制标记为超时失败,误伤仍在正常执行的长耗时工具(如 execute_command 超过 3 秒即被占位结算);其防御场景已由工具层既有超时与取消路径覆盖。恢复原始等待逻辑(保留 abort 事件 race),长任务不再被误杀;
- feat(PR #37):子代理运行时长上限可配置——新增全局
defaultMaxRuntime(-1 无限制,默认 1800 = 30 分钟),per-agent 未配置 maxRuntime 时继承全局默认(per-agent 已配置的仍优先);前端子代理设置新增「默认最大运行时间(秒)」输入框;
- 不采纳:fast-tavern 相关 commit(b9e8f29d feat(fast-tavern) build 模块、0730d582 .venv gitignore)按项目决策剔除,合并树不含 fast-tavern-main 子项目;上游 1.5.x 版本小节([1.5.0]/[1.5.1])不并入本地 CHANGELOG 版本体系(内容已在前序合并按本地口径记录)。
Fixed:并发子代理太多导致桌面版崩溃(IPC 洪峰压垮渲染进程)
- 根因:Electron 版
SubAgentMonitorBridge无条件订阅子代理事件总线,且对非 llm_delta 事件无节流、无「面板未打开」短路(VSCode 版有!panel短路,移植时漏掉)——Monitor 从未打开时,每个子代理的tool_*/content_snapshot/run_*事件仍逐条构造载荷并webContents.send,并发 8-10 个子代理即每秒数百条 IPC 灌进单一graycode:backend-to-renderer通道,渲染进程队列无限增长 → OOM/长时间无响应 → 窗口崩溃; - 修复:① 新增
monitorMounted短路——前端subagents.monitorReady到达前(面板从未打开)不推送任何事件;② 面板折叠(visible=false)时非 delta 事件按 runId 合并到 100ms 窗口粒度(每 run 保留最新一条),llm_delta 维持丢弃;③ 恢复可见时补推一次纯状态 manifest(navigate:false,不覆盖用户选中);④ 新增getCachedManifest(updatedAt 缓存 + 容量上限),消除每条事件重复派生轻量 manifest 的开销(与 VSCode 版对齐); - 附带:折叠/未挂载时不再执行
createMonitorEventPayload/getActiveRunIds等逐事件开销,主进程事件循环同步负载同步下降。
[1.7.14dev] - 2026-08-11
Merged:同步上游 main 至 bb8d0b16(发布前修复批次 H3-H6 + 子代理「与当前模型同步」+ settings/core 加固,25 commits)
- 合入上游 1f4f0020..bb8d0b16 全部 25 个 commits:
- 子代理「与当前模型同步」(上游「强制使用当前渠道」下放为逐代理勾选):勾选后子代理忽略自身固定渠道/模型,运行时使用当前会话渠道与模型(channelId + modelId 一并继承);旧全局开关启动时自动迁移(migrateForceUseCurrentChannel,显式 false 保留),运行期兜底兼容;嵌套派发继承父 run 渠道;设置页勾选 UI + 三语言文案 + 后端/前端测试齐全;
- 发布前修复批次:checkpoint 元数据残留精确匹配(H3)+ retention 假 manifest 防护;conversation appendHistory 分段索引不可读自愈重建(H5,不再静默全量重写丢历史)+ 插入同步分支图 + rejectToolCalls 空数组语义;webview 面板关闭中止活跃流(H6)+ 消息队列重置 + Monitor 路由守卫;channel providerEvent 激活 Anthropic 提前执行 + count_tokens 完整计数 + 多段 thinking 签名配对;chat usageMetadataPartial 回退估算 + editBranch 检查点对齐 + trim 预算计入首条消息 + repeatedCallGuard 失败判定;mcp/memory uri 透传 + timeout:0 无超时语义 + stale client 清理 + compress 缺参校验;prompt frontmatter 反转义校验 + fileTree 逃逸/尾斜杠 + 动态 section vanished 补发 marker;settings toolAutoExec 缺键回落默认(delete_file 确认保护)+ JSON 损坏自愈 + reset 保留 storagePath + 符号链接循环防护;deps require.cache 失效清理 + install/uninstall 互斥 + 预发布版本逐段比较 + endAiWork 空闲误判;tools realpath 防符号链接绕过 + read_file 幻影空行 + write_file 存在保护 + terminal where argv 防注入 + media 超时取消口径;subagents 排队 pause/resume 缺口/续跑互斥/mailbox hop/退避监听 5 项;前端取消标记按会话隔离 + JsonViewer DAG 误标 + 输入指纹/引用复用 + 声音聚焦等 15 文件;
- 不采纳:fast-tavern 子项目(b9e8f29d 等,-x ours 消掉并保留来源标记)与 nightly 相关 commit(gitignore/CHANGELOG 结构均按本地保持);
- 冲突解决要点:diffManager 锁冲突恢复(H4)与本地 rejectingDiffIds 机制共存;StdioClient disconnect 采用本地更强实现(treeKill 错误即时 resolve + 悬空 handle 清理);UpdateChecker 保留本地 normalizeVersion(-2dev 构建号并入第四段)+ 上游预发布逐段比较;workspacePaths realpath 比较复用本地缓存解析器(统一解析链 + 缓存 + Windows 长路径前缀剥离);子代理设置保留本地 handleChannelChange(渠道默认模型预填);
- 合并回归修复:ToolContext 补 channelModelId 类型字段(syncWithCurrentModel 模型继承)、ChatViewProvider 补 disposed 守卫字段、会话快照 lastCancelledStreamId 类型对齐会话隔离形态、child_process 测试 mock 补 execFileSync、generateImage 测试路径对齐本地 pathGuard、toolMeta/i18n 共享映射重新生成;
- 测试:后端 273 套件/3087 例 + 前端 102 文件/1000 例全绿。
Fixed:亮色模式 UI 仍为暗色风格 + 窗口背景色/原生控件跟随主题(1.7.13 主题模式落地修复)
- color-scheme 修复(主因):桌面端 CSS 从未声明 color-scheme,系统为暗色时原生 select 弹出层/复选框/滚动条按暗色渲染(即使应用已切到亮色)。theme.css 暗色块补
color-scheme: dark、亮色块补color-scheme: light; - 补全 17 个缺失 --vscode- 变量*(暗/亮两套):代码高亮语法色(keyword/string/comment/number/variable/entity/meta/entityName-function)、notifications-、settings-、warningForeground、editor-font-size——此前组件 var() 引用回落到硬编码暗色 fallback,亮色下对比度崩坏;
- 窗口背景色与原生控件跟随主题:新增 app.setTheme 上报链(App.vue → BackendHost → 主进程),主进程同步 BrowserWindow.setBackgroundColor + nativeTheme.themeSource(系统对话框/原生菜单/首帧启动画面/prefers-color-scheme 随应用主题而非系统);启动时同步预读设置文件(resolveSavedTheme)免首帧闪烁;主题 watch 补 immediate 启动兜底;设置加载完成前不上报(避免 clobber 主进程预读主题);
- 顺带:MermaidZoomModal/overlay quick-pick hover 硬编码白字改主题感知(保持黑/白描边可读性);boot-splash 首帧经 themeSource 的 prefers-color-scheme 正确取色。
Fixed:扫描优化批次(安全/一致性/死代码)
- 亮色模式灰底灰字根因修复(color-mix 定义点解析):Chromium 对 color-mix 内的 var() 按「定义点」解析(非惰性),style.css
:root上定义的--gc-surface-*(输入框/设置面板/消息区/下拉框背景)会锁死暗色--vscode-*值,body 亮色类覆盖不生效——亮色下这些面板仍是暗灰底。亮色块重定义 4 个 surface 变量(color-mix 在 body 层解析到亮色值);亮色前景统一加深为近黑#1f1f1f(此前#383a42偏灰),描述文字#4d4d4d; - crop/rotate/resize 三工具 6 处 isCancelled 对齐新口径(API 请求超时 AbortError 不再误报用户取消,与 generate_image/remove_background 一致); - Unix which 检测改 execFileSync argv 传参(customPath 为用户可控配置,字符串拼接存在命令注入面;与 Windows/异步版同口径);processRunner 优先级设置 exec → execFile;
- compareVersions 版本段解析修正:语义预发布(-beta/-nightly.x)的 dash 段不再误并入版本段(此前 1.4.6-nightly.20260810 被 parseInt 误当第四版本段判为高于正式版);nightly 用例改为 semver 预发布语义断言,补 beta.10 vs beta.2 逐段数值比较;
- 工作区路径缓存加固:realpath 失败结果不再永久缓存(此前 fail-open 边缘);路径自身改用 lstat 校验 mtime(符号链接重定向的缓存失效盲区);
- 远控端文件读写/输入读取补 isPathInsideOrEqualReal realpath 复核(词法护栏之外的符号链接逃逸,与桌面工具链同口径);
- StreamChunkProcessor 移除与 H6 中止互斥的终结事件暂存死路径(测试改写为 H6 语义);reportCancelled 视图不可达日志降级 debug;清理 shellConfig 局部 require/getEnabledShellTypes 死代码/processRunner 未用 import/UpdateChecker 死注释;
- 测试:后端 273 套件/3088 例 + 前端 102 文件/1000 例 + typecheck 全绿;版本 1.7.14dev
[1.7.13] - 2026-08-11
Fixed(1.7.13dev 补记:UI 不透明度不再影响文字 + 消息区/四个下拉框背景透出 + 移除上游 nightly 更新渠道)
- UI 不透明度改为「仅背景半透明,文字/图标始终全不透明」:此前对输入框容器与设置面板直接应用 opacity 属性,会连文字一起变淡。现改为全局表面变量(--gc-surface-editor-bg / input-bg / sidebar-bg / dropdown-bg,color-mix 按 --gc-ui-opacity 混合透明),逐处替换面板背景色;App.vue 的 --gc-ui-opacity 同步 watch 加 immediate 保证首帧一致;
- 修复消息区背景不透明(合并回归):上游 308c79d4 合入把 1.7.11dev「聊天区容器透明化」的 .message-list 背景回退为不透明 editor-background(背景图被消息区整块盖住)。现 .message-list / build/todo 粘性壳 / build 卡片 / checkpoint 条统一改用 --gc-surface-editor-bg,随 UI 不透明度滑块实时透出背景图;
- 聊天区四个下拉框背景随不透明度调节:模式/渠道/模型/思考强度选择器(trigger + 下拉面板 + 面板内搜索框)背景改走 --gc-surface-input-bg / --gc-surface-dropdown-bg;
- 设置页全面透出:设置面板背景 + 全部 40 个设置组件(form-group 卡片/对话框等)的 editor-background 统一改用 --gc-surface-editor-bg;
- 移除上游 nightly 更新渠道:设置-通用-自动更新中的「更新渠道(stable/nightly)」选择器为上游特有功能,且 i18n 键(channelLabel 等)在合并后丢失导致界面显示原始键名。已整体移除 UI(GeneralSettingsSection/SettingsPanel 相关代码与样式);后端 UpdateChecker 的 UpdateChannel 类型 / getUpdateChannel 选项 / NIGHTLY_VERSION_RE / extractNightlyVersionFromName(上游兼容死面,本地 dev/stable 通道按版本号自动判定)一并删除及对应 5 例测试移除;
- 测试:后端 273 套件/3065 例 + 前端 101 文件/994 例 + e2e/smoke 全绿;三语言文案同步更新(UI 不透明度描述明确「文字与图标保持清晰」)。
Added:[1.7.13dev] 外观设置新增主题模式切换(亮色/暗色/跟随系统)+ UI 不透明度调节;远控端 diff 查看/批准 + 流式等待提示
- 外观设置新增「主题模式」:亮色 / 暗色 / 跟随系统三档切换(ui.theme 既有配置项补全 UI 入口,默认 auto 跟随系统不变);切换即时生效(App.vue watch 监听 store 变更重挂 matchMedia 监听),保存随 updateUISettings 持久化,三语言文案与设置搜索锚点(theme-mode)齐全;
- 外观设置新增「UI 不透明度」:滑块 0-100(默认 100,即完全不透明)调节输入框、设置面板等界面面板的整体不透明度,透出窗口背景;App.vue 同步为 CSS 变量
--gc-ui-opacity(InputArea 输入框容器与 SettingsPanel 面板应用,缺省回退 1);拖动滑块所见即所得(无需先保存);仅作用于桌面端主界面,远控端 UI 为独立自包含页面不受影响;三语言文案与设置搜索锚点(ui-opacity)齐全; - 远控端 diff 查看与批准(此前远控端对桌面端 pending diff 静默空转——桌面端未开自动批准时移动端只能干等,最长 5 分钟被自动拒绝):
- 服务端:BackendHost 的 diffManager statusChanged 监听新增转推
diffStatusSSE 事件(携带 pending 元数据与终结结算 finalized,不含原文内容);新增GET /api/diff-status(待批准列表)、GET /api/diff-preview(原文/新内容双侧,单侧 256KB 截断,仅 pending 态可读,只读 pending 快照不走消费型 getDiff 以免破坏工具链 partial 结算)、POST /api/diff-accept|diff-reject(直连 diff.accept/diff.reject handler);diffId 白名单 + 既有 Host/Origin/JSON-only 安全基线,SSE 关闭时广播静默; - 移动端:流式消息区上方新增「桌面端等待 Diff 批准」横幅(文件路径 + 删除警戒 + 剩余秒数倒计时(5 分钟权威时限,到点停表)+ 自动拒绝提示),支持查看 Diff(双栏原文/新内容对话框)/ 批准 / 拒绝 / 停止生成;批准/拒绝成功后横幅即时结算、消息列表自动刷新,桌面端终结结算(finalized)仅提示本端曾跟踪的 diff(批量结算最多 3 条 toast 防风暴);进入/重连页面时经 /api/diff-status 兜底同步;
- 服务端:BackendHost 的 diffManager statusChanged 监听新增转推
- 远控端流式等待提示:首块内容到达前(模型思考/工具执行期)流式消息显示「等待桌面响应…」占位(此前空白消息 + 光标,远控端看起来像卡住);逐块 SSE 增量渲染保持不变;
- 测试:remoteControl 套件扩至 199 例(diff 四端点 HTTP 断言含非法 ID/不存在 404、diffStatus SSE 广播与 finalized 透传、移动端 diff 横幅全流程(渲染/查看/批准/拒绝 DOM 交互)、增量流式回归(chunk 逐块到达逐块渲染,不等 complete));全部后端测试 273 套件/3070 例 + 前端 101 文件/994 例通过;三语言(zh-CN/en/ja)文案齐全。
Merged:同步上游 308c79d4(渠道配置启动预加载 + 发布前修复批次:checkpoint 分支隔离/config 串行队列/MCP 生命周期/SSE 流式下载/memory 位图缓存)
- 合入上游发布前修复批次(207 文件、+6412/-2121);不采纳上游 VS Code Marketplace 上架文档(桌面版非插件,README 保持本地版本)
Merged:合入上游 Bug Hunt 分支(5a3d7d39 150+ 修复 + i18n 全量统一 + 第九批模块化)
- i18n 全量统一(shared 提取 + i18n-sync 脚本)、双撤销栈回归、token 计数守卫、updateChecker 修复、第九批模块化、Bug Hunt 五轮 150+ 修复
Merged:[1.7.12dev] 同步上游 main 至 0107c597(模块化摊平 1-9 批 + Bug Hunt 五轮 150+ 修复 + MCP/memory/prompt/子代理/输入框等修复)
- 合入上游 40+ commits:模块化摊平重构(registry 死系统删除、ChatFlowService/ConversationManager/CheckpointManager/ToolExecutionService/execute_command/search_in_files 等大文件拆分至 flow/、manager/、tool-execution/、terminal/、search/、subagents/executor|eventBus、tools/shared/ 等子目录,后端依赖方向清零);
- 修复吸收:fileWriteLock 复合身份键 + acquire 参数化超时、MCP stdio 生命周期/串行队列/原子写、memory 迁移降级与 1000 上限、prompt 动态上下文差分加固、子代理并行段收尾 30s 兜底、输入框残留双机制(DOM 指纹同步 + 清空强制提取)、流式 Markdown 表格渐进渲染、恢复默认模板 {{$MEMORY}} 占位符、i18n 死键清理、ErrorType 下沉 core/errorTypes 等;
- 桌面版独有功能全量保留(远程控制 V7.2、桌面背景图、agentInbox、多工作区、安全加固);不采纳上游 nightly 自动更新机制与 fast-tavern 子项目(桌面版更新快、用户自建简单,无需 nightly);版本 1.7.12dev
Added:[1.7.11dev] 桌面端自定义背景图——外观设置新增本地图片窗口背景 + 不透明度调节
- 外观设置新增「桌面背景图」:选择本地图片(PNG/JPG/JPEG/GIF/WebP/BMP,上限 10MB)作为应用窗口背景,cover 铺满整窗;**不透明度滑块(0-100,默认 30)**实时作用于图片本身(透明度只影响图片层,文字与界面不受影响,调节所见即所得);设置页提供与窗口同规格的 16:9 预览框、路径回显(超长省略中间)与「移除背景图」一键清除;设置搜索新增「背景图/壁纸/透明度」锚点;
- 数据流:持久化仅存路径(ui.appearance.wallpaperPath / wallpaperOpacity,默认 '' / 30,updateUISettings 深合并链路无需改动);图片内容经新增 IPC 处理器(pickWallpaper:原生对话框选图 + 扩展名白名单 + 大小校验后返回 data URL;getWallpaperImage:按已存路径重读)交给渲染层(webview CSP img-src 白名单已含 data:);文件丢失/删除/格式失效时静默回退纯色背景,不打扰用户;SVG 刻意排除(避免脚本面/外部引用解析面);
- 渲染:App.vue 新增 .app-wallpaper 图层(position:fixed 覆盖整窗 + z-index:-1 + .app-container isolation 建立层叠上下文——置于容器纯色背景之上、全部内容之下;pointer-events:none 不拦截交互);设置页选择/拖动滑块即时应用到窗口背景(保存前即可预览效果),保存时随外观设置一并持久化;
- 聊天区放行背景:聊天视图的四个全幅不透明容器(.message-list / .input-area / .welcome-panel / .tabs-bar)改为透明,背景图在会话页/空会话欢迎页/输入区持续可见(消息行/代码块/输入框/页签项自身背景保留,可读性不受影响;未设置背景图时透出的是同色 app-container 背景,VS Code 模式无感知差异);
- 远控端不涉及(移动端设置页为 schema 驱动,新增字段仅透传,不影响远控端行为);
- 测试:新增 WallpaperHandlers 单元测试(选图全流程/扩展名白名单拒绝 SVG/大小上限/非文件拒绝/文件丢失回退/取消)+ DEFAULT_GLOBAL_SETTINGS 背景图默认值断言;三语言(zh-CN/en/ja)文案齐全。
Fixed:[1.7.10dev] 远程控制 V7.1——模型管理列表刷新修复 + 图标渲染健壮性加固
- 修复模型管理对话框列表不刷新:
openModelsDialog此前依赖S.configModels缓存(modelsLoaded短路),首次打开可能显示空列表/旧列表,添加/删除模型后调用loadConfigModels被缓存直接 return、列表永远不更新;现打开对话框即强制重拉(reloadConfigModels),添加/删除成功后强制重拉并重新渲染,删除后从最新渠道数据回填当前模型(不再悬挂已删模型的「当前」标记); - 图标渲染健壮性加固:全部 HTML 内联 SVG(16 处)与 JS 动态渲染图标(icon()/ICON_SEND/ICON_STOP)补显式 width/height 属性——即使外层 CSS 规则因任何原因未生效(样式表解析失败/变量缺失/旧浏览器),图标仍以合理尺寸显示,不再出现「退出按钮/加号/工作区加号空白」;
- 测试:新增模型管理对话框全流程(打开强制重拉断言/添加模型刷新/删除模型刷新/请求体形状)+ 内联 SVG 尺寸属性断言,fixture 模拟 models-add/remove/model 端点写回。
Added:[1.7.10dev] 远程控制 V7——渠道页内联折叠菜单(桌面端 ChannelSettings 同构)+ 提示词预设条目编辑器 + 工具页配置折叠 + 图标体系补全
- 渠道页重构为桌面端同构:顶部渠道选择器(选中即设为当前)+ 当前渠道完整内联表单(改即存,POST /api/config-update)+ 渠道列表卡片保留:
- 基础字段:启用此配置/接口地址/API 密钥(占位不回写)/useAuthorizationHeader(仅 gemini/anthropic)/模型列表入口/流式输出/渠道类型(切换弹确认)/工具模式/多模态/严格工具/超时/最大上下文;
- 上下文管理(折叠 + header toggle,开启写 contextManagementMode=summarize + autoSummarizeEnabled,关闭清零旧字段,与桌面端 updateContextManagementEnabled 语义一致);
- 工具配置(折叠:toolOptions.cropImage.useNormalizedCoordinates);
- Token 计数方式(折叠:tokenCountMethod 6 枚举 + 按方法显隐 tokenCountApiConfig url/apiKey/model);
- 高级选项(折叠 + 子分组):gemini(temperature/maxOutputTokens/maxImages + 思考配置子分组 thinkingConfig.includeThoughts/mode/thinkingLevel/thinkingBudget)、anthropic(temperature/max_tokens/top_p/top_k + thinking 子分组 type/effort/budget_tokens/display)、openai(temperature/max_tokens/top_p/frequencyPenalty/presencePenalty + reasoning 子分组 effort 9 枚举/effortCustom/summaryEnabled/summary)、openai-responses(temperature/max_output_tokens + reasoning 子分组)、思考回传子分组(sendCurrentThought*/sendHistoryThought*/historyThinkingRounds)、Prompt Caching 子分组(gemini+anthropic:enabled/ttl/keepAlive)、anthropicUserIdEnabled、deepSeekUserIdEnabled、pdfAttachmentEnabled;
- 自定义 Body(折叠 + header toggle:mode simple/advanced + items JSON + json 正文);
- 自定义标头(折叠 + header toggle:JSON 数组);自动重试(折叠 + header toggle:retryCount/retryInterval);
- 全部字段 options/optionsEnabled 成对合并、即改即存、无保存按钮(桌面端同款交互)。
- 提示词预设条目编辑器(桌面端 PromptEntriesEditor 同构):组装方式改为「传统模板/预设条目」二选一按钮;entries 模式下渲染条目列表(启用开关/名称/角色 system|user|assistant/内容 textarea/assistant 专属 fakeThought/上移下移复制删除)、Chat History 固定条目(不可删/禁/复制)、新增条目(entry_时间戳_随机 id)、从传统模板转换(template→system 条目、dynamicTemplate→user 条目、自动补 Chat History、切 entries 模式);归一化对齐桌面端(chat-history 恰好一条、order 重排);整数组静默保存 POST /api/settings。
- 工具页补齐:tools 分类顶部新增「最大工具调用次数」(toolsConfig 全局 maxToolIterations);工具行新增「配置」按钮展开内联配置面板(13 个有面板工具,与 fileTools 分区同源);fileTools 分类改为逐工具折叠面板(read_file/write_file/apply_diff/list_files/find_files/search_in_files/execute_command/history_search + media 折叠组);execute_command 新增逐 Shell 管理(shells[].enabled + path)。
- 记忆页:移除 partChars/partLines 字段(桌面端已全链路删除,回写会导致 MemoryManager 校验报错);新增全局/工作区作用域切换(GET /api/memory-scopes + workspaceUri 透传);条目行内编辑(POST /api/memory-update);删除/新增携带作用域。
- 远程控制页:新增启用开关 + 端口输入(remoteControl.enabled/port 可编辑,POST /api/settings 深合并持久化,提示保存后重启生效)。
- 用量页:新增时间范围选择(全部/今天/近 7 天/近 30 天,服务端 /api/usage?range= 换算 startTime 与桌面端 usage.getStats 同语义);补 cacheCreationTokens 卡片 + skippedConversations 提示。
- 图标体系补全:ICONS 表扩充至 48 个(plug/bolt/server/hubot/note/database/package/paintcan/bell/terminal/graph/remote/pin/star/hash/grid/globe/save/download/upload/eye/eyeClosed/arrowUp/arrowDown/checkAll/fold/list/network 等);设置页 22 个分类导航全部渲染内嵌 SVG 图标;渠道卡片操作按钮(设为当前/模型管理/编辑/删除)补图标;chips 删除按钮由 × 字符改为 SVG close;toast 移除 ✓ 字符拼接;退出按钮与顶栏按钮 aria-label 改用 i18n 键(settingsClose/btnFiles/btnSettings)。
- 服务端:GET /api/memory-entries 支持 workspaceUri 查询参数(白名单校验,控制字符剥离);POST /api/memory-add|update|delete 支持 workspaceUri 透传;GET /api/usage 支持 range 参数(today/7d/30d → startTime,all/非法值不传)。
- 测试:remoteControl 扩至 196 例——新增渠道页折叠菜单渲染与即存断言(7 个折叠面板/基础字段 POST 形状/子分组)、提示词条目编辑器全流程(组装切换/新增条目/Chat History 占位/静默保存 payload)、记忆作用域 + 行内编辑(POST /api/memory-update)、远程控制 enabled/port 字段、用量范围选择器、22 分类导航 SVG 图标、服务端 workspaceUri 透传与 range→startTime 换算(7d/30d 时间窗断言);fixture 的 /api/settings POST 改为深合并回读(模拟真实服务端)。
Added(1.7.10dev 补记:远程控制 V6——布局重构为桌面版三段式 + 设置面板与桌面端 19 页签逐字段同步)
- 布局重构(V6,彻底告别移动端三页签+底部导航):删除底部导航 #tabbar,改为桌面版三段式——顶栏(会话抽屉/标题状态/文件/设置/刷新)+ 32px 会话页签条 + 消息区 + 底部输入区;文件与设置改为全屏右侧滑入面板(#panel-files/#panel-settings,桌面版整页切换语义),顶栏按钮开关;顶栏新增「文件」「设置」入口;
- 设置面板改为桌面版布局:左侧 132px 纵向分类导航(#settings-nav,active 蓝底白字)+ 右侧卡片表单(#settings-scroll/#settings-sections),22 分类不变(channel/general/proxy/tools/autoExec/mcp/fileTools/sandbox/prompt/context/memory/summarize/checkpoint/tokenCount/imageGen/skills/subagents/pinned/remoteControl/storage/dependencies/usage);
- 渠道编辑改为桌面端同款子菜单(弹窗内 4 子 tab:基本设置/上下文管理/工具配置/高级选项):
- 基本:name/url/apiKey/useAuthorizationHeader(新)/toolMode/timeout/maxContextTokens/streamOutput/multimodalToolsEnabled/strictToolsEnabled(字段名修正,此前误写 strictTools)/enabled;
- 上下文管理:contextManagementEnabled/contextManagementMode(summarize)/contextThreshold(默认 80%)/autoSummarizeEnabled;
- 工具配置:tokenCountMethod(6 枚举)+tokenCountApiConfig(url/apiKey/model)+toolOptions.cropImage.useNormalizedCoordinates;
- 高级选项(按渠道类型显示):retry 3 字段/customBody/customHeaders/温度/最大输出(max_tokens|maxOutputTokens)/Top-P/Top-K(anthropic)/惩罚(openai 系)/reasoning(effort 9 档+effortCustom+summaryEnabled+summary)/thinking(type 3 档+effort+budget_tokens+display)/thinkingConfig(includeThoughts+mode 3 档+thinkingLevel+thinkingBudget)/回传 4 开关+historyThinkingRounds/promptCaching(enable+ttl+keepAlive)/anthropicUserIdEnabled/deepSeekUserIdEnabled/pdfAttachmentEnabled;
- 设置面板逐字段同步桌面端 19 页签:
- memory 新增记忆条目管理(列表/添加/删除,GET /api/memory-entries、POST /api/memory-add|delete)——桌面端独有核心区块;
- usage 修正为桌面端同源统计(stat-grid 7 卡:总/输入/输出/思考/缓存读取/会话数/模型消息 + byModel/byDay 明细 + 刷新,数据来自 usage.getStats 平铺字段);
- sound 补全(cooldownMs/cues 8 开关/Windows 通知全组/theme 枚举修正 beep|soft)、appearance 补 loadingText/splashEnabled;
- tools 补全部启用/禁用批量按钮 + 按分类分组;fileTools 全面补全(apply_diff.format 枚举修正 unified|search_replace、outsideWorkspaceAccess、autoSaveDelay 按钮组、diffGuardThreshold;list_files/find_files chips;execute_command timeout/maxOutputLines 枚举;history_search 6 字段;5 个 media 工具 returnImageToAI);
- mcp 编辑补 description/args/env/headers/autoConnect/cleanSchema/timeout + 卡片连接/断开按钮与状态徽标;
- subagents 新建/编辑/删除完整表单(名称/描述/系统提示词/渠道/模型/工具模式与白黑名单/最大迭代/最大运行时间/启用,POST /api/subagent-save|delete);
- prompt 模式管理(新建/重命名/复制/删除,POST /api/prompt-mode-save|rename|delete)+ 每模式 template/dynamicTemplate*/dynamicContextStrategy/promptAssemblyMode(路径修正为 modes.
每模式字段 )/toolPolicy; - checkpoint 补每类别 profilePatterns;storage 补浏览文件夹/重置默认(storagePath.selectFolder/reset 透传);general 补更新按钮(checkUpdateNow/updateNow)、导入导出(settings.export/import)、应用信息;
- 服务端新增 14 个端点:/api/mcp-connect|mcp-disconnect、/api/update-check|update-now、/api/settings-export|settings-import、/api/storage-config|storage-select|storage-reset、/api/memory-entries|memory-add|memory-update|memory-delete|memory-scopes;
- 测试扩至 182 例(remoteControl 套件):新增渠道 4 子 tab 渲染与 strictToolsEnabled 保存断言、记忆条目增删、用量 stat-grid、14 个新端点路由测试、usage 平铺字段断言。
Added(1.7.10dev 补记:远程控制 V5——UI 对齐桌面版全量重写 + 设置项补全 + 消息渲染与服务端 schema 对齐)
- UI 视觉对齐桌面版(V5):
remoteControlUiCss.ts按桌面端组件实测数值全量重写——VS Code Dark+ 令牌精确对齐(editor-background #1e1e1e / panel-border #454545 / 主题蓝 #3794ff / 选中蓝 #094771 / hover #2a2d2e)、扁平化极小圆角(2-6px)、8pt 间距系统;消息列表对齐 MessageItem(用户消息淡蓝底color-mix(6%)、助手扁平分隔列表、消息头角色/模型名/时间)、工具卡对齐 ToolMessage(1px 边框 2px 圆角、蓝色工具图标、状态色、可展开 JSON 参数)、思考块对齐 MessageRenderBlock(1px 边框 + 折叠/展开 + 斜体灰字)、输入区对齐 InputArea/InputSelectorBar(选择器触发按钮 + 输入框聚焦蓝框 + 32px 发送按钮)、页签栏对齐 ConversationTabs(32px 高、2px 激活下划线)、设置面板对齐 SettingsPanel(卡片化表单 + toggle 开关)、会话抽屉对齐 ConversationList(标题/时间/消息数 + hover 操作); - 消息渲染与服务端 schema 对齐(修复「远控端消息和服务端不对应」):
- 工具调用识别改为真实形状
part.functionCall.name(此前type:'toolCall'死代码,工具调用全部不可见); - 思考部分
part.thought折叠为思考卡(此前思考过程被摊开显示成正文); functionResponse消息渲染为工具结果卡(此前显示为空白用户气泡,消息数量与桌面端不一致);- 附件消息保留元数据渲染占位卡(服务端 stripMessagePayloads 不再整段删除 inlineData/fileData,改为剥离 base64 保留 mimeType/displayName,移动端消息数与桌面端一一对应);
- 消息头字段改用真实键名(
modelVersion/timestamp,此前model/createdAt永不显示); - 消息删除改用服务端绝对索引
msg.index(此前传页面下标,历史分页后删错消息); - 流式工具阶段内容不再丢弃(toolsExecuting/toolIteration/toolStatus 的 content 与工具名实时展示);
- 工具调用识别改为真实形状
- 设置项补全(对齐桌面端 SettingsPanel 19 页签):
- 新增「MCP 服务器」分类(GET /api/mcp 列表 + 新增/编辑/删除/启用停用,透传 webview McpHandlers);
- 新增「用量统计」分类(GET /api/usage 透传 usage.getStats,总/输入/输出 Token + 总费用);
- 子代理分类列出 agents 列表并支持启用/停用;
- 渠道编辑弹窗补齐桌面端字段:流式输出、多模态工具、严格工具、自动重试(次数/间隔)、自定义请求体/请求头(开关 + JSON 编辑);
- 修复 5 个死字段(保存后对桌面端零效果):
proxy.insecureSkipTlsVerify→insecureSkipVerify、read_file/write_file.allowOutsideWorkspace→outsideWorkspaceAccess(deny/ask/allow 三态)、execute_command.defaultTimeoutMs→defaultTimeout、pinned_files.pinnedFiles→files[](对象数组,列表 + 启用/移除); - 补齐 imageGen 默认宽高比/尺寸、memory systemPrompt、apply_diff diffGuardThreshold、execute_command maxOutputLines、sandbox、prompt 组装模式/动态上下文策略、smoothStreaming 四档(silky);
- 依赖分类支持安装/卸载按钮(POST /api/dependency-install|uninstall);
- 「无法打开新聊天」修复:①前端不再以
S.activeChannelId为空拦截发送(此前桌面端未显式设置当前渠道时新聊天首条消息被前端静默拦截,服务端本有 resolveConfigId 兜底);②孤儿流终结块竞态修复——SSE 整条流(含 complete/error)早于 POST /api/send 响应到达时,终结块滞留 orphanStreams 永不重放导致新页签永久卡「生成中」,现在回填 conversationId 后立即重放孤儿缓冲(flushOrphanStream 挂载 + orphanStreamsHasConv 兜底); - 服务端:
/api/send对已存在 conversationId 增加会话存在性校验(404,此前对已删除会话发消息会在桌面端 loadHistory 读路径静默「复活」空会话);stripMessagePayloads保留附件元数据。 - 测试:远程控制测试扩至 156 例——新增 MCP/子代理/提示词模式/依赖安装/用量端点路由测试、/api/send 404 复活防护测试、附件元数据保留断言、22 分类渲染断言。
Fixed(1.7.10dev 补记:远程控制 V5)
- 消息渲染层与服务端 ContentPart schema 全面对齐(见上),删除消息索引、流式工具状态、消息头字段名等历史错位全部修正。
Added(1.7.10dev 补记:远程控制 V4 全量重写——移动端 UI 架构重构 + 设置字段与桌面端完全对齐 + 稳定性加固)
- 客户端架构重构(V4):
remoteControlUiScript.ts整体重写为单一 IIFE + 明确模块分区(工具/API 客户端/内嵌 SVG 图标/状态/视图路由/会话页签/输入区四选择器/文件与工作区/schema 驱动设置页/SSE 看门狗/启动);全部渲染函数幂等且经safe()错误边界包裹,任何异常只落 toast + 顶部错误横幅,杜绝"页面随机变空白"(含新增渠道后白屏、闲置白屏等历史故障); - 稳定性加固:SSE 看门狗(readyState 静默断连 15s 兜底重连、断线退避重连、
visibilitychange回前台立即恢复)、服务器 bye/重启后probeServerRecovery周期性探活自动重连(此前 bye 后页面永久停摆)、全局window.onerror/unhandledrejection兜底;修复loadConfigModels对每个渠道重复拉取 + 触发设置页无限重渲染的隐患(新增 modelsLoaded 缓存); - 设置页字段与桌面端完全对齐(schema 驱动):
- 检查点改为
toolsConfig.checkpoint.*(此前误写toolsConfig.checkpoints.*复数键,开关/上限对桌面端零效果),补齐消息类型存档点(before/after 用户/模型消息、仅外部模型层、合并未变化检查点)、工具备份(执行前/后工具多选清单)、排除配置(8 类别开关、最大文件大小 MiB、自定义 gitignore 模式); - 自动总结改用桌面端真实字段(summarizePrompt/autoSummarizePrompt/keepRecentRounds/keepRecentTokens/useSeparateModel/summarizeChannelId/summarizeModelId/maxAutoSummarizeAttemptsPerTurn/summarizeMaxInputRatio 百分比输入,此前 rounds/maxTokens 等全部错位);
- 记忆改用真实字段(wakeLines/entryChars/partChars/partLines,此前 wakeKeywords/maxCharsPerEntry 错位)、上下文感知补齐诊断子项(enabled/severities/workspaceOnly/openFilesOnly/每文件与文件数上限/ignorePatterns)、沙箱补齐(defaultTimeout(ms)/maxOutputLines/cleanupTempDir)、子代理改用真实字段(maxConcurrentAgents/failureModeAfterRetries/generalWorkerEnabled/defaultMaxIterations/defaultMaxRuntime)、系统提示词模式改读
system_prompt.currentModeId(modes 为对象映射)、Token 计数补 enabled、通用页补 workspaceBehavior/selectionContext/tpsBar 等; - 渠道卡片新增「模型管理」对话框(添加/移除模型、设为当前模型)。
- 检查点改为
- 设置页 20 分类全部可渲染:修复
autoExec分类点击空白问题;四选择器(模式/渠道/模型/思考强度)底部弹层联动渠道/模型数据。 - HTML/CSS:新增
#error-banner错误横幅、页签/抽屉/消息操作/确认条/清单(checklist/排除开关/百分比输入)等新控件样式,全部图标内嵌 SVG,零外部依赖。
Fixed(1.7.10dev 补记:远程控制 V4)
- 服务端设置写侧密钥占位符剥离(
RemoteControlServer.ts):POST /api/settings现在与config-update同语义——toolsConfig.generate_image.apiKey/toolsConfig.token_count.*.apiKey为'********'或空串时不落库覆盖已存密钥;proxy.url含脱敏***@时同样不覆盖真实凭据(此前设置页保存会把脱敏占位当真实值写回)。 - 远程控制测试扩至 143 例:新增 jsdom DOM 交互测试(四选择器弹层全流程、20 分类切换渲染、检查点/自动总结字段路径断言、新增渠道 modal→POST→不白屏回归、SSE 空闲稳定性、发送透传);模板完整性测试覆盖脚本全部 id 引用与全部 i18n key 三语言一致性。
Added(1.7.10dev 补记:远程控制 V2 去虚拟化直连 + 移动端 UI 彻底重构)
- 远程控制去虚拟化(V2 架构):远控端不再注册为 WebviewClientRegistry 的虚拟 webview 客户端、也不经 MessageRouter 路由——此前每次操作都要「HTTP → routeMessage → MessageRouter → handler → clientRegistry 回传 → pending 表」绕一整圈,落盘与响应多一层 JSON 序列化往返,延迟更高、链路更难维护。V2 起所有操作由 BackendHost 直连:
- 非流式操作
invokeHandler()进程内直接执行 webview handler 函数(sendResponse/sendError 直接 resolve/reject Promise),校验与业务逻辑与桌面端完全一致(同一批 handler 函数),但零虚拟客户端开销、无 20s 路由超时; - 流式操作(chatStream/retryStream/toolConfirmation/cancelStream)由远控端专用 StreamRequestHandler 直连执行(与桌面端共享同一 StreamAbortManager,移动端停止与桌面端取消共用同一取消控制器),chunk 经 getClientView 直投 SSE;
- 移除
remote-control虚拟客户端注册、pending 应答表与路由超时机制。
- 非流式操作
- 会话列表实时双向同步:会话变更(远端/桌面端新建、改名、删除、摘要更新)后:①移动端经 SSE
conversations事件实时刷新抽屉列表;②桌面端经新增conversationsChanged广播实时刷新最近对话列表——远端新建的对话不再需要重启应用才能出现在桌面端。 - 渠道完整管理(移动端设置页):新增渠道(名称 + 类型:gemini/openai/openai-responses/anthropic)、编辑渠道(名称/API 地址/API Key/工具模式/超时/最大上下文 token/思考强度)、删除渠道(确认后不可恢复);
GET /api/config返回完整可编辑配置(apiKey 脱敏为占位串,更新时占位/空串不覆盖已存密钥);新增端点POST /api/config-create|config-update|config-delete。 - 模型管理(移动端):新增
POST /api/models-add|models-remove|models-get(对齐桌面端 models.addModels/removeModel/getModels),设置页可为渠道添加/移除模型、从提供商拉取模型列表。 - 输入区四选择器(桌面端 InputSelectorBar 同款):模型模式(
GET /api/prompt-modes,随/api/send透传 promptModeId)/ 渠道 / 模型 / 思考强度(按渠道类型生成档位,写入渠道 options/optionsEnabled,语义与桌面端 buildThinkingLevelUpdates 完全一致)四个下拉选择器,以底部弹层呈现、尺寸正常(不再是被挤压变形的窄 select)。 - 移动端 UI 彻底重构(V3):由 5128 行单文件拆分为
remoteControlUi.ts(i18n + HTML 骨架)/remoteControlUiCss.ts(样式)/remoteControlUiScript.ts(脚本)三模块;会话页签全部可关闭(含未落库的新对话页签,修复「无法关闭新对话窗口」);图标全部内嵌 SVG(无 emoji/字体依赖,杜绝移动端图标丢失);设置页 20 分类(对齐桌面端 SettingsPanel 侧栏);.composer-row补上 flex 布局(修复输入框布局塌陷)。 - 发送参数透传:
POST /api/send支持configId(渠道)/modelId(modelOverride)/promptModeId(模型模式),与桌面端 chatStream 同一参数面。
Fixed(1.7.10dev 补记)
- 远程控制无法关闭新对话窗口:
renderTabsBar只为已落库会话(tab.id 非空)渲染关闭按钮,未落库的新对话页签无「×」无法关闭;现已全部页签渲染关闭按钮。 - 远程控制输入区布局塌陷:
.composer-row无任何 CSS(非 flex 容器),#input的flex:1无从生效,输入框/发送键以默认 inline-block 排布;已补 flex 布局。 - 输入区缺少模型模式/思考强度下拉框:此前移动端输入区只有渠道/模型胶囊;已按桌面端 InputSelectorBar 补齐四选择器。
- 设置页下拉框变形过小:
.set-field select被挤至 130px 宽、自定义箭头错位;已修复为全宽控件 + 完整箭头(min-width 160px)。 - 设置页渠道无法新增/编辑高级设置:此前只有渠道列表(启用/停用/设当前),无新增/编辑/删除端点与表单;已补齐渠道完整 CRUD 与高级设置字段。
- 远端会话不实时出现在桌面端最近对话:桌面端仅在启动时加载一次会话列表且无推送事件;已新增
conversationsChanged广播(前端白名单 + chatStore 监听刷新)。
Added(1.7.10dev 补记:多会话并行 + 设置分页 + 流式/落盘修复)
- 多会话并行工作(会话页签栏):移动端聊天视图新增顶部会话页签条(桌面端 ConversationTabs 同款)——可同时打开多个会话、各自独立流式状态(后台页签照常累积输出,切回即见完整进度)、互不阻塞发送(A 会话生成中仍可在 B 会话发消息);「+」新建会话页签(发送后自动落库并回填标题)、页签可关闭;会话抽屉支持分页惰性加载(每页 30,加载更多按钮)。
- 设置页分页化(对齐桌面端 SettingsPanel 19 类侧栏):设置页由单一超长滚动列表重构为「分类页签 + 当前分类渲染」——渠道/通用/代理/工具/文件工具/命令与沙箱/提示词/上下文/记忆/总结/检查点/Token 计数/图像生成/技能/子代理/固定文件/远程控制/存储/依赖 19 个分类,连接状态/访问地址/安全说明归入「远程控制」分类,渠道模型管理归入「渠道」分类。
- 输入区渠道/模型选择:输入框上方新增当前渠道+模型胶囊(桌面端 ChannelSelector 同款),点击弹出渠道与模型选择弹层(
/api/configs|config|model|channel-active),与设置页「渠道」分类同一数据源。 - 历史消息分页:
GET /api/messages支持limit/offset(默认 120,上限 500,自尾端向前开窗),移动端滚动到顶自动回溯加载更早历史,避免数百条消息一次性下发渲染;GET /api/conversations支持limit/offset(默认 30,上限 100),返回total/hasMore,会话列表先按updatedAt降序全量排序再切片(分页跨页不乱序)。 POST /api/send返回streamId:新建会话页签与 SSE 流按 streamId 精确对齐,消除「POST 响应与首个 SSE chunk 先后不确定」的竞态窗口(配合移动端孤儿 chunk 缓冲补发)。
Fixed(1.7.10dev 补记)
- 远程控制「巨大『正在加载历史消息』挡住对话」:
#messages/#empty/#file-viewer的 CSS 规则设置了display:flex,覆盖了 UA 样式表的[hidden]{display:none}——切换会话/加载历史时「加载中」巨块与消息同屏显示、挡住大半对话。新增全局[hidden]{display:none !important}兜底修复。 - 远程控制流式输出断续/丢失(批量 chunk 被丢弃):桌面端 50ms 节流合并的
streamChunkBatch(data为 chunk 数组、conversationId/streamId 位于每个元素上)此前被移动端当单对象处理全部丢弃,只剩偶发单 chunk 能渲染;现已按真实装配形状解析(兼容单/批量/包装层三种位置),批量流完整累积。 - 远程控制会话摘要不落盘(列表 messageCount 恒 0 / 预览为空):桌面端的
custom.messageCount/custom.preview由前端在流式完成后调用conversation.updateSummary写入,移动端没有该前端逻辑——远端创建的会话列表计数/预览永远缺失。服务器在流终结(complete/cancelled/error)后自动按实际历史补齐摘要(messageCount=历史总数、preview=最后一条非工具响应用户消息前 50 字符,与桌面端口径一致)。 - 消息删除定位错误(历史分页后删除错消息):删除消息现使用服务端下发的绝对
index(deleteSingleMessage按全量历史索引定位),不再使用窗口内可见下标。 - 连接断开后页签卡死「生成中」:SSE 断开(bye/error)时复位全部页签的流式状态与待批准工具,发送键不再永久禁用。
- 设置分类标题缺失翻译:
secRemote此前不在语言包中,远程控制设置节标题显示原始键名;已补齐三语言。
Fixed(1.7.13 发布版:自动更新链路 + 桌面版修复)
- 修复自动更新「下载完成但安装器从未启动」:native 层 openPath 拒绝 .exe 且 shim 静默吞掉失败——下载完成后系统从未打开安装包,UI 却提示「已下载并打开」。新增 update:launchInstaller 专用白名单通道(仅允许 <数据目录>/update 内的 .exe/.zip 启动,由 BackendHost 注册),启动失败抛错不再谎报成功;
- 修复自动更新提示永不出现:后端启动检查延迟 10s、前端仅挂载时查询一次——新增检查状态推送(update.checkAvailable),发现新版本主动弹窗;已关闭的版本不再重复弹出;
- 便携版/安装版更新资产严格区分:portable 形态只匹配便携版 exe / 免安装 zip,绝不回退 Setup 安装包(防止便携用户被拉进安装版污染系统环境);安装版优先 Setup;
- 更新下载源信任校验(安全):installUpdate 只采用检查器自身解析的更新(版本一致);下载地址必须是本仓库 GitHub Releases(UPDATE_URL_UNTRUSTED 拒绝),防渲染层 XSS 后任意 .exe 落盘启动;
- 其它修复:second-instance 启动竞态崩溃、便携版数据目录只读回退(与安装版一致,回退目录独立)、错误日志 apiKey 脱敏、MCP 配置损坏不再阻断启动、子代理 token 消耗归集主会话用量统计、远端流失败后活动会话复位、超大文件 LSP 扫描上限、目录选择对话框超时豁免、错误码结构化透传(en/ja 用户不再看到中文报错);
- 测试:后端 273 套件/3074 例 + 前端 101 文件/994 例 + e2e/smoke 全绿;版本 1.7.13
[1.7.10dev] - 2026-08-10
Added
- 远程控制(桌面版)大改版——「床上办公」移动端主界面:移动端控制页由单一对话窗口升级为三页签自包含 SPA(会话 / 文件 / 设置),可操作桌面端真实工作区:
- 会话页签:会话列表/切换/新建/重命名、发送/停止/流式输出(SSE)、思考与工具调用展示、Markdown-lite 渲染(新增表格支持);新增工具确认条——
awaitingConfirmation到达时手机端展示待批准工具(名称 + 参数预览)并可直接批准/拒绝(toolConfirmation复用桌面端同一管道);错误消息支持重试(retryStream);支持删除消息(deleteSingleMessage); - 文件页签:工作区文件树懒加载浏览(目录展开/收起,沿用统一忽略列表)、文本文件查看与编辑保存(写入真实工作区)、在桌面端打开文件(
openWorkspaceFileAt,桌面端自动跳转高亮)、切换工作区(当前打开 + 收藏列表,workspace.setActive);超过 1MB 内容仅只读预览防移动端卡顿;超大文件读取服务端截断(1M 字符 +truncated标记)避免局域网拉取 10MB 级文本; - 设置页签:连接状态/端口/版本、局域网访问地址(点击复制)、渠道与模型列表(
models.setActiveModel切换激活模型,模型列表仅下发 id/name 裁剪字段)、安全说明; - 工作区实时镜像:桌面端活动编辑器/工作区变化经新增 SSE
workspace事件实时推送到手机(BackendHost挂接onDidChangeActiveTextEditor/onDidChangeWorkspaceFolders,激活工作区切换同样触发推送),hello/status载荷同步携带工作区信息;手机端收到工作区变化自动清空文件缓存与未保存编辑(防把旧工作区相对路径保存到新工作区); - 新增 REST 端点(全部沿用既有 Host/Origin/JSON-only 安全基线):
GET /api/workspace|workspaces|files|file|configs|config、POST /api/workspace-switch|file|open-file|model|retry|delete-message|tool-confirm;文件路径(拒绝../尾点段等 Windows 规范化陷阱)/工具响应/模型 ID 均新增形状白名单前置校验;/api/messages剥离附件 base64 载荷(移动端不渲染附件,避免数十 MB 级历史下载); - 模块可测性重构:
RemoteControlServer与移动端 UI 从electron-app/src/host迁入backend/modules/remoteControl/(纯 Node 依赖,随根 tsconfig/jest 覆盖),新增 HTTP 集成测试(安全基线/端点行为/SSE)与 UI 模板完整性测试。
- 会话页签:会话列表/切换/新建/重命名、发送/停止/流式输出(SSE)、思考与工具调用展示、Markdown-lite 渲染(新增表格支持);新增工具确认条——
Fixed
- 远程控制模块测试盲区:此前
RemoteControlServer位于 electron-app(无测试运行器),HTTP 面零测试覆盖;迁入 backend 后新增 30+ 断言覆盖 403/404/413/415/400/200 全状态码与 Host/Origin/JSON-only 安全基线。 - 移动端 markdown 表格缺失:旧 UI 的 markdown-lite 不解析表格(CSS 样式存在但无生成逻辑),已补基础表格解析(表头/分隔行/行渲染,横滚容器)。
Other
- 移除 fast-tavern-main 子项目:仓库内附带的
fast-tavern-main/(npm/py 双实现参考子项目)与主项目功能无实际关联,整体移除(81 个文件);同步清理.vscodeignore条目、README/README_EN 目录结构、KNOWN_ISSUES 相关条目,promptTypes.ts注释中的「fast-tavern 风格」表述改为「SillyTavern 风格」。 - 版本号升至 1.7.10dev(根与 electron-app package+lock 同步)。
Added(1.7.10dev 补记)
- 远程控制端 UI 风格对齐桌面端(VS Code Dark+ 设计令牌):移动端控制页整体重构为与桌面端一致的视觉体系——
electron-app/renderer/theme.css同款 CSS 变量(深色默认 +prefers-color-scheme: light浅色跟随系统),扁平化黑白灰配色、2-4px 圆角、8pt 间距、桌面端同款控件(顶栏 tabs 栏、底部页签蓝顶边、widget 弹层、list 选中态);消息列表由聊天气泡改为桌面端 MessageList 同款扁平行式(角色标签 + 用户消息淡蓝底 + 分隔线)。 - 会话侧栏抽屉(桌面端侧栏布局的移动端呈现):顶栏汉堡按钮滑出左侧会话列表,支持新建/切换/重命名(长按)/删除会话(
conversation.deleteConversation新端点);会话列表读取口径修复后与桌面端历史一致(见 Fixed)。 - 消息操作菜单:长按消息弹出操作菜单——用户消息可编辑并重新生成(
chat.editBranchStream,创建编辑分支候选、不覆盖原消息)、助手消息可重新生成(chat.rerollStream,分支图保留旧回答)/重试、任意消息可删除(deleteSingleMessage)。 - 工作区管理补齐:文件页与工作区弹层新增「新增工作区」(
workspace.openFolder透传,桌面端弹出文件夹选择框,选中自动收藏并激活)、收藏工作区可「移除收藏」(workspace.removeSaved)。 - 发送键图标修复:发送按钮此前初始为空(仅流式状态切换时才写入文字,首次加载无任何图标/文字);现内置纸飞机/停止 SVG 图标并在启动时立即渲染,与桌面端 SendButton(codicon-send)语义对齐。
- 新增 REST 端点(沿用既有 Host/Origin/JSON-only 安全基线,参数形状白名单):
POST /api/workspace-add|workspace-remove|conversation-delete|edit-message|reroll。
Fixed(1.7.10dev 补记)
- 远程控制会话列表恒为空(移动端「看不到任何会话」):
handleListConversations读取meta.messageCount顶层字段——真实meta.json(HIS-11 起)的 messageCount/preview 位于custom段,顶层恒为 undefined,再经messageCount > 0过滤后整个列表为空。已按桌面端getConversationMetadataBatch同口径读取custom.messageCount/custom.preview,并取消按计数过滤(与桌面端历史列表一致)。 - 远程控制工作区根目录无法浏览(文件树打不开):移动端文件页以空路径(
path=)表示工作区根目录,但服务器白名单isSafeWorkspacePath('')拒绝空字符串(400 Invalid path),根目录列举整体不可用。新增isSafeWorkspaceDirPath(仅目录列举允许空路径,读写仍拒绝),与 webviewFileHandlers.listWorkspaceDirectory的「空路径=根目录」语义对齐。
Added(1.7.10dev 补记:移动端自选工作区 + 设置页全量补齐)
- 移动端自选工作区目录(不再依赖桌面端弹窗):文件页/工作区弹层新增「浏览目录」模式——
GET /api/fs浏览服务端任意目录(仅目录项元数据:名称/路径,绝不读取文件内容;盘符列表 + 目录树 + 隐藏项过滤 + 500 条目上限),选中后POST /api/workspace-add携带fsPath直接打开(workspace.openFolder免桌面端文件夹选择框),桌面端弹窗保留为兜底入口。绝对路径白名单:禁控制字符、禁../尾点段、长度上限 2048。 - 设置页全量补齐(此前仅「渠道」):
GET/POST /api/settings透传桌面端getSettings/updateSettings消息管道(深合并 + 危险键剥离与桌面端一致),移动端可读写全部设置项——通用(检查更新/最大工具迭代/默认工具模式)、界面(语言/主题/工作区行为/加载文案/平滑流式/提示音)、代理、工具启用、自动执行、文件工具(读/写工作区外访问、list/find/search 忽略与排除模式、apply_diff、history_search)、命令与沙箱、系统提示词(模式切换/自定义前后缀/动态模板)、上下文感知、记忆、对话总结、检查点、Token 计数、图像生成、技能(开关/移除)、子代理(全局配置 + 启用开关)、固定文件(开关/移除/添加)、远程控制(端口/启停)、数据存储与依赖环境(只读展示);响应侧脱敏:apiKey 抹为占位串、base64 音频资产删除、代理 URL 内嵌凭据打码,敏感字段绝不回写桌面端。 - 渠道管理补齐:渠道列表新增「设为当前渠道」(
settings.setActiveChannelId)与启用/停用开关(config.updateConfig);/api/status携带activeChannelId供移动端标记当前渠道。 - 新增 REST 端点(沿用既有 Host/Origin/JSON-only 安全基线 + 形状白名单):
GET /api/fs|settings|tools|dependencies、POST /api/settings|channel-toggle|channel-active|remote-action。
Fixed(1.7.10dev 补记)
- 远程控制切换工作区失效:此前一律透传
workspace.setActive——对「仅收藏、未在当前窗口打开」的工作区,WorkspaceManager 会静默无操作(不匹配列表直接 return),手机上表现为点击无效。现按目标分流:已打开 →workspace.setActive固定;仅收藏 →workspace.openFolder { fsPath }由宿主直接打开并自动固定(与桌面端「打开收藏工作区」同路径);两处都没有 → 404 明确提示。 - 远程控制设置项不完整(只有渠道):设置页仅含连接状态/渠道模型/安全说明,其余桌面端设置项无法在手机上查看或修改;已按上方 Added 补齐全部设置项(含密钥脱敏读写)。
[1.7.9dev] - 2026-08-10
Added
- 远程控制(桌面版):设置页新增「远程控制」页签(
remoteControl配置,按机器保存,默认关闭):- 启用后在局域网内监听自定义端口(1-65535,默认 17532),提供移动端友好的自包含控制页(零外部依赖,随服务器懒加载——关闭时服务器与 UI 完全不存在,不占任何资源);
- 手机上可查看/切换会话、发送消息、停止生成、重命名会话,实时流式输出(SSE);桌面端自身的会话流式输出也会镜像到手机;
- 移动端以
remote-control客户端身份接入现有 MessageRouter,与桌面端同一消息管道(chatStream/cancelStream/会话管理等全部复用既有校验与工具循环); - 安全基线:默认关闭(opt-in)、仅局域网可用;Host/Origin 校验(防 DNS rebinding 与跨站写滥用)、POST 仅接受 application/json、消息/请求体长度限制、会话读取只允许已存在会话(防穷举建目录磁盘 DoS)、SSE 并发上限 8 + 空闲超时;设置页展示本机全部局域网地址与安全说明;
- 端口/开关变更即时生效(设置变更监听 → 启停/重启服务器),监听失败(端口占用等)在设置页提示并可一键重试;
- 搜索覆盖:设置搜索索引新增远程控制条目(启用/端口/访问地址/安全说明 4 个锚点),三语言(en/zh-CN/ja)文案齐全。
Fixed
- 远程控制设置页 i18n 键路径错误:组件文案键误写为
components.settings.remoteControlSettings.*,实际语言包层级为components.settings.settingsPanel.remoteControlSettings.*——t()找不到翻译时返回原始键名,设置页整页显示键名。已修正组件与设置搜索索引中的全部引用,并新增RemoteControlSettingsI18n回归测试(静态提取组件全部t()键,逐一校验 zh-CN/en/ja 三语言包存在且为字符串),防止再次出现「键名漏译」。 - 远程控制访问地址过滤虚拟网卡:局域网地址列表此前会展示 Hyper-V/WSL/Docker 等虚拟交换机(vEthernet)的内部 bridge 地址(如 172.x.x.x)——这些地址仅对本机虚拟网络生效,手机等局域网设备不可达,展示没有意义。
computeLanUrls现按网卡名过滤虚拟适配器(vEthernet/docker/wsl/hyper/vmnet/vmware/vbox/virtual),仅展示真实局域网网卡(WLAN/Ethernet 等)。
[1.7.8] - 2026-08-10
Added
- 聊天输入区「思考强度」快捷下拉框(桌面版/插件公共前端):位于输入区左下角模型选择器旁,选项覆盖设置页全部档位、不做裁剪(文案保持英文不翻译,即各 API 的原始取值)。下拉框与设置页写同一份渠道配置(
config.updateConfig),双向联动:- openai / openai-responses →
Off / none / minimal / low / medium / high / xhigh / max / ultra / custom,映射options.reasoning.effort(闸门optionsEnabled.reasoning同步开关); - anthropic →
Off / low / medium / high / xhigh / max / ultra / custom,映射options.thinking.type + effort(档位写入强制 type=adaptive——effort 仅该模式经output_config生效,budget_tokens/display等其余字段保留); - gemini →
Off / minimal / low / medium / high,映射options.thinkingConfig.mode=level + thinkingLevel(default/budget 模式按中档展示); - Off 语义(关闭思考):openai 系 / gemini 关闭对应闸门(
optionsEnabled.reasoning/thinkingConfig = false);anthropic 显式写thinking.type = 'disabled'(闸门保持开启,后端请求显式携带{"thinking":{"type":"disabled"}},formatter 新增 disabled 分支,设置页思考模式选项同步新增「关闭 (Disabled)」,三语言文案齐全); - none 语义(仅 openai 系):思考保持开启(闸门 true)但
effort = 'none'——后端 formatter 对'none'不发送reasoning.effort参数(不传递思考强度参数),与 Off(整体关闭思考)严格区分; - 下拉选择后设置页即时刷新(新增
settingsStore.configsVersion版本信号,ChannelSettings 监听重载);新增utils/thinkingLevel.ts纯映射模块与 24 个单测(含全档位列表、Off/none 语义区分、精确读写映射、写入更新构建、文案不翻译断言)。
- openai / openai-responses →
Fixed
- 思考强度下拉框 1.7.8 初版修正:初版仅提供 Off/Low/Medium/High 四档(档位被归并,设置页 none/minimal/xhigh/max/ultra/custom 等档位无法在快捷下拉中精确保留,选择一次即被覆盖),且 Off 与 openai
none语义混淆。已修正:按渠道提供与设置页一致的完整档位列表(精确读写、不归并);Off/none 语义严格区分(none = 完全不传递思考参数:请求缺省该段,模型按 API 默认行为思考;off = 强制传递禁用参数{"thinking":{"type":"disabled"}}——anthropic 显式写thinking.type='disabled'、gemini 显式写thinkingConfig.includeThoughts=false(Gemini 缺省即思考,必须显式 false 才真正关闭)、openai 系关闭闸门后请求强制携带{"thinking":{"type":"disabled"}}且不传递任何 effort(缺省 reasoning/thinking 段时模型仍按默认行为思考,只有显式禁用才真正关闭));设置页思考模式/思考强度描述同步更新(en/zh-CN/ja 三语言)。 - 任务栏固定图标启动丢失持久化(桌面便携版):任务栏「固定到任务栏」记录的是运行中进程的 exe 路径——便携版运行的是解压缓存里的内层 exe(
%TEMP%\GrayCode-Portable\GrayCode.exe),explorer 直接启动它时拿不到 NSIS 启动器注入的PORTABLE_EXECUTABLE_DIR,resolveUserDataDir回退到%TEMP%\GrayCode-Portable\data(临时目录,表现为全新应用、数据「丢失」)。修复:每次经启动器正常启动时,把外层便携 exe 所在目录写入解压缓存内的指针文件gc-portable-home;内层 exe 被直接启动(固定图标等)时读取指针回填PORTABLE_EXECUTABLE_DIR,userData 解析、安装形态判定(getInstallerKind)等下游逻辑与正常启动完全一致。设计约束不变:不写%LOCALAPPDATA%等固定位置标记,数据仍在<便携 exe 目录>\data(exe + data 可整体拷走);多实例能力不变(经启动器启动的各副本仍以各自环境变量为准,指针仅服务内层 exe 被直接启动的兜底场景,且每次正常启动都会刷新);安装版/zip 版无gc-cache-key标记不受影响;--user-data-dir/GRAYCODE_USER_DATA_DIR显式覆盖优先级不变。新增portable-home.ts纯模块与 9 个单测。 - 设置页草稿输入(合入上游 PR #31):
- 数字输入清空后延迟回填默认值:编辑期间清空保持为空(不保存不回退),输入有效数字立即保存,离开设置页时仍为空的输入框自动回填最后保存的值(新组合式函数
useDeferredNumberInput,覆盖工具-最大调用次数/图像生成批量/上下文深度/存档点/总结/渠道超时与 token/重试/渠道选项数字/分支保留期/提示词条目名称等输入框); - 草稿输入边界修复:严格数字格式校验(拦截
2./.5/1e3等中间值提交)、maxBatchTasks/maxImagesPerTask/maxCheckpoints校验器收紧、keepRecentTokens清空恢复内置默认、useBranchCleanup拦截空串误存 0、ChannelSettings.updateConfigField(s)await 前捕获 configId(防往返期间切渠道污染新渠道本地配置)、PromptEntriesEditor清空自定义名称离开时回填最后提交值(忽略 IME 合成中间态); - 聊天输入框占位符由
::before文档流实现改为绝对定位浮层(不占布局空间),清空输入后光标回到占位符文本之前。
- 数字输入清空后延迟回填默认值:编辑期间清空保持为空(不保存不回退),输入有效数字立即保存,离开设置页时仍为空的输入框自动回填最后保存的值(新组合式函数
- deleteMessage / deleteSingleMessage 后端索引越界兜底(合入上游 332a5a6b):前端窗口可能包含后端并不存在的尾部消息(流式异常后 localOnly 标记丢失、数据文件被外部修改后前后端不一致),按前端索引走后端删除会命中
INVALID_TARGET_INDEX直接拒绝。修复:backendIndex >= totalMessages时降级为本地删除(与 localOnly 占位同一路径),不再请求后端;新增 4 用例回归测试。
Other
- 上游增量合并说明:本次合入上游
be43158..fc34ff0e中的 3 个通用修复(f1f4f7ca数字输入草稿模式 + 占位符浮层、b1cf5ad7草稿输入边界 + 渠道切换竞态防护、332a5a6b删除索引越界兜底),均经逐文件语义核验(与本地既有改动比对,无重复实现/无破坏本地修复);nightly 更新渠道相关提交(71a7e893nightly 渠道功能、58a49f0enightly 渠道审查修复、fc34ff0enightly-build.yml 注释同步)暂不引入——本地打包仍以「用户需自行准备 electron 环境」为准,nightly 渠道后续另行支持。
[1.7.7] - 2026-08-09
Fixed
- 关闭开屏动画后仍闪现 1-2 帧 Splash 动画(桌面主窗口):桌面主窗口直接加载
frontend/dist/index.html、没有__GRAYCODE_STARTUP_SPLASH_ENABLED同步注入,App.vue的splashActive走settingsStore.splashEnabled——该值此前默认true,需等getSettings往返完成后才被setSplashEnabled(false)纠正。首帧静态画面(#gc-boot)已被gc-splash-disabled标记(boot-splash.js)正确抑制,但 Vue Splash 组件仍会挂载并播放动画直到配置返回,表现为「关闭动画仍闪现 1-2 帧」。修复:settingsStore.splashEnabled初始值与首帧静态画面读取同一个 localStorage 标记gc-splash-disabled(readInitialSplashEnabled,隐私模式等不可用时回退默认开启),首帧决定与静态画面严格一致——关闭动画的用户从第一帧起完全不渲染 Splash;新增初始化标记回归测试(settingsStore.test.ts)。webview 宿主(有同步注入快照)首帧走注入值、不受影响。
Performance
- 启动提速批次③(桌面与 webview 共用前端):
chatStore.initialize启动链去重 + 并行:删除重复的config.getConfig请求(loadSavedConfigId内部已调用loadCurrentConfig);loadSavedWorkspaces/loadSavedConfigId/loadCheckpointConfig/loadConversations四个互不依赖的 IPC 改为Promise.all并行(各写独立 state 字段,应答经 per-request 响应处理器送达、无消息路由竞态)——串行 6 跳 IPC 降为约 2 跳;App.vueonMounted 并行初始化:chatStore.initialize()与loadLanguageSettings()无数据依赖(各写独立 store),改为并行启动(initialize 内部监听在调用瞬间同步注册、IPC 应答不受命令监听器注册顺序影响),关闭开屏动画用户的「专属占位」结束点由「两条链之和」提前为「两条链之较慢者」;- 工具声明热路径免全量克隆:
ToolDeclarationResolver.settingsFingerprint每次工具循环迭代都经getSettings()深拷贝整份设置(含全部 prompt 模板等大字符串对象)只为计算指纹;SettingsCore/SettingsManager新增getSettingsRaw()内部只读裸引用访问器(仅限只读热路径,外部仍走深拷贝语义防污染),指纹计算改走裸引用(测试 mock 无该方法时回退getSettings); - TaskManager 泄漏兜底接线:
cleanup()此前设计完成却无任何调用点(已取消却未注销的任务永久驻留activeTasks);registerTask惰性启动 unref 的 5 分钟周期清扫定时器(不阻止进程退出、无任务时零开销)。同时修正清扫语义:只补发「已 abort 却未注销」任务的 cancelled 终态,不再按驻留时长强杀——合法长任务(长终端命令/后台子代理 run)可能运行数小时,按 30 分钟阈值伪造 cancelled 会丢失真实完成事件; - 死代码清理:
frontend/src/utils/format.ts(formatRelativeTime/truncateText/sleep/isEmpty/deepClone/debounce/throttle)、chatStore(removeStoreAttachment/clearStoreAttachments/dequeueMessage)、settingsStore(isVisible/hideSettings)、utils/vscode.ts(clearState)、backend/tools/index.ts(initializeToolSystem/refreshToolDependencies)、execute_command.ts(onTerminalTaskEvent/getEnabledShellTypes)——全仓库(含测试)零引用,删除无行为影响; - 桌面渲染层资源注入并行(electron-app):theme.css / codicons / overlay.js 三次注入的文件读取改
Promise.all并行(注入操作本身仍按 keyName 隔离串行),省两次跨进程 IPC 往返。
[1.7.5.2dev] - 2026-08-09
Added
- 更新检查按发布通道隔离(
UpdateChecker):releases/latest按创建时间返回,dev release 晚于 stable 创建时会把正式版用户引到 dev 通道(反之亦然)。改为一次拉取全部 releases(per_page=30)并在通道内按版本号取最高:版本号含dev后缀(resolveReleaseChannel)归 dev 通道、其余归 stable 通道;dev 通道无候选时回退全部 release。上游/历史 tag(dev、dev-1.7.1)版本解析恒 0,天然不参与竞争。 - 一键更新按运行形态匹配安装包(
pickInstallerAsset):便携版运行时由patch-portable.mjs注入PORTABLE_EXECUTABLE_DIR,BackendHost注入getInstallerKind;便携用户优先下载GrayCode-Portable-*.exe(不再被拉进安装版污染系统环境),安装版用户优先GrayCode.Setup.*.exe,无匹配回退 zip。 - 版本比较支持 dash/点号双形态(
normalizeVersion):electron-builder 只接受合法 semver,四段版本被塞进 prerelease(1.7.5-2dev↔1.7.5.2dev、1.7.6-1↔1.7.6.1);比较前统一归一化,dash 构建号不再丢失(1.7.5-3dev > 1.7.5-2dev可识别);非数字预发布(-beta等)仍判为旧并按标识字符串排序。
Fixed
- 输入框 IME 撤销栈污染:合成期间每个拼音键的 input 事件不再入历史栈(
isComposing跳过),合成结束(compositionend)补推最终态一次;重复条目(收尾 input + compositionend 双推、Esc 取消合成)在pushHistory去重。发送成功/切换会话等外部清空时撤销栈同步复位,杜绝 Ctrl+Z 恢复已发送草稿。 settleFunctionResponses二次全历史扫描:BR-08 归属消息定位并入首趟索引构建(functionCallLastIndex),长会话多工具轮次扫描系数下降,语义等价(577 测试背书)。- 死代码清理:
StreamRequestHandler解构残留annotation/annotationMessageId(批注机制已删除);modeToolsPolicy.getReadonlyModeDangerousTools零调用且与GENERAL_FILE_WRITE_TOOLS口径不一致,删除。 - 后端默认声音设置补齐
subagent分组(generalTypes):前端 normalize 已有兜底,后端默认值补齐防导入导出/严格校验丢键。
Other
- 同步上游 e75cfd8..be43158(21 commits,按模块取优合并):启动画面系列(StartupBackdrop 石墨占位 + startupBootstrap 首帧注入;桌面主窗口无同步注入时保留本地 1.7.6 响应式门控,关闭开屏动画用户不回归全动画)、输入框自定义撤销/重做栈(粘贴后 Ctrl+Z 可靠)、工具确认批注移除(点击执行不再自动发出输入栏文字,待确认工具时发送改为中断回合)、Plan 渠道一次性覆盖(
pendingConfigIdOverride)、后端并行工具调用竞态修复(孤儿调用剔除/迟到结算归位/drain 超时 cancelled 占位)、子代理提示音独立控制、agent 模式权限加固、最近对话删除+渠道改进、思考回传统一、恢复默认模板{{}}占位符;冲突处按本地/上游实现优劣取并集(findFunctionResponseInsertIndex接本地已重构的模块级函数、StreamRequestHandler保留本地INVALID_CONVERSATION_ID校验)。CHANGELOG 保留本地版本体系。
[1.7.6.1] - 2026-08-09
Fixed
- 自动应用 diff 后高频弹出「diff is no longer pending」错误提示且无法关闭(
ToolMessage双自动接受竞态):- 根因:后端
DiffManager(diff 创建时调度)与前端ToolMessage倒计时(statusChanged 广播到达后调度)各持一个同autoSaveDelay的自动接受定时器——后端定时器总是先到点,前端倒计时到点再发diff.accept必然命中DIFF_NOT_PENDING(或DIFF_ACCEPT_FAILED),随后弹出 10s 自动消失的 error toast;自动应用 diff 后高频复现(用户痛点:弹窗无法手动关闭,只能等超时); - 修复一(根因):前端倒计时改为纯展示——到点不再发送
diff.accept,后端定时器是唯一权威(创建更早、必然先到点,接受后经diff.statusChanged广播终结前端倒计时),竞态从源头消除; - 修复二(兜底):
confirmDiff/rejectDiff/ 变更查看面板diffStore.act对DIFF_NOT_PENDING按良性终态处理——diff 已被自动应用/其他入口结算,本地立即结算 UI(按钮消失、错误态清空),不再弹错误提示; - 新增回归测试:变更面板
DIFF_NOT_PENDING不残留错误提示、非该错误码仍保留行内错误(diffViewerStore.test.ts)。
- 根因:后端
- 「Diff is no longer pending.」等 diff 错误文案未多语言化:
DiffHandlers的DIFF_NOT_PENDING/DIFF_ALREADY_PROCESSING/DIFF_ACCEPT_FAILED/DIFF_REJECT_FAILED全部硬编码英文,前端ToolMessage的兜底文案(未找到待处理差异 / 接受失败 / 拒绝失败)同样硬编码;已全部接入webview.errors.*/components.message.tool.*三语字典(zh-CN / en / ja)。 - 窗口标题「GrayCode — No workspace」未多语言化:无工作区时窗口标题的占位文案硬编码英文;现经
menu-i18n.ts新增windowTitleNoWorkspace键(zh-CN「未打开工作区」/ en「No workspace」/ ja「ワークスペース未選択」)随界面语言显示(有工作区时仍显示文件夹名,不翻译)。
[1.7.6] - 2026-08-09
Fixed
- 「未打开工作区」提示不再抢在开场动画之前弹出:
- 根因:
webviewReady握手(BackendHost)与工作区恢复失败路径(main.ts)都在渲染层就绪瞬间发送host.noWorkspace命令,早于 Splash 动画结束,toast 直接盖在开场动画上; - 修复:渲染层在动画淡出后(或用户关闭动画时立即)上报
splashDone信号,BackendHost 将「未打开工作区」/首启欢迎提示积压到该信号到达后再发送(20s 超时兜底,渲染层异常也不会丢提示);发送时重查工作区列表,避免恢复路径已完成时误提示;main.ts 恢复失败路径不再重复发送(与握手路径去重); - 提示文案同时本地化(zh-CN / en / ja,跟随界面语言)。
- 根因:
- 工作区恢复失效回归(1.7.5 懒加载引入):1.7.5 启动提速把
createBackend改为动态懒加载,但「恢复上次工作区」仍放在createWindow内执行——此时backendHost还是 null,恢复被静默跳过(实测启动后工作区列表为空、且必弹「未打开工作区」提示)。修复:恢复逻辑抽为restoreWorkspace(),改在 BackendHost 就绪后(createBackend的懒加载回调内)执行,恢复只跑一次且早于渲染层 splashDone,不会再出现「恢复已完成却仍提示」的时序问题。 - 文件夹选择对话框暴露 i18n 键名
dialogs.selectFolder:WorkspaceHandlers.openWorkspaceFolder的showOpenDialog传参把t('dialogs.selectFolder')写成了缺webview.前缀的键,缺失回退直接返回键名字面量,标题/按钮上显示原始 key;已修正为t('webview.dialogs.selectFolder')/t('webview.dialogs.openWorkspaceFolder')(与 StoragePathHandlers 写法一致)。 - 应用菜单(File / Edit / View / Help)未多语言化:Electron 原生菜单此前全部硬编码英文,无论界面语言怎么选都保持 English;现主进程引入独立小字典
electron-app/src/menu-i18n.ts(zh-CN / en / ja),顶层菜单与全部下拉项、File 菜单的文件夹选择对话框、About 对话框均跟随界面语言;启动时读取设置文件中的graycode.ui.language(auto 回退系统 locale),语言切换时由渲染层上报app.setMenuLanguage即时重建菜单,无需重启窗口。 - 语言切换后部分 UI 冻结在旧语言(工作区选择器标签等):
- 根因:
t()有按 key 的翻译缓存,且缓存命中时短路返回、不读取响应式currentMessages。组件内先求值的计算属性(如 tooltip)写入缓存后,后求值的计算属性(如.ws-label标签)首次求值走缓存短路——丢失对语言切换的响应式依赖,之后语言无论怎么切,标签都冻结在首帧语言(实测:切到 English/日本語 后「未打开工作区」仍不更新,观感如同漏译); - 修复:
t()在查缓存前先读取currentMessages(命中缓存也建立响应式依赖;开销仅一次 computed getter,currentMessages只在语言变化时重算,热路径无额外负担); - 新增回归测试(
i18nReactivity.test.ts):按真实组件的求值顺序(tooltip 先求值写缓存 → label 后求值读缓存)复现,zh→en→ja 切换下计算属性标签必须跟随。
- 根因:
- 启动首帧语言错位(保存 English/日本語 的用户首帧看到中文):
- 根因:界面语言只在
getSettings往返完成后(languageLoaded)才应用,此前渲染层按默认/auto 语言渲染首帧(工作区选择器、欢迎面板等); - 修复:
i18n模块启动时从 localStorage(gc-ui-language,语言成功应用时写入)同步恢复界面语言——首帧即用已保存语言渲染,与gc-splash-disabled同模式,零异步开销、不影响启动速度。
- 根因:界面语言只在
Added
- 设置页「通用」新增「工作区行为」(
ui.workspaceBehavior,默认restore):restore(默认,保持原行为):启动时自动打开上次关闭界面时打开的工作区;none:启动时不打开任何工作区(跳过恢复,也不再弹出「未打开工作区」启动提示)。
Performance
- 本批次未触碰启动路径的热点代码:菜单语言解析为设置文件单次同步读取 + 渲染层一条轻量 IPC;
splashDone为渲染层单向上报信号(宿主回 success 应答但不被渲染层 await),不影响启动流水线(实测窗口出现/后端就绪时长与 1.7.5 一致)。
[1.7.5] - 2026-08-08
Fixed
- 更新检查修复:禁用「自动检查更新」后手动检查失效(
UpdateChecker.check):- 根因:
checkForUpdates=false时check()顶部的isCheckEnabled()闸门无条件拦截,手动检查(force=true,设置页「立即检查 / 一键更新」)同样被短路为disabled且不发任何请求——设置页点「立即检查」表现为「没反应」; - 修复:
force=true绕过该闸门——开关(checkForUpdates)只约束启动时的自动检查(10s 定时器走 force=false),手动检查始终可用;updateNow的 disabled 分支保留为防御性兜底; - 新增回归测试:关闭自动检查 + force 手动检查仍发起请求并正常推进状态机(updateChecker.test.ts)。
- 根因:
Performance
- 便携版 exe 解压缓存(实测:二次启动 3.0s → ~0.5s,首次启动不变):
- 根因:便携版(NSIS 自解压)每次启动都把 ~95MB LZMA 载荷解压到 %TEMP% 再运行、退出后整目录删除——解压占启动耗时大头(本机实测 2.27s / 总 3.0s);
patch-portable.mjs给 electron-builder 的 portable.nsi 模板打「缓存优先」补丁:首次启动解压到固定目录(portable.unpackDirName = "GrayCode-Portable")后写入gc-cache-key(内容 = 本次构建随机 build ID);再次启动命中缓存(应用文件存在且 build ID 一致)→ 跳过解压直接运行,退出不再删除缓存;exe 被替换/重新下载(build ID 变化)→ 自动失效重解压。载荷仍为 LZMA 压缩,便携版体积不变(81.5MB);- 实测(同机):冷启动解压 ~2.3s / 窗口 ~3.0s;缓存命中后进程启动 ~90ms / 窗口出现 ~0.5s;
- 解压算法对比实测:LZMA 95MB/解压 2.27s、store 313MB/1.59s、zip(DEFLATE) 130MB/2.0s——store/zip 提速有限且体积翻倍(3.3×/1.4×),故保持 LZMA 体积 + 缓存方案;
- CI 与
dist:win脚本同步接入patch:portable(幂等:先还原模板备份再打补丁,模板与预期不符时构建直接报错,不静默产出未优化启动器)。
- 主进程三包拆分 + 后端懒加载(应用层启动提速)(
build.mjs):- 原单包 main.js 1.71MB 内联整个 backend + webview 路由,启动路径全量解析执行;现拆为 main.js(323KB 主进程壳)/ host/BackendHost.js(1.55MB 后端宿主)/ vscode-shim.js(31KB 共享实例),
createBackend改为动态import('./host/BackendHost.js')懒加载,when-ready 前不再解析 ~1.2MB 后端代码; - vscode-shim 独立成包保证主进程壳与后端宿主共用同一实例(windowFocused / memento 存储状态不双份漂移);e2e / monitor-smoke 动态导入路径同步适配;
- 渲染层消息在 BackendHost 就绪前缓冲、就绪后补投(消除窗口先于后端加载完成时的丢消息窗口);懒加载失败弹窗兜底退出,不静默挂起。
- 原单包 main.js 1.71MB 内联整个 backend + webview 路由,启动路径全量解析执行;现拆为 main.js(323KB 主进程壳)/ host/BackendHost.js(1.55MB 后端宿主)/ vscode-shim.js(31KB 共享实例),
- 渲染层拼写检查关闭(
BrowserWindowwebPreferencesspellcheck: false):应用无拼写检查功能,省渲染进程词典初始化开销(渲染进程启动提速)。
[1.7.5.1dev] - 2026-08-08
Performance
- 启动提速批次 ②(便携版 exe 启动 3s+ → ~2s,加载链路全面提速):
- 首帧启动画面(
boot-splash.html+patch-dist.mjs):纯静态 HTML+CSS(无 JS)注入 index.html<body>开头,窗口第一帧即显示 Splash 同款动画,消灭「纯色背景等待 ~1.3MB index.js 解析挂载」的空窗;Vue 挂载后按__GC_BOOT_TS以负延迟(--gc-boot-offsetCSS var + SMIL begin 回拨)无缝续播并移除静态画面,动画时间轴无跳变;bootSplash.test.ts比对双份路径/时长/文案防漂移。 - 关闭启动画面时首帧不再闪现动画:
splashEnabled=false时settingsStore.setSplashEnabled写入 localStorage 标记gc-splash-disabled,boot-splash.js在<head>(早于 body 解析)读取并给<html>加gc-no-splash类,CSS 直接不渲染#gc-boot——关闭动画的用户窗口第一帧直接进主界面,不再被静态动画覆盖到 Vue 挂载。 - Splash 时间轴 1.8s 叙事版(
Splash.vue,曾尝试 1.4s 速播,节奏过赶已回退):描线/上色/定影/标题/格雷码线全时间轴按 1.8s 编排(格雷码线周期 1.0s、延迟 0.65s),归一并淡出 0.7s,最短总展示 1.8s(加退场两拍共约 2.5s);CSS 动画、SMIL 笔尖光点与 JS 常量严格同步,Splash.test.ts常量同步更新。 - getSettings 快速通道(
BackendHost.ts):启动画面 ready 信号(前端languageLoaded)原本要等完整后端初始化(checkpoint/MCP/memory/activity/dependency + 工具注册),现 settingsManager 第一步就绪即应答(响应形状与SettingsHandlers.getSettings完全一致),UI 提前数百 ms 退出启动画面;其余消息仍排队等完整初始化,行为不变。加固:settingsReady 异常时 30s 兜底超时按错误应答(避免前端挂到 180s 兜底),错误形态与 webview 路径统一(外层 error,前端走 catch)。 - 打包产物裁剪 locales(
electron-app/package.json):electronLanguages限定 en-US/zh-CN/ja,未打包产物 locales 48.9MB→1.9MB,便携版 exe 98.4MB→81.5MB,每次启动解压负载下降(此前 48.9MB locales 全部打进产物但从未使用)。 - 冷缓存同步探测超时 3s→1.5s(
execute_command.ts):磁盘缓存失效(>24h)时 wsl --status / where / which 单次探测最坏阻塞减半;缓存命中路径不受影响。 - 启动阶段计时诊断(
main.ts/BackendHost.ts):GRAYCODE_DIAG=1时输出 when-ready/window-shown/did-finish-load/backend-ready/settings-loaded/tools-registered/backend-initialized 各里程碑耗时到 stdout,便于后续定位启动热点。 - bootSplash 一致性测试修复:时间 token 子集校验原取
matchAll的m[1](无捕获组恒为 undefined,校验空转),改为m[0]且只扫<style>块(注释/文案里的数字不再误报),双份时间轴漂移防线恢复生效。
- 首帧启动画面(
[1.7.5dev] - 2026-08-08
同步上游
- 同步上游 Komeiji-Shiki/Gray-Code 25 个提交(962d496..8ed8739):20 个本地适配 commit 按模块合入(checkpoint 并发锁/mcp 客户端健壮性/settings 持久化/conversation 分支去重/memory 覆盖块语义/chat 工具执行健壮性/subagents 模型继承与重试/模块健壮性/总结保留预算/配置导出键/思考强度档位/后台回执提前投递/formatter 与 regexGuard 修复/webview 处理器加固/前端缺陷批次),其余(确认门 this 绑定/CI 构建体系/未用导入/文档)本地已有等价或更优实现保留本地;上游 SHA 经 -s ours 记录消除 fork behind 计数。
- 思考强度档位扩展 + 消息统计 TTFT(上游 15125ef/2e0704a):anthropic/openai/openai-responses 渠道支持 max/ultra/custom/minimal 档位,custom 原样透传;StreamAccumulator 计算首字延迟 TTFT 写入 Content,TPS 计算剥离首字时延,MessageItem 展示。
- 后台任务回执动作边界提前投递(上游 d9d6369):LLM 动作边界(取消回合/换回合)立即投递回执,不再硬等模型回合结束。
- 总结保留预算修复(上游 962d496):keepRecentTokens 基数改为规划范围内活跃历史 token 总量(默认 50%),修复长对话总结后上下文被压光;滚动条新增总结截断点标记。
- checkpoint / mcp / settings / conversation / memory / chat / subagents / modules 健壮性修复批次(上游 6cd1330/cddf515/fc2c855/e57a657/c713154/5e8f666/63676f2/858e624/2a37702/6d4bb95/c0cf55f/171dc86):并发锁唯一化与孤儿保护/协议头优先与绝对 deadline/写队列串行化与深合并/分支并发去重与 detached 保留/覆盖块语义与损坏容错/abort 竞态与模型继承/告警节流与导出键修复等,详见各适配 commit。
- webview 处理器加固与前端缺陷修复批次(上游 05550ca/b0fb1f5/89c64c9/2a4f222):handler 鸭子分支清理与输入校验/删除二次确认与重命名并存/标签页快照绑定/历史分页空页上限/formatNumber 非有限数防护/CHANGELOG 解析支持字母预发布(1.7.2dev 格式)。
Added
- 用户可修改对话标题(1.7.4):
- 历史页/首页对话列表悬停新增「重命名对话」按钮(
ConversationList.vue),复用InputDialog弹窗;支持 Enter 确认、Escape 取消。 - 新增 store action
renameConversationTitle(conversationActions.ts):trim 校验 →conversation.setTitleIPC(后端ConversationManager.setTitle早已存在,写 meta.json 并原子提交)→ 成功后同步本地列表标题、updatedAt与已打开标签页标题(updateTabTitle);空白/未变化标题不发 IPC,失败保持原状并写入 store error。 - 新增回归测试:
conversationActions.test.ts重命名 4 例(成功同步标签页 / 空白与未变化跳过 / 不存在对话 / IPC 失败保持原状)。
- 历史页/首页对话列表悬停新增「重命名对话」按钮(
- 设置页「自动执行」给 Diff 审阅类工具提供「自动批准」开关(1.7.4):
write_file / apply_diff / insert_code / delete_code原先只显示「差异审阅管理」徽标、无任何可操作控件;现徽标旁新增真实开关(AutoExecSettings.vue),状态读写「应用diff 设置」的autoSave(四个工具共用同一开关),并显示「自动批准 / 需确认」状态文字;切换即通过tools.updateApplyDiffConfig持久化。
- 设置页子菜单折叠(1.7.4):
- 「自动执行」与「工具」页签的分类子菜单(文件操作/搜索/终端/…)头部可点击折叠/展开(
AutoExecSettings.vue/ToolsSettings.vue),折叠时显示 chevron-right 图标、收起分类内工具列表;状态为组件会话内记忆,不持久化。
- 「自动执行」与「工具」页签的分类子菜单(文件操作/搜索/终端/…)头部可点击折叠/展开(
Fixed
- 沙箱工具描述与分类汉化(1.7.4):
- 工具管理页/自动执行页的 sandbox 工具描述此前缺失
toolDescriptions.sandboxi18n 条目,回退显示后端英文声明;现三语(zh-CN/en/ja)补齐(内容与工具声明对齐:隔离临时目录/超时杀进程树/输出上限/语言列表/按需确认)。 - 工具管理页沙箱分类名缺失
toolsSettings.categories.sandbox条目(自动执行页的autoExec.categories.sandbox一直存在):工具页、子代理设置、提示词设置页的沙箱分类标题显示原始 i18n key(components.settings.toolsSettings.categories.sandbox)——即「工具页面沙箱未汉化」的真正残留;三语补齐。
- 工具管理页/自动执行页的 sandbox 工具描述此前缺失
- apply_diff 汉化统一为「应用diff」(1.7.4):中文界面中工具显示名、工具注册表 label(工具消息卡片标题,
utils/tools/file/apply_diff.ts)、消息卡片标题、审阅面板标题从「应用差异」/英文混排统一为「应用diff」;自动执行页徽标文案「Diff 审阅管理」→「差异审阅管理」、提示与 tooltip 中的 "Apply Diff" → 「应用diff」;「Diff 警戒值」→「差异警戒值」;ja 指引文案同步为「差分を適用」。 - 设置搜索补齐 apply_diff 自动应用条目(1.7.4):
SettingsPanel.vue搜索索引新增apply-diff-config条目(锚点[data-search-anchor="apply-diff-config"],位于「工具 → 应用diff → 自动应用开关」区块),关键词覆盖 自动应用/自动批准/auto apply/auto approve/应用diff/跳过差异视图/警戒值 等;tools/tools-list/autoExec条目关键词同步补全。- 搜索跳转自动展开目标工具配置面板:新增
tools/toolConfigFocus.ts展开信号,openSearchResult对apply-diff-config先请求ToolsSettings展开面板再定位锚点(双重 nextTick 保证锚点已渲染),消除「点了没反应」式静默回退到节标题。
- 回归测试:
toolLocalization.test.ts断言更新为「应用diff」并新增 sandbox 描述本地化断言;settingsSearchAnchorConsistency.test.ts反向断言覆盖新锚点。 - 安全加固批次:
- 更新器安装包路径注入修复(
UpdateChecker.downloadAndInstall):远端 Release 的版本号此前直接拼入本地文件名(path.join后writeFile+ 系统打开执行),tag 名含路径穿越序列(如v1.0.0/../../evil)时安装包可被写到更新目录之外并被执行;现下载前校验版本号仅允许[0-9A-Za-z._+-](含 semver 构建元数据+),非法即抛错并走 Release 页兜底。 - 终端工具 cwd 越界守卫(
execute_command.ts):相对 cwd(含工作区前缀解析路径)折叠..后校验必须仍落在工作区内,cwd: '../..'不再把命令工作目录带出工作区(与 write 类工具的工作区外审批策略对齐);盘根工作区(C:\)尾分隔符不再误伤合法相对路径。 - API key 不再明文驻留缓存键(
modelList.ts):模型列表缓存键改为 apiKey/customHeaders 的 sha256 短摘要,明文密钥不再长期停留进程内存(碰撞仅多一次网络请求,无正确性影响)。
- 更新器安装包路径注入修复(
- 健壮性修复批次:
- 上下文预览文件复用过期展示(
FileHandlers.showContextContent):预览文件名带时间戳,同标题二次预览不再覆盖已打开编辑器标签的磁盘文件导致旧内容不重载(与previewAttachment一致)。 - 代理非流式响应 chunked 结束判定 O(n²) 修复(
proxyFetch.ts):每个 data 事件对全部已收 chunks 全量Buffer.concat改为有界 4KB 滚动尾窗(仅含 body,header 解析后初始化),大响应(默认非流式路径 + 本地代理)下不再二次方复制;结束标记判定语义不变(仍只查响应体末尾)。 - 巨型单事件重复 JSON.parse 守卫(
streamBufferParser.ts):单条 SSE 事件(40MB 级 base64 附件)跨包到达时不再对逐渐变长的 currentData 反复全量 parse——超过 4KB 后仅当末尾字符为}/]/"才尝试解析(完成事件必以此收尾,不产生遗漏);final时无条件解析兜底保留。 - 上游错误提取函数消重(
ChannelManager.ts):删除本地私有extractUpstreamErrorMessage,统一复用proxyFetch导出实现(两处此前逐字相同,防止未来一处修复漏同步)。 - mtime 兜底扫描器 dispose 竞态(
usageCache.ts):dispose 后 in-flight 异步扫描不再写已释放缓存对象;reader.cancel()未 await/catch 的潜在 unhandled rejection 修复(proxyFetch.ts)。 - 过时注释修正(
conversationActions.ts):同步工作区注释与「对话内禁止切换工作区」实际语义一致(setActiveWorkspace/openWorkspaceFolderAction不再重绑定)。
- 上下文预览文件复用过期展示(
- 回归测试:
streamSecurity.test.tsmock 补充extractUpstreamErrorMessage真实实现(ChannelManager 消重后保持错误正文提取语义验证)。
[1.7.4] - 2026-08-08
Added
- 对话绑定工作区检查修复批次(1.7.4):
- 文件系统大小写敏感性统一为运行时探测(
webview/utils/fsCaseSensitivity.ts新增):detectFsCaseSensitivity对样本路径做大小写变体探测(变体存在且同 dev+ino → 不敏感),win32 短路不敏感,探测不到时回退平台默认(darwin 不敏感 / 其他敏感)。此前扩展端仅按process.platform !== 'win32'下发fsCaseSensitive,macOS APFS(默认大小写不敏感)被误判为敏感,同一目录以不同大小写路径打开/收藏时固定匹配静默失败。 WorkspaceManager/WorkspaceHandlers(收藏去重、waitForWorkspaceOpened、已打开判定)/WorkspaceUtils.pathsEqual(绑定归属比对)统一使用同一探测口径,消除「运行时探测 vs win32 常量」两套口径互相矛盾的遗留问题(macOS / WSL drvfs 上 URI 漂移误判NOT_IN_CURRENT_WORKSPACE、3s 误超时返回过期状态)。- 进程级共享缓存
getFsCaseSensitivity:首个有效样本探测后固定口径;空列表(Electron 启动早期)返回平台默认且不缓存,列表就绪后自动重探——修复「空列表→平台默认→终身缓存」口径漂移窗口;workspaceList广播携带fsCaseSensitive(前端初始化时列表为空只能拿到平台默认,口径随列表就绪变化时必须随广播同步)。 - 前端
fsCaseSensitive默认值按 webview 宿主平台兜底(win/mac → 不敏感,其他 → 敏感):getWorkspaceListIPC 失败时 Linux 上不再把不同大小写的两个真实目录误合并。 syncConversationWorkspaceUriTOCTOU 补完:await 后「目标会话仍是当前会话」门禁覆盖后端写入——此前仅门禁 store 同步,await 期间用户切换到已绑定对话 B(其激活工作区为 B 的绑定值)时,A 会被错误绑定到 B 的工作区并持久化;现在直接放弃本次同步,切回 A 时重新补绑。写入失败时仅当目标仍是当前会话才回滚展示值,避免覆盖新会话的锁定展示。ConversationManager.createConversation并发去重补绑:并发对同一 ID 建会话时,第二个调用携带的绑定在首个创建完成后补绑(H4 自动建会话与用户建会话并发时用户侧绑定不再丢失),已绑定不覆盖(绑定即终身)。- 新增回归测试:
fsCaseSensitivity.test.ts(平台短路/真实目录探测/共享缓存语义 6 例)、workspaceSync.test.ts切走不写后端用例、ConversationManager.appendAndMetadata并发补绑 2 例。
- 文件系统大小写敏感性统一为运行时探测(
- 移除工作区选择器「保存当前工作区」入口(打开工作区即自动收藏保存,无需显式入口):删除
WorkspaceSelector.vue保存菜单项、前端saveCurrentWorkspaceaction、workspace.saveCurrenthandler 与注册、三语 i18n 键;「打开即保存」逻辑保持不变。
Fixed
- 对话内禁止切换工作区——切换工作区 = 打开绑定新工作区的新对话:
- 移除下拉切换/打开文件夹对当前对话的重绑定逻辑(
setActiveWorkspace/openWorkspaceFolderAction不再调用conversation.setWorkspaceUri)——此前在对话内强行切换工作区会把当前对话重绑定到新工作区,导致标题与绑定错位、绑定失效(本地便携版数据实测:conv_..._2zrlyy标题为「新建文件夹」项目但绑定被改写为另一工作区)。 - 切换工作区统一走
openWorkspaceInNewConversation(tabActions):目标与当前工作区相同 → no-op;当前标签页为空白(未创建对话)→ 直接重定位工作区上下文;已有同工作区空白标签页 → 复用;否则新建空白标签页并切换过去。 - 不堆积保证:切换产生的空白标签页在首个消息前不持久化(后端无对话记录),且同工作区空白标签页复用(每个工作区最多一个);对话列表只显示已持久化对话,切换操作本身不会产生对话堆积。
- 顺序保证:先固定扩展端激活工作区(IPC 不动 store),再切换标签页(快照记录旧工作区上下文),最后设置当前工作区 URI——旧对话标签页快照不会污染为新工作区。
- 历史页/首页「当前工作区」筛选天然展示新工作区下的对话列表(
filteredConversations按currentWorkspaceUri过滤,默认current)。 - 新增回归测试:
workspaceSwitch.test.ts(同工作区 no-op/空白重定位/新建绑定标签/复用防堆积/Auto/IPC 失败/config 层不改写绑定,7 例)。
- 移除下拉切换/打开文件夹对当前对话的重绑定逻辑(
- 对话绑定工作区健壮性修复:
conversation.setWorkspaceUri与ConversationManager.setWorkspaceUri/createConversation增加 workspaceUri 归一化:null/空/空白串 → undefined(解绑 = 跟随活动编辑器),去除首尾空白——此前字面null/脏 URI 会被 JSON.stringify 持久化,破坏下游typeof string判定(记忆隔离、工具工作区路由、checkpoint 裁剪、前端筛选全部失配)。- 后端 H4 自动建会话不再重建已存在的元数据:历史文件缺失但
{id}.meta.json存在时(创建后历史被清理/损坏),保留原标题/绑定工作区/自定义字段,仅补建空历史与用量索引;原元数据未绑定时按 H4 语义补绑当前工作区,已绑定时不被调用方 hint 覆盖(绑定即终身)。此前重建会丢失自定义配置并把绑定改写为扩展端激活工作区,与前端锁定展示不一致。 syncConversationWorkspaceUri修复锁定展示被覆盖 + TOCTOU 竞态:已绑定对话在发起任何异步读取前直接返回(此前先 fetch 扩展端激活工作区再校验,扩展端旧值会覆盖 store 的锁定展示与筛选口径);await 期间会话可能被绑定/删除,写前重新校验;仅当目标会话仍是当前会话时同步 store。- 工作区 URI 匹配口径跨平台对齐:前端
WorkspaceSelector与对话筛选改为按扩展端下发的fsCaseSensitive(仅 Windows 大小写不敏感)归一——此前无条件小写归一在 macOS/Linux 大小写敏感文件系统上会把不同大小的目录误判为同一工作区。 - 新增回归测试:
workspaceBindRepair.test.ts(H4 元数据保留 + 归一化 7 例)、workspaceSync.test.ts(锁定/补绑/回退/竞态 4 例)、WorkspaceSelector 大小写敏感用例。
- 对话绑定工作区锁定 + 下拉切换工作区修复:
- 打开对话必须锁定工作区到对话绑定的工作区:
syncConversationWorkspaceUri不再因绑定工作区暂时未打开(已关闭/切换到其它文件夹)而静默重绑定——「绑定即终身」,避免显示与绑定漂移造成混淆;需要换绑时通过顶部下拉显式切换。 - 切换标签页恢复会话时同步扩展端激活工作区(
restoreSessionFromSnapshot与switchConversation对齐):绑定工作区的对话切回标签页后文件树/工具不再指向不一致;未绑定对话不发送,保持「跟随活动编辑器」不被标签页切换意外固定。 - 顶部工作区下拉(WorkspaceSelector)无法切换工作区修复:
WorkspaceManager.setActiveWorkspaceUri改为 Windows 大小写不敏感匹配,命中时固定列表中的规范 URI——同一目录以不同大小写路径打开/收藏时点击不再静默失败;被固定工作区在列表中的 URI 大小写漂移时自动采用规范 URI。- 请求的工作区未打开时不再解除现有固定(此前固定状态会被清掉,表现为「点了没反应」)。
- 通过下拉打开收藏工作区后,当前对话重新绑定到新打开的工作区——「切换工作区」真正生效,不再停留/悬空在旧工作区。
setActiveWorkspace重绑定使用扩展端返回的规范 URI(避免把大小写漂移 URI 写回对话绑定造成前后端不一致)。
- 下拉展示「锁定」状态:绑定但未打开(关闭)的工作区不再谎报为 auto——触发按钮显示绑定工作区名,菜单显示带锁图标 + 「未打开」标签的锁定条目;「保存当前工作区」入口在绑定未打开时隐藏。
- 补充测试:WorkspaceManager 大小写匹配/锁定语义单测、WorkspaceSelector 组件测试(绑定未打开展示/点击切换/收藏交互/大小写漂移)、tabActions 标签页恢复锁定测试、UI smoke 新增 workspaceSelector 步骤。
- 打开对话必须锁定工作区到对话绑定的工作区:
- 沙箱功能完整化(修复 6ad6805 引入的断点与缺陷):
- 工具声明缓存指纹纳入
toolsConfig.sandbox:在设置页开启/关闭沙箱总开关后,LLM 的工具列表立即生效,不再需要重载扩展(此前开关变更不失效声明缓存,沙箱工具对模型永远不可见)。 - 语言白名单空列表语义统一为「拒绝全部语言」:此前前端把空列表回退显示为全选、执行层回退为全允许,用户取消全部语言反而获得"全部放行",存在安全语义反转;现前后端与执行层一致(空 = 全拒),且前端禁止保存空列表并提示至少保留一种语言。
- 超时/中止杀进程补 SIGTERM 失败升级 SIGKILL:忽略 SIGTERM 的进程不再导致工具调用永久挂起(对照 execute_command 同款兜底)。
- 输出流式累积增加内存护栏(上限 800 万字符,超出丢弃最旧内容并计数提示):巨量输出(如单条 字符打印)不再在截断前撑爆内存。
- Windows 下输出解码接入 UTF-8 → GBK 自动降级(与 execute_command 同一机制),中文脚本输出不再乱码;清理原先从未被调用的死代码解码路径。
truncateOutputLines边界修复(-1返回真实行数、0全部截断);写文件/spawn 失败路径的临时目录清理尊重cleanupTempDir配置;工具声明补strict: true并注明默认需确认。updateSandboxConfig保存时过滤未知语言、钳制超时上限(1000~600000ms),与前端输入范围对齐。
- 工具声明缓存指纹纳入
- LLM 前缀缓存命中率修复(消息插入不再吃缓存):
- 根因:
injectInboxMessages把用户插入 / agent→main 信箱消息注入最近一次工具结果(agentInbox)并随历史落盘;旧实现(HIGH-1)在请求组装时对历史 functionResponse 剥离 agentInbox——同一 tool_result 在当轮请求含信箱消息、跨轮(新真实 user 消息后)被剥离,模型侧内容在回合边界翻转,Anthropic cache_control / OpenAI prefix caching 按字节匹配前缀,从翻转消息起整段缓存失效,消息插入越频繁命中率越低。 cleanFunctionResponseForAPI移除 agentInbox 剥离(顶层与 data 均保留,删除 isHistoryMessage 参数):信箱消息随工具结果常驻历史,发给 LLM 的 tool_result 内容跨回合字节稳定,前缀缓存持续命中;重放代价由 prompt cache 吸收(缓存读远低于重算)。- 子代理路径同步:删除
stripReplayedAgentInboxForModel及其调用——子模型请求历史与落盘一致,同 run 迭代与 continueFromRunId 续跑前缀稳定(DeepSeek user_id / Anthropic user_id 缓存域命中)。 SummarizeService.cleanMessagesForSummarize与主路径统一改用cleanFunctionResponseForAPI:总结请求同样保留 agentInbox(策略一致,总结上下文不丢信箱消息)。- 消息插入功能补齐:
serializeToolResultForLLM文本序列化路径(execute_command 输出 / 批量结果 / 部分成功)此前不含 agentInbox,模型实际看不到插入的消息;新增[Agent inbox messages]文本段(顶层优先渲染,formatResultItem 跳过 agentInbox 键防双份渲染),全部工具结果对模型可见且跨回合字节稳定。 - 回归测试:helpers.test.ts / ConversationManager.agentInbox.test.ts / agentSendMessage.test.ts 更新为「跨轮保留」断言(含跨轮字节一致契约);toolResponseFormatter.test.ts 新增 agentInbox 序列化 5 例;删除废弃的 subagentMailboxReplay.test.ts(H1-4 剥离函数已移除,防止旧语义回归)。
- 根因:
Changed
- 沙箱设置页 i18n 键路径修正:此前组件引用
components.settings.sandbox.*,实际键位于components.settings.settingsPanel.sandbox.*,导致全部文案渲染为原始 key;现已统一,搜索索引 labelKey 同步修正。 - 设置搜索补齐
sandbox-info条目与security/安全等关键词;锚点一致性测试增加反向断言(组件锚点必须被搜索索引收录),防止再次漏收。 - 沙箱设置页「恢复默认」改为获取后端权威默认值(
getDefaultSandboxConfig)并立即保存,消除默认值双源漂移;总开关与保存操作加并发防抖;加载失败文案 i18n 化。 - 工具管理页的沙箱开关接入真实总开关(
updateSandboxConfig.enabled),并新增"详细参数请在设置页配置"提示徽标;三语categories.sandbox/toolDisplayNames.sandbox/ 工具页sandboxHint补齐。 - 新增
SandboxSettings.test.ts(加载/空白名单语义/开关回滚/保存校验/恢复默认/数值钳制)。
[1.7.3] - 2026-08-07
Added
- 沙箱工具(Sandbox):新增
sandbox工具,供 LLM 在隔离的临时目录中安全运行代码片段。- 支持语言:Python / JavaScript / Bash / PowerShell / sh,可通过白名单按需启用。
- 安全防护:独立临时目录(运行后自动清理)、硬超时强制终止进程树、输出行数上限截断。
- 设置面板新增「沙箱」独立栏目,含总开关(默认关闭,opt-in)、语言白名单、超时、输出上限、临时目录清理等配置项。
- 默认需用户确认后执行(与
execute_command一致),可在「自动执行」设置中放开。 - 三语(zh-CN / en / ja)i18n 完整覆盖,设置搜索索引已纳入。
[1.7.2dev] - 2026-08-07
Added
- 手动创建存档点按钮(输入区工具栏 codicon-save):任意时刻保存当前工作区状态。后端
createCheckpoint支持forceCreate(跳过 enabled 开关与工具/消息类型过滤,仍尊重排除规则);webview 新增checkpoint.createManual(绑定当前最后一条消息 + BCP-02 绑定当前分支活跃尾节点);成功/失败三语通知;CheckpointManager/checkpointActions 测试补齐(合入上游 20cad4e)。
Changed
- 同步上游安全加固批次(PR #24 系 + 后续修复,桌面端适配):
- 子代理危险工具确认门:执行前与主链路共用
toolNeedsConfirmation判定,需要确认的工具直接拒绝并把原因以 functionResponse 回流;共享执行服务缺少确认门时 fail-closed 拒绝;空工具集不再被转成 undefined 回退渠道全量工具声明;发送前按渠道maxContextTokens(缺省 128000)×0.8 做请求级上下文裁剪(整轮配对丢弃保首条/末尾、超大字符串截断、lastSentHistory 同步裁剪结果);修正确认门调用丢失this绑定问题(上游 d28adfc 的getToolRejectionReason空指针,本地以方法形式调用修复 + 回归测试) - 流式缓冲上限改为「解析无进展时 64MB 终止(PARSE_ERROR 不可重试)」:合法巨型单事件(多模态 base64 附件 40MB 级)不再被 20MB 硬上限误杀;generateStream 补
formatter.validateConfig(无效配置提前 VALIDATION_ERROR);纯文本错误正文先读text()再JSON.parse(网关 502 HTML 正文不再丢失,本地 status 区间判断保留);streamChunkHasContent纳入 inlineData/fileData(多模态流连接中断不再误判空响应重播整条流);本地单行防护(MAX_SSE_LINE_CHARS)同步抬升至 128MB 兜底语义 - 写队列挂起超时不再放行并发写:四个写队列(withConversationWriteLock / runSegmentedHistoryWriteSerialized / withMetadataWriteSerialized / UsageIndexStore.enqueueWrite)链尾挂在底层任务上,超时仅 fail-fast 调用方、链不前进;挂起计时从任务真正启动开始
- 双文件提交配对一致性:checkpoint files.json/manifest.json 写入带 filesRevision 绑定 + files.json.prev 崩溃恢复(崩溃窗口混合配对可识别并拒绝)
- retry 前截断主历史末尾 model 消息(DeepSeek prefill 400 / 重试接龙):
resolveRetryTruncateIndex只删「最后一个非 model 消息之后的 model 尾巴」,失败流不误删正常回答 - 手动总结单轮对话 STALE_RANGE 放行(仅整个历史一个真实用户回合且为用户主动总结;自动总结保持严格 STALE,首条用户消息保护仍生效)
- 子代理危险工具确认门:执行前与主链路共用
- 前端多模态占位判定统一:
isEmptyAssistantPlaceholder/toolActions/streamChunkHandlers 纳入 inlineData/fileData,仅含多模态附件的 assistant 消息不再被误删;本地独有cleanupFailedSendPlaceholder同步对齐口径 - 编辑用户消息保存后分支切换器立即显示:分支流首输出 chunk 到达时提前刷新分支图(按 streamId 隔离只刷一次),终结时仍消费标记再刷新
.gitignore/.vscodeignore忽略run-logs.zip(本地调试日志不进 git / 不进 vsix)- 代码优化批次(性能 / 质量 / 安全):
- 新增
backend/core/deepClone共享深拷贝工具(structuredClone 优先、JSON 回退),替换 BranchService / runEventBus / executor / ConfigManager / storage / TranscriptMutation / TranscriptRepository / ToolExecutionService 中 21 处JSON.parse(JSON.stringify())热路径深拷贝(消除全量字符串中间体与 undefined 丢失) graycode://自定义协议缓存命中时重新 stat 比对 mtime,rebuild 后不再返回旧 bundlependingToasts(vscode-shim)增加 100 上限驱逐、toolDiffIds(BackendHost)增加 500 上限驱逐,防无界增长- DependencyManager npm install 调试日志改用结构化 Logger(截断 2000 字符),不再向 Extension Host console 输出全量 stdout/stderr
- electron 构建(build.mjs)补
process.env.NODE_ENVdefine,生产构建剔除 dev 代码路径;VitemanualChunks拆分js-tiktoken为独立 vendor chunk,减小主入口体积 - 前端懒加载重试增加 jitter;
clipboard.writeText错误改为 console.warn 记录而非静默吞掉
- 新增
Fixed
- 子代理执行任意工具报
Cannot read properties of undefined (reading 'getToolRejectionReason'):确认门以解绑函数形式调用导致toolNeedsConfirmation内部this为 undefined(上游 9644238 引入);改为方法形式调用,并加 this 绑定回归测试 - 未捕获异常对话框 detail 未脱敏(现经 redactSecrets 处理,与 unhandledRejection 口径对齐)
- IPC
graycode:renderer-to-backend消息 type 字段未做类型校验(现要求 string,强化原有if (!type)守卫) patch-dist.mjs幂等检查改用<!-- graycode-patch-dist -->marker 注释,避免源 HTML 含同名字符串时跳过 CSP / codicons 注入
Tests
- backend jest 242 套件 / 2485 用例通过(含新增 retryTruncateIndex/writeChainHangTimeout/summarizeManualSingleRound/streamSecurity/proxyFetchErrorBody/subagentToolConfirmation/subagentContextTrim 与 ATOMIC-PAIR 用例);frontend vitest 69 文件 / 655 用例通过;tsc --noEmit + frontend vue-tsc 全绿
- fork 同步:上游 9644238 之后 0 commits behind(内容 commit 以适配 cherry-pick 合入,文档/merge commit 以 -s ours 记录 SHA)
[1.7.1] - 2026-08-07
Added
- 桌面端渲染层 native op 白名单(安全收口):
graycode:nativeIPC 仅放行前端实际使用的workspace:pickFolder,剪贴板读写 / 任意路径探测 / shell 打开 / 对话框等其余 op 渲染层不再可达(仅主进程内 host.native 供 shim 使用)——渲染层渲染 AI 生成的 HTML,XSS 失守后不再拥有剪贴板与文件系统探测能力。 - 主进程
unhandledRejection日志脱敏:错误对象可能携带请求体/配置(含 apiKey)上下文,现只输出 message + 截断堆栈,并遮蔽常见密钥字段(apiKey/authorization/password/token/secret/credential),超长字符串截断,敏感信息不再进入日志管道。
Changed
- 前端启动体积与首屏性能优化(桌面端专项):
- 历史页 / 用量页 / 设置面板 / 子代理 Monitor / 变更查看 / 代码查看 / 更新弹窗改为
defineAsyncComponent懒加载(保留既有 visitedViews + v-show 惰性挂载语义),设置面板(约 488KB)等大面板代码拆出主入口——入口 JS 由约 1.8MB 降至约 1.24MB(-31%),面板级 CSS 同步按需加载; - 变更查看面板 diff 计算加内容指纹 LRU 缓存(
computeDiffLines模块级 memo,上限 64 条 / 超大文件跳过),statsByIndex/selectedHunks与工具卡不再对同一内容反复跑 LCS;语法检查同样按 语言+内容 指纹缓存(上限 64 条 / 128KB 上限),面板可见期间 entries 推送不再全量重算; chunkSizeWarningLimit由 2500KB 恢复至 1000KB 并开启压缩体积报告,入口体积回归可观测;- 移除未使用的
markdown-it-container依赖(仅 .d.ts 类型声明引用)。
- 历史页 / 用量页 / 设置面板 / 子代理 Monitor / 变更查看 / 代码查看 / 更新弹窗改为
- vscode-shim 稳定性修复:
vscode.diff预览路径双重decodeURIComponent修复:Uri.parse已解码 path(DiffHandlers 构造时编码一次),二次解码遇字面%(如report%final.md)会抛URIError导致 diff 预览打开失败,现去除多余解码;workspace.fs.copy遵守 overwrite 契约:overwrite=false(缺省)时目标已存在报错(ERR_FS_CP_EEXIST),不再静默覆盖用户文件;Uri.parse清理空分支死代码。
- builtinLsp 优化与修正:
- 未知扩展名不再回退 TS 风格正则(原实现会从 .toml/.ini/.log/Dockerfile 等提取伪符号),未显式映射的语言默认不解析;
findIdentifierLocations预计算行起始偏移(原实现每匹配做 slice+split,大文件多匹配 O(n·m)),复用调用方已读内容消除重复读盘;- 移除共享
g标志正则的lastIndex全局可变状态(getDefinitions/getReferences并发调用脆弱),统一改用matchAll。
- BackendHost 资源清理:
- diffManager 状态监听退订函数入
unsubscribers(dispose 时移除,避免模块级单例持闭包引用泄漏);dispose 清空previewToSessionId/toolDiffIds/diffPreviewContents映射; require('events')改为标准import { EventEmitter }。
- diffManager 状态监听退订函数入
- 自定义协议(graycode://local)请求热路径:缓存命中直接返回,省去每次 stat 系统调用(资源为打包产物运行时不变)。
Fixed
- 修复回复查看器(ResponseViewerDialog)渲染期空指针导致消息列表 UI 丢失(偶发,便携版/长会话消息滚动渲染时触发):
MessageItem仅在打开对话框时惰性构建responseViewerData(初始为 null),而ResponseViewerDialog随每条消息常驻渲染,模板与 computed 对props.value无条件解引用(:value="props.value.rawJson"等)——props.value为 null 时抛TypeError: Cannot read properties of null,Vue 渲染错误向上传播使该消息组件树渲染失败,表现为消息区 UI 缺失。现valueprop 改为可空(value?: ResponseViewerData | null),全部 computed / 模板访问加可选链与空值兜底(answerText/thoughtText/tools/parts/attachments/metadata/responseInfoItems/basicInfoItems/metadataKnownItems/rawJson),空值时渲染空态而非崩溃。 - 懒加载面板增加 chunk 加载失败自动重试兜底:便携版/防病毒扫描/临时目录清理等场景下异步 chunk 偶发加载失败会让面板静默空白(表现为 UI 丢失)——
defineAsyncComponent统一走withLazyFallback(失败自动重试最多 3 次、指数退避 400ms 递增),仍失败才渲染降级,不再一次性静默失败。 - 前端流式/高频路径小修正:
App.vue命令分发 switch 内重复break死代码清理。
Tests
- 后端 jest 235 套 / 2442 用例通过;前端 vitest 69 文件 / 648 用例通过;
tsc --noEmit全绿(根 + electron-app + frontend vue-tsc);electron-app esbuild 生产构建通过。
[1.7.0] - 2026-08-07
Added
- GitHub Releases 自动更新(fork 桌面版适配):应用启动后延迟 10s 检查
czocelot/Gray-Code-Desktop最新 Release(距上次检查不足 24 小时跳过,时间戳存 globalState;设置页「立即检查」忽略节流),有新版本时前端弹窗展示 Release 说明,用户确认后自动下载安装包(优先 NSISGrayCode.Setup.*.exe,回退便携版 exe / zip)并交给操作系统打开,由用户完成安装后重启应用生效;设置页「通用」新增「自动更新」区块(启用开关 + 立即检查 + 一键更新按钮——一键更新自动完成「检查 → 下载 → 打开安装包」);请求复用渠道代理配置(createProxyFetch),版本检查超时 10s / 下载 120s,失败静默不打扰;新增checkForUpdates设置项(默认 true,可关闭,随 Settings Sync);三语 i18n + 设置搜索索引;新增 webview 消息getUpdateStatus/checkUpdateNow/installUpdate/updateNow/openUpdatePage与UpdateHandlers(updateNow为检查下载一条龙;Electron 桌面端与 VSCode 扩展形态均已接入 UpdateChecker 初始化);后端新增UpdateChecker模块(版本比较 / 节流判断 / API 响应解析为纯函数,update状态机覆盖 disabled / idle / checking / upToDate / updateAvailable / error)及单元测试。 graycode.checkForUpdates注册进 package.json contributes(合入上游 c109fdd):此前该设置键仅在VSCodeSettingsStorage读写但未注册 contribution,VSCode 扩展形态下对未注册键update会抛错;桌面端 vscode-shim 不做键校验不受影响,补齐后扩展形态与设置注册测试(vscodeSettingsStorageRegisteredKeys.test.ts)一致。
Changed
- 渠道设置支持更改渠道类型(合入上游 3eba442 + c12cb52):编辑表单类型由只读徽章改为可选下拉框(CustomSelect + 三语确认弹窗);切换时后端以新类型默认配置为基底重建(
updateConfig放开 type,pickCommonFields保留 33 项跨类型通用字段 + apiKey,显式updates优先级最高),激活渠道变更同步清空会话级模型覆盖;createConfig入口运行时校验非法类型(不再落入 default 分支产生无 url 死配置);CHANNEL_TYPES常量移入configs/base.ts与ChannelType类型同源(消除校验常量与类型漂移);桌面端保留本地resolveModel模型回退(类型重建后同样生效)。新增ConfigManager.updateConfig.test.ts11 用例。 - 提示词预设 fakeThought 伪造思考过程 + 思考回传配置合并(合入上游 c109fdd):
PromptEntry新增fakeThought字段(预设临时 assistant 消息可附加伪造思考,PromptManager 组装thought: truepart 并剥离进 preserve 快照),ToolIterationLoopService 发送侧applyPromptContextThoughtPolicy按渠道「发送历史思考内容」开关过滤(不写入 turnDynamicContext 缓存,两处循环入口统一);设置页 PromptEntriesEditor 新增 fake-thought 输入区;4 个 channel options 组件「当前轮次/历史回合」思考回传双区块合并为单一thinkingBackfill区块(i18n 键迁移,ChannelSettings.vue旧 CSS 清理)。 - 根消息编辑重生成(TREE-03-R,合入上游 c109fdd):
resolveEditTargetNode两处 branch 模式不再拒绝根节点;handleEditBranchStream新增isRootEdit分支——改写根节点 +createRerollCandidate保留旧回答为候选 + 截断其后 +editStarted.parentNodeId = null;前端effectiveMode不再对根节点自动降级 keep(仅用户显式选择时透传 keep);keep 模式 complete 不再携带 content 且前端不再进入流式等待(修复「编辑根消息后无法发送」:complete 丢失时 isStreaming 残留拦截消息发送)。测试断言同步(editBranch / streamErrorRetry)。
Fixed
- 修复设置页保存提示词误报失败(合入上游 40b0ae5):
countSystemPromptTokens(调渠道 API 计数)、tokenizer.getResource(首次下载词表,分钟级)、storagePath.getStats(大目录统计)等慢 handler 占住串行messageHandlingQueue时,后续savePromptMode排队超过前端 180s 兜底超时被误报失败(对话框类exportPromptModes同样豁免);现三类消息加入NON_BLOCKING_MESSAGE_TYPESfire-and-forget(响应仍按 requestId 路由回发起方)+ 前端UNBOUNDED_REQUEST_TYPES同步豁免,saveConfig保存后的 token 计数改void countTokens()不阻塞成功反馈;桌面端保留本地独有条目(workspace.openFolder/chat.awaitConversationIdle/summarizeContext等)。新增messageRouterNonBlockingBehavior.test.ts/promptSaveChain.test.ts,messageRouterNonBlocking.test.ts并集合并。 - 修复高 tps/代码块渲染吸底优化(合入上游 c37bf00):① CustomScrollbar 新增
USER_SCROLL_COOLDOWN_MS250ms 冷静期——wheel 输入事件同步派发、早于 scroll 事件与 rAF,冷静期内跳过贴底写入(高 tps 下内容增长抵消滚动距离、每帧被拉回的问题根治),滚动条拖动同样标记冷静期;② MessageRenderBlockshouldStickBottom返回 true 前queueMicrotask读回写入后实际 scrollTop——程序贴底写入(CharFlowscrollToEnd/promote 校正)不再被紧随其后的代码块异步渲染(hljs 高亮使 scrollHeight 骤增)误判为「用户滚动」而丢吸底,scrollMediumToBottomIfStuck写入后同步记录;③ 中展开按 scrollTop 变化检测(scrollTop 未变 = 用户没动,内容增长不改变吸底意图)。与桌面端 M-5 字符级变更节流正交(纯字符变更合并 ~100ms 窗口调用,最终都走 updateLayout 冷静期检查)。新增回归测试(wheel 后不拉回、冷静期恢复、代码块异步渲染不丢吸底)。 - 修复历史截断后孤儿 functionCall(合入上游 ea05ba6):被删消息含某 functionCall 的响应、而保留区间仍持有该调用且无其它同 id 响应时,
truncateFrom/deleteLogicalMessage/deleteMessagesInRange截断后经repairFunctionCallPairsAfterDelete把该调用标记rejected = true(不伪造「用户拒绝」占位响应,避免语义混淆);settleFunctionResponses新增functionCallIds集合——迟到真实结果若对应调用已被截断则丢弃(不再制造 orphan_function_response),settledResponseIds统一在写回前清除 rejected(覆盖「截断先标记 rejected、工具结果随后结算」时序,取代原全历史 O(n²) 清 rejected 扫描);与桌面端既有 BR-07/cleanFunctionCall 读时过滤互补(写时根治)。新增orphanFunctionCallRepair.test.ts7 用例(测试播种适配桌面端 historyCache,见 Tests)。 - 修复代码块复制按钮失效(合入上游 c109fdd):
markdownUtilssanitizeHtml 此前直接移除code-tool-btn按钮(净化器把复制按钮删掉);copyToClipboard新增 execCommand 回退——VSCode Webview(vscode-webview:// 非 secure context)中navigator.clipboard缺失/被拒时回退 textarea +execCommand('copy')(恢复原选区防破坏用户文本选择),MarkdownRenderer 改用copyToClipboard并新增copy-failed红色失败反馈样式。 - 修复后台任务回执(
[Background task completed])加载旧对话时显示为普通用户消息:StreamRequestHandler.handleChatStream解构前端chatStream请求时漏透传source字段,后端落盘时request.source为 undefined,回执消息的source='background_task'从未写入历史——当前会话靠前端内存正常显示,重新加载对话后渲染成完整正文的用户消息(占地超大且无折叠卡片);现补上source透传(新数据落盘即带标记),并在统一读路径出口toFrontendMessage(一处覆盖toDisplayMessages/getMessagesPaged缓存/分页/全量路径)对历史遗留的「缺 source 且以[Background task completed]前缀开头的用户消息」做展示层归一化补source='background_task'(只补内存不写盘,避免重写历史文件);新增ensureBackgroundTaskSourceForDisplay单元测试(缺 source 补标记 / 已有 source 不覆盖 / 普通消息与 functionResponse 不误判 / 无 parts 安全跳过)。 - 渠道设置「启用此配置」开关移至表单顶部:此前该开关位于配置表单最底部,用户进入设置时下意识以为没有启用功能;现置于 API URL 之前(配置选择器/新建按钮正下方),一眼可见,
data-search-anchor="channel-enabled"搜索锚点保留。 - 修复
memory_config只读调用在工作区记忆目录尚未初始化时误报「workspace URI could not be resolved」:此前纯读走createIfMissing=false,工作区目录不存在时返回 null,被笼统报成 URI 解析失败;现区分「URI 不可解析」与「工作区记忆目录未初始化」两种失败——前者才报解析错误,后者纯读时回退显示全局配置并标注workspaceNotInitialized(保持无磁盘副作用,不创建目录),带更新参数时仍正常创建目录并写工作区独立配置;memory_zoom只读调用同样区分两种失败,工作区未初始化时改报明确的Workspace memory is not initialized for this workspace;新增memoryConfigTool.test.ts回归测试(6 用例:无工作区读全局、工作区独立配置隔离、未初始化纯读回退标注且无副作用、未初始化带更新参数建目录、URI 不可解析报错、全局未初始化报错)。 - 修复 VSCode 窗口聚焦时仍播放任务完成/错误提示音:音效控制器
handleSoundEvent此前只在文档隐藏(窗口最小化/切走)时聚合不播,窗口聚焦时无论焦点在哪都直接播放;现由扩展侧监听vscode.window.onDidChangeWindowState把窗口焦点状态(windowFocusChanged命令)推送到前端(Electron 桌面端经BackendHost等价推送,shim 的窗口焦点事件桥接自 Electron 主进程 focus/blur),音效按窗口焦点分级——VSCode 窗口聚焦(用户看得见界面、事件结果已可见)不播,窗口失焦(切到其他应用)时照常播放提醒;文档隐藏期间聚合的事件在恢复可见时仍补播一次。新增soundEventController.test.ts(7 用例:默认聚焦不播、聚焦不播、失焦播放、失焦后聚焦不播、隐藏聚合后恢复补播、visibilitychange 集成、事件过期丢弃)。 - 修复流式输出自动滚动吸底的拉回与丢吸底问题:① 正文主滚动容器(CustomScrollbar sticky-bottom)此前
wasAtBottom在 scroll 事件后的 rAF 回调里才更新,滞后一帧——流式期间 MutationObserver 驱动的贴底写入读到陈旧状态,把刚向上滚动的用户拉回底部(「使劲滚才能滚上去」);现 scroll 事件同步更新吸底状态,用户滚动意图立即生效。② 贴底写入后立即用实时 scrollHeight 复验,大段输出 md 异步解析会让 scrollHeight 在写入后继续增长,误判「用户滚离」→ 永久丢吸底;现程序贴底写入记录目标 scrollTop(programmaticScrollTop),其触发的 scroll 事件按写入值比对识别为程序行为、保持吸底状态,吸底状态只由用户滚动改变。③ 思维链中展开(MessageRenderBlock)shouldStickBottom按scrollHeight - scrollTop - clientHeight复验,用户滚回底部后内容大段增长(scrollTop 未变、scrollHeight 变大)同样误判丢吸底;现改用 scrollTop 变化检测——scrollTop 未变 = 用户没动,内容增长不改变吸底意图。④ promote 后的 nextTick 贴底校正增加当前位置复验,用户刚滚离(scroll 事件滞后)不再被拉回。新增CustomScrollbarSticky.test.ts(7 用例:底部增长贴底、滚离不打扰、写入后增长不丢吸底)与 MessageRenderBlock 中展开增长不丢吸底回归测试。
Performance
- 存档点 manifest 懒加载(CPF-LAZY-1):从 schema version 2 起,重量级
files映射(全工作区哈希表,大工作区可达 10-20MB)从 manifest.json 拆出,独立存放于checkpoints/cp_xxx/files.json——manifest.json只保留轻量元数据(workspaceRoots/emptyDirs/changes/excluded/ignoreSnapshot)。读取路径分级:存档列表摘要、设置页排除清单详情、恢复排除说明等只消费元数据视图(loadManifest),不再为少量字段解析整张文件哈希表;完整文件映射仅在恢复链构建、增量比较、链合并等真正需要的路径按需懒加载(loadManifestWithFiles/enrichRecord),经 IPC 下发给前端的checkpoint.getManifest也同步改为轻量视图。旧格式(v1 内联 files)首次读取后 best-effort 自动拆分为新格式落盘,存量存档渐进迁移:轻量读取路径解析一次后 files 进缓存、零写放大,拆分落盘只在完整数据读取(恢复/增量比较/合并)时触发,一次 10-20MB 级写入后后续读取全部走轻量路径;拆分失败/未发生时的 v1 存档由内联兜底继续提供数据,不误判丢失;写入顺序保证 manifest.json 为提交点(先写 files.json 再写 manifest.json,中途崩溃不会出现「新布局指向缺失文件」的不一致)。双缓存隔离:轻量元数据缓存维持既有 LRU 上限(32 条),files 映射缓存按需加载并设独立 LRU 上限(8 条),避免长驻 32 份 10-20MB 大对象;clearCache/删除路径同步清理双缓存。完整性检查(integrityCheck)同步支持 v2 拆分布局(files.json 缺失/损坏/ID 不符/形状非法分别上报)。新增回归测试:拆分写入、懒加载不触碰 files.json、files.json 缺失时元数据可读而完整数据显式失败、v1 读取后拆分迁移、双 LRU 淘汰、完整性检查 v2 布局(10 用例)。 - 存档点 manifest 懒加载后续加固(CPF-LAZY-1 审查优化):files.json(10-20MB 级)改为紧凑序列化(无缩进)落盘,减小磁盘体积与序列化开销(manifest.json 保持缩进可读);manifest 版本校验要求整数(非整数如 1.5 一律视为损坏走迁移/回退,不再按未知布局缓存导致数据丢失误判);
writeManifest写盘失败时清空该存档双缓存,避免链合并等路径在写盘前修改过缓存对象后残留「内存与磁盘不一致」状态。新增回归测试:紧凑序列化无换行、version=1.5 迁移落盘、写失败清缓存(3 用例)。 - 存档点 manifest 懒加载安全加固(CPF-LAZY-1 交叉审查):files 映射形状校验拒绝数组(
typeof [] === 'object'曾会让损坏的 files.json 被当作「空工作区」进入恢复流程,工作区全部文件被误判为 untracked 可删除);manifest 元数据字段补形状校验(缺 excluded/ignoreSnapshot 等的损坏 v2 manifest 不再让列表摘要/恢复排除说明 TypeError);L5 守卫用record.fileCount区分「真空工作区存档」(合法空快照可恢复)与「数据丢失」(显式报错);同一存档的磁盘写入经 per-checkpointId 单飞队列串行化(消除并发迁移/合并共享 tmp 文件的 ENOENT 竞态与 files.json/manifest.json 配对错乱);writeManifest校验 manifest.checkpointId 与参数一致;legacy 恢复扫描跳过 manifest.json/files.json/*.tmp 元数据文件;integrityCheck 与运行期对未知版本(>当前)同口径(报 warning 不深校验);clearCache('')不再误清全部缓存;checkpoint.getManifest返回浅拷贝防外部污染缓存。新增回归测试:files.json 数组拒绝、v1 内联数组拒绝、缺元数据字段迁移、真空存档可恢复、checkpointId 不一致抛错、clearCache('') 语义、并发写串行化、integrityCheck 未知版本(8 用例)。
Added
- 设置页新增设置项搜索:标题栏搜索框实时过滤(结果下拉 + 侧边栏命中页签高亮、未命中置灰),键盘上下选择/回车跳转,点击结果自动切换页签并滚动定位(节标题或精确锚点 + 1.6s 闪烁高亮);内置中/英/日三语关键词索引(SEARCH_INDEX),17 个设置组件 93 个设置块加
data-search-anchor精确锚点,具体设置项全部可搜可直达;空结果提示,三语 i18n 同步。
Changed
- 思维链(思考块)视图从两态升级为三段式(对齐后台任务回流消息):折叠(只保留头部标题行)/ 中展开(默认,固定约 10 行滚动查看)/ 完全展开;头部单击三档循环切换,头部右侧新增三个精确模式按钮(chevron-up / list-flat / chevron-down,
@click.stop防冒泡);ThoughtViewMode类型与getRenderBlockMemoDeps签名同步更新(isThoughtExpanded→thoughtViewMode),清理 MessageItem 中遗留的 thought 样式死代码;三语 i18n 同步;MessageRenderBlock 测试重写为三态覆盖。 - 思维链中展开(medium)模式完善:中展开与完全展开同源 markdown 渲染(流式时渐进 markdown 即时渲染已定型完整段落 + 未完成尾巴 CharFlow 托管,非流式 MarkdownRenderer 直接渲染,不再显示纯文本);可中断自动吸底——内容更新自动贴底跟随最新,用户向上滚动超过 40px 阈值即暂停跟随不打扰,滚回底部附近自动恢复(CharFlow 新增
scrollContainer/stickBottom回调,贴底写在滚动容器上);裁剪提示——单段超长内容触发 tailWindow 裁剪时,内容区顶部显示「内容过长,仅显示最近部分,请使用完全展开查看」提示条(CharFlow 新增onTrimmed回调,仅流式期间显示);三语 i18n 同步。 - 思维链中展开吸底稳定性修复:① promote 剥离内容时 CharFlow host 同步变矮、MarkdownRenderer 下一 tick 才渲染变高(两段式高度变化),原同步校正停在中间——改为
nextTick后按最终scrollHeight校正;② scroll 事件由浏览器合帧派发、滞后于实际滚动,用户刚滚离底部时 append 可能误拉回——shouldStickBottom增加实时位置复验(距底 ≥40px 即同步置 false 不贴底);③ 新增userScrolled标志:未滚动/重新进入中展开时无条件贴底(避免初始 scrollTop=0 被复验误判),滚动后按位置复验;注册中展开时重置吸底状态;新增 3 个回归测试(滞后复验 / nextTick 最终高度校正 / 原有恢复路径)。 - 思维链自动视图模式:思考中默认「中展开」;思考与输出全部结束后自动折叠为单行第一行预览(折叠视图新增内容预览区:非流式取思考内容首行,流式由 CharFlow 单行模式实时显示最新字符——
squashLineBreaks折叠换行 +tailWindow有界 +followEnd跟随);用户手动切换过视图模式后自动切换不再干预(尊重用户选择);已结束消息重建后初始即为折叠态;新增折叠预览与自动模式切换测试。 - 上下文总结(自动 + 手动)从「物理删除被总结消息」改为「逻辑截断」:被总结区间的原始消息打
isSummarized标记完整保留在历史中(不再从磁盘消失,history_search现在可以检索到被压缩的原文),发送给 AI 与 token 统计跳过被总结区间(ContextTrimService统一过滤);首条用户消息永远发送(任务锚点,prependFirstUserMessage在所有发送路径前置,含手动总结边界与 trim 裁剪场景);isRealUserMessage排除isSummarized,回合识别/总结规划/isFirstMessage判断(过滤后活跃消息数)全部适配;协议insertIndex改为总结消息插入位置(= summarizeEndIndex)、removedCount改为本次标记的消息数,前端handleAutoSummary同步为「标记本地消息 + 插入总结」(不再删除/平移索引);消息列表在最后一个总结消息后渲染横线分隔「已总结 / 未总结」区域(原文照常显示不折叠);自动总结的STALE_RANGE并发校验与低质量总结拒绝保留;历史文件无限增长为接受项(原文永不清理)。 - 新增「恢复原文」能力(逻辑截断反向操作):总结消息卡片新增恢复按钮(
restoreSummarizedMessagesAPI),点击后取消该总结覆盖区间的isSummarized标记并删除总结消息本身,发送起点回退到上一个总结(或 0),原文重新参与发送与统计;删除总结消息(deleteMessage/deleteMessagesInRange命中总结消息)同样自动恢复覆盖区间,杜绝「既无总结文本也无原文」的上下文真空(restoreSummarizedRange纯函数,覆盖区间 = 上一个总结之后到该总结,从晚到早逐个恢复多总结场景);三语 i18n 与新增回归测试(summarizeRestore.test.ts 7 用例)。 - 全链路性能与资源占用优化(移植自下游桌面版,仅含前后端可移植部分):
- 后端读路径缓存:checkpoint 节点反查(
getMessageNodeIdAt)300ms 短 TTL + LRU 缓存,一轮对话免十几次全量读盘;分支图读路径只读引用缓存(60s TTL + 200 会话 LRU + mtime/size 外部改写校验),大图不再每次迭代全量 structuredClone;模型列表 5 分钟 TTL;工具声明指纹缓存(tools JSON Schema 构建结果按声明/模式/工具逻辑/MCP 版本缓存);会话元数据读路径与分支图读路径解耦。 - 热路径算法:上下文裁剪起点由 O(候选历史) 改为前缀扫描 O(n) 预计算;运行时上下文回合内复用,同一回合不再重复生成;流式响应 chunk 用 offset 游标解析,消除每个数据包 Buffer.concat / 字符串拼接的 O(n²)。
- 前端流式渲染:hljs 已知语言高亮缓存(流式期间同一语言块不再反复全量高亮);
usedTokens增量指纹(每 chunk 免全量历史扫描);todo 快照尾部增量重放(每 chunk 免全量重放,前缀引用与响应表校验不一致时自动回退);MessageList 构建/todo sticky 列表短路(无 build / 无 todo 时免扫描)。 - 前端高频路径:i18n
t()翻译缓存(无参键免 split + 查找);CustomScrollbar 值相等检查(无变化不写响应式 ref)+ rAF 节流 + 贴底阈值;平滑流式增量基线(每 chunk 免累计文本 slice)。 - webview:分支图富化响应前浅拷贝(配合只读引用缓存契约);
requiresJsonRoundTrip小 payload 短路(高频小消息免分配 visited Set 深遍历);广播直接迭代订阅者 Set(免每 50ms 复制订阅者集合);getExtensionVersionmemo。
- 后端读路径缓存:checkpoint 节点反查(
Fixed
- 修复编辑用户消息保存后候选切换器(‹ 2/2 ›)不立即显示:编辑分支流结束后分支图虽已刷新,但本地窗口中被编辑消息仍保留旧候选 id,
buildCandidateGroupForNode判定其为候选组非活跃成员返回 null,需切换会话再切回(loadHistory 重载后 id 与后端一致)才恢复;现loadBranchGraph刷新成功后把窗口内「候选组非活跃成员」的用户消息 id 对齐为图活跃候选(BR-01 原则:窗口 id 与后端主历史 Content.id 一致),保存后立即可见切换器,幂等不误伤其他路径;新增回归测试(editBranchRefresh.test.ts 第 5 用例:complete 后 id 对齐 + 候选组命中)。 - 后台任务状态条(BackgroundTaskBar)新增「清除已完成」按钮:一键清除所有已完成的后台任务 chip(运行中保留);若存在结果尚未汇报给模型的任务(回执未进入对话历史),先弹危险确认框提示再清除,避免静默丢失任务结果;按钮带可清除数量提示,三语 i18n 同步;新增
backgroundTaskStore.dismissCompletedTasks单元测试(backgroundTaskDismiss.test.ts)。 - 子代理路径
ToolDeclarationResolver监听器泄漏(H-1):每次 run 新建实例会向 McpManager 单例注册 3 个永久事件监听器且从不释放,重度多代理下监听器无界累积、MCP 事件派发退化为 O(n);改为按依赖引用共享实例(容量 4 LRU 淘汰),并新增dispose()释放监听器,同时让子代理路径真正享受声明缓存收益。 ConversationManager节点 ID 反查缓存(nodeIdCache)失效覆盖不完整:invalidateCaches定义了但从未被调用,saveContents / 全量重写 / 历史迁移 / 删除对话等写路径不失效缓存,工具循环内(拒绝工具调用等结构性变更后 300ms 窗口内)checkpoint 反查可能命中陈旧节点 id;现全部写路径统一走invalidateCaches。- 设置搜索下拉键盘导航滚动跟随:结果超出下拉可视高度时,↑/↓ 选中的高亮项现在会保持在可视区域内(
scrollIntoView({ block: 'nearest' }))。 ContextTrimService.computeValidSuffixMap反向扫描与正向validateHistoryIntegrity在乱序配对时语义不一致(L-5):functionResponse 出现在其配对 functionCall 之前(跨消息或同消息内)时,正向判孤儿(invalid)而旧反向实现误判 valid,裁剪后可能把乱序配对发给 API;修复为按「本消息内更早 part / 右侧消息 / 待左侧治愈」三分支精确匹配正向语义。- 设置搜索跳转时序与状态残留(L-1/L-2):跳转定位改为按目标元素相对滚动容器偏移计算一次
scrollTo(避免 smooth 动画未推进时同步读 rect 的时序冲突、打断动画);跳转成功后清空搜索词,侧边栏恢复常态高亮;search.hint词条投入使用(搜索框聚焦且未输入时显示提示)。 pendingWholeBuffer注释修正(L-4):原注释声称「上限由硬限制保护」,实际代码对未知格式的整段累积没有大小上限(与改动前行为一致),已修正为准确描述。- 新增回归测试:
subagentResolverSharing.test.ts(监听器只注册一次 / dispose 释放 / 容量淘汰)、conversationMessageNodeId.test.ts补写路径失效断言(仓储替换、删除对话)、contextTrimValidSuffixEquivalence.test.ts(computeValidSuffixMap 与正向校验逐候选等价 + 固定 seed 随机模糊对比 50 轮)、toolDeclarationResolverCache.test.ts(缓存命中 / 参数与设置指纹与 MCP 版本失效 / dispose)、settingsSearchAnchorConsistency.test.ts(SEARCH_INDEX 锚点与组件 data-search-anchor 一致性)、todoListIncremental.test.ts(增量重放参数分段一致性)与computed.test.ts增量分支(流式追加 / 尾消息原地更新 / 前缀替换回退 / 数组缩短 / 总结估算)。 - 全仓审计修复(PR #17 合并):①跨对话存档误删——
CheckpointQueryService.removeOrphanBackupDirs孤儿判定汇总全部对话的存档记录(有界并发枚举)+ manifest 身份守卫(fail-closed,含 manifest 的目录绝不删)+ 无 manifest 目录的 mtime 新鲜度守卫(创建中窗口跳过);②代理流式 buffer 偏移——ChannelManager直接以parseStreamBuffer返回的 remaining 为下轮基线(修复 JSON-lines 逐行格式丢 chunk、SSE 事件跨 chunk 尾随空行切坏data:前缀);③总结消息插入窗口中间不可见/重复——insertMessageAt中间插入清可见消息增量缓存;④StreamAbortManager:create() 替换控制器时释放 idleWaiters、waitForIdle退休链等待超时后返回(修复awaitConversationIdle→ 后台回执永久挂起);⑤分支图冻结自愈——空占位超龄判定(10 分钟,isActiveEmptyPlaceholder):崩溃/被杀遗留的空 reroll/edit 占位不再让 append 跳过图同步(append 前先收敛、deferred 同步不再永久 defer),超龄幽灵占位软删回收;⑥SubAgent Monitor contentDelta:快照尾部为工具结果时追加新楼层而非覆盖上一轮模型消息(附 5 例回归测试);⑦分支:deleteToMessage 截断含总结走 summary_deleted 全量重建、edit 流程补写节点 contentMetadata、contentMetadata 排除 turnDynamicContext 快照、修复备份保留数上限;⑧安全:regexGuard 嵌套分组量词检测、SettingsCore 深合并过滤__proto__/constructor/prototype、Memento 写队列串行化、FileSettingsStorage 原子写、McpManager 重连前断开旧 stdio、StdioClient 通知吞错、nodeIdCache epoch 守卫防陈旧回填;⑨前端:autoSummary chunk 不再被 streamId 门禁丢弃(含 tab 缓冲路径)、error 路径结束半截消息 streaming 标志、cancelled/error/本地取消重置 turnBaseTokens、WorkspaceRestoreGuard 等待旧流完全退出、thought 视图模式与裁剪提示按 messageId 持久化 + prune 集成、SummaryMessage 删除/恢复互斥、投递提示按 seq 精确移除。 - regexGuard 增强(审查后优化):扫描式嵌套量词检测补「裸量词原子」跟踪(拦截
(?:a+|(?:ab))+、(?<name>a+)+等嵌套 + 原子量词形态,同时保持(a+)?/(ab+)?线性形态放行);正则启发式检测前净化转义序列与字符类(不再误伤\(a+\\)+、([a+])+);范围量词只认可变{n,}/{n,m}(定长(a{2}){2}放行);新增 10 组检测矩阵用例。 ConversationManagernodeIdCache epoch 改全局单调计数器 + LRU 容量淘汰(审查后优化): 计数器不归零、淘汰只删最旧条目,消除「整体清空后 0===0」与在途读盘回填的碰撞窗口。modelList缓存读写改浅拷贝一层(原 JSON 序列化深拷贝会丢失 undefined 字段且有全量序列化开销);FileSettingsStoragetmp 文件名加随机后缀(并发 save 不再互相踩)+ rename 失败清理残留;handleAutoSummary标记起点下界钳制Math.max(0, insertIndex - markedCount)(负起点会把窗口外消息全部误标记)。- 合入上游 7489a9c..70ecbb3(PR #19 记忆删除 + 审查收尾 + diff partial 修复):
- memory_forget 语义变更:单个数字 ID 由「截断删除 ID ≥ N 的全部记忆」改为「只删除这一条原始记忆」;新增闭区间模式(
"1,3"逗号分隔删除 1 到 3);MemoryManager 新增deleteRange/deleteEntries(去重排序 + 相邻闭区间聚合、从大到小逐个删),deleteEntry委托deleteRange;删除采用「先清树摘要、后原子换 LOG」顺序(崩溃窗口最多摘要缺失、自愈安全,修复此前「新 LOG + 旧摘要」崩溃窗口内已删记忆在 wake 中复活的中危问题);logAppend锁内按真实 id 精确校验记录容量(消除估算竞态),MAX_HEADER_BYTES常量替换 23 魔术数;设置页新增批量删除(全选/复选/危险确认,deleteMemoryEntriesIPC,上限 10000),单删/批量删除响应带removed,加载中禁用勾选/删除、残留选中与编辑态清理(防旧 id 错位删错);三语 i18n 与前端memory_forget描述(单条/闭区间/摘要三态)同步;新增 deleteRange / memoryForgetTool 回归测试(含 NaN/非整数/lo>hi 等非法参数防御)。 - diff 部分接受/部分拒绝状态修复:
PendingDiff新增partial/rejectedBlockIndices,finalizeAcceptedDiff终结时写回 partial 标记(含被拒绝块索引统计),apply_diff 工具结果按「初始成功 - 被拒块 / 初始失败 + 被拒块」修正计数并返回status: 'partial';DiffCodeLensProvider.updateBlockStatus改按业务下标find(b => b.index === blockIndex)(修复混合成败时稀疏下标静默 no-op 导致会话永不 complete);前端 apply_diff 面板 partial 徽标与 rejected 块标记、ToolMessage / responseViewer / agentRun reducer / streamChunkHandlers / SubAgentMonitor 状态派生全部识别 partial;三语 i18n 新增partial/rejectedBlock键。 - 工作区绑定记忆(fork 新增,桌面版/插件版双端生效):记忆系统新增作用域——全局记忆(
<dataPath>/memory,旧行为不变)与工作区记忆(<dataPath>/memory-workspaces/<hash>/,每个工作区独立 LOG/TREE/config);工具层经ToolContext.activeWorkspaceUri路由到对应实例(无工作区回退全局);设置页「原始记忆条目」分区编辑:全局 / 工作区两分区切换,工作区分区下拉选择已打开工作区后展示该工作区记忆,条目增删改与运行时参数按作用域读写(enabled/systemPrompt 保持全局);新增listMemoryScopesIPC 枚举全部工作区记忆 scope。 - 保存工作区显示修复(fork):工作区下拉「已保存的工作区」完整展示全部收藏(此前过滤掉已打开的收藏条目,导致对话绑定的多个工作区中已打开者不显示),已打开的条目标注「已打开」并可点击直接固定,未打开者点击打开;三语 i18n 同步。
- memory_forget 语义变更:单个数字 ID 由「截断删除 ID ≥ N 的全部记忆」改为「只删除这一条原始记忆」;新增闭区间模式(
Added
- 记忆设置页支持手动增加记忆(设置 → 记忆 → 原始记忆条目):此前记忆只能由 AI 通过
memory_note工具写入,用户想记录一条事实/约定必须让模型代劳。现条目列表顶部新增输入框 + 「添加记忆」按钮(支持 Ctrl+Enter / ⌘+Enter 快捷提交),写入链路与 AI 的memory_note完全等价(同一MemoryManager.note,同样触发待压缩提示);新增addMemoryEntryIPC 处理器,添加成功提示新条目 ID 并自动刷新列表 - 记忆条目列表超限保护:
getMemoryEntries支持limit(默认 5000),MemoryManager新增 O(1) 的totalEntries();海量记忆(10 万条以上)时不再全量 postMessage 传输 +v-for渲染冻结设置页,截断时前端提示「仅展示前 N 条,其余可用 memory_recall 检索」
Changed
- 记忆写入容量校验精确化:
note/updateEntry此前只按entryChars校验文本长度,用户把entryChars调高或 id 位数增长后会在pad()处以晦涩的 "Too long" 报错(固定宽度记录含 "#" 头部开销);现按实际 id 精确校验整条记录,报错信息包含头部开销与可用预算; memory_config工具与配置边界的entryChars上限同步收敛(LOG_REC - 1 - 23),工具描述不再写死错误的「最大值 280」 wake连续原始块批量读取:此前每个原始记忆块一次logSlice→ 一次 open/read/close 文件句柄循环(T ≤ wakeLines时一次 wake 可达上万次);现 cover 输出的连续原始块合并为一次logSlice批量读取,句柄数降为块数级别,读取结果逐条输出顺序不变- MemoryManager 初始化收敛:VS Code 扩展(ChatViewProvider)与 Electron 桌面版(BackendHost)重复的「建 memory 路径 → new MemoryManager → init → loadConfig → setGlobal」五连复制粘贴提取为
initMemoryManager(dataPath)共享助手,两宿主行为零漂移
Fixed
- 崩溃残留的撕裂尾部记录被当作有效记忆:日志末尾不足
LOG_REC字节的半条记录此前会被解析成垃圾条目出现在 wake/recall/listEntries 中;现records()只解析完整记录,下一次追加时由既有repair()截断修复 count()/logScan()静默吞掉 IO 错误:此前权限/IO 错误一律当成「空日志」,wake 会在文件实际不可读时谎报「没有记忆」;现只把 ENOENT 视为空,其余错误上抛- 设置页记忆条目字节校验对齐后端:新增/编辑条目的字符计数此前用 UTF-16 码元数(中文等多字节字符低估长度,前端放行、后端报错);现按 UTF-8 字节数校验并实时显示(超限红色提示),错误提示样式不再依赖字符串内容猜测
Changed(结构收敛)
- 性能与资源占用优化(子智能体并行审计 + 修复,全链路):
- 流式渐进 Markdown 渲染根治 O(n²) 重解析:此前流式期间已定型的段落被持续累积进单一字符串,每次渲染 tick(最长 180ms 一次)都把全部累计文本重新做一遍 markdown-it 解析 + 代码高亮 + 整体
v-html替换——回答越长每帧成本线性增长,长代码生成场景流式后期卡顿。现 promote 文本按\n\n段落边界切块($$数学块未闭合的边界暂不切,保证与整段渲染语义一致),每块一个独立的MarkdownRenderer实例(key 不变 → Vue 复用旧块,只渲染新块);软上限 200 块防御性淘汰最旧块 - smoothStreamManager fence 配对扫描增量 化:此前每帧对全文从零做 fence 配对正则扫描(长代码块流式时每候选段落一次 O(前缀长) 扫描);现按流实例维护增量扫描状态(只扫新增区间 + 二分计数),
findPromoteCut行为完全不变但每帧成本降为 O(delta) - MessageList / MessageItem 热路径缓存:
allMessageIndexBounds/todoStickyMeta/mergeableCheckpointKeys改为「引用指纹 + 尾部增量」缓存(复用getVisibleChatMessagesCached模式),流式 50ms 批次不再对全窗口(≤800 条)重复全扫;availableCheckpoints/checkpointsBeforeMessage改走 store 新增的checkpointLookup增量分组(升序 keys + 前缀终点,二分取最近前序),40 个可见实例不再各自 filter+sort 全量 checkpoints(非单调时防御性回退原逻辑) - CustomScrollbar 流式期间布局节流:
characterData变更(流式每帧发生)合并到 ~100ms 窗口批量更新布局,childList结构变更保持即时;卸载时清理挂起定时器 - 终端输出全链路节流:此前 stdout/stderr 每个 data chunk 独立
postMessage(高频输出命令消息风暴),且前端每次响应式整体重写<pre>;现ChatViewProvider按 terminalId 聚合 output/error 80ms 批量发送(start/exit 即时且先冲刷未决输出保持顺序),前端terminalStore只追加字符串、格式完全兼容 execute_command每次执行的外部进程开销消除:热路径不再每次 spawn 子进程检测 shell 可用性(改走已存在的 5 分钟 TTL 同步缓存,错误文案语义不变);Windows 前台命令不再额外启动powershell.exe设置优先级(前台本就是默认 Normal,纯浪费),后台命令改用execFileargv 数组形式(无 shell 解析面)search_in_files并发化:最多 1000 个文件从逐文件串行 I/O 改为受控并发(并发度 8,复用mapWithConcurrency,结果保持原文件顺序);replace 模式拆两阶段——并发只读扫描 + 串行 diff 审阅(保持审阅顺序语义不变)pushOutputLines截断摊销化:5 万行上限后不再每个 chunk 都splice(0, dropped)整段前移,累计超限 1000 行才清理一次(O(n²) → O(1) 摊销)waitForDiffResolution轮询降耗:100ms 常驻轮询降为 1.5s 兜底轮询(事件驱动为主)+ 5 分钟最长等待上限,超时按「用户中断」语义收敛,杜绝永不结算的 pending diff 空转ConversationManager读路径深拷贝消除:getMessages逐条JSON.parse(JSON.stringify)深拷贝与分页路径浅拷贝方案对齐(IPC 序列化天然隔离);cloneJson统一为structuredClone(快数倍且保undefined);getCustomMetadata缓存命中只克隆目标键,不再整份 metadata 克隆getMessageNodeIdAt缓存 TTL 300ms → 30s:此前工具循环中相邻两次反查间隔超过 300ms 即缓存失效,导致每轮反复全量重读 transcript 文件(写路径已统一失效该缓存,TTL 仅兜底外部直写);顺带usageCache降级 mtime 扫描从 15s 同步 stat 风暴改为 60s +fs.promises异步递归fileTree缓存命中跳过 statSync:TTL 内不再每次statSyncgitignore 文件(miss 时才同步遍历全树);createProxyFetch按 proxyUrl 记忆化(不再每次请求重建闭包 + 重解析代理);PromptManager占位符正则模块级预编译缓存;i18n.t()加载时拍平为 Map 查找 + 缺失 key 告警去重(只告警一次,不再刷屏)- Electron 桌面版:
graycode://协议静态资源缓存改 LRU(热点大 bundle 命中即刷新,不再被小资源挤出反复读盘);workspace.json改.tmp+ rename 原子写(崩溃不再损坏收藏工作区记录);e2e 端口改监听 0 取实际端口(消除并行冲突);esbuild targetnode18→node20与 engines 对齐;CI 去掉重复的 vue-tsc 全仓检查(build 内置一次即可)+ 增加 30 分钟超时
- 流式渐进 Markdown 渲染根治 O(n²) 重解析:此前流式期间已定型的段落被持续累积进单一字符串,每次渲染 tick(最长 180ms 一次)都把全部累计文本重新做一遍 markdown-it 解析 + 代码高亮 + 整体
Fixed
- ToolDeclarationResolver 事件监听器泄漏:每次 SubAgent 执行 /
ChannelManager.setMcpManager重建都会向全局 McpManager 累积 3 个永久监听器(长会话无界增长、闭包阻碍 GC);新增dispose()解绑(executor 用完即释放、重建前先解绑) cleanupTerminals死代码:活跃进程表只靠 close/error 事件清理,挂死进程条目永久滞留;现ChatViewProvider.dispose()调用清理- 工具注册双重实例化:注册探针不再执行工厂(此前每次启动多一轮工具声明构建 + shell 检测 execFileSync 阻塞),read_skill 仍以真实工厂注册
- Electron 主进程崩溃恢复:新增
uncaughtException处理(错误对话框提供重启选项);渲染进程render-process-gone自动 reload(最多 2 次后弹窗,防死窗);before-quit二次触发竞态修复(dispose 期间二次退出不再截断写队列,统一由首次收尾) monitor-smokeCI 挂起:失败/异常时不再让进程无窗口挂死,try/catch/finally + 状态码退出(与 e2e 对齐)Selection.isReversed逻辑错误:anchor === end恒假,改为anchor.isAfter(active)的官方语义- 前端资源清理补全:
ToolMessage的seenDiffToolIds/persistedDiffGuardWarnings加 500 上限 + 会话切换清空;InputBox预览消失定时器保存句柄并在卸载时清理;terminalStore.initialize()保存取消函数并暴露dispose()(App 卸载时调用);FileHandlers高亮定时器挂到装饰器 dispose 生命周期
Changed(结构收敛)
execute_command/diffManager/search_in_files重复逻辑收敛:图片尺寸解析(PNG/JPEG/WebP/GIF)两份同构实现统一为parseImageDimensionsFromBytes;plan/design/progress 三处ensureParentDir+ 多工作区路径策略统一收敛到backend/tools/pathPolicy.ts(薄封装保留原导出);四处分散不一致的忽略列表统一到backend/tools/ignoreLists.tsConversationManager三处重复的「未响应工具调用拒绝/补齐」逻辑提取到backend/modules/conversation/TranscriptMutation.ts共享纯函数(杜绝语义漂移)extension.ts瘦身:导出设置/导入设置/迁移旧对话历史三个命令的完整 UI 流程抽取到webview/commands/settingsTransfer.ts(依赖注入,行为逐字等价),入口只留注册与生命周期编排ModuleRegistry日志降噪:注册/注销改 debug 级
Tests
- 全量回归:backend jest 215 套件 / 2196 用例、frontend vitest 55 文件 / 551 用例全绿;新增/更新
fileTree.test.ts(缓存命中跳过 gitignore stat 的新语义)、MessageItem.test.ts(checkpointLookup mock)、MessageItemStreaming(分块渲染)、smoothStreamManager(增量 fence 扫描)等;Electron e2e / monitor-smoke / uismoke 冒烟通过
[1.6.9] - 2026-08-07
Merged
- 增量合入上游
70ecbb3..cf9330d(5 提交:记忆隔离移植 986c4d9、子代理工具轮幻觉剥离 e1d71ec、测试类型引用 92473f0、PR #20 记忆隔离审查修复 80a9fc7、merge cf9330d),保留 fork 的 electron-app / 多工作区 / 安全加固增量:- 记忆隔离作用域加固(PR #20 审查):
memory_wake/recall/zoom等只读工具不再隐式创建工作区记忆目录(createIfMissing=false,只读访问零磁盘副作用);memory_wake续读时 "T=" 快照过期不再误判为「已读完」跳过——改用该作用域自身当前总数重试,跨作用域 snapshotT 不匹配时内容不丢;memory_*工具新增scope显式参数(global/workspace),工作区解析失败不再静默回退全局(防跨工作区记忆污染);wake/recall 输出段头带作用域与工作区名标注,顶层元数据(blocks/part/totalParts/totalMemories/pendingCompression)改为双作用域合并口径 - H4 自动建会话即绑定工作区:
ConversationManager.loadHistory/getMessages/getMessagesPaged/normalizeHistoryForDisplay透传当前工作区 URI,webview 读取入口按需自动创建的会话在创建时就写入workspaceUri元数据(避免记忆工具回退全局造成跨工作区污染);createConversation两者皆空归一为undefined(不再持久化字面 null);ToolExecutionService新增conversation_unbound_workspace每会话一次告警(把静默降级变为可观测);前端切换对话时对未绑定工作区的会话用当前活动工作区补绑(syncConversationWorkspaceUri,已有绑定/分支继承不覆盖) - 记忆设置页作用域配置隔离:
getMemoryConfig/updateMemoryConfig按data.workspaceUri读写对应作用域 MemoryManager 的运行时配置(loadConfig()读磁盘最新值),工作区 tab 保存的数值不再污染全局配置;listMemoryScopes改为「当前激活工作区优先」排序(默认选中项与用户当前项目一致,防记忆写入历史项目造成隔离错位) - 子代理工具轮幻觉剥离:xml/json prompt 模式下,模型在发起工具调用的同一轮"抢跑"输出的文本(无工具结果前的幻觉预生成)从该轮 parts 剥离,不进 history/续跑上下文;
lastResponse只在无工具调用的最终轮更新——失败/空响应时partialResponse不再携带幻觉文本(新增subagentPartialResponse.test.ts5 例回归) - nodeIdCache epoch 写链守卫:
getMessageNodeIdAt读盘不持会话写锁,读盘前后 epoch 一致才允许回填缓存(消除写提交与旧盘面回填之间的竞态窗口;epoch 全局单调 + LRU 淘汰防清空后归零碰撞) - 存储统计/迁移纳入记忆目录:
StoragePathManager的清理/迁移/统计覆盖memory与memory-workspaces - 冲突解决要点:
ConversationManager保留 fork 缓存体系(30s TTL + 权威回填,弃用上游移除 historyCache 的做法);SettingsHandlers.listMemoryScopes保留 fork 收藏工作区口径(上游vscode.workspace.workspaceFolders不适用于桌面版);ConversationHandlers保留 forkassertSafeId校验与 trim 清理;webview 多工作区(WorkspaceManager/终端节流/多文件夹 skills 扫描)与前端多工作区体验(切换恢复工作区/标题附加工作区名/消息索引清理)全部保留;i18n 保留桌面键并补充workspaceNone/newlineNotAllowed(文案适配桌面版)
- 记忆隔离作用域加固(PR #20 审查):
- 合入上游
80e9de7(混合形态消息 functionCall+functionResponse 同消息拆分 tool 消息)修正版:上游原提交把 formatter 的 else-if 链改为独立 if,修复「同消息 call+response 时 response 被吞」的同时引入严重回归——「文本 + functionCall」同消息的日常形态被重复推送为第二条 assistant 消息,且 tool/tool_result 消息不再紧跟 tool_calls(OpenAI/Anthropic 400,上游实测 function_call 模式整体失败);桌面版合入时在普通消息分支加functionCallParts.length === 0守卫,混合形态修复与日常形态行为两全(新增formatterMixedToolMessage.test.ts上游 3 例 + 回归 2 例)
Added
- 记忆工具新增
scope显式参数(global/workspace)与设置页记忆作用域配置隔离(详见上方 Merged)
Fixed
- 修复
memory_wake续读时跨作用域 snapshotT 不匹配被误判为「已读完」跳过导致内容静默丢失(改用该作用域当前总数重试) - 修复只读记忆工具(wake/recall/zoom)隐式创建
memory-workspaces/<hash>/目录的磁盘副作用 - 修复工作区记忆解析失败时静默回退全局记忆的跨工作区污染风险(改为显式报错)
- 修复自动创建会话未绑定工作区导致记忆工具回退全局的跨工作区污染(H4)
- 修复子代理失败/空响应时 partialResponse 携带工具调用前幻觉预生成文本(e1d71ec)
- 修复 nodeIdCache 读盘回填竞态(写提交与旧盘面回填之间 300ms 窗口陈旧节点 id)
- 修复混合形态消息(同消息 call+response)转换时 functionResponse 被吞(80e9de7 修正版,含日常形态回归防护)
Tests
- 全量回归:backend jest 225 套件 / 2291 用例、frontend vitest 63 文件 / 610 用例、tsc --noEmit 全绿;新增
memoryWakeScopes.test.ts(跨作用域 snapshotT 重试 / nextPart 合并推进 / 压缩提示作用域标注 / 只读不建目录)、subagentPartialResponse.test.ts(5 例)、formatterMixedToolMessage.test.ts(混合形态 3 例 + 日常形态回归 2 例)、MemorySettings.test.ts(作用域缓存防闪烁等)
Added(1.6.9 迭代二)
- 子代理界面可选择模型:设置 → 子代理的「模型」下拉框此前选项恒为空(只读渠道配置里已持久化的
models数组,默认[]),表现为「只能选渠道、不能选模型」,运行时子代理永远跑渠道默认模型。现模型选项改为「本地持久化列表优先,缺失时经models.getModels实时拉取 provider 模型列表,并始终把渠道默认model兜底进选项」(与主聊天 write_file/MessageTaskCards 的loadModelsForChannel口径一致);渠道切换时自动选中新渠道默认模型(不再强制清空 modelId);新建子代理对话框补齐模型选择(渠道联动 + 默认模型预填,创建 payload 携带 modelId) - 全局 diff 文件绑定对话 + 无损压缩:
- 此前 apply_diff/write_file/insert_code/delete_code/search_in_files 每次工具调用都把完整 original/new 内容写入
diffs/__global__/且永无删除路径,磁盘无限增长(cleanupOrphanedDiffs显式跳过__global__)。现saveGlobalDiff/saveGlobalDiffDeferred支持传入conversationId:落盘到diffs/{conversationId}/对话目录并写入diffs/index.json归属索引(tmp+rename 原子写、写队列串行化)——删除对话时deleteConversationDiffs一键清理对应目录 + 索引 + 内存缓存;cleanupOrphanedDiffs同步清理孤儿目录的索引条目;已删除对话墓碑拦截 deferred 后台落盘复活目录 - gzip 无损压缩:diff 文件内容经 zlib gzip(level 6)压缩后落盘,JSON 文本(代码内容)通常可压缩 3-5 倍,磁盘增长速率大幅减缓;读取时按 gzip 魔数自动识别,旧版明文 JSON 完全兼容;
loadGlobalDiff查找顺序:内存缓存 → 索引定位对话目录 →__global__回退(旧数据) - 迁移路径(
migrateTo)覆盖 index.json 并重置索引缓存
- 此前 apply_diff/write_file/insert_code/delete_code/search_in_files 每次工具调用都把完整 original/new 内容写入
Fixed(1.6.9 迭代二)
memory_wake分页/续读历史残留移除:wake 一次输出双作用域全部可用记忆(近期原文 + 远期摘要),不再按 PART_CHARS/PART_LINES 分页、不再输出 "part N of M" 段头、不再要求模型连调memory_wake part=2,3...续读到 "You are awake."——所有相关历史残留(part/snapshotT参数、wakeScope续读重试、paginate()、totalParts字段、Not awake yet提示)全部移除;partChars/partLines运行时配置项从类型/工具声明/设置页/三语 i18n/README 全链路删除,存量 config 文件中的 PART_* 行自动忽略;recall输出上限改用独立常量(不再借用已删除的分页配置)- StreamChunkProcessor 视图缺失时终结事件静默丢弃:视图重建/销毁窗口期
processChunk对complete/cancelled/error终结 chunk 整块丢弃且不 flush 缓冲,前端永远收不到旧流终结 → 占位消息永久「生成中」、isStreaming 无法复位、缓冲滞留内存。现终结类 chunk 暂存待视图恢复后补发(pendingTerminalBuffer),无 view 时flush()清空缓冲防滞留,error 仍返回 true 供调用方中断循环(新增streamChunkProcessor.test.ts8 例) StreamAbortManager.waitForIdle活跃控制器分支无超时:活跃流 finally 永不执行时waitForIdle永久挂起(后台回执通道挂死);现复用OLD_STREAM_EXIT_WAIT_TIMEOUT_MS为活跃分支加超时兜底(新增回归用例)- 会话删除后 fire-and-forget 分支图同步复活已删除会话(幽灵 branches.json):
appendContents锁外分支图同步闭包不检查deletedConversationIds,会话删除后闭包仍创建/写入分支文件;现闭包内「读图前 + 写图前」两道删除守卫(与 BranchService BS-4 互为兜底) isFirstMessageHistory把隐藏 functionResponse 误判为「首条用户消息」:隐藏续接(Plan 执行确认)场景动态系统提示词被错误当作首条消息刷新,多余 token 消耗;现增加!isFunctionResponseMessage(active[0])条件(与文件内其它判断口径一致)- 工具循环
maxIterations === -1无终止保障:-1 无限制模式下唯一退出保障是可选 abortSignal,模型持续返回工具调用时请求永久挂起(占会话写锁与内存);现新增硬性兜底:迭代硬上限 10000(MAX_ITERATIONS_HARD_CAP)+ 墙钟 30 分钟上限(MAX_TOOL_LOOP_WALLCLOCK_MS),触发时报错MAX_TOOL_ITERATIONS_HARD_CAP/TOOL_LOOP_WALLCLOCK_LIMIT走上层错误通道(仅作用于 -1 模式,有限模式语义零变化;三语 i18n 同步) - 流式早启动工具
.catch吞掉全部异常伪装成工具失败:编程错误/系统错误被包装成{ success: false, error }写入历史,错误分类失真;现仅ChannelError(可预期执行失败)保持原包装,其余系统异常记录log.error并以空占位沉降(进度队列正常落定、不重复执行),抛出走上层统一错误通道 ChannelManager.generateStream重试时非内容 chunk 重复产出:yieldedAny在收到 usage/元数据等无内容 chunk 时已置 true,空响应重试会把这些 chunk 再 yield 一遍(token 统计可能双计);重试界限改为「已产出可见内容」yieldedContent- 子代理默认运行时长硬编码不一致:General Worker 描述写 2400s、实际默认 1800s、预设/文档数值不一;现统一为单一常量
DEFAULT_MAX_RUNTIME_S = 1800(executor 默认 + 工具描述 + General Worker 配置 + 类型默认全部引用) - diff 存储压缩/索引层健壮性加固(复扫修复):
- 索引写链(
indexWriteChain)一次失败后永久失效:旧实现chain.then(...)遇到一次 IO 错误后整条链变成 rejected,后续所有索引写入永久失败(文件写成功但永不入索引 → 重启后全部绑定 diff 不可达);现链首.catch(() => {})自愈,单次失败只影响当次并上抛给调用方 - 写入顺序改为「先索引、后文件」:旧顺序崩溃窗口产生「文件有、索引无」的永久孤儿文件(load 永远找不到、cleanup 因对话仍有效不清理 → 磁盘增长以新形式回归);新顺序崩溃窗口只留下「索引有、文件无」的陈旧条目,
loadGlobalDiff读到缺失文件时按 ENOENT 自愈删除(瞬时读错误不误删) rememberDiffOwner磁盘写失败时回滚内存索引条目(防止内存与磁盘漂移、幽灵条目随下次成功落盘写进 index.json)- 索引写失败时 diff 回退
__global__存储(load 兜底路径仍可找到内容),不再写不可达文件 getStorageStats不再把index.json/__global__计入会话数;migrateTo/initialize/updateBasePath路径变更时重置索引缓存(防旧路径条目跨路径污染);cleanupOrphanedDiffs清孤儿目录时同步标记墓碑(拦截在途 deferred 落盘复活目录)- 新增回归测试 3 例:索引写链故障恢复 / 幽灵索引自愈删除 / 统计口径
- 索引写链(
Tests(1.6.9 迭代二)
- 全量回归:backend jest 226 套件 / 2305 用例、frontend vitest 63 文件 / 610 用例、tsc --noEmit 与生产构建全绿;新增
diffStorageDeferred.test.ts(gzip 压缩写盘 / 旧版明文兼容 / 对话绑定落盘 + 删除清理 + 索引定位 / 索引写链故障恢复 / 幽灵索引自愈 / 统计口径)、streamChunkProcessor.test.ts(8 例)、streamAbortWait.test.ts增补(waitForIdle 活跃分支超时);memoryWakeScopes.test.ts分页续读用例改写为单次全量输出断言
[1.6.8] - 2026-08-06
Fixed
- 对话工作区独立(已关闭的绑定工作区仍然生效):此前桌面版切换「打开的工作区」后,绑定工作区的文件夹会从
workspaceFolders移除,工具路径解析(list_files/read_file/write_file/apply_diff/search/find/execute_command/媒体工具等)全部静默回落到当前打开的工作区——对话上下文里还是原工作区的文件树,工具却读写新工作区的文件,AI 会误报「工作区内容与任务上下文不一致」(例如绑定项目 A 的对话在打开项目 B 后把 B 当成了工作区)。现解析层对对话绑定工作区提供「虚拟工作区」能力(按 URI 重建 index=-1 的虚拟文件夹,目录已删除时回退旧行为):backend/tools/utils.ts:getWorkspaceByUri支持已关闭的绑定工作区;parseWorkspacePath单工作区/无工作区时优先解析到绑定工作区(支持绑定工作区名前缀剥离);findWorkspaceForAbsolutePath增补 preferred 参数,绑定工作区内的绝对路径归属该工作区backend/modules/prompt/fileTree.ts:getWorkspaceFolderByUri虚拟解析,绑定工作区已关闭时文件树/静态环境/诊断/固定文件仍限定原工作区(不泄漏当前打开的项目)backend/tools/search/find_files.ts:单工作区模式也按绑定工作区搜索;search_in_files/execute_command/ 媒体pathGuard/list_files的「无工作区」守卫改为「无工作区且无绑定工作区」webview/utils/WorkspaceUtils.ts:新增resolveWorkspaceFolderByUri,validateFileInWorkspace/checkFileExists对已关闭的绑定工作区做虚拟归属校验(Windows 大小写不敏感);webview/handlers/FileHandlers.ts的resolveTargetWorkspaceFolder同步支持
- 新增回归测试:
backend/__tests__/tools/boundWorkspaceIndependence.test.ts(相对路径/绝对路径/名前缀/目录删除回退)、fileTree.test.ts增补「绑定工作区已关闭时按虚拟 URI 生成文件树」 - 打开/保存工作区(多工作区收藏)在桌面版完全失效的根因:
vscode-shim的showOpenDialog/showSaveDialog把 native 层的 Electron 形状结果({ filePaths, canceled }/{ filePath, canceled })原样返回给按 VS Code 契约消费的调用方(result.length/result[i].fsPath/result.fsPath)——打开工作区文件夹弹窗、收藏工作区打开、存储路径选择、设置导入/导出全部静默退化为「取消」。现 shim 统一转换为 VS Code 契约(Uri[] | undefined/Uri | undefined),工作区收藏「保存 + 打开 + 重启保留」链路在桌面版端到端打通;存储路径选择与设置导入/导出同步修复 - 设置导入/导出的对话框 filters 形状不匹配(与上述同族):VS Code 契约的
filters是{ 'JSON Files': ['json'] }对象,native.ts 原样透传给 Electron(要求[{ name, extensions }]数组)导致过滤被忽略/对话框异常;新增normalizeDialogFilters统一转换 - 桌面版
env.openExternal拒绝file:URI(「打开 Skills 目录」等按钮静默无效):file:URI 走不了shell:openExternal的 http/https/mailto 白名单;现 shim 对file:方案的 Uri 改走shell:openPath(含目录/可执行扩展名校验),与 VS Code 中打开系统资源管理器的语义一致 - 修复说明:vscode-shim 全链路扫描(子智能体审查)未发现其他同等级 P0 形状不匹配;已知的 P1 降级项(文件写盘与文档事件脱节、未注册命令桩等)另行跟踪
- 打开/保存工作区(多工作区收藏)仍失效的残留根因(本轮彻底扫描修复):
- 60s 队列超时斩杀原生对话框:
workspace.openFolder/storagePath.selectFolder/settings.import/settings.export的 handler 会 await 原生对话框(用户浏览文件夹可能远超 60 秒),此前在messageHandlingQueue串行队列中等待,60s 超时先触发并回传HANDLER_TIMEOUT——前端请求已结算,用户稍后选完路径 handler 才继续执行(收藏已写入、工作区已切换),但迟到响应被前端当作广播丢弃,UI 状态不同步,表现为「打开/保存工作区点了没反应」。现四个对话框驱动类型全部移入NON_BLOCKING_MESSAGE_TYPES(fire-and-forget,响应仍按 requestId 路由回发起方),MessageRouter.ts同步 - 打开收藏工作区失败被静默吞掉:收藏目录已被删除/移动时(
WORKSPACE_FOLDER_NOT_FOUND)或超时等错误,前端openWorkspaceFolderAction仅console.warn,用户看到「点了没反应」;现统一经showNotification弹出错误提示(取消对话框不打扰) - 响应返回过期工作区状态:
vscode.openFolder在宿主侧异步生效(native 层 fire-and-forget),handler 先于__setWorkspaceFolders返回过期列表/激活工作区,前端拿旧状态覆盖广播;现openWorkspaceFolder打开后轮询等待列表生效(≤3s)再响应(WorkspaceHandlers.waitForWorkspaceOpened) - File 菜单打开的工作区不进入收藏:
File > Open Workspace Folder…走主进程pickWorkspaceFolder,不经渲染层消息路径,打开的工作区不在「已保存的工作区」列表;现BackendHost新增addSavedWorkspaceFsPaths(与 WorkspaceHandlers 同键graycode.savedWorkspaces写入同一global-state.json),File 菜单打开即加入收藏,多工作区「保存 + 打开 + 重启保留」闭环补全 - 收藏写入 fire-and-forget,退出竞态丢数据:
persistSavedFsPaths不 await,打开工作区后立即退出收藏可能丢失;现改为 await 写队列(VS Code 契约一致),ElectronContext.FileMemento新增flush()并在BackendHost.dispose()排空(before-quit兜底) - Windows 路径大小写敏感比较:
__setWorkspaceFolders差集、收藏去重、已打开判定一律按 Windows 大小写不敏感比较(C:\Foo与c:\foo不再误判 added+removed 触发技能重复扫描/列表闪烁,同一目录不再重复触发宿主替换) - 新增显式「保存当前工作区」入口:此前收藏只在打开文件夹时隐式写入,没有显式保存动作,用户找不到「保存工作区」;现工作区选择器下拉新增「保存当前工作区」菜单项(
workspace.saveCurrenthandler + 前端 action,无激活工作区时报错、已在收藏时置灰幂等),三语 i18n 同步 - 顺带修复 WorkspaceHandlers 的 i18n key 前缀错误:
t('webview.errors.*')/t('webview.dialogs.*')在三语语言包中均不存在(实际命名空间是顶层errors.*/dialogs.*),此前所有错误/对话框文案实际显示为原始 key 字符串;已统一修正
- 60s 队列超时斩杀原生对话框:
- 设置页搜索不能覆盖全部设置项(本轮彻底扫描修复):
SEARCH_INDEX从 22 条页签级条目扩展为 110 条(17 个页签兜底 + 93 条带data-search-anchor精确锚点的设置项条目),17 个设置组件(渠道/工具/自动执行/MCP/子代理/存档/总结/图像生成/依赖/上下文/提示词/Token 计数/通知/外观/记忆等)共 93 个设置块逐个加锚点——搜索「API URL」「多模态」「传输类型」「白名单」「宽高比」「分支清理」「排除配置」「音量」「开屏动画」等具体设置项不再搜不到,点击结果直达对应设置块(精确锚点 → h4 → h3 → 首个锚点 → 节容器 五级回退)- dependencies 页签 i18n key 缺失:
settingsPanel.sections.dependencies在三语中均不存在,搜索结果行显示原始 key 字符串且跳转失败;现三语补齐 - 匹配空格敏感:
'token 用量'匹配不到'token用量';query 与关键词统一去空白后includes - 移除误导性关键词:appearance 的「主题/字体/深色/亮色/界面/ui/语言」(外观页不存在)、tools 的「重试/git/固定文件」、channel 的「提示词模式」(实际在 prompt 页)等误导词删除,改为各页真实设置项
- 同名嵌套工作区目录(zip/7z 双解压)路径错位一层:工作区根下存在与工作区同名的真实目录(
proj/proj/...)时,parseWorkspacePath的绑定工作区前缀剥离把首段误当「工作区名前缀」——文件树索引里显示的proj/README.md被解析到根下的README.md,read_file/write_file/list_files/搜索/命令 cwd 等全部 ENOENT(现场会话中模型只能靠「加双前缀」绕过)。现仅当工作区根下不存在同名目录时才剥离前缀;存在时按原样解析(与索引展示一致),多层重名(proj/proj/proj/...)同理只判定首段;路径等于工作区名时解析到同名嵌套目录本身。新增回归测试(双层/多层/写入/纯目录名/无嵌套不回归)
Added
- 设置页设置项搜索:设置面板标题栏新增搜索框——输入关键词实时过滤(结果下拉 + 侧边栏命中页签高亮、未命中置灰),支持键盘上下键选择与回车跳转;点击结果自动切换到对应页签并滚动定位到设置项(节标题或精确锚点,附带 1.6s 闪烁高亮),搜索「存储路径/代理/语言/导入导出/应用信息」可精确直达对应设置块;内置中/英/日三语关键词索引(
SettingsPanel.vue静态SEARCH_INDEX),空结果有提示文案,三语 i18n 同步
Tests
- 新增
backend/__tests__/webview/workspaceHandlers.test.ts(8 用例):保存当前工作区(无激活报错/加入收藏/幂等)、打开工作区(目录缺失报错/已打开直接固定不重复触发宿主/未打开经宿主打开并等待生效后返回新状态/对话框选择自动收藏/取消不写收藏)、收藏持久化在响应前完成 messageRouterNonBlocking.test.ts增补对话框驱动类型(workspace.openFolder / storagePath.selectFolder / settings.import / settings.export)非阻塞断言boundWorkspaceIndependence.test.ts新增「同名嵌套工作区目录」套件(5 用例):双层同名嵌套按真实路径解析(读写)、多层同名嵌套逐层解析、路径等于工作区名时解析到嵌套目录本身、无同名嵌套时前缀剥离行为不回归
[1.6.7] - 2026-08-06
Merged
- 增量合入上游 67d7fb6..f204689(40 提交,对应上游 1.4.2/1.4.3 发布):
- 长期使用时间统计(
backend/modules/activity):ActivityTracker 以「60 秒心跳 + 用户活动事件」采集 IDE 活跃时间(监听编辑/光标/滚动/切换编辑器/终端/窗口聚焦,连续 5 分钟无活动或失焦即暂停,过滤挂机),AI 工作期间同样记活跃(模型流式生成/工具执行/子代理/后台任务打点),按天原子落盘;统计层提供每日使用时长、24 小时作息热力、当前连续工作时长(间隔 ≤15 分钟视为同一会话);新增 AI 工具get_activity_stats;用量统计页新增「使用时间」区块(今日/连续工作/近 7 天总览 + 每日条形图 + 作息热力网格 + 7/30/90 天/1 年/全部范围切换与月度聚合);设置面板新增「用量统计」页签(内嵌使用时间区块 + Token 用量摘要 + 完整统计入口);StoragePathManager存储目录新增activity,工具分类新增「使用时间」 - tokenizer 词表改为运行时联网下载:后端新增
TokenizerResourceManager(cl100k 来自 OpenAI CDN、DeepSeek V3 来自官方 api-docs zip,下载/解压/转换/本地缓存到数据目录,启动复用不再联网,adm-zip解压);前端经tokenizer.getResource消息通道获取、js-tiktoken/lite加载;移除gpt-tokenizer依赖与内置词表(vsix 瘦身 ~4MB),下载失败/离线回退字符类别加权估算 - TPS 统计接入模型专属 tokenizer + 自校准:DeepSeek 用官方
deepseek_v3_tokenizer转换词表(与官方 Python 基准逐位一致)、其余模型用 cl100k;流结束用 usage 真值按模型 EMA 学习校准因子(离群剔除 + localStorage 持久化,系统偏差收敛到35%);工具参数与思考 token 均计入生成速度;超长文本分批计数 - 自动总结历史丢失修复(物理替换语义):自动总结从「只插入不删除」改为物理替换(同一写锁事务内删除被总结区间,
STALE_RANGE并发校验防吞当前用户输入、LOW_QUALITY_SUMMARY质量校验);流式 chunk 透传removedCount、非流式循环补 abort 检查;自动总结始终保留第一条用户消息(删除起点不越过首条真实用户消息,请求组装时首条用户消息早于最后总结则拼到头部) - 渠道默认流式输出与自动重试覆盖:新渠道
options.stream默认true;HTTP 成功但空内容或流式零产出 →EMPTY_RESPONSE_ERROR自动重试;已产出内容但缺 done 标记(上游/代理掐断)→ 显式抛「流式输出被截断」不再假装成功(已产出内容不重试);ChannelError 原样透传不再误包 PARSE_ERROR - 后台命令降 CPU 优先级:
execute_command后台启动的 shell 进程降为低优先级(Windows BelowNormal 优先级类 / POSIX nice +5),跑测试/长任务时让出 CPU 给前台交互 - 后端修复批次:MCP stdio 缓冲 16MB 硬上限 + 单条消息 4MB 拒发;
McpManager.handleServerNotificationper-server 刷新串行化 + 代际重查;工具并行只读组 abort-race + 2s 收尾窗口;fileWriteLockManagerrelease 时 generation 通知等待者 + 50ms 兜底轮询(消除 25ms 固定轮询空转);checkpoint 快照 stat 复用补 size 校验;mailboxDrainEpochs会话删除清理;repeatedCallGuard大字符串改采样哈希;ToolRegistry.getFilteredDeclarations别名归一化;SettingsCore.reset深拷贝;taskManager.cleanup真正清扫终态任务 - 前端修复批次:CustomScrollbar marker 扫描节流(字符变更不再每帧强制布局);
chatStore.initialize()监听器幂等防重复订阅;终端输出 200KB 截断;MessageRouter 条目兜底清理;SubAgentMonitor run 终态缓存清理;MarkdownRenderer imageCache 32MB 字节预算;平滑流式反查索引 O(1);agentStopNotificationController 日志收敛为 debug;删除 scrollTop 死代码 - UI:系统提示词设置页「保存配置」按钮加大加宽(24×24 图标 → 带文字实底按钮)并修复窄窗口文字折行;消息操作按钮补 tooltip 与 compact 布局
flex-shrink: 0;EditDialog 底部按钮强制单行;欢迎页图标改为开屏动画同款手绘 Gray logo(补齐右侧头发色块);开屏动画与 TPS 条改为外观设置可开关(splashEnabled/tpsBarEnabled);使用时间统计默认近 7 天;get_activity_stats工具补齐三语 i18n;纯 tsc 下.vue类型噪音清理(vite-env.d.tsshim 宽松 +MessageItem.vue.d.ts旁路声明) - 上游 PR #14 设置持久化修复与 fork 独立实现(bdf9b36)同源,双端语义已一致
- 保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏 / 多工作区 / 独立版本号增量
- 长期使用时间统计(
Changed(性能与资源占用优化)
- 后端读路径去重:checkpoint 消息节点反查(
getMessageNodeIdAt)加 300ms 短 TTL + LRU 缓存,不再每回合十几次全量读盘;分支图读路径返回只读引用(去掉每迭代一次的全图 structuredClone),缓存加 200 会话 LRU 上限;模型列表拉取加 5 分钟 TTL 缓存;工具声明(tools JSON Schema)按「渠道/模式/启用工具集/MCP 版本」指纹缓存,工具循环每迭代不再重建整棵 Schema - 后端热路径算法优化:上下文裁剪起点归一化由 O(候选×历史) 改为单遍前缀扫描 O(n) 预计算;动态运行时上下文在回合内复用(不再同回合加载两次);流式响应 chunk 解析改 offset 游标累积(消除每数据包 Buffer.concat / 字符串拼接的 O(n²) 拷贝)
- 前端流式渲染优化:hljs 已知语言代码高亮加有界缓存(流式期间同一增长代码块不再每次全量重高亮);
usedTokens改增量指纹(每 chunk 不再全窗口逆序扫描);todo 快照改尾部增量重放(不再每 chunk 全量重放全部消息×工具);MessageList 的 build/todo sticky 计算加短路与指纹,无 build / 无 todo 工具时零扫描 - 前端高频路径:i18n
t()翻译结果缓存(无参调用免 split+逐层遍历);CustomScrollbar 布局值相等检查(无变化不写响应式 ref)、滚动改 rAF 节流、贴底跟随加 2px 阈值;平滑流式文本增量基线(不再每 chunk 对整段累计文本 slice 拷贝) - Electron 内存与 IPC:
diffPreviewContents加 50 条淘汰上限(对齐 VS Code 版,防无界增长);EventEmitter fire 零分配监听快照(版本号惰性重建);workspace.workspaceFoldersgetter 结果缓存(热路径免重复 Uri 编码);渲染层广播直接迭代订阅者 Set;requiresJsonRoundTrip小 payload 短路(高频小消息免全树深遍历);getExtensionVersion加 memo;删除 BackendHost 死代码 - CI:GitHub Actions 构建矩阵收敛为仅 Windows(移除 ubuntu/macos),不再吃 Linux/mac 打包报错
[1.6.6] - 2026-08-06
Added
- 工作区选择器收藏(多工作区收藏列表):顶部栏工作区选择器(文件夹图标下拉)由原生
<select>重写为自定义下拉菜单——「跟随活动编辑器」、已打开的工作区列表、收藏工作区列表三区展示;收藏列表持久化在宿主侧(VS Code 扩展globalState/ 桌面版global-state.json,跨窗口与重启保留),点击收藏条目快速打开(已在当前窗口打开时直接固定为活动工作区,未打开时经宿主打开),条目右侧小 × 一键移除收藏;菜单底部新增「打开工作区文件夹…」入口(加号图标),弹窗选择后自动加入收藏并打开。新增后端处理器workspace.getSaved/workspace.removeSaved/workspace.openFolder(webview/handlers/WorkspaceHandlers.ts),前端新增savedWorkspaces状态与loadSavedWorkspaces/removeSavedWorkspace/openWorkspaceFolder/openSavedWorkspaceactions(frontend/stores/chat),三语(zh-CN / en / ja)文案同步补齐 - Electron 桌面版
vscode.openFolder支持:vscode-shim 的executeCommand('vscode.openFolder')经主进程新增原生操作workspace:openFolder打开指定文件夹并替换当前工作区(持久化到 workspace state,窗口标题同步更新);收藏工作区快速打开由此端到端打通
Changed
- 仓库改名同步:GitHub 仓库已由
czocelot/Gray-Code-ocelot改名为czocelot/Gray-Code-Desktop,全部文档与链接同步更新——README.md/README_EN.md(徽标、下载、clone、issues 链接与 clone 目录名)、根与 electron-app 的package.json(repository.url / homepage / author.url)、设置页「应用信息 → 仓库」链接(frontend/src/components/settings/SettingsPanel.vue)
Fixed
- 多对话并发编辑多工作区的 checkpoint 全局根锁(并发编辑可用性的最大阻碍):存档创建此前对全部工作区根做快照并持有全局文件根锁
''(与所有路径互斥),对话 A 每次写工具前后(默认配置对 write_file/apply_diff/execute_command 等全部写工具在 before+after 建存档)的存档期间,绑定其他工作区的对话 B 的写工具全部lockConflict失败。现createCheckpoint按对话绑定的工作区(conversationManager.getMetadata().workspaceUri)裁剪快照范围与锁范围(CheckpointOperationLock新增fileLockPaths选项,按工作区根绝对路径加锁;未绑定/绑定工作区已关闭时回退全部根,旧行为不变)——绑定不同工作区的对话在彼此存档期间可无冲突地并发写文件,真正实现多 AI 多工作区并行编辑 - 文件写锁 key 不按对话工作区解析(跨工作区误冲突/漏锁):
ToolExecutionService加锁前把写目标路径按对话绑定的工作区解析为绝对路径(与工具执行同一口径resolveFileToolPathWithInfo)再tryAcquire;此前多工作区下同名相对路径(如src/a.ts)解析失败回退进程 cwd 相对路径,不同工作区的同相对路径会映射到同一锁 key 造成误冲突,或映射到不同 key 造成漏锁。diff 预览延迟写盘路径(PendingDiff.absolutePath)本就用绝对路径,无此问题 - 回归测试(CheckpointManagerWorkspace):绑定工作区对话的存档只快照该工作区根、未绑定对话仍快照全部根、绑定对话存档期间其他工作区的写锁持有者不受阻塞
[1.6.5] - 2026-08-05
Merged
- 增量合入上游 10c565c..67d7fb6(4 提交,详见 [Unreleased]):TPS 条移除空闲期随机模拟假数据并精确归零(
SETTLE_EPS)、工具调用输出计入 TPS;CharFlow 流式字符流水线渐进渲染(高频直连/低频快照 + 渐进 markdown 提升与折叠预览修复);开始动画「草稿→上色」叙事升级与主界面承接淡入;平滑流式生命周期修复(toolsExecuting 终结清理移至函数末尾,覆盖无 content 增量路径)。保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏 / 多工作区 / 独立版本号增量
Fixed
- 记忆删除的树摘要残留(子智能体审查修复):
MemoryManager.deleteEntry删除最后一条记忆(id=T-1)时不再清空覆盖被删记录的尾部树摘要——删除后 T 收缩,TREE/2的[T-2,T)块、TREE/4的[0,T)块等仍引用已删内容;此后note使长度回升时wake/zoom会重现已删除的记忆且pending()认为该块已压缩而永不重建。现按新长度截断树文件(与truncateLog同口径):完全位于保留区内的块摘要保留、覆盖被删记录的块清空。另将重建循环的逐条全量Buffer.alloc(T*LOG_REC)改为单条LOG_REC复用缓冲(超大记忆集删除不再有内存尖峰),损坏文件中的空记录改为跳过而非 break(后续有效记录不再被静默丢弃)。新增「删尾条目树摘要截断 + 摘要不重现已删内容」回归测试 - 分支图 append / 删除同步绕过了 60s TTL 缓存(声称未落地):
appendHistoryToGraph与syncGraphAfterHistoryDelete此前直接repository.load()全量读盘,主历史每次 append 的「读图 → 改 → 原子写回」仍重复全量磁盘 IO。现收敛到与loadGraphForWrite共用的loadGraphCached(缓存命中 + mtime/size 校验 + 语义损坏拒绝覆盖),热路径磁盘 IO 实际削减 - metaCache 未命中路径返回活引用:
getMetadataLight/loadStoredMetadata的未命中路径把刚缓存的result.value原引用直接返回、getMetadata损坏 fallback 路径把已缓存的fallback原引用返回——调用方原地修改会污染缓存。现缓存一律存structuredClone快照、返回深拷贝;persistMetadata写后回填同样存快照(保存后原地改 meta 不再污染缓存) - 负缓存 null 遮蔽 getMetadata 的历史重建 fallback:meta.json 缺失(not_found)时
getMetadataLight先负缓存 null,后续getMetadata命中 null 直接返回,不再走磁盘路径按历史重建——有历史无 meta.json 的会话标题/时间戳持续缺失直到下次写入。现getMetadata命中 null 时先探测历史索引:历史仍存在则继续走磁盘重建并回填缓存。新增 2 项回归测试 - getMetadataLight 声称的 structuredClone 未落地:命中路径仍是
JSON.parse(JSON.stringify(...))(序列化往返开销与声称不符),现统一改为structuredClone - 流式平滑显示层在 toolsExecuting 后泄漏:
handleToolsExecuting收到 content 后消息已置非流式、正文输出结束,但未终结平滑条目(smoothTexts+ manager entry)——流在 toolsExecuting 后异常终止(无终结事件且未走 cancelStream)时条目残留。已随增量合入上游 67d7fb6 统一:finishSmoothStreamForState移至函数末尾无条件执行(toolsExecuting 即当前模型文本段终点,无 content 增量同样清理当前流条目;放完积压、销毁实例、删除显示文本,UI 立即切回真实 content);工具返回后模型续写正文时pushSmoothText以当前 part 真实文本为基线重建实例(与段落切换语义一致)。新增回归测试 - 前端 i18n 参数替换的
$替换模式注入:useI18n.translate用字符串替换result.replace(regex, String(params[key])),参数值含$&/$1/$'时被String.replace解释成替换模式(如文件名price\$1.txt变price.txt)。现改为函数替换() => String(params[paramKey])(与核心 i18n 模块写法一致)。新增回归测试 - Electron About 菜单在 macOS 关窗后崩溃:
dialog.showMessageBox(mainWindow!, ...)无空值/销毁守卫,macOS 关闭全部窗口(window-all-closed 不退出)后点击 About 抛 "Object has been destroyed";现与native.ts的usableWindow模式一致退化为无父窗口对话框。pickWorkspaceFolder同步补 isDestroyed 检查;before-quit 的dispose()改经Promise.resolve().then包裹(dispose 同步抛错不再绕过超时兜底与app.exit(0)) - HttpClient MCP 握手 clientInfo 版本硬编码 1.0.5:HTTP/SSE MCP 传输的
initialize仍硬编码过期版本,与 Stdio 客户端不一致(已统一走createGrayCodeMcpClientInfo);现 HTTP 客户端同样改用统一工厂函数 - TokenCountService 外部 abort 透传是死代码(声称未落地):
fetchWithTimeout的externalSignal参数存在但 8 个计数请求调用点无一处传入,停止流/切会话时进行中的计数请求只能等 15s 超时。现贯通全链:countTokens/countTokensWithChannelConfig/countTokensBatch→ 四路提供商方法 →fetchWithTimeout,TokenEstimationService(preCountUserMessageTokensBatch / countSystemPromptTokens / countTextTokensBatch)与ContextTrimService.getHistoryWithContextTrimInfo/getHistoryWithGranularFallback透传,ToolIterationLoopService流式/非流式两路径以回合abortSignal传入——停止按钮可立即中断回合前的计数请求 - execute_command WSL 同步检测仍用
execSync字符串拼接:checkShellAvailabilitySync的wsl --status是常量字符串(无注入面),但与"同步检测统一 execFileSync 参数数组"的口径不符;现改为execFileSync('wsl.exe', ['--status']) - ContextTrimService 窗口未知时拒绝退化为 UNKNOWN_ERROR:
getHistoryWithGranularFallback的throwContextOverflow在模型contextWindow未知且无合法候选(历史结构损坏)时抛普通Error,前端错误码退化为UNKNOWN_ERROR;现以渠道maxContextTokens作为 envelope 参考上限照常抛ContextBudgetExceededError(保持 CONTEXT_OVERFLOW 语义) - 会话删除不清理回合级 fallback 切点缓存:
granularFallbackStartByConversationMap 在对话删除路径未挂钩,已删会话条目缓慢累积;新增ChatHandler.handleConversationDeleted(清clearTrimState),deleteConversationhandler 删除成功后调用(失败仅告警不阻断删除) - 清理 App.vue 遗留
.loading-container死样式(changelog [1.6.4] 声称已清理但实际残留);修正 lineDiff trace 内存注释(实际约 1/2,非 1/4)与缓存淘汰语义文档(命中移队首的 LRU,非字面 FIFO)
Tests
- 后端:deleteEntry 删尾树摘要截断、metaCache 负缓存不遮蔽 fallback 重建、损坏降级回填后 getMetadataLight 不再负缓存 null、nonStreamAutoSummarizeTurn 适配 abort 透传新签名
- 前端:handleToolsExecuting 平滑条目清理(含无 content 增量同样终结当前流条目)、useI18n 参数值
$&/$1/$'原样输出
[1.6.4] - 2026-08-05
Merged
- 同步上游 49a37f2..10c565c(PR #11/#13 等:启动动画 Splash、TPS 实时可视化与流式平滑输出(SmoothStreamer / smoothTexts / TpsBar)、上下文预算三层重构(
ContextBudgetExceededError/CONTEXT_OVERFLOW仅真实超窗抛出、模型窗口软/信封/硬边界、固定 prompt 计入预算、低收益总结跳过)、diff 工具行级差分缓存与批量加载并行化、子代理 transcript 索引投影与惰性加载(lastSentHistoryProjection)、run 终态落盘 flushRun、单会话停止不再取消全局未决 diff、对话删除检查点清理失败显式报错、上游回移植 fork 的getMetadataLight元数据缓存等性能优化),保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏 / 多工作区 / 独立版本号增量
Changed
- 工作区文件树按 (工作区 + 深度 + 自定义忽略模式 + 节点预算) 键控加 30s TTL 缓存:工具循环中每轮请求同步重建整棵目录树(
readdirSync全递归,最多 10000 节点)的磁盘 IO 与正则求值大幅减少;.gitignore的 mtime 纳入每次命中校验(改动即失效重建),其余文件变更接受 TTL 内短时陈旧(与getSystemPrompt60s 缓存同级语义);新增invalidateFileTreeCache供测试/诊断清理 getMetadataLight缓存命中返回从JSON.parse(JSON.stringify(...))深拷贝改为structuredClone:对话列表分页(每页 30 条 × 16 并发)命中路径的序列化往返开销显著下降getCustomMetadata改走 metaCache(复用getMetadataLight):trimState / todoList / pinnedFiles / skills / subAgentRuns 等键在工具迭代热路径每轮读取多次,此前每次都是整份 meta.json 的磁盘读 + JSON parsegetMetadata损坏降级(fallback 重建)结果回填 metaCache:损坏文件改名备份后getMetadataLight曾负缓存 null,导致对话列表标题/时间戳持续缺失直到下次写入;现重建即回填,且与轻量读共享同一缓存- SubAgent
flushPersist落盘从「getCustomMetadata 全量读 + setCustomMetadata 链内重读」合并为单次原子updateCustomMetadata(链内读改写):子代理流式期间每 1.5s 的落盘 IO 减半,且消除两次读取不一致的隐含分支;store 未实现原子接口时自动回退读改写 - 分支图(branches.json)按文件路径(baseDir + conversationId,天然区分多工作区)加 60s TTL 内存缓存:主历史每次 append 的「读图 → 改 → 原子写回」不再重复全量磁盘 IO;命中前 stat 校验 mtime+size,文件被仓储之外的路径改写时自动失效;缓存存/取均为快照深拷贝,杜绝调用方原地修改污染
- 历史段缓存字节估算从全量
JSON.stringify改为前 16 条抽样按比例外推:段内可能含数十 MB 超大工具结果,缓存写入不再付出二次全量序列化成本(字节软上限仅用于 LRU 淘汰优先级,无需精确) - 前端 i18n 参数替换的占位符正则按转义键缓存(
useI18n.translate在消息列表/工具卡渲染中高频调用,不再每次new RegExp) - 消息项加
content-visibility: auto+contain-intrinsic-size:长对话上拉展开后视口外消息由浏览器原生跳过渲染/样式计算(兼容性回退 = 无样式类特性,仅失去优化) - 工具结果合并逻辑收敛为公共
utils/toolResult.mergeToolResult(MessageList / MessageTaskCards / todoList 三处实现语义分叉统一);工具名/描述 i18n 收敛到utils/toolLocalization(useCheckpointConfig / AutoExecSettings / DependencySettings) - ToolMessage 自动确认倒计时从 50ms tick 降频为 200ms:有 pending diff 时每秒响应式更新从 20 次降为 5 次(显示粒度 100ms 不变)
- Shell 可用性检测缓存加 5 分钟 TTL:运行期间新装 shell(如 WSL)不再需要重启才能被工具声明识别
- 流式热路径诊断日志(
handleToolsExecuting/handleToolIteration/handleComplete/handleStreamChunkBatch跳批统计)改由性能诊断开关(localStorage.graycode.perf=1)门控:默认关闭时不再执行模板字符串拼接与计数;agentStopNotificationController 生命周期调试日志改由localStorage.graycode.debug=1开关门控 - 生产构建压缩:根 esbuild 单次构建与 Electron 桌面构建
minify: true/ 关闭 sourcemap(watch 模式保留原始形态);主进程 bundle 体积与启动解析时间下降 - 前端主入口分包:vue/pinia、highlight.js、katex+markdown-it 拆为独立 vendor chunk(主入口 2.38MB → 1.55MB),mermaid/cytoscape 保持原生动态 import 懒加载(不做 modulepreload 预取);桌面端
graycode://协议与 VS Code webview 均按相对路径加载,mtime 缓存已覆盖 - Electron 桌面版主进程包:
readRootPackageMetadatamemoize(打包后 package.json 不变,公告/版本检查多路径不再重复同步读盘);__setWorkspaceFolders按新旧列表差集生成 added/removed(此前把保留文件夹重复报为 added 导致技能重复扫描、被移除文件夹不触发清理);dialog/reload 对已销毁窗口(isDestroyed)加固,不再抛 "Object has been destroyed" - 公告检查的 CHANGELOG.md(数百 KB)解析按 mtime+size 缓存:升级后首次启动与设置页重复触发不再全量读+正则解析
esbuild.config.js移除无引用的 externaltypescript;electron-app/build.mjs支持--dev(保留 sourcemap/未压缩)与--watch;electron-app 新增typecheckscript(首次接入即修复工作区变更监听从未真正 dispose 的隐患);CI 增加后端 jest + 前端 vitest 单测与三端 typecheck 步骤、同一分支连续推送自动取消旧构建(concurrency)
Fixed
- 移除无引用的运行时依赖
@vscode/codicons(图标由resources/codicons内置 CSS/字体与 VS Code 宿主提供)与nanoid(ID 生成实际走generateId/randomUUID),锁文件同步后 npm audit 仍为 0 漏洞 - 设置持久化丢失(重启回滚):
VSCodeSettingsStorage.save()的「只写变更键」快照直接保存活对象引用,保存成功后同一嵌套对象的原地变更(自动执行toolAutoExec、工具策略toolPolicy、预设条目promptEntries.enabled、toolsConfig.*各类工具配置、单工具开关)被deepEqual的a===b引用短路误判为「无变化」而跳过写盘——UI 显示正常但重启全部回滚。快照改存深拷贝与活对象解耦;saveToolsConfigEntry/setToolAutoExec/setToolEnabled同步改为整体替换对象(防御任何存储实现);新增「load 后原地变更 ×2 + 重启读回」回归测试 - 原始记忆条目无法删除(功能缺失):设置页「原始记忆条目」此前只有查看/编辑、无删除入口。新增
MemoryManager.deleteEntry(真·单条删除:读全量 → 过滤 → 重编号 → tmp/rename 原子写回,删除中间条目后其后的 id 前移一格并清空旧树摘要;与truncateLog的尾部截断不同,不会连坐误删之后的记忆)、deleteMemoryEntryhandler、设置页删除按钮 + 确认框(三语 i18n);memory_forget工具描述强调「单个数字 ID 是截断模式,会删除该 ID 及之后所有记忆」,防模型/用户误解连坐误删;新增 6 项回归测试 - 清理遗留调试输出:App.vue 复制/加载日志、SoundSettings 预览日志、ToolExecutionService 多模态丢弃日志(降级 debug)、format.ts 5 个无引用死函数、test/jest.setup.ts 空文件;三处 hover 定时器(InlineContextMessage / ContextBlocks / InputBox)补卸载清理
[1.6.3] - 2026-08-05
Merged
- 同步上游 016706f..49a37f2(PR #10 等:子代理续跑同 run 身份与 transcript、分支树面板重构为轨道式泳道「完整消息图」+ 工具分类分组、总结模型透传(summarizeContext 处理器 / 自动总结当前模型 / 独立总结渠道隔离)、上下文管理关闭时手动总结边界生效、MCP server ID 由服务器名生成可读 ID),保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏 / 多工作区 / 独立版本号增量
- 上游 1.4.1 条目原文(部分内容已随 PR #9 在 [1.6.2] 记录,此处为上游条目全文,供核对):
Fixed
- 修复流式平滑输出折叠思考预览变空(被透明字符“挤出去”):折叠预览是单行滚动容器,CharFlow 开启
followEnd后每次 append 滚到最右端,而新字符带animation-delay错峰淡入——delay 期间opacity: 0但占据布局宽度,滚动目标恰好落在透明占位字符上,高 tps 时预览区永远显示空白占位。现折叠预览(MessageRenderBlock)注册显示层时禁用淡入(noFade,直接文本追加),最右端始终是真实可见字符;展开态保留逐字淡入。 - TPS 条移除空闲期随机模拟假数据并修复归零/统计口径:
TpsBar删除「流不活跃时伪造 ~12 tok/s 波动」的模拟逻辑(含 is-sim 视觉弱化),流结束/空闲时直接绘制tpsMeter真实 EMA 衰减曲线——柱子自然变矮滚出屏幕、不再被瞬间清空,归零后保持0.0 tok/s与空画布直到下一轮真实流;tpsMeter新增归零阈值SETTLE_EPS(无事件时 EMA 衰减到 0.05 tok/s 以下精确归零,浮点衰减不再悬停在不可见小值);工具调用输出计入 TPS:streamChunkHandlers在 functionCall 增量到达时按函数名 + 参数 JSON 长度粗估record(此前仅文本 delta 计入,工具参数流式输出期间曲线错误回落)。 - 删除消息范围或单条消息前等待主流真正退出:
deleteMessage/deleteSingleMessage先经abortAndWaitForCompletion(或cancel+waitForIdle)等待流退出再执行删除,避免停止后的迟到写入覆盖删除结果。 - 修复扩展宿主重启后子代理 Monitor 永久显示 running/queued:加载历史 run 记录时把上一宿主遗留的非终态记录纠正为
interrupted(当前进程仍活跃的 run 不受影响,按快照存在性区分)。 - 修复 shell 可用性检测的命令拼接注入面:
checkShellAvailability的 wsl / where / which 检测从cp.exec字符串拼接改为cp.execFileargv 数组传递(customPath 属用户可控配置,不再拼进 shell 命令)。 - Webview CSP 加固:ChatViewProvider 与 SubAgentMonitorPanel 的内联脚本从
'unsafe-inline'改为 nonce 机制(每面板随机 nonce,脚本标签显式携带),不再依赖内联执行豁免。 - 前端正则高亮 ReDoS 护栏:新增
regexGuard(源长度 500 上限 + 危险分组量词检测 + 构造失败回退),history_search 高亮不再因畸形正则阻塞 Webview 渲染线程(与后端搜索护栏同一限制)。 - 修复手动总结请求丢失当前对话模型:
summarizeContext处理器此前只转发conversationId/configId/abortSignal,前端载荷中的modelOverride在 webview 层被丢弃,频道配置model为空时总结请求仍发送空模型名(HTTP 404: No available providers at the moment)。处理器现原样透传modelOverride,与后端SummarizeService的模型透传修复(含独立总结渠道隔离与默认模型回落)闭环;新增处理器层透传回归测试。 - 修复总结请求不携带当前对话实际选中的模型:频道配置
model为空、用户在界面临时选择模型时,手动总结(SummarizeService.handleSummarizeContext读取请求modelOverride)与流式/非流式自动总结(ToolIterationLoopService两处调用透传当前回合modelOverride)此前均向 OpenAI 兼容接口发送空模型名(HTTP 404: No available providers at the moment);使用独立总结渠道时主动隔离主对话模型,未显式指定总结模型则回落到独立渠道自身默认模型,不再错误继承主对话的modelOverride。 - 修复手动总结假成功:上下文管理关闭时发送路径直接从索引 0 读取历史,忽略已存在的手动 summary 边界(总结消息只插入历史而不物理删除旧消息),界面显示总结成功、下一次请求却仍携带全部旧上下文。现
ContextTrimService在策略禁用时也查找并应用最后一条总结边界作为发送历史起点(decision.action =manual_summary_applied)。 - 修复编辑分支 / reroll 流停在「工具待确认」(awaitingConfirmation 终结)后 BranchSwitcherBar 不显示新候选:
streamHandler的awaitingConfirmation分支此前遗漏finishBranchStreamTracking(complete/error/cancelled/toolIteration 终结均有,唯此遗漏),_pendingBranchRefreshAfterStream标记残留导致分支图不刷新——用户点「保存」后不切对话看不到「‹ 2/2 ›」切换器,切换对话触发loadBranchGraph后才恢复。现awaitingConfirmation终结同样消费标记并刷新分支图(后端编辑候选在流开始时已落盘,刷新安全且即时);新增editBranchRefresh.test.ts覆盖 complete / cancelled / toolIteration 审批门闸 / awaitingConfirmation 四种终结路径 - 上下文阈值恢复为自动总结软触发条件,不再作为主 Agent 请求硬上限:
ContextTrimService预算体系重构——fallback 拒绝边界只取当前模型明确声明的contextWindow(ContextBudgetExceededError/CONTEXT_OVERFLOW仅在最小合法请求仍超窗时抛出),模型元数据缺失时最多 best-effort 裁剪,渠道maxContextTokens与默认值不再伪装成硬边界;contextThreshold只触发自动总结与优先压缩目标,关闭上下文管理时也不因总结阈值/显示上限阻止主请求(新增显式总开关与旧版双开关回归测试) - 跳过固定 prompt 占比过大时的低收益自动总结:系统提示词 + 动态上下文(
fixedPromptTokens)计入预算——固定 prompt 已超软阈值且新增历史很少时跳过总结(decision.action =auto_summarize_skipped_low_savings)并继续主请求;真实窗口已超限时仍进入请求级 fallback(hard_fallback_needed),位于软阈值与硬窗口之间时原样继续;ToolIterationLoopService流式/非流式路径把fixedPromptTokens透传给getHistoryWithGranularFallback,fallback 预算细化为软预算(threshold 与模型窗口 95% 取小、扣除 provider 预留)、完整窗口 envelope 与硬边界三层 - 修复总结预算口径:手动总结不再受自动总结输入比例(默认 50%)提前拒绝,仅在接近总结模型真实窗口(95%)时预检失败返回
CONTEXT_OVERFLOW;自动/手动总结按actualModelId解析模型contextWindow(独立总结渠道用总结模型、否则用当前对话模型),预算计入内置总结提示词、用户总结提示词与 provider 预留(resolveSummaryInputBudget);resolveSummarizeRange保留预算支持mainModelOverride,按主对话实际模型窗口解析而非渠道显示上限 - 修复 SubAgent transcript 大对象重复保存与持久化生命周期:终态
lastSentHistory改用索引投影(lastSentHistoryProjectionv1,可匹配contents的消息只存contentIndex、无法匹配的内嵌原文,还原时只保留 provider 消费的 role/parts),大型工具结果/图片不再在 transcript 内保存两份,运行中仍保存完整数组;独立 transcript 按需惰性加载(transcriptLoaded,Monitor 聚焦/续跑/改消息时才读正文,恢复会话只读轻量 metadata);工具返回前flushRun等待终态 transcript 与元数据落盘(有限重试,扩展重载不再把已完成 run 误判为 interrupted);continueFromRunId续跑前检测transcriptLoaded === false并先加载完整 transcript(保住 provider 前缀缓存命中所需的lastSentHistory) - 修复停止/删除生命周期边界:单会话停止只取消该会话的未决 diff(
cancelAllPending(conversationId)),仅cancelAllStreams仍执行全局清理(此前停止 A 会话会取消 B 会话等待确认的 diff);检查点备份/索引位于扩展 globalStorage,deleteCheckpoint/deleteCheckpointsFromIndex/deleteAllCheckpoints/ 批量删除在无工作区时改用稳定虚拟锁键继续删除(此前静默失败);对话删除时检查点清理失败返回显式错误(DELETE_CONVERSATION_CHECKPOINT_CLEANUP_FAILED)且不再继续删除会话 - 上下文溢出错误消息本地化与投影性能优化:
SummarizeService的CONTEXT_OVERFLOW与ContextBudgetExceededError对外消息改走 i18n(zh-CN/en/ja),ChatHandler.formatError统一按 code 透出并携带估算参数(流式/非流式同一出口);终态lastSentHistory索引投影改为「粗桶 + 惰性精确索引」两级匹配(大型 parts 不再全量 stringify 作 Map key),flushRun落盘重试次数提取为MAX_FLUSH_RETRY_ATTEMPTS常量 - 修复流式输出中长代码块无法滚动:
MarkdownRenderer通过v-html渲染,内容每次更新都会整体重建 DOM,代码块内部滚动容器(pre.code-block-wrapper,max-height: 400px+overflow-y: auto)因此被销毁重建、scrollTop归零——流式期间长代码块一旦出现滚动条就无法滚动(滚动位置被重置、滚动条滚不动)。现流式期间(is-streaming)在根节点挂is-streaming类,CSS 据此放开pre的max-height(自然展开,用户跟随输出阅读),流式结束后移除类、恢复max-height限制与内部滚动;思考块(thought)内的MarkdownRenderer同步透传is-streaming(此前缺失),使思考过程里的长代码块同样生效。新增MarkdownRenderer.test.ts(is-streaming 类切换、代码块结构完整性、流式内容追加渲染)与MessageRenderBlock.test.ts(思考块 is-streaming 透传)。 - 修复流式平滑输出生命周期清理不全(SmoothStreamer 与 smoothTexts 条目泄漏):
handleError与终结性toolIteration此前先置空streamingMessageId再清理导致清理 no-op;complete/cancelled 的占位 id → 持久化 id 迁移后按新 id 清理残留旧条目;cancelStream/cancelStreamAndRejectTools/deleteMessage/deleteSingleMessage/clearMessages/resetConversationState/closeTab/switchTab等本地重置路径(closeTab 时后端 cancelled 被后台缓冲丢弃、前端收不到终结)全部补上清理;占位 id 迁移时同步迁移 manager 条目键;disposeAllSmoothStreams挂到 webview 卸载兜底。 - 修复流式平滑「替换最后一个文本/思考块」在新段落前导空白时错位(上一段已完成内容被平滑文本覆盖 → 消失→重现闪烁):纯空白 delta 不再进入平滑层(与 flushText 的 trim 语义对齐);显示层
smoothTexts值改为携带partKey,RenderBlock增加 partKey 标识,MessageItem只替换 partKey 匹配的块、找不到匹配块(快照重建的合并块)时回退真实文本。 - 修复流式平滑档位实时切换跳变:off→on 时新建 streamer 以当前 part 已累计真实文本为显示基线(不再整段消失重打);on→off 时立即 flush + dispose + 删除显示文本,切回真实内容。
- 修复流式结束/中断时超长代码块高度塌缩导致阅读位置丢失:
MarkdownRenderer流式期间记录实际高度超过限制的代码块,is-streaming类解除时对这些块保留展开态(keep-expanded,max-height: none),用户点击换行按钮或滚动离开该块后恢复正常高度限制;流式类采用「滞后副本」过渡,杜绝先塌缩再弹回的闪烁。 - 修复 TPS 条在 Agent 工具执行/思考停顿(>2s 无 token)时误显示随机模拟数据并来回切换:TpsBar 引入「流活跃」信号(
chatStore.isStreaming || isWaitingForResponse)——流活跃期间只显示真实(衰减)曲线、禁止启动模拟;模拟阶段加视觉区分(透明度降低)。修复tpsMeter.record无容量上限(webview 隐藏/后台流停表期间 events 无界增长):记录上限 1000 条、超出丢最旧。
Changed
- 流式输出期间已完成段落即时渲染 markdown(渐进式提升):
CharFlow新增settledText/promote——已定型文本到达安全段落边界(以空行\n\n结尾、且行首代码围栏 ```/~~~ 配对,未闭合代码块整块保留到围栏闭合)时,把该前缀从字符流水线剥离并交给MessageItem新增的渐进MarkdownRenderer即时渲染,未完成尾巴继续逐字淡入;长回答不再等到输出结束才出现格式。段落切换/终结时渐进内容随显示层释放(稳定块完整接管,无重复显示);档位切换与组件重建(切标签页)时 promote 边界(promotedText)随 entry 继承/重放,CharFlow 只恢复未提升尾巴,显示连续不跳变。 - 初次载入「开始动画」升级为完整叙事(Splash.vue):蓝图点阵背景 + 晕影聚焦;笔尖光点沿描线路径执笔画出少女(SMIL
animateMotion+mpath直接引用线稿 path,先帽后身,与描线stroke-dashoffset同曲线同节奏);完稿瞬间线条定影提亮、此后呼吸待机;标题改为「Gray 粗 / Code 细」+ 蓝色终端光标▍闪烁 + 副标题「AI CODING ASSISTANT」;原横线脉冲替换为 3-bit 格雷码等待线(000→001→011→010→110→111→101→100 循环,每步恰好只变一位,ready 后归一为蓝色实线);淡出升级为 blur+scale 消散,.chat-view加 0.3s 淡入承接;DRAW_TOTAL_MS1400→1700、minDisplayMs默认 1100→1700,描线/定影/格雷码时间轴严格对齐;prefers-reduced-motion 分支同步更新(SMIL 光点直接隐藏);测试常量同步。 - 开始动画「草稿→上色」叙事升级 + 格雷码线可见性修复(Splash.vue):SVG 改双层结构——色块层(body 按 M…Z 拆块:身体/头发/脸镂空/帽檐/帽身,后画的覆盖重叠区)在描线完成后 1.6s 起
ink-in错峰渗入(身体 1.6s / 帽子 1.75s),线稿同刻退位为细描边(line-retire动画,delay 自元素插入起算,与 settled 类时机解耦);灰阶色块用color-mix从 currentColor 派生,亮/暗主题自适应;定影闪光挪到 2.0s 当「定稿章」。格雷码等待线修复「开场即全灭 + 归一不可见」:起跳提前到 1.15s、周期 2.4s→2s、相位旋转到 001 起始、对比度 0.15/0.9→0.12/1、容器与副标题同款 fade-up 入场;ready 退场改两拍——先归一(merging类,0.42s:蓝线合并 + 光标定格实心 + 一次性line-flash闪光)再淡出(0.45s),归一不再被淡出淹没;DRAW_TOTAL_MS1700→2300、minDisplayMs默认 1700→2300;光标闪烁改steps(1, end)惯用写法;splash 根加role="status";prefers-reduced-motion 分支同步(色块直接可见、线稿静态细描边);测试常量与两拍退场断言同步。 - 移植 fork 的全仓性能优化(保留插件形态,不涉及桌面版 electron 层):
getMetadataLight接入会话元数据 LRU 缓存(256 条):对话列表分页(每页 30 条)、用量统计与检查点查询的逐对话读取从「每次 fs 读 + JSON parse」降为纯内存命中;所有写路径统一失效/回填——saveMetadata落盘点收敛为persistMetadata(写后回填缓存),saveHistory/appendHistory/历史迁移/分支全量重写等刷新updatedAt的路径失效缓存,删除会话同步失效(含负缓存);读侧返回深拷贝防调用方污染usedTokens两趟循环(正序找最新总结估算 + 逆序找最后一条助手 usage)合并为单趟逆序扫描:流式期间每个 chunk 都会使该 computed 失效,数组访问量减半;语义等价(新增 6 例回归测试覆盖 usage/总结估算 timestamp 优先级)- 占位消息定位 Map 索引化:
isLateTerminalChunkWithoutStreamId与handleError的 O(n)find改为getMessageIndexById(与其它热路径一致) handleStreamChunkBatch诊断日志不再slice + filter分配临时数组,改为循环计数(终结 batch 每次都会走到)
- Diff 工具卡顿优化(前端行级差分与渲染热路径,覆盖 apply_diff / write_file / search_in_files 面板与 VirtualDiffLines):
lineDiff新增带缓存的computeLineDiffCached:按内容 + 起始行 + 编辑预算键控、上限 32 条的 FIFO 缓存。流式结果更新 / 组件重渲染期间同一 hunk 直接复用上一次结果对象,不再重复 Myers 计算;同一结果对象引用同时让下游虚拟列表的 props 保持稳定,不再整树重渲染- Myers 快速失败:新旧核心区域无公共行且 n+m 超出编辑距离预算时直接输出退化结果(语义与预算耗尽时完全一致),大文件整体重写场景从跑满 768 层迭代降为一次行 ID 集合探测
- Myers trace 改为按层动态分配(第 d 层仅覆盖 [-d, d] 对角线,offset 随层递增),总内存约为原来的 1/2,长距离 diff 的分配压力显著下降
apply_diff/write_file/search_in_files的行级差分改为增量式:只对新加载/变更的文件或块计算并缓存结果(此前任一文件加载完成都会触发全部文件全量重算);展示行从「模板内每次渲染 slice」改为「按展开状态缓存的稳定引用」,父组件重渲染不再生成新数组导致VirtualDiffLines反复整体重渲染search_in_files/write_file批量 diff 内容加载改为并行(此前逐个await串行等待,N 个文件需 N 次往返);search_in_files匹配列表按文件预分组,模板内不再对全量结果重复 filterVirtualDiffLines滚动事件按 rAF 节流:连续滚动时每帧至多同步一次视口,不再高频触发窗口行计算与重渲染ToolMessage对diff.statusChanged相同载荷去重:后端重复广播同一 pending diff 状态(定时器刷新 / 多面板路由)时跳过全部响应式更新,不再让所有消息组件无谓重渲染
- 存档点排除配置的默认类别行布局修正:「N 条规则」计数与「编辑」按钮组合为右侧操作列整体右对齐(计数紧贴按钮左侧),不再因各勾选框标签宽度不同而在行间漂移居中;补上此前缺失的编辑按钮 hover/禁用样式。
- 子代理工具白名单/黑名单改为按分类分组展示:新增公共工具分类模块
frontend/src/utils/toolCategory.ts(工具设置页与子代理设置页共用同一套分类名/图标映射),子代理面板工具列表从「内置工具 / MCP 工具」两个平铺大列表改为按后端 category 分组的分类卡片(文件、搜索、终端、媒体等,MCP 独立成组,缺省分类归入「其他」);每个工具项显示本地化名称 + 等宽工具 ID + 描述,MCP 分类文案接入三语 i18n;工具设置页同步改用公共分类模块(展示行为不变)。 - 分支树面板「完整消息」升级为「完整消息图」(高级模式):由目录树缩进改为轨道式泳道布局——每条消息一行,轨道列数由同时存在的候选分支决定(候选分支走完即释放轨道、后续新候选复用,不再随消息数量无限向右扩展);分叉以水平连接线表达,活跃路径轨道线高亮;默认折叠连续线性段,新增「展开完整消息」开关可查看全部节点;「分支导航」缩略版保持不变,三语文案同步。
- 总结 Token 统计改为「主上下文压缩量」口径:新增
SummaryTokenStats(被替换历史估算 token、新摘要 token、估算节省量、总结前主上下文 token 与总结后估算值),总结消息落库与前端展示均使用新口径(历史 → 摘要 + 节省量),旧记录明确标注为「总结模型请求输入 → 输出」(beforeTokenCount/afterTokenCount标记 deprecated);会话用量指示器在总结后优先使用新估算值,下一次真实主回复后自动恢复实际用量(timestamp 判断新旧)。 - 被裁剪历史的逐字用户输入保险档案上限从 160k 字符降至 64k(约 40k → 16k token),省略标记文本计入预算,避免保险副本吃掉默认上下文保留预算、使总结后上下文几乎不下降。
- 存储路径加固:conversationId / snapshotId / diffId 统一白名单校验(
^[A-Za-z0-9_-]+$,新增assertSafeStorageId/assertSafeDiffId),覆盖 FileSystemStorageAdapter、UsageIndexStore、DiffStorageManager 与 integrityCheck,从根源拒绝..、路径分隔符、盘符与 URI 编码绕过。 - 根项目与前端锁文件同步(npm audit 均为 0 vulnerabilities,根项目声明 engines.node >=20)。
- 子代理续跑(
continueFromRunId)改为「同一条 run 接着跑」:runId 复用旧 run(Monitor 记录唯一、transcript 一条线连续,不再出现第二条不同身份的记录),身份强制沿用旧 run 的 agent(系统提示/工具集不变,本次调用传入的 agentName 被忽略,旧 agent 已被删除时拒绝续跑),provider 前缀缓存命中条件不变(仍以lastSentHistory为请求前缀、conversationId沿用旧 runId);续跑经run_resumed事件标记,前端工具卡 pending 阶段直接沿用continueFromRunId关联 Monitor。 - apply_diff 字符串处理性能优化:匹配次数统计从
split(search)(大文件 + 短 search 时生成整个分割数组,且无上限)改为indexOf循环计数(内存 O(1),新增 100k 上限保护);起始行定位改用单次扫描的getCharOffsetForLine(消除全量split('\n')行数组 +substring拷贝);匹配行号反算改用getLineNumberAtIndex(消除substring+split);normalizeLineEndings与 diffManager 的splitLines双正则合并为\r\n?单次扫描。新增applyDiffToContent真实实现单测覆盖以上行为。 - 流式平滑输出:新增
frontend/src/utils/smoothStream.ts(SmoothStreamer自适应速率蓄水池——chunk 进池后按「每秒放字数 = clamp(积压÷前瞻窗口, 下限, 上限)」匀速放字,积压多自动加速、供应商卡顿时打字渐缓而非冻结)与frontend/src/stores/chat/smoothStreamManager.ts(每条流式消息一个实例,Map<messageId, SmoothStreamer>,多标签页/subagent 并发流互不干扰,段落切换 thought↔正文/新 part 时先放完上一段积压再重置);真实内容(message.parts/content)照旧在 delta 到达时立即累加,另设显示层store.smoothTexts(messageId → 当前正在流出段落的平滑文本),MessageItem流式期间用平滑文本替换最后一个 text/thought 块渲染、终结/中止(complete/cancelled/error/toolIteration/awaitingConfirmation)时先flush()放完积压再销毁并切回真实 content,不丢尾巴;commit 按 ~32ms 批量合并 markdown 重渲染;rAF 隐藏时 dt 钳 100ms + 速率自适应 + panic 快进三层兜底;TPS 图与 token 统计仍吃真实 chunk 不经显示层;外观设置新增「流式平滑输出」档位(off=直通 / smooth=灵敏 220ms / balanced=标准 320ms / silky=丝滑 450ms),三语文案同步。 - 平滑流式与 TPS 审查修复:平滑档位经
state.smoothMode传递(chatStorewatch 设置同步,流式处理不再内联读全局 store);SmoothStreamer.push按长度预判 panic 先快进再字素分割(超长 chunk 不再先全量分割浪费内存);commit 回调 set 前比较旧值(减少无效响应式通知);移除生产未使用的end()/ended分支;非流式消息不再写入平滑层;lineDiff快速失败条件短路重排(预算不足时不再做公共行扫描)、editDistanceLimit上限钳制 4096(防 trace O(limit²))、computeLineDiffCached返回对象文档化为只读共享契约;ToolMessage去重键改为定长长度前缀编码(与 JSON 语义等价、消除字段分隔符碰撞);MarkdownRenderer流式 CSS 改overflow: visible(消除无效的overflow-y: visible计算值);三个 diff 面板清理缓存时同步修剪展开状态集合;clearLineDiffCache接入MessageList卸载。TPS 条新增「流活跃」状态机(见 Fixed)、模拟曲线以最近真实速率为基线、稳态均值校准到 ~12 tok/s、主题色每次绘制实时读取、窄面板(≤520px)隐藏 canvas 只留数值、视图隐藏时暂停模拟定时器、tooltip 走三语 i18n。 - 流式平滑渲染重构(CharFlow 字符流水线,取代「32ms 批量 commit + 180ms 限频 markdown 全量渲染」,解决高 tps 下消息越长越卡的 O(n²) 渲染问题):
- 新增
frontend/src/utils/charFlow.ts——活动尾块(当前正在流出的 text/thought 段落)由 CharFlow 全权托管:SmoothStreamer 每帧按速率放出字素,批内每个字符以 `animation-delay$ 亚帧错峰淡入(\text{CSS} 动画按 \text{vsync} 采样,「提交频率与观感解耦」——180\text{Hz} 屏接近真·逐字流水,高 \text{tps} 下为连绵字符流),播完动画的 \text{chip} 每帧回收进单个 \text{settled} 文本节点(存活 \text{span} ≈ \text{cps} \times \text{fadeMs} 有界),\text{flush}/\text{panic} 直通定型,支持 \text{prefers}-\text{reduced}-\text{motion};\text{DOM} 全部手动操作,高频路径完全不经过 \text{Vue} 响应式链 - $SmoothStreamer
commit 回调改为(字素数组, 帧时长, instant)`:删除 commitIntervalMs 批量合并与 pendingCommit(每帧 drain 直接提交),panic 快进/flush 以 instant 直通(跳过淡入);maxCps/lookahead 语义不变 smoothStreamManager新增显示目标注册表:MessageItem 挂载活动尾块 host 时registerSmoothDisplay注册 CharFlow(组件重建/切标签页回来从累计文本 restore 定型),段落切换(thought↔正文/新 part)先 flush 旧段落再注销显示目标(旧段落由 renderBlocks 接管为稳定块);smoothTexts快照降级为低频(~120ms 节流 + 内容去重 + 段落切换/终结强制),仅用于组件判定与重建恢复MessageItem/renderBlocks:流式期间最后一个 text 段落(partKey 匹配 + 单 part 块)从渲染块摘出交给 CharFlow;活动 thought 段落保留思维卡片外壳,在折叠预览或展开内容内挂载 CharFlow,流式期间不再反复全量解析 Markdown,折叠态自动跟随最新字符;已完成段落恢复 Markdown 渲染- 修复 CharFlow 重构后正文重复:活动尾块 host 插入模板后曾拆断原
v-if/v-else-if链,导致 parts 渲染与message.content兜底同时出现;现将 content 兜底显式限制为“无渲染块且无活动尾块”。摘块行为严格服从 tailInfo,工具调用成为尾部时保留上一段正文;权威 contentSnapshot 会终结旧显示基线。显示目标注册改为同宿主幂等、按宿主安全注销,首个 delta 入队前发布空基线,并补齐 toolsExecuting 与持久化 id 迁移后的终结清理 - 滚动层无需改动(CustomScrollbar sticky-bottom 已有 rAF 合帧 + 贴底判断)
- 新增
Added
- 新增回归测试:
getMetadataLight元数据缓存(写路径回填免读盘 / 深拷贝防污染 / 负缓存 / append 与删除后失效重读,5 例)、usedTokens单趟逆序语义等价(6 例)。 - 新增回归测试:行级差分快速失败(无公共行且超预算直接退化 / 预算内不退化且输出与预算耗尽一致)、动态 trace 分配下的预算内精确匹配与回退、
computeLineDiffCached缓存命中(同值复用同一结果对象)/ 键区分(起始行、编辑预算)/ 内容变化重新计算(lineDiff 套件扩展到 14 例)。 - 新增回归测试:删除生命周期(deleteLifecycle)、总结 Token 统计(summarizeTokenStats)、存储路径安全(storagePathSafety)、被裁剪用户输入预算(preservedUserInputsBudget)、子代理 run 事件总线(subagentRunEventBus)、前端正则护栏(regexGuard)、轨道式完整消息图布局(branchTreeLayout.buildTrackGraphRows:线性单轨道、候选轨道分配与释放复用、分叉线单元、折叠/展开行为)、工具分类分组(toolCategory:分组/归一化/分类名与图标映射)、总结模型透传(summarizeModelOverride:手动总结当前模型 / 独立模型优先 / 独立渠道无模型时不继承主对话模型)、自动总结当前模型透传(nonStreamAutoSummarizeTurn)、上下文管理关闭时手动总结边界(contextTrimBackgroundReceipt)、summarizeContext 处理器模型透传(summarizeContextModelOverride)。
- 前端启动「开始动画」:新增
frontend/src/components/Splash.vue——灰码少女线稿(取自 resources/icon.svg)按「帽子先落笔 → 身体/发丝 → 标题字距收拢浮现 → 横线脉冲等待 ready」节奏以 stroke-dashoffset 描线动画呈现,最短展示约 1100ms、ready 后约 0.45s 淡出并通知父组件,支持 prefers-reduced-motion;App.vue 原 loading-container 加载界面替换为 Splash(ready 沿用languageLoaded,主界面以 v-show 在下方就位避免 pop-in),并清理原.loading-container死样式(.spin旋转动画保留,供自动总结/重试等其它组件使用)。 - TPS 实时可视化条:新增
frontend/src/components/input/TpsBar.vue与前端采样器frontend/src/utils/tpsMeter.ts(模块级单例)——TPS 条位于聊天 Webview 面板最底部一行(InputArea.bottom-toolbar)、总结上下文按钮左侧,flex 布局为「左侧 TPS 标签 + 中间 240×24 canvas 柱状图 + 右侧实时数值」;流式 chunk 到达时streamChunkHandlers按文本长度粗估 token 数调用tpsMeter.record,采样器 200ms 采样、1s 滑动窗口求瞬时速率、EMA(α≈0.3) 平滑、定长 ring 随采样滚动,柱高按窗口内峰值归一化、颜色跟随--vscode-charts-blue主题变量;无真实流(开始动画/空闲等待)时 TPS 条自行随机模拟波动(常态低流量 + 偶发突发 + 均值回归),收到真实流数据后自动切换为真实曲线,让启动与空闲阶段的图表保持活性。 - 新增测试:
SmoothStreamer单测(flush 同步输出不丢尾巴 / switchPart 段落切换先放上一段 / panic 快进 / dispose 不输出 / 档位 lookahead 有序)与smoothStreamManager单测(每消息独立实例 / partKey 切换 flush / 消息间隔离 / 模式变化重建实例);lineDiff缓存套件扩展(预算 0 与负数退化语义、32 条 FIFO 淘汰、clearLineDiffCache强制重算);前端全量 403 例通过。 - 新增修复回归测试:
SmoothStreamertick 路径(fake timers + mock rAF:速率累积 / commitIntervalMs 批量 / dt 钳 100ms / panic 快进 / 积压放完尾巴强制提交)与 manager 基线/模式切换(5+ 例);tpsMeter(fake timers:窗口累计 / 1s 修剪 / EMA 递推 / ring 上限 / live 2s 边界 / events 容量上限 / 退订停表 / 停表状态清理,8 例)与Splash状态机(ready 最短展示 / drawDone 门控 / done 单次 / 定时器清理 / reduced-motion 同步完成 / aria,8 例);lineDiff边界(n+m === limit不快速失败 / 只读契约守卫 / 预算钳制生效,+3 例);MarkdownRendererCSS 规则静态断言(流式max-height: none+overflow: visible/keep-expanded/ 规则顺序)。前端全量 439 例通过。 - CharFlow 重构配套测试:新增
charFlow单测(批内错峰 delay / step 钳制 / collapse 回收 / finish 定型 / idle / restore 替换 / instant 直通 / reduced-motion 探测 / followEnd / dispose 清空,12 例);SmoothStreamer单测重写为 commit 新签名(flush 直通不丢尾巴 / panic instant 快进 / 高帧率 180Hz 模拟逐帧输出 / dt 钳制 / 积压放完停止调度,11 例);smoothStreamManager扩展(显示目标幂等注册/安全注销/恢复、首帧快照、快照节流与内容去重、段落切换、migrate 键同步迁移、finish 定型保留内容,14 例);新增 MessageItem 正文互斥、工具尾部可见性、thought CharFlow 与 contentSnapshot 基线重置回归测试。前端全量 466 例通过。
Fixed
- 多工作区修复(子智能体全链路审查 + 合并后回归核查):
- 切换已绑定工作区的对话时同步扩展端激活工作区:此前仅恢复 UI 显示、后端 WorkspaceManager 未同步,聊天顶部选择器与文件操作(文件树/打开文件/固定文件/搜索/保存图片)指向不同项目且分歧无法自愈;现在切换对话即
workspace.setActive到对话绑定工作区(失败仅告警) - 历史页「当前工作区」筛选纳入未绑定工作区的对话(未绑定 = 跟随当前工作区):此前升级前的全部存量对话与从未打开工作区时创建的对话被默认筛选隐藏,历史页打开工作区后默认一片空白
setActiveWorkspace重绑定对话失败时回滚激活工作区(此前重绑定失败无回滚无提示,前后端激活值分歧)- 分支对话创建不再以激活工作区兜底:此前前端未传 workspaceUri 时 handler 会错误绑定到当前活动项目,绕过后端「分支继承源对话工作区」逻辑(ConversationHandlers.createBranchConversation)
- 切换已绑定工作区的对话时同步扩展端激活工作区:此前仅恢复 UI 显示、后端 WorkspaceManager 未同步,聊天顶部选择器与文件操作(文件树/打开文件/固定文件/搜索/保存图片)指向不同项目且分歧无法自愈;现在切换对话即
- 默认对话标题自动附加工作区名(格式
标题 [工作区名],无工作区时不加):多项目同时编辑时对话列表/标签页/历史页可按项目区分;标签页标题同步同一逻辑(新增公共buildConversationTitle) - 性能优化(子智能体审查实施,全部有回归测试):
getMetadataLight接入 metaCache(对话列表每页 30 条摘要从 30 次磁盘读 + JSON parse → 0 次磁盘 IO;命中返回深拷贝防污染,not_found负缓存,io/parse 错误不污染;写路径统一失效/回填)usedTokens两趟 O(n) 正序+逆序扫描合并为单趟逆序扫描(流式期间每个 chunk 使该 computed 失效,访问量减半,语义等价由新测试锁定)- 预览文本
.filter().pop()全量扫描改逆序首个命中即 break;isLateTerminalChunkWithoutStreamId与handleError占位定位从 O(n).find()改getMessageIndexByIdMap 索引;batch 跳过诊断块消除每终结 batch 的slice+filter临时数组分配
- 新增测试:
getMetadataLight缓存行为(命中不读盘/深拷贝防污染/负缓存与写路径覆盖,3 例)、usedTokens合并后语义等价(6 例)
[1.6.2] - 2026-08-05
Merged
- 同步上游 PR #9(上游 1.4.1:生命周期/存储/总结/安全加固),保留 fork 的 electron-app / 变更查看面板 / 媒体路径护栏 / 独立版本号增量
- 上游改进包括:对话删除前停止并排空主流 + 子代理(abortAndWaitForCompletion + subagent exit/flush,有界等待)、编辑「真·原地保存」(keep 模式只改写目标消息文本,不再截断后续消息/软删分支/重新生成,本地 user 消息补近似 parentId 防根节点误判)、
NODE_NOT_FOUND/INVALID_BRANCH_RELATION消息编辑 id 对齐与根节点编辑自动降级 keep、候选切换器(BranchSwitcherBar)挂载位置修正、存储 ID 统一assertSafeStorageId校验、分段历史写入串行化与挂起超时、SubAgent transcript 持久化改进、token 统计与 preservedUserInputs 预算、前端分支树面板重构(branchTreeLayout)等 - 冲突解决记录:webview CSP 采纳上游 nonce 方案并保留 fork 的
<转义(safeJson);deleteConversation/deleteSingleMessage合并 fork assertSafeId 与上游 abort/子代理排空;editBranchkeep 模式合并上游真·原地保存与 fork 的索引/工具缓存重建;loadGlobalDiff保留 fork 优雅降级(不安全 id 返回 null 而非抛错);CHANGELOG 保留 fork 版本体系不并入上游 1.4.1 条目 - 上游新测试适配 fork 语义:
DELETE_CONVERSATION_INVALID_ID错误消息统一、loadGlobalDiff期望调整为 null 降级
- 上游改进包括:对话删除前停止并排空主流 + 子代理(abortAndWaitForCompletion + subagent exit/flush,有界等待)、编辑「真·原地保存」(keep 模式只改写目标消息文本,不再截断后续消息/软删分支/重新生成,本地 user 消息补近似 parentId 防根节点误判)、
Fixed
- 修复
TokenCountService四路提供商(Gemini/OpenAI 兼容/OpenAI Responses/Anthropic)计数请求无超时、无 abort 信号:单点挂死会拖死每次模型请求前的preCountUserMessageTokensBatch(整个回合无限期挂起且停止按钮无法中断);为每个计数请求加 15s 超时 + 外部 abort 透传,超时走本地估算降级(详见TokenCountService.fetchWithTimeout) - 修复
execute_command同步 shell 检测用execSync字符串拼接(where ${shellPath}):customPath 来自工作区设置,含&/|/;时被 shell 二次解释执行任意命令(工具声明构建时同步触发、无需确认);改为execFileSync参数数组;同步版timeout参数对 NaN/负数归一化 - 修复
ConfigManager未校验 timeout 配置:NaN/负数/0 直接进setTimeout导致所有请求瞬时超时/abort;validateConfig+executeRequest/executeStreamRequest双重钳制(默认 60s,上限 1h) - 修复
StdioMcpClient.disconnect对僵尸进程固定等待 10 秒(exit 事件永不触发):exitCode/signalCode 已置位直接清理,treeKill 报错立即 resolve;MCP 握手 clientInfo 版本由硬编码 1.0.5 统一为createGrayCodeMcpClientInfo() - 修复
DiffStorageManager.migrateTo迁移中途失败静默切换 basePath(旧目录剩余 diff 数据静默丢失):仅 ENOENT(旧目录不存在)才换路径,其他迁移异常保留旧路径并报错 - 修复
chatStream.source字段在 webview 层被丢弃:后台任务回执(source: 'background_task')被当成真实用户输入(isUserInput/回合语义/历史渲染全部错乱);handleChatStream解构与透传补齐source - 修复
deleteMessage/editBranchStream的messageId在 webview 层被丢弃:后端 MESSAGE_CHANGED 防索引漂移校验形同虚设(并发删除/压缩后可能误删其他消息);DeleteToMessageRequestData/EditBranchRequestData声明messageId并透传 - 修复
chat.awaitConversationIdle后端无限等待(前端 20s 超时摘除 requestId 后,迟到响应被误当广播分发):handler 加 15s deadline(返回{ idle: true, stale: true });extensionMessageRouting增加广播白名单,无匹配 requestId 的响应静默丢弃并记录 debug 日志 - 修复 IPC 启动失败后空占位 assistant 消息永不清理(幽灵「生成中」):
cleanupFailedSendPlaceholder与 handleError 占位清理等效(空占位删除、有内容登记_failedStreamMessageId) - 修复会话快照缺失
_failedStreamMessageId/_lastCancelledStreamId/_lastApprovalGatedStreamId:标签页切换后重试回滚失效、取消检测误判、半截幽灵消息残留 - 修复审批门闸终止的 toolIteration 后
processQueue永不触发:候选区排队消息无限期冻结,终结路径补processQueue()调度 - 修复
backgroundStreamBuffers超 2000 上限淘汰可能丢掉终结事件(complete/error/cancelled 等):标签页永久「生成中」;按流保留终结事件只丢普通数据 chunk - 修复
SubAgentRunController.waitUntilRunnable无限等待(暂停中 run 永久占用并发席位):30 分钟超时自动 exit;concurrencyLimiter排队加 60s 超时;fileWriteLockManager.acquire轮询加 60s 整体上限(超时抛明确错误) - 修复
proxyFetchTLS 握手窗口 abort 信号丢失(CONNECT 成功与 tls.connect 之间取消被吞、socket 悬挂):桥接 abort 监听覆盖窗口期 - 修复
deliverInterruptMessage错误码丢失(后端 INTERRUPT_MESSAGE_RATE_LIMITED 等被吞为通用文案)、recordInterruptDeliveryTTL 定时器不随 clear 取消、switchBranchCandidate的isSwitchingBranch在会话切换后不复位(finally 无条件复位) - 修复 electron-app 退出不等待
dispose()(异步写队列被截断导致设置/对话落盘丢失):before-quit preventDefault + await dispose + 10s 超时兜底;loadURL无 catch(页面加载失败主进程崩溃)改为错误对话框退出;新增单实例锁(重复启动并发写同一 data/ 目录损坏配置);主进程安装 unhandledRejection 保护(不再崩溃);vscode-shim硬编码1.99.0改为读根 package.json;JsonFileMemento.update非原子写改为 tmp+rename+串行队列;IPC 消息队列每项 60s 超时(渲染层挂起不再冻结整个通道)、toast 5 分钟 TTL;安装版数据目录不可写时回退appData/GrayCode并告警(详见electron-app/CHANGELOG.md[1.6.2]) - 修复公告版本解析:CHANGELOG 正则不支持
## [1.3.1-1]预发布条目且重复版本号重复展示;正则支持可选预发布段、compareVersions 遵循预发布 < 正式版、重复版本去重
[1.6.1] - 2026-08-05
Fixed
- 修复
ConversationManager合并引入 metaCache 后两处漏同步:updateSummary与syncMessageCountAfterStructuralChange直写 storage 导致getMetadata读到陈旧 messageCount/preview(对话列表计数漂移),改走persistMetadata(写盘 + 同步缓存) - 修复
ChannelManager流式请求结束后在途保活成功回调重建永不清理的空闲超时定时器(挂起引用 + 120s 后 abort 已废弃 controller):生成器 finally 将idleTimeoutHandle.reset置为 no-op;非流式路径retryInterval与流式一致钳制(非法值不再以 NaN 进入 delay) - 修复
TokenCountService模板分支残留空key=查询参数(统一走stripKeyQuery) - 修复
remove_backgroundmask_path 按读策略审批可被读策略 allow 绕过写策略 deny(mask_path 是写入目标,改按写策略审批) - 修复
BranchSwitcherBar模块级共享监听器标记:多条消息各挂实例时任一实例卸载会误移除其他实例正在使用的滚动/缩放监听(移入组件实例作用域) - 修复
toolActions插入/删除消息后未重建messageIndexById/toolResponseIndex(被取消工具卡片 hasToolResponse 持续 miss) - 修复
StreamAbortManager退休旧流 delete 且会话无新流接管时不唤醒idleWaiters(纯停止场景chat.awaitConversationIdle永久挂起、后台回执被静默丢弃) - 修复桌面版主进程 stdout/stderr EPIPE 崩溃:输出被重定向到管道(CI/终端工具/脚本
2>&1 | ...)且读取端提前关闭时,Node 把后续console.log抛出的 EPIPE 当作未捕获异常,Electron 主进程直接弹「A JavaScript error occurred in the main process」崩溃(e2e 大量日志场景复现);现在主进程入口挂 stdout/stderr 错误守卫,仅吞 EPIPE、其余错误照常抛出(详见electron-app/CHANGELOG.md[1.6.1]) - 修复非流式请求遇非 JSON 错误体(代理网关 HTML/纯文本 429/5xx)时丢失真实状态码与上游错误信息:
executeRequest先判 status 再读体,错误体按 JSON → 文本降级解析并透出HTTP <status>: <message>(API_ERROR),与流式路径对齐 - 修复 Gemini 模型列表分页无守卫:上游/中转站异常重复返回
nextPageToken时模型列表接口永久拉取;补页数上限(500)+ cursor 去重,与 OpenAI/Claude 分支一致 - 修复
ContextTrimService并发删除导致estimateMessageTokens(undefined)崩溃中断整个回合:index 越界消息按 0 token 处理 - 修复
StdioClient.disconnect10s 兜底定时器在进程先退出时悬挂不清理(MCP 频繁重启累积悬空 handle) - 修复流式路径
buildRequest失败未包VALIDATION_ERROR(与非流式路径不一致,前端错误分类漂移为 UNKNOWN_ERROR) - 加固
regexGuardReDoS 检测:改用分组栈扫描,识别嵌套分组/lookaround 绕过(((a+)+)、(?=(a+))+、(a?)+),同时保持字符类内括号/量词、(?:...)非捕获组、无外层量词嵌套的正确放行;补 9 例回归测试 - 修复
remove_backgroundmask_path 写入被策略拒绝时静默跳过但结果仍报成功:与 output_path 一致改为显式失败(此前读策略 allow 可绕过写策略 deny 把遮罩写入工作区外,且任务伪装成功) - 修复
execute_command单行输出无长度上限:无换行巨块(如print('x'*2e9))不再无界累积内存与响应体,单行 1MB 上限、超限截断保留尾部并计入 omittedOutputLines - 修复
delete_code整文件删除时产出{startLine:1,endLine:0}非法块(endLine 下限钳到 1) - 修复子代理后台执行同步抛错时任务残留 running(Promise 链包裹),并清除一处重复 catch 语法错误
- 修复
generate_image对 API 返回超大体图片无字节护栏(与输入侧 50MB 上限对齐) - 修复前端「无 streamId 的迟到 complete」覆盖新流占位消息并复位 activeStreamId 导致新回答永久丢失(H4 守卫补全到 handleComplete)
- 修复前端 batch 跳过优化把无 streamId 的陈旧终结事件当作当前流,误跳过当前活跃流真实增量(只认携带 streamId 的终结事件)
- 修复
messageActions8 处截断路径(删除/重试/编辑/回档/重放失败)未重建messageIndexById/toolResponseIndex、未清空toolResponseCache(被取消工具卡持续 miss、缓存读到已删除轮的响应) - 修复会话切换/新建/重置未清空消息索引与
_failedStreamMessageId(残留旧会话条目) - 修复
handleAutoSummary窗口前插入未同步折叠提示(foldedMessageCount 虚高) - 修复后台任务回执
chat.awaitConversationIdle无超时导致回执永久滞留、且阻塞整条消息队列:前端调用加 20s 超时(超时放弃本次 flush 下次重试,绝不提前写入回执),消息路由加入非阻塞白名单 - 修复
BackendHost.previewToSessionId无界增长(500 条 FIFO 上限) - 修复桌面版 auto-open diff 路径下
resolveOriginalContent拿到的 previewId 恒为空(previewId/filePath 计算提前) - 修复
vscode.diffshim 的preview字段语义反转(options?.preview === true与 VS Code 一致) - 修复桌面版 dialog 无窗口时
win!传 null 抛 TypeError(退化为无父窗口对话框)
[1.6.0] - 2026-08-05
Merged
- 同步合入上游 c7d2e16(PR #8:分支 UI/流式竞态/上下文裁剪 fallback 稳定/总结请求去图/编辑保持当前分支/工具安全),保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏等增量:
- 上下文裁剪 fallback 切点回合内稳定(保留 provider 前缀缓存):
getHistoryWithGranularFallback支持stableStartIndex——自动总结失败后同一真实用户回合的多次工具迭代(含工具确认后的续跑)复用第一次确定的裁剪起点,工具结果增长不再每轮把absoluteStartIndex向后推(此前每轮 retainedHistory 开头漂移,缓存只能命中 history 之前的固定系统/工具段);仅当完整性校验失败或估算超过硬上限(maxContextTokens 的 95%)才重新规划;新回合/总结成功后自动清点重新评估,clearTrimState同步清理 - 上下文总结请求不再携带图片/文件载荷:
cleanMessagesForSummarize把用户消息中的inlineData/fileData替换为[Image: …]/[File: …]文本占位符(总结模型无需加载图片字节,省输入 token,也避免不支持多模态的总结渠道报错) - 编辑用户消息新增「保持当前分支」模式(
chat.editBranchStream请求新增mode字段,默认'branch'行为不变):mode='keep'时后端直接改写活跃路径上的原用户消息并截断其后内容,不创建编辑候选;先ensureBranchGraph把完整旧历史并入分支图(无图时建线性基线),截断后syncGraphAfterHistoryDelete软删被移除的子树(旧版本保留可恢复查看)、updateActiveNodeParts同步改写节点内容与候选摘要(BR-01/BR-05 保持);前端编辑对话框新增「原地保存(保持当前分支)」按钮(三语文案),编辑链路(EditDialog → MessageItem → MessageList → App → editAndRetry → webview)透传mode,分支流错误重放上下文同步携带mode - 其余 PR #8 内容(LSP 工具、regexGuard、cancelForNewTurn、流式竞态等)见上游仓库 CHANGELOG
- 上下文裁剪 fallback 切点回合内稳定(保留 provider 前缀缓存):
Fixed
- 修复桌面版打包产物(安装版/便携版/zip)通用界面版本号恒为 0.0.0:打包只含
electron-app/dist,根package.json(运行时版本唯一来源)与CHANGELOG.md未打入,设置页应用信息 / About 对话框 / 版本更新公告全部落到兜底0.0.0,公告因版本恒等永不弹出新版本更新内容;现在 electron-builderextraResources追加根package.json与CHANGELOG.md(详见electron-app/CHANGELOG.md[1.6.0]) - 修复桌面版便携式(GrayCode-Portable-*.exe)数据目录解析错误:portable 启动器解压到
%TEMP%运行、退出即整目录删除,旧逻辑把数据目录算在临时目录里导致每次启动都是全新应用、更新替换 exe 后数据无法保留;现在识别PORTABLE_EXECUTABLE_DIR并把数据写入便携 exe 旁data/(详见electron-app/CHANGELOG.md[1.6.0])
[1.5.2] - 2026-08-04
Merged
- 同步合入上游 1.4.1(大规模代码审查修复:并发/安全/性能/一致性加固),保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏等增量:
- MCP:StdioClient spawn
error立即清理并拒绝 pending 请求(不再挂满超时)+ stdin/stdout/stderr 流 error 监听 + stderr 64KB 上限;HttpClient SSE 按请求 id 匹配与多行data:合并、超时覆盖 body 读取与 sendNotification、disconnect 中止进行中请求(保留 fork 的 16MB 缓冲区上限) - 依赖安装:并发 in-flight 复用 + 独立临时目录 +
maxBuffer64MB + 失败清理(fork 保留execFile参数直传、不经 shell 解析的注入面收敛) - 用量统计:接入
UsageStatsCache+ 对话目录监听(懒初始化、宿主 dispose 时释放),结果缓存保留 fork 的 LRU 上限 - Diff 预览:
diffContentId白名单校验统一收敛到isValidDiffContentId - media 工具:generate_image / remove_background 输入输出统一走
resolveFileToolPathWithInfo+ 工作区外访问审批流(fork 的ensureMediaPathsSafe工作区护栏保留,配套测试适配) - 前端:
sendToExtension条件 JSON 往返(纯 JSON 大载荷不再双份序列化);设置语言补 'ja';声音去重与 todo 状态集合容量上限
- MCP:StdioClient spawn
- 同步合入上游 150a287(分支 reroll/编辑前端主流程接线、删除消息同步分支图、后台回执上下文骤降修复、子代理工具本地化),保留 fork 的 electron-app / 变更查看面板 / 媒体工具路径护栏等增量:
- 前端 reroll 主流程接线:消息「重试」与「回档并重试」从破坏性删除(deleteMessage + retryStream)切换为
chat.rerollStream(旧回答保留进分支图 sidecar,新候选生成后可经 BranchSwitcherBar 的「‹ 2/2 ›」切换回);reroll 流结束(complete/error/cancelled)后自动刷新分支图;重试确认框三语文案同步为「保留当前回答、生成新版本」语义;chat.rerollStream加入无超时请求白名单 - 编辑用户消息分支化:消息「编辑」与「回档并编辑」从破坏性
editAndRetryStream(覆盖原消息)切换为chat.editBranchStream(后端创建编辑候选并截断主历史,原消息及其子树保留进分支图 sidecar);本地窗口改写目标消息 + 截断 + 流式占位 + 分支图刷新标记;流启动失败时重载最后一页 + 检查点恢复前后端一致;附件仅更新本地窗口(编辑分支接口无附件字段) - 子代理设置页工具白名单/黑名单列表工具名称与悬停描述接入三语 i18n:新增公共模块
frontend/src/utils/toolLocalization.ts(工具显示名/描述本地化,缺失时机械转写回退原文),工具设置页与子代理设置页共用同一套条目,MCP 外部工具自动回退英文原名 - 删除消息同步软删分支图子树:
deleteToMessage(删除到某条消息)与单条删除在硬删除主历史后同步更新分支图——被删节点及其后续整棵子树(含非活跃候选)标记为已删除(保留可恢复语义、不物理清理 sidecar),活跃尾自动回退到最后保留消息对应节点,指向被删节点的活跃指针一并清空;无分支图(线性对话)或未注册分支服务时保持原有删除行为不变,图同步失败仅告警不阻断硬删除(主历史为唯一真源) - 修复:
_pendingBranchRefreshAfterStream标记改为按会话隔离(会话切换后其他会话的终结 chunk 不再误消费并误刷分支图,切回原会话后由该会话的终结 chunk 正确消费);retryFromMessagereroll 流启动失败且会话已切换时不再重载原会话历史(避免污染当前会话窗口与检查点);分支流失败错误条可重试(后端把底层ChannelError.type(API/NETWORK/TIMEOUT/PARSE 等)透传到错误 chunk,isRetryableError按底层 type 判定,REROLL_FINISH_SYNC_FAILED等 reroll 特有错误或 CONFIG/VALIDATION/CANCELLED 不显示重试);主聊天发起的 diff 预览同样跟随主聊天所在列(diffViewColumn+openDiffView后moveActiveEditor校正) - 后台回执上下文骤降修复(约 35k token → 2k token):新增后端
chat.awaitConversationIdle(StreamAbortManager.waitForIdle()),回执发送前以运行控制器为生命周期唯一事实来源、等待旧流真正退出(不再依靠延时或前端瞬时isStreaming状态猜测),等待期间切换会话或启动新流则重新判定;后台回执以source: 'background_task'从前端请求贯通到后端历史、isUserInput: false保存,合法裁剪起点、回合识别、当前回合定位、思考范围与 token 累加统一复用isRealUserMessage(),source在渠道 formatter 发请求前剥离、历史重载时透传回前端保持后台任务卡片样式
- 前端 reroll 主流程接线:消息「重试」与「回档并重试」从破坏性删除(deleteMessage + retryStream)切换为
[1.4.1] - 2026-08-05
Changed
- 分支树面板改造成双模式“分支历史”:默认“分支导航”会折叠连续线性消息,只保留根节点、分支点、候选入口、命名/删除节点与当前尾部;“完整消息”显示所有节点,但普通父子消息沿用同一纵向轨道,只有真正的兄弟候选才横向展开,不再随对话长度形成一路向右的阶梯。面板同时增加节点计数、角色标签、精简时间、悬停操作按钮和窄窗口适配,保留候选切换、工作区恢复确认、软删除、恢复与重命名能力,三语文案同步。
- 子代理完整 transcript 从 conversation
.meta.json迁移到conversations/<conversationId>/subagents/<runId>.json独立原子文件;元数据仅保留状态、计数、修订号和transcriptRef,不再重复内嵌contents与lastSentHistory(包括图片 Base64)。旧内嵌记录首次加载时自动迁移并清除大字段,Monitor 历史与续跑 provider 前缀保持完整。
Added
- 树状分支重 roll 前端主流程接线(此前仅后端完成):消息「重试」与「回档并重试」从破坏性删除(deleteMessage + retryStream)切换为
chat.rerollStream(旧回答保留进分支图 sidecar,新候选生成后可经 BranchSwitcherBar 的「‹ 2/2 ›」切换回);reroll 流结束(complete/error/cancelled)后自动刷新分支图;重试确认框三语文案同步为「保留当前回答、生成新版本」语义;chat.rerollStream加入无超时请求白名单与 VSCodeRequest 类型联合 - 编辑用户消息前端主流程接入
chat.editBranchStream(此前仅后端完成):消息「编辑」与「回档并编辑」从破坏性editAndRetryStream(覆盖原消息)切换为分支编辑——后端创建编辑候选(新 user 节点)并截断主历史,原消息及其子树保留进分支图 sidecar(决策 7:旧分支保留,失败可切回);本地窗口改写目标消息 + 截断 + 流式占位,置位分支图刷新标记(流结束后 BranchSwitcherBar 显示候选切换器);流启动失败时重载最后一页 + 检查点恢复前后端一致;chat.editBranchStream加入无超时请求白名单与 VSCodeRequest 类型联合;附件仅更新本地窗口(编辑分支接口无附件字段) - 子代理设置页工具白名单/黑名单列表工具名称与悬停描述接入三语 i18n:新增公共模块
frontend/src/utils/toolLocalization.ts(工具显示名/描述本地化,缺失时机械转换/回退原文),工具设置页与子代理设置页共用同一套toolDisplayNames/toolDescriptions条目,MCP 外部工具自动回退英文原名 - 删除消息同步软删分支图子树(后端):
deleteToMessage(删除到某条消息)与单条删除在硬删除主历史后同步更新分支图——被删消息对应节点及其后续整棵子树(含非活跃候选)标记为已删除(保留可恢复语义、不物理清理 sidecar,过期清理仍走保留期机制),活跃尾自动回退到最后保留消息对应节点,指向被删节点的活跃指针一并清空;无分支图(线性对话)或无分支服务注册时保持原有删除行为不变,图同步失败仅告警不阻断硬删除(主历史为唯一真源) - 编辑用户消息新增「保持当前分支」模式(
chat.editBranchStream请求新增mode字段,默认'branch'行为不变):mode='keep'为真·原地保存——只改写活跃路径上目标用户消息的文本,后续消息、检查点与分支全部保留,不截断、不软删、不创建候选、不重新生成;后端ensureBranchGraph建图(无图时建线性基线)后updateMessage改写主历史 +updateActiveNodeParts同步图节点内容,流直接完成(complete 仅通知前端复位状态);前端编辑对话框新增「原地保存(保持当前分支)」按钮(三语文案),编辑链路(EditDialog → MessageItem → MessageList → App → editAndRetry → webview)透传mode,分支流错误重放上下文同步携带mode;editAndRetry/restoreAndEdit本地同样只改目标消息(不截断窗口、不创建占位),发送时本地 user 消息补近似parentId(首条为 null)供根节点判断
Fixed
- 修复流停止等待竞态:
waitForIdle()现在同时等待当前控制器和已退休旧流的 finally;cancel()不再让既有等待者永久挂起,也不会在旧流仍处于工具结算窗口时假报空闲;cancelAll()在视图/扩展销毁时统一释放全部退休链。 - 修复删除会话与运行任务/元数据写入竞态:删除前先中止并等待主流退出,退出该会话全部前台与后台子代理,等待 executor 注销及 transcript/索引持久化排空,再删除检查点和会话;会话物理删除同时进入元数据共享写链,进行中的巨大
.meta.json写不能在删除后通过晚到 rename 复活幽灵文件。 - 修复「原地保存(保持当前分支)」误删整个分支:keep 模式原实现为「改写 + 截断其后内容 + 软删图子树 + 重新生成」,用户点击后目标消息之后的全部消息与分支候选被移除。现改为真·原地保存语义(只改目标消息文本,后续消息 / 检查点 / 分支全部保留,不重新生成),后端去掉
deleteCheckpointsFromIndex/deleteMessagesInRange/syncGraphAfterHistoryDelete与工具循环(keep 模式流直接完成),前端不截断窗口、不创建占位、不置分支图刷新标记;错误条重放(replayBranchStreamAfterError)对 keep 上下文同样不截断、不创建占位;根节点编辑降级 keep 时走同一语义 - 修复编辑第一条消息(根节点)报
INVALID_BRANCH_RELATION: cannot edit the root node:BranchGraph 为单根模型,根节点没有父节点可挂编辑候选(TREE-03 遗留「根节点编辑暂拒」)。现在编辑根节点时前端自动降级为「原地保存」语义(keep 模式——只改写根消息,后续内容保留,与编辑对话框「保持当前分支」按钮一致):resolveEditTargetNode新增mode参数、keep 模式放行根节点(图模式与线性模式都支持),editAndRetry/restoreAndEdit检测目标消息parentId == null时自动以mode='keep'发起chat.editBranchStream(错误条重放上下文同步携带 keep 模式);contentToMessage/contentToMessageEnhanced透传content.parentId(Message 类型新增parentId字段),前端据此识别根节点 - 修复编辑用户消息报
NODE_NOT_FOUND: node not found: <id>(新对话首条消息即必现):前端发送用户消息时窗口消息 id 用generateId()生成,但chatStream请求只传文本、不传 id,后端落库时由ensureNodeId另行生成randomUUID()——窗口 id 与主历史/分支图 Content.id 永远不一致,编辑/重试按 id 定位必失败(assistant 消息经流式contentToPersistedMessage有 id 对齐机制,user 消息没有)。现在chatStream请求新增messageId字段(ChatRequestData.messageId),前端sendMessage携带窗口 user 消息 id,后端addMessage原样落库(省略时仍由后端生成,兼容旧客户端);工具确认批注同款修复(annotationMessageId经toolConfirmation→handleToolConfirmation→addContent透传)。已打开会话中的历史遗留不一致消息,重新加载历史(切走再切回)后窗口 id 与后端对齐 - 修复候选切换器(BranchSwitcherBar)挂载位置:切换器改为跟随「当前活跃的候选消息」(用户重 roll / 编辑过的消息本身),而非候选组的父节点——此前
user:1 → ai:2 → ai:3重试 3 后切换器显示在 2 上(候选组挂在父节点 2 下),现在显示在 3'(3 的位置)上;新增buildCandidateGroupForNode(按消息节点推导所属候选组,仅活跃成员返回),BranchSwitcherBarprop 从parentNodeId改为nodeId - 上下文裁剪 fallback 切点回合内稳定(保留 provider 前缀缓存):
getHistoryWithGranularFallback支持stableStartIndex——自动总结失败后同一真实用户回合的多次工具迭代(含工具确认后的续跑)复用第一次确定的裁剪起点,工具结果增长不再每轮把absoluteStartIndex向后推(此前每轮 retainedHistory 开头漂移,缓存只能命中 history 之前的固定系统/工具段);仅当完整性校验失败或估算超过硬上限(maxContextTokens 的 95%)才重新规划;新回合/总结成功后自动清点重新评估,clearTrimState同步清理 - 上下文总结请求不再携带图片/文件载荷:
cleanMessagesForSummarize把用户消息中的inlineData/fileData替换为[Image: …]/[File: …]文本占位符(总结模型无需加载图片字节,省输入 token,也避免不支持多模态的总结渠道报错) - reroll/编辑分支流前端修复:
_pendingBranchRefreshAfterStream标记改为按会话隔离(记录发起流的会话 ID):会话切换后其他会话的终结 chunk 不再误消费并误刷分支图;切回原会话后由该会话的终结 chunk(或后台缓冲 flush)正确消费retryFromMessagereroll 流启动失败且会话已切换时不再重载原会话历史(避免污染当前会话窗口与检查点,与 editAndRetry 同款身份校验)- 内容型
toolIteration因「需用户确认 / 审批门闸 / 工具被取消」终结流时同样消费分支图刷新标记(此前标记残留,可能被后续无关终结事件消费) restoreAndEdit补 R3-#13 同款按 id 重定位(await 恢复期间数组变化不再错改错删),恢复失败错误写入加会话归属校验restoreAndRetry/restoreAndEdit的chat.rerollStream/chat.editBranchStream载荷补齐promptModeId(与 messageActions 入口一致)- i18n 新增
hasMessage()静默 key 存在性检查;工具本地化(toolLocalization)缺失条目不再触发[i18n] Missing translationconsole.warn 刷屏 - reroll/编辑分支流失败时错误条可重试(方案 B):后端在流式失败时把底层
ChannelError.type(API_ERROR/NETWORK_ERROR/TIMEOUT_ERROR/PARSE_ERROR等)透传到错误 chunk({ code, type?, message }),前端isRetryableError对REROLL_ERROR/EDIT_BRANCH_ERROR改为按底层 type 判定可重试——携带可重试 type 时错误条显示「重试」;无 type(如REROLL_FINISH_SYNC_FAILED等 reroll 特有错误)或 type 不可重试(CONFIG_ERROR/VALIDATION_ERROR/CANCELLED_ERROR)时不显示;ErrorInfo类型补可选type字段,retryAfterError入口守卫改用isRetryableError保持与错误条判定一致 - 主聊天发起的 diff 预览同样跟随主聊天所在列:
vscode.diff的viewColumn参数在部分布局/版本下不生效(仍在当前活动编辑器组打开,焦点在 Monitor 面板时 diff 会落到 Monitor 列),现在主聊天上下文同样下发diffViewColumn(与 Monitor 路由同语义,主聊天在侧边栏时回退主区域第一列),且openDiffView打开后用vscode.moveActiveEditor把 diff tab 校正到目标列(目标列即当前列时移动幂等)
- 修复后台子 Agent 完成回执插入尚未结束的主模型调用,并导致上下文从约 35 万 token 骤降至约 2 万 token(用户实测):
- 根因一是前端收到
completechunk 后会先清除isStreaming/isWaitingForResponse,但后端流此时可能尚未执行StreamRequestHandler.finally;后台任务回流仅依据前端状态判断空闲,随即创建同会话新流,触发StreamAbortManager.create()中止并替换仍在收尾的旧流。现在新增后端chat.awaitConversationIdle与StreamAbortManager.waitForIdle(),回执发送前以运行控制器为生命周期唯一事实来源,等待旧流真正退出;等待期间若切换会话或启动新流则重新判定,不再依靠延时或前端瞬时状态猜测 - 根因二是后台回执经普通
chatStream落盘时被标记为真实 user 消息,裁剪器将其识别为新回合;当前一个工具回合本身约 35 万 token 时,回合完整性约束会迫使裁剪器丢弃整个旧回合,只保留约 2 万 token 的回执回合。现在source: 'background_task'从前端请求贯通到后端历史,回执以isUserInput: false保存;合法裁剪起点、回合识别、当前回合定位、思考范围与 token 累加统一复用isRealUserMessage(),后台回执视为原任务的异步延续,旧历史中缺少isUserInput的真实用户消息仍兼容;source在渠道 formatter 发请求前剥离,历史重载时透传回前端以保持后台任务卡片样式 - 补充后端运行生命周期、回合边界、旧历史兼容和前端来源透传回归测试;根 TypeScript 检查、前端生产构建及目标测试通过
REROLL_ERROR/EDIT_BRANCH_ERROR错误条重试改为重放原分支流(方案 B 一致性收口):此前错误条「重试」会回退到retryStream直接追加生成——流式失败后主历史已有半截候选、请求级失败后旧回答仍留在主历史,追加生成分别造成「半截候选 + 新回答」重复与「旧回答 + 新回答」重复,并让分支图与主历史失配(后续删除/编辑报索引越界)。现在retryFromMessage/editAndRetry/restoreAndRetry/restoreAndEdit在发起分支流时记录原请求快照(目标节点、编辑文本、配置、模型覆盖与 Prompt 模式),流失败时随错误对象保存;错误条重试按错误码重放chat.rerollStream/chat.editBranchStream——流式失败(REROLL_ERROR/EDIT_BRANCH_ERROR)复用失败候选(省略旧节点 ID,由后端按当前活跃路径选择,前端仅回滚半截展示、绝不调用deleteMessage),请求级失败(RETRY_ERROR/EDIT_RETRY_ERROR)按原目标节点重建本地窗口后重放;重放上下文随标签页快照保存/恢复(切标签页后仍可重试),成功/取消/关闭错误时清理;普通流错误(STREAM_ERROR/API_ERROR等)重试行为不变
- 根因一是前端收到
[1.4.1] - 2026-08-04
Fixed
- 修复
agent.sendMessage工具名含点号导致 OpenAI 兼容 API 拒绝请求(400Invalid 'tools[N].function.name': string does not match pattern '^[a-zA-Z0-9_-]+$'):工具更名为agent_send_message(与全局 snake_case 命名一致),并在声明中注册agent.sendMessage为别名,旧对话历史中的调用仍可经 ToolRegistry 别名解析执行 - 子代理设置页工具白名单/黑名单列表不再把工具完整描述直接渲染在名字下方(几十个工具的长英文描述把设置页撑得极大),改为仅显示工具名,描述收敛为鼠标悬停的 title 提示
- 批量代码审查修复:
- 工具系统:validateToolArgs 对非对象参数加守卫(畸形模型输出不再 TypeError 崩溃整个工具批次);insert_code 空内容不再产生多余空行;jsonFormatter 字符串值内出现字面
<<<END_TOOL_CALL>>>标记不再提前截断块(状态机感知字符串开关与转义) - 对话历史:rejectToolCalls 对无 parts 消息加防御;getCustomMetadata 在 meta.json 损坏时降级返回 undefined 而非抛错;删除会话后迟到的 setTitle/updateSummary 不再重建幽灵 meta.json(loadMetadataForWrite 校验历史存在性)
- 文件与搜索:generate_image 参数缺失路径不再残留 running 任务;网络错误不再误报为用户取消;remove_background mask 缩放改 fit:'fill' 消除裁切错位;find_files maxResults 语义修正(+1 探测避免 truncated 误报);search_in_files replace 模式匹配收集加 20000 上限与 truncated 标志、多根工作区 path 解析失败不再静默回退、正则源超 500 字符拒绝(ReDoS 防护)
- 子代理与文档工具:agent_send_message 消息加 16000 字符与 inbox 50 条上限;子代理排队取消路径收敛到 finalizeRun 终态出口;update_progress latestConclusion 归一化;record_progress_milestone 里程碑 id 撞车自动递增重试;create_progress 区分 ENOENT 与其它读错误;create_design 不再静默覆盖已存在设计文档;toggle_skills 未找到技能改 data.warnings 语义
- 记忆与设置:truncateLog 长度读取移入锁内(并发 note 不再被误截断);compress 仅在 treePut 成功时上报 done;wake 缺失摘要提示指向实际缺失块;SkillsManager.refresh 同步清理已删除技能;代理设置不再默认启用;设置文件损坏抛错而非静默归零;savePromptMode 校验 mode.id 非空
- webview:MessageRouter 流式请求 clientId 映射改为流结束时统一清理(Monitor 发起的流出错不再错投主聊天或永久挂起);cancelStream 缺 data 不再泄漏映射条目;diff 预览内容缓存加 50 条上限;getExtensionVersion 收敛到公共模块;UsageHandlers dispose 清空统计缓存;删除 FileHandlers 死代码变量
- 前端:流式终结 chunk 缺 content 时流状态仍无条件复位(不再卡在"等待响应");视频/图片缩略图加载加整体超时与 onerror 兜底;声音去重集合与 todo 状态集合加容量上限;待确认工具拦截路径不再静默丢弃附件;后台会话流式缓冲加 2000 chunk 上限
- 构建与测试:.vscodeignore 补充 .env/.env./.pem/*.key 防密钥入包;jest 全局 testTimeout 20000;移除空 jest.setup 引用;messageRouterNonBlocking 测试改为断言生产常量(不再是无效测试);tsconfig 移除 tsc 直出遗留死配置;npm scripts 收敛;fast-tavern 恢复被删除的 build 模块(buildPrompt/buildPromptFromSillyTavern,npm build 与 pytest 恢复通过)、vectorSearch 类型收敛为同步并修正 Python 端异常静默、Python 正则/世界书浮点语义对齐 TS(NaN/Inf 守卫、不再 int 截断)、递归上限对齐 Math.trunc+clamp
- 工具系统:validateToolArgs 对非对象参数加守卫(畸形模型输出不再 TypeError 崩溃整个工具批次);insert_code 空内容不再产生多余空行;jsonFormatter 字符串值内出现字面
- 第二轮高风险并发/性能修复:
- 流式取消竞态(ToolIterationLoopService + ChatFlowService):取消时先以 3s 有界窗口等早启动工具落定再结算(真实结果不再丢失为 cancelled 占位);主工具循环 gen.next() 与 handleToolConfirmation 两个确认循环补 abort-race + 2s 收尾窗口(不再永久挂起);流式取消分支补 resolveAndPersistPostToolStopState(审批门不再残留误拦截)——配套 5 个时序测试
- 代理模式取消:executeStreamRequest 代理分支循环结束后显式检测 externalSignal.aborted 抛 CANCELLED_ERROR(与原生 fetch 分支对齐,半截流不再被当完整消息落盘)+ 剩余 buffer 取消后不再冲刷——5 个测试
- MCP 连接生命周期:connect 代际号机制(旧连接的晚到 exit/error/catch 不再误删新客户端/覆盖状态);connect 按 serverId 复用 in-flight promise(不再假成功);StdioClient spawn 'error' 立即 reject(不再挂满 30s 超时)+ 流 error 监听 + stderr 64KB 上限;HttpClient 超时覆盖 body 读取与 sendNotification、disconnect abort 进行中请求、SSE 按请求 id 匹配与多行 data: 合并——21 个测试
- 依赖安装与配置导出:DependencyManager 同依赖 in-flight 复用 + 每次安装独立临时目录 + exec maxBuffer 64MB + 失败清理 temp;exportConfig 递归脱敏(customHeaders/customBody/tokenCountApiConfig 不再泄漏密钥)
- 前端依赖矩阵统一:vite ^5→^6.4.3、@vitejs/plugin-vue ^5→^6.0.8、vitest 4 保持,删除 esbuild overrides,npm dedupe 后测试与生产构建统一到 vite 6.4.3 + esbuild 0.25.12(npm ci 可复现)
- 锁与设置:fileWriteLockManager 锁 key 统一绝对规范路径(相对/绝对/../写法不再绕过互斥);registerAllTools 改注册真实工厂(refreshTool 不再静默空操作);SettingsCore.updateSettings 深合并(嵌套部分对象不再抹掉同层配置);VSCodeSettingsStorage 按快照 diff 只写变更键(不再每次全量重写全部配置)
- 并发一致性:runEventBus 持久化队列改按 conversationId 串行(同会话并行子代理不再互相覆盖 transcript);新增 progressWriteLock per-path 写互斥(progress.md 读改写不再丢失并行更新)
- 性能:TranscriptRepository 结构化变更少一次写后全量回读+深拷贝;ToolExecutionService 每工具批次节点反查 2 次→1 次(200 次迭代省数百次全量读);PromptManager 固定文件 TTL+mtime 缓存与 1MB/2MB 大小限制、fileTree 节点预算截断(10000)、gitignore
!否定语义、glob 正则编译缓存;checkpoint 三处 O(n²)→O(n)(unbackedPaths/RetentionService 后继/getIncrementalChain)+ 读取侧 backupDir 越界校验 - 测试稳定性:toolBatchCheckpoint 轮询改为等待 after 最终绑定值(消除 fire-and-forget 绑定窗口的既有 flaky)
- 安全/性能/一致性修复:
- webview 安全:diffContentId 白名单校验(^[A-Za-z0-9_-]+$,5 处 loadGlobalDiff 调用点封堵 ../ 穿越);消息路由 clientId 改为按来源 webview 固定(不再信任消息体字段,杜绝跨面板身份伪造)
- media 工具工作区护栏:5 个图片工具(generate_image/remove_background/crop/resize/rotate)输入输出路径统一走 resolveFileToolPathWithInfo + outside-workspace 审批流,与 file 工具策略对齐(默认 deny 下不再能读写工作区外)
- 路径校验:integrityCheck 段文件名白名单(恶意索引不再越界读盘);BranchGraphRepository(新错误码 INVALID_CONVERSATION_ID)与 DiffStorageManager 会话 ID 白名单
- 请求一致性:ChatFlowService 前置清理(diff 中断 + rejectAllPendingToolCalls)提取为公共方法并接入非流式 handleChat/handleRetry(悬空 functionCall 不再跨回合残留);drainInboxIntoResults 显式校验 mailbox drain 持有者(并发主循环不再窃取消息)
- subagents:executor 超时/父取消直接丢弃 partial response 走终态(半截工具调用不再进 transcript);agentMailbox 线程深度原子递增 + 拒绝时清理(不再只增不删);subagents 工具名列表按 registry/MCP 计数指纹缓存(声明访问不再 O(N) 全量重算)
- 大文件护栏:apply_diff/insert_code/delete_code 同步读取前 stat 5MB 上限;remove_background 文件 50MB + 像素 16MP 双层拦截;apply_diff 精确匹配 10 万候选上限 + LCS DP 行数护栏(病态输入不再撑爆内存)
- 工具护栏:list_files 递归深度 10/条目 5000 + truncated 标志 + 跳过常见大目录;execute_command shell 检测结果缓存(不再每工具创建多次同步 execSync);find_references context 钳制 0~10;goto_definition 括号计数词法感知(字符串/注释/模板不参与)
- memory/prompt/settings:recall 淘汰 O(1) 索引指针(不再反复 shift);updateConfig 配置项边界校验(entryChars 1~319 等);listEntries 流式扫描 + 可选 limit;buildPromptCacheKey 纳入模板指纹(改模板不再 60s 内返回过期提示词);SettingsExporter YAML 双引号转义 + 解析端配套反转义(描述含换行/引号/--- 往返不损坏)
- webview 性能:附件 base64 上限 50MB;searchWorkspaceFiles limit 钳制 200 + glob 元字符剥离 + 子目录并行遍历;上下文预览改异步写;BranchHandlers 图信息单次 DFS(O(n²)→O(n));死代码清理(MessageRouter 两方法、jsonFormatter 三导出、StreamProcessorResult 接口)
- ConversationManager:insertMessage/insertContent 后 repairParentChainAfterInsert(插入点后继 parentId 重链,恢复线性活跃路径不变量);结构性删除后同步 messageCount(列表计数不再漂移);toolAdapter 旧 mcp_ 命名收敛到 codec(mcp__,删除死导出);create_progress 并入 per-path 写互斥
- 前端:sanitizeHtml 补齐(xlink:href/use href/data:/srcdoc/style 剥离、控制字符混淆防护);删除 useChat/useMessages/useConversations 三个死 composable(含从不释放的监听器);sendToExtension 条件 JSON 往返 + 失败回退(纯 JSON 大载荷不再双份序列化);settingsStore Language 补 'ja' + useI18n 接入 ja 语言包(ja 用户 store 级文案不再回退中文)
- fast-tavern:无 id 正则回退 id 改确定性 FNV-1a 哈希(TS/Python 输出一致,可复现);死代码三元收敛;py README 示例命名与代码块修正;根 package.json 新增 benchmark script 与 engines.node(>=20);BranchGraphRepository 原子写 rename 重试(Windows EPERM 偶发 flaky 根治)
- 代码组织与文档收尾:ChannelManager.getFilteredTools 与 ToolDeclarationResolver 合并(删约 235 行重复实现,主会话工具列表获得 denylist/excludeToolNames 能力,"主会话与 SubAgent 共用同一入口"兑现);review 6 个工具路径策略副本收敛到 progress/pathUtils 共享实现;handleEditAndRetry(非流式)补齐前置清理(与其它入口一致);前端三语语言包删除 useChat/useConversations 孤儿键;sanitizeHtml 补 srcset 候选级协议校验;CHANGELOG 历史条目清除全部内部代号(CP-/BR-/MIG-/TREE-/BCP-/EX-/HIS-/CPF-/MED-/审查/复查/决策/PR # 等 165 处)
- 修复刚完成的助手消息点击「重试」时报
NODE_NOT_FOUND:模型回复落盘后,后端现在把真实的稳定消息节点 ID 随流式终结内容回传;前端在toolsExecuting、awaitingConfirmation、toolIteration、complete与取消收尾阶段用该 ID 替换本地流式占位 ID,并同步消息索引与当前流引用。retryFromMessage因此不再把形如1785860200670_2ojp0foff的前端临时 ID 传给分支图,普通回答、工具调用回答及已落盘的取消回答均使用后端节点 ID。 - 修复工具调用后续接回答重生成时报
INVALID_BRANCH_RELATION,并明确 reroll 为“单条助手消息重新生成”:分支服务现在允许被点模型消息的直接父节点是模型节点,新旧回答在该父节点下形成同级候选;主历史与检查点从被点回答自身开始截断,目标之前的模型工具调用和functionResponse完整保留,因此只重新生成选中的回答,不会退回用户消息重跑整轮工具。 - 修复
read_file单文件调用被空批量参数误判为冲突:部分 function-calling 客户端会为未提供的可选数组自动补上files: [],此前与有效path同时出现会报Provide either path or files, not both.;现在空数组在存在path时按“未提供批量参数”处理,同时仍拒绝无path的空批次及path+ 非空files的真正混合调用。 - 修复排队消息「立即发送」仍会掐断前台子 Agent(用户实测):前台 SubAgent 转后台(detach)此前只挂在
StreamAbortManager.create()(新流启动)上,而队列箭头的sendQueuedMessageNow是先显式cancelStream()再发送新消息——旧流 abort 发生在create之前,父取消信号已传播到子 Agent,等新流创建时 detach 已来不及。现在cancelStream支持preserveSubAgents标记:前端「立即发送」路径携带该标记,后端StreamAbortManager.cancelForNewTurn()在 abort 旧流之前先把该会话活跃前台 SubAgent 转为后台(与 create 路径同款 detach 语义),普通「停止」按钮仍走原cancel保持真正终止;新增回归测试(管理器 detach 顺序矩阵、路由标记透传、前端请求顺序)。 - 修复
find_files等未配置存档的单个只读工具偶发显示“对话已存在”:单工具存档判定现在与批量工具一致,未配置存档时不再提前反查会话节点;ConversationManager同时按会话 ID 合并仍在进行的首次创建,消除显式创建与读路径按需创建的并发竞争,创建完成后的真正重复调用仍保持报错。 - 改善主模型与 SubAgent 的停止响应:主聊天点击停止后立即清除前端流式、加载和等待状态,后端关闭 diff、拒绝悬空工具与持久化清理仍按原顺序完成;Monitor 的暂停、继续、退出请求改为非阻塞路由;SubAgent 工具执行增加 500ms 有界中止收尾,即使工具完全不响应
AbortSignal,run 也会进入 cancelled 并释放控制器、并发席位与文件锁,退出成功后 Monitor 立即隐藏控制按钮。 - 降低
apply_diff接受修改后的等待与界面冻结:目标文件 stat/read 改为异步 I/O;完整 diff 内容先写入 16 条/32MiB 双上限的内存缓存,工具结果立即获得预览引用,JSON 持久化转后台并改为紧凑格式,当前会话预览优先读内存、扩展重启后仍可从落盘文件读取;写前/写后工作区存档和 diff 确认流程保持不变。 - 修复前台 SubAgent 返回后主模型输入从约 30 万 token 突然减少约 5 万的真实上下文丢失:上下文管理不再静默按完整用户回合推进持久
trimState,统一改为模型总结优先;总结范围按 token 预算选择,并可在多轮历史的超长工具回合内部以完整functionCall/functionResponse组为边界切分。工具循环同一用户回合持续工作时仍会逐轮检测上限、最多尝试两次自动总结,失败后仅对当前请求执行不持久化的细粒度安全裁剪;旧版 trim 状态首次读取自动失效,升级前被遮蔽的历史可重新参与评估。 - 上下文总结与裁剪现在独立保留历史真实用户输入:被压缩区间中的用户原话和附件名称按时间顺序注入请求,排除 functionResponse、后台回执与旧总结;首次目标和最近补充在异常大输入触发安全预算时仍优先保留,档案不写回 transcript,避免重复膨胀。functionResponse token 估算同步按实际 API 可见字段计算,diff 与 SubAgent UI 元数据不再虚增裁剪预算;同时修复总结消息被起点归一化误跳过的问题。
- 总结设置新增两个可调项:①「自动总结最大尝试次数」——单个真实用户回合内最多尝试 1-5 次(默认 2),尝试耗尽后仍超阈值时本次请求改用不持久化的细粒度安全裁剪;②「总结模型输入占比」——自动总结单次请求输入占总结模型上下文窗口的 5%-95%(默认 50%),超出时自动缩小总结范围、保留最近一轮工具交互。同时清理总结设置页已迁移的过时「自动总结」区块文案,三语同步。
- 修复分支图异步同步未完成时 functionResponse 可在切换重写中丢失:
rewriteHistoryFromBranchGraph的一致性检查此前只验证非 functionResponse 消息已入图,FR 内容(决策 8 并入所属节点 parts)未校验——FR 图同步未完成/失败时切换会静默丢 FR 内容并误清检查点。现在新增findUnsyncedFunctionResponses纯函数(按所属节点做 FR id 子集匹配、防误报),任一 FR 未同步即拒绝切换并返回BRANCH_OPERATION_CONFLICT,主历史保持不变;补 8 个纯函数用例与集成回归(含补同步后重试幂等)。 - MCP 工具调用全链透传外部
AbortSignal:用户取消回合后 MCP 请求立即中止,不再挂到超时。HTTP 客户端外部信号与内部超时 controller 联动(区分中止/超时文案),SSE 读流外部中止时同步取消 reader;Stdio 客户端外部中止清理 pending、超时与进程退出监听并拒绝;ToolExecutionService→McpManager→ 客户端逐层透传。新增 11 个用例,MCP 6 套件 86 测试全绿。 - LSP 生命周期保护抽成共享模块并接入全部 LSP 工具:
get_symbols的打开文档激活语言服务、超时、取消、瞬时失败重试逻辑提取为lspLifecycle.ts(withTimeoutAndAbort/executeLspCommandWithRetry/openDocumentWithGuard),goto_definition与find_references补齐同等保护——provider 挂起不再无限等待,回合取消立即中止;get_symbols保留原导出常量与行为,新增 21 个测试。 - 修复 SubAgent
continueFromRunId续跑丢失 provider 前缀缓存的真正根因:此前的修复只解决了缓存域(user_id 沿用旧 runId),但续跑请求历史取自 Monitor 展示 transcript——首条# SubAgent Invocation卡片从未发送给 provider,与旧 run 的任何一次已缓存请求从第 0 条就不共享前缀,缓存必然全 miss。现在事件总线持久化「最后一次实际发送给 provider 的 history」(lastSentHistory,发送前已完成 agentInbox 剥离、深拷贝、不污染 Monitor 内容与修订号),续跑严格以它为前缀再追加新用户消息;旧记录缺字段时降级过滤 invocation 卡片。新增前缀不变量测试(续跑首请求 = 旧最后请求 + 新消息、不含 Invocation 卡片、持久化恢复后仍成立)。 - 优化 apply_diff 的固定延迟:写前工作区存档不再阻塞工具启动——批内全部为 diff 审阅类工具(apply_diff / write_file / insert_code / delete_code)时,before 存档与工具前置阶段(读文件 + hunk 规划 + 预览渲染)并发启动,预览先行显示;写盘前由 DiffManager 强制等待存档完成并获取目标文件写盘锁(审阅期间持有、diff 终结释放,与入口持锁语义一致,冲突按既有 lockConflict 语义收敛为拒绝),混合批保持同步语义。结构化 hunk 首次精确匹配计划(fast path 产物)缓存到 pending diff,块级拒绝与最终内容重算直接按计划重放、不再重复全文件扫描(起始内容不一致时自动回退重扫);write_file 新建文件预写空文件同样在 checkpoint 就绪后带临时写锁执行。新增并发时序、锁持有/释放与计划重放等价性测试。
- 修复
get_symbols在大型、尚未打开的 TypeScript 文件上偶发1 file(s) failed to get symbols或无限等待:查询前主动打开文档激活语言服务,瞬时未就绪时重试一次,provider 挂起与用户取消均有界退出;聚合错误现在携带具体文件和 tsserver 原因,并补齐 DocumentSymbol 层级、重试与超时回归测试。 - 修复主聊天或 SubAgent Monitor 获得焦点时原生文件 diff 打开到 Monitor 列:所有写工具共用的 diffManager 在打开瞬间定位主聊天列,
vscode.diff后再按实际 tab 校正目标组,主聊天位于侧边栏时回退第一编辑器列。 - 改进批量
read_file工具卡片摘要:不再把后续文件折叠为+N,而是逐行显示真实文件路径、范围与批次状态;SubAgent Monitor 在窄列下允许运行元信息收缩换行,标题与控制区不再横向溢出。 - 修复分支候选下拉框在消息项
contain: layout定位上下文中横纵坐标重复偏移、窄侧栏右侧溢出的问题:候选浮层改为 Teleport 到body,根据视口宽高选择向上或向下展开并约束左右边界,滚动和窗口缩放时持续重算位置。 - 修复
read_file成功执行但工具卡片摘要显示?、展开后丢失文件的问题:单文件调用同时携带规范化生成的空files: []时不再误入批量分支,摘要和内容面板都会回退使用有效path;新增空批量与单文件路径并存的回归测试。 - 放宽同参数重复失败调用护栏:失败次数改为只统计没有其他真实工具调用介入的连续同签名失败,执行诊断、修改文件或其它成功调用后允许原参数重跑测试;真正连续原样失败仍会被短路,默认系统提示同步允许相关状态变化后的重新验证。
- 完善分支候选切换数据源与状态同步:新增
buildCandidateGroupAt按父节点推导候选组(取代原先只取「活跃尾兄弟组」的buildCandidateGroup),BranchSwitcherBar接收parentNodeId,多个分支点可各自计算「‹ N/M ›」候选状态;候选列表使用 fixed 定位浮层防止被消息滚动容器裁剪;DirtyFilesConfirm由MessageList常驻挂载,分支切换遇到未保存文件时确认框不受组件显隐影响。 - 按消息操作栏重新整理分支交互:候选切换器不再作为消息下方独立一列,改为嵌入
MessageActions,与复制 / 重试按钮保持同一行和高度;分支树面板改为论坛评论树式连接线布局,用竖向树干与横向分叉线表达父子关系,活跃路径只高亮导线,只有活跃尾节点显示「当前」,分支点显示未删除候选数量,并补齐中英日三语文案。
Tests
- 新增分支历史纯布局测试,覆盖 20 条线性消息不增加横向轨道、兄弟候选独立轨道、导航模式连续消息折叠及特殊节点保留;更新组件测试覆盖双模式切换与既有管理交互。
- 新增子代理独立 transcript 新格式/旧数据迁移、文件系统原子写与会话级清理、停止前后空闲等待、运行中会话删除生命周期顺序测试。
[1.4.0] - 2026-08-04
Changed
- SubAgent Monitor 运行列表改多行布局(用户反馈):run tabs 从单行横向滚动改为
flex-wrap自动换行,tab 在行内伸展铺满(flex: 1 1 170px),子 agent 数量多时不再横向翻找;限制最大高度约 3 行,run 极多时退化为纵向滚动,不占满整个面板 - Diff 应用与展示性能重构:
apply_diff、write_file、search_in_files共用带编辑距离预算的 Myers 行级差分,移除 Webview 主线程上的二维 LCS 表和模板内同一 diff 最多 5 次重复计算;每个文件/块改为响应式缓存一次统计与行结果,超长展开内容通过VirtualDiffLines仅渲染可视窗口,降低大文件和批量替换时的 CPU、内存与 DOM 开销 - 后端 diff 应用增加快速路径:互不重叠且唯一匹配的结构化 hunks 先规划位置并一次拼接文件,保留依赖前序修改、缩进容错和歧义场景的原逐块语义;unified patch 改为整块单次
splice,fallback 先按首行筛选候选再校验完整块,避免逐行修改数组和无条件嵌套扫描 - 存档排除配置编辑器美化:设置页「自定义排除模式」与「每类别模式编辑」从裸 textarea 改为 chips 风格模式列表编辑器(
PatternListEditor)——已有模式以标签卡片展示、悬停逐个删除,输入框回车添加、粘贴多行自动拆条去重,添加/删除即时保存;类别编辑面板补充标题栏与「清空(恢复默认)」按钮并补齐样式;自定义模式标签旁新增规则数量徽标;三语文案同步 - 后台任务回流卡片新增三段式折叠视图(用户反馈):默认折叠为两行省略,可切换「中展开(约 15 行内滚动查看)」与「完全展开」,三个图标按钮置于卡片头部右侧,当前视图高亮;配合后台回执完整内联修复,长报告不再撑满聊天窗口
- 存档路径安全加固:删除、合并、manifest 读取路径统一经共享
isSafeCheckpointDirName校验(/^cp_[a-z0-9_]+$/i),损坏/恶意元数据中的backupDir不再能触发fs.rm(recursive)递归删除存档目录外内容;恢复侧文案与失败摘要统一走t()并补齐modules.checkpoint.restore.*三语条目(checkpointNotFound / manifestMissing / cannotBuildChain / backupDirNotFound / moreFailures / excludedNote / excludedNoteChanged) - 索引删除补祖先闭包:
deleteCheckpointsFromIndexInternal与批量删除对齐,从所有保留节点向前遍历完整基链,编辑+重试导致消息索引回退时不再删掉保留节点的基快照(不再产生永久断链存档);预览返回deleted与deletedIfUnconfirmed两个计数,与默认执行口径严格一致 - 存档配置保存链路加固:
updateCheckpointConfig改为深合并落盘(部分 exclusion/messageCheckpoint 负载不再覆盖已保存的 profilePatterns 等嵌套字段);enabledProfiles值必须为 boolean("false"字符串不再被当真)、工具列表必须为字符串数组、maxCheckpoints仅接受有限整数(保留 -1 无上限哨兵)、enabled必须为 boolean;自定义模式拒绝*/**//**//*全忽略模式(新增 blanket 原因) - 强制排除大小写折叠扩展到 macOS:
.GIT/NODE_MODULES目录片段与扩展存储绝对路径自排除在 win32/darwin 大小写不敏感卷上不再可绕过,normalizeWorkspaceUri同步折叠;符号链接不再静默丢弃,记录为unsupported_file_type排除条目供预览解释 - 用量索引并发丢失更新根治:
FileUsageIndexStore内部实现 per-conversation 写串行队列(appendUsage / appendUsageMessages / write / remove 全部入队,write 内按条目键去重),并行子代理与主会话的读改写不再互相覆盖;usage.json 改 tmp+rename 原子写;统计 listConversations 失败时跳过 prune 保留内存缓存;fs.watchrecursive 增加递归能力探测,不支持时退化为 mtime 快照比对 - 历史存储读一致性加固:
loadSegmentedHistory读后校验Σcount === totalMessages且段齐全(双 rename 提交窗口不再静默返回错位历史),读侧重试改为 2~3 次带退避;getMessagesPaged初始页先只读浅扫描,仅存在悬空 functionCall 才走深拷贝路径(首屏收益找回);钳制改轻量只读 index(不再每条消息 O(段数) 次 stat);删除会话后 append/mutate 短路(流式中删除不再"无 meta 幽灵复活");自愈优先从可读段重建、totalMessages 重算为 Σcount、批量摘要返回 truncated 标志、段缓存增加字节软上限与按会话分桶失效 - 前端设置页与 checkpoint store 加固:
updateConfigField保存失败回滚字段 + 保存串行化;loadConfig失败时禁用表单并展示错误横幅(不再以默认值渲染导致真实配置被覆盖);checkpoint.restore/deleteBatch/previewExclusions超时豁免;失败路径重载 checkpoints;进度轮询瞬时错误不停止 + 陈旧检测 + 新操作重启;展开对话列表响应校验对话身份;批量删除失败保留列表 + 防重入;mergeUnchanged仅保存成功才同步 chatStore - 恢复错误语义修正:恢复结果(失败/部分失败/未备份警告/成功)改用独立分级提示,不再塞入
chatStore.error;错误条「重试」按钮仅在可重试错误码(STREAM_ERROR 等)时显示,恢复失败后点击不再误触发 LLM 重新生成;恢复确认框固化conversationId(预览/确认期间切对话不再恢复错误对话);previewExclusions/getAllConversationsWithCheckpoints加入非阻塞路由;updateCheckpointConfig响应携带归一化配置供前端校正;checkpoint handler 补入参校验与明确错误码 - 快照构建/查询收敛:
runBounded/hashFileStreaming/isExcludedAbsolutePath三处重复实现收敛到共享模块(checkpointConcurrency/fileHashing/checkpointPathUtils,大小写策略统一);排除预览 samples 按路径排序;设置页统计改有界并发 +getMetadataLight;getCheckpoints区分「无记录」与「读取失败」;移除as any类型绕过 - 消息稳定 ID 地基:
Content新增id/parentId,所有写入路径(append 锁内尾读、mutate 插入、functionResponse 补齐)统一经ensureNodeId生成稳定 ID + 线性 parentId;旧历史在首载/迁移入口按「缺 id 自判定」于会话写锁内确定性补 ID(uuidv5 风格,幂等:多次迁移 ID 集合一致)并原子全量重写一次(totalMessages 不变、指纹校验);formatHistoryForAPI白名单确认不下发 id/parentId;前端 parsers 透传content.id为Message.id(跨加载稳定,不再每次生成) - 前端清理:
summarizeContext/cancelSummarizeRequest从 checkpointActions 迁入 messageActions(re-export 保持导出名兼容);设置页存档项新增「排除详情」入口接通checkpoint.getManifest(前端缺口闭合,旧存档提示不可用) - 子 agent 嵌套能力(用户需求):子 agent 现在可派生子子 agent(subagents 工具对子 agent 开放)——嵌套深度上限 2(主=0/子=1/子子=2)超限拒绝,深度由框架注入不可伪造;父 run 结束级联清理派生子 run;子 agent system prompt 追加使用说明(一般不需要,仅代码需独立复查或主模型明确指令时使用);嵌套派发继承父级工具过滤(只读 agent 不能通过嵌套获得写权限)
- 用户消息插入:主会话工具循环/流式中用户发消息不再排队等整轮结束——
chat.sendInterruptMessage投递到主会话 inbox,随最近一次工具调用结果一起注入给模型(10s/条频率限制、4000 字符上限、仅投递不落历史);sendMessage忙时自动改走插入路径 - 树状分支接线:新建
BranchService(分支图读写删接口 getBranchGraph/getBranchGraphMeta/createRerollCandidate/editCandidate/switchBranchCandidate/deleteBranchCandidate、validateActivePathMatchesHistory活跃路径校验、跨对话导出建模 exportedFrom/exportedRefs、importLinearHistory线性导入);BranchHandlers注册 5 个分支 API;ConversationManager暴露runExclusive公共锁包装(锁序文档化)、createBranchConversation记录 sourceNodeId + 图初始化/导出标注、deleteConversation清理 sidecar;switchBranchCandidate明确不重写主历史(边界留给后续分支任务) - 迁移与完整性:新建
BranchMigration(逐版本迁移注册表 + 链式升级 + 升级前深拷贝失败回滚 + 原子落盘 + 损坏拒绝覆盖);新建backend/tools/maintenance/integrityCheck只读完整性检查(历史 Σcount/段齐全/孤儿段、存档 backupDir/manifest/增量链 base+环、分支 validate + 活跃路径与主历史对比,只报告不修复);复查后分支对比降级为 warning(回收条件注释随分支任务落地更新) - 候选切换全链:
ConversationManager.rewriteHistoryFromBranchGraph(会话写锁内从图活跃路径重建主历史:FR 拆分、幂等、分歧索引、用量重建 + trim 失效)+BranchHandlers.switchBranchCandidate全链编排(切图 → 主历史重写 → 锁外检查点清理 → rewritten 标记,失败回滚图状态);复查后补:FR 消息 id 按「节点 id + FR part id 集」复用旧历史 id(防幂等失效与检查点误删)、invalidate 移至 saveHistory 前(metadata 写失败不再分裂图/历史)、切换前锁内历史/图尾部一致性检测(不一致拒绝切换返回 BRANCH_OPERATION_CONFLICT) - 树状分支前端:
branchActions.ts(切换成功后重载历史 → 重建 messageIndexById/toolResponseIndex → 清理错误条/流式残留 → TODO/Build 重置 → 刷新检查点与分支图,失败快照回滚,BRANCH_BUSY 前端双保险);BranchSwitcherBar.vue(‹ 2/3 › 循环切换 + 候选下拉 + 两步确认删除,无分支图自动隐藏);BranchTreePanel.vue(分支树浮层面板:本地 DFS 组装 + 活跃路径高亮 + 软删灰显/恢复 + 行内重命名);标签页快照保存 branchGraph(修复切标签页残留旧图) - 用量含全部分支:方案 A 读取时合并——统计读取时经
readBranchGraph读 branches.json,主历史消息 id 为权威去重键(图活跃路径仅作旧索引无 id 时兜底),非活跃候选 token 以source='branch'并入各维度 +inactiveBranchTokens细分;复查后补:混合态索引去重修正(historyIdsComplete 判定)、候选节点携带 usageMetadataPartial(中断候选按估算口径) - 分支管理:软删除(deletedAt + 保留期默认 30 天可配置 + 级联软删/恢复整棵子树——修复 prune 静默移除 live 子孙的数据丢失高危)、重命名(renameBranchCandidate 仅改 label)、修剪(pruneDeletedBranches 过期节点+子树物理清理)、purgeBranchCandidate 彻底删除(幂等化)、getDeletedBranchCount 与 prune 孤儿口径统一;设置页新增
BranchCleanupSettings.vue区块(软删数量/一键清理/保留期输入,三语文案);switch 目标到 root 链上软删节点校验返回 BRANCH_OPERATION_CONFLICT - 性能基准:
test/benchmark/(.benchmark.ts 后缀 + --testMatch 显式运行,普通测试不执行)——2000 文件快照创建 0.3s/恢复 0.7s、1 万条历史 append 0.9s/读取 27ms/用量 12ms、100 候选图操作全亚毫秒(含漂移恢复测量与 102 层深链场景,smoke 上限按实测 10-20× 收紧,harness 输出 GC 可用性并做 JIT 预热) - 分支-存档联动:
bindWorkspaceCheckpoint(节点绑定 workspaceCheckpointId/workspaceState,工具执行存档点 fire-and-forget 接线);切换双模式(chat-only/chat-and-workspace,编排:安全校验→dirty 闸门→取消流→预览→恢复(失败不切分支)→切换,锁序「恢复先于切图」);dirty 文件拦截(WorkspaceRestoreGuard 统一拦截普通恢复与切换,未保存内容不再被静默丢弃);判据富化(hasWorkspaceState/wroteToWorkspace)+ 前端双按钮确认(三语);引用计数清理(checkpointRefCounts 扫描 + deleteCheckpointsByNodeIds 三重闸门 + purge/prune 联动,软删不触发);不做内容哈希去重(增量链共享 4 测试固化);一致性矩阵 26 场景盘点;核实旧存档 manifest 兼容与 ignorePatterns 合并口径已覆盖 - 大文件拆分(落地):
CheckpointManager2413→1687 行,恢复侧文件操作与辅助平移至CheckpointRestoreService(722 行,prepareRestore/legacy 恢复/过滤/哈希收集/排除说明等 12 方法)与WorkspaceEditorRefresher(94 行);CheckpointSettings.vue3284→2263 行,script 拆为 5 个 composable(useCheckpointConfig/useCheckpointExclusion/useCheckpointCleanup/useCheckpointOperationProgress/useCheckpointManifest);SettingsManager2347 行拆为门面 + SettingsCore + 14 个主题服务,settings/types.ts2419 行拆为 11 个主题类型文件 + 聚合入口(公共导出零变化,纯重构)
Added
- 新增共享行级 diff 算法与虚拟行组件测试,以及结构化/unified diff 应用回归测试,覆盖大文件预算降级、公共边缘裁剪、顺序依赖与 relocated hunk fallback
- 新增 agent 间消息通信(用户设计):
agent.sendMessage工具 + 内存 mailbox(会话限定 + 已知 runId 防冒充、threadId + hopDepth 5 跳防循环)——收件方在最近一次工具调用结束后把 inbox 消息追加到工具结果之后随结果返回(主会话工具循环 5 处调用点与子代理执行器均接入),run 结束自动清理;配套信箱与注入点测试 34 用例;用户消息插入与对话删除接线作为二期方案 - 新增树状分支底座(初版):
backend/modules/conversation/branch/——BranchGraph.ts纯函数模块(insertNode / rerollCandidate / editCandidate / activePath / rebuildActivePath / childrenIndex / validate,含环检测)、BranchGraphRepository.ts(branches.json 原子写、损坏抛 BRANCH_STORAGE_CORRUPT、删除对话清理)、types.ts(ConversationBranchGraph / ConversationBranchNode / BranchErrorCode;functionResponse 不独立成节点、kind 含 exported、单 parentId 索引 + activeChildId);配套纯函数与仓储单测 61 用例 - 审计修复核对与测试补齐:确认 xmlFormatter 防御配置、toolResponseFormatter 部分成功序列化、SubAgentRegistry.isEnabled 修复已在提交 3bfab33 就位;
promptToolParser.test.ts补齐 DOCTYPE 实体不展开与超深嵌套拒绝两项安全用例;新增toolResponseFormatter.test.ts(文档 5.6 节 10 项全覆盖)与subagentRegistry.test.ts;各修复批次新增回归测试(损坏 backupDir 删除拒绝、索引回退不断链、manifest LRU、锁排队取消、大小写绕过、深合并保留、用量并发、双 rename 读一致性、删除复活、设置页保存回滚/加载失败等) - 本轮新增测试:子 agent 嵌套(15 例:深度限制/父过滤传播/级联清理)、用户消息插入(8 例:忙时投递/频率限制/失败回退)、分支接线(BranchService 23 + BranchHandlers 6 + BranchGraph 扩展 5)、迁移与完整性(BranchMigration 15 + integrityCheck 32)、复审修复(用量重建/队列超时/重读校验/原子化 9、agentInbox 剥离 11、错误码与重试 8、前端 UX 9、嵌套权限逃逸回归 等)
Fixed
- 修复 SubAgent Monitor 面板抢走 diff 预览位置(用户反馈):
vscode.diff不带 viewColumn 时在「当前活动编辑器组」打开,焦点在 Monitor(Beside 列)时 diff 会开在 Monitor 旁边而非主聊天侧;现在 Monitor 路由上下文下发diffViewColumn(经 tabGroups 按 viewType 定位主聊天所在列,侧边栏时回退主区域第一列),openDiffView显式传viewColumn——无论焦点在哪,diff 都固定跟随主聊天所在列;HandlerContext新增diffViewColumn字段,主聊天自己发起的 diff 行为不变 - 修复前台 SubAgent 转后台(detach)机制的三处残留缺陷:① 循环顶部/工具执行前/启动检查三处取消判定仍裸读父 abortSignal,转后台的 run 在后续迭代或工具调用前仍会被旧流 abort 杀死(绝大多数真实场景失效)——统一改为
parentAbort()(detached 后视为无父信号);② 排队期间 detach 后,acquire 成功时启动检查与超时桥(对已 abort 信号注册的 onParentAbort)仍会杀掉 run——超时桥注册加!detachedFromParent保护;③ detach 把 acquire 桥的 run 控制信号监听一并移除,排队中已转后台的 run 失去 Monitor 终止响应——acquire 桥拆分父信号/控制信号两部分,detach 只摘父信号;新增回归测试(多轮迭代继续执行、排队-detach 继续执行) - 修复用户发消息时前台子 agent 被连带杀掉(用户实测):此前新流启动(StreamAbortManager.create)会 abort 旧流,而前台 SubAgent 的 abort 信号挂在主会话工具循环上,旧流取消会连带终止还在干活的子代理;现在
SubAgentRunController增加attachedToParent标记与detachFromParent(转后台)能力——StreamAbortManager.create在 abort 旧流之前先把该会话活跃前台 SubAgent 转为后台(executor 同步解绑父 abort 信号的组合监听、排队唤醒桥与超时桥),run 继续执行至完成,结果经 Monitor/事件总线呈现(广播run_detached事件);后台 run(attachedToParent=false)不受影响,保留 TaskManager 取消能力;新增回归测试 11 例(runController detach 语义 5、StreamAbortManager 转后台矩阵 4、executor 集成含对照组 2) - 修复后台子 agent 完成消息被截断(用户实测):
buildSubAgentSection此前把后台 SubAgent 最终报告按 4000 字符截断,并以[Truncated N more characters. Open Monitor to view the full transcript.]收尾,而 Monitor 是人类 UI、主模型没有访问路径,研究/审查报告被腰斩(前台不传 background 的回复完整,因 functionResponse 无截断);现在回执完整内联结果正文,与前台载荷同规格——完整结果本就要经 postMessage 转发给 Monitor(现状无截断),回执再经 chatStream 与普通用户消息同路径发送,无新增载荷上限;新增回归测试锁定超长报告不再截断 - 修复 manifest 缓存无界与锁队列不可取消:manifest 内存缓存改 LRU(上限 32)且
getManifest读后即弃;工作区锁排队等待响应取消信号(abort 时移出队列);同 owner 超集重入改为运行时 fail-fast 而非静默排队死锁 - 修复存量并发与一致性缺陷:RetentionService 清理以删除返回值为准、对多依赖者循环合并;updateSummary 不再多余写入
updatedAt(列表排序不再抖动);loadCheckpoints失败保留旧值;trimWindowFromTop窗口裁剪不再永久丢弃窗口外检查点;恢复确认框取消时清理选中残留;前端restoreAndEdit失败补重载兜底 - 修复恢复/预览性能残留:
collectCurrentWorkspaceState与 legacy 恢复哈希从顺序读盘改为共享模块有界并发流式哈希;previewRestore经runExclusive({ needFileLock: false })只取工作区级互斥,不再持有全局文件写锁阻塞全部写工具 - 修复恢复顺序与进度:恢复改为「先复制(含哈希校验)→ 全部成功后最后删除」,复制失败不再留下「已删未补」中间态;删除阶段逐文件上报进度,进度 total 覆盖删除 + 恢复全量
- 修复复审轮发现的高危问题:用量索引全量重建改为队列内基于最新盘面执行(并发 main 条目不再被覆盖丢失);
agentInbox在落盘前剥离(不再随历史每轮重放给模型);错误条重试白名单并入后端真实可重试错误码(API/NETWORK/TIMEOUT/PARSE,排除 CANCELLED/CONFIG/VALIDATION 与 RESTORE_*——引入的重试回归修复);只读预设嵌套派发权限逃逸修复(嵌套继承父级工具过滤、无写工具 agent 移除 subagents、空工具集拒绝一切);retryFromMessage/editAndRetry删除或编辑 IPC 异常路径不再继续重试(历史不重复、本地与后端一致);rejectToolCalls读改写原子化;deleteConversation纳入会话写锁(删除复活闭环);段读取后重读 index 版本比对(双 rename 窗口错位历史被检出);enqueueWrite挂起超时;统计缓存回填含 subagent 合并条目
[1.5.1] - 2026-08-04
Added
- 代码查看面板自动打开工作区文件树:面板打开即列出工作区根目录(新 IPC
listWorkspaceDirectory,工作区包含校验 + 默认忽略.git/node_modules/dist等重型目录),目录点击懒加载展开、文件点按即查看代码;工具栏新增文件树开关与刷新按钮;相对路径打开改为拼接工作区根 URI(修复file://相对路径被Uri.parse解析成 authority 导致工作区文件无法打开的问题) - 变更查看面板支持展示并比对上一轮变更:已处理(已接受/已拒绝)条目在关闭面板后保留,重新打开可继续查看与比对历史 diff,不再只有待处理变更;条目按「轮」分组(连续推送视为同一轮,间隔超过 2s 视为新一轮),文件列表显示「第 N 轮」轮次分隔;全部处理完毕后显示提示条(历史条目仍可查看);新增「清空历史」按钮显式清空记录
- 新增变更查看 Store 单元测试 7 例(
frontend/src/__tests__/stores/diffViewerStore.test.ts):push 建条目/关闭后保留/已处理条目重复推送保持状态/轮次分组/清空历史/批量接受只作用于待处理条目
Fixed
- 修复已接受的变更通过工具卡「查看差异」再次打开时状态被重置为待处理、重新出现接受/拒绝与全部接受/全部拒绝按钮:
diffStore.push对已存在条目保留原已解决状态(已接受/已拒绝),不再回退成 pending - 修复变更查看面板对已处理条目仍渲染(仅禁用)接受/拒绝按钮:改为非待处理条目完全不渲染接受/拒绝按钮,历史变更只读查看与比对(全部接受/全部拒绝同样只在存在待处理条目时出现)
- 修复 SSE 心跳事件污染解析累积器导致长流被误判失败并反复超时重试:上游/网关在长时间思考期间周期性回传的
data: keep_alive/keep-alive/ping/heartbeat等非 JSON 心跳行,旧实现会混入currentData并按「不完整 JSON」继续累积,之后所有真实事件全部解析失败,流结束时被误报「模型返回空内容」、触发无谓的 NETWORK_ERROR 重试;现在只有「看起来像 JSON 前缀」({/[开头)的内容才允许跨行累积,心跳行直接替换/丢弃,纯心跳流在结束时不再进入错误详情(unparsed),网关真实纯文本错误仍照常带出;新增 5 例回归测试 - 修复代理链路由 CONNECT 阶段
http.request({ timeout })武装的 socket 空闲定时器残留:握手成功后旧定时器仍存活,长流式请求在「上游思考、无数据可发」的静默期超过固定timeout毫秒时触发proxyReq 'timeout'→destroy()把已转交的隧道 socket 销毁,正在进行的流被固定超时强行掐断(外部 keep-alive 心跳也救不回来);现在 CONNECT 成功后立即socket.setTimeout(0)解除残留定时器,流的空闲超时统一交给ChannelManager.executeStreamRequest的可重置计时器(任意到达字节都会续期) - 修复 LLM 模块缓存保活请求未正确判定成功:
sendKeepAliveRequest旧实现不检查response.ok,非 2xx(429/5xx/错误体)也被当作「保活成功」,Anthropic Prompt Caching 的 5 分钟 TTL 实际已过期却静默继续、下一轮对话全价计费;现在非 2xx 明确抛错、瞬时失败自动重试一次(500ms 间隔),返回布尔值供调用方判断「上游确实接受本次刷新」 - 修复 LLM 模块保活调度与流空闲超时脱节:保活定时器从固定 4 分 30 秒的
setInterval改为链式setTimeout(首个保活提前到「流空闲超时前 10 秒」,下限 30s、上限 4 分钟),保活请求成功即通过idleTimeoutHandle.reset()刷新流的空闲超时——上游静默思考且不回传心跳时,流不再被固定超时掐断,而是靠 LLM 模块自己的保活续命;另加在途互斥(上一次保活未完成不叠加触发)与流结束即停调度(catch/finally 置streamFinished,杜绝残留定时器) - 修复重试成功事件在重试请求真正完成前就触发(重试页面过早消失):
executeStreamRequest是异步生成器,await它只拿到生成器对象、请求尚未发出,旧代码在生成器创建后立即广播retrySuccess——重试页面在重试请求真正完成前就消失,且重试再次失败时会闪现错误面板;现在retrySuccess移到本次尝试的for-await正常结束后才广播(新增回归测试锁定:网络错误→重试→成功的事件序列) - 修复
GenerateRequest.retryStatusCallback(请求级重试回调)从未被读取:ChannelManager只使用全局retryStatusCallback,导致 SubAgent executor 传入的重试状态路由(retryFailedInThisCall→wait_for_monitor_action恢复路径)与 Monitor 内部重试展示全部失效;现在优先使用请求级回调,suppressRetryNotification只抑制全局回调、不抑制显式传入的请求级回调(新增回归测试覆盖 4 种场景:重试重发请求、请求级回调路由、全部失败 retryFailed、skipRetry 不重试) - 修复超时重试面板近乎透明、可读性差:
.retry-panel/.retry-header/.retry-error-json原本使用 rgba 低透明度背景叠加在聊天区上,错误信息与重试进度几乎不可读;全部改为不透明主题色背景(editorWidget-background/editorGroupHeader-tabsBackground/textCodeBlock-background,浅色主题同样有值),并加深面板阴影
Added
- 新增 ChannelManager 重试链路回归测试 4 例(
backend/__tests__/channel/channelManagerRetry.test.ts,mock fetch 首答失败后成功):验证重试真的重新发送 HTTP 请求(fetch 调用次数 = 尝试次数)、retrying → retrySuccess事件序列、请求级回调在suppressRetryNotification下仍收到事件、全部重试失败抛错且不重复回调 - 新增重试面板生命周期前端测试 5 例(
frontend/src/stores/chat/__tests__/retryStatus.test.ts):retrying 显示面板、retrySuccess/retryFailed 消失面板、失败后可再次重试、非当前对话的重试状态写入标签页快照不污染当前面板
Changed
- 前端 i18n 新增
components.diff.roundLabel/allProcessed/clearHistory与components.codeView.workspaceFiles/noWorkspace/refreshTree/treeEmpty三语翻译键;components.diff.empty文案改为「暂无变更记录」;components.codeView.empty文案提示从工作区文件树选择
[1.5.0] - 2026-08-04
Added
- 新增代码查看面板(内嵌右侧抽屉,与变更查看面板同布局体系):工作区路径打开(复用
readFileForContext的扩展端工作区校验)与内存内容查看(diff 新内容 / 工具结果片段),行号 + highlight.js 语法高亮 + 错误行标记 + 诊断列表点击跳转 + 最近打开列表 + 跳转行号输入;入口:聊天区右下角 dock 按钮、read_file 工具卡「代码面板查看」、变更面板「查看新内容」 - 新增纯前端基础语法检查引擎
frontend/src/utils/syntaxCheck.ts(零依赖、单次线性扫描):JSON 真实解析报错(带行列定位)、C 系(JS/TS/JSX/Java/C/C++/C#/Go/Rust 等)括号/字符串/模板/注释平衡、Python、CSS 块注释、HTML/XML/Vue 标签匹配、Shell 引号;512KB / 2 万行护栏防大文件卡顿;配套 Vitest 17 例(含标签名截断回归) - 变更查看面板(Diff Viewer)接入语法检查:文件列表显示新内容语法错误数徽标,详情区展示诊断列表(L行:列 + 消息),仅对支持检查的代码语言展示「未发现语法问题」,非代码文件不误导;「查看新内容」按钮一键在代码查看面板打开修改后内容
- Electron 桌面版 codicon 图标字体改为主进程运行时注入(insertCSS + 相对字体 URL 重写为绝对
graycode://local/...),不再依赖 patch-dist 静态补丁,前端 rebuild 后图标/徽标不再丢失;注入按 key 幂等(reload 先移除旧样式,修复规则翻倍累积)
Security
- 修复
graycode://自定义协议可读取含 API Key 的用户数据目录(H-1):服务根收窄为frontend/dist/resources/renderer静态资源白名单,用户数据目录(默认位于 REPO_ROOT 内)显式排除;hostname 强制为local(graycode://evil/一律 403);500 错误返回固定文案,不再回显内部路径 - 修复 openPath/showInFolder 可执行扩展名黑名单不完整(H-2):补充
.hta/.lnk/.url/.reg/.iso/.vhd/.vhdx/.docm/.xlsm/.pptm/.svg,阻断「AI 写入恶意文件 → 用户打开 → 任意代码执行」链路 - 修复 API Key 拼进 URL query(泄漏到访问日志/代理日志/浏览器历史):Gemini token 计数(模板、
generateContent端点替换、裸路径三分支)与 generate_image 全部改走x-goog-api-key请求头,模板残留与key/api_keyquery 统一剥离 - 修复 MCP StdioClient stdin 写入无 error 监听:进程退出与
write()竞态窗口内 EPIPE/ERR_STREAM_DESTROYED 不再抛未捕获异常导致扩展宿主崩溃;spawn 失败(ENOENT)等不触发 exit 的路径立即拒绝挂起请求;Windows 移除 cmd.exe shell 包装(消除&/|/引号参数的二次解释,命令注入面) - 修复 MCP stderr 无界累积(与 stdout 对齐 1MB 护栏 + 截断标记)
- 修复
SkillsHandlers.openDirectory可在任意位置创建目录并打开任意文件夹:只允许打开 skillsManager 管理的目录(绝对路径 containment 校验) - 修复代理链路 header CRLF 注入面(纵深防御):请求头值统一剥离 CR/LF
- 修复通知处理器把完整 payload(对话标题/正文)写入默认可见的 WARN 日志:只记录元数据,debug 级同样脱敏
- 修复 i18n 占位符可访问原型链属性(
{toString}类占位符):改hasOwnProperty校验 - 修复 glob 连续
**展开成多个可选.*组(长路径指数级回溯):编译前折叠为单个 globstar - Electron
fs:existsnative op 增加字符串类型校验(非字符串路径不再抛 TypeError)
Fixed
- 修复流式请求校验在 try 块外:非法 conversationId 时前端请求永久挂起 +
requestClients路由表泄漏(chatStream / retryStream / editAndRetryStream / toolConfirmation 四处),统一改为校验失败即回错误响应并清理路由表 - 修复
cancelStream载荷解构无防御:data 缺失时 route() 抛错导致路由表条目永久泄漏,改为防御性取值 + 错误回执 - 修复
WebviewClientRegistry.resolveClientId返回未注册 id:requested 未命中时回退到已注册客户端,避免requestClients记录无效条目、响应错投 - 修复 App.vue 监听
diff.statusChanged消息类型写错('message'vs'command'):变更面板条目状态同步与删除警戒提示恢复生效 - 修复扩展端未实现
subagents.monitor.setVisible(与 Electron 版行为对齐):Monitor 折叠时后端停止推送 llm_delta 高频增量 - 修复
summarizeContext完成后重载无会话归属校验:切换会话竞态不再把新会话历史整体覆盖进 allMessages;前端将该消息加入无兜底超时列表,与后端分钟级长任务语义一致(180s 兜底超时误触发会把迟到响应误当广播推送) - 修复
restoreAndEdit错误路径无会话校验:跨会话不再污染新会话的错误/流式状态 - 修复发送失败错误展示依赖
isStreaming判断:await 期间用户取消导致的竞态下,真实发送失败不再被静默吞掉 - 修复
apply_diff重叠匹配 O(n²) 主线程 DoS(高频短 oldContent 卡死数分钟):匹配数上限 2 万;同步读文件加 20MB 大小护栏 - 修复
processQueue发送失败时排队消息永久丢失:失败消息放回队首(去重防死循环) - 修复附件无大小上限(全量 base64 入内存可拖垮 webview):50MB 上限(视频 200MB);批量上传 try/finally 复位上传状态
- 修复 UsageStats 统计缓存客户端可控 key 无上限:LRU 上限 20 条
- 修复 HttpClient SSE 服务器结构化错误被当作解析错误吞掉:真实错误不再被替换成误导性的「超时」
- 修复
cleanJsonSchema无深度护栏:外部 MCP 服务器构造的极深嵌套 schema 不再栈溢出(深度上限 64) - 修复 DependencyManager
exec字符串拼接(POSIX 路径注入面):改execFile参数数组直传 - 修复 execute_command 每数据块重建 GBK 解码器(表加载开销大):预览解码器提升为复用实例
- 修复 HistoryPage 递归预加载风暴(数千条历史串行拉几十页):单次挂载最多自动补齐 3 页,其余交给滚动触发
- 修复 i18n
translate正则参数键未转义(元字符键替换异常);App 级声音去重集合无界增长(上限 1000 条) - Electron:
workspace.fs.delete支持useTrash(进回收站,与 VS Code 语义一致,不再永久删除);applyEdit 对已删除文件不再静默重建残缺文件(ENOENT 明确报错);documentCache 加 100 条 LRU 上限;overlay toast 超时自动移除前回执undefined(后端 Promise 不再永久挂起);后端初始化失败弹原生错误框(可打开数据目录/退出),不再白屏 + unhandled rejection;will-navigate严格限定graycode://local/
Changed
frontend/src/utils/vscode.ts的 UNBOUNDED_REQUEST_TYPES 增加summarizeContext(与后端 NON_BLOCKING 语义对齐)- 前端 i18n 新增
components.codeView.*与components.diff.*(viewNewContent/syntaxIssues/noSyntaxIssues)三语翻译键
[1.4.1] - 2026-08-04
Security
- 修复设置导出明文泄露 API Key:导出 JSON 前统一脱敏渠道
apiKey与 MCP 服务器headers/env(占位符***REDACTED***) - 修复 Markdown 图片
src未转义 XSS:MarkdownRendererimage 渲染器输出前对 src 转义;sanitizeHtml改为 scheme 白名单(href 仅 http/https/mailto/tel,src 仅 http/https/data:image),剥离 scheme 内控制字符并处理xlink:href/srcset/formaction,阻断java\tscript:类绕过 - 修复 SubAgent Monitor 面板内联脚本注入:
__GRAYCODE_INITIAL_RUN_ID等 JSON 注入前转义<(</script>闭合绕过) - 修复 conversationId 路径穿越:
ConversationManager存储层getConversationDir/getMetadataPath/getSnapshotPath与UsageIndexStore全部入口统一assertSafeId校验;webview 边界ChatHandlers/StreamRequestHandler/FileHandlers.summarizeContext/SubAgentMonitorPanel同步加校验 - 修复设置导入自动执行任意命令:导入的 MCP 服务器强制
autoConnect: false,并校验 SSE/HTTP 传输 URL 仅允许 http/https - 修复代理链路 TLS 证书校验全关:默认
rejectUnauthorized: true,仅显式设置GRAYCODE_ALLOW_INSECURE_TLS=1才放行自签名证书 - 修复 Gemini 模型列表 API Key 出现在 URL query:密钥统一走
x-goog-api-key头传输 - 修复 MCP 客户端响应缓冲无上限(内存 DoS):
StdioClient/HttpClient缓冲上限 16MB,超限断开 - 修复深合并原型污染:
SettingsManager/configs/base.ts深合并跳过__proto__/constructor/prototype键;toggleSkills拒绝危险技能名 - 修复自定义 Header CRLF 注入/保留头覆盖:header 键校验
/^[a-zA-Z0-9-]+$/并禁止覆盖 Host/Content-Length/Transfer-Encoding 等保留头 - 修复 ReDoS 防护可绕过:
isRegexPotentiallyCatastrophic新增重叠分支交替检测((a|aa)+类)与贪婪无锚前缀检测,正则长度阈值收紧到 200 - 修复 realPath 缓存陈旧导致符号链接逃逸:缓存按最近存在祖先 mtime 失效,新建符号链接后 containment 判定立即重新解析
- Electron 桌面版安全基线:开启
contextIsolation+sandbox,preload 改用contextBridge白名单暴露;graycode:native/renderer-to-backendIPC 校验发送方为主窗口主框架;shell:openExternal仅允许 http/https/mailto,shell:openPath/showInFolder拒绝可执行扩展名;自定义协议不再bypassCSP,生产 index.html 注入严格 CSP;外链恢复为系统浏览器打开
Fixed
- 修复 UI 对比度异常(桌面版 light 主题从未生效):
ui.theme设置此前无任何代码消费,theme.css的 light 变量块是死代码且大量变量缺失;现在 App.vue 按ui.theme(light/dark/auto)维护 body 主题 class 并监听系统主题变化,light 块补全 60+ 变量(checkbox/hoverWidget/icon/ansi/placeholder/hint 等) - 修复 Mermaid 图表浅色主题下白字白底:移除强制
#ffffff,改随--vscode-foreground,按主题配黑白描边;isDark检测补充桌面版主题 class - 修复浅色主题下多组件硬编码色对比度不足:音频占位图渐变、TODO 状态徽章、危险按钮、行号徽章、Diff 面板、工具卡按钮边框、token 环形进度、overlay.js toast 等 12 处改为
--vscode-*变量 - 修复语法高亮退化为单色:highlight.js 改走
lib/core+ 常用语言子集(主 bundle 减约 900KB),并补充跟随主题的.hljs-*配色 - 修复 ToolMessage 自动确认计时器泄漏:全部组件卸载后停止倒计时,用户不可见时不再静默自动接受 diff
- 修复 diff 审阅破坏用户未保存编辑:创建/展示 diff 前检查目标文档
isDirty并中止;磁盘内容被外部修改时不再强制覆盖,返回明确错误 - 修复 read_file 批量读取无上限:上限 20 个文件 / 50MB 总预算
- 修复 list_files 可枚举工作区外目录:纳入与 read_file 一致的 deny/ask/allow 策略,默认忽略 node_modules 等大目录
- 修复 execute_command 绕过 Shell 启用限制:shell 类型必须存在于配置且启用
- 修复流式路径重试次数未钳制:
retryCount钳制 [0,20](与非流式一致) - 清理测试残留:移除
electron-app/data/中 3 个 smoke test 对话与release/win-unpacked/data/全部运行时数据,dist:*打包脚本先清理release/防止测试数据随发布包分发 - 移除 limcode 品牌残留:设置导出默认文件名改为
graycode-settings.json、依赖默认安装目录改~/.graycode(旧~/.limcode已装依赖时兼容沿用)、Anthropic user_id 前缀加兼容性说明
Changed
electron-app/package.json锁定electron ^43.2.0(原latest不可复现)- Vite dev server CORS 从
*收窄为 localhost/vscode-webview 来源 .vscodeignore排除AUDIT_REMEDIATION.md/.github/;.gitignore补充密钥类文件模式- MCP 工具名编码统一走
encodeMcpToolNamecodec(消除手拼与旧单下划线双规范)
[1.4.0] - 2026-08-04
Fixed
- 修复存在最近对话栏时无法发送消息:渠道只配置
models列表而未选择model(model为空)时,前端发送按钮因currentModel为空被禁用;ConfigManager创建/更新/读取三路径统一回退models[0](读取路径只作用于副本、更新路径自我修复历史坏数据),前端loadCurrentConfig与输入区同步兜底,新增 6 个后端回归用例 - 桌面版便携式多实例:所有数据默认写入应用目录下
data/(不写 AppData/Program Files),复制应用目录即得互不影响实例,--user-data-dir可显式覆盖(详见electron-app/CHANGELOG.md)
Added
- 桌面版变更查看面板(内嵌 GitHub 风格):全屏 Diff 模态框改为主窗口右侧内嵌抽屉(非独立窗口),
vscode.diff拦截 →host.openDiffPreview命令驱动打开,左侧文件列表(状态 + ±统计)与右侧统一 diff(hunk 头/双行号/增删着色),单文件与全部接受/拒绝、删除警戒提示、diff.statusChanged状态同步;accept/reject 复用同一协议(详见electron-app/CHANGELOG.md) - 行级 diff 计算抽取为共享工具
frontend/src/utils/diffLines.ts(LCS 匹配 + hunk 分组 + 统计,超大文件 DP 保护),write_file 工具卡删除重复实现并复用,新增 12 个 Vitest 用例 - 对话重 roll 树状分叉(DeepSeek 风格):重新生成 AI 回答不再破坏性覆盖——截断前把当前回答及后续尾部保存为版本(每会话上限 10 个,全等去重,随删除对话清理);AI 消息上出现 v1/v2/v3 版本切换器(chips + 前后箭头),随时切回旧版本,切换前自动保存当前尾部(不丢数据),切换后继续聊天基于所选分支;版本保存失败静默降级不阻塞重roll;
conversation.saveTailVersion/conversation.getTailVersions/conversation.restoreTailVersion三个 IPC + 6 个后端回归用例 - 历史记录读取性能优化:ConversationManager 新增历史 LRU(24 会话)与元数据 LRU(256)缓存,写路径统一失效/回填;
getMessagesPaged缓存命中直接从内存快照切片(免分段存储磁盘解析),移除逐条 JSON 深拷贝;getMetadata缓存命中跳过磁盘完整性检查(两次 fs → O(1));分段历史并行读取(Promise.all 保持段序,单段失败不中断);history_search新增getHistoryRef免深拷贝供只读调用方
Fixed
- 修复 unifiedDiff hunk 边界误判:hunk 末尾的
--- x/+++ y内容对 + 下一行@@被当作下一个文件头而中断,导致内容丢失;新增isFileHeaderPair()按「路径形」消歧(-- old item这类内容行不再中断 hunk),apply_diff的 loose 解析同步修复避免同样丢行 - 修复
insert_code幻影尾行:文件以\n结尾时split('\n')产生的尾部空串让末尾追加产生多余空行;新增hasPhantomTailLine()判定并导出insertAtLine(插入索引钳制到幻影行之前)
Changed
- 工具调用格式选项移除「(推荐)」标记:JSON 边界标记不再标注为推荐项(原生 Function Calling 已是主流选择),渠道设置下拉与提示文案的中/英/日三语同步调整
[1.3.2] - 2026-08-04
Changed
- 存档点创建/恢复主流程切换到新架构:创建改用
CheckpointSnapshotBuilder(多根工作区扫描、强制排除存档目录自身、流式哈希 + 有界并发、stat 复用),恢复改用CheckpointRestoreEngine(增量链文件索引 O(1) 查询、scoped 路径安全解析、失败清单区分 missing_in_chain / hash_mismatch / copy_failed / delete_failed);新存档记录工作区身份(workspaceRoots/workspaceFingerprint),恢复前校验当前工作区,跨项目恢复被明确拒绝;新存档备份目录改用 scoped 布局(cp_xxx/ws_xxx/relative),多根工作区同名文件不再互相覆盖;旧格式存档(相对路径键 + 旧布局)单根恢复保持兼容,多根下明确拒绝而非静默错恢复;存档创建/恢复进入工作区级互斥锁(等待进行中的写工具退出并阻止新写入),恢复失败路径转相对路径展示 - 用量统计性能再优化:统计读取元数据改为轻量路径(只读
{id}.meta.json,不再走getMetadata的历史完整性检查——此前每次统计都会为每个对话额外加载一次历史,索引优化的收益被抵消大半);新增对话目录监听(fs.watchrecursive)+ 内存明细缓存——任何历史/元数据/索引文件写入都会把对应对话标记为 dirty,统计只重读 dirty 对话并回填缓存,其余对话直接重放内存明细(零 stat、零读文件),日常统计从几千次跨进程文件调用降到毫秒级;统计自身重建索引写入{id}.usage.json会触发一次自伤标记,下一轮重读小索引文件后自然恢复,不会无限循环;扩展 dispose 时释放监听,非文件存储(测试/内存适配器)自动退化全量扫描;新增缓存命中跳过读取 / dirty 重读回填 / 已删对话清理 / 缓存时间筛选与 watcher 文件名解析测试 - 提示词设置页排版重排:动态上下文保留策略区块从全局固定位置移入对应的模板模式内——预设条目模式下显示在条目编辑区下方,传统模板模式下内联显示在动态模板文本框下方,选项归属不再让人困惑;新增「可用变量参考」可收缩面板(默认收起,静态变量组 / 动态变量组分组展示,chevron 展开收起),长变量列表不再永久占据设置页空间
- 提示词模式栏新增保存按钮(绿色保存图标,保存中切换为 loading 动画),与底部原保存按钮并存;导入 / 导出按钮从 codicon 通用图标改为成对的自定义 SVG 图标(方向相反的导出/导入箭头),视觉上明确为一对操作
- 提示词页保存 / 导出 / 导入反馈统一为浮窗 toast(成功 / 失败着色,2.5 秒自动消失,Transition 动画),移除底部行内文本提示(saveMessage)
- 存档点文件哈希改为流式读取(
CheckpointManager.getFileHash/computeFileHashes),不再把大文件整体readFile进内存,哈希结果不变 - 默认启用存档的写工具列表补齐:新增
insert_code、delete_code、search_in_files(replace 模式)、图像处理(remove_background/crop_image/resize_image/rotate_image)与文档类(create_plan/update_plan/create_design/update_design/create_progress/update_progress/record_progress_milestone/create_review/record_review_milestone/finalize_review/reopen_review)默认在执行前/后创建存档;search_in_files纯 search 模式(非 replace)不再创建全工作区存档 - 恢复检查点前主动取消该对话的流式请求与关联的活跃 SubAgent,防止恢复后迟到 chunk 污染历史、SubAgent 继续写文件与恢复结果冲突
- 存档排除功能上线:
CheckpointIgnoreResolver升级为四层排除模型——强制排除(.git/node_modules/ 扩展存储根绝对路径,!不可否定)→ 默认排除类别(8 类,设置页可分别开关,可被!重新纳入)→ 嵌套.gitignore(anchored + 否定 + 目录作用域)→ 用户自定义模式(独立最终求值阶段,最后生效);shouldIgnore返回{ignored, reason, rule, source},快照构建输出完整excluded清单(含命中规则文本)与排除统计;单文件大小上限默认 50 MiB(0 = 不限制),超限文件记录reason: 'size'不静默消失;存档记录与 manifest 保存排除规则快照ignoreSnapshot与excludedCount/excludedBytes,恢复时对比快照规则与当前规则输出excludedNote(含rulesChanged),且恢复过滤严格按当前规则(不因旧规则宽而覆盖当前明确忽略的文件) - 存档排除设置与预览:
CheckpointConfig.exclusion(enabledProfiles 全开 / maxFileSizeBytes 50MiB / customPatterns,兼容旧customIgnorePatterns合并);设置页新增默认类别开关、大小上限输入、自定义模式编辑器与「预览排除结果」按钮(按类别聚合展示、samples 上限 50、命中 reason/rule/source、被排除目录有界遍历 2000 项且complete=false标记);新增checkpoint.previewExclusions/checkpoint.getExclusionProfileshandler;配置校验拒绝空模式、绝对路径(盘符/UNC)、纯!、..越界、换行注入、未知类别 id 与非有限数值 - 排除语义细节:win32 下强制排除绝对路径比较统一小写归一(防
C:\Projvsc:\proj大小写漏排);「重新纳入目录类别下文件需同时否定目录本身(如!data/ + !data/keep.txt)」在设置页给出提示;自定义模式不再被嵌套.gitignore覆盖(见 Fixed) - 每类别排除模式可编辑(用户需求):设置页每个默认排除类别新增「编辑模式」按钮,可覆盖该类别的默认模式清单(每行一个 gitignore 模式,清空保存 = 恢复默认清单);配置新增
profilePatterns(profileId -> 模式清单),collectEnabledProfilePatterns/ resolver 按覆盖优先解析,并随规则快照写入 manifest(恢复说明口径一致);保存校验复用规则(未知类别 id / 非字符串数组 / 非法模式均拒绝);新增覆盖/回退/快照深拷贝测试 3 用例
Fixed
- 存档恢复边界显式化:只删除目标快照
fileHashes中记录过的路径(快照语义),快照后新建、快照时被忽略/未备份(复制失败、大小超限、不可读)的文件恢复时不会被静默删除;恢复/创建期间与写工具互斥,避免快照与文件写入竞态 - 修复批量删除增量链断链:旧实现只检查「被保留检查点直接引用」一层,链 A→B→C 删除 {A,B} 时 A 被删而 B 保留,B 恢复时断链;现在从所有保留节点向前遍历完整祖先链,被直接或间接依赖的祖先全部强制保留并返回 rejectedIds
- 存档删除/合并操作接入工作区级互斥锁:删除、按索引删除、批量删除与创建/恢复互斥;
CheckpointOperationLock支持同 owner 相同工作区集合的可重入(引用计数),create 锁内清理旧存档(cleanupOldCheckpoints → deleteCheckpoint)不再嵌套等待自己而死锁 - 修复回档并重试 / 回档并删除时后端删除失败仍继续执行:前端
deleteMessage返回失败或抛错时中止后续重试/流程并展示明确错误,不再出现「前端已截断而后端历史残留」的静默不一致;后端各删除路径的磁盘删除失败不再完全静默,记录 warn 便于排查(元数据已正确移除,残留目录为孤儿目录不影响正确性) - 恢复结果新增未备份文件提示:
restoreCheckpoint返回unbackedPaths(快照时大小超限/不可读/复制失败的文件,恢复时受保护不会被删除),前端恢复确认后展示失败/部分失败/未备份文件清单;设置页批量删除展示被依赖保留与删除失败的数量 - 新增恢复预览确认流程:所有恢复入口(普通恢复 / 回档并重试 / 回档并删除 / 回档并编辑)先调用
checkpoint.previewRestore计算恢复计划(将恢复/删除/跳过数量 + 待删除文件清单),确认框展示清单后才执行真正恢复;待删除文件区分「快照记录过」(快照白名单)与「快照后新建」(默认保留,用户确认后一并删除,实现「撤销工具新建文件」语义);RestoreEngine提取纯计算函数computeRestorePlan,预览清单与实际执行的删除严格一致;restoreCheckpoint新增deleteUntrackedFiles选项,未确认时保持原有保护语义不删除任何快照后新建文件 - 恢复确认流程安全加固:
restoreAndRetry/restoreAndDelete/restoreAndEdit的「删除快照后新建文件」改为调用方(确认框)显式传参确认,默认 false——绕过确认框的调用不会静默删除文件;回档三连中deleteMessage失败时不再只提示,而是重新加载历史拉回前端窗口与后端一致;恢复确认框取消时清理暂存的预览动作状态;预览期间恢复按钮显示 loading 并禁用 - 存档维护改进:
pruneMissingBackupCheckpointRecords顺带清理孤儿备份目录(磁盘存在但无任何记录引用,如删除失败/崩溃残留,仅处理cp_*格式目录);设置页存档详情展示「N 个文件未备份」(悬停显示路径清单,去除工作区作用域前缀);CheckpointOperationLock可重入放宽为「请求集合是已持有集合的子集即放行」,嵌套调用更不易死锁 - 深度审查修复:快照强制排除范围从存档目录扩大为整个扩展存储根(自定义数据目录位于工作区内时,memory/conversations 等扩展数据不再进入存档);恢复时「删除多余空目录」纳入
deleteUntrackedFiles确认控制(快照后新建的空目录默认保留,快照语义,预览清单一并展示);legacy 存档预览返回legacy标记,前端展示「恢复以备份内容为准」避免误判「无变更」;恢复确认框打开期间恢复按钮禁用,防止重复点击覆盖确认内容 - 修复增量链恢复索引错误:增量节点磁盘上只保存
changes里的文件,但恢复索引此前把该节点完整fileHashes都指向其目录,导致未变化文件恢复时报missing_in_chain;现在按changes限定节点备份边界,未变化文件从更早节点(base)恢复 - 修复存档路径安全缺口:备份源目录(
backupDir)来自存档元数据,损坏数据可含../绝对路径,现在恢复时校验备份源必须位于存档根目录内(越界视为链上缺失);恢复目标路径全程做符号链接/junction 检查(resolveSafePathInsideRoot),链接不能绕过工作区边界 - 修复旧版存档(无
fileHashes)恢复安全隐患:多根工作区下明确拒绝(旧记录无工作区身份,无法确定文件归属);单根恢复以备份目录实际内容为目标、绝不删除当前工作区任何文件(旧记录没有“快照时可见”清单),替代此前“删除备份里没有的所有文件”的危险行为 - 修复同一对话切换工作区后增量链错乱:新存档识别到工作区指纹不一致时从新的完整备份开始(断开旧链),不再跨工作区串接增量
- 部分恢复失败时返回
error摘要(前 5 条路径+原因,超出计数),前端restoreCheckpoint类型同步补充failures字段 - 修复流式报错后重试残留半截回答:流式过程中后端报错时,后端不会持久化半截 assistant 消息,但前端窗口会保留有内容的半截消息,点击错误通知上的「重试」(
retryAfterError)之前不会清理,导致重试后窗口/历史出现半截回答残留,且与后端历史错位;现在handleError会记录失败半截消息 ID,retryAfterError重试前回滚(删除窗口消息 + 清理检查点 + 防御性同步删除后端),错误条「关闭」按钮与发送新消息也会一并清理失败残留,工具响应后的「继续对话」语义不受影响(不删除正常历史);新增回归测试 12 用例(frontendstreamErrorRetry.test.ts) - 修复动态上下文策略选项的误导性括号标注:单份模式选项原先带有「(当前策略)」(zh-CN)或「(当前行为)」(en/ja)注释,而该选项与保留模式是并列可切换的,标注「当前」会让用户在切换后看到错误的归属语义;现在移除括号注释,三语统一为中性文案「单份动态上下文 / Single dynamic context / 単一の動的コンテキスト」
- 修复动态上下文策略警告文案硬编码英文:设置页选中保留模式时提示「preserve 会把旧回合的动态快照固定插回原位…」,而选项在 UI 上显示的是中文「保留旧动态上下文原位」,用户无法把二者对应;现在句首直接使用选项的中文名称,不再出现英文标识
- 修复空提示词保存后回退默认模板:
resolvedMode?.template || promptConfig?.template(PromptManager.ts)与mode?.template || ...(SettingsManager.getSystemPromptTemplate)的空字符串回退导致 legacy 模式显式保存的空模板在运行时被全局模板覆盖,用户无法真正清空模板;两处改为??(nullish coalescing),空字符串原样保留;前端loadModeConfig同步用typeof === 'string'判断而非||兜底,空模板不再被 DEFAULT_TEMPLATE 顶替,新增回归测试锁定该行为 - 修复提示词导出流程不可控:前端 Blob 下载在 webview 环境保存位置与文件名不受用户控制,改为通过新增的
exportPromptModeswebview handler 调用vscode.window.showSaveDialog让用户选择保存位置,确认后才写文件;取消保存对话框时不写文件并返回{ success: false, cancelled: true },成功后才报告成功;导出成功 / 取消 / 失败均有明确反馈,不再出现「已导出但不知道存到哪」 - 修复恢复路径未接入四层排除模型:恢复时的目标状态过滤与当前工作区状态收集此前只走
.gitignore+ 旧customIgnorePatterns两层,恢复可能把文件写回当前明确排除的路径(dist/、data/、超过大小上限的文件)或删除当前应排除的文件;现在createIgnoreResolver统一构造完整四层规则(强制排除含扩展存储根、默认类别、嵌套.gitignore、新旧自定义模式合并),filterRestoreTargetScoped/collectCurrentWorkspaceState与快照构建同一口径,恢复不再触碰当前明确排除的路径 - 修复空增量节点恢复必失败:增量链索引构建时
changes为空数组的节点(工具执行但无文件变化的 before/after 存档)被当作完整节点,其全部哈希被指到自己的空备份目录并覆盖更早节点,恢复任何漂移文件都报missing_in_chain;现在区分「未提供 changes(完整节点)」与「空数组(空增量节点,不索引任何文件)」,空增量后的恢复由更早节点提供文件 - 修复跨格式合并断链:容量清理把 legacy 布局(
cp_xxx/relative)被清理节点并入新格式后继时,文件被原样复制到后继根目录且不写进 manifest,恢复时missing_in_chain;现在按后继 scoped 布局重写路径(ws_xxx/前缀)再复制,并把合并文件的 scoped 键并入后继 manifest.files(hash 取自被删节点),legacy→新格式过渡期清理不再破坏可恢复性 - 修复存档取消竞态与锁等待裸异常:取消发生在等待文件写锁期间时,锁管理器抛普通 Error 从
runExclusive漏出并冒泡到工具循环中断整轮执行;现在 create/restore/deleteAll/deleteBatch 外层捕获锁取消错误转为取消结果;取消发生在复制完成、元数据落盘之前时检查点仍会被保存且进度被done覆盖——现在写 manifest 与写会话元数据前检查throwIfAborted,进度终态改为signal.aborted ? 'cancelled' : 'done' - 修复排除规则对比漏类别开关:
rulesChanged只比较大小上限与自定义模式,设置页仅开关默认类别(如关闭 logs)时恢复说明误报「规则未变化」;现在同时比较键排序后的enabledProfiles与规则版本号 - 修复自定义排除模式被嵌套
.gitignore双向覆盖:自定义模式与默认类别原先注入根作用域 matcher,嵌套.gitignore可否定自定义层的!规则或反过来;现在自定义模式从作用域链拆出,作为所有作用域求值之后的独立最终阶段(强制排除仍不可覆盖),「设置页规则最后生效」与计划语义一致 - 修复排除预览
complete谎报:主扫描遇到不可读目录时静默跳过且complete仍为 true;现在不可读目录产出unreadable排除条目并置complete=false计入统计 - 修复恢复说明与未备份提示回归:
rulesChanged与excludedNote补全后恢复说明准确;存档摘要(CheckpointSummary)化后设置页「N 个文件未备份」提示丢失——摘要补齐unbackedPaths相关字段,前端悬停提示恢复 - 修复 append-only 崩溃恢复后计数永久不一致:尾段 rename 成功但 index 写失败/崩溃时残留行会在下次追加被并入段计数,
index.totalMessages与各段 count 永久相差、全量读与分页读口径不一;现在尾段读取后先按 index 提交点截断(slice(0, count))再拼接新内容,at-most-once 语义下重试不重复,崩溃残留不会泄漏 - 修复元数据文件损坏导致列表 UNKNOWN_ERROR(真实故障):
saveMetadata原为非原子writeFile,写入中途崩溃/断电即截断{id}.meta.json(如 24MB 大文件),读取时parse_error抛到前端阻塞对话列表;现在元数据写入改为临时文件 + rename 原子替换(index 式提交点),getMetadata遇parse_error时把损坏文件改名备份为.corrupt-*(只保留一份)并从历史时间戳重建 fallback 元数据返回,不再向上抛错(存档记录列表随损坏文件丢失属降级代价,磁盘cp_*备份目录不受影响且不会被自动清理) - 修复完整性检查两类误判:legacy 单文件历史只
exists不解析导致损坏 JSON 报ok——现在至少做一次JSON.parse探测;segmented 分支 index 完好但段文件缺失时误报ok——现在对每个段stat存在性(不解析内容,保持只读结构目标),任一缺失即readable=false - 修复段缓存元素引用污染:
loadSegmentedHistory的slice只复制数组、元素与缓存共享引用,ContextTrimService对tokenCountByChannel的原地赋值会污染缓存;现在加载路径返回前对元素浅拷贝,缓存只读边界落实;缓存键纳入段文件 mtime(revision::m{mtime}),外部进程改写段内容后命中前stat比对自动失效 - 修复用量与元数据一致性:
updateSummary不再无条件写前端传来的messageCount——超过历史实际条数时按index.totalMessages钳制,前端 IPC 失败时不同步本地计数;append 遇「index 存在但尾段缺失/损坏」时不再永久失败,回退全量重写自愈 - 修复前端历史窗口与缓存问题:backfill 把 IPC 失败误当「已到历史开头」置
windowStartIndex=0导致更早消息无法上拉——现在错误与空页区分,错误时放弃合并保留原窗口;loadMoreConversations游标按实际返回数量前进,批量结果缺失时不再跳过未加载对话;消息中间位置同长度替换(迟到 cancelled chunk 清理)会命中陈旧可见缓存——replaceMessageAt非尾部替换时清缓存;addBatch直通 append 可能绕过 functionResponse 去重安全网——契约注释明确仅限纯追加 user/model 并对 functionResponse 显式拒绝 - 修复子agent 续跑丢失 provider 缓存(用户反馈):子agent 每次执行分配新 runId 作为请求
conversationId,DeepSeek/Anthropic 的user_id按它哈希,continueFromRunId续跑时新 runId 落入新缓存域、前缀缓存必 miss;现在续跑时conversationId直接沿用旧 run 的 runId(request.continueFromRunId || runId),user_id哈希输入与旧 run 完全一致、缓存域天然相同——模型调用工具只需传continueFromRunId,系统自动注入稳定缓存域,无需任何额外字段(同时移除临时引入的GenerateRequest.cacheDomainId机制,formatter 回退为 conversationId 单一来源) - 修复子agent 反复调用 todo 工具报「无权限」(用户反馈):
todo_write/todo_update依赖主会话ToolContext.conversationId,子agent 执行路径不注入该值,声明了也必然失败并浪费迭代——现在从子agent 工具声明与执行期允许列表统一排除 todo 工具(主会话不受影响) - 修复子agent 窗口被尾部校准清空(用户反馈):SubAgentMonitor 收到工具/内容事件时对聚焦 run 拉取尾部 20 条并整体替换窗口,用户「加载更早消息」prepend 的历史被清空;现在尾部校准改为保留早于传入
startIndex的前缀合并(replaceRunContentWindowPreservingPrefix),删除/重试的权威校准路径仍走纯替换 - 修复子agent 写文件冲突提示不友好(用户反馈):冲突消息不再笼统「不要重试」,改为明确持有者身份(
agent "X"/ 主会话 / 存档操作)与三步指引(不循环重试 → 先做其他工作、持有者释放后重试 → 持续冲突在最终回复上报主会话协调),presets.ts指引语义同步 - 修复子agent 运行时间显示本地绝对时间戳(用户反馈):SubAgentMonitor 的「运行中 · 15:16:46」改为相对耗时(
42s/2m30s/1h5m,活跃态显示已运行时长、终态显示总耗时),新增 1s ticker 仅在有活跃 run 时运行
Added
- 新增
exportPromptModeswebview handler(webview/handlers/SettingsHandlers.ts)与回归测试backend/__tests__/webview/promptModeExport.test.ts(取消对话框不写文件 / 选路径并写文件成功后才响应,2 用例);PromptManager.promptEntries.test.ts新增「显式空模板不回退全局模板」用例;vscode mock 补充showSaveDialog/showOpenDialog - 新增存档快照构建器
CheckpointSnapshotBuilder(多根工作区扫描、强制排除绝对路径防存档自备份、单文件大小上限记录排除原因、流式哈希、有界并发)与单元测试 7 用例 - 新增存档恢复引擎
CheckpointRestoreEngine(增量链文件索引 O(1) 查询、scoped 路径安全解析兼容旧相对路径存档、哈希校验、失败清单区分 missing_in_chain / hash_mismatch / copy_failed / delete_failed)与单元测试 6 用例 - 新增工作区身份与路径安全模块
CheckpointWorkspace(工作区根 ID / 指纹 / 快照校验 / 安全相对路径与符号链接边界)与存档操作互斥模块CheckpointOperationLock(工作区级 FIFO 互斥 + 全局文件写锁等待),配套单元测试 26 用例 - 新增存档工作区边界集成测试
CheckpointManagerWorkspace.test.ts6 用例(多根创建/恢复、跨项目恢复拒绝、存档目录位于工作区内时自排除、多根下旧存档明确拒绝、unbacked 文件恢复保护) - 新增增量链/路径安全回归测试 6 用例:增量节点未变化文件从 base 恢复(
changes边界)、backupDir越界备份源忽略、跨工作区创建新存档断链、无fileHashes旧存档多根拒绝、旧存档恢复不删除备份外文件、部分失败返回错误摘要 - 新增测试:
CheckpointOperationLock可重入 3 用例(同 owner 嵌套不死锁、不同 owner 仍串行、内层释放不提前释放外层锁)、批量删除祖先闭包 1 用例(保留尾节点保护整条基链)、恢复返回unbackedPaths且未备份文件不受删除 1 用例 - 新增测试:
computeRestorePlan白名单/受保护/快照后新建文件过滤 1 用例、previewRestore预览无副作用 + 未确认不删快照后新建文件 + 确认后删除 1 用例 - 新增测试:锁子集可重入 1 用例、孤儿备份目录清理 1 用例、前端
checkpointActions.test.ts9 用例(previewRestore 透传/异常、restoreCheckpoint 确认标记、restoreAndRetry 删除失败中止 + 重载历史、成功路径、restoreAndDelete 失败重载历史) - 新增测试:扩展存储整根排除(memory 数据不进存档)增强 1 用例、快照后空目录默认保留 + 确认后清理 1 用例
- 设置页存储路径区域新增「打开目录」按钮,复用既有
storagePath.openInExplorerwebview handler,一键在系统文件管理器中打开当前生效的存储目录 - 新增 checkpoint 模块共享类型契约
backend/modules/checkpoint/types.ts(CheckpointExcludeReason/CheckpointExcludedEntry/CheckpointExclusionSummary/CheckpointExclusionConfig/CheckpointIgnoreSnapshot/CheckpointManifest/CheckpointSummary/CheckpointExclusionPreviewResult/CheckpointOperationProgress),作为排除与 manifest 并行改造的接口锚点 - 新增默认排除类别模块
CheckpointExclusionProfiles.ts:8 个类别(logs / aiModels / datasets / caches / pythonVenvs / buildArtifacts / largeMedia / archives)严格按计划清单(不含*.bin/*.dat/*.model、env/、png/jpg/svg),导出resolveEnabledProfiles/collectEnabledProfilePatterns/buildIgnoreSnapshot/validateCustomExclusionPatterns - 新增 manifest 仓储
CheckpointManifestRepository.ts:checkpoints/cp_xxx/manifest.json原子写入(tmp+rename)、按 ID 加载(内存缓存)、旧记录迁移(从CheckpointRecord.fileHashes/fileStats/emptyDirs/changes生成并落盘,幂等)、损坏回退、写入失败清理 tmp;新格式记录无文件哈希时迁移产物为空则返回 null 并显式报「存档数据缺失」而非假成功 - 新增
CheckpointQueryService.ts(getCheckpoints / getAllConversationsWithCheckpoints / getDirectorySize / pruneMissingBackupCheckpointRecords / 孤儿目录清理)与CheckpointRetentionService.ts(cleanupOldCheckpoints / mergeCheckpointIntoSuccessor),CheckpointManager从 2000+ 行拆分为协调层 + 三服务 - 新增共享有界并发池
checkpointConcurrency.ts(runBounded,首错停止取新任务并正确传播),创建复制、恢复/删除循环、目录大小统计均改为有界并发(默认 8) - 会话元数据精简:完整
fileHashes/fileStats从会话元数据迁到独立 manifest,元数据只保留CheckpointSummary(fileCount / backupBytes / excludedCount / manifestVersion 等);getCheckpoints/getAllConversationsWithCheckpoints只下发摘要,旧存档缺字段时按需懒扫描并写回缓存;磁盘占用创建时直接记录(backupBytes),设置页不再重复递归扫描 - 流式路径下发摘要化:工具执行期间的 checkpoints chunk 经
CheckpointService.toStreamSummary()剥离fileHashes/fileStats,loadConversationForView与流式两条路径都不再向 webview 传全量哈希映射(补全) - 存档操作接入进度与取消:Manager 维护进行中操作状态(阶段 / 已处理 / 总数,AbortController),create / restore / deleteAll / deleteBatch 全接入;RestoreEngine 支持
signal+onProgress;新增checkpoint.getOperationProgress/checkpoint.cancelOperationhandler 与前端轮询 + 取消按钮 - 只读工具批次不再创建存档:
tool_batch判定改为基于真实工具名集合toolNames.some(name => configuredTools.includes(name)),read_file + search_in_files(search)等纯只读批次不建存档,search_in_files仅 replace 模式计入 - 历史追加改为 append-only 尾段写入:普通追加只写最后一段(不足 200 条)或新建下一段 + 更新 index,不再全量重写所有段;写入顺序「临时尾段 → 原子替换 → 临时 index → 原子替换」,index 是提交点;删除 / 编辑 / 回档 / 分支切换仍走全量重写;
TranscriptRepository新增appendContents直通 append,addContent/addBatch纯追加路径不再读全量(functionResponse 保留 mutate 去重安全网) - 新增段级 LRU 缓存
history/HistorySegmentCache.ts:键conversationId + segmentFile + revision(+mtime),默认 32 段,写后 / 删除会话失效;多段读取改有界并发(并发 4) - 同一工具迭代内复用历史快照:
getHistoryForAPIFrom(contents)/getStatsFrom(contents)支持基于已加载历史直接格式化,ContextTrimService不再每次重新读全量历史 - 元数据写入合并:新增
conversation.updateSummary({conversationId, messageCount, preview})一次读写完成,前端流式结束后由 3 次setCustomMetadata改为 1 次;updatedAt由历史提交统一维护 - 对话列表批量元数据:新增
conversation.getConversationMetadataBatch(16 并发、每页 ≤200),前端loadMoreConversations一次 IPC 拉一页摘要,消除逐对话 IPC - 用量索引增量维护:新增
UsageIndexStore.appendUsage/appendUsageMessages,普通追加助手消息只追加条目,删除 / 编辑 / 回档 / 索引损坏才全量重建;getMetadata完整性检查只读history.index.json结构,不再解析末段历史 - 子agent 用量归集(用户需求):子agent 每轮 generate 的
usageMetadata以source: 'subagent'条目追加到发起它的主会话用量索引(appendUsageIndexMessages),用量统计 totals / byConversation / byModel / byDay 自动包含子agent 消耗,ConversationUsage新增subagentTokens细分;索引 stale 全量重建时保留已有 subagent 条目;无主会话归属时跳过归集 - 前端渲染优化:可见消息窗口增量缓存(同引用 + 长度 + 首尾指纹 O(1) 校验,流式尾替换 O(1),结构变更回退全量过滤);对话加载先渲染最后一页再异步补拉更早历史(
backfillInitialVisibleWindow,与用户上拉 / 发送 / 流式并发时放弃合并) - 元数据写入原子化:
saveMetadata改为临时文件 + rename 原子替换,任何写路径不再可能留下截断的 meta.json - 子agent 设置新增「默认迭代次数」(用户需求):
SubAgentsConfig.defaultMaxIterations(默认 80,上限 1000),executor 取值per-agent maxIterations > 全局默认 > 50,设置页全局配置区新增输入框(1~1000),subagents.list返回该值
[1.3.1-1] - 2026-08-02
Fixed
- 修复存储路径迁移目录套娃(无限递归):
copyDirectory复制时若目标位于源目录内部会无限递归自我复制(mkdir 目标后 readdir 源会看到刚创建的子目录,一次误选子路径可产生数千层嵌套),现检测到目标在源内部时跳过;路径重叠判断改用realpath,junction/符号链接无法绕过防套娃 - 修复存储路径迁移数据安全:源/目标互相包含时先复制到临时目录中转,避免清理旧目录时删除新数据;复制失败终止迁移并回滚,源数据与配置保持不变;失败时恢复原
customDataPath/状态,不再错误切回默认路径;路径验证改用随机临时目录,不再覆盖用户.limcode-test文件 - 修复前端误读
config.customPath(后端字段为customDataPath)导致重置按钮永远禁用;应用/重置按钮增加明确提示(空路径、已是默认路径时不再静默无反应) - 修复设置页描述单行截断:工具名与描述改用 i18n(47 个工具全覆盖),描述样式改自动换行(pre-wrap),不再截断
Changed
- 工具调用格式选项移除「(推荐)」标记:JSON 边界标记不再标注为推荐项(原生 Function Calling 已是主流选择),渠道设置下拉与提示文案的中/英/日三语同步调整
- 设置页 i18n 补全:工具设置/自动执行/存档点/子代理/模型管理的分类分组全量三语翻译(记忆/审查/进度/技能/设计/通知/代理等 16 类),消除重复「其他」分组;Prompt 设置补
modules.MEMORY(记忆系统)三语;记忆设置 Raw Memory Entries 等硬编码英文改走 i18n - 存储路径设置 UI 改版:合并「当前存储路径/自定义路径」为单一输入框,新增 📁 文件夹选择按钮(
storagePath.selectFolder),删除冗余的迁移数据按钮;validatePath放宽——允许选择默认路径/子路径/普通非空目录(如桌面),仅拒绝已包含扩展数据子目录(conversations/checkpoints 等)的目标,防止数据混合 - 渠道设置新建配置:改为模态遮罩弹窗(点击遮罩取消),配置名称为空时红框+提示
- 更新扩展与活动栏图标:市场图标由 1024px 角色插画(1.4MB)替换为 256px 三色剪影版(73KB,深蓝圆角方底,小尺寸辨识度更好);活动栏/侧边栏图标由 VS Code 默认地球替换为角色剪影,并进一步改为纯轮廓线稿(fill=none + stroke=currentColor 随主题着色,Douglas-Peucker 路径简化 716→161 点,24px 下无锯齿)
Added
- 新增
StoragePathManager单元测试(6 项):覆盖迁移中转、失败回滚、realpath 重叠判断、路径验证临时目录等安全加固行为
[1.3.1] - 2026-08-02
Fixed
- 修复 README 与实际工程能力不一致:更新 npm 构建、Node.js 版本、工具参数、模板变量、设置导出边界、测试命令和项目目录说明
- 修复 npm 工作流残留 pnpm 调用与根锁文件过期:
vscode:prepublish、前端构建和开发脚本统一通过 npm 执行,重新生成与 GrayCode 1.3.0 当前依赖一致的package-lock.json - 修复 SubAgent 对话延续入口不可达:
subagents工具正式暴露并在前台、后台、General Worker 与自定义代理路径中透传continueFromRunId - 修复 Sub-Agent 可获得永久记忆工具:所有子代理统一排除 7 个 memory 工具,工具清单描述和执行期允许列表使用同一隔离规则
- 再次修复输入框 Ctrl+Z 撤销忽略粘贴内容:此前文字粘贴在
paste回调中preventDefault后通过execCommand('insertHTML')模拟插入,虽然单独执行命令可进入撤销栈,但没有保留 Chromium 原生insertFromPaste事务,实际 webview 中仍可能跳过粘贴内容;现在仅在本次粘贴默认动作期间把编辑器临时切换为contenteditable="plaintext-only",由 Chromium 原生完成纯文本粘贴并记录撤销项,事件结束后恢复普通编辑模式,不影响 Shift+Enter 自定义换行与上下文徽章;文件粘贴仍按附件处理,新增组件级回归测试覆盖文字与文件两条分支 - 修复用量索引文件被识别为假对话:
FileUsageIndexStore把索引写到{conversationId}.usage.json(与历史文件同级),而listConversations只排除了.meta.json,导致每个对话的.usage.json都被识别成假对话 ID(形如xxx.usage)显示在历史列表,点入报 "Metadata file is missing";现在文件识别同样排除.usage.json,只返回真实对话 ID(legacy{id}.json与 segmented{id}/目录),新增回归测试锁定该行为 - 修复 XML 工具调用解析安全:
fast-xml-parser升级到 5.10.1 后为解析器增加processEntities: false与maxNestedTags: 100,工具协议不再接受 DOCTYPE 自定义实体与超深嵌套输入;协议层额外过滤__proto__/constructor/prototype危险键名防原型污染,新增安全输入回归测试(数字字符串保持、实体不展开、深嵌套安全失败、危险键名拒绝) - 修复批量工具部分成功时 LLM 只看得到顶层错误:
serializeToolResultForLLM()错误分支不再丢弃data,data.results混合数组逐项格式化(避免 JSON 二次转义)、data.message与批量统计(successCount/failCount/totalCount)一并输出,data.output与取消标记保持原有格式;新增共享 formatter 回归测试覆盖 10 项场景 - 修复 XML 工具指南示例过时:
read_file的paths与write_file的files旧示例改为真实 schema(单文件path/ 批量files: [{ path, startLine?, endLine? }]/ 顶层path+content),XML/JSON 测试夹具同步更新为真实参数形状 - 修复
SubAgentRegistry.isEnabled()把未注册代理误判为启用:未注册代理现在返回 false - 修复注册的自定义 Sub-Agent executor 从未被调用:Registry 查询不再隐式创建并缓存默认 executor,正式工具调用路径优先使用显式注册的 executor;executor 请求新增
conversationId/conversationStore/promptModeSnapshot动态上下文并在每次调用透传 - 修复 Sub-Agent 跨对话接续泄漏:
continueFromRunId只允许接续当前主对话所属的 run,归属不一致时拒绝且错误信息不泄漏旧对话 ID 或内容 - 修复重载/内存淘汰后已持久化 run 无法接续:接续时内存快照未命中会只加载当前对话的持久化记录,恢复后仍执行归属与终态校验
- 修复全部配置代理禁用时
subagents工具被整体隐藏:ChannelManager/ToolDeclarationResolver统一使用「配置代理计数 > 0 或 General Worker 启用」的hasAvailableSubAgent()判断 - 修复 Windows 通知依赖链:移除已停更且有生产审计告警的
node-notifier,通知适配器改为 VS Code 原生showInformationMessage(操作按钮打开聊天、不阻塞工具调用),esbuild 不再复制原生包,npm audit --omit=dev归零 - 修复
.vscode/launch.json的Extension Tests指向不存在的测试入口:替换为可运行的 Jest 调试配置
Added
- 永久记忆设置新增默认开启的总开关;关闭后不再向系统提示词注入
{{$MEMORY}}内容,也不会向 AI 暴露 7 个 memory 工具,已有记忆、运行参数和自定义提示词保持不变并可继续在设置页管理,重新开启后恢复使用 read_file新增单次批量读取:保留path/startLine/endLine单文件调用,新增files: [{ path, startLine?, endLine? }],每个文本文件可独立指定行范围,结果按输入顺序汇总并保留部分失败详情;前端工具摘要与结果面板同步支持批量参数- 用量统计新增缓存维度:此前 Anthropic 的缓存写入(cache_creation_input_tokens)与缓存命中(cache_read_input_tokens)在 formatter 被合并成 cachedContentTokenCount 后明细即丢失,聚合器也从未读取该字段,统计里完全没有缓存信息;现在 usageMetadata 拆分保存 cacheCreationTokenCount / cacheReadTokenCount(Anthropic 分别映射写入与命中,OpenAI cached_tokens / Gemini cachedContentTokenCount 映射命中),流式累加器同步合并;aggregateUsageStats 总览 / 按对话 / 按模型 / 按天各维度新增缓存写入与缓存命中两个桶——缓存是 promptTokenCount 的细分(prompt 已含缓存部分),不重复计入 totalTokens;用量统计页总览卡片与明细行新增「缓存写入 / 缓存命中」展示(有值才显示),i18n 三语补齐,新增聚合与 formatter 断言测试
- 用量统计兼容旧数据缓存记录:旧版本只存缓存合并值(cachedContentTokenCount)无法拆分写入/命中,升级前的对话统计时近似全部记为缓存命中(OpenAI/Gemini 语义下该值本就是命中,Anthropic 实际以命中为主,偏差最小),避免旧对话的缓存贡献在统计中消失
- 用量统计性能优化:聚合由串行逐个读取改为限流并发(12 路);新增轻量读取接口 getMessagesRaw 绕过显示规范化与逐条深拷贝,只读统计所需的原始消息;handler 层新增进程内 5 分钟 TTL 结果缓存,短时间内重复打开统计页直接命中缓存,手动刷新(force)强制重算
- 用量统计性能优化新增消息级增量索引:全量扫描历史文件的开销随对话数增长(每次统计都要解析全部历史 JSON),现在消息落盘时同步维护每对话的用量索引({conversationId}.usage.json,只存消息级 token 明细,不存消息内容),统计时按历史文件与索引文件的 mtime 判定新鲜度——索引最新则直接聚合索引(完全不读历史文件),缺失/过期/损坏则回退读取历史并重建写回(一次性成本);任何历史写路径(编辑/删除/回滚/清空/导入/分支)都会更新历史 mtime 从而自动触发索引重建,无需逐一追踪写入口;删除对话时索引同步清理;索引写失败静默降级,不影响对话保存与统计正确性;新增索引构建/命中/重建/损坏回退/写失败降级测试
- 新增本轮安全与行为修复的回归测试:
toolResponseFormatter.test.ts(部分成功序列化)、subagentRegistry.test.ts(isEnabled 与 executor 语义)、subagentExecutorContinuation.test.ts(跨对话拒绝与持久化恢复)、windowsToastAdapter.test.ts(VS Code 原生通知适配器)
[1.3.0] - 2026-08-01
Fixed
- 修复输入框 Ctrl+Z 撤销忽略粘贴内容:contenteditable 粘贴为强制纯文本走
preventDefault+ 手动 Range 插入,操作不进浏览器原生 undo 栈,Ctrl+Z 会跳过刚粘贴的内容去撤销更早的操作(Shift+Enter 换行、插入 @路径文本同理);现在粘贴 / 换行 / 插入 @路径文本改用document.execCommand('insertText'/'insertHTML')写入原生撤销栈——一次粘贴对应一个 undo 条目可整体撤销,同时保持纯文本语义与 lim-break BR + ZWSP 的既有 DOM 结构;execCommand不可用时回退手动插入保证功能不回归,插入函数返回inputFired避免 execCommand 自动派发 input 事件后调用方重复提取节点,新增 14 个 vitest 用例 - 修复 subagents 工具后台模式缺失(计划标记完成但实际未实现):工具声明无
background参数、handler 无后台分支,前端 backgroundTaskStore / BackgroundTaskBar / backgroundStatus 整套后台基建空转;现在按已确认设计补齐——background: true时创建独立 AbortController(用户停止当前对话流不连带取消)、以background_subagent类型注册到 TaskManager、executor 启动后不 await、工具立即返回{ background: true, taskId, runId, agentName },executor settle 时注销任务并携带完整结果载荷(response/steps/runId/error),经现成 taskEvent 转发链路由前端混合回流(会话空闲立即发回执、正忙挂起补发)送达主模型 - 修复代理非 chunked 流式解码仍损坏中文:非 chunked 消费点仍逐 TCP 包
toString('utf8'),被包边界切开的 UTF-8 多字节字符固化成 U+FFFD;现在与 chunked 一致走流式TextDecoder,flush 移入非中止分支 - 修复 glob globstar
**失效:GLOBSTAR 占位符正则匹配三个转义星号而**转义后是两个,**/node_modules/**等规则永不跨目录命中;修正为匹配两个转义星号(PromptManager / fileTree 两处) - 修复 diff 预览 LCS 后缀匹配丢失:computeLCS 剥离公共后缀后从不回填,任何带公共尾部的 diff 尾部公共行被标为「删除+新增」、统计虚高;现在按原始索引回填后缀匹配(apply_diff / write_file 两处)
- 修复
deleteCheckpoint缺少基快照引用保护:updater 未检查baseCheckpointId引用,被后继检查点引用为基快照时仍删除会断增量链、恢复 100% 失败;现在被引用时返回原引用拒绝删除 - 修复 ChatViewProvider 关闭标签页后消息仍静默丢失:
onDidDispose不重置_view/webviewReady,isAlive 判定对已销毁 webview 仍返回 true,面板关闭期间 postMessage 静默丢弃;现在与 dispose() 语义对齐重置并释放主聊天 client 注册 - 修复 media 工具取消后终态恒为
completed:批处理末尾无条件unregisterTask('completed'),用户取消的任务显示为「已完成」、后台回执误报成功;现在全部任务被取消时终态为cancelled;generate_image的 failedResults 同步排除 cancelled(与其余 4 个 media 工具对齐) - 修复终端输出护栏丢弃行时无截断提示:显示上限关闭时
omittedOutputLines不计入wasTruncated,AI 看不到「输出被截断」;现在护栏丢弃同样触发截断提示 - 修复 search_in_files 高亮替换串
$特殊语义:匹配文本含美元符特殊替换序列(、$$)时String.replace` 展开特殊替换模式导致高亮内容错乱;改用替换函数 - 修复 MarkdownRenderer mermaid 残留注入面:
securityLevel: 'loose'下模型可控的图例 HTML 可经 zoomedContent 的 v-html 再次注入执行(webview CSP 含 unsafe-inline);改为'strict' - 修复 fast-tavern Python 遗漏项:
build_prompt.py实际存在(文档误判为「已移除」)且recentHistoryForWorldbook仍int()强转、浮点字符串抛 ValueError,改为int(float())+ 解析失败回退 0;convert_from_silly_tavern遗留isinstance(p, int)漏 float position,改_is_number;get_active_entries._to_recursion_limit不可解析回退 5(TS 应为 NaN→循环不执行)、负数被钳制到 0 多执行一次、-inf分支多执行一次——全部对齐 TS Math.trunc/Number 语义 - 修复 glob 通配零段语义:
**/x不匹配根级x、a/**/b不匹配a/b(**展开为.*后要求至少一个目录段);现在统一到backend/modules/prompt/glob.ts的globPatternToRegExp(PromptManager / fileTree 三处共用),**后跟分隔符时零段可选(gitignore 语义)、单星不跨目录段(fileTree gitignore 分支原先*跨/一并修正);同时去掉「斜杠展开为[/\\]字符类」的 4 反斜杠魔法——三处调用点路径均已归一化为/,模式里的/直接作字面/,「斜杠替换必须先于星号替换」的顺序耦合随之消除 - 修复 fast-tavern Python normalize_worldbooks 缺字段语义与 TS 不一致:
_to_number的 None 分支忽略 fallback 直接返回 0.0,缺probability的条目概率变 0 永不注入、缺index/order/depth的条目被保留(TS 侧分别回退 100 / 丢弃条目);现在 None 返回 fallback,新增_entry_number区分「键缺失」(→ fallback)与「显式 null」(→ 0,对齐Number(null)),补 5 个 pytest 用例 - 修复关闭活跃标签页产生孤儿快照(内存泄漏):closeTab 删快照后 switchTab 会把已关闭标签页的完整会话状态(allMessages/messageQueue 等)重新写回 sessionSnapshots 成为永不被清理的孤儿条目;现在快照仅在标签页仍存在于 openTabs 时写入,新增 3 个 vitest 用例
- CheckpointManager 测试补强:测试 mock 此前缺
updateCustomMetadata(迁移后的 7 处调用零覆盖),且并发 mock 未模拟真实串行链;现在 mock 补链式updateCustomMetadata,新增 8 个用例覆盖 saveCheckpointToConversation(含并发追加无丢失)、deleteCheckpoint(含 isReferencedBase 拒绝与磁盘目录清理)、deleteCheckpointsFromIndex(含 excludeCheckpointId 基链保留)、deleteAllCheckpoints、pruneMissingBackupCheckpointRecords、cleanupOldCheckpoints 链合并重挂
Added
- 新增 subagents 工具后台分支单元测试(
backend/__tests__/tools/subagentsTool.test.ts,8 用例):声明暴露 background 参数、后台调用立即返回 stub 且不 await、TaskManager 注册(background_subagent + 元数据)与注销载荷(response/steps/runId/error)、executor 失败/取消状态映射、父 abortSignal 已中止时后台任务仍启动(独立取消)、前台模式回归 - 新增存档点批量管理/清理:设置页「清理存档点」支持对话多选 + 全选 + 跨对话批量删除(顶部显示已选数量与磁盘占用合计);对话可展开查看内部存档点列表(阶段/工具/备份类型/文件数/磁盘占用),支持存档点多选或单个删除;后端新增
deleteCheckpointsBatch批量接口(沿用基快照引用保护,整条增量链同时选中时可一并删除,空 ID 列表 = 清空该对话),getCheckpoints支持withSize返回每条存档点磁盘占用,前端 CheckpointRecord 类型补齐与后端一致的字段
[1.2.9] - 2026-08-01
Fixed
- 修复上传 txt 等文本附件报
API_ERROR: HTTP 400: unknown variant image_url, expected text:OpenAI Chat Completions / OpenAI Responses / Anthropic 三个 formatter 把用户附件一律按图片序列化(image_url / input_image / image base64),text/plain 文件被当作图片发送被纯文本 API 拒绝;现在按 MIME 类型分发——图片保持原行为,文本附件解码为 text 块,PDF 在 OpenAI Responses 转input_file(官方支持 base64 内联)、Anthropic 转 document 块;OpenAI Chat Completions 新增pdfAttachmentEnabled渠道开关(默认关闭,直连官方端点可手动开启),开启后 PDF 以file内容块发送,关闭时转文本占位避免不支持 file 类型的兼容端点报 400;TokenCountService 同步修正,新增回归测试formatterAttachments.test.ts - 修复 MemoryManager 编辑记忆死锁:
updateEntry持锁期间调用dropSummariesCovering→treeDrop二次 acquire 同一把不可重入的 AsyncLock,形成闭环等待,记忆条目 ≥2 条时编辑操作永久挂起、整个记忆模块排队瘫痪;dropSummariesCovering移出锁外执行(treeDrop 自身会加锁),新增回归测试h1_deadlock.test.ts - 修复 Anthropic 并行工具调用参数全部丢失:formatter 未透传
content_block_*事件的顶层index,累加器把多个工具的input_json_delta全部拼进最后一个空工具壳导致JSON.parse失败、工具以空参数执行;现在content_block_start/input_json_delta均透传chunk.index,新增回归测试formatterParallelTools.test.ts - 修复 OpenAI Responses 渠道工具参数双重拼接:
function_call_arguments.done携带完整 arguments 但未设置finalArgs,累加器把完整 JSON 追加到已累积的半截增量上形成垃圾串,工具全部空参数执行、"流式边执行工具"失效;现在 done 事件设置finalArgs: true,累加器按覆盖语义解析 - 修复
delete_file可递归删除整个工作区的问题:handler 对""/"."/".."及解析后等于任一工作区根的路径零校验,一次误调用即删光全部文件;现在显式拒绝上述路径(工作区外策略拦不住根目录本身) - 修复 limcode→graycode 改名残留导致多处功能不可用:diff 视图悬停 ✅/❌ 链接、灯泡操作、编辑器标题栏 Accept/Reject All 按钮、Windows 通知点击打开聊天全部失效(命令均未注册);8 处
limcode.*全部替换为graycode.*,另修复show_windows_notification的GrayCode.openChat大小写错误(extension 注册的是小写graycode.openChat,VS Code 命令名大小写敏感) - 修复工具执行后中止时已执行结果被丢弃:模型消息已写入历史、流式提前执行的工具已产生真实副作用,用户停止后直接返回导致结果永久丢失、模型可能重复执行同一工具调用;现在 abort 路径把提前执行与串行执行的结果(含多模态附件)合并写回历史并结算 stop state,等待提前执行工具的循环内部增加 abort 检查避免某工具不响应信号时请求永久挂起
- 修复同一会话并发流:第二个流创建时静默覆盖旧控制器不中止旧流,旧流先结束时其 finally 无条件 delete 误删新流控制器,旧流不可取消、新流变孤儿、两个流并发读写同一历史文件互相覆盖;现在
create()先 abort 旧控制器再替换,delete/deleteSummary加引用校验 - 修复 diff 自动保存与取消竞态:auto-save 的 acceptDiff 在队列中异步执行,期间用户发送新消息触发 cancelAllPending(不走串行队列)恢复文件后,accept 后续的
doc.save()/writeFileSync仍把 AI 内容写回磁盘;现在cancelAllPending纳入diffActionQueue串行队列,acceptDiffUnlocked在 openTextDocument/applyEdit/写盘前复查diff.status - 修复同一会话历史写并发覆盖:分段历史写入先删整个目录再逐段重写(无锁),transcript
get→mutate→replace无串行化,checkpoint 元数据 read-modify-write 无锁——并发时 index 与 segment 不一致、真实执行成功的工具结果被"用户拒绝"占位覆盖、检查点/裁剪状态随机丢失;现在历史写入按会话串行化并改为"临时目录 + rename"原子切换,transcript mutate 整体互斥,setCustomMetadata加 per-conversation 写锁 - 修复检查点增量链断裂:cleanup 按时间删最旧不检查
baseCheckpointId依赖,配置maxCheckpoints(如 1~2)后回档 100% 失败;现在只删除不再被任何存活检查点引用为 base 的项 - 修复检查点恢复时 dirty 文档把用户旧缓冲区写回磁盘覆盖刚恢复内容的问题:恢复后对 dirty 文档直接
doc.save()会覆盖恢复结果,现在先把文档 buffer 替换为磁盘内容再静默保存(直接 revert 会弹原生确认框阻塞流程) - 修复中断/取消流的 token 严重少计:
usageMetadataPartial标记此前从未被写入也从未被检查;现在取消路径写入该标记,用量统计与对话统计对半截 usage 回退到文本长度估算 - 修复 SSE 合法多行
data:事件内容静默丢失:前一段不完整数据被无条件覆盖丢弃(注释写"继续累积"实际是覆盖);现在按 SSE 规范用单个换行累积多行 data,解析不了的中间行保留到流结束进入 unparsed 错误详情不再静默吞掉 - 修复
execute_command超时被误判为执行成功:超时把killed = true复用为成功标志,模型把超时命令当成功;现在新增独立timedOut标志,超时按失败返回,任务状态显示 error 而非 cancelled - 修复
insert_code内容以\n结尾时多出空行且 CodeLens 高亮偏移:split('\n')多出的尾部空串被移除,插入行数统计同步修正 - 修复
read_file无文件大小护栏:超大文件全量读入并全量塞进模型上下文;新增 5MB 上限(与 search_in_files 一致),超限拒绝并提示改用搜索 - 修复 unified diff 解析把 hunk 内以
--开头的删除行(SQL/YAML 注释等)误判为下一个文件头,整包被当作 multi-file 拒绝;---中断条件改为仅当与下一行+++成对出现(文件头对)才触发 - 修复被拒绝的 diff 被 FIFO 淘汰(上限 50)后
write_file/insert_code/delete_code/search_in_files误报"写入成功":DiffResolutionReason新增rejected终态,淘汰时对 rejected 留痕,工具改为按interruptReason === 'none'判定接受 - 修复 ChatFlowService 主流程
markUserInterrupt与resetUserInterrupt之间无 try/finally:中途抛错全局中断标记残留,无会话 diff 被误取消;现在重置放入 finally(与 delete 路径一致) - 修复 MessageRouter 非阻塞消息异常兜底先删路由条目再发错误导致错误必然错投主聊天、Monitor 面板请求永久挂起;现在先
sendRoutedError再清理,回退路径也补删条目防requestClients无界泄漏 - 修复流式处理器构造时捕获 view 引用:视图重建后 chunk 发往已销毁 webview,新视图永远收不到 complete/cancelled、占位消息永久"生成中";改为每次发送前实时获取 view
- 修复
deleteConversation不清理孤儿数据:snapshots/ 与 diffs/ 残留孤儿;现在删除对话时一并清理快照与 diff 目录,cleanupOrphanedDiffs不再把__global__全局 diff 目录连带删除 - 修复
search_in_filesreplace 模式漏传replace参数时替换串为空、静默删除所有匹配内容的问题:replace 模式下参数缺失直接报错 - 修复
execute_command用shell.includes('cmd')判断 shell 类型(自定义 shell 路径目录名含 cmd 误判)与相同 toolId 并发执行覆盖activeProcesses条目(旧进程成孤儿无法取消);改为按 shell 文件名精确匹配,覆盖前先终止仍在运行的旧进程 - 修复
list_filesWindows 递归返回\分隔路径与其余工具/约定冲突、回传给 read_file 时解析失败的问题 - 修复
SettingsManager.getToolsConfigEntry浅合并导致用户手写部分配置整体替换嵌套默认对象的问题:改为递归深合并(数组与原始值仍直接覆盖) - 修复
getHistoryForAPI在 startIndex ≥ history.length 时返回完整历史而非空历史的问题 - 修复
DiffEditorActionsProvider从翻译后的 label 文本正则提取块索引(翻译含数字时可能确认错误块):改为 QuickPick 项结构化携带块索引 - 修复快照 ID 用
Date.now()同一毫秒内连续创建互相覆盖的问题:追加随机后缀保证唯一 - 修复检查点增量哈希复用漏检:
mtimeMs + size在毫秒精度内同秒等长修改不触发重算;新增纳秒精度mtimeNs比较(旧记录回退旧行为) - 修复 Gemini 流式 URL 拼接未处理 baseUrl 已有 query 参数的问题(生成畸形 URL);非流式解析对
content缺失的候选直接 TypeError(流式路径已判空) - 修复 Anthropic
message_delta的 usage 只含 output_tokens 时totalTokenCount = 0 + output覆盖 message_start 的正确 total、输入 token 从总量中消失的问题:无 input 侧计数时不输出 total,累加器走重算路径 - 修复
delete_file根目录防护可被 Windows 大小写变体绕过(盘符/目录大小写不一致时大小写敏感比较不命中、递归删除整个工作区):根路径比较改用路径规范化(Windows 折叠大小写 + 去尾斜杠),并在 handler 内实时获取工作区集合 - 修复
rejectAllPendingToolCalls/settleFunctionResponses直写仓储绕过互斥执行器、真实工具结果仍被“用户拒绝”占位覆盖的竞态:replaceContents纳入 exclusive(内部拆saveAndReload防锁嵌套),两个函数整体改走mutateContents串行域 - 修复
setTitle/setWorkspaceUri整对象元数据覆写未加锁:与setCustomMetadata并发时会把 custom 对象整体冲掉;现在统一走 per-conversation 写锁 - 修复中止路径写回与
rejectAllPendingToolCalls占位竞争导致真实工具结果被丢弃:abort/等待取消路径改用settleFunctionResponses(真实结果覆盖占位),补齐多模态附件与 stop state 结算;等待提前执行工具的循环与 abort 事件做 race,消除工具不响应信号时的永久挂起窗口 - 修复 Anthropic 流 total 仍缺输出 token:
message_start的 total 只含 input,message_delta的 output 增量现在会合并进总量,下游上下文裁剪/汇总的total−prompt不再恒为 0 - 修复
execute_command同 toolId 并发时旧进程 close/error 处理器无条件删除同 key 条目、把新进程变孤儿的问题:预杀分支立即注销旧任务并摘除旧条目,close/error 处理器加身份校验;success前置!timedOut,消除 close(code=0) 晚于超时回调时“成功 + timed out”自相矛盾 - 修复 retry / edit-and-retry / delete-to-message 三条流程的
markUserInterrupt无 try/finally:中途抛错全局中断标记残留,无会话 diff 被误取消;现在重置统一放入 finally - 修复
summarizeContext的deleteSummary未传控制器引用:同一会话两个总结流交叠时旧者 finally 误删新者控制器、新流无法取消;现在传控制器引用做身份校验 - 修复 diff 自动保存分支 3 的
doc.save()与writeFileSync之间无状态复查:取消/拒绝后 AI 内容仍可能被写回磁盘;现在写盘前补diff.status复查 - 修复
evictedRejectedDiffIds随会话无界增长:淘汰留痕只对仍有活跃等待者的 rejected diff 生效(新增activeDiffWaiters登记) - 修复 unified diff hunk 内相邻“删除行
--+ 增加行++”仍被误判为文件头对、整包拒绝的问题:文件头对要求后跟@@才触发中断 - 修复历史迁移与删除绕过写队列:
migrateLegacyConversationsToSegmented与deleteHistory与saveHistory共用同一 per-conversation 写队列,消除迁移/删除与并发写互相干扰(删除后目录被复活、tmp 目录被误删) - 修复 checkpoint cleanup 对完整链恒为 no-op、
maxCheckpoints静默失效的问题:删除链上中间节点前先把其备份合并进后继(不覆盖后继已有文件)、changes 合并、base 重挂,再删除 - 修复取消流从未收到 usage 事件时(OpenAI chat/Gemini)整条 model 消息被跳过漏计的问题:
estimatePartialMessageTokens在 usage 缺失时也按文本长度估算(含 functionCall 参数) - 修复 fast-tavern Python
process_content_stages调用apply_regex时漏传variableContext:{{getvar::...}}/{{setvar::...}}在 replaceRegex 场景端到端仍失效;现在与 TS 调用方对齐透传 - 修复 Gemini 空候选报错信息不具体:非流式解析对
content缺失的候选抛笼统错误,现在显式报出finishReason(新增emptyCandidate三语言词条),内容安全拦截等场景可直接看到真实终止原因 - 修复 Anthropic
count_tokensURL 归一化顺序:baseUrl 形如.../v1/models/complete时先处理/v1/models会残留/complete后缀、拼出畸形端点 URL;现在先去掉/complete再规整/v1/models - 修复分段历史原子提交的临时路径类型错误:
getHistoryDir(...) + '.tmp'把 Uri 对象与字符串拼接成字符串后直接传给workspace.fs(createDirectory/delete/writeFile/rename),扩展宿主按 UriComponents 重新解析抛[UriError]: Scheme contains illegal characters,导致新建对话/保存历史失败(新建对话闪一下无变化、旧对话发消息报错);改为Uri.joinPath构造真正的 Uri 对象,新增回归测试storageSegmentedWrite.test.ts(锁定所有 workspace.fs 路径参数必须是 Uri 对象) - 修复
validateFileInWorkspace对 workspaceUri 的裸Uri.parse:非法 URI(如旧格式 Windows 路径)抛 UriError 被外层 catch 吞成UNKNOWN错误码,或把C:\...误解析成scheme='c'导致合法文件被误判为「属于其他工作区」;现在 Windows 盘符路径按Uri.file语义解析,解析失败时跳过归属比对(不误杀合法文件) - 修复会话元数据读改写互相覆盖:
setCustomMetadata/setTitle/setWorkspaceUri与各存储适配器saveHistory内部的 updatedAt 更新此前在两条独立串行链上,并发时后写者基于旧 meta 的整体写回会把先写者的 custom 字段覆盖(检查点列表/裁剪状态随机丢失);现在storage.ts新增模块级withMetadataWriteSerialized共享链统一所有元数据读改写,ConversationManager新增updateCustomMetadata(链内「读 meta→updater→无变更跳过写回」,updater 支持异步) - apply_diff 匹配失败报错增强:oldContent 找不到时不再只说「请核实内容」,新增最近似块诊断——在文件中定位与 oldContent 最接近的行块,逐行报告差异(含首差异字符列与期望/实际内容片段),帮助快速定位全角/半角、空格、缩进或内容已变等问题;块首行不匹配时自动尝试后续行作锚点,超长块/超大文件自动跳过诊断避免 O(m×n) 扫描卡死;结构化 hunk 与 legacy search/replace 两条失败路径均接入
- 修复 CheckpointManager 全部 7 处「读列表→内存改→整体写回」竞态:并发创建互相覆盖记录、并发删除/裁剪互相丢失;全部迁移到
updateCustomMetadata,删除类操作在链内算好保留集合、写回成功后才删磁盘目录(竞态窗口收敛) - 修复
normalizeHistoryForDisplay锁外写回覆盖真实工具结果:getMessages/getMessagesPaged的补齐流程基于旧快照整体写回,与工具结果并发落盘互相覆盖;现在整个读-改-写移入仓储互斥执行器,TranscriptRepository.mutateContents新增「返回原引用=跳过写回」无变更契约(无未响应调用时不再每次读历史都写一次盘) - 修复
addContent去重锁外执行导致同一 tool_use_id 出现两条 functionResponse:去重+追加整体移入mutateContents,取消流与工具执行循环之间的竞态安全网恢复有效;同步修复契约上线暴露的 9 处「原地修改+返回原引用」mutator(appendContent/addBatch/updateMessage/updateMessagesBatch/insertMessage/insertContent/deleteMessagesInRange/rejectAllPendingToolCalls/settleFunctionResponses)改为有变更时返回新引用 - 修复 MemoryManager.updateEntry 越界写垃圾记录:
logLen()校验与logGet读取在锁外执行,并发truncateLog/logAppend改变日志长度后基于过期 id 的写入越过 EOF;校验与读取移入锁内 - 修复
getStats对缺data/mimeType的 inlineData 抛 TypeError:旧版本或手动编辑的历史不再导致统计面板/上下文裁剪入口崩溃 - 修复代理 CONNECT 隧道流式解码损坏中文:
decodeChunkedStream逐 chunktoString('utf8')把被 TCP/chunk 边界切开的 UTF-8 多字节字符在第一个包固化成 U+FFFD,后续 SSE 行JSON.parse永远失败;现在只收集原始字节,由流式TextDecoder跨 chunk 拼接解码,循环结束 flush 尾部字符 - 修复代理取消被误判为可重试:
fetchWithProxy/sendRequestOverSocket的取消 reject 普通 Error,ChannelManager 只认AbortError导致取消变无谓重试;新增createAbortError统一 6 处取消错误,CONNECT 握手成功后移除旧 abort 监听避免重复取消 - 修复重试等待窗口内发送保活请求:重试路径 delay 前未停 keepAlive 定时器,错误后到 delay 完成之间在无活动流时发出保活请求;现在 delay 前先 clearInterval
- 修复 OpenAI strict 工具混用被 API 400 拒绝:任一工具 strict 时 OpenAI 要求全部工具 strict,混用显式发送
strict: false被拒;现在整体降级为不启用 - 修复 directApplyAndSave 把编辑器旧缓冲区写回磁盘覆盖 AI 内容且 diff 永久 pending:dirty 文档
openDoc.save()会把旧内容+用户未保存编辑写回磁盘,且saved提前 return 跳过 finalizeAcceptedDiff;现在先写盘,再用 WorkspaceEdit 静默替换编辑器内容为 AI 内容并save()清理 dirty(内容与磁盘一致,保存无害)——早期方案用workbench.action.files.revert,但文档 dirty 时会弹 VS Code 原生确认框阻塞整个 diff 流程,已弃用 - 修复关标签页不收敛 accepted、diff 永久 pending:磁盘已是 AI 内容(files.autoSave 直接落盘)时关闭标签页既不接受也不拒绝;现在内容相等收敛为接受
- 修复 legacy 多 diff 行号偏移累积:
start_line相对原始文件,前序 hunk 改变行数后后续 hunk 整体错位;三处 legacy 应用路径新增 lineDelta 累计 - 修复 glob 元字符未转义抛 SyntaxError:
matchGlobPattern/shouldIgnore只转义.,配置含[/(/+/?时new RegExp抛错中断动态上下文生成;改为整体escapeRegExp后再做通配替换,并修复斜杠替换在星号替换之后导致[^[/\]]通配永不命中的顺序缺陷 - 修复 fsPath 大小写敏感比较失效:diffManager 11 处
fsPath ===严格比较在 Windows/macOS 上因大小写变体路径失效导致监听器/文档查找失灵;新增sameFsPath(win32/darwin 折叠大小写,Linux 精确) - 修复分段存储 delete+rename 提交窗口与无读重试:删旧目录→rename 期间并发读可能看到 index 在但段文件消失;现在写前清理 tmpIndexPath 残留、提交改 overwrite rename、
loadHistoryWithStatus/loadHistoryPage对 not_found/io_error 重试一次(50ms) - 修复 cancelTask 提前删任务丢终态事件:abort() 后立即删任务+发裸 cancelled,完成路径的
unregisterTask变 no-op、前端任务条卡在「已取消但无结果」;现在只 abort,终态由各完成路径统一发出(已核对 terminal/media 全部取消路径) - 修复终端输出无内存护栏:长运行进程持续输出内存无限增长;新增
MAX_RETAINED_OUTPUT_LINES = 50000+pushOutputLines(超限丢最旧并计数),截断提示用output.length + omittedOutputLines总量 - 修复 search_in_files / FilePickerPanel / AnnouncementModal 三处 v-html 注入:搜索结果上下文、文件路径、changelog 正文未转义直接注入 HTML,工作区文件内容含
</>/&或恶意 HTML 时可执行任意脚本(远程代码执行级风险);现在统一先escapeHtml再做高亮/markdown 标记替换 - 修复中文/日文输入法合成回车误发消息:InputBox 无 IME 守卫,按 Enter 确认候选词触发发送逻辑误发半截消息;现在
isComposing/keyCode 229 直接 return - 修复批注消息发送失败不回滚:ToolMessage 先 push 用户批注再发送,失败时批注残留成幻影消息、前端索引与后端错位、重试会再插一份;现在失败按 id 回滚
- 修复 apply_diff / write_file 大文件 diff 预览卡死:computeLCS 全量二维 DP,数千行 diff 占数百 MB 内存并阻塞 webview 主线程;现在公共前缀/后缀剥离 + 核心区域超过 100 万跳过 DP
- 修复 isLoadingMore 切标签页后永久禁用:复位在 tabId 匹配分支内部,加载期间切走标签页后上拉加载被永久跳过;现在 finally 无条件复位
- 修复消息列表 UI 状态组件级丢失:uiStateByTab 是组件实例级 Map,空会话过渡卸载组件后滚动位置/展开状态全丢;现在提升为模块级保存
- 修复切会话清空排队消息:switchConversation 无条件清空 messageQueue,排队消息被静默丢弃;现在只清理附件,跨会话消息由队列匹配跳过机制处理
- 修复跨会话消息卡队头:processQueue 取到不属于当前会话的消息放回队头并中止,该消息永久阻塞队列;现在改为查找第一条属于当前会话的消息
- 修复关标签页不取消流 + 废弃缓冲累积:closeTab 不取消该会话仍在进行的流,后续 chunk 为已关闭会话重建缓冲区且无消费者,反复开关页无限累积;现在关页时按 conversationId 取消流,缓冲对已关闭会话直接丢弃不重建
- 修复消息 timestamp 被完成时刻覆盖:四个流式 handler 用
{...message, ...finalMessage}展开,finalMessage 的 timestamp 是完成时刻导致时间戳漂移、排序错乱;现在补 timestamp 保留 - 修复消息订阅者单点崩溃:一个订阅者抛异常中断其余订阅者(backgroundTaskStore 收不到同一条消息);现在每个订阅者单独 try/catch
- 修复 Markdown 渲染缓存无界增长:codeHighlightCache/fileExistenceCache/imageCache 无上限,长会话持续增长;现在统一
setCached容量 500 FIFO 淘汰 - 修复 ChatViewProvider.dispose 不重置 _view:_view 仍指向已销毁 webview,重开面板后 diff 状态/终端输出等事件永久丢失;现在 dispose 置空
- 修复 pendingCommands 无上限:面板长期未打开期间反复触发命令队列无界增长、打开后一次性重放陈旧命令;现在上限 100
- 修复 sendError 对非 Error 对象取 message 得 undefined:改为 instanceof 判断回退 String(error)
- 修复 webview 已死路由判定失效:已销毁 webview 的 postMessage resolve(false) 而不抛异常,调用方误判成功跳过回退路径、响应静默丢失;现在注册表按 isAlive 判定存活,SubAgentMonitorPanel 注册绑定 panel 实例
- 修复流 chunk 不按 clientId 路由:所有流都发往主聊天,monitor 面板发起的流错投;现在
getClientView(clientId)按注册表路由 - 修复 requestClients 泄漏:请求结束不清理 requestId→clientId 映射;现在 4 个流式 handler 的 finally 与取消路径统一 finalizeRequest
- 修复 showDiffView 未入串行队列:与 accept/reject 动作并发时状态互相抢占;现在包
runDiffActionSerialized(原实现改 showDiffViewUnlocked) - 修复被淘汰 rejected diff 墓碑 Set 无界增长:evictedRejectedDiffIds 随会话无限累积;现在容量上限 2000 FIFO 淘汰
- 修复 fast-tavern Python 与 TS 语义差异:assemble_tagged_prompt_list 的 NaN/bool 通过 isinstance 过滤导致 int(nan) 抛 ValueError;history/factories 的 str(text or "") 把 0/False 变空串;convert_from_silly_tavern 的 isinstance(v, int) 漏 float 且 bool 误判;normalize_worldbooks 的 _to_number 未对齐 Number() 且 index/probability int 截断(2.5 与 2 是不同键);apply_regex 的 macroMode 缺失被当 none(TS 缺失=执行替换)且 {{}}/<<>> 替换顺序与 TS 相反;variable_context 的 float(None) 抛错使已存 null 走字符串拼接;get_active_entries 的 recursionLimit/index/order 数值强转抛 ValueError/TypeError/丢小数——全部对齐 TS 语义(build_prompt 对应文件已随重构移除,不适用)
Changed
StreamChunkProcessor构造从持有 view 引用改为持有getView回调,视图重建后消息自动发往新视图TranscriptRepository支持注入互斥执行器(exclusive),mutateContents的 get→mutate→replace 整体串行化- fast-tavern Python 版
apply_regex对齐 TS 版:替换结果中的{{user}}、{{getvar::...}}、{{setvar::...}}等宏立即展开,并透传variableContext - SubAgent Monitor 流式卡顿优化:前端
llm_delta事件改为非响应式队列 + rAF(setTimeout 兜底)批量 flush,事件回调从「每 chunk 全量更新 manifests/windowsByRunId + renderMessages 全量重建」降为 O(1) 入队、每帧至多一次合并提交;renderMessages 按 content/overlay 引用缓存 Message 对象,未变化的楼层不再触发 MessageItem 重渲染(连带避免重复解析 Markdown),流式更新成本与窗口长度解耦;前端事件数组加 500 条上限(与后端 journal 对齐);后端 SubAgentMonitorPanel 对llm_delta做 50ms 节流合并,跨进程 postMessage 次数与渲染帧率对齐而不是与 token 产出速度对齐,并发 SubAgent 下 Monitor 不再卡顿 - SubAgent 默认限制放宽:迭代次数默认 20 → 50(预设 30
40 → 4080),运行时间默认 300s → 1800s(预设 600900s → 12002400s),同步更新设置面板默认显示值、工具描述与类型注释;复杂任务不再频繁触顶「超出最大迭代次数 / 运行时间」
Added
- 新增回归测试:
formatterParallelTools.test.ts(Anthropic 并行工具参数按 index 合并、OpenAI Responses done 覆盖增量)与h1_deadlock.test.ts(≥2 条记忆编辑不死锁) - 修正 4 处 limcode→graycode 改名遗留的过期测试断言(
show_windows_notification、create_progress、diffManager、PromptManager.promptEntries)
[1.2.8] - 2026-07-30
Changed
- 品牌更名:LimCode → GrayCode。扩展 ID 由
limcode改为graycode。所有 VSCode 命令已更名(limcode.*→graycode.*),配置命名空间已变更(limcode.*→graycode.*)。从旧 LimCode 导出的 JSON 文件导入时会自动迁移。 DiffHandlers.ts中buildPreviewContentsFromUnifiedPatch的flush()优化:只在 hunk 有实质内容时才追加空行分隔,减少预览中的多余空行- 工具设置页面新增工具名称和描述的中文/日文翻译:42 个工具的名称和描述现在会根据界面语言切换显示,覆盖文件和目录操作、终端命令、代码智能、媒体处理、TODO、设计/计划/进度/审查文档、历史搜索、Windows 通知、永久记忆等全部工具
- 记忆设置页面新增 4 个运行时参数配置项:wakeLines(唤醒输出行数)、entryChars(单条记忆最大字节)、partChars(分页最大字符数)、partLines(分页最大行数),用户可直接在设置界面调整记忆系统的输出格式和容量,无需通过 AI 工具
- MemoryToolConfig 类型扩展,新增 wakeLines / entryChars / partChars / partLines 可选字段,默认值与 DEFAULT_MEMORY_CONFIG 对齐
- getMemoryConfig / updateMemoryConfig 处理器合并 MemoryManager 运行时配置:读取时自动合并文件系统的运行时参数,保存时同步到 MemoryManager(若已初始化)
Fixed
- 修复
read_file等工具返回给 LLM 时文件内容反斜杠被二次转义的问题(\→\\),根因在anthropic.ts/openai.ts/openai-responses.ts三个 formatter 中对functionResponse.response统一做了JSON.stringify,导致 JSON-in-JSON 嵌套编码。现改为共享的serializeToolResultForLLM函数,大段文本内容原样透出,元数据用纯文本前缀。修复后 AI 在apply_diff等工具中不再因反斜杠翻倍而写出错误的转义序列 - 修复
apply_diff前端组件中 diff 块失败原因被 CSS 截断不显示的问题:.error-msg移除max-width: 200px+text-overflow: ellipsis+white-space: nowrap,失败原因完整展示;失败 diff 块新增错误摘要区直接显示具体失败原因,不再只有参数预览 - 修复加载历史对话时前端工具调用卡片显示状态不正确、搜索结果缺失的问题:根因是前端
toolResponseIndex(functionResponse.id → 消息下标 O(1) 索引)在历史加载路径(loadHistory/loadOlderMessagesPage/switchConversation/ tab 恢复 / 检查点回档 / 重试重载)中未被重建,导致getToolResponseById()始终返回 null,工具卡片无法匹配到对应的functionResponse数据。修复方式为在以上路径的allMessages.value直接赋值后统一调用rebuildMessageIndexById(state)重建索引 - 修复
serializeToolResultForLLM(Anthropic/OpenAI function_call 模式)三处信息丢失:(1) 错误分支遇到response.error时只返回简短错误文本,丢弃了data.output等诊断信息,导致 AI 只看到 "Command exited with code 1" 而看不到具体 stderr;(2)data.results数组分支只序列化data.results而丢弃了data中其他元数据(count/filesModified/skippedFiles/queryFallback等),AI 看不到搜索结果摘要;(3)formatResultItem无条件删除每项success字段(注释称"顶层已有"),但单文件失败状态被顶层success: true掩盖,AI 看不到具体哪个文件出错。修复:(1) 错误分支附加data.output;(2) results 分支改为JSON.stringify(data)保留完整元数据;(3) per-itemsuccess: false时标记FAILED;同时将lineContent/context/output加入TEXT_CONTENT_KEYS,移除误删type字段的逻辑
Added
apply_diff结构化 hunk 匹配失败时新增转义诊断(detectEscapeIssues):当oldContent包含字面\n/\t/\"序列时,错误消息自动追加诊断提示,帮助 AI 识别 JSON 参数中的过度转义- 新增
toolResponseFormatter.ts共享序列化模块,统一处理工具响应到 LLM 消息的格式化,避免各 formatter 各自 stringify 导致行为分叉 - 记忆系列工具(memory_wake / memory_note / memory_recall / memory_compress / memory_zoom / memory_forget / memory_config)前端自定义展示组件
MemoryResult.vue重构:展开工具卡片后同时展示模型传入的参数(Parameters 区)和工具返回的文本结果(Result 区),区分原始记忆块与摘要块的颜色,展示统计标签(Memories / Hits / Part / ID / Removed 等);移除硬编码 max-height 限制,内容完整可见 memory_forget新增原始记忆截断模式:传入单个数字 ID(如"0")可截断原始 LOG,删除 ID >= 该值的所有原始记忆及关联树摘要;传入范围 ID(如"16-31")保持原有仅删摘要行为。MemoryManager新增truncateLog(keepId)方法支持物理截断固定宽度记录文件- 记忆设置页面新增「Raw Memory Entries」管理面板:用户可直接查看所有原始记忆条目(ID / 日期 / 文本),支持原地编辑单条记忆文本(后端
MemoryManager.listEntries/updateEntry新增固定宽度原地覆写能力),编辑后自动清理相关树摘要
[1.2.7] - 2026-07-28
Added
- 永久记忆系统(OptMem):AI 跨会话自动记住约定、决策和知识,每次新会话开始时通过
memory_wake自动恢复记忆上下文;记忆以追加式日志 + 二叉树摘要存储,旧记忆智能压缩为摘要节省 token - 新增 7 个记忆工具:
memory_wake(唤醒记忆)、memory_note(记录记忆)、memory_recall(正则搜索记忆)、memory_compress(执行压缩合并)、memory_zoom(展开树节点)、memory_forget(丢弃错误摘要)、memory_config(查看/修改参数) - 新增
MemoryManager核心引擎(backend/modules/memory/):TypeScript 原生实现的固定宽度记录存储、二叉树 cover 算法、分页输出、异步锁并发控制,完全兼容 OptMem 数据格式 - 新增
{{$MEMORY}}系统提示词模板变量:在内置 DEFAULT 和 CODE 模板中默认引用,用户可在 设置 → 记忆 中自定义记忆使用说明,或在提示词设置中删除此变量以关闭记忆系统 - 新增记忆设置页面(设置 → 记忆):可视化编辑自定义记忆提示词,保存/重置按钮,MemoryToolConfig 类型持久化到
graycode.toolsConfig.memory - 提示词设置「插入变量」列表新增
{{$MEMORY}}(静态分组) - 记忆数据默认存储在
globalStorage/memory/,随 GrayCode 自定义存储路径迁移 - 新增 MemoryManager 初始化集成(ChatViewProvider.initializeBackend 步骤 25.6)
Fixed
- 修复消息列表滚动到顶部后无法加载更早消息的问题:
hasMore条件只看后端是否还有数据,忽略了前端已加载但未渲染的消息;loadMore()在后端无更多数据时直接 return,导致visibleCount永远不增长。现拆开前端渲染展开与后端分页加载两个步骤,即使全部消息已在内存中也能正常展开渲染 - 修复
insert_code和write_file工具结果中文件路径不可点击跳转的问题,补充clickable样式和点击事件,与其他文件工具(delete_code、read_file、apply_diff 等)行为一致
[1.2.6] - 2026-07-27
Added
- SubAgent 对话延续:主模型调用
subagents工具时可传入continueFromRunId参数,将新子代理接续到之前已完成子代理的对话上,新子代理自动继承旧 run 的完整 transcript(对话历史),实现跨调用的对话接力;对仍在运行中的旧 run 会拒绝延续并返回明确错误 - 新增 StreamAccumulator 回归测试(
backend/__tests__/channel/streamAccumulator.test.ts,覆盖结构修订号递增语义 / 完成工具调用 id 去重 / prompt 模式分片块解析 / thought 文本不解析 / 未闭合块 flush,9 用例)与 xmlFormatter 解析测试(backend/__tests__/tools/xmlFormatter.test.ts,tool_name 形态容错 / 带属性参数节点,5 用例) - 新增用量统计页面:从已落盘对话历史回溯聚合 token 用量,支持总览 + 按对话 / 按模型 / 按日期三个维度,包含 CSS 条形图可视化;入口位于历史页头部图表按钮
- 用量统计页新增 VSCode 视图标题栏入口(
graycode.showUsage命令 + graph 图标按钮,位于历史与设置之间),不再只能从历史页右上角的隐藏入口进入 - 用量统计页新增时间范围筛选(全部 / 今天 / 近 7 天 / 近 30 天),后端
aggregateUsageStats支持按消息时间戳过滤(UsageStatsOptions.startTime/endTime),总览与三个维度均为筛选后口径;筛选激活时缺失时间戳的消息不参与统计 - 用量统计页新增成本估算:「按模型」维度可就地配置模型单价(美元/百万 token,思考 token 按输出价计),行上显示单模型估算成本,总览卡片显示总估算成本;单价持久化在
ui.usagePricing,随设置导出/导入一同迁移 - 用量统计页「按对话」维度支持点击行直接打开对应对话并返回聊天视图
- 新增后端用量聚合器
usageStats.ts,从 model 消息的usageMetadata提取输入/输出/思考 token,兼容旧字段格式,单对话读取失败自动跳过不影响整体 - 新增
UsageHandlerswebview 处理器,注册usage.getStats消息 - 新增用量统计聚合的后端单元测试(
backend/__tests__/conversation/usageStats.test.ts,覆盖聚合正确性 / 旧字段兼容 / 读取失败跳过计数 / 双边与单边时间范围筛选,共 5 个用例) - 用量统计页三语 i18n(zh-CN / en / ja)
- 文件工具卡片(apply_diff / write_file / insert_code / delete_code / read_file / delete_file)文件名与路径支持点击跳转到编辑器;insert_code 和 delete_code 还会自动定位到插入/删除行并高亮
- 新增文件跳转公共 composable
useOpenWorkspaceFile,封装openWorkspaceFile/openWorkspaceFileAt扩展桥接 - Anthropic 渠道新增 Prompt Caching 缓存 TTL 选择(5 分钟 / 1 小时),可在渠道设置中选择缓存保持时间;1 小时 TTL 写入价格为 2x 基础输入价格
- Anthropic 渠道新增 Prompt Caching 缓存保活开关(循环保活 + 退出保活):当 TTL 为 5 分钟时,流式请求期间每 4 分 30 秒自动发送 max_tokens=5 的保活请求循环刷新 TTL;流正常结束且无工具调用时,若距请求开始已过 4 分钟则额外保活一次,防止用户下一轮输入时缓存刚好过期
- Anthropic 渠道新增思考内容显示模式开关(隐藏 / 摘要),控制 API 响应中是否返回可见的思考内容;Opus 4.7+ 默认隐藏思考,选择「摘要」可恢复思维链输出;该开关与思考启用状态独立
- Anthropic 渠道新增 xhigh 思考努力级别,位于 high 和 max 之间(Opus 4.7+)
- OpenAI 兼容渠道新增 DeepSeek
user_id开关,用户可在渠道设置中显式启用,启用后主聊天请求会基于当前对话 ID 生成稳定且不包含隐私信息的user_id,用于 DeepSeek KVCache 按对话隔离;默认关闭,避免误判中转或其他兼容服务 - 新增设置导入/导出功能:可在设置 → 通用设置中将渠道配置、MCP 服务器、Skills 和 VSCode 设置导出为 JSON 文件,或从文件导入恢复;支持跳过已存在项和覆盖全部两种导入模式,导入时弹出覆盖确认对话框
- 新增
SettingsExporter后端模块(backend/modules/settings/SettingsExporter.ts),负责收集导出数据(VSCode 设置、渠道配置、MCP 服务器、Skills)并序列化/反序列化,排除对话历史与检查点 - 设置导入/导出支持设置页「通用设置」按钮和命令面板(
graycode.exportSettings/graycode.importSettings)两种入口 - 新增设置导入/导出三语 i18n(zh-CN / en / ja)
- 新增
settings.export/settings.importwebview 消息处理器,前端按钮通过消息桥接调用扩展端文件对话框与导出/导入逻辑 - 类型安全渐进启用:tsconfig 新增
strictNullChecks+alwaysStrict+noImplicitThis+strictBindCallApply+strictFunctionTypes+noFallthroughCasesInSwitch,backend + webview 零严格错误 - 大段提示词模板从
backend/modules/settings/types.ts(2675 行)拆分到独立的promptModes.ts,类型文件只保留类型定义与 re-export,旧 import 路径 100% 兼容 - 新增 i18n 语言包 key 一致性校验测试(
backend/__tests__/i18n/languageParity.test.ts),递归比对 backend + frontend 各三份语言文件的 key 集合与{placeholder}占位符 - 新增渠道 formatter 核心解析测试(
backend/__tests__/channel/formatterParsing.test.ts),覆盖 OpenAI / Gemini / Anthropic 三个 formatter 的 parseResponse / convertTools / 非法响应报错(13 个用例) - 前端构建新增
vue-tsc --noEmit类型检查步骤(pnpm run build:frontend自动执行),根 package.json 新增typecheck脚本 - 引入 esbuild 打包方案(
esbuild.config.js),扩展入口extension.ts→dist/extension.js单文件 bundle(2.1 MB),node-notifier 作为 external 保留原生文件;vscode:prepublish 与 compile 脚本指向 esbuild - 新增工具参数规范化统一入口
normalizeToolArgs(backend/tools/coerceToolArgs.ts):单数别名提升(模型误传path自动转为paths: [...])、递归嵌套类型容错(files[].line: "5"等嵌套字段也能修正,兼容 Python 风格"True"/"False")、未知参数剥离;所有自动纠正通过parameterWarnings字段随工具结果回传,帮助模型在后续调用中自行修正参数写法 - search_in_files 新增
caseSensitive参数(search 默认不区分大小写、replace 默认区分,可显式覆盖);replace 模式 0 命中时返回zeroMatchHint诊断提示两种模式的大小写语义差异,终结“search 搜得到、replace 替不了”的困惑 - prompt 模式(JSON/XML)工具调用解析失败反馈:有完整边界标记但解析失败的块不再静默降级为普通文本,而是转为携带具体语法错误的合成调用,模型能收到可读的失败原因并重试(含意图工具名提取)
- JSON 工具调用宽松解析:严格解析失败后自动修复模型高频语法错误(字符串值内的裸换行/制表符、尾逗号)后重试一次,减少细小瑕疵导致整个调用丢失
- XML 工具模式 CDATA 支持:提示词新增 CDATA 用法说明与代码示例,历史重放时含特殊字符的参数自动 CDATA 包裹(含
]]>分段处理),写入代码类内容不再因<>&解析失败 - 只读工具并行执行:
ToolDeclaration新增readOnly标记(read_file / list_files / find_files / get_symbols / goto_definition / find_references / history_search / read_skill),同一批调用中相邻的只读工具 Promise.all 并行,降低多读取/搜索调用的累计延迟;写类、MCP 和需确认工具保持严格串行 - 新增同参数重复失败调用护栏
RepeatedCallGuard(turn 级别):相同 name+args 连续失败 2 次后第 3 次相同调用短路返回“换个思路”提示,不再真实执行;成功的重复调用(重跑测试等)完全不干预,阻止小模型烧完 maxIterations 的失败循环 - 新增工具调用链路测试:
promptToolParser.test.ts(宽松解析/失败反馈/CDATA/类型保护 12 用例)、repeatedCallGuard.test.ts(7 用例)、diffReviewConfirmation.test.ts(确认语义 14 用例),coerceToolArgs.test.ts/validateToolArgs.test.ts同步新契约 - 工具参数校验升级为递归校验(
validateToolArgs重写):required 与类型检查深入 array items 和嵌套 object,错误带完整路径(如files[0].line);新增 enum 值校验,报错时附全部可选值(如must be one of "revision" | "progress_sync");校验失败时回显从 schema 生成的 TypeScript 风格参数签名(Expected parameters),模型一轮即可修正参数结构;问题超过 10 条自动截断并提示剩余数量 - 新增 SubAgent 运行事件总线测试(
backend/__tests__/tools/subagentRunEventBus.test.ts,13 用例):manifest 预览截断与超长单条消息不被完整拼接、事件 journal 有界与 llm_delta 不入 journal、updateLastModelContent落盘一致性与 contentRevision 同步、连续写入合并且不丢内容、快照淘汰只作用于已终态且可恢复的 run(运行中与无持久化归属的 run 不被淘汰) - 新增 SubAgent 运行控制器测试(
backend/__tests__/tools/subagentRunController.test.ts,7 用例):暂停后挂起 / 继续返回 running、退出唤醒并返回 cancelled、反复暂停继续后唤醒列表必须为空、resume 重建 AbortController、暂停时长不计入活跃运行时间、非活跃 run 的控制操作一律失败 - 新增 Monitor 窗口新鲜度判据测试(
test/unit/frontend/components/subagents/monitorWindowState.test.ts,7 用例):无窗口必拉、无 manifest 不拉、manifest 修订号领先判定过期、修订号相同不拉(纯状态事件不触发窗口请求)、本地 delta 领先时不回头拉旧窗口、条数领先仍判定过期、缺失协议字段按 0 处理 - 新增扩展消息分类规则测试(
test/unit/frontend/utils/extensionMessageRouting.test.ts,6 用例):成功/失败响应兑现且不广播、兑现后摘除 requestId、无人等待的响应不得被当作推送消息广播、非对象与无 type 消息忽略 - 新增事件载荷瘦身与落盘节流测试(补充进
subagentRunEventBus.test.ts,4 用例):content_snapshot只携带计数、journal 不再引用被替换的 contents 数组、节流窗口内连续变更只落盘一次、终态事件跳过节流并写入最新全量内容 - 新增 SubAgent executor 终态收敛测试(
backend/__tests__/tools/subagentExecutorTermination.test.ts,4 用例):早退路径必须发出终态事件并返回 runId、run 结束后从活跃控制器注销、释放并发席位、清理超时轮询定时器不留下常驻 interval - 新增工具参数兼容别名通用机制:
ToolDeclaration.paramAliases(纯改名别名,如 read_file 的 maxLine → endLine,自动改名 + 警告)与ToolDeclaration.compatParams(语义透传参数,不写进 schema 向模型宣传但不被未知参数剥离,由 handler 解释语义),由 normalizeToolArgs 统一消化 - 新增流式错误归一模块
backend/modules/channel/formatters/streamError.ts:把 Anthropic 的{ type: 'error', error: {...} }、OpenAI / Gemini 的{ error: {...} }、简化代理的{ error: '文本' }三种形态统一识别为ChannelError,结构不认识但确实带内容时原样透出;只有能提取出非空文本才算数,正常 chunk 上的error: null/error: {}不会被误判 - 新增回合信号桥接包装器
backend/tools/abortLink.ts(withLinkedAbort),统一处理「进入时父信号已中止」与「退出时摘除监听器」两件事 - 流式缓冲区解析从
ChannelManager(1300+ 行)提取为独立模块backend/modules/channel/streamBufferParser.ts:它是纯函数却埋在类里,既无法单独测试,也让「上游到底回了什么」这一层的行为难以推敲;新增unparsed字段承载流结束后仍解析不出的原始内容 - 新增本轮修复的回归测试共 36 个用例:
streamErrorDetection.test.ts(12,四个 formatter 的流内联错误识别 + 非流式 HTTP 200 错误体 + 正常 chunk 不误判)、streamBufferParser.test.ts(11,SSE / JSON 行 / 纯文本三类格式与 unparsed 语义)、abortLink.test.ts(5,含监听器不累积与抛出时仍摘除)、pagedHistoryIntegrity.test.ts(4,分段存储的悬空工具调用补齐与幂等)、subagentRunEventBus.test.ts补充(4,runId 冲突分配)
Changed
- SubAgent transcript 落盘改为节流合并:每次内容变更都要「读整份 conversation metadata → 改 → 写回」,而 metadata 里装着该对话全部 run 的完整 contents,一个多轮子代理跑下来会把同一份大 JSON 反复 parse/stringify 几十次;现在内容类写入按 1.5 秒窗口合并,run 状态变更(含所有终态)仍然立即落盘,落盘次数与真实时间挂钩而不是与 token 产出速度挂钩
- SubAgent Monitor 面板切到后台标签页时不再推送高频正文增量:
retainContextWhenHidden让面板隐藏后依然存在,于是每个流式 chunk 仍要走一遍 payload 清洗、manifest 派生、序列化和 postMessage,最终画在一个用户看不见的 UI 上;现在不可见时只丢弃llm_delta(run 状态、工具状态等低频事件继续推送),重新可见时补推一次 manifest 让前端自行校准窗口 - SubAgent Monitor 窗口刷新改为 revision 驱动:过去每个非
llm_delta事件(含完全不改 transcript 的 tool_started/tool_completed)都强制重拉一次完整窗口,高频调用工具的子代理会把窗口请求打成风暴;现在以 manifest 的contentRevision/contentCount作为唯一新鲜度判据,真正变化时才拉取 - 前端扩展消息分发改为单一全局分发器:过去每次
onMessageFromExtension都往 window 挂一个独立监听器,十几个组件订阅后,流式期间每个 chunk 都要走十几遍相同的分类逻辑;现在只保留一个分发器,消息只解析和分类一次 - SubAgent Monitor 顶部新增控制反馈与历史 run 只读标识:暂停/继续/退出失败时给出明确提示(后端同时回传该 run 是否仍被运行控制器持有,前端据此纠正按钮可见性),非活跃 run 显示「历史运行 · 仅可查看」徽标而不是让控制按钮整组无声消失
- 后台子代理回流改为轻量卡片:后台任务完成后不再作为普通用户消息渲染,而是在对话中显示为带
codicon-hubot图标和 "COMPLETED" 标签的紧凑卡片(左边框色条 + 浅色背景),与用户自己的消息视觉上明确区分;回执除元数据摘要(状态 / 步数 / 耗时)外仍内联子代理结果正文,超过 4000 字符时截断并提示剩余字符数与「可在 SubAgent Monitor 查看完整 transcript」 - SubAgent Monitor 顶部控制按钮文案改为与实际动作一致的「暂停 / 继续」:原「中止」(实为 pause)容易与同排的「退出并让主工具失败」混淆,原「重试」(实为 resume)会让用户误以为会重跑整个 run,实际只是从暂停处继续同一个 runId
Fixed
- 修复
execute_command的cwd参数在传入绝对路径时被path.join错误拼接到 workspace 根目录导致 "Working directory does not exist" 的问题:cwd解析逻辑新增path.isAbsolute()判断,绝对路径直接使用不再拼接 - 修复上游返回报错却只显示「模型返回空内容」的问题:这条链路上有三处都在丢信息。其一,OpenAI / Anthropic 两个 formatter 的
parseStreamChunk完全不认流里内联的错误(Anthropic 官方的event: error、兼容代理的{"error": {...}})——这类 chunk 没有choices/content_block,被当成空块跳过,累加器什么也没累加;其二,上游用非 JSON 的纯文本或 HTML 报错(网关 502、代理的纯文本错误)时,缓冲区里的内容在流结束时被静默丢弃,只报一句「没有响应体」;其三,formatter 主动抛出的ChannelError被外层无条件重新包装成PARSE_ERROR,把「上游返回 429」说成「解析失败」,还改变了重试判定。现在四个 formatter(含 Gemini / OpenAI Responses)统一走throwIfStreamError识别并归一错误、原样带出上游文案,非流式的parseResponse同样处理 HTTP 200 + 错误体,未能解析的原始响应作为rawResponse附在错误详情里,ChannelError直接透传不再被改写类型 - 修复流式中途取消后,下一次请求被 provider 以 400 拒绝的问题:取消时累加器里的部分内容会直接写进历史,其中可能已经包含完整的
functionCall,但对应的functionResponse永远不会补上,历史里就留下悬空的 tool_use;现在取消路径会就地结算这些调用——流式提前执行已经跑完的工具用真实结果(它们的写文件、跑命令等副作用已经发生,丢掉结果等于对模型隐瞒),其余标记为已取消 - 修复分段存储下悬空工具调用永远不被补齐的问题:
getMessages(全量)一直会把未响应的functionCall标记为 rejected 并补functionResponse,但getMessagesPaged的分段存储快路径直接返回窗口、跳过了这一步,而分段存储正是当前的主存储格式;现在首次加载(默认页)会先做一次全量补齐再分页,上拉加载更早消息时跳过以免每翻一页读一次全量 - 修复五个媒体工具(crop / generate / remove_background / resize / rotate image)的 abort 监听器泄漏,同时修掉一个更实际的缺陷:父信号在工具启动前就已中止时,
abort事件早已派发完毕,新挂的监听器永远不会触发,子信号会停留在未中止状态、工具照常跑完整个任务。现在统一由withLinkedAbort高阶包装器注入 AbortController——进入时若父信号已中止则立即同步中止,退出时无条件摘除监听器 - 修复子代理配置界面保存失败时 UI 假装成功的问题:
updateAgentField内部吞掉了错误,于是saveRename的失败分支成了死代码——后端拒绝保存(重名等)时编辑框照常关闭,用户看到的是「改成功了但值没变」;现在保存结果由返回值传递(模板里的@change不接 catch,抛出会变成 unhandled rejection),失败在顶部横幅明示,删除失败同样不再静默 - 修复子代理配置写入缺少校验:
createSubAgent不拦截空的type/name,updateSubAgent传空名称会跳过重名检查直接写入(agent 在选择器里变成看不见的条目);deleteSubAgent也不检查该 agent 是否还有正在跑的 run——配置一旦消失,run 结束后 Monitor 只剩一个查不到定义的孤儿 - 修复子代理 runId 撞车会覆盖内存快照的问题:runId 由主工具调用 id 推导,同一 toolId 二次执行时会重复,
createRun直接覆盖旧快照,而runController.register又把旧 AbortController 交给新 run,于是在 Monitor 里暂停其中一个会连带暂停另一个;现在冲突且旧 run 仍活跃时追加后缀(旧 run 已终态则沿用同名,前端在 pending 阶段正是按 toolId 推导 runId 关联工具卡的) - 修复子代理撞上下文上限时错误不可读的问题:子代理没有接主链路的
ContextTrimService,history 只增不减,工具结果一大、迭代一多就会撞上限,而用户只看到一句原样透传的AI call failed: ...;现在识别各家 provider 的上下文超限措辞,附上已迭代轮数、累积消息数和可操作的建议 - 修复自动总结在回合级 abortSignal 上累积监听器:
mergeAbortSignals在两个信号都没触发时监听器不会自行摘除,而abortSignal的生命周期是整个回合,一轮里多次自动总结会持续累积;现在返回 dispose 并在总结结束的 finally 中摘除 - 修复
MessageRouter.requestClients无上界增长:requestId → clientId的映射只在sendResponse/sendError时删除,但过去无论如何都先登记——未命中处理器而回退的消息、以及 handler 抛异常的请求都会留下永不清理的条目;现在只为确实由本 router 处理的请求登记,handler 抛出时就地清理 - 修复
sendToExtension无超时导致调用方永久 pending:「后端渠道配置已有超时」这个理由只覆盖 LLM 请求,任何因处理器异常、面板销毁等原因不回复的普通消息都会让调用方永远挂着,UI 上是一个再也不会停下来的加载态;现在非流式请求有 180 秒兜底超时(流式对话、依赖安装、存储迁移等长任务豁免,调用方也可显式覆盖) - 修复用户中止子代理后主聊天卡片「打开详情」按钮消失的问题:同步执行路径的取消分支和异常分支都只返回 error,不带
data.runId,而按钮可见性依赖 runId——run 明明已经真实创建并留下了 transcript,用户最需要进 Monitor 查看已完成部分时反而点不进去;现在两条路径都回填 runId、agentName 与已产出的部分响应 - 修复子代理每轮模型输出被重复写入 transcript 三次的问题:流结束后写一次、额外 emit 一次裸
content_snapshot、prompt 模式工具调用解析后再写一次,每次都递增contentRevision、广播事件、入队全量落盘,并让 Monitor 前端强制重拉一次窗口;现在统一由解析完成后的唯一写入口落盘,写入的是工具调用已还原为 functionCall 的权威版本 - 修复子代理在父 abortSignal 上累积 abort 监听器的问题:
maxRuntime > 0时挂上去的超时桥接监听器从不摘除,而父信号(主会话 AbortController)生命周期远长于单个 run,一轮对话里派发 N 个子代理就会永久累积 N 个监听器,触发 MaxListenersExceededWarning 且长期驻留内存;现在在 executor 最外层 finally 统一摘除 - 修复 SubAgent 暂停/继续循环在退出唤醒列表累积僵尸回调的问题:
waitUntilRunnable会同时向 resumeWaiters 和 exitWaiters 各注册一次 resolve,而 resume 只清空前者;现在合并为单一唤醒列表(退出原因本就由record.exitReason承载,旧 exitWaiters 的 reason 参数在调用点被忽略),注册与清空严格一一对应 - 修复事件 journal 长期引用已被替换的 contents 数组的问题:三个 transcript 写入口都把整份
snapshot.contents塞进content_snapshot事件 payload,该 payload 没有任何消费者(Monitor 面板一律从 snapshot 自行派生 contentCount),却让内存事件 journal 持有旧数组,replaceContents之后被替换掉的数组因此无法回收;现在事件只携带 contentCount,三个写入口共用同一个提交入口 - 修复 SubAgent Monitor 面板关闭后事件订阅仍留在扩展生命周期里的问题:
onDidReceiveMessage/onDidDispose过去注册到context.subscriptions,面板关闭后这些已失效的订阅不会被移除,反复开关 Monitor 会持续累积;现在改为面板级 disposables,随面板一次性清空 - 修复 SubAgent Monitor 消息处理异常导致前端请求永久挂起的问题:处理器抛异常时旧实现只打日志,带 requestId 的请求便永远收不到回复,前端那个 Promise 永久 pending——「加载更早消息」的 loading 状态再也不会结束,按钮永久转圈;现在异常统一转成错误响应回传,与主聊天路由的保底行为一致,前端同时把失败呈现为可重试的顶部提示
- 修复 SubAgent Monitor 切回此前查看过的 run 时显示过期内容的问题:窗口请求的早退条件只判断「有没有缓存」,缓存命中就直接沿用,于是切回去看到的是上次离开时的 transcript,要等下一个事件到达才刷新;现在与窗口刷新共用同一套 revision 新鲜度判据
- 修复扩展响应消息会被误当作主动推送消息投递给业务 handler 的问题:响应只会被第一个 window 监听器兑现(它随即删掉 requestId),其余监听器查不到该 requestId,就把这条响应交给了推送处理链路
- 修复 SubAgent Monitor「加载更早消息」失败后只留下一个未处理的 Promise rejection、用户看不到任何原因的问题后台调用的工具结果只是含
taskId/runId的派发 stub,主模型不会通过 functionResponse 拿到任何产出,回执消息是结果回流的唯一通道;而buildSubAgentSection基于「主模型已通过 functionResponse 拿到完整输出」的错误前提丢弃了response字段(该前提只对同步执行的子代理成立),导致后台派发的全部工作被静默丢弃。现在回执内联结果正文并按 4000 字符上限截断 - 修复子代理在超时 / 超出最大迭代次数 / AI 调用失败等早退路径下 run 状态永久停留在
running的问题:这些路径直接 return 裸结果对象,既不向事件总线广播终态事件也不携带runId,Monitor 中对应 run 永远显示为运行中;更关键的是主聊天工具卡片的「Open details」按钮可见性依赖result.data.runId,缺失时按钮恰好在子代理运行失败时消失,用户最需要查看 Monitor 排查时反而点不进去。现在所有返回路径统一经由finalizeRun收敛,补齐 runId 并在事件总线尚未进入终态时补发 run_completed / run_failed / run_cancelled - 修复每次子代理运行都泄漏一个常驻定时器的问题:
maxRuntime > 0时创建的 500ms 超时轮询setInterval只在父 abortSignal 触发时才清理,正常完成、失败、取消的 run 均不清理,泄漏的定时器会持续调用 checkTimeout 并在超过 maxRuntime 后反复 abort 已废弃的控制器;现在在 executor 最外层 finally 无条件清理 - 修复后台任务回执发送失败后结果永久丢失的问题:
flushReports先把任务乐观标记为reported: true再await sendMessage,发送抛异常时标记不回滚,该任务再也不会被补发;现在捕获异常并回滚标记,等待下一次 flush 时机重试 - 修复 SubAgent Monitor 面板始终以中文渲染、不跟随语言设置的问题:Monitor 复用同一前端入口,但
onMounted在 Monitor 模式下直接 return,跳过了loadLanguageSettings(),导致面板内已国际化的 MessageItem / ToolMessage / 各工具卡全部回退到默认中文;英文与日文用户看到的子代理详情是混合语言 - 修复后台派发的子代理工具卡片显示为「成功」的问题:卡片按
result.success判定状态,而后台调用的 stub 结果恒为 success,导致子代理刚进入队列卡片就显示绿色成功态,且运行完成后卡片里永远看不到产出;现在后台卡片跟随 backgroundTaskStore 中对应 taskId 的真实任务状态,并回填结果正文、错误与步数,同时标记「后台」chip - 修复 SubAgent Monitor 消息区底部内容被裁切的问题:滚动容器写死
max-height: calc(100vh - 96px),该值与外层 flex 布局冲突且未计入 run tabs 行、重试状态行的实际高度,多个并发 run 时滚动区会溢出视口;现在移除该覆盖,交由flex: 1精确分配剩余空间 - 修复调大子代理并发上限后排队中的 run 不会立即启动的问题:
drainQueue仅在 release 时触发,maxConcurrentAgents的「立即生效」语义实际要等到某个运行中的 run 结束才成立;新增onCapacityChanged入口由设置更新处调用 - 修复请求在进入流式前就失败时后台任务回执不被补发的问题:
flushReports的忙闲判断同时看isStreaming与isWaitingForResponse,但补发只监听前者,isWaitingForResponse单独由 true 转 false 时不会触发补发,挂起的回执要一直等到下一次流结束或切换会话 - 修复子代理 transcript 的
updateLastModelContent写入口不落盘的问题:三个写入口中仅此路径不入队持久化,持久记录的contentRevision会落后于内存快照,扩展在 run 进行中重载时最后一轮模型输出无法恢复 - 修复用户新建子代理时选择预设模板(如"代码审查者")必定报错
Failed to execute 'postMessage' on 'MessagePort': [object Object] could not be cloned.的问题:前端createAgent()中预设模板对象来自 Vueref响应式数组,其嵌套对象(tools等)为 Proxy,无法被vscode.postMessage的 structured clone 序列化;修复方式为发送前通过JSON.parse(JSON.stringify(payload))解包所有响应式代理 - 修复模型频繁幻觉"用户附加了 新建文件夹 (10).zip"的问题:system prompt 的
CONTEXT BADGE FORMAT示例硬编码了新建文件夹 (10).zip这个看起来像真实用户文件的名称,模型将示例中的文件名误判为实际附件;三处默认值(PromptManager.ts/PromptSettings.vue/settings/types.ts)统一替换为example-report.pdf (example)并标注(example) - 修复上游 API 错误消息被吞掉:非 200 响应现在从 Anthropic/OpenAI/OpenRouter 通用
{error:{message}}格式提取具体错误消息,前端错误面板直接显示如HTTP 429: Provider returned error,不再仅展示无信息的 HTTP 状态码 - 修复 write_file 新建文件被用户拒绝或中断后磁盘残留空文件的问题,拒绝/取消时自动删除原先创建的空文件
- 修复命令执行期间无法继续对话的问题:前台命令现在支持运行时转移至后台(detach),用户发送新消息时自动触发;SendButton 在响应期间仍保留发送入口,消息以排队方式进入队列,命令结果稍后以回执消息回流唤醒模型
- 修复应用差异/写入代码后用户光标跑进代码编辑器的问题:关闭 diff 标签页的
tabGroups.close未传preserveFocus,关闭活动标签后 VSCode 激活相邻编辑器并把光标带进去;现在 diff 应用/拒绝(diffManager)与检查点回档清理 diff 视图(CheckpointManager)均保持焦点原位 - 修复关闭 diff 标签后聊天输入框仍会失焦的问题(
preserveFocus只能阻止焦点跳进编辑器,无法阻止 workbench 把焦点从侧边栏 webview 收走):新增焦点守卫chatFocusGuard,前端输入框通过chatInput.focusState消息上报焦点状态,扩展端在关闭 diff 标签前采样、关闭后若输入框此前持有焦点则执行graycode.chatView.focus归还 webview 焦点并推送chat.restoreInputFocus命令让光标回到输入框;焦点在编辑器/终端等其他位置时不干预,连续关闭多个 diff 的 blur 上报竞态由 1.5s 宽限期兜底 - 修复流式提前执行工具的多模态附件(
multimodalAttachments)从未被写入历史的问题:xml/json 模式下提前执行的 generate_image / MCP 图片结果不再静默丢失,提前执行与串行执行两条路径的附件统一合并后随函数响应写入 - 修复流式边执行工具可能被重复执行的隐患:
getNewCompletedFunctionCalls改用稳定工具调用 id 去重(原 parts 数组索引在结构调整时会漂移,导致同一工具被重复上报并重复执行);无稳定 id 的调用交给最终统一执行路径兜底 - 修复 XML 工具调用
<tool_name>带属性时工具名以对象形态流入执行层导致查找必然失败的问题(提取#text并校验为非空字符串) - 修复 XML 工具调用带属性的纯文本参数节点(如
<content lang="en">xxx</content>)内容整个丢失变{}的问题:无子元素时#text文本内容作为参数值本身保留 - 修复 write_file / apply_diff 等写入工具打开 diff 预览时强制抢占键盘焦点的问题(
preserveFocus改为 true),用户输入框未完成内容不再意外掉入代码文件 - 修复检查点回档后存档点消失无法二次回档的问题:回档流程在删除消息时保留刚用于恢复的存档点及其增量基链,新增
preserveCheckpointId参数贯穿前端 store → webview handler → ChatFlowService → CheckpointService → CheckpointManager 全链路 - 修复聊天消息列表右侧滚动条在长对话、工具卡片和流式输出场景下抽搐、跳位的问题
- 修复用户消息滚动条标记在滚动过程中可能消失的问题,保留已加载消息窗口内的用户消息标记和预览文本
- 修复 search_in_files replace 模式下「实际已替换但报告未找到匹配」的 false positive:匹配统计从逐行 exec 改为全文 exec,与
String.replace语义对齐,消除跨行正则的漏报 - 同步上游 search_in_files / history_search 正则诊断能力:非正则零命中时识别疑似正则查询并提示显式启用 isRegex / is_regex,避免
foo|bar、ssh.*root、38\\.12等查询被静默按字面量搜索 - 修复 apply_diff / insert_code / delete_code 在工作区外且 autoSave 开启时,用户手动确认工具调用后仍需等待 diff 自动保存计时器的问题,现在确认后直接应用保存
- 修复 MCP 工具名包含双下划线时前端解析错误的问题
- 修复 Anthropic 流式请求未从
message_start事件提取并传递modelVersion,导致落盘消息缺少模型版本字段、用量统计「按模型」维度所有 Anthropic 用量被归类为 unknown 的问题 - 修复 Anthropic 渠道在部分第三方代理(OpenRouter、one-api 等)下无法正确获取 token 用量的问题:统一 usage 提取逻辑,覆盖 message_start / message_delta / message_stop 三个流式事件;新增 thoughtsTokenCount 提取(output_tokens_details.thinking_tokens),区分思考 token 与输出 token;非流式响应复用同一提取逻辑,消除重复代码
- 删除 openai formatter 流式热路径上的
console.log调试残留(每收到 tool_call 分片即 JSON 打印),降低长参数场景下的日志刷屏与 CPU 消耗 - 修复提示词模式导入时工具策略过滤的 TypeScript 类型问题
- 修正历史页头部「用量统计」与「返回聊天」按钮的样式类名语义(close-btn → header-btn,与用量页命名对齐)
- 修复 esbuild 在 pnpm symlink 环境下重复构建时
cpSync抛出 EEXIST 的错误:copyNativePackages先 rm 旧目标再 dereference 复制真实文件 - 修复 esbuild 只复制
node-notifier自身而未带上传递依赖(growly/semver/uuid/which/shellwords/is-wsl/is-docker/isexe),导致 vsix 安装后运行时require找不到模块 - 修复 webview(ChatViewProvider / SubAgentMonitorPanel)中 codicons CSS 引用指向
node_modules/@vscode/codicons,经过.vscodeignore排除后打包丢失,界面图标全部消失;引用改为包内自带的resources/codicons - 修复 jest 配置依赖被
.gitignore排除的test/目录导致干净环境npm test无法运行的问题:移除.gitignore中对test/的排除,19 个原有测试文件入库 - 修复
typescript/undici-types被错误放置在dependencies而非devDependencies的分类问题 - 修复
backend/tools/skills/readSkill.tshandler 参数类型不兼容ToolHandler的问题(strictFunctionTypes 暴露) - 修复
backend/modules/channel/StreamAccumulator.ts18 处text/functionCall可能为undefined的类型错误(strictNullChecks 暴露) - 修复
backend/modules/channel/ChannelManager.tstimeoutId未初始化被引用的错误 - 修复 MCP stdio 连接失败时子进程永不回收泄漏进程树的问题:connect 外套 try/catch,失败时 await disconnect() + 从管理 map 移除
- 修复 Windows 上 MCP kill() 只杀 cmd.exe 真正 server 进程逃逸的问题:StdioClient 改用 tree-kill 杀整棵进程树(复用项目已有依赖),等待进程真正退出后再 cleanup
- 修复 MCP 连接进行中的 delete/disable/disconnect 全部落空进程成孤儿的问题:client 提前在 connect 之前 eager 注册进管理 map
- 修复 MCP HTTP/SSE 传输超时只覆盖响应头、SSE 正文无限等待无法取消的问题:SSE 读取循环内添加 idle-based 空闲计时器,超时 cancel 底层流避免误杀合法长任务
- 修复 MCP stdout 按 chunk 调 Buffer.toString() 截断多字节 UTF-8 工具结果静默损坏的问题:spawn 后立即 setEncoding('utf8'),移除逐 chunk toString
- 修复 MCP validateServerId 允许双下划线违反 mcpToolNameCodec 解析前提的问题:提取 MCP_SERVER_ID_PATTERN 为唯一事实源统一校验
- 修复 MCP cleanSchema 开关不被持久化每次重载静默回到 true 的问题:storage 读写持久化 cleanSchema 字段
- 修复 MCP stdio 传输完全忽略用户配置 timeout 硬编码 30 秒的问题:构造函数加 timeout 参数并贯穿到 sendRequest
- 修复 SSE 缓冲区解析对非 SSE 格式的误判:
buffer.includes('data:')改为按行判定(只有存在以data:开头的行才算 SSE),避免 JSON 错误体恰好包含该子串时被整块丢弃 - 修复 HistoryIntegrityValidator 不检测悬空 functionCall 的盲区:新增
orphan_function_call检测(由detectOrphanFunctionCall选项控制),ChannelManager 前置校验启用,裁剪/总结等切片调用跳过以避免配对断裂假阳性——这种悬空调用会导致 Anthropic/OpenAI 直接 400 - 修复 calculateThreshold 把 "0%" 解析为 80% 最大上下文的 bug:
percent > 0放宽为percent >= 0(使 "0%" 合法),新增fallbackRatio参数使额外裁剪调用在非法值时回退到 0 而非 0.8,防止一次裁剪清空整段对话;targetTokens 为 0 时记 debug 日志 - 修复 countAndUpdateMessageTokens 的精确计数结果被丢弃,accumulateTokens 退化到粗估(chars÷4)的问题:捕获
Promise.all的第二个返回值并回填 fullHistory 快照,使本轮裁剪判定读到刚算好的精确 token 数 - 修复 ConversationManager.types 缺失
usageMetadataPartial标记:流被中断时 usageMetadata 只覆盖已收到 chunk 的 token 数(可能严重偏低),现在打显式标记供上下文裁剪和用量统计回退到估算 - 修复
applyDiffToContent使用String.replace拼接时 replacement 文本里的$&/$`` /$'/$$` 被当作替换模式展开导致静默写坏文件的问题:改为基于索引的切片拼接完全绕开 replacement 模式语义 - 新增 ConversationManager.settleFunctionResponses:用真实工具结果就地覆盖 cancelStream 提前写入的「用户拒绝」占位,同时清除对应 functionCall 的 rejected 标记;handleToolConfirmation 的持久化上移到 abort 检查之前以阻止真实副作用结果被丢弃
- 删除 OrphanedToolCallService 死代码:retry_stream 路径上 rejectAllPendingToolCalls(995 行)已将所有悬空调用标记为 rejected 并补 functionResponse,紧随其后的 checkAndExecuteOrphanedFunctionCalls(998 行)永不触发——删除该服务文件、ChatFlowService/ChatHandler 注入点与 services/index 导出
- 修复
backend/modules/channel/proxyFetch.tsAbortSignal | null无法赋值给AbortSignal | undefined的类型冲突 - 修复
backend/modules/checkpoint/CheckpointManager.tstargetState可能为undefined的错误(添加非空断言) - 修复
backend/modules/conversation/ConversationManager.ts与helpers.ts中cleanedResponse返回类型可能为undefined的问题 - 修复
backend/modules/conversation/functionCall.tsThoughtSignatures与Record<string, string>类型不兼容问题 - 修复
webview/handlers/SettingsHandlers.tssyncLanguageToBackend可能为undefined的调用错误 - 修复
webview/handlers/ToolHandlers.tsserverTools.tools可能为undefined的空值访问 - 修复
webview/ChatViewProvider.tsinitializeSubAgents构造 HandlerContext 缺漏必填字段导致类型不匹配 - 修复
backend/tools/progress/validate_progress_document.tspath重复声明与ProjectProgressToolResultOptions参数缺漏问题 - 修复
backend/tools/search/search_in_files.tsreplacement参数可能为undefined传递给替换引擎的类型错误 - 修复
backend/tools/terminal/execute_command.tsactiveProcessesMap 在getActiveTerminalProcesses中类型退化为never[]的问题 - 修复
backend/modules/settings/SettingsManager.tsProxySettings更新 spread 合并后类型不完整的问题 - 修复
backend/modules/settings/VSCodeSettingsStorage.tslegacySettingsDir可能为undefined的赋值错误 - 修复
backend/tools/media/remove_background.tsdimensions返回值null与接口undefined类型不兼容问题 - 修复
webview/types.tsHandlerContext 中chatHandler/modelsHandler/checkpointManager/getCurrentWorkspaceUri错误标记为可选字段导致 20+ 处判空不一致(改为必选) - 修复
extension.ts中newChat/showHistory/showSettings命令回调未对chatViewProvider判空的不一致(统一改为可选链) - 修复 selection hover 与 code action 只注册
scheme: 'file',未涵盖untitled未保存文件的问题 - 清理
.tmp/目录中 80+ 个上游同步遗留物(diff patch、python 脚本、旧版文件副本) - 删除
package.json中指向不存在文件的test:diagnose-execute-command-order脚本 - 彻底修复用户在聊天输入框打字时 AI 写入/修改文件导致焦点丢失的问题:diff 预览不再打开多余的文件本体 tab(
showTextDocument+editor.edit改为WorkspaceEdit直接修改文档,每次写入从两个 tab 减为一个 diff tab) - 修复 diff 自动保存/检查点回滚时 revert 操作切换活动编辑器抢占用户焦点的问题:
workbench.action.files.revert改为传显式 URI,删除三处(diffManager 两处 + CheckpointManager 一处)showTextDocument前置步骤 - 修复 search_in_files 的 search 与 replace 模式大小写语义不一致(
gimvsg)导致“搜索命中但同一 query 替换 0 命中”的问题(新增 caseSensitive 参数 + 诊断提示) - 修复 search_in_files replace 模式文件级异常被静默吞掉的问题:diff 创建/审阅/写入失败、超大文件跳过、“有匹配但替换无变化”等情况现在通过
skippedFiles: [{file, reason}]明确返回,模型能区分“没匹配”和“处理失败” - 修复 search_in_files 多工作区 replace 时 maxFiles 扣减语义漂移的问题(按实际处理文件数而非产生修改的文件数扣减)
- 修复 XML 工具模式下 fast-xml-parser 自动类型转换破坏字符串参数的问题(
"1.10"→1.1、纯数字文件内容变 number):parseTagValue/parseAttributeValue关闭,类型还原交给 schema 驱动的递归 coerce 层 - 修复模型多传无害未知参数导致整个工具调用失败、白白浪费一轮迭代的问题:未知参数改为剥离 + 警告回传,仅必需字段缺失或类型无法修复时才真正报错;顺带清理 validateToolArgs 死代码分支
- 修复流式期间早启动执行的工具(含 execute_command)不创建任何检查点的问题:早启动路径现在把检查点正确挂到即将写入的模型消息索引上,回滚不再缺档
- 修复 insert_code / delete_code / search_in_files(replace) 在自动应用关闭时被聊天确认框 + diff 审阅双重确认的问题
- 修复 write_file / apply_diff 在自动应用开启后仍需在”自动执行”页单独勾选才能真正自动的双重配置问题:diff 审阅类调用一律不再叠加聊天确认,确认行为的唯一数据源是 Apply Diff 工具设置(autoSave / 延迟 / 跳过差异视图);工作区外 ask 策略的安全确认优先级不变
- 修复 proxyFetch 流式取消后生成器可能永久挂起的问题:新增
closeSocketGracefully统一优雅关闭 socket(先 FIN 后 destroy 超时兜底),onAbort 与 finally 共用避免定时器泄漏与重复代码 - 修复代理握手阶段取消泄漏隧道 socket:
proxyReq.destroy()仅在 CONNECT 未完成时有效,connect 之后的隧道 socket 现在在finishReject一处统一清理 - 修复代理 URL 认证信息被丢弃、https 代理按明文 80 端口连接的问题:新增
parseProxyLeg共享 helper 正确解析 https/http 协议、默认端口与 Basic 认证头 - 修复代理流式非 2xx 错误体取到半截/未解 chunk 框架字节的问题:累积错误体字节并按 transfer-encoding 正确解 chunk 框架后再构造 ChannelError
- 修复非流式代理响应每 data 事件全量 Buffer.concat + utf8 解码导致的 O(n²) 问题:改为
chunks[]+receivedLength增量维护,完成判定时一次性 concat - 修复代理隧道中途断开时截断响应当成功返回的问题:socket close/end 路径上按 contentLength 或 chunked 终止块判定 body 完整性
- 修复 CheckpointManager
computeFileHashes方法被调用但缺失实现导致整个测试套件编译失败的问题:实现增量哈希(stat mtime+size 不变时复用旧哈希) - 修复增量链断裂后 restore 静默降级为部分恢复仍返回 success 的问题:
getIncrementalChain返回{ chain, broken },broken 时显式失败 - 修复 restore 会删除检查点从未备份过的工作区文件的问题:删除集合只包含
fileHashes中记录的路径,不删快照时被 ignore 的文件 - 修复 restore 无法恢复的文件被静默跳过仍返回 success 的问题:四类失败场景(missing_in_chain/hash_mismatch/copy_failed/delete_failed)显式收集并体现在返回值中
- 修复备份复制失败被吞掉但 fileHashes 声称已备份的问题:复制失败从 fileHashes 剔除 + 恢复侧 detect missing_in_chain
- 修复检查点元数据写入失败返回幽灵检查点并泄漏备份目录的问题:save 失败 rethrow + catch 中回收 backupDir
- 修复每个检查点全量 MD5 整个工作区(每次工具调用两遍扫描)的问题:stat 增量哈希 + 避免 createCheckpoint 重复扫描
- 修复导入设置时 VSCode 配置被无条件整块覆盖、无视用户选择「跳过已存在项」的问题:导出侧移除 machine-local 键 + 导入侧按合并策略跳过已有项
- 修复渠道配置导入丢弃原始 id 导致 activeChannelId 悬空与重复导入产生重复渠道的问题:getImport 改为保留原始 id
- 修复导出/导入包含 machine scope(proxy/storagePath)跨机器导入打断网络与数据目录的问题:新增
MACHINE_SCOPE_KEYS常量统一定义,导出与导入两端过滤 - 修复内置提示词模式自定义 toolPolicy 每次读取被强制回滚并落盘的问题:getter 移除隐式变更,新增
toolPolicyCustomized标记区分「未定制」与「主动定制」,迁移显式幂等 - 修复导入 Skill 用未校验 id 拼路径、导出文件可写任意目录的问题:skill id 校验收敛到 SkillsManager 单一来源 + resolve 后边界断言防路径穿越
- 修复 collectVSCodeSettings 用 defaultValue 兜底把包默认值当用户值导出固化的问题:去掉 defaultValue + 补 workspaceFolderValue 三层解析
- 修复导入后 initialize() 不触发变更事件导致 PromptManager 缓存过期的问题:新增
reloadAndNotify()重新加载并广播 type:full 变更事件 - 修复 rejectToolCalls 拒绝响应插入位置错误导致 tool_result 与 tool_use 顺序错乱的问题:新增
findFunctionResponseInsertIndex跳过同批次已有响应 - 修复 markUserInterrupt/cancelAllPending 全局中断 A 会话强杀 B 会话 pending diff 的问题:中断语义改为按 conversationId 隔离
- 修复 VSCode files.autoSave + pending diff = 死循环(每 autosave tick 全量回写磁盘)的问题:willSave 改为标记
nonManualSaveFlushed直接落盘不再触发回写循环 - 修复 pendingDiffs/diffSessions 条目永不删除内存泄漏的问题:新增
finalizedDiffOrderFIFO 队列 +MAX_FINALIZED_DIFFS=50延迟淘汰 - 修复关闭标签页拒绝新建文件 diff 后磁盘残留空文件的问题:抽取
closeDiffTabAndCleanNewFile统一关 tab + 删残留 - 修复 directApplyAndSave fallback 打开 diff 视图 original 侧为空且无 CodeLens 的问题:contentProvider.setContent 改为无条件执行,addSession 保持懒注册
- 修复 Close 监听器吞掉文件读取失败导致 diff 永久 pending 的问题:catch 到读文件失败时按 reject 收敛 diff
- 修复 newFile 标记在 createPendingDiff resolve 之后才设置导致 showDiffView 期间取消泄漏空文件的问题:改为通过 CreatePendingDiffOptions 传入提前标记
- 修复 MarkdownRenderer 未标注语言代码块每次渲染 hljs.highlightAuto 遍历 192 种语法导致流式期间主线程秒级冻结的问题:完全无标注的跳过高亮,有标注但不识别的走缓存
- 修复 mermaid 代码块 fence 原文未转义拼进 HTML 造成 v-html 注入执行且绕过 artifactSafe 配置的问题:源码插入 HTML 前 HTML 转义,渲染走 DOM API
- 修复默认档位 html:true 产物未经净化直接 v-html,模型正文原始 HTML 可在 webview 内执行脚本的问题:新增
sanitizeHtmlDOM 净化器(去危险标签+事件+js 协议),非 artifactSafe 档位启用 - 修复后处理完成标记在 await 后读 props.content 叠加 isMermaidRendering 提前返回导致 mermaid/图片永久不渲染的问题:renderMermaid 改 promise 串行化 + scheduleRender 快照校验
- 修复 markdown-it 实例/文件缓存/图片缓存每个消息块各造两份的问题:提升到模块级单例跨消息共享
- 修复 renderLatexOnly 行内正则缺空格护栏导致货币金额
$5 to \$10被当公式渲染的问题:正则新增(?!\\s)...(?<!\\s)首尾空白护栏 - 修复消息队列串行等待长任务导致总结中「取消总结」永不执行、整条 webview 消息通道冻结的问题:MessageRouter 新增 NON_BLOCKING_MESSAGE_TYPES,fire-and-forget 不占住队列
- 修复 saveImageToPath 未做工作区包含校验、webview 消息可用
..覆写工作区外任意文件的问题:新增isUriInsideWorkspace路径包含性 helper,越界拒绝并回错误 - 修复 extension.ts deactivate 未摘除 DiffManager 状态监听器导致停用过程中复活已 dispose provider 单例永久泄漏的问题:监听器提为模块级,deactivate 最前面同步摘除
- 修复 ChatViewProvider 每次重建视图追加 diff 状态监听器旧的不摘除的问题:新增
viewDisposables数组每次 resolve 清空并重新注册 - 修复 ToolMessage onMounted 内 await 后注册的 onBeforeUnmount/watchEffect 全部失效、每个实例永久泄漏 2 个全局消息订阅者的问题:生命周期注册搬到同步 setup 作用域
- 修复每个 ToolMessage 为全局 pending diff 启动自动保存倒计时、N 个组件到点同时发 diff.accept 的问题:倒计时提升为模块级单例按 sessionId 去重
- 修复 ToolMessage 内联箭头函数组件
<component :is=”()=>renderToolContent(tool)”>每次渲染换 vnode type 导致展开面板整棵卸载重建的问题:用 defineComponent 创建恒定 ToolContentHost - 修复未完成工具每个 chunk 触发全量消息线性扫描、enhancedTools 订阅整个消息列表的问题:toolResponseCache 改造为随写入维护的 O(1) 权威索引
- 修复后台派发 subagents 工具卡头部状态恒为「成功」、后台任务失败仍显示绿色对勾的问题:新增
computeTaskCardStatus单一数据源 helper,头部与卡片共用 - 修复 diff 孤儿宽限期 Date.now() 判定但无重估调度导致超时纠正分支不可达的问题:补 setTimeout 到达宽限期触发 computed 重求值
- 修复排队消息在流出错/取消后永不重发、输入框进入死循环的问题:cancelled/error 分支补齐
nextTick(processQueue) - 修复 sendMessage 在多次 await 后重读 currentConversationId 导致消息被发进另一个会话的问题:固化 targetConvId + 写 state 前归属校验
- 修复 switchConversation 在 await 后无条件覆盖 allMessages/checkpoints 把 A 历史灌进 B 视图的问题:每个 await 后 validateSessionIdentity 守卫
- 修复 switchConversation 不清空 messageQueue 导致排队消息被自动灌进新会话的问题:清理块追加清空 + QueuedMessage 加 conversationId 字段 processQueue 校验
- 修复 deleteMessage/retryFromMessage 在 await cancelStream() 后才算索引可能截断另一个会话历史的问题:await 前固化索引 + await 后校验未变
- 修复 sendMessage 吞掉发送异常导致后台任务回执乐观标记回滚永不生效的问题:改返回
Promise<boolean>+ backgroundTaskStore 按返回值回滚 reported - 修复切换标签页恢复快照不重置 toolResponseCache 导致工具响应全文永久驻留内存的问题:纳入 ConversationSessionSnapshot 按会话存取
- 修复 loadOlderMessagesPage prepend 了会话 A 历史到会话 B 的问题:锁定请求发起时对话身份 + await 后校验
- 修复 loadMore scroll-anchor fix-up 在 finally 把上一标签页几何应用到新标签页的问题:归属校验 + finally scroll 恢复仅在归属未变时执行
- 修复 Message windowing 失效每个 loaded message 在每个 chunk 被重新 enhance/重排的问题:resolveLoadedVisibleMessages 恢复尾部窗口切片
Improved
- SubAgent Monitor 未打开时不再为不可见 UI 支付流式序列化成本:事件总线订阅在面板关闭后依然存在,
postEvent过去对每个llm_delta都完整执行 payload 白名单清洗、manifest 派生与 activeRunIds 收集,再在postRoutedMessage中因没有 panel 被整个丢弃;现在无活跃面板时直接短路 - 子代理 manifest 预览派生从 O(消息长度) 降为 O(预览长度):
extractContentPreview过去先把整条消息的全部 parts 拼成完整字符串再截断到 160 字,而 manifest 会在每个llm_delta事件上重新派生,上一轮若是数万字符的模型输出则每个增量都要重跑一次全量拼接;现在逐 part 累积、超过上限立即停止读取 - 子代理 transcript 持久化写入合并:
enqueuePersist过去为每一次 transcript 变更都排一次完整的「读元数据 → 改 → 写回」,流式期间队列被同一 run 的连续写入撑满;现在用脏标记合并尚未开始执行的排队写入(写入前清除标记,写入期间的新变更会正常排下一次),同一 tick 内 30 次变更由 30 次落盘降至个位数 - 子代理运行时内存改为有界:单个 run 的内存事件 journal 上限 500 条(超出丢弃最旧),事件总线内存快照上限 200 个 run;淘汰只作用于「已进入终态且已持久化到 conversation metadata」的 run,运行中的 run 与无持久化归属的 run 永不淘汰,被淘汰的 run 仍可通过
loadConversationSnapshots从元数据恢复查看 - 修正子代理组合中止信号的监听器生命周期:
createOperationSignal过去把 abort 监听器永久挂在父 abortSignal 与 run 控制器信号上且从不摘除,一个 20 轮带工具调用的 run 会累积上百个监听器并触发 Node 的 MaxListenersExceededWarning;现在返回 release 句柄,由每次 LLM 调用与工具调用在 finally 中摘除,信号生命周期与单次操作对齐 - 后台任务状态条的 1 秒计时器改为按需启停:
now只被运行中任务的耗时显示消费,但 ticker 过去在组件整个生命周期内无条件运行,没有任何后台任务时也会每秒触发一次响应式更新与重渲染,且持续整个 VS Code 会话;现在按runningCount启停 - SubAgent Monitor 新增实时输出自动跟随:作为实时监视面板过去从不跟随新内容,用户必须持续手动下拉才能看到子代理正在输出什么;现在复用主聊天 MessageList 的贴底判定,贴底时随尾部内容增长自动滚动,用户向上翻阅历史后不再被拽回底部;尾部指纹使用消息的全局 index 而非窗口内数组长度,因此「加载更早消息」向前 prepend 不会误触发跳底
- SubAgent Monitor 界面文案接入 i18n(zh-CN / en / ja):标题、副标题、run 计数、空状态、已加载条数、加载更早、控制按钮、自动重试状态与全部 8 个 run 状态(queued / running / paused / awaiting_monitor_action / completed / failed / cancelled / interrupted)此前均为硬编码中文
- 流式热路径 O(n²) 性能优化:StreamAccumulator 新增结构修订号
contentRevision(仅在新 part 入列、工具参数解析完成等结构性变化时递增),StreamResponseProcessor 据此决定是否下发 contentSnapshot,移除每个 chunk 全量重建 Content + 逐 partJSON.stringify深比较 + 尾部大文本startsWith比较;长回复/大参数工具调用场景 CPU 开销显著降低,thinkingStartTime也改为直接从累加器读取 - 删除 StreamAccumulator 旧解析路径
extractAndConvertToolCalls:json/xml 模式下每次文本合并都全量重扫所有 parts(O(n²)),职责早已由 IncrementalPromptToolParser 在入口处全量接管;顺带修正 thought 文本中的工具标记被误当真实调用的行为(与 ToolCallParserService 跳过 thought 的语义对齐) - jsonFormatter 边界标记正则预编译为模块级常量,
hasCompleteJSONBlock/parseJSONToolCalls不再每次调用重新转义拼接 - 清理 ToolIterationLoopService 流式提前执行结果收集中被后续整体覆盖的
earlyResponseParts.push死代码 - 优化自定义滚动条的尺寸、内容和 marker 更新时机,合并到浏览器渲染帧中处理,降低重复布局计算导致的抖动
- 历史 / 用量 / 设置三个页面从 v-if 互斥渲染改为惰性挂载 + v-show 保活:首次访问才创建组件(不影响首屏),切换视图不再丢失滚动位置和表单编辑状态;用量页保活后重新进入时自动刷新统计
- MarkdownRenderer 的 mermaid 图表库改为按需动态导入:首屏 bundle 不再包含 ~1MB 的 mermaid,仅在内容中出现 mermaid 代码块时才加载
- 优化 search_in_files 替换结果的 diff 预览,仅折叠大段未变化内容并保留变更附近上下文
- search_in_files 工具结果面板新增查询诊断展示,直接显示 suspected_regex、关键词兜底和疑似多个 path 的纠错建议
- 同步上游 search_in_files / history_search 多关键词搜索兜底:非正则搜索先匹配完整短语,零命中后再尝试空格分隔关键词,提高自然语言式关键词输入的召回率
- 优化 history_search 与 execute_command 的工具描述,减少历史读取、正则搜索和工作目录参数误用
- 增强 execute_command 的 cwd 工作目录说明,明确单根/多根工作区相对路径、workspace 外绝对路径和避免在 command 中嵌入 cd 的规则
- 主聊天接入 functionCallMerge,统一流式工具调用的 itemId/index/finalArgs 合并逻辑,降低重复工具卡、空参数工具卡和分片参数错位问题
- diff 预览按钮迁移到 ToolConfig.actions,移除 ToolMessage 对 hasDiffPreview/getDiffFilePath 的旧特判依赖
- read_file 前端组件适配 path 参数,支持 startLine/endLine 行范围显示
- resolveUri / resolveUriWithInfo 增强绝对路径处理,自动匹配所属工作区
- 实现 Anthropic 渠道配置验证(
validateAnthropicConfig),替换原有的 TODO 占位:校验 URL / apiKey / model / temperature(0-1) / max_tokens / top_p / top_k / thinking.budget_tokens(>=1024),新增对应 i18n 键 - 用量统计的前端类型抽取到共享文件
frontend/src/types/usage.ts(与后端usageStats.ts聚合结构对齐),不再手写在组件内 - 补齐用量页新功能的 i18n 文案(zh-CN / en / ja,时间范围 / 单价编辑 / 估算成本 / 对话跳转等 11 个 key)
- 重构 SettingsManager 工具/模块配置的 getter/update 方法:新增私有
getToolsConfigEntry/saveToolsConfigEntry泛型帮助方法统一 22 组样板逻辑的 merge-保存-通知流程,文件从 2447 行缩至 2063 行,公开 API 不变 - 重构前端五个媒体工具展示组件(crop / resize / rotate / remove_background / generate_image):提取共享骨架
MediaToolPanel.vue和类型模块mediaToolTypes.ts,五个组件从合计 4394 行缩减为 1744 行(净减约 2650 行),主题色/任务解析/取消通道等差异参数化;补充 crop/resize/rotate 三面板的tasksFailed三语 i18n 键 - i18n 类型定义从手写接口(frontend 3075 行 + backend 714 行)改为从基准语言包(zh-CN)
typeof推导,新增翻译键只需修改语言文件即可,en/ja 因保留LanguageMessages类型标注会在结构不一致时 typecheck 报错 - todo 工具清理
(context as any)类型逃逸和require()双重导入:直接使用ToolContext已有的conversationStore/conversationId类型字段,index.ts 改为静态 import - 清理 ToolMessage.vue 中的重复 toolId 排查调试代码(debugToolOnce / isPerfEnabled / console.warn),约 30 行临时代码
- 4 处空 catch 块补日志:ToolIterationLoopService 两处移除冗余 try/catch(Logger 自身已安全序列化)、StreamAccumulator 一处添加英文注释说明流式 JSON 不完整是正常现象、SettingsHandlers 一处 catch 读版本失败时输出 console.warn
- backend/webview 共 53 处
console.log/console.debug统一迁移到结构化Logger(含通知模块 31 处、ChatViewProvider 8 处、DiffStorageManager 6 处、CheckpointManager 3 处、DependencyManager / ToolExecutionService / ModuleRegistry 等) - 通知模块(WindowsAgentStopNotificationService / WindowsToastAdapter / NotificationHandlers)移除模块级
LOG_PREFIX常量,改用Logger.get()实例化命名日志器 extension.ts中console.log/console.error全部替换为Logger.get('extension')统一日志输出esbuild.config.js新增--watch参数支持(使用esbuild.context().watch()),内置 rebuild 日志插件;package.jsonwatch 脚本从无用的tsc -watch改为node esbuild.config.js --watch- esbuild
copyNativePackages重写为递归复制 + 循环依赖保护,确保 external 原生包的所有传递依赖被打进dist/node_modules,模拟安装后加载验证全部通过 package.jsonengines.vscode 从^1.74.0升级到^1.84.0,与 esbuild targetnode18和@types/vscode ^1.84.0保持一致,消除运行时 API 版本不匹配风险.vscodeignore移除不存在的旧版 jest 配置条目(jest.config.cjs / tsconfig.jest.json),保留实际存在的jest.backend.config.js和tsconfig.test.json.vscodeignore的*.map改为**/*.map,覆盖子目录 sourcemap;新增排除入口源码文件extension.ts、index.ts;清理过时的!node_modules/node-notifier例外规则(运行时依赖已移入dist/node_modules)- webview 的
localResourceRoots移除node_modules/@vscode/codicons条目,统一到resources/根目录 package.jsonlicense 字段从ISC改为MIT,与仓库根目录LICENSE文件内容一致- 合并 ToolExecutionService 的
executeFunctionCallsWithResults/executeFunctionCallsWithProgress孪生方法(约 210 行逐行重复):前者改为驱动后者的 generator 到底并丢弃进度事件,检查点/参数规范化/策略过滤/多模态处理只剩一份实现;执行循环抽取runSingleToolCall/finalizeToolResponse共用方法 - 删除 update_plan 硬编码的 14 个 carry-over 字段剥离特例(
stripKnownUpdatePlanContinuationFields),由通用未知参数剥离规则覆盖;getToolArgsArrayValidationError的友好错误措辞合并进 validateToolArgs,参数校验从两次遍历合并为一次 - 新建共享
diffReviewTools.ts判定模块(write_file / apply_diff / insert_code / delete_code / search_in_files replace),消除 ToolIterationLoopService 与 ToolExecutionService 各自维护的重复工具集定义 - 自动执行设置页对 diff 审阅类工具不再显示无效的勾选框,改为“Diff 审阅管理”状态徽标(悬停说明指向 Apply Diff 设置),批量操作自动跳过这些工具,页面新增配置关系说明(三语 i18n)
- 清理从未被执行链路消费的僵尸配置字段
DeleteFileToolConfig.autoExecute/ExecuteCommandToolConfig.autoExecute,避免与统一自动执行配置(toolAutoExec)混淆 - delete_file / get_symbols / list_files 等工具描述中的“MUST be an array”强调不再是唯一防线,参数层通用别名提升从根源上消化单复数误用
- read_file 工具声明瘦身:line/maxLine/maxLines/limit 四个兼容别名参数从 schema 和描述中移除(每轮请求少发一大段别名说明),通过 paramAliases/compatParams 机制继续接受旧写法,行范围语义不变
- RepeatedCallGuard 签名改用键排序的稳定序列化,键顺序不同的语义等价参数不再绕过护栏;rejected:true 的结果(并发超限、策略过滤等)不再计入连续失败,避免“换个思路”提示误导本可稍后重试的场景
- coerceToolArgs 类型容错补齐 object 分支:JSON 字符串 → 对象(双重编码容错,与 array 分支对称),解析后继续递归修正内部类型;单数别名提升支持 -ies 复数(query → queries)
- 工具响应深拷贝从
JSON.parse(JSON.stringify(...))换成structuredClone(不可克隆值回退旧方式),大文本 / 多模态 base64 场景显著降低序列化开销 - ToolRegistry 新增别名索引(alias → 主名),getTool 的别名查找从 O(n) 遍历降为 O(1),注销 / 刷新工具时同步维护,保持先注册者优先语义
- XML 工具调用解析失败反馈具体化:借助 XMLValidator 报出具体语法错误与行号,缺失
<tool_name>时单独指出,不再是一句笼统的 "not valid XML" - 工具调用链路测试扩充:validateToolArgs 嵌套/enum/签名回显 11 个新用例、coerceToolArgs 对象解析与别名机制 9 个新用例、repeatedCallGuard 稳定签名与 rejected 语义 4 个新用例,新增
toolRegistryAliases.test.ts(6 用例)
Synced from upstream (1.1.28 → 1.2.5)
工具增强
- apply_diff 升级为结构化 hunks(oldContent/newContent),保留旧 patch 兼容入口;新增行首缩进容错兜底,降低模型缩进误差导致的匹配失败
- execute_command 重写 Shell 选择规则说明:明确 PowerShell/CMD/sh/Git Bash/WSL/Zsh 的解析规则、管道符转义、复杂命令最佳实践和 SSH 多层解析边界
- read_file / write_file 输入格式简化,单文件读写改为直接传
{ path, ... };read_file 增加line/maxLine/maxLines/limit兼容别名 - list_files / find_files 增加文本文件
lineCount元数据,list_files / find_files / history_search 前端结果卡片展示行数信息 - DiffReviewSession 抽取为 DiffManager 内部协作者,集中单个 diff review 生命周期;新增 autoSaveError 避免自动确认模式下悬挂状态
流式渲染
- MarkdownRenderer streaming 调度从纯 debounce 调整为 leading/trailing/max-wait 策略:首个非空片段立即显示,持续输出有最大等待上限
- 主聊天流式正文不再因 text/thought block key 随正文长度变化而闪烁重建
架构模块
- 新增 TranscriptRepository / TranscriptMutation 抽象层,收敛主聊天与 SubAgent transcript 读写入口
- ConversationManager 接入 TranscriptRepository 处理删除、截断、清空和快照恢复等结构性历史变更,并在变更后清理上下文裁剪状态
- RunController 最小共享契约迁移到
backend/core/,统一主聊天取消与 SubAgent pause/resume/exit 接口 - 新增 ToolDeclarationResolver 工具声明解析器
- 新增 mcpToolNameCodec 模块,修复 MCP 工具名包含双下划线时前端解析错误
- 新增 functionCallMerge 模块,标准化 Anthropic
tool_use流式工具调用 id/index 语义,消除重复工具卡片
Token 速度
- 新增 tokenRate 公共工具,统一主聊天、SubAgent Monitor 和响应详情的 token 速度计算入口
- 修复流式
streamDuration语义:使用请求开始到最后一个流式块的完整耗时,降低上游一次性吐出多段 SSE 时的畸高速率
SubAgent Monitor(基础设施)
- 新增 SubAgent Monitor 独立编辑器面板、运行事件总线(runEventBus)与运行控制器(runController)
- 新增 WebviewClientRegistry 实现 client-aware Webview routing,让 Main Chat 与 SubAgent Monitor 响应回到正确 Webview
- 新增 agentRun store(events/reducer/selectors/contentDelta)为 Monitor 前端数据流提供状态管理
- Monitor 前端组件:实时输出、工具卡参数显示、多 run 标签页、窗口状态管理
- 接入 App 独立面板模式:
__GRAYCODE_VIEW_MODE = 'subagentMonitor'时渲染 SubAgent Monitor,并跳过主聊天初始化链路 - SubAgent 工具卡新增“打开详情 / Open details”操作,复用
ToolConfig.actions和ToolMessage通用工具操作按钮渲染 - Webview 侧补齐
subagents.openMonitor、pause/resume/exit、delete/retry message 等 Monitor 操作 handler,并在ChatViewProvider中完成最小路由接线 - 补齐 SubAgent Monitor 相关 i18n key(zh-CN / en / ja)和前后端通信类型
- 补齐 ToolProgressEvent、ToolExecutionResult.args、countTextFileLines、gcd 等同步过程中需要的后端类型与工具函数导出
- 验证通过:
cd frontend; npx vue-tsc --noEmit、根目录npx tsc --noEmit、相关 Jest 单测parsers.test.ts/ConversationManager.branch.test.ts/toolIterationDynamicContextPreserve.test.ts
新增文件统计
- 后端新增 13 个模块/工具文件,前端新增 14 个组件/工具文件
- 核心工具 4 个文件同步至上游最新,语法验证通过
[1.1.27] - 2026-05-01
Added
- Gemini 频道新增「上游请求最多图片数」配置,可限制发送给 API 的历史图片数量,超出上限时优先保留最新图片
[1.1.26] - 2026-04-24
Fixed
- 修复没有思考内容时不发送reasoning_content的问题
[1.1.25] - 2026-04-15
Fixed
- 修复聊天历史完整性与消息可见性问题
- 修复 diff 生命周期、plan 可见性、NoAct 审批门闸与提示系统设置
- 其他
[1.1.24] - 2026-04-04
Fixed
- 新增 Progress 文档能力
- 修复命令执行的个别bug
[1.1.23] - 2026-04-03
Fixed
- 修复流式工具id问题
[1.1.22] - 2026-04-02
Fixed
- progress_sync 模式下误传 sourceArtifact 时改为忽略并警告,不再报错
[1.1.21] - 2026-04-02
Improved
- 将 prompt mode 的使用范围从全局切换,收敛到会话和请求链路,并补齐运行时上下文。
- 完善 review mode 的文档生命周期、结构化结果处理与对比流程。
- 为 design / plan 文档增加更新能力,并让计划文档与任务卡、续写流程保持同步。
- 提升 Webview 声音提醒的稳定性,处理音频解锁、并发播放、过期事件丢弃和隐藏态折叠等问题。
[1.1.20] - 2026-04-01
Added
- 增加边流式边执行工具的功能
Fixed
- 优化工具的兜底机制
[1.1.19] - 2026-03-31
Fixed
- 调整工具解析兜底策略,降低解析失败问题
[1.1.18] - 2026-03-30
Fixed
- 修复ignore模块未被打包导致启动失败的问题
[1.1.17] - 2026-03-30
Fixed
- 添加遵循.gitignore,并修复Windows 系统下的路径规范化问题
- 修复不同格式下,对于缓存命中token信息的显示和存储问题,使用⚡显示缓存命中token数
[1.1.16] - 2026-03-25
Fixed
- 修复包管理器锁文件冲突:删除多余的 pnpm-lock.yaml,统一使用 npm(package-lock.json)作为包管理器
- 修复 LLM 工具参数序列化问题:新增 coerceToolArgs 模块,自动修正 AI 模型返回的工具参数类型错误(如将字符串 "true" 转为布尔值 true,字符串 "123" 转为数字 123,字符串化的数组/对象自动解析为原类型)
- 在主工具执行入口(ToolExecutionService)和子代理执行入口(subagents/executor)中接入 coerceToolArgs,统一参数类型矫正逻辑
Added
- 新增 backend/tools/coerceToolArgs.ts 工具参数类型矫正模块
- 新增 coerceToolArgs 单元测试(backend/tests/tools/coerceToolArgs.test.ts)
- 新增 Jest 测试配置(jest.config.js、tsconfig.test.json)
Improved
- tsconfig.json 排除测试目录,避免测试文件影响生产构建
Note
- ⚠️ 此为初步修复,coerceToolArgs 的类型矫正覆盖了常见场景,但可能存在边界情况未处理,后续会持续完善
[1.1.14] - 2026-03-25
Added
- 增加Anthropic格式下缓存创建开关
Improved
- 优化skill实现逻辑
[1.1.13] - 2026-03-19
Fixed
- 修复了sub-agent不能正常调用的bug
[1.1.12] - 2026-03-19
Fixed
- 兼容旧版 VS Code(移除 nanoid 的 ESM 依赖)
- 降低vscode版本限制
[1.1.11] - 2026-03-19
Fixed
- 修复设置-提示词-工具策略修改不能保存的问题,优化默认模式工具配置
[1.1.10] - 2026-03-17
Added
- 引入 Review 模式并完善审查文档、工具摘要与前端展示
[1.1.9] - 2026-03-17
Added
- 补齐 design 文档产出与 design 到 plan 联动链路
Fixed
- 修复由于ai输出工具调用结构不齐导致的前端渲染崩溃
- 修复非function call格式的解析
- 修复skill不支持claude api的问题
[1.1.8] - 2026-03-16
Improved
- 重构前端回复查看器并统一查看回复入口命名
[1.1.7] - 2026-03-13
Fixed
- 修复了获取模型时,自定义标头不起作用的问题,以及使用Auth发送对获取模型无效的问题
[1.1.6] - 2026-03-13
Fixed
- 提高了设置页面中 Token 统计的准确性,并增强了消息处理管道的稳定性
[1.1.5] - 2026-03-10
Fixed
- 修复了切换模型时,发送为gemini格式时,思考签名导致的空括号问题
- 提高了设置页面中 Token 统计的准确性,并增强了消息处理管道的稳定性
[1.1.4] - 2026-03-09
Fixed
- 修复了单个流式块导致的消息消失问题
- 修复了拒绝执行工具时,拒绝消息重复添加的问题
- 修复多标签页同时工作时无法完成响应的问题
[1.1.3] - 2026-03-07
Fixed
- 修复两个源代码里的注释编码问题
- 修复Anthropic格式下input token,total token记录问题
[1.1.2] - 2026-03-07
Fixed
- 修复Anthropic格式的获取模型死循环和token计数接口格式问题,以及思考签名不发送问题
- 修复Windows终端工具的编码问题,添加编码失败回退逻辑
[1.1.1] - 2026-03-06
Added
- 添加了外观配置:是否显示添加内容到输入框
[1.1.0] - 2026-03-05
Added
- 添加了Plan卡片消息的标签页打开功能
Improved
- 优化了Plan卡片的显示,不再截断内容
- 交换了Plan文件里正文和todolist的顺序
[1.0.99] - 2026-03-04
Fixed
- 修复点击工具执行的状态问题
- 修复对话文件的工作区路径无法变更问题
- 修复长历史对话的全量重载问题
[1.0.98] - 2026-03-01
Fixed
- 修复MCP自动连接依赖UI的Bug
- 修复历史对话内容检索工具的范围问题
[1.0.97] - 2026-02-27
Added
- 添加了对于文件夹的shift拖拽到输入框的徽章消息支持
[1.0.96] - 2026-02-27
Added
- 鼠标悬停在底部模式/渠道/模型上的悬浮显示支持
- 拖拽工作区非文本类文件到输入框的徽章优化,不再尝试使用文本解析,改为上传附件+传递路径框架信息,同时优化上传的附件类型,默认支持:图片/视频/音频/文档
- 系统提示词的静态提示词里添加了{{$CONTEXT_BADGE_FORMAT}},务必重置一下静态提示词
[1.0.95] - 2026-02-27
Added
- 新增声音提醒功能:支持警告/错误/任务完成/任务失败事件,提供独立设置界面,支持导入本地音效,并内置免版权默认提示音
Improved
- 优化外观细节:思考内容垂直居中,正文、工具、思考对齐,删除浅色主题的思考标题内容分界线,代码块行号显示自适应
[1.0.94] - 2026-02-26
Added
- 为总结功能添加系统提示词,避免某些缺系统提示词导致的报错问题
[1.0.93] - 2026-02-24
Fixed
- 修复模型回退逻辑与第三方 Gemini 模型过滤
[1.0.92] - 2026-02-21
Fixed
- 修复上下文裁剪估算问题
- 修复粘贴文本为富文本的问题
[1.0.91] - 2026-02-18
Fixed
- 修复工具等待执行状态不更新的问题
[1.0.90] - 2026-02-16
Added
- 添加了对于mcp工具按照mcp规范工具响应返回图片时的显示支持
Fixed
- 优化前后端流式,添加id绑定,修复几个竞态问题
[1.0.89] - 2026-02-13
Added
- 添加了自动总结功能,位于上下文管理里,与上下文裁剪互斥
- 添加了总结功能的取消操作
- 添加了对话标签页拖拽调整顺序功能
- 添加了被总结的对话的历史对话检索工具
Improved
- 优化了本地计算token的数量,添加了兜底以及统一系数1.5,降低超上下文情况
- 优化了前后端流式信息的通信性能消耗
- 将动态提示词改为回合内固定不变,而不是每次调用ai都实时生成
Fixed
- 修复了命令行工具终止不完全的问题
- 修复了输入框粘贴内容无法撤销的问题
- 修复了不同对话之间,模型、模式、skill、固定文件无法单独配置的问题
- 修复了启用自动应用时不打开差异视图配置导致diff一直处于等待的问题
- 修复了加载对话时跳转到末尾不完全的问题
[1.0.88] - 2026-02-12
Improved
- 增加了聊天界面右侧滚动条和消息节点的大小
- 修改了遮挡关系,让消息节点位于滚动条上方
[1.0.87] - 2026-02-12
Added
- 添加了Anthropic格式里自适应思考模式和思考effort参数的配置支持
- 添加了两个diff类工具:插入代码(insert_code),删除代码(delete_code)
- 添加了diff类工具,自动应用diff时是否显示diff标签页的功能
- 添加了diff类工具,diff警戒值的功能,只会在开启自动应用diff时显示
- 添加了聊天界面右侧滚动条节点的功能,可以快速跳转和定位不同的用户消息
- 添加了聊天界面用户消息的特殊显示,添加了淡蓝色背景,方便快速定位
Improved
- 优化了subagent内部的重试机制,改为静默,不再显示到外部
Fixed
- 修复了不同对话之间,输入框状态不隔离的问题
- 修复了执行plan后,如果模型回答没有调用任何工具,导致todolist消失的问题
- 修复了搜索替换工具点击查看差异按钮没有响应的问题
- 修复了subagent工具,子代理内部调用ai报错时不重试的问题
- 修复了subagent工具,子代理配置的工具列表不被使用的问题
- 修复了不同对话之间,报错重试的串对话问题
- 修复了顶部todo list的状态保存,不会再切换对话时总是展开,改为对话持久记忆
- 修复了切换对话后,总是重新渲染文字显示的问题
[1.0.86] - 2026-02-12
Fixed
- 修复了流式工具调用响应的显示问题
[1.0.85] - 2026-02-11
Fixed
- 修复了获取模型列表的数量问题
[1.0.84] - 2026-02-10
Fixed
- 修复了plan模式下,执行计划后todo list消失问题
[1.0.83] - 2026-02-10
Added
- 初步添加了回合消息队列功能,在此基础上保留了立马发送消息功能和添加批注功能,可能有些bug
Improved
- 优化了路径高亮的显示,避免不存在的文件路径也显示可点击
Fixed
- 修复了通过plan模式创建todo list的显示和更新问题
[1.0.82] - 2026-02-10
Added
- 添加了对话标签页功能,现在可以同时开多个对话任务
- 添加了流式工具响应的显示功能
Improved
- 优化工具的处理和排队显示
- 优化多工具响应时的显示性能消耗
- 优化回退时,回退到的存档点的判断
Fixed
- 修复了diff保存时的竞态问题导致的显示内容不一致问题
[1.0.81] - 2026-02-09
Added
- 当点击plan工具的执行计划按钮时,自动切换到选择的模式,默认使用code模式,且后续会记住选择的模式
- 优化了diff工具同一标签页的预览,避免不刷新
[1.0.80] - 2026-02-09
Improved
- 优化了subagent不必要的字段,不再发给ai
- 优化了subagent的显示,不再显示外部面板
- 优化了plan工具相关的交互
- 优化plan工具,会自动打开标签页显示,并且可以提前编辑其内容
- 优化了todolist的语言翻译问题
- 优化了diff工具的实现,修复偶尔发生的换行查找失败问题
- 优化了重试次数的统计,改为额外统计报错次数
[1.0.79] - 2026-02-09
Improved
- 优化网络空回问题和报错
Fixed
- 修复todo列表导致的消息列表无法正确滚动到底部问题
[1.0.78] - 2026-02-06
Added
- 添加了聊天记录里 文件路径高亮,代码行号高亮和点击跳转功能
[1.0.77] - 2026-02-06
Fixed
- 修复读取非文本类文件时传入行号导致的问题
[1.0.76] - 2026-02-06
Improved
- 优化了编辑框的显示
- 去除了等待字体的首字母花体效果
[1.0.75] - 2026-02-06
Improved
- apply_diff 添加兜底全局搜索替换机制
[1.0.74] - 2026-02-06
Improved
- apply_diff:unified patch 支持“裸 @@”hunk 头(无行号)时自动退化为全局精确 search/replace 应用,提升兼容性
- apply_diff 工具面板/历史预览:增强对“裸 @@ / 无前缀行”的展示兜底
[1.0.73] - 2026-02-05
Improved
- 优化了todo工具和实现方式,请务必重置一下所有模式的动态上下文模板,以便使用todo list
[1.0.72] - 2026-02-05
Improved
- 优化了新diff格式的提示词,减少失败概率
[1.0.71] - 2026-02-05
Added
- 添加了新的diff格式,且默认使用新diff格式。新格式成功率更高,依旧可以在设置里使用旧格式
Fixed
- 修复gemini格式工具响应无法正常发送的问题
[1.0.70] - 2026-02-04
Added
- 添加plan/build模式(测试版,暂时有很多bug)
[1.0.69] - 2026-01-28
Fixed
- 修正diff配置的遗漏问题
[1.0.68] - 2026-01-27
Fixed
- 修复配置未持久化问题
[1.0.67] - 2026-01-27
Improved
- 迁移至 VSCode 原生配置以支持 Settings Sync
[1.0.66] - 2026-01-24
Fixed
- 修复拖选添加文件时路径问题报错导致的添加失败
[1.0.65] - 2026-01-24
Added
- 添加了代码块自动换行显示的功能
[1.0.64] - 2026-01-24
Improved
- 优化前端显示历史消息,变得更流畅,避免全量加载
[1.0.63] - 2026-01-24
Improved
- 移除了附件大小限制(仍可能受vscode本身限制)
Fixed
- 修复换行视图上移问题
- 修复中断报错时的前端索引问题
[1.0.62] - 2026-01-22
Fixed
- 修复子代理创建后无法删除的问题
[1.0.61] - 2026-01-22
Added
- 添加了选中文件里某一部分添加到上下文的功能,可以在选中要添加的代码后,悬停在代码上面,或者点击左侧的灯泡添加到输入框中。后续会扩展更多其他的添加上下文功能
[1.0.60] - 2026-01-22
Improved
- 拆分解耦了输入框组件,使其更简洁
[1.0.59] - 2026-01-21
Added
- 添加了编辑消息面板的"@"菜单
- 添加了附件消息文件内容的功能
- 将拖拽和"@"菜单内容做成了两个功能,按住ctrl使用原来的添加路径提示词,不按ctrl则表示直接添加文件内容进提示词
Improved
- 重构了输入框的代码,现在可以支持插入更多模块的提示词了
- 优化了添加文件时的图标显示,改成更符合其文件扩展名的图标
[1.0.58] - 2026-01-20
Added
- 添加了使用"@"选择文件时,打开标签页的高亮显示和优先排序
[1.0.57] - 2026-01-20
Fixed
- 修复ctrl+s保存后diff状态清除不完全的问题
- 修复Latex公式显示问题
[1.0.56] - 2026-01-20
Improved
- 重构了工具的状态和执行逻辑
Fixed
- 修复了思考内容的字体显示问题
[1.0.55] - 2026-01-20
Added
- 添加了 Mermaid 图表 显示支持
Fixed
- 修复了生成图片时路径和图片格式不一致的问题
[1.0.54] - 2026-01-19
Fixed
- 修复了"@"菜单里使用↑↓按键无作用的问题
[1.0.53] - 2026-01-19
Added
- 添加了快速回顶/回底按钮,添加了滚动动画
Fixed
- 修复了获取模型列表时没有走设置的网络代理的问题
[1.0.52] - 2026-01-19
Added
- 添加了外观设置面板,添加了等待的文字配置项,可以自己配置显示文字,而不使用Loading
Improved
- 优化了历史对话加载方式,改为分页加载,减少等待时间
Fixed
- 修复了前端中断消息时,流式动画未消失的问题
[1.0.51] - 2026-01-19
Added
- 添加了diff时修改文件内容的支持,同时会告诉ai手动修改了哪些内容
Improved
- 优化了读取类工具的换行符读取,使用\n而不再是\r\n,会更节省token和上下文
- 优化了等待ai响应的动画
Fixed
- 修复了写入文件,搜索内容两个工具的diff中断问题,并采取了更稳健和兜底的中断机制
- 修复了ai使用apply diff工具没有输出行号时的兜底机制没有工作的问题
- 修复了diff工具文字显示问题
[1.0.50] - 2026-01-19
Fixed
- 修复总结上下文总是带全部历史的问题
- 发送时过滤掉空的thought块,以格式更正确
- 修复了发送消息时的token重复计数问题
Improved
- 优化了默认的动态提示词,请务必去设置-提示词页签里重置一下动态提示词
[1.0.49] - 2026-01-18
Added
- 添加了diff的全部应用和部分应用功能。对于部分应用,可以通过点击diff视图左侧的小灯泡来应用对应部分的diff,或者通过右上角的按钮来一次性保存多个diff块
Improved
- 移除搜索的dryrun模式
- 优化了diff类工具的显示和逻辑,使用统一的diff逻辑,包括apply diff,write file,search in file
Fixed
- 修复部分拒绝工具,切换对话、中断工具等复杂情况时的竞态问题
- 修复需要批准执行的工具造成的索引问题
- 修复了diff类工具多个diff块时的行号问题
[1.0.48] - 2026-01-17
Fixed
- 修复子代理工具的文字显示问题
[1.0.47] - 2026-01-17
Added
- 添加了子代理工具,现在ai可以分任务给子代理,可以在设置中自行添加不同的agent
Improved
- 优化了搜索替换工具的显示和工具定义
- 优化了token计数api的调用,改为并行调用节省时间
Fixed
- 优化了oai response接口的请求体结构
- 修复了部分工具调用结果拒绝时没有添加响应的问题
[1.0.46] - 2026-01-16
Added
- 添加了模式选择按钮,现在可以自己修改并保存不同的系统提示词和动态提示词为模版并持久保存了
Fixed
- 修复ssh时拖拽固定文件路径的问题,以及拖拽ssh拖拽添加文件到输入框的路径问题
[1.0.45] - 2026-01-16
Fixed
- 修复了MCP Studio类型的注册问题,测试使用python、npx、uvx均正常
[1.0.44] - 2026-01-14
Improved
- 优化了动态提示词的插入算法,改为插入到回合之前,避免破坏回合完整性
[1.0.43] - 2026-01-11
Improved
- 优化了提示词,由于提示词更新,所以尽量去前端提示词面板里重置系统和动态提示词
[1.0.42] - 2026-01-11
Added
- 初步添加了动态skills功能
[1.0.41] - 2026-01-10
Improved
- 优化了提示词,由于提示词更新,所以尽量去前端提示词面板里重置系统和动态提示词
- 优化了裁剪上下文的逻辑
[1.0.40] - 2026-01-10
Improved
- 优化了变量加载方式,改为在末尾,以便缓存命中,同时优化了提示词结构
- 优化了前端提示词配置面板,以顺应新更改
- 由于提示词更新,所以尽量去前端提示词面板里重置系统和动态提示词
- 添加了版本更新公告功能
[1.0.39] - 2026-01-10
Fixed
- 修复图像生成类工具的api调用不传递role的问题
[1.0.38] - 2026-01-08
Fixed
- 修复cmd工具无法执行的问题
[1.0.37] - 2026-01-08
Fixed
- 修复了报错后点击重试按钮无响应的问题
[1.0.36] - 2026-01-08
Fixed
- 修复了搜索工具的显示内容问题
- 修复了cmd终端类型引号参数问题
- 修复了搜索工具无法指定单个文件内搜索的问题
Improved
- 优化了初始化时按钮的线程堵塞问题
- 添加了加载历史对话的等待动画
- 优化了一个大文件,进行了拆分解耦
[1.0.35] - 2026-01-07
Added
- 添加了输入框里"@"选择路径功能
Fixed
- 修复中断后点击继续按钮无法继续问题
- 修复工具显示问题
- 修复工具分类问题
- 修复裁剪上下文问题
- 修复部分情况下思考签名的存储问题
- 修复文件夹文件不显示末尾/的问题
- 修复cmd运行问题
- 修复中断后点击继续无响应的问题
- 修复上面三种工具显示问题
[1.0.34] - 2026-01-07
Added
- 添加了find_references、get_symbols、goto_definition工具
- 添加了read_file工具带行号的阅读功能,这可能会导致旧对话旧的读取文件块显示异常,建议开新对话
[1.0.33] - 2026-01-07
Improved
- 优化了两个大文件,进行了拆分解耦
[1.0.32] - 2026-01-06
Improved
- 优化了oai-responses格式,使其更符合官方示例
[1.0.31] - 2026-01-06
Fixed
- 修复终端工具编码显示异常问题
[1.0.30] - 2026-01-05
Added
- 添加openai-responses格式对话和token计数支持
[1.0.29] - 2026-01-01
Changed
- Myers 差分算法重构:
myersDiffLines从逐层拷贝 Map(O(D²) 内存)替换为公共前后缀裁剪 + 行 id 化 + Int32Array 状态数组;超预算自动降级为线性路径;全量重写大文件(5000+ 行)从数十秒降至毫秒级,不再阻塞 extension host - diff 警戒检测(
checkDiffGuard)改用快速删除行统计countDeletedLines:只计算编辑距离而不回溯全 diff 操作序列,每次创建 diff 预览时不再触发全文件差异计算 computeUserEditedNewLinesSummary新增 500 行截断上限,防止超大编辑生成的摘要膨胀塞满模型上下文- 暂时回档到1.0.26
[1.0.28] - 2025-12-31
Fixed
- 修复diff无法自动确认问题
[1.0.27] - 2025-12-31
Added
- 支持工具确认后的分步批注提交
Fixed
- 修复总结对话后functionCall被错误裁剪
[1.0.26] - 2025-12-31
Fixed
- 修复存档点问题
- 修复自定义body时的合并问题
[1.0.25] - 2025-12-26
Added
- 添加回退存档点二次确认功能
[1.0.24] - 2025-12-26
Added
- 在工具确认界面支持读取输入框内容作为批注发送给 AI
- 当有待确认工具时,发送输入框内容将自动触发“全部拒绝”并带上批注消息
- 后端 ChatHandler 支持在处理工具结果前插入用户批注消息并重新计算 Token
- 优化 diff 管理器:在非自动保存模式下,用户手动保存文件后自动关闭 diff 标签页
- 前端chatStore 增加待确认工具检测逻辑及 rejectPendingToolsWithAnnotation 方法
- 调整输入框逻辑,允许在工具待确认状态下发送文本内容
Fixed
- 修复输入框无法右键粘贴问题,简单模式”下,支持使用 a.b.c 这样的键名
[1.0.23] - 2025-12-25
Improved
- 优化apply diff等工具的存储和显示以及实现
[1.0.22] - 2025-12-23
Fixed
- 修复输入框以及长对话时卡顿问题,引入消息分页,每次多加载40条
[1.0.21] - 2025-12-22
Fixed
- 修复oai格式流式响应中提取token计数问题
[1.0.20] - 2025-12-22
Fixed
- 修复oai格式,Anthropic格式的工具调用格式和显示问题
[1.0.19] - 2025-12-22
Fixed
- 修复终止按钮以及思考消息存储和前端显示问题
[1.0.18] - 2025-12-22
Fixed
- 修复思考删除消息
[1.0.17] - 2025-12-22
Fixed
- 修复文件扩展名识别问题,添加兜底机制
- 修复空目录的增量备份问题
[1.0.16] - 2025-12-22
Added
- 添加token计数api配置面板
Improved
- 大幅优化token计数方法
- 大幅优化裁剪上下文功能
[1.0.15] - 2025-12-21
Fixed
- 修复开关返回图片给ai时刷新多模态工具配置问题
- 修复工具调用块里思维链存储和返回问题
[1.0.14] - 2025-12-21
Fixed
- 暂时修复多工具确认问题
[1.0.13] - 2025-12-21
Fixed
- 修复提示词的刷新规则,每次循环都刷新
- 修复总结对话问题
[1.0.12] - 2025-12-21
Added
- 新增发送前估算token功能
- 新增额外裁剪功能
- 新增发送历史对话思考时,控制发送对话轮数的功能
Fixed
- 修复历史思考签名回传开关的问题
- 修复token计算问题,现在会实时裁剪上下文
- 修复不同渠道的发送思考问题
Improved
- 优化了历史思维链回传说明
- 优化了写入文件,应用差异工具的diff预览问题
[1.0.11] - 2025-12-21
Fixed
- 修复工具格式和解析不匹配问题
Improved
- 优化了系统提示词
[1.0.10] - 2025-12-21
Improved
- 优化了系统提示词
Fixed
- 修复抓包问题
- 修复保存正文签名问题
- 修复总结上下文后使用token不对问题
- 修复裁剪上下文问题
[1.0.9] - 2025-12-20
Added
- 新增单回合最大工具调用次数配置
- 在工具设置面板中添加配置项,允许用户自定义每轮对话中 AI 最多可调用的工具次数
- 默认值为 50,-1 表示无限制
Improved
- 优化工具设置面板的数字输入框样式,隐藏上下箭头按钮
Fixed
- 修复工具参数验证问题:强调所有数组类型参数必须使用数组格式(即使只有单个值)
- 文件工具:read_file、write_file、list_files、delete_file、create_directory、apply_diff
- 搜索工具:find_files
- 媒体工具:generate_image、resize_image、rotate_image、crop_image、remove_background
- 修复 AI 调用时出现
Malformed function call错误的问题
[1.0.8] - 2025-12-20
Fixed
- 修复增量存档,始终使用
[1.0.7] - 2025-12-20
Added
- 新增自定义存储路径功能
- 支持在通用设置中配置自定义存储路径,用于存放对话历史、存档点等数据
- 支持路径验证和数据迁移功能
- 可将现有数据迁移到新的存储位置
- 为搜索工具添加替换功能
Fixed
- 修复上下文阈值在有总结消息时不生效的问题
- 原逻辑:发现总结消息后直接从总结开始返回历史,跳过上下文阈值检查
- 修复后:即使有总结消息,也会继续检查 token 数是否超过阈值,超过时会对总结后的历史进行回合裁剪
- 修复 apply_diff 工具前端缩略视图行号始终从 1 开始的问题
- 将
start_line参数改为必填,要求 AI 必须提供准确的起始行号 - 后端返回带有实际匹配行号的 diffs 供前端显示
- 前端优先使用后端返回的 diffs 数据(包含实际匹配行号)
- 修复diff差异工具的显示问题,优化diff工具的存储
Improved
- 优化大部分工具定义和响应
- 改为使用增量备份功能
- 添加更多md渲染支持
[1.0.6] - 2025-12-19
Fixed
- 修复上下文总结功能发送给 API 时包含无效字段的问题(如
functionCall.rejected、inlineData.id/name等内部字段) - 修复 apply_diff 工具前端面板中行号从 0 开始显示的问题,现在正确使用
start_line作为起始行号
Improved
- 优化总结请求的字段清理,过滤思考内容和思考签名,保持与
getHistoryForAPI一致的清理逻辑 - 改进 apply_diff 工具的"查看差异"按钮功能,现在点击后在 VSCode 中显示完整文件的差异视图(包含完整代码上下文),而不仅仅是 search/replace 块
- 改进切换对话时的自动滚动逻辑
- 前端添加取消兜底机制,避免一直显示等待
[1.0.5] - 2025-12-19
Improved
- 优化生图工具(generate_image)描述,添加提示说明生成的图片是实色背景而非透明底图
[1.0.4] - 2025-12-19
Fixed
- 修复工具执行完成后点击终止按钮无法正常结束的问题(循环开始时检测取消信号后需发送 cancelled 消息给前端)
Improved
- 优化搜索工具(find_files、search_in_files)忽略问题,添加默认排除模式配置
[1.0.3] - 2025-12-19
Added
- 添加了向 AI 发送诊断信息功能
Fixed
- 修复上下文感知页面保存问题
Note
- ⚠️ 旧版本使用者建议重置系统提示词以添加诊断信息功能
[1.0.0] - 2025-12-19
Added
- 🎉 首次发布
- AI 编程助手核心功能
- 多模态支持
- 对话历史管理
- 多语言支持(中文、英文、日文)
- MCP 服务器集成
- 文件操作工具
- 终端命令执行
- 图像处理功能
- 终端命令执行
- 图像处理功能