dsh-pause-session 0.1.0 → 0.2.0

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
@@ -5,6 +5,43 @@ All notable changes to this project are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project uses [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.2.0] - 2026-11-06
9
+
10
+ ### Changed
11
+
12
+ - Both controls now use a native DSH Remote namespace and stream. The plugin
13
+ registers no slash commands, so a status refresh never appends
14
+ `command/run`/`command/done` records to a Session.
15
+ - Pause, resume, goal, and decision-list actions travel through the same
16
+ native namespace on Web and Desktop.
17
+
18
+ ### Added
19
+
20
+ - Global progress names every draining session and its running tools, and the
21
+ in-progress action is **Cancel this pause**.
22
+ - The Remote namespace is owner-only.
23
+ - The client bundle uses a build-time codec-builder shim instead of bundling the full Zod runtime.
24
+ - One snapshot is shared by every connected Remote observer, and the snapshot projection shares its tree walks.
25
+ - The park episode machine, snapshot projection, release ordering, and resume copy now live in separate modules; `control.ts` is composition only.
26
+ - State-changing Remote actions are recorded with a structured host log entry and the caller principal.
27
+
28
+ ### Fixed
29
+
30
+ - A park reaches `safe` only when the session-level flush actually ran; an
31
+ unreadable record and a partially unread tree are reported instead of being
32
+ counted clean.
33
+ - A restart-adopted park is no longer cancelled by the per-session button; it
34
+ stays on the decision path.
35
+ - Stream and triage failures render as unavailable instead of stale rows, and
36
+ triage decisions that the host refuses show the refusal.
37
+
38
+ ### Removed
39
+
40
+ - The `/pause`, `/pause-resume`, `/pause-state`, `/pause-goal`, and
41
+ `/pause-triage*` command surface.
42
+ - The command-era `ReadBurst`/JSON-status-route client machinery and the
43
+ `@deepseek-ai/dsh-commands` dependency.
44
+
8
45
  ## [0.1.0] - 2026-11-02
9
46
 
10
47
  ### Added
