dsh-session-manager 0.4.4 → 0.4.7

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 ADDED
@@ -0,0 +1,131 @@
1
+ # Changelog
2
+
3
+ ## 0.4.7 — 2026-09-10
4
+
5
+ - **fix(disk scan)**: include `session.v3.jsonl.zstd` in the on-disk
6
+ filename list used by readSessionArtifact() and listSessionHeaders().
7
+ DSH 0.1.5-rc.1's persistence backend writes generation v3 artifacts at
8
+ that filename; the 0.4.6 release scanned only v2/plaintext names, so
9
+ fresh sessions appeared to have no disk record and the move/migrate
10
+ endpoints failed with "会话没有磁盘记录" / "session has no artifact".
11
+
12
+ - **chore**: bump version to 0.4.7.
13
+
14
+
15
+ ## 0.4.6 — 2026-09-05
16
+
17
+ - **fix(persistence)**: read all concatenated Zstandard frames in a session
18
+ artifact. DSH writes one frame for the header and additional frames for
19
+ event batches; reading only the first frame made sessions appear to lose
20
+ their event history after refresh.
21
+ - **fix(move)**: preserve the session generation/header version when
22
+ re-homing an artifact, and synchronize the live session, persistence
23
+ coordinator, registry indexes, and workspace accounting after a move.
24
+ This avoids stale-path `ENOENT` failures and v2/v0 filename/header
25
+ mismatches on the next DSH startup.
26
+ - **fix(preset migration)**: fall back to an id-based artifact scan when a
27
+ persistence locate result points at a stale path, and mirror cold-path
28
+ migrations into the live session projection.
29
+ - **fix(client)**: stop calling the removed/unavailable
30
+ `noteAgentPreset` client method; refresh the session projection instead.
31
+ - **recovery**: add `scripts/heal-v2-sessions.ps1` for the DSH 0.1.1-rc.2
32
+ boot-time quirk where `session.v2.jsonl.zstd` contains a `version: 0`
33
+ header. Run it before starting DSH; this repair must happen before DSH's
34
+ workspace initialization, which is earlier than user plugin `apply()`.
35
+
36
+ - **docs**: bump version to 0.4.6.
37
+ ## 0.4.5 — 2026-09-05
38
+
39
+ - **fix(move)**: keep the live session and agent in place during a cross-workspace
40
+ move. The previous code tore down the live agent/session, moved the file, then
41
+ called `ctx.agents.resume` to re-create the agent. DSH's `agent/status` event
42
+ is only emitted on phase changes, so a freshly resumed agent never told the
43
+ client it was now idle, leaving the sidebar's model selector and send button
44
+ disabled ("会话不可用") until a manual browser refresh. The new path flushes
45
+ pending events to disk, updates the in-memory session header + coordinator
46
+ state + workspace accounting in place, and atomically renames the artifact,
47
+ so the agent's UI keeps showing the same in-memory session with no client
48
+ re-init.
49
+ - **fix(preset migration)**: drop the over-strict `persistence.readRaw` /
50
+ `persistence.list` precondition that caused the
51
+ `/session-manager/api/preset-scan` endpoint to fail with
52
+ `current persistence backend does not support readRaw/list` on a default DSH
53
+ build. The actual `JsonlSessionPersistence` backend exposes both methods, so
54
+ the precondition is replaced with a try/catch around `listSessionHeaders` that
55
+ converts any missing-method failure into a useful
56
+ `failed to enumerate sessions: <detail>` message.
57
+ - **chore**: remove the now-unused `quietLive` / `releaseLiveSession` helpers
58
+ and squash the per-route indentation noise around `/move` and `/workspaces`.
59
+
60
+ ## 0.4.4 — 2026-09-03
61
+
62
+ - **docs**: rename the English README wording from `conversation` to `session` to align with the plugin name (`dsh-session-manager`), the Chinese README (`会话`), the DSH host APIs, and the [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) registry entry.
63
+ - **chore**: rewrite `package.json` `description` to use `Session manager` / `sessions` for the same alignment, and bump the version to `0.4.4`.
64
+ - **chore(repo)**: update the GitHub repository description to match.
65
+
66
+ ## 0.4.3 — 2026-09-03
67
+
68
+ - **docs**: add the [Awesome DSH Plugin](https://awesome-dsh-plugin.com) badge to `README.md` / `README.zh.md` so the repo surfaces its curated registry membership.
69
+
70
+ ## 0.4.2 — 2026-09-03
71
+
72
+ - **feat(theme)**: dialogs now auto-follow DSH''s dark/light theme (`data-ds-dark-theme` / ` `code-scheme` / `data-theme`) via a single `data-sm-theme` attribute and scoped CSS variables, with inline `background` / `color` / `border-color` applied to each dialog root so they stay opaque regardless of how DSH resolves its own tokens. The previous manual light/dark toggle button is removed.
73
+ - **docs**: aligned bilingual README structure, dropped the obsolete "no bulk migration" wording, and added an Acknowledgments section that thanks the users and the contributors filing issues and opening PRs. Listed [dsh-market](https://github.com/dsh-market/dsh-market) and [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) as install sources.
74
+ - **chore**: rewrote `package.json` `description` to match the new English summary.
75
+
76
+ ## 0.4.1 — 2026-08-28
77
+
78
+ - **fix(ui)**: keep the title-bar **Delete conversation** button readable on hover with a red background, white text, and red border; remove the unused legacy danger-button rules.
79
+
80
+ ## 0.4.0 — 2026-08-28
81
+
82
+ - **feat(session preset migration)**: replaces the former bulk workflow with a
83
+ per-conversation **Migrate preset** action in Session manager. It resolves the
84
+ effective preset from the latest `agent-preset/selected` event or, when absent,
85
+ the session header, then safely updates that one conversation.
86
+ - **fix(lifecycle)**: moving a conversation or migrating its preset now retires stale
87
+ live agents and persistence owners before refresh. This prevents resume failures
88
+ such as `already has a live persistence owner`.
89
+ - **fix(move)**: refreshes session and workspace state immediately and once more after
90
+ the host event race, so a moved conversation reappears in its target workspace
91
+ without a manual browser refresh.
92
+ - **ui**: finalizes header actions and Session manager dialogs: red delete actions,
93
+ per-row preset migration, consistent dialog placement, readable hover states, and
94
+ a close button beside the manager title.
95
+ - **docs**: refreshes bilingual documentation and npm metadata for the single-session
96
+ preset migration workflow.
97
+
98
+ ## 0.3.0 — 2026-08-27
99
+
100
+ - **feat(preset migration)**: introduced preset migration support for conversations
101
+ whose configured Agent preset was renamed or removed.
102
+ - **feat(move)**: added workspace move handling and client-side workspace refreshes.
103
+
104
+ ## 0.2.1 — 2026-08-26
105
+
106
+ - **fix(move)**: reimplemented cross-workspace moves so the session artifact, stored
107
+ `cwd`, and workspace accounting are moved together while preserving history,
108
+ title, archive state, and derived-session relationships.
109
+ - **feat(workspaces API)**: added the workspace projection endpoint used by the move UI.
110
+ - **guard**: reject subagent and transient blank-session placeholders for move actions.
111
+
112
+ ## 0.2.0 — 2026-08-16
113
+
114
+ > ⚠️ The initial workspace-move implementation was superseded by 0.2.1.
115
+
116
+ - **feat(move)**: added the initial move-to-workspace UI and host endpoints.
117
+
118
+ ## 0.1.2 — 2026-08-16
119
+
120
+ - **docs**: synchronized package metadata and bilingual README files for publication.
121
+
122
+ ## 0.1.1 — 2026-08-16
123
+
124
+ - **fix(panel)**: hide transient blank-session placeholders from the manager panel.
125
+ - **test**: added the host API smoke test.
126
+ - **ci**: added syntax and package-content verification.
127
+
128
+ ## 0.1.0 — 2026-08-16
129
+
130
+ - **feat**: initial session deletion with confirmation, archive management, and the
131
+ Session manager panel.
package/README.md CHANGED
@@ -1,113 +1,107 @@
1
- # dsh-session-manager — session manager for DeepSeek Harness
2
-
3
- English | [中文](README.zh.md)
4
-
5
- [![npm version](https://img.shields.io/npm/v/dsh-session-manager)](https://www.npmjs.com/package/dsh-session-manager)
6
- [![GitHub](https://img.shields.io/badge/GitHub-repository-blue)](https://github.com/hkkz9522/dsh-session-manager)
7
- [![CI](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml)
8
- [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
9
-
10
- A DeepSeek Harness (DSH) Web plugin for session management: delete sessions, archive sessions, move sessions across workspaces, and migrate a session's Agent preset. Suggestions are welcome on GitHub.
11
-
12
- ## Features
13
-
14
- - **Archive / unarchive** sessions.
15
- - **Delete sessions** with an explicit irreversible-action confirmation.
16
- - **Move to workspace**: preserves history, title, archive state, and derived-session relationships, and updates the session's working directory to the target workspace.
17
- - **Migrate Agent preset**: change the preset on demand. Typical use case: when the original preset was renamed or removed and the session can no longer resume, you can repair that session.
18
- - **Session manager**: browse active and archived sessions in the sidebar, and run Open, Archive / Unarchive, Move, Delete, or Migrate preset on each row.
19
- - The current session's title area offers Archive / Unarchive, Move to workspace, and a red Delete session button.
20
-
21
- ## Where to find the UI
22
-
23
- - **Session title area (right side):** archive/unarchive, move to workspace, delete session.
24
- - **Sidebar footer → Session manager:** browse all sessions (including archived ones) and operate on each one.
25
-
26
- ## Agent preset migration
27
-
28
- Use this when a session can no longer resume because its original preset no longer exists, for example after removing a custom preset such as `router-standard`.
29
-
30
- 1. Open **Session manager**.
31
- 2. Locate the session and select **Migrate preset**.
32
- 3. Choose one of the currently available target presets and confirm.
33
-
34
- The plugin determines the session's effective preset from its latest `agent-preset/selected` event when present; otherwise it uses the session header. It safely updates the relevant stored value, releases any live persistence owner, and refreshes the session list. If the migrated session is open, reopen it before continuing the chat.
35
-
36
- > A preset migration changes session metadata only. It does not alter message history, files, or the selected workspace.
37
-
38
- ## Install
39
-
40
- The plugin is listed in [dsh-market](https://github.com/dsh-market/dsh-market) and [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin), and can be installed directly from the **Plugin Marketplace** inside DSH.
41
-
42
- ### From dsh-market
43
-
44
- ```powershell
45
- dsh plugin --profile web add npm:dsh-session-manager
46
- ```
47
-
48
- ### From GitHub
49
-
50
- ```powershell
51
- dsh plugin --profile web add github:hkkz9522/dsh-session-manager
52
- ```
53
-
54
- Restart DSH Web after installation. If the browser still holds an older client bundle, force refresh with `Ctrl+Shift+R`.
55
-
56
- ### Local development / runtime injection
57
-
58
- ```text
59
- dev_inject_plugin {"dir": "<absolute path to this repository>"}
60
- ```
61
-
62
- ## HTTP API
63
-
64
- The following local endpoints are used by the Web UI and are also useful for integration and diagnostics:
65
-
66
- ```text
67
- POST /session-manager/api/delete { sessionId }
68
- POST /session-manager/api/unarchive { sessionId }
69
- GET /session-manager/api/workspaces
70
- POST /session-manager/api/move { sessionId, targetWorkspaceId }
71
- GET /session-manager/api/preset-scan?sessionId=<sessionId>
72
- POST /session-manager/api/preset-migrate { sessionId, toPreset }
73
- ```
74
-
75
- Example: migrate a session to the `standard` preset.
76
-
77
- ```bash
78
- curl -s -X POST http://127.0.0.1:3080/session-manager/api/preset-migrate \
79
- -H 'content-type: application/json' \
80
- -d '{"sessionId":"session-...","toPreset":"standard"}'
81
- ```
82
-
83
- ## Safety and behavior
84
-
85
- - **Deletion is permanent**, so the UI always asks for confirmation.
86
- - Moving a running session first interrupts and closes it, then refreshes the sidebar; reopen the session from the target workspace to continue.
87
- - Move rewrites the session's stored `cwd`; subsequent tool calls run in the target workspace.
88
- - Subagent sessions and transient blank-session placeholders are excluded from delete, move, and preset migration.
89
- - File rewrites use temporary files and atomic replacement (when supported by the environment) to avoid partially written session artifacts.
90
-
91
- ## Compatibility and development
92
-
93
- - This is a Cordis plugin with peer dependency `cordis >=4.0.0-rc <5`.
94
- - `lib/index.js` is the host-side ESM plugin, `lib/client.js` is the Web client bundle; no build step is required.
95
- - Before submitting changes, run:
96
-
97
- ```powershell
98
- node --check lib/client.js
99
- node --check lib/index.js
100
- git diff --check
101
- node scripts/smoke-test.mjs
102
- npm pack --dry-run
103
- ```
104
-
105
- Release history is in [CHANGELOG.md](CHANGELOG.md).
106
-
107
- ## Acknowledgments
108
-
109
- Thanks to everyone who installs and uses dsh-session-manager, and to the people who file issues and open pull requests to help improve it. This plugin is listed in [dsh-market](https://github.com/dsh-market/dsh-market) and [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin). Suggestions and feedback are welcome.
110
-
111
- ## License
112
-
1
+ # dsh-session-manager — session manager for DeepSeek Harness
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/dsh-session-manager)](https://www.npmjs.com/package/dsh-session-manager)
6
+ [![GitHub](https://img.shields.io/badge/GitHub-repository-blue)](https://github.com/hkkz9522/dsh-session-manager)
7
+ [![CI](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml)
8
+ [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
9
+
10
+ A DeepSeek Harness (DSH) Web plugin for session management: delete sessions, archive sessions, move sessions across workspaces, and migrate a session's Agent preset. Suggestions are welcome on GitHub.
11
+
12
+ ## Features
13
+
14
+ - **Archive / unarchive** sessions.
15
+ - **Delete sessions** with an explicit irreversible-action confirmation.
16
+ - **Move to workspace**: preserves history, title, archive state, and derived-session relationships, and rewrites the session's working directory to the target workspace.
17
+ - **Migrate Agent preset**: change the preset on demand. Typical use case: when the original preset was renamed or removed and the session can no longer resume, you can repair that session.
18
+ - **Session manager panel**: browse active and archived sessions in the sidebar, and run Open, Archive / Unarchive, Move, Migrate preset, or Delete on each row.
19
+ - The current session's title area offers Archive / Unarchive, Move to workspace, and a red Delete session button.
20
+ - Each dialog button (Move, Migrate preset, Delete, plus the Session manager toggle) closes its own popup when clicked a second time, matching the built-in title-area buttons.
21
+
22
+ ## Where to find the UI
23
+
24
+ - **Session title area (right side):** Archive / Unarchive, Move to workspace, Delete session.
25
+ - **Sidebar footer → Session manager:** browse all sessions (including archived ones) and operate on each one.
26
+
27
+ ## Agent preset migration
28
+
29
+ Use this when a session can no longer resume because its original preset no longer exists, for example after removing a custom preset such as `router-standard`.
30
+
31
+ 1. Open **Session manager**.
32
+ 2. Locate the session and select **Migrate preset**.
33
+ 3. Choose one of the currently available target presets and confirm.
34
+
35
+ The plugin determines the session's effective preset from its latest `agent-preset/selected` event when present; otherwise it uses the session header. It then rewrites that event in place (or appends a fresh one if the session has never recorded a selection), so the migration is durable and the prior entry remains visible in the event log as history. For a live session, the new event is appended in memory via `Session.append()` and flushed to disk via `SessionStore.flush()`; the api-gateway's chat panel sees the new preset on the next event fold.
36
+
37
+ > A preset migration changes session metadata only. It does not alter message history, files, or the selected workspace.
38
+
39
+ ## Install
40
+
41
+ The plugin is listed in [dsh-market](https://github.com/dsh-market/dsh-market) and [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin), and can be installed directly from the **Plugin Marketplace** inside DSH.
42
+
43
+ ### From dsh-market
44
+
45
+ ```powershell
46
+ dsh plugin --profile web add npm:dsh-session-manager
47
+ ```
48
+
49
+ ### From GitHub
50
+
51
+ ```powershell
52
+ dsh plugin --profile web add github:hkkz9522/dsh-session-manager
53
+ ```
54
+
55
+ Restart DSH Web after installation. If the browser still holds an older client bundle, force refresh with `Ctrl+Shift+R`.
56
+
57
+ ### Local development / runtime injection
58
+
59
+ ```text
60
+ dev_inject_plugin {"dir": "<absolute path to this repository>"}
61
+ ```
62
+
63
+ ## Safety and behavior
64
+
65
+ - **Deletion is permanent**, so the UI always asks for confirmation.
66
+ - Move and Migrate preset do **not** tear down the live agent or session. They keep the in-memory session/agent alive, write the new artifact in place, update the in-memory session header to point at the new cwd (move) or append the new event (migrate), and refresh the workspace registry. The api-gateway's chat panel therefore stays "available" without a manual refresh.
67
+ - Move rewrites the session's stored `cwd`; subsequent tool calls run in the target workspace.
68
+ - Subagent sessions and transient blank-session placeholders are excluded from Delete, Move, and Migrate preset.
69
+ - The move path encodes the artifact in the backend's own physical layout (zstd frames with a one-header-line first frame, or plain JSONL), matching DSH's own writer. The migrate path rewrites the relevant event in place at the existing file.
70
+
71
+ ## Compatibility
72
+
73
+ | Plugin version | Verified DSH version |
74
+ | --- | --- |
75
+ | 0.4.7 | v0.1.5-rc.1 |
76
+ | 0.4.4 | 0.1.3-alpha.2 |
77
+ | 0.4.1 | 0.1.3-alpha.2 |
78
+ | 0.4.0 | v0.1.2-rc.1 |
79
+ | 0.1.2 | v0.1.0-rc.7 |
80
+ | 0.1.1 | v0.1.0-rc.7 |
81
+ | 0.1.0 | v0.1.0-rc.7 |
82
+
83
+ The plugin is a Cordis plugin and declares `cordis: ">=4.0.0-rc <5"` as its peer dependency.
84
+
85
+ ## Development
86
+
87
+ - `lib/index.js` is the host-side ESM plugin; `lib/client.js` is the Web client bundle. No build step is required.
88
+ - Before submitting changes, run:
89
+
90
+ ```powershell
91
+ node --check lib/client.js
92
+ node --check lib/index.js
93
+ node --test test/*.test.mjs
94
+ node scripts/smoke-test.mjs
95
+ git diff --check
96
+ npm pack --dry-run
97
+ ```
98
+
99
+ Release history is in [CHANGELOG.md](CHANGELOG.md).
100
+
101
+ ## Acknowledgments
102
+
103
+ Thanks to everyone who installs and uses dsh-session-manager, and to the people who file issues and open pull requests to help improve it. This plugin is listed in [dsh-market](https://github.com/dsh-market/dsh-market) and [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin). Suggestions and feedback are welcome.
104
+
105
+ ## License
106
+
113
107
  [MIT](LICENSE)
package/README.zh.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-session-manager)](https://www.npmjs.com/package/dsh-session-manager)
6
6
  [![GitHub](https://img.shields.io/badge/GitHub-仓库-blue)](https://github.com/hkkz9522/dsh-session-manager)
7
- [![CI](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml)
7
+ [![CI](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/hkkz9522/dsh-session-manager/actions/workflows/ci.yml)
8
8
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
9
9
 
10
10
  用于在 DeepSeek Harness(DSH)Web 中进行会话管理,包括:删除会话、归档会话、跨工作区移动会话、迁移会话的 Agent 预设。欢迎至 GitHub 提意见。
@@ -13,10 +13,11 @@
13
13
 
14
14
  - **归档 / 移出归档**会话。
15
15
  - **删除会话**:带不可逆操作的二次确认。
16
- - **移动至工作区**:保留历史、标题、归档状态和派生会话关系,同时把会话的工作目录更新为目标工作区。
17
- - **迁移 Agent 预设**:可按需修改。典型工况:当原预设被改名或删除,导致会话无法恢复时,可修复该会话。
18
- - **会话管理窗口**:在侧边栏中浏览未归档和已归档会话,并对每一行执行打开、归档 / 移出归档、移动、删除、迁移预设。
16
+ - **移动至工作区**:保留历史、标题、归档状态和派生会话关系,同时把会话的 `cwd` 更新为目标工作区。
17
+ - **迁移 Agent 预设**:按需修改。典型工况:当原预设被改名或删除,导致会话无法恢复时,可修复该会话。
18
+ - **会话管理窗口**:在侧边栏中浏览未归档和已归档会话,并对每一行执行打开、归档 / 移出归档、移动、迁移预设、删除。
19
19
  - 当前会话标题区域提供归档 / 移出归档、移动至工作区和红色的删除会话按钮。
20
+ - 弹窗按钮(移动、迁移预设、删除,以及"会话管理"入口)再次点击会关闭对应弹窗,与标题栏原生按钮行为一致。
20
21
 
21
22
  ## UI 入口
22
23
 
@@ -31,7 +32,7 @@
31
32
 
32
33
  例如:当会话无法恢复,报错表明原 Agent 预设不存在时(例如删掉了 `router-standard`),可以使用迁移功能。
33
34
 
34
- 插件会优先读取最后一条 `agent-preset/selected` 事件中的有效预设;若不存在该事件,则读取会话 header 中的预设。迁移时会安全改写对应的持久化记录、释放可能残留的 live persistence owner,并刷新会话列表。若该会话当前打开,请在迁移后重新打开再继续会话。
35
+ 插件会读取最后一条 `agent-preset/selected` 事件中的有效预设(若不存在则读取会话 header),然后就地重写该事件(若会话从未记录过选择事件则追加新事件)——这一做法是持久的,旧事件保留在日志中作为历史。对 live session,新事件通过 `Session.append()` 追加到内存,再通过 `SessionStore.flush()` 刷到磁盘;api-gateway 的聊天面板在下次事件折叠时即可看到新预设。
35
36
 
36
37
  > 迁移预设只会修改会话元数据,不会改写历史消息、文件或当前工作区。
37
38
 
@@ -59,46 +60,39 @@ dsh plugin --profile web add github:hkkz9522/dsh-session-manager
59
60
  dev_inject_plugin {"dir": "<本仓库的绝对路径>"}
60
61
  ```
61
62
 
62
- ## HTTP API
63
-
64
- 以下本地接口供 Web UI 使用,也可用于集成和排查:
65
-
66
- ```text
67
- POST /session-manager/api/delete { sessionId }
68
- POST /session-manager/api/unarchive { sessionId }
69
- GET /session-manager/api/workspaces
70
- POST /session-manager/api/move { sessionId, targetWorkspaceId }
71
- GET /session-manager/api/preset-scan?sessionId=<sessionId>
72
- POST /session-manager/api/preset-migrate { sessionId, toPreset }
73
- ```
74
-
75
- 示例:将会话迁移到 `standard` 预设。
76
-
77
- ```bash
78
- curl -s -X POST http://127.0.0.1:3080/session-manager/api/preset-migrate \
79
- -H 'content-type: application/json' \
80
- -d '{"sessionId":"session-...","toPreset":"standard"}'
81
- ```
82
-
83
63
  ## 安全与行为说明
84
64
 
85
65
  - **删除不可恢复**,因此界面始终要求确认。
86
- - 移动正在运行的会话时,插件会先中断并关闭该会话,然后自动刷新侧边栏;请在目标工作区重新打开会话后继续。
66
+ - 移动和迁移预设会先 quiesce 该会话的 live agent(取消运行 + 释放 scope + 移出 SessionStore),即使聊天标签页还开着也能成功;侧边栏会自动刷新。
87
67
  - 移动会改写会话保存的 `cwd`,之后的工具调用将在目标工作区执行。
88
- - subagent 会话和临时空白会话占位不会参与删除、移动或预设迁移。
89
- - 文件改写使用临时文件和原子替换(环境支持时),避免产生部分写入的会话工件。
68
+ - subagent 会话和临时空白会话占位不会参与删除、移动或迁移预设。
69
+ - 持久化改写走 DSH 自身的 `open/create/append/flush` 接口,编解码链在内部处理 v2 → v3 格式迁移,写出的工件对当前 DSH 版本始终合法。
70
+
71
+ ## 兼容性
72
+
73
+ | 插件版本 | 已验证 DSH 版本 |
74
+ | --- | --- |
75
+ | 0.4.7 | v0.1.5-rc.1 |
76
+ | 0.4.4 | 0.1.3-alpha.2 |
77
+ | 0.4.1 | 0.1.3-alpha.2 |
78
+ | 0.4.0 | v0.1.2-rc.1 |
79
+ | 0.1.2 | v0.1.0-rc.7 |
80
+ | 0.1.1 | v0.1.0-rc.7 |
81
+ | 0.1.0 | v0.1.0-rc.7 |
82
+
83
+ 本插件是 Cordis 插件,peer dependency 为 `cordis: ">=4.0.0-rc <5"`。
90
84
 
91
- ## 兼容性与开发
85
+ ## 开发
92
86
 
93
- - 本插件是 Cordis 插件,声明的 peer dependency 为 `cordis >=4.0.0-rc <5`。
94
87
  - `lib/index.js` 是 host 端 ESM 插件,`lib/client.js` 是 Web 客户端 bundle,无需构建步骤。
95
88
  - 提交修改前请运行:
96
89
 
97
90
  ```powershell
98
91
  node --check lib/client.js
99
92
  node --check lib/index.js
100
- git diff --check
93
+ node --test test/*.test.mjs
101
94
  node scripts/smoke-test.mjs
95
+ git diff --check
102
96
  npm pack --dry-run
103
97
  ```
104
98
 
@@ -108,10 +102,8 @@ npm pack --dry-run
108
102
 
109
103
  感谢每一位安装和使用 dsh-session-manager 的用户,也感谢提交 Issue 与 Pull Request 帮助改进本插件的朋友们。
110
104
 
111
- 本插件已被 [dsh-market](https://github.com/dsh-market/dsh-market) 和 [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 收录。
112
- 欢迎提出修改意见。
105
+ 本插件已被 [dsh-market](https://github.com/dsh-market/dsh-market) 和 [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 收录。欢迎提出修改意见。
113
106
 
114
107
  ## 开源许可
115
108
 
116
109
  [MIT](LICENSE)
117
-
package/lib/client.js CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * @dsh-session-manager — Client half.
3
- * v0.3.0 — replaces 0.2.1 client.js which had V8 strict-mode parse errors.
4
- * Functionally equivalent: header actions (open/archive/move/delete/manage),
5
- * footer action (open session manager panel), and the panel itself with
6
- * delete/move confirm dialogs. The "preset migration" feature is registered
7
- * as a separate slot in a sibling client bundle.
3
+ *
4
+ * Renders the title-bar action cluster (Archive / Unarchive, Move to
5
+ * workspace, Delete session) and the sidebar-foot Session manager panel
6
+ * (Open / Archive / Unarchive / Move / Migrate preset / Delete per row,
7
+ * plus the panel's own filter pills and toggle-close behaviour). No build
8
+ * step: DSH loads the file as a Cordis client bundle via its inject
9
+ * declaration in package.json.
8
10
  */
9
11
  window.__ModuleLoader__.load({
10
12
  id: "dsh-session-manager",
@@ -617,6 +619,7 @@ window.__ModuleLoader__.load({
617
619
  getSnapshot() { return this.open; },
618
620
  subscribe(cb) { this.listeners.add(cb); return () => this.listeners.delete(cb); },
619
621
  set(v) { if (this.open === v) return; this.open = v; for (const fn of [...this.listeners]) fn(); },
622
+ toggle() { this.open = !this.open; for (const fn of [...this.listeners]) fn(); },
620
623
  // Pending action queued by the title-bar buttons (e.g. 移动至工作区).
621
624
  // The SessionManagerPanel consumes this on mount so it can pre-open
622
625
  // the matching inner dialog (move / delete / migrate) next to itself.
@@ -727,9 +730,9 @@ window.__ModuleLoader__.load({
727
730
  h("div", { className: "sm-rowActions" },
728
731
  h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => onOpen(s.id) }, t("row.open")),
729
732
  h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => runRow(s.id, () => isArchived ? onUnarchive(s.id) : onArchive(s.id)) }, t(isArchived ? "row.unarchive" : "row.archive")),
730
- h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => setMoveFor(s) }, t("row.move")),
731
- h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => setMigrateFor(s) }, t("row.migrate")),
732
- h("button", { type: "button", className: "sm-rowBtn sm-rowBtnDanger", disabled: busy, onClick: () => setConfirmFor(s) }, t("row.delete"))
733
+ h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => { if (moveFor && moveFor.id === s.id) setMoveFor(null); else setMoveFor(s); } }, t("row.move")),
734
+ h("button", { type: "button", className: "sm-rowBtn", disabled: busy, onClick: () => { if (migrateFor && migrateFor.id === s.id) setMigrateFor(null); else setMigrateFor(s); } }, t("row.migrate")),
735
+ h("button", { type: "button", className: "sm-rowBtn sm-rowBtnDanger", disabled: busy, onClick: () => { if (confirmFor && confirmFor.id === s.id) setConfirmFor(null); else setConfirmFor(s); } }, t("row.delete"))
733
736
  )
