Releases: panzeyu2013/dsh-chamber
Release list
dsh-chamber v0.4.1
[0.4.1] - 2026-10-03
新增
- 侧边栏每来源视图选项(对齐上游) —— 每个来源可在 pin 分区 / 平铺列表 / 工作区树之间切换,并对归档过滤;pin 面与上游一致(design 06 §5/§7/§10:kebab 的 pin/unpin 位于重命名之前、悬停簇最右键为 pin/unpin、尾部状态槽之后是非交互的固定标记;写入走官方幂等 RPC,无乐观回显,失败落行级错误,pin 集合沿用归档集合的三态纪律)。
- 工作区折叠态字形 —— 工作区与管理头部按折叠状态显示开/合文件夹字形。
- 每来源面板轴入口落在来源头 ——
sidebar.panellist的宽态入口渲染在其所属来源的 server 头动作簇首位(视图选项左侧、与其余头部动作共用 hover 揭示,静息不占位),取代 beta 期「来源头与浏览区之间的 36px 面板行」;折叠来源头仍在、入口不随浏览区收起,rail 仍保留上游全局面板字形行,每个条目任一时刻恰好挂载一次(design 05 §2 / design 06 §4.7;宽态不再有上游nav[aria-label]分组壳、选中态只在簇现形时可见,按裁决登记)。 - open-in 占用上游 files-tab 目录动作座席 —— 跟随 rc.2 的目录动作位(design 16 §3/§5、design 20 §6.3)。
- 托管主机继承登录 shell 环境 —— 桌面侧先按用户登录 shell 解析环境,再拉起托管实例(design 05)。
- 捆绑 dsh 前端基线升至 0.2.0-rc.2 —— 官方前端与连接客户端一并对齐该基线。
- 打包移动客户端(design 17 §18) —— 自研客户端插件为窄屏/触屏提供完整移动视图:视口档位与资源手术(keyed viewport token 与 theme-color 镜像,进出档位按 key 还原)、抽屉导航(安全区、inert 回收、与官方状态锁步)、composer 键盘抬升(visualViewport 观测、单执行器、停滞自愈)、会话停滞提示与自动重建(共享阶梯表;预算用尽后的文案优先)、设置面板与官方 hover card 的触屏适配;gateway 在认证边界内提供移动入口(
/chamber/mobile.html为兼容页,--mobile-entry归一为同源路径)。 - 本地
@引用的宿主路径面(design 25 §5.7 / S-56) —— Electron 经webUtils.getPathForFile精确取路径,Swift/WKWebView 以「拖拽板快照 + 事件批次唯一配对」补齐;两腿共用data-chamber-painted-source作用域门,vendor 补丁把 ui-attachment 的 document 级 drop 收敛到落点所在壳(同批修掉既有的图片双附),失配一律回退上传,不给错路径。
变更
- 侧边栏悬停揭示改为按行门控 —— 指针下滑进入的行不再立即揭示动作簇;重命名抑制优先于门控揭示;StrictMode 重挂载后门控按新行重建(design 06 §7)。
- 设置 → 内置插件 —— 内嵌插件页的标题块按位置隐藏,只保留上游内容本体。
--mobile-entry校验收紧(破坏性) —— 入口必须是同源绝对路径、不得含查询/片段、不得指向/auth*;旧版把原样值当重定向目标(半可用且静默截断),现在启动即exit 2。- 移除归档后提示(design 06 §3.4) —— 侧栏不再实例化上游的 RowActionToast:archived / stoppedAndArchived 两态与其 undo / show-archived 动作、按 kind 的 TTL 模型、dismiss 管线与两本字典里的死键一并删除;archivedNotOpenable 警告保留(独立触发、3s 普通 alert)。已知代价:归档集未知的降级来源上,已归档行被本地墓碑隐藏、要到该来源挂载且基线落地后才能恢复(被删掉的 6s undo 是覆盖该窗口的入口)。
修复
- facts 应用步骤的重入环(React #185) —— 通知/facts 步进链在写入 store 触发的同步渲染里再回调自身时,React 以 #185 中止且异常被 never-throw 守卫吞掉,导致整拍作废;现在 `apply-session-facts` 按来源过重入闸(非重入仍同步执行),重入只登记并补跑最新快照,撤回来源的待应用快照随撤回丢弃;`reconcile` 与 `completion-arm` 语义不变(design 19 §3.7)。
- 连接重置期间的会话投影事实保留(design 05 §2.3) —— 连接代际变化会让客户端清空会话投影、直到下一次 session/list 回填;窗口期内侧栏行会丢失持久 title 与稀疏 hasActiveSchedule 标记(实测:远端来源在 0.6–0.8s 内把会话名显示成目录名)。现在行会携带最后一次已知的投影事实跨越该窗口:非空 title 始终优先,行消失即丢弃记忆,updatedAt 前进即停止携带(无定时器、无状态),挂载推送与 unary 回退两个提交点都适用。
- 被删除的工作区行不再滑到列表尾部(design 05 §2.2.1 / design 06 §7) —— 宿主先按不含被删 id 的顺序发 order follow 帧、后发 remove,窗口期内 pinned store 把未命名项排到最后,侧栏的 keyed-row 动画会把注定消失的行滑到末尾再消失。删除漏斗现在在 workspace/delete 线前先发 reportWorkspaceRemoving(未提交时由 reportWorkspaceRemovingFailed 撤回),App 在渲染末记账,投影按「上一条投影的真实尾部」摘掉尾部的 pending 段——行就地卸载;无尾部证据时保持 no-op。
dsh-chamber v0.4.1-beta.2
[0.4.1-beta.2] - 2026-10-02
新增
- 侧边栏每来源视图选项(对齐上游) —— 每个来源可在 pin 分区 / 平铺列表 / 工作区树之间切换,并对归档过滤;pin 面与上游一致(design 06 §5/§7/§10:kebab 的 pin/unpin 位于重命名之前、悬停簇最右键为 pin/unpin、尾部状态槽之后是非交互的固定标记;写入走官方幂等 RPC,无乐观回显,失败落行级错误,pin 集合沿用归档集合的三态纪律)。
- 工作区折叠态字形 —— 工作区与管理头部按折叠状态显示开/合文件夹字形。
- 每来源面板轴入口落在来源头 ——
sidebar.panellist的宽态入口渲染在其所属来源的 server 头动作簇首位(视图选项左侧、与其余头部动作共用 hover 揭示,静息不占位),取代 beta 期「来源头与浏览区之间的 36px 面板行」;折叠来源头仍在、入口不随浏览区收起,rail 仍保留上游全局面板字形行,每个条目任一时刻恰好挂载一次(design 05 §2 / design 06 §4.7;宽态不再有上游nav[aria-label]分组壳、选中态只在簇现形时可见,按裁决登记)。 - open-in 占用上游 files-tab 目录动作座席 —— 跟随 rc.2 的目录动作位(design 16 §3/§5、design 20 §6.3)。
- 托管主机继承登录 shell 环境 —— 桌面侧先按用户登录 shell 解析环境,再拉起托管实例(design 05)。
- 捆绑 dsh 前端基线升至 0.2.0-rc.2 —— 官方前端与连接客户端一并对齐该基线。
- 打包移动客户端(design 17 §18) —— 自研客户端插件为窄屏/触屏提供完整移动视图:视口档位与资源手术(keyed viewport token 与 theme-color 镜像,进出档位按 key 还原)、抽屉导航(安全区、inert 回收、与官方状态锁步)、composer 键盘抬升(visualViewport 观测、单执行器、停滞自愈)、会话停滞提示与自动重建(共享阶梯表;预算用尽后的文案优先)、设置面板与官方 hover card 的触屏适配;gateway 在认证边界内提供移动入口(
/chamber/mobile.html为兼容页,--mobile-entry归一为同源路径)。 - 本地
@引用的宿主路径面(design 25 §5.7 / S-56) —— Electron 经webUtils.getPathForFile精确取路径,Swift/WKWebView 以「拖拽板快照 + 事件批次唯一配对」补齐;两腿共用data-chamber-painted-source作用域门,vendor 补丁把 ui-attachment 的 document 级 drop 收敛到落点所在壳(同批修掉既有的图片双附),失配一律回退上传,不给错路径。
变更
- 侧边栏悬停揭示改为按行门控 —— 指针下滑进入的行不再立即揭示动作簇;重命名抑制优先于门控揭示;StrictMode 重挂载后门控按新行重建(design 06 §7)。
- 设置 → 内置插件 —— 内嵌插件页的标题块按位置隐藏,只保留上游内容本体。
--mobile-entry校验收紧(破坏性) —— 入口必须是同源绝对路径、不得含查询/片段、不得指向/auth*;旧版把原样值当重定向目标(半可用且静默截断),现在启动即exit 2。- 移除归档后提示(design 06 §3.4) —— 侧栏不再实例化上游的 RowActionToast:archived / stoppedAndArchived 两态与其 undo / show-archived 动作、按 kind 的 TTL 模型、dismiss 管线与两本字典里的死键一并删除;archivedNotOpenable 警告保留(独立触发、3s 普通 alert)。已知代价:归档集未知的降级来源上,已归档行被本地墓碑隐藏、要到该来源挂载且基线落地后才能恢复(被删掉的 6s undo 是覆盖该窗口的入口)。
修复
- facts 应用步骤的重入环(React #185) —— 通知/facts 步进链在写入 store 触发的同步渲染里再回调自身时,React 以 #185 中止且异常被 never-throw 守卫吞掉,导致整拍作废;现在 `apply-session-facts` 按来源过重入闸(非重入仍同步执行),重入只登记并补跑最新快照,撤回来源的待应用快照随撤回丢弃;`reconcile` 与 `completion-arm` 语义不变(design 19 §3.7)。
- 连接重置期间的会话投影事实保留(design 05 §2.3) —— 连接代际变化会让客户端清空会话投影、直到下一次 session/list 回填;窗口期内侧栏行会丢失持久 title 与稀疏 hasActiveSchedule 标记(实测:远端来源在 0.6–0.8s 内把会话名显示成目录名)。现在行会携带最后一次已知的投影事实跨越该窗口:非空 title 始终优先,行消失即丢弃记忆,updatedAt 前进即停止携带(无定时器、无状态),挂载推送与 unary 回退两个提交点都适用。
- 被删除的工作区行不再滑到列表尾部(design 05 §2.2.1 / design 06 §7) —— 宿主先按不含被删 id 的顺序发 order follow 帧、后发 remove,窗口期内 pinned store 把未命名项排到最后,侧栏的 keyed-row 动画会把注定消失的行滑到末尾再消失。删除漏斗现在在 workspace/delete 线前先发 reportWorkspaceRemoving(未提交时由 reportWorkspaceRemovingFailed 撤回),App 在渲染末记账,投影按「上一条投影的真实尾部」摘掉尾部的 pending 段——行就地卸载;无尾部证据时保持 no-op。
dsh-chamber v0.4.1-beta.1
[0.4.1-beta.1] - 2026-09-30
新增
- 侧边栏每来源视图选项(对齐上游) —— 每个来源可在 pin 分区 / 平铺列表 / 工作区树之间切换,并对归档过滤;pin 面与上游一致(design 06 §5/§7/§10:kebab 的 pin/unpin 位于重命名之前、悬停簇最右键为 pin/unpin、尾部状态槽之后是非交互的固定标记;写入走官方幂等 RPC,无乐观回显,失败落行级错误,pin 集合沿用归档集合的三态纪律)。
- 工作区折叠态字形 —— 工作区与管理头部按折叠状态显示开/合文件夹字形。
- 每来源面板轴 —— 侧边栏面板渲染在其所属来源之下(放置位置有测试锁)。
- open-in 占用上游 files-tab 目录动作座席 —— 跟随 rc.2 的目录动作位(design 16 §3/§5、design 20 §6.3)。
- 托管主机继承登录 shell 环境 —— 桌面侧先按用户登录 shell 解析环境,再拉起托管实例(design 05)。
- 捆绑 dsh 前端基线升至 0.2.0-rc.2 —— 官方前端与连接客户端一并对齐该基线。
变更
- 侧边栏悬停揭示改为按行门控 —— 指针下滑进入的行不再立即揭示动作簇;重命名抑制优先于门控揭示;StrictMode 重挂载后门控按新行重建(design 06 §7)。
- 设置 → 内置插件 —— 内嵌插件页的标题块按位置隐藏,只保留上游内容本体。
修复
- facts 应用步骤的重入环(React #185) —— 通知/facts 步进链在写入 store 触发的同步渲染里再回调自身时,React 以 #185 中止且异常被 never-throw 守卫吞掉,导致整拍作废;现在 `apply-session-facts` 按来源过重入闸(非重入仍同步执行),重入只登记并补跑最新快照,撤回来源的待应用快照随撤回丢弃;`reconcile` 与 `completion-arm` 语义不变(design 19 §3.7)。
dsh-chamber v0.4.0
[0.4.0] - 2026-09-29
新增
-
孤儿工作树行有常驻的清理入口(design 06 §7、design 08 §3.4) —— 路径已消失的孤儿工作区只亮 Missing 徽标:派生工作树行没有 kebab(design 08 §3.2),其 Git 占位者在工作树记录被剪除后也随快照消失(没有快照行 ⇒
gitFactsForWorkspace为空、座席不渲染),状态胶囊成了唯一的出口。现在孤儿工作树行(orphaned && isWorktree && !ungrouped && !synthetic)在徽标旁常驻一枚删除钮、且位于悬停揭幕簇之外(坏行不得把唯一的删除动作藏在 hover 后面);它复用onDeleteWorkspace,与既有入口共享登记式孤儿确认、单 Modal 门与拖尾点击守卫,可访问名按仓库行动作纪律带行名参数化(action.orphanedCleanup.aria),徽标作为刻意的第二入口保留。 -
会话 pin 与上游表面一致(design 06 §5/§7/§10) —— 侧栏会话行接上官方 pin 表面:右键菜单的 pin/unpin 排在重命名之前(order 100),悬停区最右一枚 pin/unpin 钮(order 200),行尾状态槽之后是非交互的
role="img"+row.pinned标记(悬停或菜单持开时与状态槽一起隐藏),文案逐字取上游 zh/en 词典,字形是 14px 的填充/描边一对。写路径走官方幂等 RPC(workspace/pinSession|unpinSession,行键<source>/session/<id>/pin、per-session 在途守卫、方向取自被点行自己的 pinned 事实、无乐观回显、成功后 requestRefresh、失败落同一行级 rowErrors);集合事实按归档集同一三值纪律(pinnedSessionIds+pinSetKnown:unary 回退不是 pin 来源,缺席/假只表示 unknown,消费方不得从它断言「没有 pin」),标记集合随 follow 基线或其{type:'pinned'}增量到达;回退聚合拉取按稀疏在场规则保留 pin 集与位(marker 不再闪回,等值门也不 churn)。chamber 偏差(design 06 §5/§7/§10、清单 4.6 登记):标记盒用 20px 动作盒且无外边距(上游 16×20 加 6px,chamber 行距已提供)、标记位于状态槽之后、本版不带 pin 顺序、失败留在行级而不上抛 toast。 -
侧栏在 vendor patch 13 之后自持会话行座席(design 06 §5) —— 上游 patch 13 撤掉了 ui-workspace 对
sidebar.session.row.leading/sidebar.session.row.hover的声明,chamber 侧栏现在自己声明这两座并仍按上游地址渲染:leading 在行标题之前(走官方 occurrence 份额)、hover 在行卡内;chamber 调度标记退为座席空缺时的 fallback,绝不会与占位者叠加,leading 座席补齐上游的非空白守卫;悬停卡顶部 clamp 镜像ui-primitives的 overlayTopMargin(macOS 68px / Windows 60px / 全屏 20px),两种窗口状态下遮罩都不压到帧条。 -
新建工作树落在其来源之后,行入场有动画 ——
+创建的工作树此前被宿主 prepend 到列表最前(宿主不接位置参数),现在投影按路径键发布放置意图:只在权威行仍是真列表头时移动它,reorder / 删除 / TTL 即退役,创建途中源行被折叠或重排也不会把行漂走;新出现的行按既有 AnimatedRows 入场动画落位(App.tsx 与 aggregate-store.ts 的预算上调按评审理由记录在 file-budgets,方向是把放置事实移到 workspace-placement 旁)。 -
桌面载体按需携带官方反馈问卷的机器描述 —— preload 经
dshDesktopcarrier 暴露deviceInfo(设置 IPC 读process.getSystemVersion,带os.release回退并剥离行分隔符),Swift bridge shim 的 fetchInfo 成功分支返回它此前丢掉的 info 对象(那字段此前是死代码);官方反馈问卷在两个 flavor 下都能拿到机器描述。 -
页面通道:全部长活流收敛到一条页面级多路复用 WS(design 26) —— 每个页面只保留一条长活通道(
/api/page-channel):来源图、会话事实与直接订阅的流帧都按(kind, key)登记在同一个 socket 上,隐藏 ≥60s 的页面不再各自维持连接(收敛判据与既有隐藏期纪律同源);Remote mux 与推送路径不搬、行为逐字保留。控制面在既有 origin 栅栏后注册该端点并承载三类上游适配,gateway 明确不挂载它(非目标,遇到即 404);每条流按booked判定写入[chamber:evidence]账本,未调度窗口覆盖不到的观测不落失败(design 14 §D4 同一判据)。 -
目标运行期间,完成通知按目标自己的结局收尾(design 19 §3.2) —— 会话目标处于 active 且 armed 时,一次完成不再立刻以「会话已完成」播报:收敛器把它压住(呈现面同样不亮完成未读),等目标结束(完成 / 受阻 / 停止)时按该目标的首次结局播报一次「目标已完成」「目标已受阻」「目标未继续运行」,同目标的后续完成回到「会话已完成」;目标事实缺席时保持现有中性行为(fail-open),提问与审批不受目标状态影响。目标三值事实(缺席 = unknown / null = 明确无目标 / 对象 = 有目标)与 activation 事件在 renderer、sidebar 与 gateway 三侧同源,远端来源与壳被回收的来源都走同一收敛器;侧栏不新增独立目标视觉元素。
-
open-in 官方行的文件级动作开始生效,chamber 目录打开保持严格超集(design 20 §7) —— 官方 open-in 客户端行不再被跳过:右栏文档页签与交付卡上的文件级打开动作(
sidebar.right.tab.document.actions/deliverables[.review].file.actions)由它注册,经每实例会话 RPC 取数;chamber 自有的open-in头部入口在同一槽位以自有 id 保留目录级打开超集(本机全量应用拾取器、真实 bundle 图标、官方分体按钮形态),官方头部条目在复合壳里不再产生第二个入口。 -
双 flavor 的原生键盘快捷键桥 —— 官方快捷键服务由每个注入
shortcuts的官方客户端族构造,在桌面形态下要求宿主提供原生键盘面:Electron 侧由主进程按上游before-input-event语义实现(决策表、按键记录、偏好事务与其 revision 门),Swift 原生壳由注入 shim 提供等价的 DOM 键源;设置里的快捷键录制/编辑与原生按键投递因此在两个 flavor 下同样可用,页面也不会因缺该面而整体起不来。 -
载入停滞的自动重建改走官方
Session.resync(),并由页面级座席独占 —— 只有具象Session.openPromise证明没有在途 open 且状态仍是 loading 时才执行,借此原位重建该会话的流而不丢页面(5 分钟内至多 2 次、间隔 ≥15 s),慢宿主不被打断;vendor 头部座位保留error阶段的迁移与用户主动重建,两个座席共用同一能力守卫,隐藏的头部不再对用户没在看的会话动手。 -
本地来源缺图端点现在给出病因,而不只是后果 —— 新增 boot-gap 事实
local-graph-not-injected(仅本地实例;远程与 gateway 逐字保留):本机实例没有注入 chamber 的客户端图通道时,横幅先报「安装 / seed 完整性」这一病因,并以优先级压过 5 秒后到达的required-services-missing后果;同一 ready 世代内可撤销、可复查(判词后 +30s 有界复查,provider 迟到即清事实),不再长期挂着并白烧一次冷重挂。 -
诊断点名缺失的提供方 —— 控制台诊断行由只报「等待者 ui-chat」升级为同时给出缺失提供方(
sidebarRight → @deepseek-ai/dsh-client-ui-sidebar-right);未登记的服务显式写 "provider row unknown",缺行的病因不再零日志。 -
Windows 腿开始跑前端契约,发布证明要求 Windows 打包彩排 —— ci.yml 的 Windows 腿新增 renderer 与 sidebar 的
test:win32清单(根test:win32扇出到 5 个包,每包一个可点名的步骤),每个清单带「零测试即失败」守卫;verify-release-ci-proof.mjs的REQUIRED_JOB_STEPS同步要求这两步与 Windows 打包彩排,删步/改名即红。 -
通知失败不再是无解的死路(design 19 §3.3/§4.1) ——
dsh-chamber:notify由布尔改为{ shown, outcome, error? }(outcome区分 shown / suppressed / retryable / permanent):宿主/系统的拒绝原因与裁决侧抑制原因穿过 IPC 保留;新增dsh-chamber:open-notification-settings(固定主进程侧 URL,不接受渲染端传入),设置页据此渲染原因、权限提示与「打开系统设置」按钮(中英);映射纯函数有单测,Swift 壳把授权裁决与投递失败写入 native-shell.log。 -
会话流健康臂(design 14 §D4) —— api-gateway 流载体改为重试而非终态失败并投影页级
stream-carrier-failed事实;open-in 插件渲染会话流健康 chip 座位;控制面记录被放弃的升级以便归因;修复被判定失败后立即锁存重载动作(判据挂在 settle 时钟而非相位,loading驻留与隐藏期都不再吞掉它),载体重连的抖动也不再只留在闭包里。2026-09 的卡死排查把这条臂补成完整闭环:开帧发送前校验 socket(被替换/正在关闭即按载波失败,杜绝 RFC 6455 静默丢弃)、逻辑流首帧期限(单档 30 s,加宽阶梯已退役)、WebSocket 握手 30s、socket 丢失后自查重连(1s 起、封顶 10s,连接泵下令的重连不计失败)、journal 静默 ≥45s 时开旁路 sibling follow 并只比对 opening cursor(仅宿主确已前进才替换物理世代);健康 chip 退为纯报告(手动恢复控件按用户裁决整体退役——chamber 的边界是自动升级 + 显式失败面)。 -
macOS Swift 原生壳(design 25 路线 A,预览) —— macOS 上新增第二只壳:Swift/AppKit 只做壳(窗口、WKWebView、菜单/通知/角标/深链/对话框/外部打开/隐藏恢复),壳内不承载任何业务;业务由打包成独立 Node 可执行文件的 sidecar 承载(现有 control-plane 与 desktop 的纯 Node 业务模块族原样运行),Swift 与 sidecar 之间走一条受信的 stdio JSON-RPC 通道,页面侧用与 preload 等价的注入 shim 顶替
window.dshChamber,web UI 100% 复用。与原 Electron 版共存:产物为dsh-chamber-<版本>-macos-arm64.dmg/.zip(本版起命名归属反转,见「变更」),bundle idcom.dshchamber.native(通知授权身份独立),双 flavor 共用同一 userData 根与目录锁(<userData>/.dsh-chamber.lock,darwinflock/O_EXLOCK,锁本身是唯一仲裁权威),并保证关窗决策只吃本世代的关闭语境事实:取消退出后不再沿用旧决定,设置变更与 sidecar 重启各失效一次、重启后再预热一次以保住 ms 级关窗。 -
原生 flavor 的应用内更新链(design 25 §7,D-1 = B) —— 改为 Sparkle 2:检查真实 appcast(EdDSA 签名;公钥/私钥由发布链配置),支持应用内下载、安装与重启,并保留用户手动的「检查更新…」;beta 通道用滚动 appcast 同时收当前 beta 与最新 final,让 beta 客户端也能看到 final(S-22/S-23/S-36)。更新面不可用、坏 feed/坏公钥或忙态点击都返回诚实错误而不是静默吞掉(S-37–S-39)。
-
双 flavor 防漂移锁步与新 CI 腿 —— IPC 面镜像(main/preload 两侧字面量与结构)、桥 manifest(
bridge-manifest.json↔ 生成的 Swift 白名单,通道 70 = 61 invoke + 9 push)、注入 shim 表面、core 的 electron-free 传递闭包、打包清单与产物命名(-native不含碰撞、更新 feed 归属唯一)各有独立门禁;新增 macOS CI 腿test-macos(Swift 构建 + XCTest + 打包干跑 + darwin 目录锁与打包脚本套件),发布证明要求 linux/windows/macos 三腿同时通过。 -
打包链 ——
build:sidecar(官方 Node 归档按仓库固定 SHA-256 校验后捆绑,基名必须是node;内置 dsh 工作区与内嵌 pnpm)与build:swift-app(组装 → ad-hoc 或 Developer ID 签名 → 公证 → stapler 装订 → 归档,任一缺失即 fail-closed),同一 tag 下与 Electron 产物并行发布、互不覆盖。 -
托管宿主用随包 pnpm 安装/卸载插件 —— Finder 双击的打包 App 里,宿主插件管理器此前在 PATH 解析不出可执行 pnpm 时无法工作:控制面现在于
<stateDir>/pnpm-shim/生成 wrapper 并只前置到该次宿主 spawn 的 PATH(design 02 §3.1,withPnpmShim);宿主已有 pnpm 时逐字不动(此时不保证与随包版本一致)。 -
原生壳本地落盘日志(design 25 排障面,T-25) —— 原生壳此前双击态白屏/退出没有任何本地 dump 可考古;现在关键行(启动、sidecar spawn/退出、导航失败、更新相位、退出链)同写
<userData>/logs/native-shell.log,256 KiB 单份轮转(.1)、0600/0700,写不进静默退回 stdout。它不复用 Electron 的<userData>/state/host-logs/<port>.log——那是控制面按端口寻址的宿主 stdout/stderr 管道,两条日志面不同目录、不能混用;唤醒与「壳→页面」推送的每一跳(含失败分支)也走这条日志,真机上能分清「没发」与「没消费」。 -
Electron mac 打包演练进 push CI(G41) —— main push 的
test-macos腿新增 ad-hoc、--publish=never、无凭据/无公证/无上传的electron-builder --mac --arm64演练,并紧跟verify-electron-artifacts.mjs对真实.app校验;发布证明(verify-release-ci-proof.mjs的REQUIRED_JOB_STEPS)同步要求该步名,删步/改名即红。代价 = macos 腿每次 push 真跑一次打包(时间变长),换取 files/extraResources/beforePack/afterPack/entitlements 的破坏在 push 即暴露,而不是等到 release(draft 已建、凭据已加载)才失败。 -
更新链 fail-closed 门禁(G42) —— 正式发布中 Sparkle 公钥在而私钥缺 = FAIL(壳会轮询没人签的 feed);私钥在而 beta/stable appcast 缺失 = FAIL(不再静默跳过滚动发布);
/releases/latest解析失败(非 404)或 final 有 native zip 但下载失败 = FAIL;新增verify-native-appcast.mjs断言本版本 appcast 条目同时带shortVersionString=本版本、sparkle:version=本.app的 CFBundleVersion、enclosure 指向本版本 zip(appcast 步与滚动刷新两处都跑)。两把钥匙都缺仍是 loud 降级(照常出包、客户端看不到更新);仓库尚无 final release 或最新 final 确实没有 native zip 时保留 loud 警告。 -
原生壳跟随显示器刷新率(S-48) —— 原生 flavor 此前把渲染上限压在接近 60Hz:面板是 ProMotion/高刷时会明显比 Electron 侧"钝"。现在按所在显示器的刷新率取整跟随(低电量模式减半),偏好必须在 web view 构造前应用,且先读回确认可写再改;实测原生壳 114–120fps。
-
原生壳视口弹性回弹消除(S-50) —— macOS WebKit 在视口层做橡皮筋:指针停在不可滚动 chrome(顶栏、会话栏头部)上滚动、或某个滚动器到端点继续滚时,整页(含
position: fixed层)会被整体平移再弹回。壳在 configuration 段以 documentStart、仅主 frame 注入一条根级overscroll-behavior: none !important规则关掉它,不动任何滚动容器的滚动语义。 -
控制面与 sidecar 的诊断也落盘(T-25 扩展) —— 继原生壳本地日志之后,控制面日志与 sidecar 诊断同样按 0600 落盘:双击态出问题不再只能靠系统日志猜。
-
未就绪来源的 boot 死区可以逃出去(design 05 §4.1) —— 远程来源未就绪时点开会话,此前会停在全窗遮罩上等最长 135s 的收割臂,期间没有任何导航出口。现在遮罩按相位给动作:未连接(idle)立即给「连接」+ 切换行且不启动 boot;
error与托管stopped/restart-exhausted在 1.5s 宽限后判不可服务(不再等满 60s);degraded(重连在途)不判死、仍在预算内等;挂死 boot 超过反馈窗(10s)后给重试/连接/切换 + ⌘R 提示;502(隧道通、远端端口死)是非阻断横幅并按 ready 世代自愈一次。 -
侧栏会话 running 位陈旧会自愈 —— 会话已被判定结束、running 位却没收敛时,聊天面此前会一直不渲染:现在由侧栏会话事实与渲染位活性守卫三层收敛,聊天面恢复挂载。
-
gateway 登录页阶段预热(design 17 §10.6) —— 未登录访客在输入密码时即预取真实的
/pluginsbundle URL(HTTP 缓存按 URL 建键,包装 URL 拿不到收益),登录后首屏直接取用整册前端 bundle(实测约 4.35 MiB gzip),不再落在关键路径上;能力由一枚短时 HttpOnly cookie 承载(HMAC、客户端地址绑定、120 s),该路由在认证门之前被咨询,但只认两种真实 bundle 形态 + 有效 capability,缺/过期/篡改/他人 cookie 一律落回原有 401/session 判定与类别审计,其余/plugins/**不放开;限速与容量 fail-closed(超限 429/503,且限速只对已验签的 capability 生效),并带--no-warmup/DSH_GATEWAY_WARMUP=0关闭开关(关闭时登录页 HTML 逐字节回旧模板)。 -
原生壳文案本地化并跟随应用内语言(design 25 §5.3) —— 原生壳的菜单、托盘、对话框与错误文案此前是写死的中文;现在整表(122 键)以 en / zh-Hans 两份字符串资源随包发布,键表由
NativeTextKey单一来源锁步,两份文件的占位符逐键同型同序。壳自建文案跟随页面语言(应用内切换即生效),系统与框架面(Sparkle 标准窗、AppKit 内建串、右键菜单)默认跟随系统语言,仅当语言族不同时才写AppleLanguages让它们一起跟随(下次启动生效)。装配期对每个.lproj做存在 + 逐字节 +plutil三重 fail-closed 断言,缺件不再出包。 -
共享会话生命周期包与跨语言锁步门(design 14 §D4) —— 新增零依赖、零时钟的纯状态包
@dsh-chamber/dsh-stream-state:载体重建 reducer 与节流表、页面生命周期账本/容器、揭幕仲裁、四条恢复阶梯的单张阈值表、有界异步原语(withDeadline/waitForCondition)、带世代围栏的 load 状态机与对账权威判定,并带 Foundation-only 的 Swift 镜像(CarrierDecision.swift/LoadState.swift)。api-gateway / renderer / sidebar / mobile / open-in 一律改用这一所有者,阈值只剩一处;锁步门进 static、CI 与发布验证(差分回放 drift≠0 即红、Swift 镜像编译断言、阶梯阈值逐模块比对),并新增有界流取证环(默认 256 条 FIFO、记录时脱敏、实时分发前先写入)与页面侧快照桥,无 DevTools 的 Swift 壳里也能事后回读载波决策。 -
*...
dsh-chamber Swift beta appcast (rolling)
Rolling release carrying appcast-swift-beta.xml and the archives its enclosures reference for the Swift native shell's beta channel. Republished by every beta; do not delete.
dsh-chamber v0.3.1
[0.3.1] - 2026-09-15
新增
- 托管宿主的应用日志桥(opt-in;design 18 §3.4 诊断面) —— 托管 dsh 此前没有任何可打开的应用日志面:web CLI 只有
--host/--no-open/--port/--trusted-host,运行时也不装 exporter(LoggerService只有 1000 条内存环),进程内的事故无法从外部定位。现由DSH_CHAMBER_HOST_LOG_LEVEL开启:不设/off 时 profile overlay 字节不变,设为级别名取该 Cordis 阈值,未知值按保守warn挂载并响亮告警(阈值是单调的:warn含 info)。实现是 chamber 自己生成的一个无依赖 Cordis 插件、挂到既有 seed 通道,把消息写到 stderr,再由既有的子进程输出管线脱敏并滚入host-logs/<port>.log;脱敏规则同时抽成可单测的纯函数。它不进CHAMBER_HOST_PACKAGES——无 Typert Remote 域,注册表行会因为缺探针域而激活失败。 - 移动端会话打开面重做(design 17 §18.6) —— ① 会话头拥挤(面包屑条被强制换行,未分类的子代理计数跨 CJK 词断成五行、把 30px 行推到约 96px)改为官方单行 + 横向平移:手机档 48px 行高 + 顶部/右侧安全区,写明收缩顺序(当前面包屑先让宽,谱系 chip 不缩——它是子代理目录的唯一入口),谱系触发起码 44px 触摸底线,两个图标座按 border-box(否则刘海侧画到视口外);480/360 两档约束 agent-preset 标签,此前那条
> button > span规则没有任何注册方渲染,是死代码。② frame 打章改为全有或全无:会话列缺失就不打章,vendor 改中心槽位名时样式表的列锁不会把转录钉死在 0px 首轨;抽屉开关/背幕只在真的找到 sidebar 角色时渲染(无死控件、无孤立遮罩),探针把结果记进data-mobile-roles。③ 会话打开卡死提示:客户端与宿主都不给会话打开设期限,流卡住时转录会永远停在「加载历史」。现用一个纯属性判定的提示(active/settling 会话根、无锚点行的聊天流、已渲染的会话头,持续 45s 可见时间),只提供一个用户主动的刷新动作,绝不自行重载或重开会话;提示自身的文案节点从不被匹配。 - 仓库门禁、单入口检查与移动端走查工具箱 —— 新增三个此前不可见的门(
verify:test-wiring:磁盘上每个测试都必须可达;verify:md-links:自有文档的相对链接与锚点必须可解析;verify:workflow-yaml-scalars:形如single entry: ...的步骤名是非法 YAML,而纯文本检查全绿)与一个pnpm run check单入口(scripts/dev/run-checks.mjs的 static/tests/typecheck 模式,本地与 CI 同源,不再维护平行清单);release-preflight现在会扫描packages/与scripts/的FIXME并在未决时阻断发布(须显式--allow-fixme才放行,让「带着 FIXME 发布」变成记录在案的决定,TODO/XXX仍只作背压标签)。验收面新增 CDP 移动端走查(Emulation.setDeviceMetricsOverride+ 触摸模拟 + WebSocket 帧捕获;判定以设备宽度为准,因为mobile:true的 shrink-to-fit 会让scrollWidth <= innerWidth自证成立;凭证只从命令行点名的环境变量读、经脱敏后才落任何输出)与移动端插件锚点保鲜门(逐条声明的锚点必须仍被钉住的上游发出,19 项最小集合兜底;无上游树时 fail-soft 并打印跳过了什么),并给 control-plane / dsh-runtime / renderer / gateway / cli 五个核心包补契约 README。
变更
- gateway 安装单元补全登录环境(design 17 §5) —— 默认服务形态(
SERVICE_USER为空)不渲染User=,而 systemd 只对带User=/DynamicUser=/PAMName=的单元设置$HOME/$LOGNAME/$SHELL,于是 gateway 与它拉起的每个子进程(托管 dsh → 代码运行时 → bash 工具 → gh / npm / git credential helper)都在空 HOME 下运行:gh 报未登录、npm 找不到缓存、git 凭据助手读不到 token。write_unit现在只为该形态注入HOME/LOGNAME/USER/XDG_CONFIG_HOME,取值来自运行用户的 passwd 条目(绝不是安装者的$HOME,sudo 可能把它带过来),取不到就是硬失败;--service-user形态保持 systemd 自己的推导、不注入。迁移:就地部署需重跑一次install以重写单元(会同时重新生成凭据)。 - 代理压缩协商(design 17 §8、design 03) —— 此前每个被代理请求都被剥掉
accept-encoding,强制托管宿主以 identity 应答,而钉住的 gzip 中间件本可压缩:官方前端首屏是单个约 10.65 MiB 的 client-module combo(内嵌 document-preview 的 pdfjs-dist),实测按配置级别 1 压到 4.16 MiB。现在只有代理自身需要原始字节的两处保留 identity:HTML 文档导航(S0 信任注入要前插脚本并重算 content-length)与Accept: text/event-stream;其余交给上游协商(其自身过滤器已拒绝 event-stream 与 content-range)。同一提交落地窄接口ProxyForwardDeps.onUpstreamResponseHeaders(在重算 content-length 之前调用、fail-soft)并导出isHashedStaticAssetPath供 gateway 复用。 - gateway 的 CSP 允许上游
<base href="/">——@deepseek-ai/dsh-host-frontend-static会给每个渲染的 index 文档重新注入<base href="/">(它的 SPA 深链修复)。在base-uri 'none'下浏览器直接拒绝该元素,深链于是把自身的./assets/...解析到深链路径、404、白屏;代理无法重写流式 HTML(正如无法回填 nonce),故base-uri跟随script-src取同源允许值,其余指令逐字节不变。 - gateway 对内容哈希静态资源给 immutable 缓存 —— 官方前端由
dsh-host-frontend-static提供,它只写 content-type(没有 Cache-Control/ETag/Last-Modified),于是即使 Vite 给每个文件名带了内容哈希,重复访问仍可能整包重下。现在对恰好/assets/<name>-<8 位哈希>.(js|css|woff2?|svg)的普通 200(无 content-range)补cache-control: public, max-age=31536000, immutable,并按证据判定而不只看路径:上游没有自带 cache-control/etag/expires、路径无百分号转义或点段、content-type 是该扩展名真能产出的类型;favicon.svg、manifest.webmanifest、index.html、.map与任何 range 响应永不匹配。接口在代理重算 content-length 之前运行,不会破坏 framing。 - auth 拒绝审计按窗口合并 —— 每个被拒请求此前都要追加一行并 fsync;一次无凭证的手机加载会打出成串记录(manifest/图标/service worker 全部无凭证),一次页面浏览要付若干次同步 fsync,还产出若干行完全相同、读者读不出额外信息的记录。现在按
(client, code, path category)分窗:首个事件仍立即落盘(「确实发生了」这个证据不能等计时器),窗内重复只计数,窗口关闭时写一行带count:<n>(含首个锚记录);不同 client/code/路径类永不合并。窗口状态在 dispatch 闭包里(不是模块单例),计时器unref()以免拖住进程,quiesce()释放所有权前排空所有窗口;不同客户端身份是无界的,故窗口表有上限,到顶时提前发布最旧的窗口而不是无限增长。 - 受保护集合加入版本维度(design 21 §6.11.1) —— 安装后校验此前把每个顶层拷贝都按 dsh 代际串判定,于是安装官方 opt-in 层会以四条 finding 响亮失败:它的传递 experimental 包是官方 scope 但不在 F(C11 禁止该段),而被改 scope 的 vendor 包(cosmokit、schemastery)保留上游版本、永远不等于代际串。现在 F 在名字集合旁另带 name→version 事实,并有一条第二信任判据:当名字与版本两个解析器对同一批键说法不一致时拒绝该来源(而不是静默丢掉版本维度、把误报放回来)。校验按固定顺序跑两条臂:命中 F 的名字按本运行线能提供的版本判定(无事实表的调用方保留代际臂,§6.11.4),不在 F 的名字仅在官方直接依赖的闭包能到达它时才豁免——闭包只展开官方节点,第三方中间人无法为官方名字背书。桌面主进程与 gateway 执行器都传事实;内建锚仅当它就是当前活动运行线时使用,环境提供的 dev 树可回落到锚以免写面降级。
- 工作区创建/接管走单一事实通道(design 05 §2.2.1、design 08 §4.2) —— Git worktree 插件此前用自己的 unary
workspace.create创建/接管工作区,只有侧栏的加工作区对话框会发布工作区回声事实;对未挂载 shell 的来源,全新(0 会话)工作区没有别的读通道(unary 兜底从会话 cwd 派生分组,已推送过的来源其工作区集合是冻住的),于是那一行只有用户点开该服务器才出现。现在 create/delete/rename 统一经shared/workspace-mutations.ts包装:每个包装既发线调用又发布对应的一次性事实,调用方无从遗漏;Git 创建携带放置锚(回声行直接落在主检出下面而不是尾部)并在发布之前完成装饰(beforePublish,worktree 标记与未注册折叠在同一同步续段里写入),接管也携带分支标题,于是行一出生就是最终形态与位置。同批修掉回声规则的两个审阅发现:锚放置改为按锚分组并重新查位(原游标存绝对下标,插入的锚会把下一行提前一格),接管装饰跳过主检出(此前会把主行标成派生 worktree)。
修复
- 重启 dsh 后新装/重打包的客户端插件不出现(design 18 §3.6 项 8) —— 窗口的 client 插件集在每个实例壳 boot 时固定(宿主图每 boot 取一次、页面模块表按 id first-load-wins),重启 dsh 只刷新宿主侧,于是新装或重打包的
dsh.client半身(例如设置分节)要等整个应用重启才出现。现在由 sidebar 共享面的 page-owned completion 收尾:按来源 key(local/gateway-<id>/dsh-<id>)单飞、发起面板卸载不取消、就绪预算内未恢复则不重载并如实报错(绝不把失败藏进一次新 boot)、结算后可重试再 arm。接线范围:「重启 dsh」两种形态、本地「立即应用/重试应用/重试恢复」三类重启事务(仅成功时)、本地卡「启动」/写者接管、gateway 卡「重启 dsh」/「启动实例」、插件对话框 footer 重启与全部 restart-to-apply(行删/加/导入/撤销/批量应用)、ssh 卡「重启实例」(仅 dsh 目标);「重启网关服务」(systemd)不改变实例插件集,有意不接。设计 18 §3.6 项 8 记下契约、接线清单与被拒替代。 - gateway 不再把「读不出来」当作「没有要保留的」 —— 两条写面路径曾把读取失败折叠成「空」,后果是删除证据:① profile manifest 超过读取上限、父目录是符号链接或不是合法 JSON 时引用集合为空,暂存的每个
.tgz都会被当作孤儿删掉——现在非 ENOENT 的读失败、非法 JSON 与损坏 journal 都会阻断清扫并响亮告警,只有真正的 ENOENT 保留原清理语义;② 损坏的 journal 解析成空列表,于是对账报告「没有待处理操作结转」、从不回收已记录的子进程,随后的 prune 还会删掉丢失操作的 preImage——现在损坏与空 journal 可区分、原始字节保留为.corrupt-<ts>旁证、证据未决期间 prune 保留所有 preImage、无法改名旁置的文件绝不被覆写。 - 插件归档完整性(构建与扫描两侧) —— ① ustar 的 name 字段是 100 字节,而构建器按 UTF-16 码元比较,CJK 路径能通过检查却在头里被截断、构建器仍报告完整名字;现在按 UTF-8 字节长度度量,边界钉在 100 vs 101 字节。② tar 读取器此前返回归档顺序里第一个可解析的 manifest,而 pnpm 安装的是
package/package.json,构造一个带诱饵根 manifest 的归档就能让写面判错包名;现在优先安装路径、根 manifest 只作兜底,申报与安装身份不一致时带两个名字响亮失败。③ gateway 扫描器的 manifest 捕获没有关闭,manifest 之后的任何条目都会被追加进捕获字节、把合法归档判为tgz_invalid,且超大候选是粘滞的、捕获没有上限;现在捕获随候选数据区关闭、超大按候选判定、只保留有界的申报字节。 - 控制面代理的响应头白名单与日志桥卸载 —— ①
onUpstreamResponseHeaders回调之后重新施加RESPONSE_HEADER_WHITELIST:回调写content-length/transfer-encoding(或任何非表示头)不再能上到线缆(JSDoc 声称 framing 不可触碰,但content-length不在白名单里、且只在上游声明过它且响应不是 SSE 时才被重新推导);chunked 与 SSE 两种形态都有测试。② 生成的日志桥 exporter 改为经插件自己的ctx.effect挂载:cordis 的LoggerService.exporter()把 effect 注册在服务 ctx(app root)并返回该 disposer,直接注册会在插件卸载后存活,loader remount 会叠第二个 exporter、把每行应用日志写两遍。③ 不可变缓存规则改用共享的isHashedStaticAssetPath而不是裸/assets/前缀(后者会把未来某个未哈希条目钉住一年)。 - 连接页 live-state 单元格不再把 bundle 层误报为待重启 —— 该单元格按精确模块名匹配 Loader 快照,而
dsh.bundle包永远不是 Loader 行(组合树是空根条目列表 + 各 bundlecordis.patch.yml的插入行),于是每个 bundle 层都匹配不到东西、永远显示「重启后生效」——包括在一次真的激活了它的重启之后。现在没有同名 Loader 条目的行一律中性,死掉的语言键也删掉;其余诚实上限不变(快照不可读、protected/composition/seed 行、disabled/failed/loading 各有自己的答案,manifest 仍绝不作为存活来源)。 - 桌面本地 patched 探针按两个挂载来源判定 —— 本地 chamber 行来自两处:profile 自己的
cordis.patch.yml用户层(app-boot 组合到根条目列表之上)与传给 spawn 的--patchoverlay。探针只读 overlay 文件,于是组合树里明明有该行却报 false,而一次不再传 overlay 的 spawn 又会从残留文件继续报 true。现在探针回答「这一行是否到达组合树」(profile patch 里的精确插入行,或 overlay 里的),读不到或缺失的事实保持 false 而不靠猜;生产者侧让 overlay 文件的存在只意味「上一次 spawn 传了它」:任何不传 overlay 的解析都会删掉残留文件,overlay 解析器导出以便用真实文件系统测试而不是源码文本钉。 - 移动端卡死提示的相位、身份与「继续等待」 —— ① 相位集合:上游
ConversationRoot往[data-phase]写settling/hero/active,旧的['active','engaging']有一个永远到不了该属性的成员、又漏掉settling(正在载入历史、头部可见的会话打开);现为['settling','active'],hero(无会话)仍在集合外,头部可见门继续排除空壳。② 会话身份:相位节点不是会话作用域的(main槽按 entry 身份键控,会话切换时div.root[data-phase]原地重渲染),身份改取已渲染的<header>(会话作用域的conversation.session.header子树会重挂),于是计时与已显示的提示不会带进下一个会话。③ 消除方式:第二个控件(「继续等待」)只对当前连续卡死隐藏提示,不再逼用户要么忽略要么中断一次慢但健康的加载;抑制随该次卡死结束(DOM 形状破坏或页面被隐藏——后者同时清零计时),应用恢复后回到仍卡死的会话会再被告知一次。④ 安装所有权改为引用计数:第二个上下文此前拿到的是已死的 disposer,释放第一个就停掉了第二个的监听。 - 打包产物陈旧即失败 ——
dist/control-plane与 gateway bundle 内联源码逻辑,而行为测试跑的是 workspace 源码,于是旧构建能在测试全绿的同时让打包应用发布上一轮的判定(上一轮受保护集合校验就这样在 dist 里活到被手工重建)。现在两个守卫在已存在的 bundle 缺少当前标记时直接失败,只在产物缺失时才构建;静默重建会让检查恰好治好它本该抓到的漂移。 - gateway 审计窗口在关停时二次排空并设上限 ——
flushAuditWindows()在 HTTP listener 关闭后再排空一次:quiesce()在准入栅栏排空,但栅栏与关闭之间被接受的拒绝会打开一个再无人发布的窗口,那条记录就丢了。窗口表同时有了上限(MAX_AUTH_REJECTION_WINDOWS):不同客户端身份无界,到顶时提前发布最旧窗口而不是无限增长。