dsh-recall-plugin 2.3.22 → 2.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  本文件格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
4
4
 
5
+ ## [2.3.24] - 2026-09-18
6
+
7
+ ### 新增
8
+
9
+ - **「仅撤回对话」模式(撤回范围二选一)**:对生成结果不满意、但文件改动恰是想要(或已人工修整)时,整段回退会把文件一并覆盖。确认面板新增撤回范围 radio 组(原生 input、键盘可达;默认「回退文件与对话」与现状逐项一致;首条用户消息因对话无从回退不渲染)——选「仅撤回对话」后文件清单降级为参考语义、安全快照预告隐藏(不打安全快照:零文件改动即无不可逆操作缺口),按钮与 executing/done 文案随模式分叉。实现=`ExecuteArgs` 增 `scope?: 'both' | 'session-only'`(缺省/非法值回落 both:老 Client 与直调 API 行为不漂移),Host execute 开头分叉——session-only 不进串行队列、零 git 写操作(保留 NO_SNAPSHOT/AGENT_BUSY 两道护栏,跳过 STALE 校验/安全快照/rollback/rescue 全链),直接 `resolveCutSeq` + `resolveStaleQueueItemIds` 返回 `count: 0`;fork/归档/子会话导航/排队消息清理/lineage/草稿回填链与模式无关,原样复用。新增 `tests/unit/routes-scope.test.js` 5 例(session-only 零 git 调用与透传、agentBusy 拦截、NO_SNAPSHOT、非法 scope 回落 both、不传 scope 现状回归钉)。
10
+
11
+ ## [2.3.23] - 2026-09-18
12
+
13
+ ### 修复
14
+
15
+ - **撤回后子会话不打开(dsh 0.1.6-alpha.2 移除 `ISessions.open`,实弹冒烟发现)**:alpha.2 起 `ISessions` 只保留列表快照与 `retain`/`using` 引用模型,契约注释写明「navigation belongs to view owners」——原调用的 `sessions.open(sessionId)` 已不存在,守卫判断静默跳过,于是撤回的 execute/fork/lineage 全部正常,唯独 fork 出的子会话不会被打开:页面停在工作区空态。导航入口迁至独立 `uiWorkspace` 服务(`dsh-client-ui-workspace`)的 `openSession(target: SessionTarget)`(`SessionTarget = SessionId | SubagentAddress`,官方 UI 同样传裸 sessionId;`ctx.workspaces` 只有归档能力、无导航)。修复=client `inject` 声明 `uiWorkspace` + `ctx.uiWorkspace` 类型化(`ClientUiWorkspaceService`),导航点改双版本分支:`uiWorkspace.openSession(id)` 优先、旧版回退 `sessions.open(id)`(撤回节点与快照管理「切换」两处)。`tests/probe/api-surface.test.js` 新增「会话导航归属」2 例钉住两侧事实,compat-audit 新增 I37。实弹复验:撤回第二条消息后子会话自动打开、对话回退、标题继承、被撤回消息文本回填输入框。
16
+
17
+ - **快照管理「切换」把归档会话放进点击路径,一点就落到工作区空态**:按钮判据只查会话是否在官方列表里(`sessions.list`),依据「已归档会话不在列表」的假设;alpha.2 起该快照包含归档会话,而归档会话不是合法的主视图选择——官方导航会先设置选择、随即按「归档选择不保留」把它清空,视图落空态(撤回后归档的原会话最常命中)。修复=判据叠加归档集合排除:`ClientWorkspacesService` 补 `list` 面,从 `ctx.workspaces.list.getSnapshot().archivedSessionIds` 取归档集合(服务经 `buildSettingsCards` 传入快照管理卡),只有「在官方列表且未归档」的会话才渲染「切换」。实弹复验:归档会话行不再出现「切换」,保留「切换」的活跃会话点击后正常打开。
18
+
19
+ ### 变更
20
+
21
+ - **旧版回退核验 + 兼容声明下界收窄**:本批次三处改码都在跨版本面上(静态 `uiWorkspace` inject、`plugins.bundle.config` 注册、读 `workspaces` 归档集合),故把全局 dsh 降到纯 `0.1.6-alpha.1`(`npm install -g @deepseek-ai/dsh@0.1.6-alpha.1 --before=2026-09-16`;不带 `--before` 会因 dsh 自身 `^0.1.6-alpha.1` 放行同 tuple 预发布而混入 alpha.2 的包)实弹一轮,确认未升级 dsh 的用户更新插件后不会变砖——三项全过、控制台零报错:旧 slot(`settings.plugin.item`)卡片照常渲染且样式注入正常、`plugins.bundle.config` 在旧渲染器上是静默 no-op;撤回 fork 后子会话由 `uiWorkspace.openSession` 正常打开(切过去后再发消息、新快照记到子会话 id 为证);快照管理树按 lineage 聚族(`v1/2`/`v2/2`)。同时按 registry 产物逐版核验 `uiWorkspace` 服务可用性:`0.1.2-alpha.2` 起有该服务但无 `openSession`(该线走 `sessions.open` 回退,`ISessions.open` 到 alpha.1 都在)、`0.1.5-rc.2` 起 `openSession` 在位,而 **`0.1.1-rc.2` 线没有该服务**(同线亦缺 `sessions`/`workspaces`:`dsh-api-session-controller`/`dsh-api-workspace-controller` 无该版本发布)——静态声明无法满足,插件 UI 会静默不渲染。据此**7 个 dsh-* peer 范围去掉 `>=0.1.1-rc.2 <0.1.2` 段**,让该组合在安装期被明确拦住而不是装上了白屏;README 双语兼容声明与 badge 上界由 `0.1.6-alpha.1` 更新为 `0.1.6-alpha.2` 并写明不再声明支持 0.1.1-rc.2 及更早的原因;compat-audit I37 补「服务可用性」条目,实弹记录见 `docs/plans/completed/smoke-checklist-records.md`。核验完装回 `0.1.6-alpha.2`(树内 8 个 `@deepseek-ai/dsh-*` 包一致),`npm run check:upgrade` 三层门禁全绿(check:dsh 全一致 / test:probe 39 通过 / verify:host 通过)。
22
+
23
+ - **README 双语补充快照捕获窗口的边界说明**:快照为异步捕获,从收到消息到 `git add` 之间有约 0.5–1.5 秒窗口(Windows 上一次 PowerShell 启动即约 0.4 秒;index.json 记的 `time` 是脚本发起时刻而非捕获时刻)。秒级完成的琐碎任务若落在窗口内改完文件,该条快照会连带捕获本轮改动——撤回时文件回退成为空操作(预览显示「共 0 个文件将变更」),对话回退不受影响,且撤回前仍先落 `snap-pre-rollback-*` 安全快照,无数据丢失。此为异步快照的固有边界,无法消除(除非让每条消息同步阻塞等快照完成)。
24
+ - **dsh 0.1.6-alpha.2 兼容适配:设置卡片迁挂插件管理页 slot(I12)**:全局实装 `@deepseek-ai/dsh@0.1.6-alpha.2`(npm dist-tag `alpha`,tag commit `ddefc45`)后核查发现旧设置页插件 tab 整体移除——`settings.plugin.item` 与 `settings.plugins.tab` 产物字符串归零,新增 ui-plugin-manager 插件管理页,声明 `plugins.item` / `plugins.bundle.config` / `plugins.row.config` 三 slot(bundle 自带配置走 `plugins.bundle.config`,keyed by bundle 包名,page 视图要求表单自含保存控件)。Client 侧改为双键并注册:新增 `plugins.bundle.config`(key=`dsh-recall-plugin`,插件管理页 bundle 页渲染 RecallSettingsCard)+ 保留旧键 `settings.plugin.item`(key=`dsh-recall`,0.1.6-alpha.1 及以前生效)——官方 renderer 对未声明 key 的 `slots.inject` 是静默 no-op(`specDynamic` 为 undefined 直接 return),双版本各吃各键无需运行时探测。其余消费面零破坏:fork 签名与切点 `cut = boundary.seq + 1`(I35 根治)逐字保持;connection `fetch.register` 契约不变(仅新增 `streamBaseUrl?` 可选字段);client sessions 改 retain/release 引用模型(多实例共存),`binding()` 收窄为「只借已 retain 的会话」——附件重建链(I34)全链 typeof 降级兜底,最坏仅附件不重建(导航面另有两处问题,见上方修复)。peer 范围 `>=0.1.6-alpha.1 <0.1.7` 天然覆盖 alpha.2 无需扩展。机器化断言:`npm test` 361/361 + `check:upgrade` 三层门禁全绿(probe 37/37)。reference/ 镜像按 alpha.2 tag 重拉(仅 06/09 文档文字修订);compat-audit 头部追加 alpha.2 核验段并更新 I12。实弹冒烟记录见 `docs/plans/completed/smoke-checklist-records.md`。
25
+
5
26
  ## [2.3.22] - 2026-09-16
