# Changelog 本项目版本号遵循 `0.x` 阶段的语义化:`0..`;预发布版本带 `-beta.N` 后缀(面板中显示为 `0.3.0beta1`)。 ## v0.7.8 — 2026/09/29(**主线 · 正式版 · 会话级档位 / 交互框架 / bash 判定**) 作者:啃轮胎的西狐 这一版是三件事叠在一起:**档位终于按会话**、**多了一档会改变语域的协作基调**、**bash 调用开始当场判值不值**。 ### 一、档位改为会话级(修「点一次正常,之后固定」) - **成因**:点档位是**合并**写入,而宿主早先把 `tier` 展开成 assist/detail/budget 后**存了回去**; 于是第二次点击时,新的 `tier` 会与上一次展开的**陈旧三项**合并,读取时那三项盖过新预设 ⇒ 推导档位不变 ⇒ 界面看起来「点了不动」。第一次之所以正常,是因为覆盖是空的、没有残留可覆盖。 - **修法**:**存意图、读取时展开**——设置层只存用户写的 `tier`,展开挪到 `effectiveSettings`; 点档位时**整份替换**该会话的覆盖(不合并),从源头杜绝残留。 - 档位与协作基调都按会话存(`bySession`),全局只作默认值;另修掉两处 early-return 导致「加码只第一轮生效」。 ### 二、新会话首条消息挑错模型(修宿主方法名) - `agentDefaultModel` 的真实方法是 `currentSelection()`,而代码里试的是 `current/read/get/selection`—— **四个全不存在** ⇒ 第③步整段空转 ⇒ 掉到「模型清单第一条」,用与会话无关的模型去优化。 - 修法:把 `currentSelection` 放到候选名首位(实测它返回的正是 `{provider, model}` 形状)。 ### 三、交互框架(协作基调):普通 / 硬邦邦 - **依据**:用户实测——同样字数的正式提示词做不到口语版的效果 ⇒ 起作用的是**语域**,不是信息量。 机制是分布:正式语域采样「专业助手」那一簇(客套、求稳),口语+高唤醒语域采样「把活干出来」那一簇。 - **分工**:骨架归代码(标签 / 语域 / 越权反制行——三条不变量),加码归模型(按本轮实际写,长度自定、定点爆破)。 加码插在中间,**边界行永远在最后**;且必须**引用包内真实条目 id**,写不出引用就整段不采用、退回纯骨架。 - 两类例外保持字面、不许修辞:**未决项**(没拍板的事说清楚)与**防御性限制**(不许做什么、范围边界)。 ### 四、单轮提升(第一次就把事做对) - **任务类自查表**:【完成前自检】节,来自代码持有的任务类知识(第一批:单文件可交互 3D/可视化程序)。 来源是 `project_convention` 而非 human ⇒ 结构上不可能升格成用户要求。 - 质量解释要求落到「**可肉眼判断的维度 + 最低可接受线**」;新增【结构性分叉】规则(选错了后面全要返工的那种选择)。 ### 五、bash 调用质量判定 - **长等待 / 低产出**:耗时与字节当场交回(工具一直知道这两个数,却从没告诉过模型)。 - **链结构**:段数 ≥3 且用了吞错型连接符(`;` `|` `||`)⇒ 点明「中间某段失败了你看不出来」。 - **重武器 + 替代路径**:命中无头浏览器 / 装包 / 网络下载 / 重构建时,直接给能照做的更省做法。 - **崩溃/中止探测器**:调用被外层掐掉时(`AbortError`)工具交不出任何东西,故落「进行中」标记, **下一次调用开头点明「上次没有正常收尾、那次等待是纯损失」**。 ### 六、文档与仓库 - 新增 `docs/0.7.8plan.md`:四个既定突破点 + 更本质的潜在突破 + 单轮表现 + 实施优先级 + 交互框架附录。 - `.gitignore` 补 `po06/runtime/tmp/`(运行期临时目录,此前会被 `files: [runtime]` 带进包)。 **回归**:57 套测试全绿。 ## v0.7.6 — 2026/09/26(**主线 · 正式版 · 长输入与 bash 让位**) 作者:啃轮胎的西狐 两处用户反馈:**几万字提示词必然失败**、**关掉内置 Bash 后系统自带的 bash 也回不来**。 ### 一、修「几万字提示词必然失败」 - **现象**:提示词几万字时,面板报「失败:连不上宿主服务(它可能刚重启)」。 - **根因**(两处叠加):① control-api.js 的 MAX_BODY_BYTES 只有 64KB,而它的注释理由是「设置/指令都很小」—— **这个前提不成立**:readBody 也服务解释端点,而那个 body 里装的是**用户原文**。 中文一字 3 字节 ⇒ 64KB ÷ 3 ≈ **21800 字**即撞墙(实测 39123 字 ≈ 117KB)。 ② 超限分支执行 req.destroy(),**直接销毁 TCP 连接**而不是回 HTTP 错误, 浏览器看到的是「连接断开」,client 归类 unreachable ⇒ **真因被彻底盖掉**。 - **修法**:① 上限 64KB → **2MB**(约 66 万汉字,仍能挡误发的二进制); ② 超限**不再砍连接**,改为如实返回 body-too-large + 实际字节数,由既有调用方回 400,界面可显示真因。 - **顺带**修正同链路另一处旧尺度:session-context.js 的 CTX_MAX_TEXT_CHARS 4000 → 6000、 CTX_BUDGET_TURNS 12000 → 24000(单段不能等于总预算,否则一段吃光预算挤掉其它上下文)。 该常量只作用于「存进会话历史供后续轮次当上下文」的那份文本;**本轮解释走 userText,逐字不截断**。 ### 二、修「非 Windows 平台:关掉内置 Bash 后什么都没有」 - **现象**:系统自带 bash 的用户(觉得原来那个更好)关掉内置 Bash 后,DSH 里彻底没有 bash。 - **根因**:宿主的 @deepseek-ai/dsh-tool-bash 注册的工具名**也是 bash**,而它在 @deepseek-ai/dsh-base/cordis.patch.yml:266 写着 disabled: !!js process.platform === win32 —— **官方只在 Windows 禁用它**,非 win32 平台宿主本来就提供 bash。 而 po06 此前无差别注册同名工具 ⇒ 在 Linux/macOS 上把宿主那份顶掉; 宿主只在装配时注册一次、**被顶掉后不会重试** ⇒ 用户一关内置,表里就再没有 bash。 - **修法**:**让位判据取平台这一静态事实**——hostProvidesBash = process.platform !== win32, 成立则 po06 不注册。于是:非 win32 → 让位(关掉开关即回到宿主那个 bash); win32(宿主被官方禁用)→ 补位(行为不变)。 - **为什么不用「查表里有没有 bash」**:表里只看得到名字、分不清是谁注册的; po06 自己刚注册完再查会把自己认成宿主,判据失明。平台不依赖装配时序。 - 新增 po06/test/bash-yield.test.mjs 钉住让位判据,防止日后改回无差别注册。 ### 三、仓库结构:文档归入 docs/ - 仓库根由 27 项降为 10 项:只留对外门面(README ×2 / LICENSE / CHANGELOG)与必需文件 (package.json / .gitignore / .gitattributes),其余 18 项移入 docs/ 并按用途分组, 新增 docs/README.md 索引。 - 同步修正引用,并**顺带修掉一处早已存在的死链**:README 指向 README-0.5.md, 而该文件上一轮已随 0.5 源码移入 old/0.5/。 - docs/RELEASING.md 补入「发布前核对所有相对链接」一条(步骤 3 的核对 + 清单第 3b 项)—— 这条正是本次整理踩出来的。 **回归**:50 套测试全绿。 ## v0.7.5 — 2026/09/26(**主线 · 正式版 · 档位与仓库结构**) 作者:啃轮胎的西狐 这一版来自两类反馈:**思考档位不生效**(用户实测)与**仓库结构混乱**(外部用户:npm 上是 0.5、Release 是 0.7、而 0.7 在子目录)。 ### 一、思考档位:按模型各配,并真正传给调用 - **根因**:po06 调 llm.stream 时只传 provider/model/temperature/messages,**从不传 reasoningEffort** (宿主契约 types.d.ts:494 有该字段,:355 写明不传则走 provider 默认)。于是每次都按默认档跑, 而默认档下**由模型自己决定要不要思考** ⇒ 用户看到「有时有思考、有时没有」。 插件里其实早有 reasoningEffort 设置项,但它只出现在 migration.js 的迁移清单里,**从未接线**。 - **修法**:新增 effortByModel({ provider/model: effortId },**按模型各配**——不同模型档位划分不同, 且优化模型与会话模型未必是同一个);resolveInterpreterCfg 在**定完路由之后**按该模型查表; 两处 llm.stream(默认路径、工具回落)与工具循环都带上 reasoningEffort。 - **档位来源与官方同源**:读宿主 resolveModelInfo 的 reasoning.efforts,写同一个 reasoningEffort 字段, 不存在第二套档位名。注意宿主 listModels 是白名单返回、**会剥掉 reasoning**,所以档位另走 resolveModelInfo。 - **界面**:优化选项里新增「思考档位」下拉,**两种模式都能配**——选了具体模型就按它查, 「跟随会话模型」就先问 /session-model 再按会话模型查(档位写在真正会被调用的那个模型名下)。 - **实测(对照实验,同模型同输入只差档位)**:off → 思考 0 字 / 7 秒;max → 思考 40589 字 / 63 秒。 ### 二、修「档位选完立刻被覆盖」 - **根因**:键格式三处不一致——前端用 JSON.stringify([provider, model])、后端校验要求键含 /(not-a-route)、 wire.js 查表用 provider/model。于是每次保存都被判非法、丢弃并回默认。 - **修法**:前端改为 provider/model,与后端校验及查表口径统一。 ### 三、修「拦截 UI 不再统计 token」 - **根因**:用量只在解释**完成那一刻**写进进度面,而 client 的阶段一离开 optimizing 就 setProg(null) 并停止轮询 ⇒ 最后那次写入永远拉不到(那行代码与其上方注释的意图**正好相反**)。 - **修法**:轮询放宽到 optimizing 与 review;收尾时把最后一份用量钉在结果上;显示改为「结果优先、进度面兜底」; /interpret 响应也带上 usage。 ### 四、修「调 skill 时漏拦截 + 旧包迟到、新包随后才到」 - **根因**(两处叠加,台账为证):① 去重判据只认**文本逐字相等**,而前置拦截记的是客户端原文、 订阅侧取的是宿主事件文本,**调 skill 时两者形态不一致** ⇒ 去重失配 ⇒ 同一句话被解释两遍; ② 第二遍是 defer 出去的**并发**执行,两遍基于同一旧状态各写一次,**后完成的覆盖先完成的** (台账实测 12:35:39 rev=309 → 12:35:40 rev=307,revision 倒退)。 - **修法**:判据增加**时间窗**维度——刚放行后 15 秒内无论文本是否变形都认定为同一条, 两种跳过在台账里分开记(intercepted-already / intercepted-recently),使「这轮为什么没解释」始终可查。 ### 五、仓库结构整理(回应外部用户反馈) - **仓库根 = 最新版**:0.1~0.6 的历史产物全部移入 old/(38 个 tgz 按主次版本分组 + 0.5 的源码), 根目录不再有任何 .tgz 与旧源码;old/README.md 给出各代简介与三种下载方式。 - **根 package.json 是薄壳**:逐字段从 po06/package.json 派生,main 指向 po06/lib/index.js。 此前它曾是 0.5.x 的完整插件包,而安装入口读的正是仓库根 ⇒ 外部用户按仓库地址装到的是 0.5。 - **新增 RELEASING.md**:仓库结构四条不变量 + 9 步发布流程(每步带核对方法)+ 可照抄的检查清单 + 故障排查表。 - **README 写明安装来源**:唯一正确来源是 Release 附件;npm 上的 @dsh-external/dsh-prompt-optimizer 是 0.5 老包,不要装。 ### 六、其它 - 台账新增 effort / effortRoute:记录每次调用**实际带出去**的档位与作用模型,便于自查(需重启后生效)。 - 回归:49 套测试全绿。 ## v0.7.4 — 2026/09/25(**主线 · 正式版 · 位置无关修复**) 作者:啃轮胎的西狐 修掉一个**只有别人会踩到**的缺陷(外部用户反馈:装上后 bash 跑不起来)。 - **根因**:lib/bash/pg-jobport.mjs 顶部写死了**打包者本机**的绝对路径—— file:///C:/Users/<打包者>/AppData/Roaming/npm/.../dsh-win32-process/lib/index.js ——而且是**顶层 await import**。别人机器上没有这个路径 ⇒ 该 import 抛错 ⇒ 本模块加载失败 ⇒ index.js 的 load('pg-jobport.mjs') 落到 catch ⇒ **每次调用都回「插件运行时模块加载失败」**。 工具在工具表里、却完全跑不动。作者本机因为路径恰好存在,一直测不出来。 - **修法**:① 去掉硬编码,改为**多种候选位置运行时解析**(裸包名 → DSH_CHECKOUT → %APPDATA%/npm → 从宿主入口脚本 argv 推导 → node 同级的全局 node_modules);② **全失败也不抛**, 降级到 spawn + taskkill /T /F 的等价实现(接口与 win32 作业对象版一致); ③ 新增 DSH_BASH_FORCE_FALLBACK=1 强制降级开关,便于自测与排障。 - **实测两条路径**(同一台机器):win32-job 与 fallback-taskkill 均 exitCode=0、输出正确、超时终止有效。 - 顺带清掉产物里的其它本机痕迹:runtime/manifest.json 的 source(D:/other/Git → bundled), 以及调试时遗留在 runtime/tmp/ 的 3 个 json。 ## v0.7.3 — 2026/09/25(**主线 · 正式版 · 开关修复**) 作者:啃轮胎的西狐 修掉 0.7.2 里两个**用户看得见**的缺陷(均由真机复测指出): - **开关关不掉**(严重):设置与 /status 都显示 false,工具表里却还有 bash,而且照样能跑。 · 根因不是某行写错,而是**判据本身**错了:它问的是「模块实例记不记得自己注册过」 (typeof dispose === function,而外层 effect 的返回值靠不住),而不是「工具表里到底有没有」。 · 修法:① 用**布尔标志**记状态,不依赖返回值类型;② 判「有没有」以**工具表实测**优先; ③ 注销之后**再实测一次**确认;④ 关键——**真正的注销器是 bash 内部那个 effect 的 dispose**, 外层包一层拿不到它,改为**拦截 effect、收集内层注销器**。 · 实测往返:true → 表 75 / 含 bash;false → 表 74 / 无 bash,可反复切换。 - **卡片外观与原插件不一致**:内置后 bash 调用卡片回落成宿主的通用工具样式。 · 根因:一个插件的 client 入口**只有一个**,原卡片的注册写在 bash 自己的 client 里, 并入本包后**没有任何地方加载它** ⇒ 那次注册从未执行。 · 修法:把原组件**原样复用**进本插件 client 入口(同一份代码,不另做一套),注册同一个 key:bash; 并补上原插件有、本包缺的 dsh.client.external = [dsh-client-ui-primitives](取宿主终端原语)。 - 新增回归测试 test/bash-toggle.test.mjs(4 项):专守「关掉之后工具**真的**从表里消失」, 以及开→关→开→关 的往返与幂等。 ## v0.7.2 — 2026/09/25(**主线 · 正式版 · 内置 Bash**) 作者:啃轮胎的西狐 - **内置 Bash**:原独立插件 dsh-bash-runtime 的实现与运行时并入本包(lib/bash/ 与 runtime/)—— 装上这一个插件就有 bash,无需再装第二个插件。 · 注册改为**裸 tools.register + 对象根 JSON Schema**:原来依赖宿主的 defineTool / schemastery, 而这两个包在 tgz 装配环境里解析不到 ⇒ 模块 import 整体失败 ⇒ **bash 工具静默消失**。 · **详情面板新增开关**:关掉=**不注册该工具**(模型看不到),不是注册了再拒绝执行; 开关走 onSettingsWritten 钩子按差额同步,**改完即生效**,不需要重启或重载插件。 - 上一版(0.7.1-beta.1)的策略改动全部保留:三档拉开、控制面信息移出上下文、质量解释=结果方向、 可逆实现默认、思维层可读进度。 - **验证**:48 套 / 645 项全绿;check-docs --strict 全绿;卸载独立 bash 插件后内置工具仍可用。 ## v0.7.1-beta.1 — 2026/09/25(**主线 · 预发布 · 策略与呈现修复**) 作者:啃轮胎的西狐 - **三档真正拉开**(`lib/settings.js`):补充程度(700 / 1200 / 2000 字)与自主预算(1 / 2 / 3 个问题) 两个维度逐级递进。此前 `minimal` **从未被任何档位使用**、且 standard 与 heavy 的 detail 相同 ⇒「重度」实际只等于「标准 + 多问 1 个」(用户 2026-09-24 实测反馈后查证属实)。 - **内部控制面信息移出工作上下文**(`lib/compiler.js`):注入头部原先带「任务 `default` · 意图修订 N」, 会被工作模型当成任务语义处理(伪语义与锚定);现已移除,元数据仍留在宿主 state 与 wire 台账里。 - **质量解释改为「结果方向」**(`lib/interpreter.js` 规则 2):不把零件、参数、材质、后期效果逐项列成清单; 一个示例就够,示例不是验收项,同一方向不拆成多条。 - **可逆实现默认**(`lib/interpreter.js` 规则 3):可逆细节写 `implementation_option` 并说明「默认取什么、为什么可逆」; **不可逆的产品方向**(联网与否、交付形式、功能范围、审美取舍)仍只能写 `unknown`。 - **思维层不再显示裸 JSON**(`lib/client.js`):无 reasoning 时把结构化补丁解析成可读产出条目 (中间一版只报「已产出 N 字」=留白,用户反馈「直接没有思考过程了」,同样不可接受)。 - **验证**:48 套 / 645 项全绿;`check-docs --strict` 四条门禁 ✅。 - **未验证(如实登记)**:本版的档位差异是**可测的配置差异**,**不等于效果已被证明**—— 此前的留出评估只跑完 S1(两臂没测出差),等级仍是「实验构建」。 ## v0.6.10 — 2026/09/24(**主线 · 正式版 · 兼容性修复**) 作者:啃轮胎的西狐 - **修掉 0.1.7 的第二处契约破坏:工具结果的消息形状**。上一版(0.6.9)修的是投递消息的 `source.kind`; 发完之后按台账复核,发现**开了「只读工具」的每一轮都断在工具循环第 2 轮**。 证据:`~/.dsh/po06-wire.jsonl` 按部署时点切分——`signal is not defined` 的最后一条在 09-24T00:59Z(部署前), 部署后 4 行 `rounds = 1..2`、`calls = 2`(**修复生效、循环真的跑起来了**),但**全部**带 `llm-error: DeepSeek Messages cannot represent user/tool-result content`(`code: UNSUPPORTED_CONTENT`)。 根因:0.1.7 起工具结果是**一等 `role:'tool'` 消息** (`createToolResultMessage({callId, content, isError})`,内容块**直接**是 content、id 由工厂生成), 而循环仍在造 `role:'user'` + `tool-result` 块并手搓字符串 id。**这条路径此前零测试。** - **形状只在一处决定**:`lib/llm-lib.js` 新增 `toolResultShape(mod)` —— 有 `createToolResultMessage` ⇒ `tool-role`;只有 `createUserMessage` ⇒ `legacy-user-block`;**都没有 ⇒ 不猜**(不造消息、循环自然收敛、 由调用方回落)。`lib/read-tools.js` 的结果消息与"助手请求工具"消息都改走它。 - **顺手修掉一个一直存在的接线缺陷**:`loadLlmLib` 的 `env` 默认空表,而生产调用点从没传过 ⇒ `DSH_PO06_LLM_LIB` 这类显式覆盖**永远读不到**。现在两处调用点都显式传 `{env: process.env, argv1: process.argv[1], cwd: process.cwd()}`。 - **验证**:全套 **46 个测试文件 / 620 项全绿**;变异检验 **221 个 / 40 个源文件 / 漏捕 0**; `check-release` 全绿。新增守卫(`test/read-tools.test.mjs` 8 → 10):工具结果必须是 `role:'tool'` 一等消息、**不得再出现 `tool-result` 块类型**、旧形状退回、形状未知时不造消息; 配套夹具 `test/fixtures/llm-lib-017.mjs`(按 0.1.7 导出对齐的假宿主模块)。 - **未验(如实登记)**:**真机复验**——判据是一次真实拦截后台账里 `toolLoopError` 消失且能拿到包, 这一步只能由人在真实对话里触发;观感类结论需真人看;**专业跑分 / 留出评估仍未完成**(只跑完 S1), B 臂(冻结的 0.4.4 对照)**成本基线仍缺失**。 ## v0.6.9 — 2026/09/24(**主线 · 正式版 · 兼容性与缺陷修复**) > ⚠️ **本版发布当天即被 `0.6.10` 取代**(同日按台账复核抓出 0.1.7 的**第二处**契约变化:工具结果的消息形状)。 > 装最新版请用 `0.6.10`;本条保留作为当时的事实记录。 作者:啃轮胎的西狐 - **适配宿主 `dsh 0.1.7-rc.1` 的会话格式 v4**(**ADR-0087**)。宿主把会话日志升到 v4,而 v4 的**准入校验会明确 拒收**我们过去投递通知用的旧来源名——这不是风格过时,是**写入会话日志那一步会抛错**。 依据读的是宿主源码:`dsh-session-format-v3-to-v4` 里 `if (… || value["kind"] === "plugin") throw new SessionFormatError("format v4 message requires a producer-owned source kind")`。 现在投递来源固定为 **`kind: 'plugin:@dsh-external/dsh-po06'`**(宿主迁移表 `producerKind()` 给第三方插件的规范名), 并去掉 `plugin` 字段。**对两代宿主都成立**:0.1.6 的 v3 对用户消息 kind 不设白名单;"绝不自我触发"那道闸 本来就是正向白名单(只认 `kind === 'user'`),换名字不会漏;0.1.6 界面也从未特判 `kind === 'plugin'`。 - **台账仪器兼容两代形态**:`scripts/dump-wire.mjs` 新增 `producerOf()`——旧形态取 `plugin` 字段、 `plugin:<包名>` 归一到裸包名、真人消息不算插件贡献。**只认一代就等于换宿主后旧台账全读不出来** (仪器报错方向最危险,ADR-0034)。 - **只读工具(「只读工具:开」)链路补齐**,并配 `test/read-tools.test.mjs`(8 项)。 - **验证**:全套 **46 个测试文件 / 618 项全绿**;变异检验 **221 个 / 40 个源文件 / 漏捕 0**(源文件字节还原); `check-release` 全绿(含打包自足性与文档漂移门禁)。新增守卫:投递来源不得再用被 v4 拒收的 `plugin`(静态守卫, 注释里允许也必须讨论"为什么不能这么写")、线缆仪器两代形态单测(旧形态 / 新形态 / 混代台账 / 真人消息排除)。 - **发版过程中抓到并修掉的两处**(都会骗人,所以记下来):① **测试夹具跟不上产物形状**—— `check-install` 的假包 `package.json` 只有 `name`/`version`,而宿主 0.1.7 **在装配前会检查 `dsh.bundle`**, 于是夹具里的包被整块跳过、装配树为空,三条"应放行"用例全红;夹具改成**从仓库那份派生**(只覆盖 `version`) 并补上包根的两份手册。② **一个变异体长期存活**——删掉"缺 `cordis.patch.yml` 就拦"后,用例的三条断言 照样全绿(宿主自己也拦了,装配树本来就是空的);现在断言直接咬住脚本自己的判定出口(`--json` 的 `problems` 必须点名 bundle 层),**不写死正文措辞**。修完 5 个 `checkinstall` 变异全部被抓住。 - **未验(如实登记)**:0.1.7 上的**真实投递**只到"按宿主源码与迁移表改对形状 + 有守卫", 端到端(真模型、真会话)**仍需一次实跑**才作数;观感类结论需真人看;**专业跑分 / 留出评估仍未完成** (只跑完 S1),B 臂(冻结的 0.4.4 对照)**成本基线仍缺失**。 ## v0.6.8-stable — 2026/09/22(**主线 · 正式版**) 作者:啃轮胎的西狐 - **修掉"思考完却拿不到包"(no-packet)**。台账取证:28 条 `noop` 里 **26 条**的原话只有两个字, 同一句话反复重试**每次都空**(有会话连续 16 次)——这不是抖动,是"模型交了空产出,宿主照收"。 现在:① 空产出(空 `ops` / 没吐 JSON)**有界重试一次**(把"你上一轮交了空产出"明确告诉解释层); ② 仍空 ⇒ 宿主补一条**关于这轮原话本身**的待确认条目(`unknown`,不发明要求、不拦下游)⇒ **这一轮必有包**; ③ 条目超单轮上限:**截断记账**(原来整轮作废);④ 销账指向不存在的条目:**逐条丢弃**; ⑤ 用户点「跳过/取消」**不再被记成解析失败**(abort 判定提到解析之前,单列 `empty-completion` 与 `aborted`)。 - **浅色模式**:界面颜色改为**由主题驱动**(一份 token 表、两套取值)。两个真因都修了: ① 主题信号从 `documentElement` 读,而宿主的 token 写在 **`body`** 上 ⇒ 读空 ⇒ 被判成深色 (所以"浅色模式看着跟深色没区别");② token 选择器只覆盖"标记在自身",插件里思维层/折叠体**各自** 带 `data-po06` ⇒ 各自重新声明浅色 ⇒ **深面板里嵌一块浅底**。现在:`body[data-ds-dark-theme]` → 根 `color-scheme` → 文字亮度三级判定(都读不到按浅色),深色规则同时覆盖"自身/祖先/宿主属性"三条路径。 - **语言跟随 DSH**(`zh`/`en`,含 `?` 手册;改设置即时切换、不用刷新)——本版把界面文案全部收口到中英对照, 并给英文适配补了静态+运行时守卫。 - **启用判定修对**(`gate:rollout-off` 调查结论):`rollout` **缺失或写错**时不再把显式 `enabled:true` 的插件**静默关掉**(只有**显式** `{mode:"off"}` 才是不启用);顺带修了 `normalizeRollout` 不幂等 (第二次归一化会把"回落来的 off"洗成"用户显式 off")。`/status` 增加 `gate` **结论分布**, 把"配置意图"与"闸门实际放行"分开显示。 - **修掉一次"配置被重置"的数据丢失**(真机发现:`/status` 显示的设置与文件里写的对不上;随后配置被一次设置写入**重置成默认值**, `settingsVersion`/`enabled`/`rollout` 三个"启用意图"字段被**静默抹掉** ⇒ 插件不再被认作 0.6 自己的配置 ⇒ **明明开着却什么都不做**,也就是用户报的 `gate:rollout-off`)。根因是 **BOM**:Windows 上 PowerShell / 记事本写出的 UTF-8 带 BOM,而设置读路径没剥 BOM(EV-0132 只给 `parseEnableIntent` 补过)⇒ `JSON.parse` 抛 ⇒ 配置被当成"空的" ⇒ `writeSettings` 拿空对象合并后写回一份**只有设置项**的文件。 现在:① 配置读取一律先剥 BOM(`parseJsonText`,设置读路径与 `/status` 共用); ② 万一真的读不出来,先从**最近一份可解析的备份**里把启用意图字段捞回来,并**如实上报** `gateRepaired` / `recoveredGateFrom`; ③ 无论如何都保证 `settingsVersion` 标记在(它只是"这份配置是 0.6 写的",不含任何启用决定)。 守卫:带 BOM 的配置照常读(不许当空配置重写、不许丢字段);坏配置写入后启用意图字段必须从备份恢复。 - **验证**:全套 **46 个测试文件 / 618 项全绿**;新增守卫包括 WCAG 对比度(浅/深两套都算)、 主题信号三级判定、"空产出必有包"、"关档不注入"、"客户端读过的服务必须声明 inject"、BOM 容错与配置字段保全。 - **未验(如实登记)**:观感类结论需真人看;**专业跑分 / 留出评估未完成**(只跑完 S1)——作者的日常实测观察 (DeepSeek-V4.1-Flash + PTC + PowerShell:one-shot 与长任务迭代效果明显强于同环境同提示词,少量项目统计疑似降低 token 消耗)见根 README 的「诚实声明」。 ## v0.6.8-beta.2 — 2026/09/22(已被 `v0.6.8-stable` 取代 · 英文适配 + 对外文本对齐版) 作者:啃轮胎的西狐 - **英文 UI 适配**:界面语言**只跟 DSH 的语言设置**(`设置 → 通用 → 语言`,`zh`/`en`),插件内**不设**语言 开关;客户端文案全部走 `L(中文, English)`(49 条),`?` 用户手册按语言取宿主 `GET /help?lang=zh|en`, 新增 `po06/HELP-0.6.en.md`(带同一 `po06:help-start` 区间标记)并进 `files` 白名单。英文界面不再夹中文。 - **语言探测按真机契约重写(发出后 30 分钟内发现并原地重发)**:`ctx.locale` 是 DSH 的 **LocaleFace 实例** (`dsh-client-locale/lib/client.js` 里 `ctx.provide("locale", locale)`),语言在 `getSnapshot().active`; 第一版按 `v.locale/v.name/v.id/v.language` 猜属性 ⇒ 真机上**永远读不到** ⇒ 恒中文(英文适配等于没做)。 现在:读 `getSnapshot().active`(兼容 `getLocale()/snapshot.active/字符串` 三种形态,拿不到才回中文), 并 `subscribe()` 订阅语言变化 ⇒ **在 DSH 里切语言,插件界面即时跟着换,不用刷新页面**。 > 首发字节(tag 指向 `6f9b972`)已被本次重发取代,tag 与 Release 都指向含本修复的提交;首发字节不再对外。 - **修一次真机白屏崩溃(用户报告:"dsh 突然崩溃"、界面停在 `Failed to load plugins`)**:客户端 `apply()` 读 `ctx.locale`(语言适配)却只声明了 `exports.inject = ['slots']` —— **cordis 对未 inject 的服务 getter 是抛错** (`cannot get property "locale" without inject`),于是客户端 entry 进 `FAILED`、引导层整页白屏。 两条一起修:① `exports.inject = ['slots', 'locale']`(写**服务名**,与宿主客户端插件同一写法); ② 读服务一律走包住的 `readSvc()`,`detectLocale` 也套 try/catch —— 万一某个 profile 没有 locale 服务, 最坏是**用中文兜底**,绝不再整页崩。 > 回归守卫(防同类再犯):① 静态——**代码里读过的每个 `ctx.<服务>` 都必须在 `exports.inject` 里声明**; > ② 运行时——用**照 cordis 语义的 ctx**(未声明的服务读就抛)驱动 `apply()`:没有 locale 服务时要照样注册满 > 3 个插槽、语言回落中文;有 locale 服务时按它定语言。这一版是**同一版本号的第二次原地重发**(首发:缺语言 > 契约修复;次发:缺本次崩溃修复)。 - **README 对外文本与版本对齐**:更正 0.5 线的版本号(**最后发布 `v0.5.0-beta.1`**;仓库内 0.5 源码版本号 `0.5.2-beta.1`,未曾单独发 Release);0.5 的安装不再指向 `releases/latest`(那一页现在是 0.6 线、资产名 不同 ⇒ 404),改为钉 `v0.5.0-beta.1` 直链;英文 README 结构对齐中文(0.6 在前,0.5 设计说明移入附录并 标明边界);两处 README 的 0.6 之前更新日志条目移除,统一指向本文件。 - **测试门禁**:`po06/test/wire.test.mjs` 的两条历史断言按现状改写(覆盖提示词从"全等"改成"以覆盖文件开头 + 追加会话上下文";自检判空的静态定位改成锚在自检独有的分支上,不再被同名的变量声明带偏)⇒ **全套 45 个测试 文件全绿(585 条断言)**,`check-release` 的阻断项从 4 条降到 1 条(只剩变异检验输出解析)。 - **未验**:观感类结论需真人看;真机 + 真模型端到端与效果对比未跑;**本版没有任何"效果更好"的证据**。 ## v0.6.8-beta.1 — 2026/09/22(已被 `v0.6.8-beta.2` 取代 · 对外文本对齐版) 作者:啃轮胎的西狐 - **代码与 `v0.6.7` 等价**(没有新增行为改动);本版按用户要求改用 beta 号发布, 并把**对外可见的文本**(Release 说明、README 中/英、本 CHANGELOG、仓库描述)与这一版对齐。 - **README 的安装方法已按本版真跑一遍**(隔离 home):从 Release 直链下载 ⇒ sha256 与 `SHA256SUMS` 一致 ⇒ 建干净 profile ⇒ `dsh plugin add`(`dependencies` 与 `dsh.profile.bundles` 都写入)⇒ `check-install --expect-version 0.6.8-beta.1` ⇒ **33/33 lib 与仓库逐字节相同 · 装配树含该层 · ✅ 可以开始试了**。 - **未验**:观感类结论需真人看;真机 + 真模型端到端与效果对比未跑;`check-release` 仍因 `wire.test.mjs` 2 条过时断言而阻断;**本版没有任何"效果更好"的证据**。 ## v0.6.3 ~ v0.6.7 — 2026/09/22(**补记**:这几版当时只登记在 `po06/RELEASE-CHECKLIST.md`,没写进本文件) - **v0.6.3** 拦截弹窗拖拽回归修复:入场动画的 `transform` 填充盖住了拖拽写的**内联 transform**(关键帧改成只碰 opacity)。 - **v0.6.4** 位置夹紧不再把面板钉死(面板高于视口时旧式夹紧恒等于 8);引文判据从"整轮作废"改成"只丢那一条并记账"。 - **v0.6.5** 控件栏收成「优化选项」按钮 · **撞 id 改名不再判死整轮**(no-packet 真因:解释层每轮从 `req-1` 起编号, 而旧条目只退场不删除)· **跳过/取消之后真的停**(连接断开 ⇒ AbortSignal ⇒ 提交前闸门 + 模型调用随信号中止)。 - **v0.6.6** 「优化选项」弹层可见(`position: fixed` 却没给坐标 ⇒ 落在看不见的地方)。 - **v0.6.7** 面板控件**铺满整格**且点击范围与视觉重合 · 模型下拉不再白底白字(跟随主题 `color-scheme`)· **DSH 主题副色**克制用在选中/悬停/键盘焦点三处。 ## v0.6.2 — 2026/09/22(**主线**) 作者:啃轮胎的西狐 - **拦截弹窗:功能性区域不再被裁** —— 正文区从 `overflow:hidden` 改成 **`overflow:auto`**,内容装不下时 由**这一处全局滚动**(就是 0.5.x 的那根滑块;细、低调、悬停才明显)。面板本身 `maxHeight: min(78vh,660px)` 并随窗口重新夹紧(自适应);思维层仍是它自己那个固定窗口(内部滚动条隐藏)⇒ 不会回到"两根可见滑块"。 - **交互反馈与极简动效**(注入一小段样式表,卸载即摘):所有插件按钮 130ms 过渡 + 悬停/按下/键盘焦点/禁用态; 浮层入场 140ms 上浮淡入 · 运行中状态灯呼吸 · 思维层新内容 180ms 淡入;`prefers-reduced-motion` 下一律关闭。 - **观感**:圆角 12→14px、阴影更收敛;配色继续沿用 DSH 自己的变量(`--dsw-*`),浅色/深色主题与 DSH 一致。 - **未验**:无截图证据(我无法对 GUI 截图),观感与动效幅度**需真人在真窗口里看一眼**; 全量 45 套 · 44 通过(唯一未过是 `wire.test.mjs` 里 2 条早已过时的断言)。 ## v0.6.1 — 2026/09/22(**主线**:0.6 线,包名 `@dsh-external/dsh-po06`) 作者:啃轮胎的西狐 - **这是主线**:默认分支 `main` 与最新 Release 都是它;0.5 线(`v0.5.x`)保留在下方历史与 tag 里,仍可用但不再更新。 - **每轮独立产生目标,不遗传**:每轮开始把上一轮的条目与待问问题整体退场(`stale`,留档不删除), 本轮的包只由「你这轮的原话 + 本轮读入的会话上下文」重新得出 ⇒ 不会再出现"上一轮早已解决的问题又被要求一次"。 **代价**:长期约束("只交单个文件""别动别的文件夹")也要靠上下文每轮重新看出,别把「上下文」调得太小。 - **界面对齐 0.5**:档位 `关闭/轻度/标准/重度` · 两行控件栏 · `?` 用户手册 · 拦截浮层分**思维层 / 产出层** · 思维层**固定显示范围、无滚动条、正文不截断**(可往回滚,自动跟到最新)。 - **token 计数**:只用 provider **真实上报**的 `入 / 出 / 缓存` 三分量(过千记 `k`/`M`,拿不到就显示 `—`,从不估算)。 - **只读工具那条必现故障的真因(三条)**:解释层标识符笔误 `TOOL_SYSTEM_NOTE is not defined`; 一条写坏的来源引用能弄死整轮(`kind:'tool'/'file'` 的 `toolCallId`/`uri` 只有宿主才有 ⇒ 现在只补宿主能机械核对的事实、其余逐条丢弃并记账); `provenance:'machine'` **从未生效**的顺序缺陷。 - **移除**「条目与结案」面板与其宿主通路(目标每轮自动产生,不再需要人工勾选)。 - **文档**:根 README(中/英)改为以 0.6 为主线并写明 30 秒安装;`po06/README.md` 给出照抄即可的下载+安装+自检; `?` 帮助写明"不遗传"及其代价。 - **未验**:全量 45 套 · 44 通过(唯一未过是 `wire.test.mjs` 里 2 条早已过时的断言);真机 + 真模型端到端与效果对比未跑。 **本版没有任何"效果更好"的证据。** ## v0.5.2-beta.1 — 2026/09/19 作者:啃轮胎的西狐 **交付门(机器替员工验):任何被 present 的网页类交付物,落盘后由宿主侧真机打开一次,写成机器裁决——不再采信模型的"Everything is verified."** 权威定义见 [SPEC.md](SPEC.md) §0⁵。 **病根(会话日志可复核 · `session-7df19a05`)**:工作会话在 **workspace-write** 档下交付前两次尝试 `msedge --headless --screenshot`,两次都是 `SHOT_MISSING` + `Program 'msedge.exe' failed to run: Access is denied`——**它从没见过自己的产物**;随后退回静态检查(标签平衡 / 19 个 script 块 / 0 处外链)并写下 **"Everything is verified."**。而那两个文件里有: 1. **三层着色器拼装 bug**(`mbt-m1a2-sep-v3.html`):① `