734
737
  );
735
738
  };
@@ -1062,10 +1065,11 @@ window.__ModuleLoader__.load({
1062
1065
  ctx.sessions.open(sessionId);
1063
1066
  }
1064
1067
  };
1065
- // /move retires a live session, so host/session-removed can arrive on
1066
- // the streaming channel slightly after the HTTP success response.
1067
- // Pull both projections now and once more after that frame to make the
1068
- // destination row appear without a browser refresh.
1068
+ // The 0.4.6+ move path keeps the live agent/session intact (no
1069
+ // session/disposed, no half-resumed Session object), so the chat
1070
+ // panel keeps the in-memory session as active. We still refresh
1071
+ // the workspace + session-list projections so the destination
1072
+ // workspace and the moved row appear without a manual refresh.
1069
1073
  await refreshMovedSession();
1070
1074
  setTimeout(() => { void refreshMovedSession(); }, 250);
1071
1075
  setTimeout(() => { void refreshMovedSession(); }, 900);
@@ -1074,20 +1078,21 @@ window.__ModuleLoader__.load({
1074
1078
  const wasCurrent = ctx.sessions.list.getSnapshot().current === sessionId;
1075
1079
  const response = await callApi("/preset-migrate", { sessionId, toPreset });
1076
1080
  if (!response.ok) throw new Error(response.error || "preset migration failed");
1077
- ctx.sessions.noteAgentPreset(sessionId, toPreset);
1081
+ // The current DSH client session store derives agentPreset from
1082
+ // the refreshed projection; older builds exposed noteAgentPreset,
1083
+ // but calling it unconditionally breaks migration on newer builds.
1078
1084
  await ctx.sessions.refresh();
1079
1085
  if (wasCurrent) ctx.sessions.open(sessionId);
1080
- // Host/session-removed and the HTTP response travel on different
1081
- // streams. One delayed baseline closes that ordering race without a
1082
- // page refresh and keeps the migrated conversation selectable.
1086
+ // The migrate rewrite happens in-process on the live session, so
1087
+ // we just need a delayed baseline to let the api-gateway's projection
1088
+ // settle before re-activating the in-memory session.
1083
1089
  setTimeout(() => {
1084
1090
  void ctx.sessions.refresh().then(() => {
1085
- ctx.sessions.noteAgentPreset(sessionId, toPreset);
1086
1091
  if (wasCurrent) ctx.sessions.open(sessionId);
1087
1092
  }).catch(() => {});
1088
1093
  }, 250);
1089
1094
  },
1090
- onOpenPanel: () => panelStore.set(true)
1095
+ onOpenPanel: () => panelStore.toggle()
1091
1096
  });
1092
1097
  ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
1093
1098
  name: "conversation.session.header.actions",