6
27
 
7
28
  ### 修复
package/README.en.md CHANGED
@@ -7,7 +7,7 @@
7
7
  ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-blue)
8
8
  ![Build](https://img.shields.io/badge/pure%20JS-green)
9
9
 
10
- [![DSH](https://img.shields.io/badge/DSH-0.1.6--alpha.1-blue)](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.6-alpha.1)
10
+ [![DSH](https://img.shields.io/badge/DSH-0.1.6--alpha.2-blue)](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.6-alpha.2)
11
11
  ![DSH](https://img.shields.io/badge/DSH-Desktop-blue)
12
12
  ---
13
13
  Under any message you've sent, click "↶ Recall" — **your workspace files and the conversation history roll back to just before that message was sent**.
@@ -45,7 +45,8 @@ Files and conversation roll back together: the workspace is first snapshotted in
45
45
 
46
46
  Abilities with a version in parentheses require that version or later; the rest have no special version requirement.
47
47
 
48
- - **Files + conversation, rolled back together**: recalling isn't just about chat history — files the agent modified go back to their original state too; immune to your project's `.gitattributes` conversion, with byte-level fidelity for line endings and binary content (2.1.1+).
48
+ - **Files + conversation, rolled back together**: recalling isn't just about chat history — files the agent modified go back to their original state too; immune to your project's `.gitattributes` conversion, with byte-level fidelity for line endings and binary content (2.1.1+).
49
+ - **Just want a fresh conversation? Leave the files alone** (2.3.24+): the confirmation panel offers a recall-scope choice — the default "Roll back files & conversation" behaves as before; picking "Conversation only" keeps your project files byte-for-byte untouched (no safety snapshot either) and rewinds only the conversation, ideal when you dislike the reply but want to keep the file changes.
49
50
  - **Never touches your project's own git, and keeps it clean**: snapshots live in an independent shadow git repository — branches, staging area, and uncommitted changes are untouched; storage stays under `$DSH_HOME` regardless of the session's sandbox permission (workspace-write / read-only sessions work as usual), falling back to an in-project `.dsh-recall-snapshots` only when home itself is unwritable.
50
51
  - **See the list before you act — and change your mind as often as you like**: recall first shows the list of files that will change (modified / restored / deleted); nothing runs until you confirm. After a recall you can recall again to an even earlier point, and files overwritten during a recall always remain recoverable (up to 500 snapshots per workspace by default).
51
52
  - **Resend right after a recall** (2.3.15+): a recall places the message's text and attachments back into the input box — images and files return as well, so you can edit and send again without picking the attachments over.
@@ -58,6 +59,7 @@ Abilities with a version in parentheses require that version or later; the rest
58
59
  Boundaries accepted by design and edge cases not yet covered — worth checking before you rely on them.
59
60
 
60
61
  - Snapshots are created **when a message is sent**; messages from before the plugin was enabled have no snapshot and show no recall button.
62
+ - Snapshots are **best-effort**: there is a 0.5–1.5 second window between the message arriving and `git add` (on Windows, a single PowerShell start alone costs about 0.4s). If a trivial task finishes editing files inside that window, the snapshot captures the turn's own changes — the file rollback then becomes a no-op (the preview panel reports "0 files will change") while the conversation rollback is unaffected.
61
63
  - The first user message of a session cannot roll back the conversation (files only), because fork requires an earlier turn boundary.
62
64
  - Recall cannot be initiated while an agent is running in the target workspace (by design — stop the agent first).
63
65
  - Supports Windows (PowerShell 5.1/7 + git CLI) and Linux/macOS (bash + git CLI). Windows is thoroughly verified on real machines; Linux has been fully tested on WSL2 (Ubuntu 26.04, bash 5.3 + git 2.53), including Chinese paths, home fallback, session cleanup, and gc; the macOS side is written to be bash 3.2 compatible but has not been tested on real hardware yet.
@@ -67,7 +69,7 @@ Boundaries accepted by design and edge cases not yet covered — worth checking
67
69
 
68
70
  ## Installation
69
71
 
70
- Prerequisites: git CLI (without it the recall button won't appear and a notice shows at the top of the page — DSH itself keeps running); PowerShell 5.1 / 7 on Windows, bash + git on Linux/macOS; DSH `0.1.1-rc.2` through `0.1.6-alpha.1` (peerDependencies open a window per minor line: `>=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7`, consistent with the `dsh.compatibility.dshReleases` declaration; each line is anchored at its first verified version with an exclusive upper bound at the next minor, so later prereleases/releases within a verified line are admitted without touching the peer declaration, while unverified new minor lines (e.g. 0.1.7) remain blocked).
72
+ Prerequisites: git CLI (without it the recall button won't appear and a notice shows at the top of the page — DSH itself keeps running); PowerShell 5.1 / 7 on Windows, bash + git on Linux/macOS; DSH `0.1.2-alpha.1` through `0.1.6-alpha.2` (peerDependencies open a window per minor line: `>=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7`, consistent with the `dsh.compatibility.dshReleases` declaration; each line is anchored at its first verified version with an exclusive upper bound at the next minor, so later prereleases/releases within a verified line are admitted without touching the peer declaration, while unverified new minor lines (e.g. 0.1.7) remain blocked). `0.1.1-rc.2` and earlier are no longer declared supported: their client runtime lacks the `sessions`/`workspaces`/`uiWorkspace` services, so the plugin UI silently fails to render.
71
73
 
72
74
  - Official DSH plugin command: install and auto-mount into the web profile
73
75
  ```powershell
@@ -92,8 +94,8 @@ pm2 restart <your-dsh-name> # if managed by pm2
92
94
  A full recall of one user message sent after the plugin was enabled goes like this.
93
95
 
94
96
  1. Hover over any user message sent **after the plugin was enabled** (including steering messages inserted while the agent is running) — "↶ Recall" appears to the left of the copy button.
95
- 2. Click it → the confirmation panel shows the list of files that will change (modified / restored / deleted).
96
- 3. Click "Confirm rollback" → files are restored to their state before that message was sent; the view switches to a new session (that message and everything after it is removed), while the original session is archived and can be recovered anytime.
97
+ 2. Click it → the confirmation panel shows the list of files that will change (modified / restored / deleted), plus a scope choice: "Roll back files & conversation" (default) or "Conversation only" (files stay as they are).
98
+ 3. Click "Confirm rollback" (or "Confirm conversation recall") → files are restored to their state before that message was sent (files are untouched in conversation-only mode); the view switches to a new session (that message and everything after it is removed), while the original session is archived and can be recovered anytime.
97
99
 
98
100
  ## Configuration
99
101
 
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-recall-plugin?style=flat-square&label=npm&color=3178C6)](https://www.npmjs.com/package/dsh-recall-plugin)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/dsh-recall-plugin?style=flat-square&label=downloads&color=1F883D)](https://www.npmjs.com/package/dsh-recall-plugin)
7
7
  ![License](https://img.shields.io/badge/license-MIT-blue)
8
- [![DSH](https://img.shields.io/badge/DSH-0.1.6--alpha.1-blue)](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.6-alpha.1)
8
+ [![DSH](https://img.shields.io/badge/DSH-0.1.6--alpha.2-blue)](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.6-alpha.2)
9
9
  ---
10
10
  在任意一条你发过的消息下方点「↶ 撤回」——**工作区文件和对话历史一起回到那条消息发出之前的状态**。
11
11
  ---
@@ -43,7 +43,8 @@
43
43
 
44
44
  带括号版本号的能力需要该版本或更高;其余无特殊版本要求。
45
45
 
46
- - **文件 + 对话,整段回退**:撤回的不只是聊天记录,agent 改过的文件也一并回到原样;不受项目 `.gitattributes` 转换影响,换行与二进制内容字节级保真(2.1.1+)。
46
+ - **文件 + 对话,整段回退**:撤回的不只是聊天记录,agent 改过的文件也一并回到原样;不受项目 `.gitattributes` 转换影响,换行与二进制内容字节级保真(2.1.1+)。
47
+ - **只想重来对话?文件可以不动**(2.3.24+):确认面板里可二选一撤回范围——默认「回退文件与对话」同现状;选「仅撤回对话」则项目文件一个字节都不动(也不打安全快照),只有对话回退,适合对生成结果不满意、但文件改动恰是想要的场景。
47
48
  - **不碰你项目自己的 git,目录保持干净**:快照存在独立的影子 git 仓库里,分支、暂存区、未提交改动统统不受影响;存储默认落在 `$DSH_HOME` 下,与会话的沙箱权限无关(workspace-write / read-only 照常工作),仅当 home 不可写才降级到项目内 `.dsh-recall-snapshots`。
48
49
  - **先看清单再动手,可反复后悔**:撤回前展示将变更的文件清单(修改 / 恢复 / 删除),确认后才执行;撤回后还能再撤到更早,被覆盖的文件一直找得回来(默认每工作区保留 500 条)。
49
50
  - **撤回完就能重发**(2.3.15+):撤回会把这条消息的文本与附件一起放回输入框——图片、文件原样回来,改完直接发送,不必重新挑一遍附件。
@@ -56,6 +57,7 @@
56
57
  设计上接受的边界与尚未覆盖的极端情形,使用前值得先确认。
57
58
 
58
59
  - 快照在**消息发送时**创建,插件启用前的历史消息没有快照,不显示撤回按钮。
60
+ - 快照是**尽力捕获**:从收到消息到 `git add` 之间有约 0.5–1.5 秒窗口(Windows 上仅一次 PowerShell 启动就占约 0.4 秒)。秒级完成的琐碎任务若在这个窗口内改完文件,该快照会连带捕获本轮改动——撤回时文件回退成为空操作(预览面板显示「共 0 个文件将变更」),对话回退不受影响。
59
61
  - 会话第一条用户消息无法回退对话(仅文件回退),因为 fork 需要更早的 turn 边界。
60
62
  - 目标工作区的 agent 正在运行时无法发起撤回(防护设计,先停止 agent 再撤回)。
61
63
  - 支持 Windows(PowerShell 5.1/7 + git CLI)与 Linux/macOS(bash + git CLI)。Windows 真机验证充分;Linux 已在 WSL2(Ubuntu 26.04,bash 5.3 + git 2.53)实测全流程(含中文路径、home 降级、会话清理、gc);macOS 侧脚本按 bash 3.2 兼容编写,尚未真机实测。
@@ -65,7 +67,7 @@
65
67
 
66
68
  ## 安装
67
69
 
68
- 前置:git CLI(未装时撤回按钮不出现,页面顶部会提示安装 git,不影响 DSH 运行);Windows 上 PowerShell 5.1 / 7 均可,Linux/macOS 需 bash + git;DSH `0.1.1-rc.2` 至 `0.1.6-alpha.1`(peerDependencies 为按 minor 版本线开窗 `>=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7`,与 `dsh.compatibility.dshReleases` 声明一致;每条线以首个核验版本为下限、开一条上界到下一 minor 的区间,同线内后续 prerelease/正式版自动放行、无需改 peer 声明,未验证的新 minor 线(如 0.1.7)仍被拦截)。
70
+ 前置:git CLI(未装时撤回按钮不出现,页面顶部会提示安装 git,不影响 DSH 运行);Windows 上 PowerShell 5.1 / 7 均可,Linux/macOS 需 bash + git;DSH `0.1.2-alpha.1` 至 `0.1.6-alpha.2`(peerDependencies 为按 minor 版本线开窗 `>=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7`,与 `dsh.compatibility.dshReleases` 声明一致;每条线以首个核验版本为下限、开一条上界到下一 minor 的区间,同线内后续 prerelease/正式版自动放行、无需改 peer 声明,未验证的新 minor 线(如 0.1.7)仍被拦截)。`0.1.1-rc.2` 及更早不再声明支持:那条线的客户端运行时没有 `sessions`/`workspaces`/`uiWorkspace` 服务,插件 UI 会静默不渲染。
69
71
 
70
72
 
71
73
  - DSH 官方插件命令:安装并自动挂载进 web profile
@@ -95,8 +97,8 @@ dsh plugin --profile web remove dsh-recall-plugin
95
97
  ## 使用
96
98
 
97
99
  1. 鼠标悬停任意**插件启用后发送**的用户消息(含 agent 运行中插入的转向指令消息),复制按钮左侧出现「↶ 撤回」。
98
- 2. 点击 → 确认面板展示将变更的文件清单(修改 / 恢复 / 删除)。
99
- 3. 点「确认回退」→ 文件恢复到该消息发送前的状态;视图切到新会话(该消息及之后的对话移除),原会话归档、随时可找回。
100
+ 2. 点击 → 确认面板展示将变更的文件清单(修改 / 恢复 / 删除),并可选撤回范围:「回退文件与对话」(默认)或「仅撤回对话」(文件保持当前状态)。
101
+ 3. 点「确认回退」(或「确认撤回对话」)→ 文件恢复到该消息发送前的状态(仅撤回对话时文件不动);视图切到新会话(该消息及之后的对话移除),原会话归档、随时可找回。
100
102
 
101
103
  ## 配置项
102
104
 
package/lib/client.js CHANGED
@@ -36,6 +36,16 @@
36
36
  // grid-column 对非 grid 祖先(exclude/快照卡片的 flex 布局)自动无效,无害;
37
37
  // 在 cfg-grid 内则保证操作区/占满行不被 auto-placement 塞进第一列撑爆列宽。
38
38
  ".dsh-recall-panel-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;margin-top:2px;grid-column:1/-1}",
39
+ // scope radio 组(撤回范围二选一):原生 input 保留 UA 交互(键盘方向键切换、
40
+ // 空格选中),accent-color 走品牌令牌让选中态随主题翻转;label 整体可点扩大
41
+ // 命中区,字色与 panel-note 同层级(secondary),hover 提亮示意可交互
42
+ ".dsh-recall-scope{display:flex;flex-wrap:wrap;gap:4px 16px;padding:2px 0}",
43
+ ".dsh-recall-scope-item{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:13px;line-height:1.5;color:var(--dsw-alias-label-secondary)}",
44
+ ".dsh-recall-scope-item:hover{color:var(--dsw-alias-label-primary)}",
45
+ ".dsh-recall-scope-item input{accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}",
46
+ // 焦点可见性对齐按钮类约定(brand-primary 2px outline):UA 默认环跨引擎不一,
47
+ // 统一收敛到与面板内其他控件同一套焦点语言
48
+ ".dsh-recall-scope-item input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}",
39
49
  // 按钮体系对齐官方设置卡(dsh-client-ui-settings-plugins PluginCard 底部按钮
40
50
  // 组实测产物):次级 = 描边幽灵(discard 逐字配方——l2 描边 + 透明底,hover
41
51
  // 升 label-dimmed 描边 + primary 字色);官方 discard/save 同高靠 save 也带
@@ -438,7 +448,7 @@
438
448
  }
439
449
  return parts.join(" \xB7 ");
440
450
  }
441
- function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc) {
451
+ function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc, uiWorkspaceSvc) {
442
452
  const { api, ensureInit, showThrottledToast, writeClipboard, clockText: clockText2, pluginConfig, messageFor } = util;
443
453
  function CopyIcon() {
444
454
  return React.createElement(
@@ -463,7 +473,7 @@
463
473
  React.createElement("path", { d: "M4.5 7.5h5a3 3 0 0 1 0 6H8" })
464
474
  );
465
475
  }
466
- function recallPanel(recall, closePanel, executeRecall) {
476
+ function recallPanel(recall, closePanel, executeRecall, scope, onScopeChange) {
467
477
  if (recall.stage === "loading") {
468
478
  return React.createElement(
469
479
  "div",
@@ -500,30 +510,72 @@
500
510
  React.createElement("span", { className: "dsh-recall-rel" }, c.rel || "")
501
511
  );
502
512
  });
513
+ const canRevertChat = typeof recall.cutSeq === "number";
514
+ const sessionOnly = canRevertChat && scope === "session-only";
503
515
  if (recall.truncated) {
504
- rows.push(React.createElement("div", { className: "dsh-recall-panel-note", key: "truncated" }, "\u2026\u4EC5\u663E\u793A\u524D " + changes.length + " \u6761\uFF0C\u5171 " + total + " \u4E2A\u6587\u4EF6\u5C06\u53D8\u66F4"));
516
+ rows.push(React.createElement(
517
+ "div",
518
+ { className: "dsh-recall-panel-note", key: "truncated" },
519
+ sessionOnly ? "\u2026\u4EC5\u663E\u793A\u524D " + changes.length + " \u6761\uFF0C\u5171 " + total + " \u5904\u5DEE\u5F02" : "\u2026\u4EC5\u663E\u793A\u524D " + changes.length + " \u6761\uFF0C\u5171 " + total + " \u4E2A\u6587\u4EF6\u5C06\u53D8\u66F4"
520
+ ));
505
521
  }
506
- const canRevertChat = typeof recall.cutSeq === "number";
507
522
  return React.createElement(
508
523
  "div",
509
524
  { className: "dsh-recall-panel" },
510
525
  React.createElement("div", { className: "dsh-recall-panel-title" }, "\u6574\u6BB5\u56DE\u9000"),
511
- React.createElement(
526
+ sessionOnly ? (
527
+ // session-only:零文件改动即无不可逆操作缺口——安全快照预告随之隐藏
528
+ //(不打安全快照),主说明换成模式语义
529
+ React.createElement(
530
+ "div",
531
+ { className: "dsh-recall-panel-note" },
532
+ "\u9879\u76EE\u6587\u4EF6\u4FDD\u6301\u5F53\u524D\u72B6\u6001\uFF0C\u4E0D\u4F1A\u88AB\u56DE\u9000\u6216\u5220\u9664\uFF1B\u5BF9\u8BDD\u56DE\u9000\u5230\u8BE5\u6D88\u606F\u4E4B\u524D\u3002"
533
+ )
534
+ ) : React.createElement(
512
535
  "div",
513
536
  { className: "dsh-recall-panel-note" },
514
537
  "\u5C06\u9879\u76EE\u6062\u590D\u5230" + (recall.time ? " " + clockText2(recall.time) + " " : " ") + "\u53D1\u9001\u8BE5\u6D88\u606F\u65F6\u7684\u72B6\u6001\u3002\u5171 " + total + " \u4E2A\u6587\u4EF6\u5C06\u53D8\u66F4" + (summaryText(counts) ? "\uFF08" + summaryText(counts) + "\uFF09" : "") + "\u3002\u6B64\u64CD\u4F5C\u4F1A\u8986\u76D6\u5F53\u524D\u6587\u4EF6\u5185\u5BB9\uFF1B\u56DE\u9000\u524D\u4F1A\u81EA\u52A8\u4FDD\u5B58\u4E00\u4EFD\u5F53\u524D\u72B6\u6001\u7684\u5B89\u5168\u5FEB\u7167\uFF08\u4E0D\u542B\u5728\u4E0B\u65B9\u6E05\u5355\u5185\uFF09\u3002"
515
538
  ),
516
- React.createElement(
539
+ sessionOnly ? null : React.createElement(
517
540
  "div",
518
541
  { className: "dsh-recall-panel-note" },
519
542
  canRevertChat ? "\u5BF9\u8BDD\u5C06\u4E00\u5E76\u56DE\u9000\u5230\u8BE5\u6D88\u606F\u4E4B\u524D\uFF1A\u8BE5\u6D88\u606F\u53CA\u4E4B\u540E\u7684\u5168\u90E8\u5BF9\u8BDD\u4F1A\u4ECE\u5F53\u524D\u89C6\u56FE\u79FB\u9664\uFF0C\u539F\u4F1A\u8BDD\u5F52\u6863\u4FDD\u5B58\uFF08\u53EF\u4ECE\u5F52\u6863\u627E\u56DE\uFF09\u3002" : "\u8BE5\u6D88\u606F\u662F\u672C\u4F1A\u8BDD\u4E2D\u7B2C\u4E00\u6761\u7528\u6237\u6D88\u606F\uFF0C\u65E0\u6CD5\u56DE\u9000\u5BF9\u8BDD\uFF1B\u786E\u8BA4\u540E\u4EC5\u56DE\u9000\u9879\u76EE\u6587\u4EF6\u3002"
520
543
  ),
544
+ sessionOnly && changes.length > 0 ? (
545
+ // 文件清单保留展示但降级为参考语义:清单照常算(Host preview 链路
546
+ // 不分叉),只是告知用户所选模式不会真的改这些文件
547
+ React.createElement(
548
+ "div",
549
+ { className: "dsh-recall-panel-note", key: "ref-note" },
550
+ "\u4EE5\u4E0B\u5DEE\u5F02\u4EC5\u4F5C\u53C2\u8003\uFF0C\u6240\u9009\u6A21\u5F0F\u4E0D\u4F1A\u6539\u52A8\u6587\u4EF6\u3002"
551
+ )
552
+ ) : null,
521
553
  changes.length > 0 ? React.createElement("div", { className: "dsh-recall-list" }, ...rows) : null,
554
+ canRevertChat ? (
555
+ // 模式二选一(原生 radio,键盘方向键可达):临场选择不设全局配置项;
556
+ // 默认 both 与现状一致,面板每次打开都复位到默认起点
557
+ React.createElement(
558
+ "div",
559
+ { className: "dsh-recall-scope", role: "radiogroup", "aria-label": "\u64A4\u56DE\u8303\u56F4" },
560
+ React.createElement(
561
+ "label",
562
+ { className: "dsh-recall-scope-item" },
563
+ React.createElement("input", { type: "radio", name: "dsh-recall-scope", checked: scope === "both", onChange: () => onScopeChange("both") }),
564
+ React.createElement("span", { className: "dsh-recall-scope-label" }, "\u56DE\u9000\u6587\u4EF6\u4E0E\u5BF9\u8BDD")
565
+ ),
566
+ React.createElement(
567
+ "label",
568
+ { className: "dsh-recall-scope-item" },
569
+ React.createElement("input", { type: "radio", name: "dsh-recall-scope", checked: scope === "session-only", onChange: () => onScopeChange("session-only") }),
570
+ React.createElement("span", { className: "dsh-recall-scope-label" }, "\u4EC5\u64A4\u56DE\u5BF9\u8BDD")
571
+ )
572
+ )
573
+ ) : null,
522
574
  React.createElement(
523
575
  "div",
524
576
  { className: "dsh-recall-panel-actions" },
525
577
  React.createElement("button", { type: "button", className: "dsh-recall-btn", onClick: closePanel }, "\u53D6\u6D88"),
526
- React.createElement("button", { type: "button", className: "dsh-recall-btn dsh-recall-btn-danger", onClick: executeRecall }, "\u786E\u8BA4\u56DE\u9000")
578
+ React.createElement("button", { type: "button", className: "dsh-recall-btn dsh-recall-btn-danger", onClick: executeRecall }, sessionOnly ? "\u786E\u8BA4\u64A4\u56DE\u5BF9\u8BDD" : "\u786E\u8BA4\u56DE\u9000")
527
579
  )
528
580
  );
529
581
  }
@@ -531,7 +583,7 @@
531
583
  return React.createElement(
532
584
  "div",
533
585
  { className: "dsh-recall-panel" },
534
- React.createElement("div", { className: "dsh-recall-panel-title" }, "\u6B63\u5728\u56DE\u9000\u2026")
586
+ React.createElement("div", { className: "dsh-recall-panel-title" }, scope === "session-only" ? "\u6B63\u5728\u64A4\u56DE\u5BF9\u8BDD\u2026" : "\u6B63\u5728\u56DE\u9000\u2026")
535
587
  );
536
588
  }
537
589
  if (recall.stage === "done") {
@@ -542,7 +594,10 @@
542
594
  React.createElement(
543
595
  "div",
544
596
  { className: "dsh-recall-panel-note" },
545
- recall.chatReverted ? "\u9879\u76EE\u6587\u4EF6\u4E0E\u5BF9\u8BDD\u5DF2\u56DE\u9000\u5230\u8BE5\u6D88\u606F\u4E4B\u524D\u3002\u65B0\u4F1A\u8BDD\u5DF2\u6253\u5F00\uFF0C\u539F\u4F1A\u8BDD\u5DF2\u5F52\u6863\uFF08\u53EF\u4ECE\u5F52\u6863\u627E\u56DE\uFF09\u3002" : "\u9879\u76EE\u5DF2\u6062\u590D\u5230\u53D1\u9001\u8BE5\u6D88\u606F\u65F6\u7684\u72B6\u6001\u3002" + (recall.chatError ? " \u5BF9\u8BDD\u56DE\u9000\u5931\u8D25\uFF1A" + recall.chatError : "")
597
+ scope === "session-only" ? (
598
+ // session-only 文案矩阵:文件侧零改动是确定事实,失败时也只描述对话侧
599
+ recall.chatReverted ? "\u5BF9\u8BDD\u5DF2\u56DE\u9000\u5230\u8BE5\u6D88\u606F\u4E4B\u524D\uFF0C\u9879\u76EE\u6587\u4EF6\u4FDD\u6301\u5F53\u524D\u72B6\u6001\u3002\u65B0\u4F1A\u8BDD\u5DF2\u6253\u5F00\uFF0C\u539F\u4F1A\u8BDD\u5DF2\u5F52\u6863\uFF08\u53EF\u4ECE\u5F52\u6863\u627E\u56DE\uFF09\u3002" : "\u5BF9\u8BDD\u56DE\u9000\u5931\u8D25\uFF1A" + (recall.chatError || "\u672A\u77E5\u539F\u56E0") + "\u3002\u9879\u76EE\u6587\u4EF6\u672A\u505A\u4EFB\u4F55\u6539\u52A8\u3002"
600
+ ) : recall.chatReverted ? "\u9879\u76EE\u6587\u4EF6\u4E0E\u5BF9\u8BDD\u5DF2\u56DE\u9000\u5230\u8BE5\u6D88\u606F\u4E4B\u524D\u3002\u65B0\u4F1A\u8BDD\u5DF2\u6253\u5F00\uFF0C\u539F\u4F1A\u8BDD\u5DF2\u5F52\u6863\uFF08\u53EF\u4ECE\u5F52\u6863\u627E\u56DE\uFF09\u3002" : "\u9879\u76EE\u5DF2\u6062\u590D\u5230\u53D1\u9001\u8BE5\u6D88\u606F\u65F6\u7684\u72B6\u6001\u3002" + (recall.chatError ? " \u5BF9\u8BDD\u56DE\u9000\u5931\u8D25\uFF1A" + recall.chatError : "")
546
601
  ),
547
602
  React.createElement(
548
603
  "div",
@@ -677,6 +732,7 @@
677
732
  const [copied, setCopied] = React.useState(false);
678
733
  const [hasSnapshot, setHasSnapshot] = React.useState(false);
679
734
  const [recall, setRecall] = React.useState({ stage: "idle" });
735
+ const [scope, setScope] = React.useState("both");
680
736
  React.useEffect(() => {
681
737
  let alive = true;
682
738
  let timer = null;
@@ -733,6 +789,7 @@
733
789
  };
734
790
  const openPreview = () => {
735
791
  if (recall.stage === "loading" || recall.stage === "executing") return;
792
+ setScope("both");
736
793
  setRecall({ stage: "loading" });
737
794
  api("preview", { messageId, sessionId }).then((res) => {
738
795
  if (!res || !res.ok) {
@@ -759,7 +816,7 @@
759
816
  const previewTotal = typeof recall.total === "number" ? recall.total : changes.length;
760
817
  const attachmentFiles = pluginConfig.refillDraft && attachmentRefs.length > 0 && sessionId ? preloadAttachmentFiles(sessionId, attachmentRefs) : null;
761
818
  setRecall({ stage: "executing", changes });
762
- api("execute", { messageId, sessionId, previewTotal, previewTreeId: recall.treeId || void 0, previewAt: Date.now() }).then(async (res) => {
819
+ api("execute", { messageId, sessionId, previewTotal, previewTreeId: recall.treeId || void 0, scope, previewAt: Date.now() }).then(async (res) => {
763
820
  if (!res || !res.ok) {
764
821
  if (res && res.code === "STALE") {
765
822
  setRecall({ stage: "loading" });
@@ -793,7 +850,8 @@
793
850
  try {
794
851
  const childId = await sessionsSvc.fork({ sessionId, atSeq: cutSeq });
795
852
  if (childId) {
796
- if (typeof sessionsSvc.open === "function") sessionsSvc.open(childId);
853
+ if (uiWorkspaceSvc && typeof uiWorkspaceSvc.openSession === "function") uiWorkspaceSvc.openSession(childId);
854
+ else if (typeof sessionsSvc.open === "function") sessionsSvc.open(childId);
797
855
  chatReverted = true;
798
856
  fillTarget = childId;
799
857
  removeStaleQueueItems(childId, res.staleQueueItemIds);
@@ -820,7 +878,10 @@
820
878
  setRecall({ stage: "error", message: String(error) });
821
879
  });
822
880
  };
823
- const closePanel = () => setRecall({ stage: "idle" });
881
+ const closePanel = () => {
882
+ setScope("both");
883
+ setRecall({ stage: "idle" });
884
+ };
824
885
  const bubbleChildren = [];
825
886
  if (imageBlocks.length && typeof renderMessageImages === "function") {
826
887
  const render = renderMessageImages;
@@ -874,7 +935,7 @@
874
935
  { className: "dsh-recall-row", "data-time-hover-root": true },
875
936
  bubbleChildren.length > 0 ? React.createElement("div", { className: "dsh-recall-stack", key: "stack" }, ...bubbleChildren) : null,
876
937
  React.createElement("div", { className: "dsh-recall-actions", key: "actions" }, ...actions),
877
- recallPanel(recall, closePanel, executeRecall)
938
+ recallPanel(recall, closePanel, executeRecall, scope, setScope)
878
939
  );
879
940
  }
880
941
  return { UserRecallNode };
@@ -1322,7 +1383,7 @@
1322
1383
  }
1323
1384
  return result;
1324
1385
  }
1325
- function buildSnapshotManager(React, util, sessionsSvc) {
1386
+ function buildSnapshotManager(React, util, sessionsSvc, workspacesSvc, uiWorkspaceSvc) {
1326
1387
  const { api, clockText: clockText2, sizeText: sizeText2, buildTree: buildTree2 } = util;
1327
1388
  function ManageCard() {
1328
1389
  const [items, setItems] = React.useState(null);
@@ -1481,6 +1542,13 @@
1481
1542
  } catch (e) {
1482
1543
  listById = null;
1483
1544
  }
1545
+ let archivedIds = null;
1546
+ try {
1547
+ const snapshot = workspacesSvc && workspacesSvc.list && typeof workspacesSvc.list.getSnapshot === "function" ? workspacesSvc.list.getSnapshot() : null;
1548
+ archivedIds = new Set(snapshot && snapshot.archivedSessionIds || []);
1549
+ } catch (e) {
1550
+ archivedIds = null;
1551
+ }
1484
1552
  function confirmDelete(kind, key, extra, text) {
1485
1553
  setConfirming({ kind, key, extra, text });
1486
1554
  }
@@ -1528,7 +1596,7 @@
1528
1596
  const open = expanded.has(key);
1529
1597
  const label = s.title || (titlesPending && s.sessionId ? "\u2026" : "\uFF08\u5DF2\u5220\u9664\u4F1A\u8BDD\uFF09");
1530
1598
  const version = s.sessionId ? versionMap.get(String(s.sessionId)) : null;
1531
- const switchable = Boolean(s.sessionId && listById && listById[s.sessionId]);
1599
+ const switchable = Boolean(s.sessionId && listById && listById[s.sessionId] && !(archivedIds && archivedIds.has(String(s.sessionId))));
1532
1600
  return React.createElement(
1533
1601
  "div",
1534
1602
  { className: "dsh-recall-tree-node", key },
@@ -1557,7 +1625,8 @@
1557
1625
  title: "\u5207\u6362\u5230\u8BE5\u7248\u672C\u4F1A\u8BDD",
1558
1626
  onClick: () => {
1559
1627
  try {
1560
- sessionsSvc.open(s.sessionId);
1628
+ if (uiWorkspaceSvc && typeof uiWorkspaceSvc.openSession === "function") uiWorkspaceSvc.openSession(s.sessionId);
1629
+ else if (typeof sessionsSvc.open === "function") sessionsSvc.open(s.sessionId);
1561
1630
  } catch (e) {
1562
1631
  }
1563
1632
  }
@@ -1709,7 +1778,7 @@
1709
1778
  }
1710
1779
 
1711
1780
  // src/client/settings-cards.ts
1712
- function buildSettingsCards(React, util, sessionsSvc) {
1781
+ function buildSettingsCards(React, util, sessionsSvc, workspacesSvc, uiWorkspaceSvc) {
1713
1782
  function SectionToggle(props) {
1714
1783
  return React.createElement(
1715
1784
  "button",
@@ -1728,7 +1797,7 @@
1728
1797
  }
1729
1798
  const { ConfigForm } = buildConfigForm(React, util, SectionToggle);
1730
1799
  const { ExcludeFilesSection } = buildExcludeCards(React, util);
1731
- const { ManageCard } = buildSnapshotManager(React, util, sessionsSvc);
1800
+ const { ManageCard } = buildSnapshotManager(React, util, sessionsSvc, workspacesSvc, uiWorkspaceSvc);
1732
1801
  function RecallSettingsCard() {
1733
1802
  const [open, setOpen] = React.useState(false);
1734
1803
  const [sections, setSections] = React.useState({ exclude: false, manage: false });
@@ -1801,8 +1870,9 @@
1801
1870
  document.head.appendChild(tag);
1802
1871
  }
1803
1872
  const util = buildUtil();
1804
- const { UserRecallNode } = buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc);
1805
- const { RecallSettingsCard } = buildSettingsCards(React, util, sessionsSvc);
1873
+ const uiWorkspaceSvc = ctx.uiWorkspace;
1874
+ const { UserRecallNode } = buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc, uiWorkspaceSvc);
1875
+ const { RecallSettingsCard } = buildSettingsCards(React, util, sessionsSvc, workspacesSvc, uiWorkspaceSvc);
1806
1876
  for (const slotKey of ["user", "steering"]) {
1807
1877
  try {
1808
1878
  slots.inject("conversation.chat.node", () => {
@@ -1824,6 +1894,14 @@
1824
1894
  } catch (error) {
1825
1895
  console.error("[dsh-recall-plugin] settings card register failed:", error);
1826
1896
  }
1897
+ try {
1898
+ slots.inject("plugins.bundle.config", () => slots.register(
1899
+ { name: "plugins.bundle.config", key: "dsh-recall-plugin" },
1900
+ RecallSettingsCard
1901
+ ));
1902
+ } catch (error) {
1903
+ console.error("[dsh-recall-plugin] plugin manager config register failed:", error);
1904
+ }
1827
1905
  };
1828
1906
  }
1829
1907
 
@@ -1834,7 +1912,12 @@
1834
1912
  const React = require2("react");
1835
1913
  return {
1836
1914
  name: "dsh-recall-plugin",
1837
- inject: ["slots", "sessions", "workspaces", "timer"],
1915
+ // uiWorkspace(ui-workspace UiWorkspace):0.1.6-alpha.2 起 ISessions
1916
+ // 移除 open,会话导航(fork 后打开子会话)移交其 openSession——0.1.2-alpha.1
1917
+ // 起该服务即存在,声明安全;0.1.1-rc.2 无此服务(同线亦无 sessions/
1918
+ // workspaces),声明会令 fiber pending——该线段已从 peer 范围移除
1919
+ // (见 compat-audit I37「服务可用性」)。
1920
+ inject: ["slots", "sessions", "workspaces", "uiWorkspace", "timer"],
1838
1921
  apply: createApp(React)
1839
1922
  };
1840
1923
  }
@@ -44,6 +44,15 @@ function createRoutesCore(deps) {
44
44
  "execute": async (args) => {
45
45
  const id = args && args.messageId ? String(args.messageId) : "";
46
46
  const sessionId = args && args.sessionId ? String(args.sessionId) : null;
47
+ const scope = args && args.scope === "session-only" ? "session-only" : "both";
48
+ if (scope === "session-only") {
49
+ const snap = state.snapshots.get(id);
50
+ if (!snap) return { ok: false, code: E.RECALL_NO_SNAPSHOT, message: "\u8BE5\u6D88\u606F\u6CA1\u6709\u53EF\u7528\u7684\u9879\u76EE\u5FEB\u7167" };
51
+ if (agentBusy(sessionId, snap.root)) return { ok: false, code: E.RECALL_AGENT_BUSY, message: "Agent \u6B63\u5728\u8FD0\u884C\u4E2D\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u64A4\u56DE" };
52
+ const cutSeq2 = await snaps.resolveCutSeq(sessionId, id);
53
+ const staleQueueItemIds2 = await snaps.resolveStaleQueueItemIds(sessionId, cutSeq2);
54
+ return { ok: true, count: 0, cutSeq: cutSeq2, staleQueueItemIds: staleQueueItemIds2 };
55
+ }
47
56
  const result = await enqueue(async () => {
48
57
  const snap = state.snapshots.get(id);
49
58
  if (!snap) return { ok: false, code: E.RECALL_NO_SNAPSHOT, message: "\u8BE5\u6D88\u606F\u6CA1\u6709\u53EF\u7528\u7684\u9879\u76EE\u5FEB\u7167" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-recall-plugin",
3
- "version": "2.3.22",
3
+ "version": "2.3.24",
4
4
  "description": "在 DSH 中撤回自己发过的消息:工作区文件与对话历史一起回到那条消息发出之前,消息的文本与附件自动放回输入框,改完即可重发。文件走独立影子 git 快照(不碰项目自身的 git),对话走官方 sessions.fork,原会话归档可找回。",
5
5
  "type": "module",
6
6
  "repository": {
@@ -57,18 +57,19 @@
57
57
  "0.1.5-alpha.2": "compatible",
58
58
  "0.1.5-rc.1": "compatible",
59
59
  "0.1.5-rc.2": "compatible",
60
- "0.1.6-alpha.1": "compatible"
60
+ "0.1.6-alpha.1": "compatible",
61
+ "0.1.6-alpha.2": "compatible"
61
62
  }
62
63
  }
63
64
  },
64
65
  "peerDependencies": {
65
66
  "@deepseek-ai/cordis": "^4.0.1",
66
- "@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
67
- "@deepseek-ai/dsh-sandbox-policy": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
68
- "@deepseek-ai/dsh-session": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
69
- "@deepseek-ai/dsh-session-query": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
70
- "@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
71
- "@deepseek-ai/dsh-shell": ">=0.1.1-rc.2 <0.1.2 || >=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
67
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
68
+ "@deepseek-ai/dsh-sandbox-policy": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
69
+ "@deepseek-ai/dsh-session": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
70
+ "@deepseek-ai/dsh-session-query": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
71
+ "@deepseek-ai/dsh-settings": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
72
+ "@deepseek-ai/dsh-shell": ">=0.1.2-alpha.1 <0.1.3 || >=0.1.3-alpha.1 <0.1.4 || >=0.1.5-alpha.1 <0.1.6 || >=0.1.6-alpha.1 <0.1.7",
72
73
  "@deepseek-ai/schemastery": "^3.18.1",
73
74
  "react": "^18.2.0"
74
75
  },