# Changelog 本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本遵循语义化版本。 发布前版本 `<1.0.0`:破坏性变更会在 Minor 版本体现。 ## [Unreleased] ### 新增(2026-09-09,上游对照 openclaw-weixin 2.4.8 后的借鉴批次) - **OpenClaw 2.0 投递语义对齐**:发送超时标记 `uncertain`,不盲目重发;仅明确未建立连接的网络失败自动重试;下一次入站携带系统备注。入站文本默认 2 秒防抖合并,媒体立即冲刷;轮询网络重连采用 2/5/15/30 秒退避;停机为出站队列提供 4 秒有界排空。 - **配置与凭据卫生增强**:拒绝 `baseUrl` 中的凭据型 userinfo/query;allowFrom 条目 24 小时零匹配时告警;重新启动轮询代际时清理 typing ticket;修正游标存储的过时注释(游标本已持久化)。 - **QR 验证码状态机补全**(P0):`need_verifycode`(CLI stdin / 面板输入框)→ 携 `verify_code` 立即重轮;`verify_code_blocked` 清码 + 刷新二维码 + 3 次封顶;`expired` 刷新计数封顶。此前服务端要求数字校验时配对会挂死到超时。 - **QR 请求上报 `local_token_list`**(P0):最多 10 个已有 bot_token,服务器 据此识别已绑定 bot(对齐官方 2.3.1,防重复绑定会话)。 - **notifyStart/Stop 返回检查**(P0):上线通告被服务器拒绝(ret≠0)时置 `paused` 并提示重新配对,不再假装 polling。 - **入站 file/video 下载落盘**(P1):复用入站 CDN 管线(assertCdnUrl/手动 重定向/流式限长),扩展名 mime 表,路径交给会话;voice 无转写文本不再 静默丢弃(明确告知用户改用文字)。 - **出站媒体支持远程 URL**(P1):`uploadAndSendMedia` 接受 http(s) URL (私网/环回段拒绝 + 30s 超时 + 上限),能力层就绪。 - **桥级暂停开关**(P1):面板一键暂停/恢复;暂停时入站只记日志不进模型, 凭据/队列/会话保留。 - **健康快照**(P2):`healthSnapshot()` 命名原因(starting/reconnecting/ no-inbound-since-boot/…)+ 每条 issue 自带 fix 建议,状态端点与面板展示; 纯只读,无任何探针发送。 - **日志脱敏收敛**(P2):debug 三个 sink 统一键名脱敏(token/aes_key/ typing_ticket/qrcode_img_content…);`encrypt_query_param` 以长度保留 形式掩码(形状对照价值不丢,下载凭据不落盘明文)。 - **配置 strict 校验**(P2):未知配置键启动即报错(schemastery 默认静默 保留未知键);新增 `botAgent` 配置(base_info.bot_agent,UA 语法 sanitize, 256B 上限——默认值跟随真实包版本,修复硬编码 0.1.0 失真)。 - **配对治理**(P2):信任待确认与 bot 身份切换请求 10 分钟 TTL;请求/ 确认/拒绝/吊销/过期全部审计进 events.jsonl。 - **typing ticket stale-while-revalidate**(P2):过期票先服务再后台刷新, 消除打字指示中断窗口。 - 上游对照全程记录见 `docs/porting-notes.md` 与 `docs/protocol.md` §9/§10。 ### 修复 - **Web 面板跨层契约修复(审查批次)**: - `pause` 往返死锁:客户端原先发 `String(!paused)`,服务端 `Boolean("false")` 恒真 → 面板暂停后无法恢复。改客户端发布尔、服务端仅 `=== true` 才暂停。 - `/status` 500 崩屏:客户端无 `res.ok`/`data.ok` 校验,把 `{ok:false}` 当合法 Status 渲染,缺 `prefs/outbox` 时白屏。改非 2xx/非 ok 时保留上次状态 + 子字段可选链兜底。 - **共享会话面板恒空**:`/status` 从不产 `sessions`,且 `/sessions` 形状与客户端 `Status.sessions`(`{id,label,status,lastActivityAt,enabled}`)不符。新增共享 `SessionInfo` 契约,`/status` 与 `/sessions` 统一产出该形状(含 agent 状态映射)。 - **吊销残留**:`revokePairedUser` 只清了持久化 state,运行时 `sessionOwners`(`peerOf`/审批路由读取)未级联,吊销后该用户仍可能在进程内收到其会话的出站/审批。改运行时归属级联删除 + 取消其活跃 turn。 - **入站媒体 message_id 路径穿越**:`message.message_id` 未经校验直接拼文件名。新增 `sanitizeMessageId`(限 `[0-9a-zA-Z_-]{1,64}`,否则回退数字戳),图片/文件/视频路径统一净化。 - **README/release 对齐**:测试数 220→242;README 重复「移动端完整体验」行删除;RELEASING 明确 `dry-run/probe-media/wrap-client` 为开发期工具不进包。 - **二维码面板自动刷新(L3)**:网关在 QR 过期/验证码受限时会重新签发新码并更新 `pairingQr`,但面板只取首张、永不感知变化(旧码扫码必失败)。改 `/status` 暴露当前 `qr` svg,面板轮询时同步刷新显示;配对按钮改为可手动重发起(不再是 `pairing` 永久禁用)。 - **长任务出站静默根因修正(2026-08-19 实测)**:`prepare failed` 的归因从 "context_token 时效"修正为**会话窗口出站配额**——服务器对每个用户入站窗口 允许约 10 条成功出站(三次实测均恰好第 11 条失败),超出后一切发送失败且 tokenless 降级重发实测 5/5 不恢复,直到用户下一条入站消息重置窗口。原 "tokenless 恢复"机制(b4c3720)在窗口耗尽场景下无效。 - **must 最高优先级**(`OUTBOX_PRIORITY.must`,新增):最终答案、审批提示、 出错/停止通知、critical 重推**豁免窗口配额**,永远尝试发送——服务器配额 永远优先保障用户明确要求的消息 - **窗口配额会计**(outbox):per-peer 计数窗口内成功发送(入站重置, `sessionWindowSendMax` 默认 10);非 must 条目超配额直接跳过(drop 'quota', 静默、不占队列) - **心跳/todo 让位**(`HEARTBEAT_QUOTA_RESERVE=3`):窗口剩余 ≤3 条时心跳与 todo 快照源头停发,配额留给最终答案;「正在输入」typing 指标(独立 API) 继续维持存活信号 - **stale-session 直弃**:`prepare failed` 不再退避重试 5 次、不再暂停队列 (实测不会自愈,重试只拖延恢复);must 消息立即入恢复重推队列 - **答案整段重推**:多分块最终答案任一块失败时,整段文本入恢复重推队列, 用户下一条消息到达时重新分块补发(绝不出现只有 "(2/2)" 的残缺答案) - 观测:`poll-token-bearer`(轮询中带 context_token 的非 USER 消息,探索 主动刷新路径)、`typing-failed`、`critical-message-dropped` 增加 wholeAnswer 标记 - 文档:docs/protocol.md §5/§6 按实测证据重写;README 已知限制更新 - 测试 220→226(窗口配额/重置/must 优先级/stale-session 直弃/整段重推/ 配额跳过不进重推链) - **Security hardening**:开源前全量安全审计(5 维 ~60 项)后的集中修复,详见 README「安全模型」。要点: - 设置面板端点补齐浏览器信任栅栏(Host 回环/声明主机 + Origin 同源 + 拒绝 cross-site),与平台 `/api` RPC 栅栏同语义 - 配对信任收敛:首个扫码者自动 bootstrap 信任集,后续扫码者一律进入面板 确认门;不同 bot 身份扫码须面板确认才覆盖凭证;面板可吊销已配对用户 (吊销即清除其会话绑定与令牌并通知本人) - `/video` 限定配置根目录(默认 cwd+媒体目录)内的 ≤10MB `.mp4` 普通文件, realpath 防符号链接逃逸,ftyp 魔数校验 - 媒体下载 URL 白名单/超时/大小上限;baseUrl 跳转主机校验 - 群聊引用消息只保留标题(正文可能来自未授权成员);引用递归上限 8 层; 多文本片段全量聚合不再截断 - 出站 `-12`/`-14` 丢弃经 `onDrop` 进入恢复重推链;文件回退一次性; 同一发送者入站消息串行化(消除双会话竞态);命令异常回执兜底 - 孤儿会话收养收紧:仅创建者可收养;`/close` 释放的会话永不改属; 无创建者记录的旧会话仅单人信任集可继承 - 状态/日志文件 0600、媒体捕获 aeskey 脱敏、token 尾缀截断、导出文件 原子写+随机后缀、配置内联 token 警告、数值配置 min 约束 - 测试 170→220(信任准入/孤儿收养/栅栏表/视频校验表/回退一次性/限流重推等) ### 新增 - **关键消息必达重推(2026-08-18 事件全量梳理后)**:DSH session 46 种事件按 用户可感知度分类——必须触达(审批/最终答案/出错/停止/截断/完成播报)、低频 存在信号(心跳 120s + 原生 typing)、静默(中间叙述/工具/步骤等 38 种)。 必须触达类消息全部带 `resendOnRecovery` 标记:通道故障期间发送失败即记录 (每用户最多 3 条、同文本去重),用户下一条微信消息(= 通道恢复)时按序补发。 审批提示沿用专属重建路径(避免重推已超时审批)。 - 测试 124→126(关键消息重推 + 积压上限去重) - **关键事件独立日志** `events.jsonl`:inbound/send(含 token 尾缀与失败分类)/ poll/notify/审批生命周期写入独立 sink,不再被 assistant/chunk 高频事件在 debug.log 轮转中冲掉(2026-08-18 排查教训)。 ### 变更 - **长任务默认静音(2026-08-18 二次修复)**:实测发现服务器在会话窗口约 5-10 条 后触发发送风控(`prepare failed` 持续数分钟,tokenless 亦被拒),中间消息过多 正是导火索。产品决策: - 中间工具叙述(assistant/message 非最终轮)不再推送微信,仅缓存;最终答案在 `turn/end` 一次送达(completed / max-tokens 均冲刷,aborted / error 不发) - 出站滑动窗口预算:默认 60s 窗口最多 4 条(`sendBudgetWindowSec` / `sendBudgetMaxPerWindow`),超限排队等待窗口滚动,**消息不丢只延迟** - 执行中心跳降频降噪:`thinkingDigestSec` 默认 15s→120s,文案精简为 「🔄 仍在处理中 · 已调用 N 个工具 · 用时 M 分 S 秒」(工具名/思考字数不再推送) - 最终答案以 system 优先级入队,确保先于「⏱ 用时」送达 - 测试 120→124(窗口预算 2 项 + 静音冲刷管线 2 项) ### 修复 - **出站断流根因修复(2026-08-18 事故,stale context_token)**:iLink 对过期 context_token 返回 `ret=-2 errmsg="prepare failed"`,旧实现把它当"服务器拒绝" 直接丢弃,长任务执行超过 token 时效后所有消息(含审批提示)静默丢失——表现为 "发了几条后没消息 / 出现任务计划后卡住"。本次: - 错误分类 `classifySendFailure()`:`prepare failed` / `unknown error` = stale session;`rate limited` / `freq limit` = 限流;`-12` / `-14` 保持。 - **tokenless 恢复**:stale session 时 compare-and-delete 缓存 token(并发 刷新不被误删)→ 无 token 重发一次(不消耗重试预算),后续重试自然 tokenless (iLink 接受降级发送,hermes/openclaw 同款策略)。 - `ret=-2` 统一退避重试(10s→30s→60s,预算 5 次)而非立即丢弃。 - 发送失败不再静默:重试耗尽后向用户通知「❌ 消息发送失败」。 - **审批必达手机(2026-08-18)**:审批提示发送失败不再放弃——标记待重推, 用户下一条入站消息(= 通道恢复 + 用户在场)自动重推;提示带审批 coalesce 键, 排队中不堆积。等待窗口内通道始终不通才超时自动拒绝(GUI 审批卡片兜底可见)。 ## [0.2.0] - 2026-08-17 ### 移除 - **origin 徽标(🟢 侧栏标记)与全部 DSH 部署补丁(2026-08-17)**:按用户铁律 「禁止以打补丁方式实现需求,宿主不支持即如实说明」废弃——此前用 8 项手动补丁 放宽 DSH 的 origin 校验来实现徽标,升级即碎且曾导致 dsh web 无法启动。现在 插件零宿主依赖:不写 origin 头、不修改任何 DSH 部署文件,任何 DSH 开箱即用。 DSH 若原生支持自定义 origin 再恢复该能力。 ### 新增 - **UX 打磨批(2026-08-17,产品评审 9 项)**: - 会话消息去内部 id(创建/恢复/列表/切换/归档改用模式名、首句、编号) - 每条完成回复附用时(`⏱ 用时 23s · 3 个工具`;长任务播报保留富版) - 媒体发送失败不静默(重试耗尽后通知原因;文件已有文本降级) - 断线恢复通知(连续轮询失败后恢复,向信任用户广播「✅ 已恢复在线」) - 欢迎消息与自动创建说明默认模式(未配置时明确「DSH 默认角色」) - `notifyRejected`(可选):陌生账号尝试联系时通知信任用户(默认关) - 上下文压缩事件提示(compaction/start →「🧹 上下文已自动压缩」) - `/sessions` 行增强:上下文用量 + 相对时间(`N. 首句 · 上下文 12.0k · 2h 前 ▶`) - 思考心跳默认 10s → 15s(长任务减少打扰) - **执行中停止交互(2026-08-17)**:任务开始时思考心跳附「回复 /stop 可停止」 (发现性);执行中直接回复「停 / 停止 / 算了 / 别做了 / 不做了」即取消 (idle 时不拦截,不吞普通消息);停止即时反馈「⏹ 正在停止…」,turn 结束 附完整确认(思考字数 · 工具调用数 + /retry 重跑引导);无任务时提示 「当前没有执行中的任务」。 - **零配置会话(2026-08-17)**:微信发消息时若无活动会话,自动按顺序 恢复绑定会话 → 恢复最近孤儿会话 → **自动创建默认模式新会话**并投递消息 ——用户永远不会被"没有活动会话"卡住;恢复/创建失败才提示手动操作。 - **每轮上下文用量提示(2026-08-17)**:每轮结束后附一行 `🧮 上下文 Xk / Yk(N%)`(最新输入 token vs 模型 contextWindow); ≥70% 提示"接近上限会自动压缩,建议 /new";超限提示自动压缩; 模型未披露窗口时只显示用量。用户始终知道会话上下文状态。 - **扫码即配对(多用户,2026-08-17)**:每次配对确认的微信 id 追加进持久化白名单 (`pairedUserIds`),后扫不顶先扫——任何人在 Web 面板扫码即自助接入,无需手动 配置;`isAllowed = allowFrom ∪ 全部配对者`;旧单 owner 凭证自动迁移。 - **多用户 1:1 隔离(2026-08-17)**:模型/工作区/思考偏好改为 per-peer(旧全局单例 不再跨用户串扰,旧值迁移到 default 桶兜底);孤儿会话恢复增加历史守卫——新用户 不会继承其他用户关闭的会话。 - **视频外发打通(2026-08-17 晚间)**:根因 = 类型号错误(此前把 VIDEO 写成 type:3 实为 VOICE,语音通道"API 接受但客户端静默丢弃");修正为 ITEM_VIDEO=5 后 openclaw 精简形状单发即端上正常显示。`buildOutboundMediaItem` 加 VIDEO 分支,新增 `/video <路径>` 命令。教训:发送常量必须用本地库 ITEM_*/UPLOAD_MEDIA_*,禁止手写数字。 - **bot → 微信 媒体外发打通(终局,2026-08-17)**:官方形状 (`xep + aes_key=base64(hex)44字符 + encrypt_type:1 + mid_size`)端上验证成功, 手机正常显示图片。生产 `buildOutboundMediaItem` 已改为官方形状;`/export`、`/card`、 长文转文件(`fileThresholdChars>0`)立即可用。根因定案(此前"客户端渲染门禁"结论 推翻):旧形状用 `upload_param` 当下载引用 + 自创 `full_url`/`image_item.aeskey` 附加字段 + 缺 `encrypt_type`;`ret=-2` 实为限流/会话错误(openclaw #216 印证)。 详见 docs/porting-notes.md §6.2。 - **Markdown 渲染实测矩阵(P1)**:生产通道单发验证 h1-h4/粗体/斜体/行内代码/ 列表/引用块/表格/代码块/分隔线/链接全部正常;确认 **CJK 斜体**为已知边界 (中文字体无斜体,标记可能透出 → filter 模式剥离),见 docs/verification-records.md。 - **typing 心跳(P1)**:长任务期间按 `typingHeartbeatSec`(默认 25s,0=关闭)重发 「正在输入」指示,避免客户端长时间无刷新后停止显示;停止/结束自动取消。 - **命令体系手机端体检(P1)**:/help 按类别分组(会话/模型/审批/其他)便于扫读; 命令示例去除业务化引用(改为通用示例)。 - **通道健壮性(P1 审计,见 docs/verification-records.md)**: - 出站失败分类重试:传输层失败自动重试(最多 3 次尝试,自然退避), 服务器显式拒绝不重试——消除"网络抖动丢回复"; - context_token 持久化(state.json):重启后主动推送/出站仍带会话上下文; - get_updates_buf 持久化(poll-cursor.json,带所属 bot 身份)+ 会话过期 保留游标(对齐官方 monitor)——消除重放/漏消息边界; - **引用回复(ref_msg)**:用户引用某条消息时,被引用内容(标题+正文,含嵌套引用) 以 `[引用: …]` 形式带进 agent 上下文——逐字段移植官方 bodyFromItemList; 引用媒体消息时仅保留当前文本(对齐官方语义)。协议类型补 RefMessage 定义。 - **配对欢迎引导(first-run)**:扫码配对确认后自动向配对者推送引导消息 (/modes 提示 + 命令速览 + 信任来源说明)——新用户零配置即可上手。 - **/status 产品化**:新增配对账号、白名单方式(配置/自动)、发图通道状态三行, 回答"我是谁/谁可信/为什么发不了图"。 - **扫码配对即自动白名单**:配对确认时保存 `WEIXIN_ILINK_USER_ID`(扫码者的微信 id), 桥运行时动态放行该 id——新用户安装后只需「安装 + 扫码」两步,无需手写 `allowFrom`; `allowFrom` 降级为可选的收紧/多用户配置(状态端点新增 `pairedUserId` 字段)。 - **`/modes` 全量模式**:列出全部 agent 预设(含中文名称与说明,读 DSH `agentPresets` 服务), 每项附可复制快捷命令 `/new `,且**回复编号直接创建**(菜单 60 秒内有效)。 - **`/model`**:桥内模型偏好。列表选择(供应商→模型)或显式 `/model /`; `/model default` 恢复跟随 DSH 默认。仅对 `/new` 新建会话生效,持久化到桥状态文件。 - **`/workspace`**:桥内工作区偏好,仅允许选择 DSH 已注册工作区(安全默认); `/workspace default` 恢复默认。仅对 `/new` 生效,持久化。 - **`/retry`**:重放本 peer 最后一条任务;**`/close`**:归档当前会话并解绑。 - **`//` 转义**:以 `//` 开头的文本原样发给 agent(`/` 开头不再必然被当作命令)。 - **`/help` 注册表化**:命令注册表是单一事实源,`/help` 与未知命令提示自动同步;`/help <命令>` 看详情。 - **会话来源徽标**:微信创建的会话写入持久化 `origin: 'wechat'` 头部,DSH 侧栏渲染 🟢 徽标 (悬停"来自微信";需 harness 补丁,相关配套文档已移除)。取代早期方案——不再写 `🟢 微信 ·` 标题前缀,会话标题回归干净的首句。 - **`/modes` 精简**:每模式一行(编号+中文名+id+22 字截断说明+默认标记),整体约 370 字; 去掉逐条 `/new` 行(微信复制整条气泡,逐行命令无选择性复制价值)。 - **FILE 附件通道(P1)**:CDN 上传全流程逐字段移植(`docs/porting-notes.md §6`)。 全矩阵探针证实本后端对 bot 外发媒体"消息可送达、内容取流不通"(官方/nanobot 参考实现同病), 故 `fileThresholdChars` **默认 0=关闭**;`/export` 保留(后端支持后立即可用)。 - **`/thinking` 开关(P1)**:`/thinking on|off`(per-peer 持久化),开启后思考心跳附带最近 60 字原文。 - **任务完成主动推送(P1)**:`notifyOnComplete`(默认关)+ `notifyMinTurnSec`(默认 300s); 长任务完成后主动发完成摘要。存储 token 主动发送已探针 ack,端上可见性待实测。 - **媒体留存清理(P1)**:`mediaRetentionDays`(默认 30)每日清理媒体/导出文件。 - **群聊支持(P2)**:`allowGroups: [{roomId, allowFrom}]` room 级两层白名单;群内静默 (无心跳/typing/进度卡片,只回命令结果与最终答复);每 room 一个活跃会话。 **实测判定(2026-08-16)**:iLink 机器人身份无法被拉入普通微信群(腾讯侧限制, 官方参考实现 group_id 未实现、同协议项目文档同样标注),配置保持就绪待群事件投递开放。 - **长图骨架(P2)**:`cardMode: 'off'|'long'`(默认 off)+ `/card` 命令——Markdown→HTML→ Chrome headless 两段式截图→IMAGE 发送;Chrome 路径自动探测(可配 `chromePath`)。 - **多好友绑定**:会话按 peer 绑定(持久化),回复/审批路由到会话所属 peer;context token 按 peer 保存。 - **Markdown 保真策略**:微信客户端对 iLink 机器人消息支持 Markdown 渲染(实测全格式通过)。 默认 `passthrough`(仅把 `![图](url)` 转成可点 URL);可选 `filter`(官方过滤器逐字段移植)与 `plain`。 - **思考进度**:`reasoning-delta` 聚合为 `🤔 思考中…(N 字)` 心跳(`thinkingDigestSec`,默认 10s); `todo/write` 变化推任务清单快照;`turn/end` 错误附 `/retry` 引导。 - **工具进度卡片**:`TOOL_CALL_START/RESULT`(type 11/12)按官方 `reply-progress-sender` 逐字段对齐发送; **默认关闭**(`progressToolPrefixes: []`)——send-only 探针实测当前微信后端对卡片 item 静默丢弃(200 空响应、不投递),手机端已核对确认无卡片显示;后端支持后填前缀即可启用。 其余工具只进聚合心跳,防骚扰。 - **限流感知出站队列**:单一串行队列 + 最小发送间隔(默认 5s)+ 优先级(审批>终态>正文>进度) + 进度合并(coalesce)+ `-12` 指数退避(10/30/60s)+ `-14` 全局暂停 1h(对齐官方 session-guard)。 - **typing ticket 缓存**:24h TTL + 指数退避(官方 config-cache 语义),不再每次发送都调 getConfig。 - **入站幂等持久化**:seen 集合落盘(TTL 10min / cap 2000),重启后游标重放不再重复执行任务。 - **审批参数摘要**:经 callId 反查会话日志中的工具参数,审批文案展示参数摘要。 - **图片回显修正**:微信端只回「已收到 N 张图片」,不再回显本机绝对路径。 - **Web 面板扩展**:模式中文名、桥内偏好(模型/工作区)、Markdown 策略、出站队列/限流状态、最近发送错误。 ### 变更 - **移除配置** `digestIntervalSec`、`sendChunkDelayMs`(心跳与节流由 `thinkingDigestSec` 与 `minSendIntervalMs` 取代)——**破坏性配置变更**,见 README 配置表。 - 默认心跳语义:active turn 内按 `thinkingDigestSec` 刷新思考摘要;无新进展不重复打扰。 - `/sessions`、`/use` 现在只列本 peer 的会话(多好友隔离)。 - `sendText` 返回结构化 `SendResult`(ok/ret/errcode/messageId),发送错误不再被吞。 ### 修复 - **外发媒体 `full_url` 相对路径缺陷**:`cdnBaseUrl` 配置默认值为空时,媒体 item 的 `full_url` 被拼成 `/download?...` 相对路径;现 Config 默认 `WEIXIN_CDN_BASE_URL`, 且 `uploadAndSendMedia` 有兜底(`cdnBaseUrl || WEIXIN_CDN_BASE_URL`)。媒体 item 组装 抽为纯函数 `buildOutboundMediaItem`(`src/gateway/upload.ts`),单测锁定官方形状 (44 字符 key、无 encrypt_type、绝对 full_url、image.aeskey/mid_size、file.len)。 - **媒体外发探针工具**:`scripts/probe-media.mjs` —— 生产 lib 产物端到端探针 (getUploadUrl → AES-ECB → CDN 上传 → sendMessage),形状变体 current/official + item 字段二分 + context_token + 服务器自下载闭环;§6.1 重测工具。 - **`run_id` 协议缺口**:官方 `buildTextMessageReq` 的 `run_id` 字段此前漏移植——现已全链路补上 (网关 `InboundEvent.runId` → per-peer 保存 → 出站 `sendMessage` 携带),工具进度卡片与 run 的关联对齐官方。 - 独立代码审查(子代理全量 diff)发现并修复:思考心跳空状态刷屏(H1);模型菜单跨 peer 串线(M1); 重启后旧会话不可恢复(M2,改查 sessionPersistence + 激活提示);`/status` token 字段名错误(M3); `/model default` 空字符串阻断配置级回退(M4,`setPrefs` 空串=删除);工具卡片跨调用串名(L1); 面板错误横幅不随成功清除(L2);typing 票据跨用户复用(L3,改 per-user 缓存);`/close` 不先取消运行中 agent(L4);暂停 sleep 未 unref(L5);菜单编号越界即关菜单(L6,改为保留菜单);死参数/死代码清理(L7/L8)。 - **侧栏 🟢 徽标不显示的根因**:`dsh-client-ui-workspace` 的 `sessionNode()` 以白名单拷贝字段, `origin` 未透传到行节点——已在 harness 补丁中补上(与徽标渲染一并;相关配套文档已移除)。 - 状态与 seen 文件 dispose 时 flush 被跳过(先置 disposed 后 flush)——已修,测试覆盖。 - 出站队列在同步批量入队时的排序/合并竞态——泵启动改为微任务。 ## [0.1.0] - 2026-08-15 - M0 骨架(双插件、配置 schema、挂载验证) - M1 通道:iLink 客户端(QR 登录 / 长轮询 / 文本收发 / typing)+ 登录 CLI - M2 桥接:白名单 / 多模式动态路由 / 审批 / 长文分段 + 测试 - M3 图片进会话(CDN 下载 + AES-128-ECB 解密)+ Web 设置面板