dsh-pause-session 0.0.0-stage → 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.
Files changed (49) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/DEVELOPMENT.md +78 -0
  3. package/LICENSE +21 -0
  4. package/README.md +140 -2
  5. package/README.zh.md +101 -0
  6. package/REHEARSAL.md +90 -0
  7. package/cordis.patch.yml +3 -0
  8. package/docs/images/pause-controls.webp +0 -0
  9. package/icon.svg +5 -0
  10. package/lib/client.js +2024 -0
  11. package/lib/client.js.map +1 -0
  12. package/lib/index.js +2996 -0
  13. package/lib/index.js.map +1 -0
  14. package/lib/typert.host.d.ts +3 -0
  15. package/lib/typert.host.js +339 -0
  16. package/lib/typert.remote-client.d.ts +38 -0
  17. package/lib/typert.remote-client.d.ts.map +1 -0
  18. package/lib/typert.remote-client.js +244 -0
  19. package/lib/types/client/control.d.ts +99 -0
  20. package/lib/types/client/global.d.ts +125 -0
  21. package/lib/types/client/icons.d.ts +24 -0
  22. package/lib/types/client/index.d.ts +78 -0
  23. package/lib/types/client/locales.d.ts +67 -0
  24. package/lib/types/client/pill.d.ts +49 -0
  25. package/lib/types/client/remote.d.ts +71 -0
  26. package/lib/types/client/view.d.ts +151 -0
  27. package/lib/types/coldlog.d.ts +111 -0
  28. package/lib/types/composition.d.ts +94 -0
  29. package/lib/types/control.d.ts +95 -0
  30. package/lib/types/gate.d.ts +110 -0
  31. package/lib/types/global.d.ts +103 -0
  32. package/lib/types/history.d.ts +47 -0
  33. package/lib/types/index.d.ts +64 -0
  34. package/lib/types/park-state.d.ts +51 -0
  35. package/lib/types/park.d.ts +50 -0
  36. package/lib/types/registry.d.ts +117 -0
  37. package/lib/types/release-order.d.ts +21 -0
  38. package/lib/types/remote-adapter.d.ts +22 -0
  39. package/lib/types/remote.d.ts +158 -0
  40. package/lib/types/resume-activation.d.ts +27 -0
  41. package/lib/types/resume-text.d.ts +67 -0
  42. package/lib/types/resume.d.ts +126 -0
  43. package/lib/types/shared.d.ts +221 -0
  44. package/lib/types/snapshot.d.ts +29 -0
  45. package/lib/types/tree.d.ts +71 -0
  46. package/lib/types/triage.d.ts +120 -0
  47. package/locale/en.json +6 -0
  48. package/locale/zh.json +6 -0
  49. package/package.json +166 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,79 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project uses [Semantic Versioning](https://semver.org/).
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
+
45
+ ## [0.1.0] - 2026-11-02
46
+
47
+ ### Added
48
+
49
+ - Pause every running DSH session and its subagents at the next model-request
50
+ boundary, after the tool already running finishes.
51
+ - Session-header and whole-app controls, with `Pausing`, `Paused`, and
52
+ `All Paused` states.
53
+ - Durable pause registry that re-holds parked sessions after a DSH restart.
54
+ - Clean resume that restores the recorded Agent preset composition, including
55
+ subagent delegation context and tool restrictions.
56
+ - Goal re-arm toggle for cleanly paused sessions.
57
+ - Decision list for sessions that did not pause cleanly, with continue,
58
+ continue-with-note, review-only, leave, and goal actions.
59
+ - Localized English and Chinese UI copy, plugin-manager metadata, and a
60
+ user-facing README screenshot.
61
+ - `/pause`, `/pause-resume`, `/pause-all`, `/pause-state`, `/pause-goal`, and
62
+ `/pause-triage*` command surface.
63
+
64
+ ### Changed
65
+
66
+ - The package is published as `dsh-pause-session`; the slash-command namespace
67
+ remains `/pause*`.
68
+ - One-shot and external subagent routes are reported as unresumable and are not
69
+ registered as local pause records.
70
+
71
+ ### Known Limitations
72
+
73
+ - Background jobs and shell tasks outside the agent loop are not stopped.
74
+ - A paused session still appears `running` to parts of DSH's session lifecycle;
75
+ exit, archive, compaction, and `wait_agent` can behave differently while held.
76
+ - External one-shot subagent routes cannot be cold-resumed.
77
+
78
+ [0.2.0]: https://github.com/timho1047/dsh-pause-session/releases/tag/v0.2.0
79
+ [0.1.0]: https://github.com/timho1047/dsh-pause-session/releases/tag/v0.1.0
package/DEVELOPMENT.md ADDED
@@ -0,0 +1,78 @@
1
+ # Development
2
+
3
+ This is a personal DSH plugin repository. `dsh-plugins/` is not part of the
4
+ official DSH source tree; it is only the author's local layout.
5
+
6
+ ## Layout
7
+
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.
13
+ - `src/client/` — Web client TypeScript/React: the session control, global
14
+ control, state mapping, and locale dictionaries.
15
+ - `lib/` — committed build output. Run `pnpm run build` to refresh it before a
16
+ release commit.
17
+ - `.scratch/pause-session/` — local-only design record (ignored by Git).
18
+ - `REHEARSAL.md` — the manual end-to-end acceptance run.
19
+
20
+ ## DSH dependency links
21
+
22
+ The development dependencies in [package.json](package.json) point at a
23
+ DeepSeek Harness checkout through `link:../../deepseek-harness/...`. Local
24
+ typecheck, build, and tests expect that checkout to be present at the same
25
+ relative depth.
26
+
27
+ The published npm packages currently lag the APIs this plugin uses
28
+ (`0.2.2-alpha.2`), so replacing these links with registry versions would break
29
+ the build. A fresh clone can run `pnpm pack` (the release path does not install
30
+ dependencies), but cannot run the full verification suite without the harness
31
+ checkout.
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
+
53
+ ## Build and test
54
+
55
+ ```sh
56
+ pnpm install
57
+ pnpm run verify # typecheck + build + tests
58
+ pnpm run build # tsc for both faces, then tsdown
59
+ ```
60
+
61
+ The host half builds to `lib/index.js`; the client half builds to
62
+ `lib/client.js`, the browser module bundle loaded under the `dsh-pause-session` id.
63
+ `tsdown.client.ts` is the vendored client-bundle preset shared by the plugins
64
+ in this directory.
65
+
66
+ ## Design record
67
+
68
+ The specification and task breakdown live under `.scratch/pause-session/`, local-only
69
+ by this directory's convention. The load-bearing findings behind the design —
70
+ where a pause can land, what a pause costs the surrounding app, and what a
71
+ restart does to a paused session — are recorded in the spec's evidence section.
72
+ Read it before changing the pause or resume path.
73
+
74
+ ## Manual acceptance
75
+
76
+ [REHEARSAL.md](REHEARSAL.md) is the end-to-end acceptance run: precedence for
77
+ what the automated suite already proves, how to install, the steps to walk, and
78
+ the rollback if a profile will not start.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tim HO
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,141 @@
1
- # Temporary Holding Version
1
+ # dsh-pause-session
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ English | [中文](README.zh.md)
4
+
5
+ <p align="center"><img src="icon.svg" width="64" height="64" alt="dsh-pause-session icon"></p>
6
+
7
+ [npm: dsh-pause-session](https://www.npmjs.com/package/dsh-pause-session)
8
+
9
+ Pause every running DSH session and its subagents before you leave, then resume
10
+ them later.
11
+
12
+ dsh-pause-session stops each session at the same point: the tool call that is already
13
+ running finishes, then the next model request is held. Subagent trees are
14
+ included, and the pause survives a DSH restart.
15
+
16
+ > Status: beta. Tested against DSH `0.2.2-alpha.2`; the end-to-end rehearsal is
17
+ > tracked in [REHEARSAL.md](REHEARSAL.md).
18
+
19
+ <p align="center">
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%">
21
+ </p>
22
+
23
+ *The session is paused; the global pill shows Paused (1/1).*
24
+
25
+ ## Quick start
26
+
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).
49
+ 2. Open the session you want to pause. Press the pause button beside its title
50
+ to pause that session and its subagents, or press the pill on the right side
51
+ of the header to pause every running session tree.
52
+ 3. The control shows **Pausing** until the running tools finish and the next
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.
60
+
61
+ ## The two controls
62
+
63
+ | Control | Scope | What it does |
64
+ |---|---|---|
65
+ | Session header button | One session and its subagents | Pauses the current session tree, then resumes the same tree. |
66
+ | Global pill | All running session trees | Pauses every registered session, then resumes every cleanly paused session. |
67
+
68
+ A session with an unfinished tool is shown as **Pausing**. It moves to
69
+ **Paused** only after the tool returns, the next model request is held, and the
70
+ session state is saved.
71
+
72
+ ## What pause actually does
73
+
74
+ - A tool call already running is allowed to finish. No new tool call or model
75
+ request is sent after the pause is taken.
76
+ - The next model request is held before it reaches the provider.
77
+ - Subagents already under the paused tree are stopped with the same rules.
78
+ - The pause state is durable. If DSH exits or restarts, the sessions are held
79
+ again on the next mount.
80
+ - The composer stays usable; the pause is released by the same control, not by
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.
85
+
86
+ ## What is not stopped
87
+
88
+ - Background jobs and shell tasks outside the agent loop are not stopped. The
89
+ global control names them as a caveat.
90
+ - External one-shot subagent routes, such as Codex, Claude Code, ACP, and DSH
91
+ SDK executions, cannot accept another turn or be cold-resumed. They are
92
+ reported as unresumable and are not registered as paused local sessions.
93
+ - A paused session still looks `running` to parts of DSH's session lifecycle.
94
+ Exit may take about five seconds; archiving, context compaction, and
95
+ `wait_agent` can behave differently while a session is held.
96
+
97
+ ## Resume and goals
98
+
99
+ Cleanly paused sessions resume from the point where they stopped. A session
100
+ goal is re-opened by default, which means it can continue running rounds and
101
+ spending money on its own. Before leaving, turn off the goal switch on the
102
+ session control if you do not want that. The setting is recorded in the pause
103
+ record and applies when that session is resumed.
104
+
105
+ Sessions that did not stop cleanly are never resumed silently. The global
106
+ control opens a decision list where each row can be continued, continued with a
107
+ note that the tool result is unknown, opened for review without running, or
108
+ left paused.
109
+
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.
115
+
116
+ ## Requirements
117
+
118
+ - DSH `>=0.2.2-alpha.2 <0.3.0-0`. The package declares this as `engines.dsh`;
119
+ the Plugin Manager refuses an older runtime instead of starting an
120
+ incompatible resume path.
121
+ - The standard Web profile. It mounts `sessionQuery` and `agentPresets`, which
122
+ the resume path uses to rebuild each session's scoped Agent composition.
123
+ - Building from this repository requires the local development layout described
124
+ in [DEVELOPMENT.md](DEVELOPMENT.md).
125
+
126
+ The plugin makes no network calls. Pause records live in the profile's storage
127
+ and session state stays in the existing session logs.
128
+
129
+ ## Development
130
+
131
+ See [DEVELOPMENT.md](DEVELOPMENT.md) for the workspace layout, build commands,
132
+ test suite, and the local DeepSeek Harness dependency links. The end-to-end
133
+ manual acceptance run lives in [REHEARSAL.md](REHEARSAL.md).
134
+
135
+ ## Changelog
136
+
137
+ See [CHANGELOG.md](CHANGELOG.md) for release notes.
138
+
139
+ ## License
140
+
141
+ MIT. See [LICENSE](LICENSE).
package/README.zh.md ADDED
@@ -0,0 +1,101 @@
1
+ # dsh-pause-session
2
+
3
+ [English](README.md) | 中文
4
+
5
+ <p align="center"><img src="icon.svg" width="64" height="64" alt="dsh-pause-session 图标"></p>
6
+
7
+ [npm: dsh-pause-session](https://www.npmjs.com/package/dsh-pause-session)
8
+
9
+ 在离开前暂停所有运行中的 DSH 会话及其子代理,之后再恢复。
10
+
11
+ dsh-pause-session 会把每个会话停在同一个点:当前已经运行的工具先跑完,然后拦住下一条模型请求。子代理树也会一起暂停,暂停状态可以跨 DSH 重启保留。
12
+
13
+ > 状态:beta。已针对 DSH `0.2.2-alpha.2` 验证;完整的实机演练见 [REHEARSAL.md](REHEARSAL.md)。
14
+
15
+ <p align="center">
16
+ <img src="docs/images/pause-controls.webp" alt="dsh-pause-session 控件:会话已暂停,全局显示已暂停" width="100%">
17
+ </p>
18
+
19
+ *会话已暂停;全局控件显示“已暂停”(1/1)。*
20
+
21
+ ## 快速开始
22
+
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)。
45
+ 2. 打开要暂停的会话。按标题旁的暂停按钮,会暂停这个会话及其子代理;按头部右侧的胶囊,会暂停所有运行中的会话树。
46
+ 3. 控件会先显示 **正在暂停**(Pausing),等运行中的工具结束、下一条模型请求被拦住后,才会变成 **已暂停**(Paused)。全局胶囊变成 **已暂停**(Paused)时,所有已登记的会话都已停住,待处理输入也已落盘。
47
+ 4. 下次按 **已暂停** 可以恢复所有干净暂停的会话;按会话旁的控制可以只恢复这一个会话及其子代理。暂停尚未完成时,胶囊会点名正在排空的会话和工具,并提供 **取消这次暂停**。
48
+
49
+ ## 两个控件
50
+
51
+ | 控件 | 范围 | 作用 |
52
+ |---|---|---|
53
+ | 会话标题旁 | 一个会话及其子代理 | 暂停当前会话树,之后恢复同一个会话树。 |
54
+ | 头部右侧胶囊 | 所有运行中的会话树 | 暂停所有已登记会话,之后恢复所有干净暂停的会话。 |
55
+
56
+ 有工具在运行时,会话显示 **正在暂停**。只有工具返回、下一条模型请求被拦住并且会话状态已保存后,才会进入 **已暂停**。
57
+
58
+ ## 暂停具体做了什么
59
+
60
+ - 已经在运行的工具会先跑完;暂停生效后不会再发新的工具调用或模型请求。
61
+ - 下一条模型请求会在到达供应商之前被拦住。
62
+ - 已经登记在暂停树里的子代理会按同样规则停下。
63
+ - 暂停状态是持久化的。DSH 退出或重启后,下次挂载会重新拦住这些会话。
64
+ - 输入框保持可用;暂停要通过同一个控件释放,而不是靠再发一条消息。
65
+ - 两个控件在 Web 和 Desktop 上都使用原生 Remote 流。插件不注册任何斜杠命令,后台状态刷新不会向会话追加命令记录。
66
+
67
+ ## 哪些东西不会被停住
68
+
69
+ - agent loop 之外的后台任务和 shell 任务不会被停住;全局控件会把它们列为限制。
70
+ - Codex、Claude Code、ACP、DSH SDK 等外部一次性子代理不能继续下一轮,也不能冷恢复。它们会被报告为不可恢复,不会登记成本地暂停会话。
71
+ - 暂停中的会话在 DSH 的部分生命周期里仍显示为 `running`。退出 DSH 可能需要约 5 秒;归档、上下文压缩和 `wait_agent` 在会话被拦住时的行为可能不同。
72
+
73
+ ## 恢复与目标
74
+
75
+ 干净暂停的会话会从停下的位置恢复。会话目标默认会在恢复时重新打开,这意味着它可以自己继续跑轮次并产生消耗。离开前如果不想这样,可以在会话控件上关掉目标开关。这个设置会写进暂停记录,在该会话恢复时生效。
76
+
77
+ 没有干净暂停的会话不会被静默恢复。全局控件会打开决策清单,每一行可以继续、带说明继续(说明工具结果未知)、只看不运行,或保持暂停。
78
+
79
+ ## 只用控件
80
+
81
+ 插件不注册任何斜杠命令。暂停、恢复、goal 开关和决策清单全部由会话头部控件驱动;Web 和 Desktop 使用同一个原生 Remote 命名空间。
82
+
83
+ ## 要求
84
+
85
+ - DSH `>=0.2.2-alpha.2 <0.3.0-0`。包通过 `engines.dsh` 声明该范围;插件管理器会拒绝旧版本运行时,而不是启动不兼容的恢复路径。
86
+ - 标准 Web profile。它会挂载 `sessionQuery` 和 `agentPresets`,恢复路径用它们重建每个会话原本的 Agent 组合。
87
+ - 如果从本仓库构建,还需要满足 [DEVELOPMENT.md](DEVELOPMENT.md) 里的本地开发布局。
88
+
89
+ 插件不发起网络请求。暂停记录保存在 profile 的存储中,会话状态仍保存在原有会话日志里。
90
+
91
+ ## 开发
92
+
93
+ 工作区布局、构建命令、测试和本地 DeepSeek Harness 依赖链接见 [DEVELOPMENT.md](DEVELOPMENT.md)。完整的人工验收流程见 [REHEARSAL.md](REHEARSAL.md)。
94
+
95
+ ## 更新记录
96
+
97
+ 发布记录见 [CHANGELOG.md](CHANGELOG.md)。
98
+
99
+ ## 许可证
100
+
101
+ MIT,见 [LICENSE](LICENSE)。
package/REHEARSAL.md ADDED
@@ -0,0 +1,90 @@
1
+ # 演练:下班 → 过夜 → 上班
2
+
3
+ 这份文档是给**人**照着走的验收流程。代码侧的自动化测试已经覆盖了接缝;这里要证明的是真实机器上的那一整套动作。
4
+
5
+ ## 一、它要证明什么
6
+
7
+ 1. 按下暂停后,会话**停在下一条模型请求之前**,而不是停在工具中途。
8
+ 2. 界面能如实回答"现在都暂停了吗",并且点名它兑现不了的承诺。
9
+ 3. 进程重启后暂停仍然成立;第二天一次恢复,会话从同一点继续,**模型上下文没有多出任何东西**。
10
+ 4. 未完全暂停的会话不会被静默唤醒,而是进清单交给你决定。
11
+
12
+ ## 二、已经做完的预检(无需重做)
13
+
14
+ | 检查 | 结果 |
15
+ |---|---|
16
+ | 全量测试(typecheck + build + 全部用例) | 通过 |
17
+ | 真实 Loader 组合:挂上插件真正 inject 的那几行 | 该行 `active`;裸组合里它停在 `pending`(如实断言) |
18
+ | 一次性 profile + 绝对路径覆盖层冷启动 | **启动成功**,任务正常完成(退出码 0) |
19
+ | 反向对照:给非法 `config` | **大声失败并点名插件与字段**,证明这一行真的被加载 |
20
+ | 插件行加载失败会不会拦住启动 | **不会**——非 `required` 行只产生 `warning: 1 entry did not activate` |
21
+
22
+ > 那次隔离验证建了一个一次性 profile `~/.dsh/profiles/<isolated-profile>`,与你的日常 profile 无关。
23
+
24
+ ## 三、安装(目标:`web` profile)
25
+
26
+ 选 `web` 的理由:它当前运行 `0.2.2-alpha.2`,与插件构建和验证所依据的版本一致。其他 profile 的版本可能不同,安装前先确认版本。
27
+
28
+ 1. 打开 Web 界面 → 侧边栏 **Plugins** 页面。
29
+ 2. 安装本目录(`<repository>`),或让会话里的 `plugin_manager` 执行 `install_bundle`。
30
+ 3. 安装结果里确认 `application: applied` 且 `warnings` 为空。
31
+
32
+ **出问题的回滚**(照抄,别临场想):
33
+
34
+ - 插件行失败:**启动不会被拦住**,只会有一条 `warning: 1 entry did not activate`;在 Plugins 页面关掉它即可。
35
+ - 整个应用起不来:用市场那个脱离宿主的恢复界面取消勾选本插件;或 `dsh plugin --profile web remove dsh-pause-session`,再把 `dsh-pause-session` 从该 profile `package.json` 的 `dsh.profile.bundles` 里删掉。
36
+
37
+ ## 四、演练 A:干净的下班 → 上班
38
+
39
+ **先分清两颗按钮**(它们都是图标芯片,靠悬停文案区分):
40
+
41
+ | 按钮 | 位置 | 作用范围 |
42
+ |---|---|---|
43
+ | **会话那颗** | 会话标题旁 | **这个会话 + 它属下的全部子代理(含嵌套)** |
44
+ | **胶囊** | 会话头部右侧的 utilities 行 | **所有**正在运行的会话树 |
45
+
46
+ 会话那颗只在**主会话**上出现——子代理会话上没有它(你不需要单独暂停子代理)。按下去的回答会报出登记了几个成员。再按一次的含义取决于状态:树里**还没有任何干净记录**时它是**取消**(把这次暂停收回来);树里已经有停稳的成员时它是**释放**(父先子后,不干净的成员留在清单上)。
47
+
48
+ 用一个**无关紧要的会话**(不要用你正在干活的会话):
49
+
50
+ 1. 让它跑一个会占住工具的动作,例如 `sleep 60`。
51
+ 2. 找到会话头部右侧的胶囊并按下。
52
+ - **期望**:胶囊显示"正在暂停",点名正在排空的会话和工具,并提供一个"取消这次暂停"的动作;此刻它还不会说安全。
53
+ 3. 等它变成"已暂停"。
54
+ - **期望**:只有在工具返回、请求停住、并且会话状态已保存之后才变色。
55
+ - **反例**:工具还在跑或 flush 未完成就显示“已暂停” → 失败。
56
+ 4. 确认会话**停在下一条请求之前**:它不应再出现新的模型输出;界面显示已暂停。
57
+ 5. 如果这个会话带着目标:在它的标题栏控件上把**目标开关关掉**("恢复这个会话时不会自己重新启动它的目标")。
58
+ - **期望**:开关状态来自宿主,按一下之后会被重新读取,而不是本地翻转。
59
+ 6. 直接退出 DSH(或强杀),重启。
60
+ - **期望**:重启后该会话仍是暂停状态,头部胶囊仍显示全局暂停状态。
61
+ 7. 按恢复(头部胶囊)。
62
+ - **期望**:会话从停下的那点继续,模型回应的是暂停时那条待发输入;**上下文里没有"你被打断过"之类的新内容**。
63
+ - **期望(目标)**:第 5 步关掉开关的那些会话,恢复后**目标保持不启动**、不产生新的轮次;没关的照常推进。
64
+ - **前提**:早上的组合必须提供与昨天相同的工具集,否则 DSH 自己会补工具增减的系统消息,"线上零新增"的肉眼结论会失真。
65
+
66
+ ## 五、演练 B:未完全暂停的早晨
67
+
68
+ 1. 再起一个会话,让它跑一个长工具(`sleep 300`)。
69
+ 2. **不按停止**,直接强杀 DSH(`kill -9`)。
70
+ - 这一格模拟"合盖/被杀",也就是没有受控停顿的那条路径。
71
+ 3. 重启后打开胶囊里的清单。
72
+ - **期望**:该会话在清单里,显示停在哪个工具、留下了什么痕迹。
73
+ - **可能的真相**:子代理常**根本没有保存的会话日志**,此时清单必须如实显示"读不到",而不是编一行出来。
74
+ 4. 逐行试四个动作:直接继续 / 继续并附说明 / 只看不跑 / 今天先别碰。
75
+ - **期望**:"只看不跑"**保持暂停、不激活 agent、不产生任何模型请求**——它只给你一个答复,现场要你自己去会话历史里看;"继续并附说明"的那条请求里带着"结果未知、不要盲目重试"的说明。
76
+
77
+ ## 六、已知代价与限制(不是 bug)
78
+
79
+ - 暂停中的会话在核心看来仍是 running:退出 DSH 会约 5 秒后被强退(所以停止前必须 flush);归档会报错或不等结算;压缩会以"已有工作"报错;等待该会话的 RPC 会挂住客户端;`wait_agent` 会白等到上限。
80
+ - 插件不注册斜杠命令。暂停、恢复、goal 和决策清单都由头部控件通过原生 Remote 触发;状态读取走 Remote 流,不写入 `command/run`/`command/done`。
81
+ - 对一个已经暂停的会话再按一次暂停**不会**产生新的停稳判定;要新判定必须先恢复、跑出新的工作周期、再停一次。
82
+ - 时间上下文冻结在暂停时刻("仿佛没中断"的字面含义)。
83
+ - 一次性子代理路由(`subagent_codex` / `subagent_claude_code` 之类桥接)的工作跨重启无法续跑,只会被点名。
84
+ - 后台 shell 任务不在 agent loop 内,插件停不住,只会被点名。
85
+
86
+ ## 七、还没被验证的地方(说清楚,不含糊)
87
+
88
+ - 胶囊的完整视觉验收尚未做;本地 Web 页面已确认控件渲染、状态可读,并已在插件页看到 `Pause` 的标题与描述。
89
+ - 唤醒在真实模型上的效果:空唤醒是否被服务商接受、兜底那条极简标记会不会诱发模型重述。
90
+ - 真实整机重启(本次只做了隔离 profile 的冷启动 + 自动化重启用例)。
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: dsh-pause-session
3
+ name: dsh-pause-session
Binary file
package/icon.svg ADDED
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Pause">
2
+ <rect x="4" y="4" width="56" height="56" rx="14" fill="#111827"/>
3
+ <rect x="20" y="18" width="9" height="28" rx="3" fill="#F5C451"/>
4
+ <rect x="35" y="18" width="9" height="28" rx="3" fill="#F5C451"/>
5
+ </svg>