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/CHANGELOG.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [2.3.0] - 2026-10-13
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Persistent busy-session migration queue with idle retries, cancellation, and individual/batch retry.
|
|
8
|
+
- Migration preview and explicit target-workspace selection, adapter diagnostics, and v3/v4/plain/Zstd format checks.
|
|
9
|
+
- Optional descendant migration and Portable Bundle export/inspection/dry-run import APIs (sandbox verified; real-runtime validation remains pending).
|
|
10
|
+
- npm weekly downloads badge and documentation of the expected filesystem adapter warning.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Identical content reuses a recovery snapshot, ignoring migration-only cwd changes. Changed content creates a new snapshot; every move remains in history. Legacy backup filenames remain supported.
|
|
15
|
+
- Preview displays newly required backup bytes and snapshot reuse. Retention limits count physical snapshots.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Return-move workspace resolution and stale hover targets; failed or stale previews cannot execute against an earlier target.
|
|
20
|
+
- Default backup restoration chooses the newest saved snapshot.
|
|
21
|
+
- Portable Bundle space estimates include attachments and known insufficient space blocks execution.
|
|
22
|
+
|
|
23
|
+
### Validation
|
|
24
|
+
|
|
25
|
+
- User confirmed Desktop idle-session migration and snapshot reuse. Web, full runtime rollback smoke, and DSH process-restart queue recovery remain unverified; see the dated compatibility report.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [2.2.0] - 2026-10-09
|
|
29
|
+
|
|
30
|
+
### Changed (behavior)
|
|
31
|
+
|
|
32
|
+
- **Batch and multi-select moves no longer guess a session id.** When the authoritative row-to-id channel (the React fiber carrying `node.id`) is unavailable, the client used to fall back to positional order and, on a title mismatch, take the *next* id in sequence. Because the official sidebar hides blank and archived rows, that fallback could shift a group by one and move a *different but valid* set of sessions — undetectable host-side. The fallback now refuses to guess: unresolvable rows are reported to the user, and a move either aborts (nothing resolvable) or proceeds with only the rows that resolved, after an explicit confirmation that names the skipped count. This is the one intentional behavior change in this release.
|
|
33
|
+
- **Workspace resolution verifies instead of trusting DOM order.** The positional fallback that mapped the *i*-th sidebar header to the *i*-th registry item is now accepted only when the header text actually matches that item's title or path; otherwise the move aborts with the existing "list out of sync" message. Previously a single hidden header (for example a workspace whose folder was moved) shifted every later index by one.
|
|
34
|
+
- **`workspace-mover` styles and dialog semantics** unchanged in appearance; dialogs gained an accessible name, initial focus, and a Tab trap.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **`screenshots.json`**: declares the plugin's screenshots in-repository so plugin storefronts (dsh-market and peers) show them App Store style in a controlled order instead of scraping the README.
|
|
39
|
+
- **`peerDependencies`** for the official packages the plugin integrates with, declared as `*` and marked optional in `peerDependenciesMeta`. These peers are declarative only — the plugin fail-softs at runtime and reports any real degradation through `mover.status` capabilities and `mover_doctor` — so they exist for storefront metadata, not as a compatibility gate. The real floor is `engines.dsh`.
|
|
40
|
+
- **Fixed: the first attempt at those peer ranges made the host declare the plugin incompatible with `0.2.0-rc.2`.** The ranges were written in the ecosystem's "explicit prerelease branch" idiom, e.g. `>=0.0.1-rc.1 <0.1.0 || >=0.1.0-rc.1 <0.2.0-0`. npm's prerelease rule evaluates each `||` alternative as a *set* and only admits a prerelease when a comparator in that set shares the version's exact `major.minor.patch` tuple **and** carries a prerelease tag; then every comparator is checked normally. Because `0.2.0-rc.2 > 0.2.0-0`, the upper bound `<0.2.0-0` excluded **every 0.2.0 prerelease** — i.e. the plugin's own tested host line. Enumerating release lines would reproduce this on each new line (a `<0.3.0-0` bound breaks the moment 0.3 lands), so all eight peers are now `*`. A regression test asserts the declared ranges plus `engines.dsh` yield `compatible` (never `incompatible`) for every DSH line from 0.1.5-rc.1 through 1.0.0.
|
|
41
|
+
- **Storage-layout self-check.** The plugin re-implements the session-store directory encoding, and the persistence root it derives from is not a documented part of the `SessionPersistence` contract. A new read-only check reverse-derives one real session's directory from `persistence.list()` and verifies it exists; the result appears as `mover.status.capabilities.storageLayout` and as a `data-layout` check in `mover_doctor`, so a host layout change becomes a visible degraded state instead of sessions that silently cannot be found.
|
|
42
|
+
- **Archive-truncation visibility.** The rescue scan parses only the newest 400 session archives, and archived sessions are typically old — so on large libraries they could drop out of the archived list with no explanation. The archived view now reports when the underlying scan was truncated.
|
|
43
|
+
- **Client test coverage.** `test/client-dom.test.mjs` exercises the client half against a hand-rolled DOM stub (no new dependencies): workspace resolution, row-to-id mapping, the drop payload, listener teardown, dialog dismissal and the RPC failure matrix.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **Client half had no teardown.** Seven document-level listeners and a `document.body` subtree `MutationObserver` were never released. The project's own hot-reload path (the desktop client disposes and recomposes the plugin fiber) could therefore stack a second copy of every listener, causing duplicate confirm dialogs, duplicate RPC calls, and two copies fighting over the same selection highlight. All listeners and the observer are now registered through the plugin context's disposal channel, and a module-level guard prevents a duplicate `apply`.
|
|
48
|
+
- **The menu observer no longer runs for the whole page lifetime.** It is connected after an ellipsis click and disconnected on injection or timeout, instead of observing every DOM mutation in the app forever.
|
|
49
|
+
- **Dead and contradictory client strings.** `ungroupedUnsupported` was never referenced. `pickEscHint` was never referenced *and* contradicted the implementation; Escape now respects the copy (it does not clear the multi-selection while a text input has focus). Two hard-coded English strings that leaked into the Chinese UI are now localized.
|
|
50
|
+
- **Documentation drift**: the READMEs and `docs/ARCHITECTURE.md` described three agent tools while four are registered (`mover_doctor` was missing), and the compatibility section still claimed verification against `0.1.5-rc.1` while the README badge claimed `0.2.0-rc.2`. Tool tables, the compatibility boundary, and the test-suite description are now consistent and dated.
|
|
51
|
+
- **Tests 108 → 144**: 10 new client DOM cases (row/workspace resolution, drag payload, listener teardown, dialog dismissal and the RPC failure matrix, against a hand-rolled DOM stub), 13 policy/Config/peer-range cases, and host-side coverage for the storage-layout self-check, archive truncation, backup orphan GC, the unarchive dual path, setTitle decoupling, and the official-API capability flags.
|
|
52
|
+
- **Fixed a latent policy bug found while wiring the tunables**: `cleanupOldData` destructured `{ days = 30 }`, so "not supplied" became `30` and the `Number(days) || cleanupDays()` fallback could never see `undefined` — the configured cleanup age was silently shadowed by the default.
|
|
53
|
+
- **Backups taken in the same millisecond no longer overwrite each other.** `stashBackup` named files `${id}.${Date.now()}.zstd`, so two backups landing in the same millisecond produced the same name and the second silently replaced the first — the configured retention (`backupKeep`) was then not honoured, and an operation's pre-move safety copy could be lost. This is platform-dependent and was invisible on Windows: Linux exposes it readily (coarser clock granularity), which is why the `ubuntu` and `macos` CI jobs failed while `windows` passed. Backup names now carry a `-N` disambiguator only when the base name is already taken, so distinct operations always leave distinct files while deliberately re-stashing within one millisecond still collapses to one (bounded disk use). Both filename parsers (cleanup and listing) accept the optional suffix. Covered by a new policy case plus a direct same-millisecond assertion in the sandbox suite.
|
|
54
|
+
|
|
55
|
+
## [2.1.1] - 2026-10-05
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **`mover.doctor` self-check**: a read-only diagnostics endpoint, a "Doctor" button in the rescue panel, and a `mover_doctor` agent tool. ~13 checks cover host services (registry, persistence, projection cache, archive channel, agents, approval seam), agent-tool registration, data directories (recycle bin, backups, move history, task records), pending manual-recovery records, and workspace folder presence — each reported as pass / warn / fail with details and a summary. Intended for after DSH upgrades: see what is degraded before attempting anything else. Stays sub-second (no full scan), never mutates, and never throws — degraded hosts get fail/warn checks instead of errors.
|
|
60
|
+
- **Install and trust assets in the README**: the npm one-liner featured under the tagline (a `dsh://plugin/install` deep-link button was attempted and removed — GitHub's sanitizer strips custom-protocol links and rewrites the anchor to the badge image itself; enter through dsh.so for one-click install on Hub-aligned clients), a dsh.so risk badge (listed, L5 run-tested, risk low), a dsh-plugin-registry listing badge, and a "DSH tested 0.2.0-rc.2" badge.
|
|
61
|
+
- **Compatibility report**: `docs/compatibility/dsh-0.2.0-rc.2-2026-10-04.md` records the real desktop verification (shared data home, in-app plugin install, drag move, dialog, hot-reload fix, agent tools) and the web-profile regression status; future DSH adaptations add a dated copy each.
|
|
62
|
+
- **Safety Ledger**: the security-guarantees section is now branded around the backup-first pipeline (backup → stepwise rollback → post-move verification → recovery ledger) with an explicit never-does list (no git writes, no unbacked edits, no silent data loss, no unconfirmed destructive actions, no uploads — the plugin makes no network requests).
|
|
63
|
+
- Tests 105 → 108 (doctor all-green in sandbox, degraded-registry fail/warn behavior, recovery-record warning; agent-tool roster updated).
|
|
64
|
+
|
|
65
|
+
## [2.1.0] - 2026-10-04
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- **Agent tools**: the plugin now registers three model-callable tools through the official `dsh-tools` registry — `mover_list_sessions` (read-only listing of workspace groups and sessions with their rescue statuses, for resolving a user-named group or conversation into exact ids), `mover_move_session` (moves one session through the same locked, backup-first, verified pipeline the panel uses), and `mover_repair_sessions` (one accounting-only repair pass). Tools are plain zero-dependency tool definitions; registration is skipped silently on hosts without `dsh-tools`, leaving the panel and drag flows untouched.
|
|
70
|
+
- **User approval for mutating tools**: `mover_move_session` and `mover_repair_sessions` request an explicit user decision through the host approval seam (`dsh-user-approval`, mounted by dsh-base) before touching anything; a denial, dismissal, or unavailable answerer fails closed with a clear message, and approval-seam errors also block the call. Cancellation propagates cooperatively into the RPC layer, which finishes any in-flight rollback before stopping.
|
|
71
|
+
- `mover.status` reports an `agentTools` capability flag.
|
|
72
|
+
- Tests 97 → 104 (tool registration and capability flag, listing composition, approval-gated move success, fail-closed outcomes for denied / cancelled / unavailable / seam-error, error-code passthrough with no approval round-trip for invalid input, repair with approval).
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
75
|
+
|
|
76
|
+
- **Opaque confirm dialog on the desktop (0.2).** The desktop theme defines `--dsw-specific-menu` as a translucent glass color, so the cross-workspace confirm card blended with the text underneath. The card now forces the themed color to full alpha via CSS relative-color syntax (browsers without support keep the previous translucent behavior).
|
|
77
|
+
- **Desktop (0.2) hot-reload no longer breaks moves.** The client half accessed `ctx.connection` lazily on every RPC. After the desktop app hot-reloads or recomposes its client, the plugin's old cordis fiber is disposed, and that access throws `cannot get required service "connection" in inactive context` — surfacing as a failed-move toast even though nothing was wrong with the session. The connection service instance is now captured once at apply time (while the context is active) and reused for every call; if capture is not possible, a clear "refresh the page" message replaces the internal error in both the drag toast and the rescue-panel note paths (new `contextStale` strings, zh/en).
|
|
78
|
+
|
|
79
|
+
## [2.0.3] - 2026-09-21
|
|
80
|
+
|
|
81
|
+
### Engineering
|
|
82
|
+
|
|
83
|
+
- First publish to the public npm registry as `dsh-workspace-mover` (installs via `dsh plugin --profile web add dsh-workspace-mover`).
|
|
84
|
+
- Local quality gate `npm run check` (syntax + tests + pack dry-run); CI runs the same steps on ubuntu / windows / macos × Node 22/24.
|
|
85
|
+
- README (zh/en): CI / npm version / plugin / DSH engines badges and a host compatibility matrix (`0.1.5-rc.1` / `rc.2`; `0.1.6-alpha` pending verification).
|
|
86
|
+
- CONTRIBUTING: release checklist keeps `package.json` version, CHANGELOG, and git tags aligned; PR template requires `npm run check`.
|
|
87
|
+
|
|
88
|
+
## [2.0.2] - 2026-09-13
|
|
89
|
+
|
|
90
|
+
- Fixed GitHub Traffic badge updates when a Gist patch would delete a file that is not present; the workflow now skips missing-file deletes and avoids HTTP 422 failures.
|
|
91
|
+
- Completed the architecture documentation: the RPC endpoint list and workspace projection refresh behavior now match the implementation.
|
|
92
|
+
- Published `.tgz` assets now include the architecture documentation and screenshots, and duplicate historical changelog entries were removed.
|
|
93
|
+
|
|
94
|
+
## [2.0.1] - 2026-09-12
|
|
95
|
+
|
|
96
|
+
- Compatible with DeepSeek Harness `0.1.5-rc.1`.
|
|
97
|
+
- Release downloads stay off the README until the total exceeds 10; when shown they use shields.io like the other badges instead of a gist SVG that GitHub renders as a broken text link.
|
|
98
|
+
- Host half waits for `webServer` before registering RPC, fixing boot failures on 0.1.5.
|
|
99
|
+
- Session relocation follows the highest canonical generation (`session.vN.jsonl[.zstd]`) instead of a hard-coded `session.jsonl.zstd`.
|
|
100
|
+
- Refuse conflicting operations through in-process session/workspace locks; no `session.lock` file is created.
|
|
101
|
+
- Keep full mover feature set (rescue, repoint, trash/backup, task center); official DSH still has no cross-workspace true move.
|
|
102
|
+
|
|
103
|
+
All notable changes to this project are documented here.
|
|
104
|
+
|
|
105
|
+
## [1.4.2] - 2026-09-09
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
|
|
109
|
+
- GitHub Release tags now publish a versioned `.tgz` asset and collect its download count separately from repository clones.
|
|
110
|
+
- The public README keeps only the observed GitHub clone metric; the Release downloads badge remains visually hidden until the total exceeds 10.
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- Traffic history collection now consumes GitHub's `clones[]` response, upserts daily corrections, and labels the cumulative value with its observation start date.
|
|
115
|
+
|
|
116
|
+
## [1.4.1] - 2026-09-09
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- **GitHub traffic history now uses the real `clones[]` response field.** The collector no longer mistakes the rolling 14-day aggregate for an all-time total.
|
|
121
|
+
- Daily clone rows are upserted by date, and the badges now distinguish observed cumulative clones from GitHub's current 14-day clone and unique-cloner window.
|
|
122
|
+
- Added deterministic traffic-response contract tests and migrated legacy state without presenting the old estimate as verified history.
|
|
123
|
+
|
|
124
|
+
## [1.4.0] - 2026-09-06
|
|
125
|
+
|
|
126
|
+
### Added
|
|
127
|
+
|
|
128
|
+
- **Concurrency guards (try-acquire locks)**: per-session and per-workspace keys now serialize every entry point — single move, batch move, trash delete / restore, backup restore, and workspace re-point. A second operation touching the same key never queues or deadlocks: it fails immediately with a stable `busy` code, and the client explains that the session is still being processed. Batch inputs are de-duplicated so one batch cannot race itself.
|
|
129
|
+
- **Stable RPC error codes**: every RPC failure now carries a machine-readable `code` — `busy / conflict / not-found / invalid-input / not-writable / insufficient-space / backup-failed / rollback-failed / corrupt-artifact / unsupported / bad-request / internal-error` — mapped at the dispatch boundary, with codes attached at the source where a message pattern would mislead (e.g. a writability-probe `EEXIST` maps to `not-writable`, not `conflict`). The client reads `error.code` first and keeps the old English-message matching only as a fallback.
|
|
130
|
+
- **Minimal recovery ledger**: any "rollback also failed" path (attach-rollback failure on move; manifest-write failure plus failed move-back on delete) writes a durable record to `$DSH_HOME/workspace-mover/recovery.json` (kind, phase, session, source / target, last error, time). The scan response carries `recoveryCount`, `mover.status` reports it, and the rescue panel shows a red "needs manual recovery" row — nothing is auto-deleted and the session files plus backups always remain in place.
|
|
131
|
+
- **Capability report**: `mover.status` now enumerates which official services it actually detected (registry, persistence, projection read/write, archive channel, coordinator states, file references, agents) plus degraded features, so support questions answer themselves.
|
|
132
|
+
- Input caps: session / workspace ids are validated (non-empty, ≤ 300 chars) at every entry point; data-cleanup day ranges clamp to [1, 3650].
|
|
133
|
+
|
|
134
|
+
### Fixed
|
|
135
|
+
|
|
136
|
+
- **Backup now precedes every side effect.** `moveSession` previously detached accounting before taking the byte-level backup, so a backup failure left a detached, unaccounted session behind. The pipeline now reads the source and stashes the backup first — a backup failure aborts with `backup-failed` and nothing has been touched (no accounting, no files, no indexes).
|
|
137
|
+
- **Scan truncation kept the wrong 400.** The 400-item scan cap was applied before the mtime sort, so very large libraries showed the oldest directory-order slice while the newest sessions could vanish from the rescue panel entirely. Metadata (stat) is now collected for everything first, sorted newest-first, and only the newest 400 get header-parsed — same parse cost, correct survivors.
|
|
138
|
+
- Tests 70 → 77 (backup-failure zero side effects, concurrent same-session double move → one ok / one busy, repoint-holds-lock → move busy, error-code assertions for conflict / not-writable / unsupported / not-found / invalid-input, newest-400 scan truncation, recovery-record write + recoveryCount).
|
|
139
|
+
|
|
140
|
+
## [1.3.0] - 2026-09-05
|
|
141
|
+
|
|
142
|
+
### Added
|
|
143
|
+
|
|
144
|
+
- **Data protection summary and time-based cleanup**: one combined line over the recycle bin and backups (item counts and footprint), plus a clean-older-than-30-days action — dry-run first (shows exactly how many entries and how much space would be freed), explicit confirmation, then per-item cleanup with the freed-space report. Corrupt or stale entries never block the rest.
|
|
145
|
+
- New RPC endpoint: `mover.data.cleanup` (with `dryRun`).
|
|
146
|
+
- Tests 69 → 70.
|
|
147
|
+
|
|
148
|
+
## [1.2.0] - 2026-09-05
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **Migration task center (record-style)**: every bulk move is persisted as a task — per-session state (done / failed with last error and last attempt time), source and target paths. Failed items retry in one click; each retry resolves the session's CURRENT location (never the stale recorded path), stays individually isolated, and an "already at target" failure converges to done (idempotent). Retried moves land in the move history like normal batches, so undo still works. Records are clearable without touching moved sessions.
|
|
153
|
+
- New RPC endpoints: `mover.tasks.list / retry / forget`. `mover.moveMany` results now include a `taskId`.
|
|
154
|
+
- Tests 66 → 69.
|
|
155
|
+
|
|
156
|
+
## [1.1.0] - 2026-09-05
|
|
157
|
+
|
|
158
|
+
### Added
|
|
159
|
+
|
|
160
|
+
- **Preflight completion**: moveSession preflights before touching anything — double-accounting detection (extra owners detached during the move instead of lingering as ghosts), target writability probe, advisory disk-space check. The move detaches ALL owners and the post-move single-owner pass detaches any stale remainder; rollbacks re-attach every prior owner. Results carry a `warnings` array.
|
|
161
|
+
- Tests 64 → 66.
|
|
162
|
+
|
|
163
|
+
## [1.0.0] - 2026-09-05
|
|
164
|
+
|
|
165
|
+
### Added
|
|
166
|
+
|
|
167
|
+
- **Post-move consistency verification**: every relocation — single move, batch move, and workspace re-point — now reads the relocated archive back and requires both the session id and the rewritten cwd to match before the move counts as done; a mismatch rolls the whole move back (destination moved back, original bytes restored) exactly like any other failure. `mover.move` results carry a `verified` flag.
|
|
168
|
+
- **One-click repair**: a "Fix all" action in the rescue panel runs one scan pass and automatically fixes everything fixable — misfiled sessions are homed, unregistered sessions with a matching group are attached — while anything needing a decision (orphans, damaged archives, no matching group) is skipped with a stated reason. Results report fixed / skipped / failed counts; every fix stays individually isolated and goes through the same accounting-only paths (no files are moved).
|
|
169
|
+
- **Panel filter**: a filter box matches title, session id, path, and group across every rescue list — orphaned, unregistered, misfiled, archived, recycle bin, and backups — with per-section shown/total counts; "Home all" acts on the currently filtered set.
|
|
170
|
+
- New RPC endpoint `mover.repairAll`; `verifyRelocatedArtifact` is exported for tooling.
|
|
171
|
+
- Tests 58 → 62 (verification helper pass/mismatch cases, verified flag on moves, repair-all mixed/empty scenarios).
|
|
172
|
+
|
|
173
|
+
## [0.9.0] - 2026-09-05
|
|
174
|
+
|
|
175
|
+
### Added
|
|
176
|
+
|
|
177
|
+
- **Session recycle bin**: the rescue panel's orphaned / unregistered / misfiled / archived rows gain a "Delete" action that moves the whole session into `$DSH_HOME/workspace-mover/recycle/` behind a manifest recording everything needed to bring it back (title, original path, owning group, archive flag, projection snapshot). Deletion clears all four traces — files, workspace accounting, registry indexes, and the projection-cache entry — so nothing lingers as a ghost or stale row. The physical move happens first: a failed delete (or a failed manifest write) rolls everything back and changes nothing. Sessions still resident in harness memory are refused with a clear message (their live objects would zombie-recreate files).
|
|
178
|
+
- **Restore from the recycle bin**: one click back to the original path (re-attaching accounting, re-writing the projection title, and re-entering the archived set when the session was archived), or into any other group — which routes through the full moveSession pipeline (backup, header rewrite, hot fixes, move history). If the original spot is occupied or its workspace is gone, the restore dialog opens with a target picker.
|
|
179
|
+
- **Purge**: single item or empty-the-bin, each behind an explicit confirmation.
|
|
180
|
+
- **Backup management**: every move already kept rolling byte-level backups; they are now visible — grouped per session with copy count, total size, and date span, plus the overall footprint — with one-click restore (to the backup's original location or into any group, header round-trip verified before accounting) and per-session backup deletion.
|
|
181
|
+
- New RPC endpoints: `mover.session.delete`, `mover.trash.list / restore / purge`, `mover.backups.list / restore / deleteOne`. Projection-cache operations degrade gracefully on hosts without the service (stale entries are harmless by design); archive-set changes skip with a warning when the registry lacks the durable state channel.
|
|
182
|
+
- Tests 47 → 58 (delete four-way cleanup, resident refusal, archived delete/restore symmetry, restore to original path / other group / missing workspace, purge, backup aggregation, restore with round-trip verification, per-session backup deletion).
|
|
183
|
+
|
|
184
|
+
## [0.8.1] - 2026-09-05
|
|
185
|
+
|
|
186
|
+
### Fixed
|
|
187
|
+
|
|
188
|
+
- **Directory relocation is now safe on the copy fallback.** `moveDir` previously copied the session directory file-by-file; a mid-copy failure left a partial destination directory behind, and since neither the move nor the workspace re-point wizard cleans up the target on failure, every subsequent retry was rejected with "destination artifact already exists" until files were deleted by hand — with the half-written files (already carrying the new cwd header) polluting scan results. The fallback now uses recursive `cpSync`, cleans up a half-built destination it created on failure (retry is idempotent), and refuses — without touching either side — when the destination directory already exists non-empty (unknown content is never overwritten; the error message explains that a process-interrupt leftover contains only this session's own files and can be removed by hand).
|
|
189
|
+
- Backup pruning matched files with `startsWith(id)`; tightened to `startsWith(id + '.')` so sessions with prefix-adjacent ids (e.g. `session-x` vs `session-x-1`) can never prune each other's backups. Same-millisecond backups of one session overwrite atomically (last-wins) without breaking the retention count.
|
|
190
|
+
- Tests 41 → 47 (recursive relocation, non-empty-destination refusal with both sides untouched, injected copy-failure cleanup, rename-EEXIST fallback, flow-level residual-destination recovery through `mover.move`, backup prefix isolation and same-millisecond retention).
|
|
191
|
+
|
|
192
|
+
## [0.8.0] - 2026-09-05
|
|
193
|
+
|
|
194
|
+
### Added
|
|
195
|
+
|
|
196
|
+
- **Archived session management**: the rescue panel gains an "Archived sessions" block. Sessions hidden by the official archive action — previously unreachable from any UI — are listed under their owning group (the archive set never touches workspace accounting, so ownership survives). One click restores a session to its original group, or "Restore to…" moves it into another group through the same protected move pipeline (backup, history, undo). Sessions whose real folder matches a different workspace carry a homing suggestion, so restoring and re-homing is one decision.
|
|
197
|
+
- **Empty group detection and cleanup**: the rescue panel lists workspaces with zero members — counted against the raw registry ledger (`record.sessionIds`), so archived and ghost roster entries always count as members and never misreport. Single delete or delete-all; each delete re-checks the raw ledger right before acting, and goes through the official workspace delete API (registration only, no session files touched).
|
|
198
|
+
- **"Open folder" in the workspace "…" menu**: opens the group's directory in the system file manager (explorer.exe / open / xdg-open). The RPC only accepts paths belonging to registered workspaces, and refuses missing directories.
|
|
199
|
+
- `mover.archived`, `mover.unarchive`, `mover.openFolder` RPC endpoints; `mover.workspaces` items now carry `rawSessionCount` (raw ledger length, including archived/ghost members, alongside the index-filtered `sessionIds`). Unarchive writes through the registry's durable state channel — the same `enqueueOperation` + `setState` path the official `archiveSession` uses — so changes survive restarts; hosts without that channel fail with a clear "unsupported on this DSH version" error.
|
|
200
|
+
- Tests 35 → 41 cases (archived listing + homing suggestion, unarchive with/without a target including undo round-trip, raw ledger counting, open-folder path validation and per-platform command assembly).
|
|
201
|
+
|
|
202
|
+
### Fixed
|
|
203
|
+
|
|
204
|
+
- The group-merge "deleted empty group" toast never fired: the official `workspaces.delete()` resolves with no value on success (it rejects on failure), so checking `result.ok` mislabeled every successful delete as a failure. The new empty-group cleanup uses the same corrected semantics.
|
|
205
|
+
- Sidebar-visible titles (official auto-naming and renames) live in the projection cache, not in the on-disk session header — so auto-titled sessions showed as "Untitled session" in the archived block and scan lists. Titles now prefer the projection cache (`storages/session_projcache.json`, read-only defensive parse) and fall back to the header.
|
|
206
|
+
- "Open folder" on Windows: the window opens via explorer.exe, and ~0.8s later the plugin attempts to bring it to the front via `WScript.Shell.AppActivate` on the folder title. The attempt can still be denied by Windows' foreground-lock policy depending on what has focus at the moment — the window always opens, but may occasionally need a taskbar click. (Direct explorer spawn alone always opened behind; ShellExecute-based alternatives from the harness host silently do nothing at all.)
|
|
207
|
+
- A session whose group was deleted ("ungrouped" with no path-matching workspace) used to offer only a permanently disabled button; it now gets the same move-into-any-group dropdown as orphaned sessions.
|
|
208
|
+
|
|
209
|
+
## [0.7.0] - 2026-08-28
|
|
210
|
+
|
|
211
|
+
### Added
|
|
212
|
+
|
|
213
|
+
- Misfiled-session detection and one-click homing: the scan now recognizes sessions whose header cwd matches an existing workspace but whose bookkeeping lives elsewhere (clone-style movers, groups recreated after folder renames, double-accounting). The rescue panel lists each as "current group → correct group" with a "Home" button plus a "Home all" batch; homing detaches every wrong owner and attaches the matching workspace without touching files on disk.
|
|
214
|
+
- Group merge: the workspace header's "…" menu gains a "Move whole group…" entry (injected into the official menu; the right-click interception is gone). After the move, an emptied source group can be deleted in one confirmation through the official workspace delete API.
|
|
215
|
+
- `mover.repair` gains the `home` action kind; `mover.scan` items now carry `homeWorkspaceId` / `homeTitle` / `homePath` / `ownerWorkspaceIds` and a `misfiled` status with matching counts.
|
|
216
|
+
- Tests 32 → 35 cases.
|
|
217
|
+
|
|
218
|
+
## [0.6.3] - 2026-08-28
|
|
219
|
+
|
|
220
|
+
### Fixed
|
|
221
|
+
|
|
222
|
+
- **Critical**: multi-select drag could move a session the user never picked. Row-to-id resolution previously aligned visible rows against `workspace.sessionIds` by order; hidden blank/archived members occupy slots without rows, shifting every subsequent pairing. Ids now come from the row's own React props (`SessionNodeItem` `node.id` — the same value the official dragstart writes into the drag payload), with the alignment kept only as a fallback.
|
|
223
|
+
- The "Recently updated" re-sort after moves never executed in the field: the v0.6.1 fiber walk found nothing and v0.6.2 called `workspaces.list()`, which does not exist on the client-side service. Membership is now derived from the order account itself plus the moved session ids, and the exact recency order is written through the official store action — verified end-to-end through the real drop pipeline.
|
|
224
|
+
|
|
225
|
+
## [0.6.2] - 2026-08-28
|
|
226
|
+
|
|
227
|
+
### Fixed
|
|
228
|
+
|
|
229
|
+
- "Recently updated" re-sort after moves is now applied through the official slot system's store instance (`ctx.slots.resolveStore` on the `sidebar.workspaces` registration) instead of walking React fibers, which silently failed in the field. When the account's timestamp cache covers every member, the plugin writes the exact correct recency order itself (replicating the official comparator); otherwise it clears the account so the official reconciliation performs a full re-sort. Flat mode and manual sort are never touched.
|
|
230
|
+
- Undoing a move from the settings panel now re-fetches the workspace baseline, so the session returns to its original group immediately instead of landing in "Ungrouped" until a page refresh (also applied to relink and attach).
|
|
231
|
+
- Starting a multi-select with Ctrl+click now automatically includes the currently open session (the one row the sidebar marks with `aria-selected`), so "open A, Ctrl+click B" selects both in one step.
|
|
232
|
+
|
|
233
|
+
## [0.6.1] - 2026-08-28
|
|
234
|
+
|
|
235
|
+
### Fixed
|
|
236
|
+
|
|
237
|
+
- Bulk moves now aggregate into a single "Recent moves" entry (with per-session sources recorded inside), and one Undo sends every session back to its own original group; sessions whose source workspace disappeared stay in the entry for a retry.
|
|
238
|
+
- Picking a session with a plain click now leaves multi-select automatically — no more stale "N sessions picked" badge after navigating away.
|
|
239
|
+
- Esc clears the multi-select even when the chat input has focus.
|
|
240
|
+
- The sidebar's "Recently updated" sort no longer pins freshly moved sessions to the top: the official per-workspace order account treats any unknown session as newly active and remembers the wrong order. After every move (single, batch, whole-group) and every undo, the plugin clears that workspace's account through the official store action, triggering the same full recency re-sort as manually toggling the sort option — silently, and only while "Recently updated" is the active sort (manual custom order is never touched).
|
|
241
|
+
|
|
242
|
+
## [0.6.0] - 2026-08-28
|
|
243
|
+
|
|
244
|
+
### Added
|
|
245
|
+
|
|
246
|
+
- Bulk move via multi-select drag: Ctrl/Cmd+click toggles sidebar rows, Shift+click extends within a group, Esc clears; dragging any picked row moves the whole set. Selection is built by the plugin (the sidebar has no native multi-select) with a live count badge.
|
|
247
|
+
- Move a whole group: the workspace header's "…" menu picks a target group and bulk-moves its accounted sessions. (Later versions moved this entry off the right-click menu to avoid clashing with the official menu.)
|
|
248
|
+
- New RPC endpoint `mover.moveMany`: up to 50 sessions per batch, reusing the single-move pipeline — independent per-session backup/rollback, per-item error isolation, and per-move history entries (batch results stay undoable one by one).
|
|
249
|
+
- Row-to-session resolution aligns each group's DOM rows with `workspace.sessionIds` order and disambiguates via `mover.scan` titles, so officially hidden blank sessions cannot shift the mapping.
|
|
250
|
+
|
|
251
|
+
## [0.5.1] - 2026-08-27
|
|
252
|
+
|
|
253
|
+
### Fixed
|
|
254
|
+
|
|
255
|
+
- Workspace titles now follow folder renames during move-home when the title still equals the old folder's basename (the official `create` default); user-chosen titles are preserved.
|
|
256
|
+
- Resident sessions get their frozen in-memory header swapped to the new cwd after a move, so `@` file references rebuild their search root without a harness restart.
|
|
257
|
+
- Stale `@` file-reference search caches rooted at the old path are disposed after every move/repoint.
|
|
258
|
+
- Projection-cache checkpoints have their log identity (`identity.cwd`) aligned after header rewrites, so cold starts keep serving cached projections (session titles) instead of discarding them and lazily falling back to the group name until first open.
|
|
259
|
+
|
|
260
|
+
## [0.5.0] - 2026-08-27
|
|
261
|
+
|
|
262
|
+
### Added
|
|
263
|
+
|
|
264
|
+
- Workspace health panel: settings view lists every workspace with its official status (`ok` / `missing-dir`) and raw membership count.
|
|
265
|
+
- Move-home wizard: redirects a stale workspace in place through the entity's unified `mutate` channel (workspace id, title, order and archive flags preserved), after pre-seeding registry indexes so the membership prune keeps everyone.
|
|
266
|
+
- Batch migration of all affected sessions — accounted members plus stranded orphans still on the old path — with per-file backup, automatic rollback and resident-session write-state cleanup.
|
|
267
|
+
- Resume support: rerun the same wizard inputs and only the remaining stragglers are processed; running sessions are skipped per-file, never pruned.
|
|
268
|
+
- New RPC endpoints: `mover.ws.audit`, `mover.repoint`.
|
|
269
|
+
|
|
270
|
+
### Fixed
|
|
271
|
+
|
|
272
|
+
- Ghost detection now iterates raw `record.sessionIds`; the official filtered getter hides exactly the missing-on-disk entries ghosts are.
|
|
273
|
+
|
|
274
|
+
## [0.4.0] - 2026-08-26
|
|
275
|
+
|
|
276
|
+
### Added
|
|
277
|
+
|
|
278
|
+
- Display session titles in move confirmations, repair lists, and recent move history.
|
|
279
|
+
- Persist the latest 100 cross-workspace moves.
|
|
280
|
+
- Add `mover.history` and `mover.undo` RPC endpoints.
|
|
281
|
+
- Add one-click undo in Settings > Session Repair.
|
|
282
|
+
|
|
283
|
+
## [0.3.2]
|
|
284
|
+
|
|
285
|
+
- Added session scanning, orphan repair, unregistered-session attachment, and rollback protection.
|
package/README.md
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
<p style="font-size: 0; line-height: 1;">
|
|
10
10
|
<a href="https://github.com/PianoPrince/dsh-workspace-mover/actions/workflows/test.yml"><img alt="CI" src="https://github.com/PianoPrince/dsh-workspace-mover/actions/workflows/test.yml/badge.svg" style="height:20px; margin:0 2px;" /></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/dsh-workspace-mover"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-workspace-mover" style="height:20px; margin:0 2px;" /></a>
|
|
12
|
-
<img alt="
|
|
12
|
+
<a href="https://www.npmjs.com/package/dsh-workspace-mover"><img alt="npm weekly downloads" src="https://img.shields.io/npm/dw/dsh-workspace-mover" style="height:20px; margin:0 2px;" /></a>
|
|
13
|
+
<img alt="plugin version" src="https://img.shields.io/badge/dsh--plugin-2.3.0-4d6bfe" style="height:20px; margin:0 2px;" />
|
|
13
14
|
<img alt="DSH tested 0.2.0-rc.2" src="https://img.shields.io/badge/DSH_tested-0.2.0--rc.2-4c8dff" style="height:20px; margin:0 2px;" />
|
|
14
15
|
<img alt="Node" src="https://img.shields.io/badge/Node-%E2%89%A522-339933" style="height:20px; margin:0 2px;" />
|
|
15
16
|
</p>
|
|
@@ -53,13 +54,15 @@ DeepSeek Harness 侧边栏可以拖拽排序**同一工作区**内的会话,
|
|
|
53
54
|
|
|
54
55
|
- **🖱️ 拖拽迁移**:把空闲会话行拖到目标工作区标题行,确认后完成移动
|
|
55
56
|
- **📦 批量迁移 / 分组合并**:Ctrl/Shift 多选后整批拖移,或用组标题「⋯」菜单「整组迁移…」;源分组清空后可一键删除,两条命令完成合并(单批至多 50 个,失败互不牵连)
|
|
56
|
-
- **🚚 真迁移 · 零 token**:会话 ID
|
|
57
|
+
- **🚚 真迁移 · 零 token**:会话 ID 与完整历史原样保留,不复制第二条会话、不重新注入上下文
|
|
57
58
|
- **🏠 工作区搬家向导**:项目文件夹被移动/改名后,一键把失效分组原地重定向到新位置;id、标题、排序、归档位保持,名下会话连同旧路径散件一起迁移
|
|
58
59
|
- **🛟 会话救援**(设置 → 会话救援):一键找回「失联」「未记账」「挂错分组」的会话;已归档会话可恢复;支持一键修复与筛选
|
|
59
|
-
- **🗑️
|
|
60
|
-
- **🛡️
|
|
60
|
+
- **🗑️ 回收站与备份**:删除先进回收站,可还原到原位置或任意分组;迁移自动生成恢复快照,可按会话恢复或清理
|
|
61
|
+
- **🛡️ 数据保护**:相同会话内容只保留一份物理快照,往返迁移不会无限增长;每次迁移仍写入历史,备份列表显示快照份数与占用
|
|
61
62
|
- **⏪ 移动历史与撤回**:记录最近 100 次跨工作区移动,批量聚合为一条,整批可一键撤回
|
|
62
63
|
- **🧾 迁移任务中心**:批量迁移逐项持久化记录(完成/失败、最后错误与尝试时间),失败项一键重试——按会话当前位置重新迁移,不用陈旧路径
|
|
64
|
+
- **⏳ 忙碌会话自动排队**:运行中的会话不会触碰文件,空闲后自动重试;队列持久化,支持单项取消、单项重试和批量重试失败项
|
|
65
|
+
- **🔎 迁移预览**:确认前展示来源、目标路径、冲突、运行状态、适配器和本次预计新增备份大小;已有内容快照会明确显示复用
|
|
63
66
|
- **📂 空分组清理 / 打开文件夹**:只列出真正零成员的工作区;组菜单可直达系统文件管理器
|
|
64
67
|
- **🤖 Agent 工具**:`mover_list_sessions` / `mover_move_session` / `mover_repair_sessions` / `mover_doctor` 四个模型可调用工具——在对话里说「把这个会话挪到某组」即可触发与面板完全相同的备份回滚管线;迁移与修复执行前经宿主审批弹窗确认,未装 dsh-tools 的宿主自动停用
|
|
65
68
|
|
|
@@ -215,14 +218,32 @@ dsh plugin --profile web add "link:C:/path/to/dsh-workspace-mover"
|
|
|
215
218
|
|
|
216
219
|
## 🧩 兼容性与卸载
|
|
217
220
|
|
|
221
|
+
### 为什么自检显示“存储适配器”警告?
|
|
222
|
+
|
|
223
|
+
当前 DSH 未公开原始档案路径或原始字节迁移接口,插件使用宿主存储根目录和经过检查的 JSONL 文件布局进行迁移,因此显示 `filesystem-fallback` 警告。它表示兼容性降级,不代表迁移失败;请同时查看“存储布局”检查结果。宿主升级后应重新自检,布局未知或损坏时不要继续迁移。仅提供官方会话 handle、没有物理路径的宿主不支持物理迁移。
|
|
224
|
+
|
|
225
|
+
恢复快照独立于主会话档案;复用的快照保留首次保存时的路径,默认恢复到该路径,也可明确选择其他工作区。历史记录不意味着对应快照会永久保留,超出保留上限或手动清理后,该快照可能不存在。
|
|
226
|
+
|
|
218
227
|
### 版本兼容矩阵
|
|
219
228
|
|
|
220
229
|
| 插件版本 | 已验证 DeepSeek Harness | Node | 备注 |
|
|
221
230
|
|----------|-------------------------|------|------|
|
|
222
|
-
| 2.
|
|
231
|
+
| 2.3.0 | `0.2.0-rc.2` Desktop(用户验证部分场景) | `≥22` | 空闲会话迁移与快照复用已反馈通过;Web、队列进程重启和完整 runtime smoke 待验证 |
|
|
232
|
+
| 2.2.0 | `0.1.5-rc.1`、`0.1.5-rc.2`、**`0.2.0 桌面版`**(0.2.0-rc.2 内核) | `≥22` | 存储布局自检、Agent 工具与桌面版实测;宿主缺 `dsh-tools` 时工具自动停用 |
|
|
223
233
|
| 2.0.3 | `0.1.5-rc.1`、`0.1.5-rc.2` | `≥22` | 真迁移 / 批量 / 救援 / 回收站 / 备份;首次发布 npm |
|
|
224
234
|
| — | `0.2.0 web`(0.2.0-rc.2) | `≥22` | 与桌面版同内核,已按同一代码路径适配;web 启动场景待回归 |
|
|
225
235
|
|
|
236
|
+
### 会话档案格式验证
|
|
237
|
+
|
|
238
|
+
以下“本地通过”指仓库沙盒 fixture,不代表官方 DSH runtime 实测。Desktop 空闲迁移与快照复用已获用户反馈通过;其余真实 runtime 场景仍待验证,详见[兼容报告](docs/compatibility/dsh-0.2.0-rc.2-2026-10-13.md)。
|
|
239
|
+
|
|
240
|
+
| 档案布局 | 本地沙盒 | 官方 DSH runtime |
|
|
241
|
+
| --- | --- | --- |
|
|
242
|
+
| v3 / v4 Zstd | 迁移与撤回通过;同目录选择最高代际并保留旧文件 | 待验收 |
|
|
243
|
+
| legacy / v3 plain JSONL | 迁移与撤回通过,不升级代际 | 待验收 |
|
|
244
|
+
| 混合压缩编码 | 明确拒绝 | 待验收 |
|
|
245
|
+
| 文件名与 header 代际不符 | header 声明代际时,迁移前拒绝且字节不变 | 待验收 |
|
|
246
|
+
|
|
226
247
|
- **engines 声明**:`package.json` → `engines.dsh` ≥ `0.1.5-rc.1`,`engines.node` ≥ `22`(与 CI 矩阵 Node 22/24 一致)。
|
|
227
248
|
- **其他已知组合**:dsh-market `1.45.1`。不修改 DSH 源码,仅通过官方扩展点接入。
|
|
228
249
|
- **质量门禁**:提交前运行 `npm run check`(语法检查 + 测试 + `npm pack --dry-run`);CI 在 ubuntu / windows / macos × Node 22/24 上执行同等步骤。
|
|
@@ -247,7 +268,8 @@ dsh plugin --profile web add "link:C:/path/to/dsh-workspace-mover"
|
|
|
247
268
|
|
|
248
269
|
**具体承诺:**
|
|
249
270
|
|
|
250
|
-
-
|
|
271
|
+
- **移动前自动生成恢复快照**;相同内容(忽略迁移产生的 `cwd` 变化)复用既有快照,搬运落地后再核对会话身份与路径,不符则整体回退;
|
|
272
|
+
- **每次移动都记入历史**;历史记录保存来源、目标和所使用的快照,因此快照去重不会隐藏操作轨迹;
|
|
251
273
|
- **失败时恢复到移动前状态**(文件与记账一并恢复);
|
|
252
274
|
- **删除先进回收站**,可还原到原位置或任意分组;彻底删除需二次确认;
|
|
253
275
|
- **无法自动恢复时**,会在救援面板明确标出,需要人工确认;会话文件与备份始终保留;
|
|
@@ -265,12 +287,13 @@ dsh plugin --profile web add "link:C:/path/to/dsh-workspace-mover"
|
|
|
265
287
|
- 宿主大版本升级若改变内部结构,相关能力可能降级或需重启后生效;搬家向导在无法安全写入时会在改动任何文件之前中止并提示;
|
|
266
288
|
- **没有图形化设置页**:官方设置页需要宿主提供 `schemastery`(插件目录下不可解析,静态引入会打断启动)。策略改用环境变量配置,见下表;`mover_doctor` 会报告宿主服务与存储布局的降级情况;
|
|
267
289
|
- **降级是可观测的**:插件优先使用官方接口(取消归档 `registry.unarchiveSession`、改名 `entity.setTitle`),宿主没有时自动回退到等价实现。回退是静默的(功能不变),所以 `mover.status.capabilities` 会同时给出 `unarchiveApi` / `setTitleApi` 能力位,`degradedFeatures` 里也会列出 `unarchive-official-api` / `set-title-official-api`——真机上一眼能看出走的是哪条路。
|
|
290
|
+
- **存储适配器也会明确报告降级**:公开 persistence 句柄可用但没有物理路径时,`storageAdapter` 为 `official-handle`,诊断与预览仍可用,物理移动会明确提示不支持;有物理根目录时标记为 `filesystem-fallback`,并由 `mover_doctor` 解释原因。
|
|
268
291
|
|
|
269
292
|
### 🔧 可调策略(环境变量)
|
|
270
293
|
|
|
271
294
|
| 策略 | 默认 | 环境变量 |
|
|
272
295
|
|------|------|----------|
|
|
273
|
-
|
|
|
296
|
+
| 每个会话保留的物理快照数 | 20 | `DSH_WORKSPACE_MOVER_BACKUP_KEEP` |
|
|
274
297
|
| 移动历史保留条数 | 100 | `DSH_WORKSPACE_MOVER_HISTORY_LIMIT` |
|
|
275
298
|
| 单批移动 / 修复上限 | 50 | `DSH_WORKSPACE_MOVER_BATCH_LIMIT` |
|
|
276
299
|
| 单个工作区搬家上限 | 200 | `DSH_WORKSPACE_MOVER_REPOINT_LIMIT` |
|
|
@@ -281,6 +304,15 @@ dsh plugin --profile web add "link:C:/path/to/dsh-workspace-mover"
|
|
|
281
304
|
|
|
282
305
|
## 🆕 最近版本
|
|
283
306
|
|
|
307
|
+
### v2.3.0 · 2026-10-13
|
|
308
|
+
|
|
309
|
+
- **恢复快照复用**:会话内容相同时复用已有快照,忽略迁移产生的 `cwd` 变化;内容发生变化才新增备份。每次迁移仍记录来源、目标及快照引用,默认保留最多 20 个物理快照,兼容旧备份。
|
|
310
|
+
- **预览更清晰**:确认前显示实际来源、目标路径、冲突、运行状态及本次新增备份大小;复用时明确显示“复用已有快照”。单会话确认框支持显式选择目标工作区,修复往返迁移时目标识别错误。
|
|
311
|
+
- **忙碌会话队列**:运行中的会话不触碰文件,进入持久化队列,空闲后自动尝试;支持取消、单项及批量重试。真实 DSH 进程重启恢复仍待实测。
|
|
312
|
+
- **存储适配器与格式诊断**:显示当前适配模式及降级原因;支持 v3/v4 和 plain/Zstd 的沙盒验证,区分不支持的格式、未知布局和损坏数据,不强制升级旧格式。
|
|
313
|
+
- **分支与便携包接口**:可明确选择包含后代分支;Portable Bundle 提供导出、校验和及默认 dry-run 导入接口,冲突与已知空间不足会阻断。当前只有沙盒验证,尚未完成真实 runtime 验收。
|
|
314
|
+
- **恢复修正**:未指定文件时选择最新备份;导入空间估算包含附件。新增 npm 周下载量徽章。
|
|
315
|
+
|
|
284
316
|
### v2.2.0 · 2026-10-09
|
|
285
317
|
|
|
286
318
|
- **批量移动不再"猜"会话身份**:权威 id 通道不可用时,旧兜底会按顺序顶替一个 id;现在无法确认的行一律跳过并在确认框里如实说明(全部无法识别则整体中止,不动任何文件)
|
|
@@ -289,7 +321,7 @@ dsh plugin --profile web add "link:C:/path/to/dsh-workspace-mover"
|
|
|
289
321
|
- **存储布局自检**:反推一个真实会话的目录并验证,结果进入 `mover.status` 与自检面板(`data-layout`),把"某天突然全都找不到"提前变成可见的降级提示
|
|
290
322
|
- **孤儿备份可见可清**:会话彻底删除后其迁移备份会永久残留;现在会标记孤儿组并支持一键清理,「彻底删除」时也可顺带勾选清理
|
|
291
323
|
- **归档列表说明截断**:扫描只解析最新 400 条,较旧的归档会话可能不在列表中——UI 现在会说明
|
|
292
|
-
-
|
|
324
|
+
- **策略可调**:物理快照数 / 历史条数 / 单批上限 / 搬家上限 / 扫描上限 / 清理天数支持环境变量覆盖(`DSH_WORKSPACE_MOVER_*`)
|
|
293
325
|
- **官方接口替代私有耦合**:取消归档改走官方 `registry.unarchiveSession`(保留回退通道);标题同步改用官方 `entity.setTitle` 并与路径重定向解耦;`record.sessionIds` 的读取收敛为单一访问器
|
|
294
326
|
- **可达性与文案**:弹窗补 `aria-labelledby`、打开即聚焦、Tab 循环;Esc 尊重"输入框聚焦时不清空";清理死文案与两处漏出的英文硬编码,新增中英词条对账告警
|
|
295
327
|
- **生态元数据**:新增 `screenshots.json`(自主控制市场卡片截图);声明宿主包 `peerDependencies`(全部 `*` 且标 optional——它们只是元数据,真正的版本下限是 `engines.dsh`,运行时不匹配由能力位如实上报);修正 README/ARCHITECTURE 中长期存在的工具数量与兼容性描述漂移
|