Skip to content

Releases: G57651/dsh-session-manager

v0.4.1 — 插件内回收站:删除双写 + 恢复到原位

Choose a tag to compare

@G57651 G57651 released this 06 Oct 18:06

🗃 v0.4.1:插件内回收站 —— 删除双写 + 恢复到原位

新增:插件内回收站

用户从资源弹窗删除的文件/目录先复制到插件内回收站(内容 + 元数据),再移入系统废纸篓。恢复时从插件回收站写回原位并清除废纸篓中的已知副本。

  • 存储布局:$DSH_HOME/dsh-session-manager/recycle/<entryId>/{meta.json, payload/},0700 权限。
  • 每条元数据记录:会话 ID、原始路径、类型(file/directory)、SHA-256、大小、删除时间、工作区路径、系统废纸篓路径。

恢复流程

  1. 从插件回收站读出元数据(原始路径 + 工作区 + 指纹);
  2. 写回原位(目标已存在则拒绝覆盖;文件恢复后 SHA-256 校验;目录树整体恢复);
  3. 移除系统废纸篓中已知路径的副本(仅当移入策略为 rename 且路径可知);
  4. 从索引中移除该条目。

安全边界:entryId 严格校验(正则 + 包含性);恢复目标仍限于原工作区内;已存在目标拒绝覆盖。

修改

  • deleteResources 现为双写(先复制到回收站,再移入废纸篓);复制失败则不动文件。

验证

验证项 结果
smoke-lifecycle.mjs 332 项断言(新增:双写/按会话列表/恢复到原位含目录树/目标已存在拒绝/entryId 穿越拒绝) 连跑三轮全绿
真机:deleteResources → recycleList → recycleRestore 全链路(文件进废纸篓 → 还原到原位 → 废纸篓副本清除 → 回收站消费) 通过

升级

从 0.4.0 直接升级,无迁移。

v0.4.0 — 资源删除:移入本机废纸篓 + 弹窗批量删除

Choose a tag to compare

@G57651 G57651 released this 06 Oct 17:36

🗑 v0.4.0:资源删除 —— 移入本机废纸篓 + 弹窗批量删除

新增

  • 单个资源删除:资源弹窗内每个文件类资源行的「删除」按钮——文件移入本机废纸篓(macOS 废纸篓 / Windows 回收站 / Linux XDG trash),可随时从系统废纸篓恢复,绝不直接销毁。
  • 批量删除:勾选资源后工具栏「删除所选(N)」批量移入废纸篓;「清除选择」保留(一键取消勾选)。
  • 删除后自动刷新:弹窗内资源状态即时更新(被删资源转为已不存在)。

