dsh-workspace-mover 2.2.0 → 2.3.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 +285 -0
- package/README.md +40 -8
- package/README_EN.md +346 -0
- package/client/client.js +376 -37
- package/docs/ARCHITECTURE.md +17 -9
- package/docs/compatibility/dsh-0.2.0-rc.2-2026-10-04.md +39 -0
- package/docs/compatibility/dsh-0.2.0-rc.2-2026-10-13.md +45 -0
- package/lib/index.js +1465 -141
- package/package.json +102 -99
- package/test/client-dom.test.mjs +129 -0
- package/test/e2e-sandbox.test.mjs +417 -10
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -35,6 +35,7 @@ Single logical channel `/workspace-mover` via `ctx.connection.rpc.handle('/works
|
|
|
35
35
|
| `mover.status` | Capability report (detected services / degraded items) plus `storageLayout`, `degradedFeatures`, and the `unarchiveApi` / `setTitleApi` flags |
|
|
36
36
|
| `mover.workspaces` | List workspaces |
|
|
37
37
|
| `mover.move` | Single-session true move |
|
|
38
|
+
| `mover.preview` | Read-only migration preview: source/target, collision, running state, adapter and estimated new snapshot bytes; `backup.reused` identifies an existing matching snapshot |
|
|
38
39
|
| `mover.moveMany` | Bulk move (≤ `batchLimit`, default 50) |
|
|
39
40
|
| `mover.scan` | Classified rescue scan (parses the newest `scanLimit`, default 400; reports `scanned` vs `scannedParsed`) |
|
|
40
41
|
| `mover.repair` | Attach / relink / home one item |
|
|
@@ -47,8 +48,10 @@ Single logical channel `/workspace-mover` via `ctx.connection.rpc.handle('/works
|
|
|
47
48
|
| `mover.openFolder` | Open group directory in OS file manager |
|
|
48
49
|
| `mover.session.delete` | Session → recycle bin; optional `purgeBackups: true` also deletes that session's migration backups |
|
|
49
50
|
| `mover.trash.list` / `mover.trash.restore` / `mover.trash.purge` | Recycle bin; `purge` accepts optional `purgeBackups: true` |
|
|
50
|
-
| `mover.backups.list` / `mover.backups.restore` / `mover.backups.deleteOne` |
|
|
51
|
+
| `mover.backups.list` / `mover.backups.restore` / `mover.backups.deleteOne` | Recovery-snapshot management; `list` reports `orphan` per group, physical `count`, plus `orphanGroups` / `orphanBytes` |
|
|
51
52
|
| `mover.tasks.list` / `mover.tasks.retry` / `mover.tasks.forget` | Migration task center |
|
|
53
|
+
| `mover.migrations.enqueue` / `mover.migrations.list` / `mover.migrations.retry` / `mover.migrations.cancel` | Persistent busy-session queue; `retry` accepts one `taskId` or a `taskIds` batch, with per-item failure isolation |
|
|
54
|
+
| `mover.bundle.export` / `mover.bundle.inspect` / `mover.bundle.import` | Portable Bundle export, dry-run inspection, and import through the adapter/backup pipeline |
|
|
52
55
|
| `mover.data.cleanup` | Dry-run and clean aged plugin data (default age = `cleanupDays`) |
|
|
53
56
|
|
|
54
57
|
### Tunable policies
|
|
@@ -57,7 +60,7 @@ Single logical channel `/workspace-mover` via `ctx.connection.rpc.handle('/works
|
|
|
57
60
|
|
|
58
61
|
| Policy | Default | Environment override |
|
|
59
62
|
| --- | --- | --- |
|
|
60
|
-
|
|
|
63
|
+
| physical snapshot retention per session | 20 | `DSH_WORKSPACE_MOVER_BACKUP_KEEP` |
|
|
61
64
|
| move history length | 100 | `DSH_WORKSPACE_MOVER_HISTORY_LIMIT` |
|
|
62
65
|
| batch cap (move / repair) | 50 | `DSH_WORKSPACE_MOVER_BATCH_LIMIT` |
|
|
63
66
|
| repoint cap | 200 | `DSH_WORKSPACE_MOVER_REPOINT_LIMIT` |
|
|
@@ -102,25 +105,30 @@ When the host provides the `tools` service, `apply()` registers four plain (zero
|
|
|
102
105
|
- `exec.signal` propagates into the RPC layer; cancellation lets the in-flight step finish rolling back to a consistent state.
|
|
103
106
|
- Hosts without `dsh-tools` skip registration silently; `mover.status` reports the `agentTools` flag.
|
|
104
107
|
|
|
105
|
-
## Session archives
|
|
108
|
+
## Session archives and storage adapter
|
|
106
109
|
|
|
107
|
-
-
|
|
108
|
-
- Mixed compression
|
|
110
|
+
- The fallback filesystem adapter recognizes names `session.jsonl[.zstd]` and `session.vN.jsonl[.zstd]`; it selects the highest generation without rewriting older files to v3.
|
|
111
|
+
- A mixed plain/Zstd directory and a file whose compression differs from the host's configured mode are rejected explicitly. Mixed compression elsewhere under the same root is diagnosed per session, not by a root-wide scan.
|
|
112
|
+
- v3/v4 filenames are recognized, but a v4 runtime fixture has not yet been verified. Filename/header mismatch is rejected only when the header contains one of the generation fields currently recognized by the adapter.
|
|
109
113
|
- True move keeps the session id and all frames; only the header `cwd` (first frame) is rewritten; other frames stay byte-identical. Publish via temp file + atomic rename.
|
|
110
114
|
|
|
111
115
|
### The storage-layout assumption, and its self-check
|
|
112
116
|
|
|
113
|
-
The
|
|
117
|
+
The adapter first reports the public `list` / `stat` / `open` surface. When a provider also exposes a physical root, the plugin uses the legacy directory adapter as a visible `filesystem-fallback`; when only official handles are available it stays read/diagnostic capable and marks physical moves as `unsupported` instead of guessing a path.
|
|
114
118
|
|
|
115
119
|
`verifyStorageLayout(ctx)` closes that gap: it takes up to five real headers from `persistence.list()`, reverse-derives each session's directory with this plugin's own encoding, and confirms an archive is actually there. Result states are `ok` / `degraded` / `empty` (no sessions to verify) / `unavailable`. It is exposed as `mover.status.capabilities.storageLayout` plus a `data-layout` check in `mover_doctor`, is strictly read-only, and never throws (any error degrades to a warning).
|
|
116
120
|
|
|
121
|
+
`mover.status.capabilities.storageAdapter` is `filesystem-fallback`, `official-handle`, or `unavailable`; `storageApi`, `physicalPath`, and `migrationQueueState` expose the exact degradation and queue state. `mover_doctor` reports the same adapter under `storage-adapter` and checks the durable migration records under `data-migrations`.
|
|
122
|
+
|
|
123
|
+
Portable Bundles contain `manifest.json`, `sessions/`, `attachments/`, `checksums.json`, and `workspace-metadata.json`. Import defaults to dry-run and reports id conflicts, missing attachments, compression incompatibilities, required/free space, and recoverable files. Execution refuses a blocked plan, backs up each artifact, verifies the rewritten header, and isolates failures per session. Attachment files are preserved and copied into the imported session directory; the bundle report calls out any missing file.
|
|
124
|
+
|
|
117
125
|
## Move pipeline
|
|
118
126
|
|
|
119
127
|
Order of operations for a cross-workspace move:
|
|
120
128
|
|
|
121
129
|
1. **Running check** — reject only mid-turn sessions (`agents.get(id)?.status === 'running'`); idle resident sessions may move.
|
|
122
130
|
2. **Read authority header** from disk; verify target ≠ source.
|
|
123
|
-
3. **
|
|
131
|
+
3. **Recovery snapshot** to `$DSH_HOME/workspace-mover/backups/` (up to `backupKeep` distinct physical files per session, default 20) **before any side effect**. The content fingerprint ignores the migration-only header `cwd`, so a move back and forth reuses the existing snapshot. A backup failure aborts with `backup-failed` and nothing has been touched.
|
|
124
132
|
4. **Preflight** — dual-accounting detect, target writability probe, disk-space hint.
|
|
125
133
|
5. **Rewrite first frame** (header cwd) only.
|
|
126
134
|
6. **Move directory** (Windows: exponential-backoff retry on EPERM; fallback copy+delete).
|
|
@@ -129,7 +137,7 @@ Order of operations for a cross-workspace move:
|
|
|
129
137
|
9. **Verify** — read archive back; id + cwd must match or the move fails.
|
|
130
138
|
10. **Rollback on any failure** — restore live header + index snapshot → original bytes back to source dir → reattach source workspace.
|
|
131
139
|
|
|
132
|
-
Concurrency: same session / same target workspace try-acquire a lock
|
|
140
|
+
Concurrency: same session / same target workspace try-acquire a lock. A running session returns `busy` to the transaction layer and is persisted in `migrations.json` as `waiting-for-idle`; the queue wakes every few seconds and on the next plugin start. Bulk moves de-duplicate first and isolate each result.
|
|
133
141
|
|
|
134
142
|
If “rollback also failed”, a durable recovery record is written and shown as a red manual-recovery row. Session files and backups stay in place — never auto-deleted.
|
|
135
143
|
|
|
@@ -151,7 +159,7 @@ All plugin metadata lives under `$DSH_HOME/workspace-mover/` and never overwrite
|
|
|
151
159
|
|
|
152
160
|
| Path | Use |
|
|
153
161
|
| --- | --- |
|
|
154
|
-
| `backups/` | Byte-level
|
|
162
|
+
| `backups/` | Byte-level recovery snapshots; new files include a SHA-256 content fingerprint, while legacy timestamp-only names remain readable |
|
|
155
163
|
| `history.json` | Last 100 cross-workspace moves |
|
|
156
164
|
| trash / task / recovery files | Recycle bin manifest, task center, recovery ledger |
|
|
157
165
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# DSH 兼容性实测报告:0.2.0-rc.2 · 2026-10-04
|
|
2
|
+
|
|
3
|
+
> 本插件的兼容性验收记录。每适配一个 DSH 版本新增一份带日期的报告;README 的 "DSH tested" 徽章链接到最新一份。
|
|
4
|
+
> 插件版本:**2.1.0**(npm + GitHub tag v2.1.0)· 运行环境:Windows 10.0.26200 x64 · Node ≥22
|
|
5
|
+
|
|
6
|
+
## 验证范围
|
|
7
|
+
|
|
8
|
+
| 场景 | DSH 版本 | 结论 |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| **桌面客户端**(Electron 44 壳,`E:\DeepSeekHarness\desktop`) | 0.2 线(0.2.0-rc.2 内核) | ✅ 已实测通过 |
|
|
11
|
+
| **web profile** | 0.2.0-rc.2 | ⏳ 与桌面版同内核、同一代码路径,启动器已切换,回归待跑 |
|
|
12
|
+
|
|
13
|
+
## 桌面版实测项(2026-10-04)
|
|
14
|
+
|
|
15
|
+
| 项目 | 结果 | 说明 |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| 数据家共享(`DSH_HOME` 指向既有 `data\`) | ✅ | 会话、工作区、投影缓存全部直接可见,无格式迁移(会话文件保持旧命名) |
|
|
18
|
+
| 桌面 profile 插件安装 | ✅ | 应用内「插件」页安装,profile 与 web 相互独立 |
|
|
19
|
+
| 拖拽跨工作区迁移 | ✅ | 会话行 → 工作区标题行,确认后真迁移 |
|
|
20
|
+
| 确认框渲染 | ✅ | 修复后为不透明卡片(0.2 主题的 `--dsw-specific-menu` 为半透明玻璃色) |
|
|
21
|
+
| 插件热重载后的移动 | ✅ | 修复了旧 fiber 失活导致的 `inactive context` 报错(connection 实例在 apply 时捕获) |
|
|
22
|
+
| agent 工具(dsh-tools 注册) | ✅ | dsh-base 在 web/桌面共享 `tools` 行;三个工具 + 审批门就绪 |
|
|
23
|
+
| `mover.status` 能力位 | ✅ | `agentTools` 标志如实汇报 |
|
|
24
|
+
|
|
25
|
+
## 已知事项(非本插件缺陷)
|
|
26
|
+
|
|
27
|
+
- **遗留 Agent 预设**:0.2 不再读取 `$DSH_HOME\.agent-presets\<id>\` 旧格式目录,旧会话恢复会报 `Unknown agent preset`。迁移步骤:[docs/dsh-0.2-preset-migration.md](../dsh-0.2-preset-migration.md)。
|
|
28
|
+
- **web profile 回归**:拖拽 / 面板 / agent 工具在 web 0.2 场景按同一代码路径适配,尚未单独实测;完成后本报告将更新。
|
|
29
|
+
|
|
30
|
+
## 测试基线
|
|
31
|
+
|
|
32
|
+
- `npm run check`(语法 + 105 用例 + pack dry-run)全绿;
|
|
33
|
+
- CI:ubuntu / windows / macos × Node 22/24 矩阵通过(v2.1.0 tag 构建)。
|
|
34
|
+
|
|
35
|
+
## 历史
|
|
36
|
+
|
|
37
|
+
| 日期 | DSH 版本 | 报告 |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| 2026-10-04 | 0.2.0-rc.2(桌面) | 本文件 |
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# DSH compatibility report: 0.2.0-rc.2 · 2026-10-13
|
|
2
|
+
|
|
3
|
+
Release: 2.3.0. Desktop results below are user-reported partial verification; they do not claim a full real-runtime smoke pass.
|
|
4
|
+
|
|
5
|
+
## Matrix
|
|
6
|
+
|
|
7
|
+
| Environment | Node | Result | Scope |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| DSH Desktop 0.2.0-rc.2 | pending | partial: user confirmed idle-session migration and snapshot reuse; initial return-preview failures and corrections are documented below | adapter status, v4 move, preview; queue resume still pending |
|
|
10
|
+
| DSH Web 0.2.0-rc.2 | pending | pending user verification | same smoke flow on web connection |
|
|
11
|
+
| Local sandbox fixtures | 22.23.2 | passed: `npm run check`, 171/171 tests, `npm pack --dry-run` | v3/v4 Zstd, plain JSONL, format diagnostics, rollback, queue state transitions, return preview, drop-target identity, explicit target selection, snapshot deduplication |
|
|
12
|
+
| Node 24 fixtures | 24 | not run | CI/runtime matrix remains pending |
|
|
13
|
+
|
|
14
|
+
## Implemented checks
|
|
15
|
+
|
|
16
|
+
- `filesystem-fallback`, `official-handle`, and `unavailable` adapter modes are reported through `mover.status` and `mover_doctor`.
|
|
17
|
+
- Physical operations fail with a stable `unsupported` error when the provider exposes no raw-byte path.
|
|
18
|
+
- A running session is persisted in `migrations.json` as `waiting-for-idle`; the queue drains after idle and after plugin re-mount. Process-restart validation remains pending.
|
|
19
|
+
- `mover.preview` reports source, target, collision, running state, adapter mode, warnings, and estimated new snapshot bytes; a matching snapshot is reported as reused.
|
|
20
|
+
- Recovery snapshots use a SHA-256 fingerprint of session content with migration-only `cwd` normalized. Legacy timestamp-only backup names remain readable. Each migration still records its source, target, and snapshot reference in history.
|
|
21
|
+
- Mixed compression is rejected explicitly; no format upgrade is performed. Header-generation mismatch detection only applies when the header declares a recognized generation field.
|
|
22
|
+
- The local queue test covers plugin re-mount. A full DSH process restart with a waiting task has not been exercised yet.
|
|
23
|
+
- The user confirmed snapshot reuse for an old idle session after moving it; local fixtures cover Zstd, plain JSONL, round trips, and content changes.
|
|
24
|
+
|
|
25
|
+
## Still requiring a real DSH run
|
|
26
|
+
|
|
27
|
+
- Official-runtime plain JSONL and v3/v4 fixtures, including mismatch and mixed-layout diagnostics. The local sandbox fixtures are not official DSH runtime evidence.
|
|
28
|
+
- Desktop and Web smoke flow with a real session: create, preview, move, verify id/cwd/events, conflict, attach failure and byte-exact rollback.
|
|
29
|
+
- Restart DSH while a queue item is waiting, then verify it completes after the session becomes idle.
|
|
30
|
+
|
|
31
|
+
The next report should replace the pending rows with the exact DSH build, Node version, successful scenarios, and known limits.
|
|
32
|
+
|
|
33
|
+
## Desktop feedback and correction
|
|
34
|
+
|
|
35
|
+
The user restarted Desktop and reported all doctor checks passing except the expected filesystem adapter warning. A session moved from `E:\DeepSeekHarness` to `E:\VSCode_Project\quant_research`. Read-only inspection found one `session.v4.jsonl.zstd` primary archive at the destination (419,562 bytes) and no primary archive for that ID at the source. The return preview nevertheless showed both source and target as `quant_research` and incorrectly labelled the session's own archive as a conflict.
|
|
36
|
+
|
|
37
|
+
The candidate now resolves drop targets from the rendered `data-row-key` workspace ID before React group props and unique text evidence. It refreshes workspace data at drop time and rejects ambiguous text matches. Same-workspace previews distinguish existing membership from an unregistered archive, and report no recovery backup for those operations. Doctor adapter explanations and preview notices are localized; the recovery backup copy is explicitly described as separate from the registered primary session.
|
|
38
|
+
|
|
39
|
+
The user retested after restart and still received a same-workspace return preview. The exact Desktop event target has not been captured, so the identity-based correction alone is not considered verified. Further changes remove the stale last-hover fallback when dropping outside a header and clear the hover target when leaving a header. Single-session confirmation now offers an explicit workspace selector, refreshes the preview for the selected target and fork scope, and keeps execution disabled while loading or on preview failure. Late preview responses are ignored. These flows have DOM regression coverage; The latest user feedback confirms migration and snapshot reuse, but does not separately document every selector/drag scenario.
|
|
40
|
+
|
|
41
|
+
## Release checks
|
|
42
|
+
|
|
43
|
+
- Version 2.3.0: local Node 22.23.2 checks passed, 171/171 tests, syntax checks and npm pack dry-run.
|
|
44
|
+
- Regression coverage now includes newest/default versus explicitly selected backup restoration, attachment space estimates, and insufficient-space import refusal before writing.
|
|
45
|
+
- README_EN.md and CHANGELOG.md are included in the npm package.
|