@@ -38,4 +75,5 @@ and this project uses [Semantic Versioning](https://semver.org/).
38
75
  exit, archive, compaction, and `wait_agent` can behave differently while held.
39
76
  - External one-shot subagent routes cannot be cold-resumed.
40
77
 
78
+ [0.2.0]: https://github.com/timho1047/dsh-pause-session/releases/tag/v0.2.0
41
79
  [0.1.0]: https://github.com/timho1047/dsh-pause-session/releases/tag/v0.1.0
package/DEVELOPMENT.md CHANGED
@@ -5,8 +5,11 @@ official DSH source tree; it is only the author's local layout.
5
5
 
6
6
  ## Layout
7
7
 
8
- - `src/` — host-half TypeScript: pause gate, park registry, resume path,
9
- triage, and host services.
8
+ - `src/` — host-half TypeScript: pause gate, park registry, park-state
9
+ machine, snapshot projection, resume path, triage, and host services.
10
+ `control.ts` is the composition root; `park-state.ts`, `snapshot.ts`,
11
+ `resume.ts`, `resume-text.ts`, and `release-order.ts` own their respective
12
+ change reasons.
10
13
  - `src/client/` — Web client TypeScript/React: the session control, global
11
14
  control, state mapping, and locale dictionaries.
12
15
  - `lib/` — committed build output. Run `pnpm run build` to refresh it before a
@@ -27,6 +30,26 @@ the build. A fresh clone can run `pnpm pack` (the release path does not install
27
30
  dependencies), but cannot run the full verification suite without the harness
28
31
  checkout.
29
32
 
33
+ ## Native Remote transport
34
+
35
+ `src/remote.ts` is the generated Remote surface. Its `observe` stream carries
36
+ status snapshots and its `act` / `triage` / `decide` methods carry every button
37
+ action. The Client mounts the generated contribution (`dsh-pause-session/remote`)
38
+ and consumes the namespace through a child injection; the same Gateway path is
39
+ used on Web and Desktop. No slash command is registered anywhere.
40
+
41
+ The client build aliases the generated contribution's `zod` import to
42
+ `src/client/zod-lite.ts`: the Gateway validates browser-to-host arguments, and
43
+ host results are produced by this plugin, so the browser keeps only the codec
44
+ builder shape. The client bundle stays around 20 KB gzip instead of pulling the
45
+ full codec runtime.
46
+
47
+ `scripts/generate-typert.mjs` builds a temporary Typert workspace containing
48
+ this Remote service and the Harness protocol source, then commits the generated
49
+ `lib/typert.*` artifacts beside the other build output. The release workflow
50
+ never needs a Harness checkout. The tests drive the same native namespace via
51
+ `tests/native-driver.ts`; no command-shaped test compatibility surface remains.
52
+
30
53
  ## Build and test
31
54
 
32
55
  ```sh
package/README.md CHANGED
@@ -4,6 +4,8 @@ English | [中文](README.zh.md)
4
4
 
5
5
  <p align="center"><img src="icon.svg" width="64" height="64" alt="dsh-pause-session icon"></p>
6
6
 
7
+ [npm: dsh-pause-session](https://www.npmjs.com/package/dsh-pause-session)
8
+
7
9
  Pause every running DSH session and its subagents before you leave, then resume
8
10
  them later.
9
11
 
@@ -15,27 +17,46 @@ included, and the pause survives a DSH restart.
15
17
  > tracked in [REHEARSAL.md](REHEARSAL.md).
16
18
 
17
19
  <p align="center">
18
- <img src="docs/images/pause-controls.webp" alt="dsh-pause-session controls showing a paused session and All Paused for the whole app" width="100%">
20
+ <img src="docs/images/pause-controls.webp" alt="dsh-pause-session controls showing a paused session and Paused for the whole app" width="100%">
19
21
  </p>
20
22
 
21
- *The session is paused; the global pill shows All Paused (1/1).*
23
+ *The session is paused; the global pill shows Paused (1/1).*
22
24
 
23
25
  ## Quick start
24
26
 
25
- 1. Open the **Plugins** page in the DSH Web sidebar and install this directory
26
- as a bundle. The repository ships the built `lib/` tree; if you changed the
27
- source, run `pnpm run build` first. From a session in that profile,
28
- `plugin_manager` can do the same with `install_bundle` and the directory's
29
- absolute path. The local development layout is in
30
- [DEVELOPMENT.md](DEVELOPMENT.md).
27
+ 1. Install the plugin for your target:
28
+
29
+ **Desktop** — open the **Plugins** page in the Desktop sidebar and install
30
+ `dsh-pause-session` there.
31
+
32
+ **Web profile, from npm:**
33
+
34
+ ```sh
35
+ dsh plugin --profile web add dsh-pause-session
36
+ ```
37
+
38
+ **Web profile, from source:**
39
+
40
+ ```sh
41
+ git clone https://github.com/timho1047/dsh-pause-session.git
42
+ dsh plugin --profile web add "$PWD/dsh-pause-session"
43
+ ```
44
+
45
+ For either Web installation, restart the DSH Web process once so the running
46
+ process loads the new client bundle. The checkout ships the built `lib/`
47
+ tree, so no separate build is needed; only changed sources require a rebuild.
48
+ The local development layout is in [DEVELOPMENT.md](DEVELOPMENT.md).
31
49
  2. Open the session you want to pause. Press the pause button beside its title
32
50
  to pause that session and its subagents, or press the pill on the right side
33
51
  of the header to pause every running session tree.
34
52
  3. The control shows **Pausing** until the running tools finish and the next
35
- model requests are held. When the global pill shows **All Paused**, every
36
- registered session is stopped.
37
- 4. Next time, press **All Paused** to resume every cleanly paused session, or
38
- press the session button to resume that session and its subagents.
53
+ model requests are held. When the global pill shows **Paused**, every
54
+ registered session is stopped and its pending input is durable.
55
+ 4. Next time, press **Paused** to resume every cleanly paused session, or
56
+ press the session button to resume that session and its subagents. While a
57
+ park is still in progress, the pill names the draining sessions and tools and
58
+ offers **Cancel this pause**. Drag the pill to move it; its position is
59
+ remembered, and the panel offers a reset.
39
60
 
40
61
  ## The two controls
41
62
 
@@ -58,6 +79,9 @@ session state is saved.
58
79
  again on the next mount.
59
80
  - The composer stays usable; the pause is released by the same control, not by
60
81
  sending a message.
82
+ - Both controls use a native Remote stream on Web and Desktop. No slash command
83
+ is registered, so background status refreshes never append command rows to a
84
+ Session.
61
85
 
62
86
  ## What is not stopped
63
87
 
@@ -83,25 +107,11 @@ control opens a decision list where each row can be continued, continued with a
83
107
  note that the tool result is unknown, opened for review without running, or
84
108
  left paused.
85
109
 
86
- ## Commands
87
-
88
- The buttons drive these commands; they are useful for scripts and for
89
- keyboard-first use:
90
-
91
- | Command | Purpose |
92
- |---|---|
93
- | `/pause` | Pause the current session and its subagents. |
94
- | `/pause-resume` | Resume the current paused session tree. |
95
- | `/pause-resume-all` | Resume every paused session that stopped cleanly. |
96
- | `/pause-all` | Pause every running session tree. |
97
- | `/pause-state` | Report the current session tree's pause state. |
98
- | `/pause-state-all` | Report the whole-app pause state. |
99
- | `/pause-goal` | Toggle the current session's goal re-arm on resume. |
100
- | `/pause-triage` | Read the decision list for sessions that did not pause cleanly. |
101
- | `/pause-triage-continue`, `note`, `review`, `leave`, `goal` | Take one decision on a listed session. |
102
-
103
- Status reads are commands too, so they appear as command rows in the session
104
- transcript.
110
+ ## Controls only
111
+
112
+ The plugin registers no slash commands. Pause, resume, the goal switch, and the
113
+ decision list are driven entirely by the header controls. The controls use the
114
+ same native Remote namespace on Web and Desktop.
105
115
 
106
116
  ## Requirements
107
117
 
package/README.zh.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  <p align="center"><img src="icon.svg" width="64" height="64" alt="dsh-pause-session 图标"></p>
6
6
 
7
+ [npm: dsh-pause-session](https://www.npmjs.com/package/dsh-pause-session)
8
+
7
9
  在离开前暂停所有运行中的 DSH 会话及其子代理,之后再恢复。
8
10
 
9
11
  dsh-pause-session 会把每个会话停在同一个点:当前已经运行的工具先跑完,然后拦住下一条模型请求。子代理树也会一起暂停,暂停状态可以跨 DSH 重启保留。
@@ -11,17 +13,38 @@ dsh-pause-session 会把每个会话停在同一个点:当前已经运行的
11
13
  > 状态:beta。已针对 DSH `0.2.2-alpha.2` 验证;完整的实机演练见 [REHEARSAL.md](REHEARSAL.md)。
12
14
 
13
15
  <p align="center">
14
- <img src="docs/images/pause-controls.webp" alt="dsh-pause-session 控件:会话已暂停,全局显示全部已暂停" width="100%">
16
+ <img src="docs/images/pause-controls.webp" alt="dsh-pause-session 控件:会话已暂停,全局显示已暂停" width="100%">
15
17
  </p>
16
18
 
17
- *会话已暂停;全局控件显示“全部已暂停”(1/1)。*
19
+ *会话已暂停;全局控件显示“已暂停”(1/1)。*
18
20
 
19
21
  ## 快速开始
20
22
 
21
- 1. 打开 DSH Web 侧边栏的 **Plugins** 页面,把本目录作为 bundle 安装。仓库里已经提交了构建好的 `lib/`;如果改过源码,先执行 `pnpm run build`。也可以在该 profile 的会话里用 `plugin_manager` 的 `install_bundle`,传入本目录的绝对路径。本地开发布局见 [DEVELOPMENT.md](DEVELOPMENT.md)。
23
+ 1. 按目标选择安装方式:
24
+
25
+ **Desktop**:打开 Desktop 侧边栏的 **Plugins** 页面,在那里安装
26
+ `dsh-pause-session`。
27
+
28
+ **Web profile,从 npm 安装:**
29
+
30
+ ```sh
31
+ dsh plugin --profile web add dsh-pause-session
32
+ ```
33
+
34
+ **Web profile,从源码安装:**
35
+
36
+ ```sh
37
+ git clone https://github.com/timho1047/dsh-pause-session.git
38
+ dsh plugin --profile web add "$PWD/dsh-pause-session"
39
+ ```
40
+
41
+ 两种 Web 安装方式完成后,都重启一次 DSH Web 进程,让运行中的进程加载
42
+ 新的 client bundle。仓库里已经提交了构建好的 `lib/`,不需要额外构建;
43
+ 只有改过源码时才需要重新构建。本地开发布局见
44
+ [DEVELOPMENT.md](DEVELOPMENT.md)。
22
45
  2. 打开要暂停的会话。按标题旁的暂停按钮,会暂停这个会话及其子代理;按头部右侧的胶囊,会暂停所有运行中的会话树。
23
- 3. 控件会先显示 **正在暂停**(Pausing),等运行中的工具结束、下一条模型请求被拦住后,才会变成 **已暂停**(Paused)。全局胶囊变成 **全部已暂停**(All Paused)时,所有已登记的会话都已停住。
24
- 4. 下次按 **全部已暂停** 可以恢复所有干净暂停的会话;按会话旁的控制可以只恢复这一个会话及其子代理。
46
+ 3. 控件会先显示 **正在暂停**(Pausing),等运行中的工具结束、下一条模型请求被拦住后,才会变成 **已暂停**(Paused)。全局胶囊变成 **已暂停**(Paused)时,所有已登记的会话都已停住,待处理输入也已落盘。
47
+ 4. 下次按 **已暂停** 可以恢复所有干净暂停的会话;按会话旁的控制可以只恢复这一个会话及其子代理。暂停尚未完成时,胶囊会点名正在排空的会话和工具,并提供 **取消这次暂停**。
25
48
 
26
49
  ## 两个控件
27
50
 
@@ -39,6 +62,7 @@ dsh-pause-session 会把每个会话停在同一个点:当前已经运行的
39
62
  - 已经登记在暂停树里的子代理会按同样规则停下。
40
63
  - 暂停状态是持久化的。DSH 退出或重启后,下次挂载会重新拦住这些会话。
41
64
  - 输入框保持可用;暂停要通过同一个控件释放,而不是靠再发一条消息。
65
+ - 两个控件在 Web 和 Desktop 上都使用原生 Remote 流。插件不注册任何斜杠命令,后台状态刷新不会向会话追加命令记录。
42
66
 
43
67
  ## 哪些东西不会被停住
44
68
 
@@ -52,23 +76,9 @@ dsh-pause-session 会把每个会话停在同一个点:当前已经运行的
52
76
 
53
77
  没有干净暂停的会话不会被静默恢复。全局控件会打开决策清单,每一行可以继续、带说明继续(说明工具结果未知)、只看不运行,或保持暂停。
54
78
 
55
- ## 命令
56
-
57
- 按钮驱动的就是这些命令;脚本和键盘操作用得上:
58
-
59
- | 命令 | 作用 |
60
- |---|---|
61
- | `/pause` | 暂停当前会话及其子代理。 |
62
- | `/pause-resume` | 恢复当前暂停的会话树。 |
63
- | `/pause-resume-all` | 恢复所有干净暂停的会话。 |
64
- | `/pause-all` | 暂停所有运行中的会话树。 |
65
- | `/pause-state` | 读取当前会话树的暂停状态。 |
66
- | `/pause-state-all` | 读取整体暂停状态。 |
67
- | `/pause-goal` | 切换当前会话恢复时是否重新打开目标。 |
68
- | `/pause-triage` | 读取未干净暂停会话的决策清单。 |
69
- | `/pause-triage-continue`、`note`、`review`、`leave`、`goal` | 对清单中的一个会话执行对应决策。 |
79
+ ## 只用控件
70
80
 
71
- 状态读取本身也是命令,所以会在会话转录里留下命令行。
81
+ 插件不注册任何斜杠命令。暂停、恢复、goal 开关和决策清单全部由会话头部控件驱动;Web 和 Desktop 使用同一个原生 Remote 命名空间。
72
82
 
73
83
  ## 要求
74
84
 
package/REHEARSAL.md CHANGED
@@ -49,16 +49,16 @@
49
49
 
50
50
  1. 让它跑一个会占住工具的动作,例如 `sleep 60`。
51
51
  2. 找到会话头部右侧的胶囊并按下。
52
- - **期望**:胶囊显示"正在暂停"并**点名正在跑的工具**;此刻它还不会说全部已暂停。
53
- 3. 等它变成"全部已暂停"。
52
+ - **期望**:胶囊显示"正在暂停",点名正在排空的会话和工具,并提供一个"取消这次暂停"的动作;此刻它还不会说安全。
53
+ 3. 等它变成"已暂停"。
54
54
  - **期望**:只有在工具返回、请求停住、并且会话状态已保存之后才变色。
55
- - **反例**:工具还在跑就显示“全部已暂停” → 失败。
55
+ - **反例**:工具还在跑或 flush 未完成就显示“已暂停” → 失败。
56
56
  4. 确认会话**停在下一条请求之前**:它不应再出现新的模型输出;界面显示已暂停。
57
57
  5. 如果这个会话带着目标:在它的标题栏控件上把**目标开关关掉**("恢复这个会话时不会自己重新启动它的目标")。
58
58
  - **期望**:开关状态来自宿主,按一下之后会被重新读取,而不是本地翻转。
59
59
  6. 直接退出 DSH(或强杀),重启。
60
- - **期望**:重启后该会话仍是暂停状态;`/pause-state-all` 仍能读到它。
61
- 7. 按恢复(胶囊或 `/pause-resume-all`)。
60
+ - **期望**:重启后该会话仍是暂停状态,头部胶囊仍显示全局暂停状态。
61
+ 7. 按恢复(头部胶囊)。
62
62
  - **期望**:会话从停下的那点继续,模型回应的是暂停时那条待发输入;**上下文里没有"你被打断过"之类的新内容**。
63
63
  - **期望(目标)**:第 5 步关掉开关的那些会话,恢复后**目标保持不启动**、不产生新的轮次;没关的照常推进。
64
64
  - **前提**:早上的组合必须提供与昨天相同的工具集,否则 DSH 自己会补工具增减的系统消息,"线上零新增"的肉眼结论会失真。
@@ -77,7 +77,7 @@
77
77
  ## 六、已知代价与限制(不是 bug)
78
78
 
79
79
  - 暂停中的会话在核心看来仍是 running:退出 DSH 会约 5 秒后被强退(所以停止前必须 flush);归档会报错或不等结算;压缩会以"已有工作"报错;等待该会话的 RPC 会挂住客户端;`wait_agent` 会白等到上限。
80
- - 暂停中的会话会在斜杠命令菜单里多出 `/pause-resume`、`/pause-state`、`/pause-goal`(以及全局的 `/pause-all`、`/pause-state-all`、`/pause-triage*`)——状态通道的形状就是这么来的。**每次读状态都是一次命令执行,因此会在对话里留下一行**(harness 无条件记录并渲染每一次命令执行,没有"不记录"的开关)。读取已改成事件驱动:一次暂停周期个位数次,停稳后不再读;但被暂停会话自己的转录里仍会剩下那么几行,无关会话不会再出现。
80
+ - 插件不注册斜杠命令。暂停、恢复、goal 和决策清单都由头部控件通过原生 Remote 触发;状态读取走 Remote 流,不写入 `command/run`/`command/done`。
81
81
  - 对一个已经暂停的会话再按一次暂停**不会**产生新的停稳判定;要新判定必须先恢复、跑出新的工作周期、再停一次。
82
82
  - 时间上下文冻结在暂停时刻("仿佛没中断"的字面含义)。
83
83
  - 一次性子代理路由(`subagent_codex` / `subagent_claude_code` 之类桥接)的工作跨重启无法续跑,只会被点名。