平台策略(lifecycle/trash.js)

  • macOS:优先同卷 rename 进 ~/.Trash(重名自动编号);跨卷(iCloud 工作区)回退 Finder 删除(osascript,正确处理 iCloud 与分卷废纸篓)。
  • Windows:PowerShell 回收站 COM API(Shell.Application Namespace(10).MoveHere),参数单引号转义。
  • Linux:优先 gio trash,无 GVfs 时直接实现 XDG trash 规范(Trash/files + Trash/info/*.trashinfo)。
  • 测试隔离:DSH_SM_TRASH_DIR 可重定向废纸篓目录(冒烟套件永不触碰真实废纸篓)。

新增 RPC

端点 入参 说明
deleteResources { id, paths } 将会话资源移入本机废纸篓;路径仅限该会话工作区内,逐条返回结果(unsafe-path / resource-missing / untracked)

安全边界不变:进程启动全部 argv 数组无 shell 拼接(Windows PowerShell 参数做元字符校验);工作区根本身不可删除。

验证

  • smoke-lifecycle.mjs 309 项断言(新增:移入废纸篓且内容完好、路径越界/缺失守卫、双文件批量删除),连跑三轮全绿;
  • 真机(隔离宿主 + 真实 agent 回合):驱动 29/29、agent 回合 8/8、deleteResources 真机验证(文件经 rename 进入隔离废纸篓且内容完好)。

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)并刷新页面。

v0.3.9 — 资源弹窗布局修复 + 一键清除选择

Choose a tag to compare

@G57651 G57651 released this 06 Oct 17:17

🖼 v0.3.9:资源弹窗布局修复 + 一键清除选择

修复:资源行被勾选框标签挤扁(显示异常)

行内勾选框的无障碍标签文本就是完整路径(会话删除的文件路径很长),未约束宽度时吞掉整行宽度,把路径列挤压成一字宽竖排、行高暴涨——即你截图中的显示异常。

修复沿用批量操作栏的既有模式:视觉隐藏标签文本、保留无障碍名(屏幕阅读器仍可朗读),路径回到宽列正常显示、长路径自动换行。

新增:一键清除选择

工具栏新增**「清除选择」**按钮(无选中时禁用),与全选 / 反选并列——勾选后一键清空,不必逐个取消。

验证

  • 渲染冒烟新增断言:清除按钮存在、路径列(dsm-resId)存在;
  • smoke-lifecycle 295 项断言通过;smoke-host 66 项通过。

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)并刷新页面。

v0.3.8 — 第三轮审计:修复大工作区跟踪死锁(全树遍历 + 哈希预算)

Choose a tag to compare

@G57651 G57651 released this 06 Oct 17:10

🔬 v0.3.8:第三轮审计 —— 修复大工作区跟踪死锁(本轮最重要发现)

本轮最重要的发现

探针实测(5000 文件工作区,与你的 default-workspace 同条件):基线一旦收录满 trackingMaxFiles(5000)个文件,之后会话创建/修改/删除的所有文件都落在截断线之外——每一轮 diff 都看不见它们,Journal 永远为空。资源弹窗显示"没有记录到资源变化"、删除会话清理不到任何东西——这正是你在真机截图里看到的那个会话的表现,此前被误判为"该会话没动过文件"。

修复:扫描器重构——全树始终遍历(不再有条目截断导致的跟踪死锁),trackingMaxFiles 语义变为内容哈希预算(昂贵的部分才封顶):已知未变文件(size+mtime+mode 相同)直接复用上一轮条目(零读取零哈希);预算耗尽后的文件仍记录存在性(无哈希,如实报告截断),由 birthtime 收养保护(既有文件绝不被清理移除);mtime 严格相等(<2ms 容差曾吞掉同窗口重写——审计探针发现)。

性能实测(5000 文件):

指标 修复前 修复后
diff(无变化) 548 ms 174 ms(-68%,未变文件零读取)
diff(50 新文件) 540 ms / journaled 0 151 ms / journaled 50
450 条 Journal 后 diff — 128 ms(无退化)

第三轮其余交叉验证(全部通过)

  • 镜像与真实宿主源码逐项一致:encodeSegment/projectKey/会话目录布局与 session-persistence-jsonl 的真实实现逐字符语义一致;RPC 分发 handler(endpoint, payload, …) 与结果形状 {ok,value}/{ok,error} 与真实 connection 源一致;session/event/session/created 监听签名与真实发射点一致;无 cwd 会话的 _no-cwd 布局由插件的扫描式定位天然覆盖。
  • R2 修复回归验证:15 项修复逐条复核,未发现回归。
  • client 契约(locale.register/bind、panelInfo.getSnapshot/subscribe、slots.inject/register)与真实客户端包一致。

验证

验证项 结果
smoke-lifecycle.mjs 295 项断言(新增满预算死锁回归用例:预算耗尽后创建/修改仍被跟踪、删除行为正确) 连跑三轮全绿
smoke-host.mjs 66 项 + client 渲染冒烟 通过
真机:驱动 29/29、真实 agent 回合 8/8、kill -9 崩溃恢复 全部通过

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.7 — 第二轮技能化审计:15 处隐形 bug 修复(红灯先行)

Choose a tag to compare

@G57651 G57651 released this 06 Oct 10:37

🛡 v0.3.7:第二轮技能化审计 —— 15 处隐形 bug 修复(全部红灯先行)

第二轮审计(code-review 双轴隔离法 + diagnosing-bugs 红灯纪律)换了四个视角:修复回归验证 / 未覆盖角落与并发 / 安全与隐私 / 测试有效性。每个修复都先写出能红的回归用例,再修,再验证转绿;并发去重与 env 解析用例做了红检确认。

HIGH

  1. 会话新建的目录从来清理不掉:rm(recursive:false) 对任何目录恒抛 EISDIR,"非空保守跳过"分支是死代码。改用 rmdir(真正的空目录契约)。
  2. 显式 resume 跳过回滚直接销毁 Journal:cleanup RPC 的 resume 对 delete_requested/rolling_back(崩溃残局)状态直接拆除——现在这三态一律先回滚、失败即止。
  3. Journal 并发序号全为 0:seq 分配是读-改-写且无串行化;env/进程记录与各类 diff 并发时全部拿到 seq 0(回放顺序失去意义)。append 改为单链串行;撕裂尾行也不再吞掉下一条记录(写前补换行修复)。
  4. 密钥泄漏面(三处一起堵):下载 URL 的 user:pass@ 与 token=/X-Amz-Signature= 等签名参数会原文进入 Journal 与 RPC → 落盘前脱敏;后台命令里的 Authorization: Bearer … 与 TOKEN=… 赋值 → 遮蔽;环境变量值一律只存指纹(不再依赖"名字像不像密钥"的启发式,DATABASE_URL=postgres://user:pw@… 不再明文)。
  5. 快照库路径逃逸:Journal 里被伪造的 sha256(如 ../x)能读到快照目录之外的文件 → 只接受 64 位十六进制。
  6. 符号链接越出工作区:词法包含性检查挡不住符号链接父目录 → 写入/删除前追加 realpath 复核。
  7. 权限变更不被恢复:仅 chmod 的既有文件命中 already-restored,权限原样保留 → mode 不一致同样执行恢复。

MEDIUM

  1. 显式 cleanup 被 autoCleanup 门控;且清理被跳过时 delete/purge 现在保留 tracking 目录(原会销毁显式清理的唯一依据)。
  2. 并发 diff 重复记账:防抖 diff + 显式 track + 列表自愈 + 删除前最终 diff 并发时同一修改被记录 2–3 次(红检确认)→ 按会话共享在途 diff。
  3. 卸载后仍在写入:HMR 重挂载后旧实例继续追加 → disposed 守卫;同会话 prepareRemoval 在途锁。
  4. 归档失败留下假墓碑:会话被隐藏却未删除 → 失败即回滚回收站条目。
  5. 进程误判/漏判:URL 查询里的 &、make && 被当作后台启动;cmd1 &\ncmd2 漏判 → 按行单 & 判定。
  6. 下载归因错配:一条下载意图贴到第一个创建的文件 → 按 -o/--output 与 URL 文件名提示优先匹配。
  7. pnpm 符号链接依赖不被跟踪 → 适配器接受符号链接(卸载只删链接、不动 store,真机用例验证目标目录完好)。
  8. env 解析:FOO=bar cmd 前缀被误记(现在只有显式 export 才算持久变更)、export A=1 B=2 漏第二个、"x;y" 被错误拆分。

其他

文档漂移全部修正(env 语义、purge 不归档、幽灵行两步失效、activity.json、断言数等);tracking 目录以 0700 创建;build-client 的 useStore 选择器检查加固(支持无空格/任意参数名、只认顶层 init 键)。
测试端同步修复:dispose/flush 路径现在被真实行使;isSessionDir 断言指向真实存在的目录;弱断言文案修正。

验证

验证项 结果
smoke-lifecycle.mjs(284 项断言,第二轮新增 15 组回归用例) 连跑三轮全绿
smoke-host.mjs 66 项 + client 渲染冒烟 通过
真机:驱动 29/29、真实 agent 回合 8/8、kill -9 崩溃恢复、截断场景 5/5 全部通过

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.6 — 技能化双轴审计:7 处隐形 bug 修复 + 死代码清理

Choose a tag to compare

@G57651 G57651 released this 06 Oct 10:20

🔬 v0.3.6:技能化双轴审计(code-review + diagnosing-bugs)—— 7 处隐形 bug 修复 + 死代码清理

用两个社区技能对全部约 7300 行代码做了一轮完整审计:

  • code-review(67 万安装):双轴隔离并行审计 —— Standards(仓库规范 + Fowler 坏味道基线)与 Spec(需求符合度),四个子代理并行、报告不合并不重排;
  • diagnosing-bugs(72 万安装):修复纪律 —— 每处 bug 先写能红的反馈循环(回归用例),看它红,再修,再看它绿。

修复的隐形 bug(全部红灯先行验证)

  1. env 清理会写宿主 env → 改为纯报告:插件从不改写宿主环境(子 shell 的 export 不会到达宿主),清理自然也不写;不再产生伪冲突。
  2. remove 分支缺少冲突检查:会话「创建→删除」的路径被外部重建时,旧代码因 after 为空跳过校验、静默删除;现在判冲突保留,无哈希的大文件增加 size 兜底。
  3. 恢复流程双重编码(两层真 bug):清理目录名是 encodeSegment(id);resume 把已编码目录名再喂给路径构造会二次编码——连 cleanup.json 都读不到、静默跳过;且 rollback 会把编码名写回状态文件,第二次 resume 定位失败、销毁 Journal 却留下会话目录。现在新增 decodeSegment,以目录名为主源直接寻址。
  4. trackingExclude 替换默认排除表:自定义一项排除即丢失 node_modules/.git 等默认项 → 改为合并。
  5. 所有权标签错报:会话自建文件再次编辑被标成 session_modified → 标签改为跟随基线归属。
  6. 快照缺失报告误导:未存快照的恢复失败报 snapshot-missing → 统一为文档一致的 snapshot-unavailable;基线对超大文件跳过快照时输出日志。
  7. 清理意图晚于最终 diff 落盘:diff 窗口内崩溃会留下「删除中但不可续跑」的中间态 → 状态先落盘(对齐文档流程 step 1)。

client 侧:未知资源类型归入「其他」且不可打开(原来冒充文件并可点开);仅含环境变量的会话仍显示工具栏;已删除视图行恢复显示工作目录;config 调用失败不再静默关闭自动刷新。

死代码清理

safeList、snapshots.pathFor、未用图标与常量、死 locale 键、死 CSS、测试脚本死片段、trackers 未用参数;记录 id 去掉恒为 0 的 seq;index.js 端点与 RPC 回退分支去重;轮询扫描移入 manager 域层。导出/导入双扫描器复查归零。

验证

验证项 结果
smoke-lifecycle.mjs(214 项,含 6 组审计回归用例) 连跑三轮全绿
smoke-host.mjs 66 项 + client 渲染冒烟(新增 3 组断言) 通过
真机:驱动 29/29、真实 agent 回合 8/8、kill -9 崩溃恢复、截断场景 5/5 全部通过

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.5 — 代码审计:4 处隐形 bug 修复 + 死代码清理

Choose a tag to compare

@G57651 G57651 released this 06 Oct 10:01

🔍 v0.3.5:全量代码审计 —— 4 处隐形 bug 修复 + 死代码清理

对全部源码做了一轮系统审计(死代码扫描 + 逐文件精读 + 真机复验),结果如下。

修复的隐形 bug(均已补回归用例)

1. 环境的「外部改动」被静默覆盖(与文件域保护不一致)

  • 会话创建的变量若其后被外部改过值:清理会盲目 unset,删掉别人的值 → 现在仅当环境仍与 Journal 记录完全一致才 unset,否则记 externally-modified-after-session 冲突并保留;
  • 既有变量被外部 unset 后:恢复逻辑会把它复活 → 现在判为冲突,保留外部的删除。

2. 权限变更丢失「既有」血统
收养的既有文件若仅被 chmod(内容不变),permission_changed 记录没有携带 unbaselined 标记——删除会话会把这个既有文件删掉。已修复:权限记录的血统与其它动作一致。

3. verify 阶段自相矛盾
非空的会话新建目录在 path 阶段是「保守跳过(非失败)」,verify 阶段却被判定为失败(rollback_failed、Journal 保留)。现在跳过结果统一传递,行为一致。

4. ENOENT 竞态被记成失败
文件在「状态检查」与「删除」之间消失会被记为 failed;现在视为幂等成功(目标状态已达成)。

另:resume 分支的「先删目录后写标记」顺序与其它移除路径对齐(幂等性本就兜底,统一更稳妥)。

死代码清理

files.js(pathExists/relativeTo/absoluteIn/parentDirOf/noteDir/knownDirList/resourceType 属性及未用 path 导入)、baseline.js(BASELINE_FILE_NAME)、journal.js(destroy)、snapshots.js(destroyAll/limits/logger)、opener.js(platform getter/logger)、manager.js(未用的公共面与导出)、session-manage.js、smoke-host.mjs 的未用导入。两个引用扫描器(导出/导入)复查归零。

验证

验证项 结果
smoke-lifecycle.mjs(新增 env 外部改/外部删、chmod 收养文件保留用例) 193 项 × 3 轮全绿
smoke-host.mjs + client 渲染冒烟 66 项 + 全状态通过
真机:驱动 29/29、真实 agent 回合 8/8、kill-9 崩溃恢复、截断场景 5/5 全部通过

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.4 — 截断误删防护(birthtime 判定)· 环境变量只记录不污染宿主

Choose a tag to compare

@G57651 G57651 released this 06 Oct 09:55

🛡 v0.3.4:修复两个高危隐形问题(截断误删防护 + 环境变量不再污染宿主)

1. 基线截断可能误删既有文件 —— 已修复

工作区文件数超过 trackingMaxFiles(默认 5000)时基线会被截断;未被基线收录的既有文件在首次 diff 时会被误判为「会话新建」——删除会话时可能把它们一起删掉(你的 default-workspace 已触发截断条件)。

修复:用 birthtime 二次判定(扫描时已记录;无 birthtime 的文件系统回退 mtime)——早于会话开始的文件一律静默收养为既有资源:不写 Journal、不出现在资源视图、绝不被清理移除。会话若修改/删除了这类文件,回滚时跳过并如实报告 preexisting-unbaselined(原内容未被快照,无法恢复)。状态刷新时保留血统标记,before 侧全程可追溯。

真机截断场景实测(基线强行截断到 1 个文件):两个既有文件全部保留 ✅,同时会话真新建的文件仍被正常清理 ✅——安全与核心功能同时成立。

2. 环境变量解析会真实污染宿主进程 —— 已修复

旧行为把解析出的 export FOO=bar 写进宿主进程 env——一条会话命令(如 export PATH=...、NODE_OPTIONS=...)会真实影响 harness 之后启动的所有子进程。

修复:只记录、绝不改写宿主 env;并把 PATH / NODE_OPTIONS / NODE_PATH / LD_* / DYLD_* / HOME / TMPDIR / SHELL / IFS / DSH_HOME 等运行性变量直接排除出跟踪。清理阶段的 env 恢复对「宿主从未改变过」的变量是刻意的 no-op。

3. 附带修复

session-manage.js 资源清理异常处理器引用了不在作用域的 logger——会把真实清理错误掩盖成 logger is not defined(本轮回归首次触发暴露,已修)。

验证

  • 离线:smoke-lifecycle 181 项断言(新增收养/保留/新建照常清理/PATH 排除/宿主 env 不被改写),连跑三轮全绿;smoke-host 66 项通过;
  • 真机(隔离宿主 + 真实 agent 回合):驱动 29/29、agent 回合端到端 8/8、截断场景 5/5。

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.3 — 修复已删除会话的 tracking 目录复活(真机验证发现)

Choose a tag to compare

@G57651 G57651 released this 06 Oct 09:43

🩹 v0.3.3:修复已删除会话的 tracking 目录被"复活"

真机验证发现并修复两个竞态缺陷——删除会话后,其资源跟踪目录可能重新出现:

  1. 宿主重启的基线扫描依据过期的内存语料,把一个已被删除的会话重新建基线,把刚销毁的 tracking 目录建了回来。修复:ensureBaseline 守卫扩展为凡在回收站清单中的会话一律不再建基线(用户在回收站里恢复该会话后自动解除,可重新跟踪)。
  2. **activity.json 的防抖写入(1.5 秒)**可能在删除完成之后才落盘,mkdir 把目录建回来(残留一个 activity.json)。修复:写入落盘前核对回收站清单,且销毁 Journal 前取消未决的写入定时器。

真机验证(隔离实例:npm 发布版宿主 0.2.0-rc.2 + 真实 agent 回合)

项目 结果
生命周期驱动(基线 / 跟踪 / 删除回滚 / 外部修改保护 / openResource 守卫与真实定位) 29/29 通过
真实 agent 回合端到端(mock LLM → 真实 bash 工具 → 真实 tool/call+tool/result 事件 → 事件驱动 Journal → 删除回滚) 8/8 通过
kill -9 崩溃恢复(重启自动续跑:junk 回滚、会话目录与 Journal 销毁、日志无异常) 通过
修复复验:建→跟踪→删除→等 3 秒→重启,tracking 保持清理 通过

离线:smoke-lifecycle 163 项、smoke-host 66 项断言通过。

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)。

v0.3.2 — 打开方式收敛为本机文件管理器(移除应用选择)

Choose a tag to compare

@G57651 G57651 released this 06 Oct 09:33

🧹 v0.3.2:打开方式收敛为本机文件管理器

按要求,会话资源的打开方式只保留本机自带的文件管理器,其余打开方式全部移除:

  • 移除:应用下拉选择、本机应用扫描(listApplications 端点及其扫描代码)、按指定应用打开的整条路径(openWith);
  • 保留:单个「打开」、勾选后的批量「打开所选(N)」、「全选 / 反选」、「打开工作区」——全部统一走文件管理器定位:
    • macOS:访达(open -R,在访达中显示该文件);
    • Windows:资源管理器(explorer /select,<path>,选中该文件);
    • Linux:xdg-open 打开所在目录。
  • openResource 端点签名收敛为 { id, path };工具栏改为一行说明文案("将在本机文件管理器中显示(访达 / 资源管理器)")+ 操作按钮。

安全边界不变:所有进程启动均为 argv 数组、无 shell 拼接;可打开路径严格限制在该会话的工作区内(越界 / 已不存在 / 未跟踪分别报错)。

验证

  • smoke-lifecycle.mjs 156 项断言(open 用例:reveal argv、工作区根、路径越界、文件缺失、未跟踪会话);
  • smoke-host.mjs 66 项断言通过;
  • client 渲染冒烟:断言应用下拉已不存在、工具栏与全选 / 反选按钮存在,全部面板状态渲染正常。

升级

从 0.3.x 直接升级,无迁移。更新后在 Plugins 面板重载插件(或重启 Harness)并刷新页面。