dsh-ws-recency 0.11.1 → 0.11.3

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/README.md CHANGED
@@ -88,7 +88,7 @@ DSH 原生的置顶只把会话顶到**它所属工作区分组的第一行**,
88
88
  3. 把旧日志目录移进 `.trash/ws-recency/<id>-move-<时间戳>`(既是备份,也腾出这个 id);
89
89
  4. 用新 `cwd`、原 id 重建日志,再回放全部事件;
90
90
  5. 校验新 header 的 cwd;
91
- 6. 先 attach 到目标工作区(失败就回滚原目录),再 detach 旧工作区;
91
+ 6. 把新 cwd 同步到工作区的 header 索引和这个会话的内存对象(否则宿主会用旧目录拒绝 attach),再 attach 到目标(失败就回滚原目录),最后 detach 旧工作区;
92
92
  7. 删投影缓存,让它按新路径重建。
93
93
 
94
94
  **只移动会话**:对话框里明确提示——它在旧工作区里创建/修改的文件不会跟着走,仍留在原目录(附件与 rewind 快照按会话 id 存,不受影响)。
@@ -130,7 +130,7 @@ dsh plugin --profile <profile> add github:chyxhtc/dsh-ws-recency
130
130
  或固定版本的预构建包:
131
131
 
132
132
  ```powershell
133
- dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.11.1/dsh-ws-recency-0.11.1.tgz
133
+ dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.11.3/dsh-ws-recency-0.11.3.tgz
134
134
  ```
135
135
 
136
136
  装完把 `dsh-ws-recency` 加进 `~/.hypers-work/profiles/<profile>/package.json` 的 `dsh.profile.bundles`,重启应用。
package/client.js CHANGED
@@ -212,6 +212,7 @@
212
212
  "move.current": "当前",
213
213
  "move.working": "移动中…(会先停止会话)",
214
214
  "move.done": "已移动到「{workspace}」。若列表没刷新,切换一下工作区或重启应用。",
215
+ "move.doneLive": "\n\n这个会话刚才是打开状态:建议重启应用后再继续对话,避免它沿用旧的目录。",
215
216
  "move.failed": "移动失败:",
216
217
  "stats.chart": "消耗分布",
217
218
  "stats.details.show": "显示明细 ▾",
@@ -265,6 +266,7 @@
265
266
  "move.current": "current",
266
267
  "move.working": "Moving\u2026 (the session is stopped first)",
267
268
  "move.done": "Moved to \"{workspace}\". If the list has not refreshed, switch workspaces or restart the app.",
269
+ "move.doneLive": "\n\nThe session was open: restart the app before continuing it so it does not keep using the old directory.",
268
270
  "move.failed": "Move failed: ",
269
271
  "stats.chart": "Where the tokens went",
270
272
  "stats.details.show": "Show details",
@@ -1447,6 +1449,7 @@
1447
1449
  .then(function (result) {
1448
1450
  if (result.json !== null && result.json.ok === true) {
1449
1451
  body.textContent = t("move.done", { workspace: label });
1452
+ if (result.json.live === true) body.textContent += t("move.doneLive");
1450
1453
  return;
1451
1454
  }
1452
1455
  var reason = (result.json !== null && result.json.error) || (result.text || "").trim().slice(0, 160) || "(empty response)";
package/index.js CHANGED
@@ -545,6 +545,45 @@ export async function moveSessionToWorkspace(ctx, sessionId, workspaceId) {
545
545
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
546
546
  }
547
547
 
548
+ /* The moved cwd lives in three places: the log (just rewritten), the Workspace
549
+ registry's header index, and the live Session object when this process still
550
+ has the session open. The registry validates against its own view, so both the
551
+ cached header and the live one have to follow - otherwise an open session is
552
+ refused with its old directory. */
553
+ const movedHeader = { ...header, cwd: targetPath };
554
+ /* Cordis throws on an undeclared service, so the probe is guarded. */
555
+ let wasLive = false;
556
+ try {
557
+ wasLive = typeof ctx.sessions?.get === "function" && ctx.sessions.get(sessionId) !== undefined;
558
+ } catch {
559
+ wasLive = false;
560
+ }
561
+ try {
562
+ if (typeof ctx.workspaceRegistry.indexHeader === "function") await ctx.workspaceRegistry.indexHeader(movedHeader);
563
+ } catch {
564
+ /* the index rebuilds from disk on its own */
565
+ }
566
+ try {
567
+ const live = typeof ctx.sessions?.get === "function" ? ctx.sessions.get(sessionId) : undefined;
568
+ if (live !== undefined && live !== null && live.header !== undefined) live.header = movedHeader;
569
+ } catch {
570
+ /* an immutable live header: the attach below reports it */
571
+ }
572
+
573
+ let seenCwd = targetPath;
574
+ try {
575
+ if (typeof ctx.workspaceRegistry.readSessionHeader === "function") {
576
+ const seen = await ctx.workspaceRegistry.readSessionHeader(sessionId);
577
+ if (seen !== undefined && seen !== null && typeof seen.cwd === "string") seenCwd = seen.cwd;
578
+ }
579
+ } catch {
580
+ seenCwd = targetPath;
581
+ }
582
+ if (seenCwd !== targetPath) {
583
+ await rollback();
584
+ return { ok: false, error: `the app still holds this session's old directory (${seenCwd}); restart the app and move it again` };
585
+ }
586
+
548
587
  /* Attach first, detach second: a refused attach must not orphan the session. */
549
588
  try {
550
589
  await target.attachSession(sessionId);
@@ -573,7 +612,7 @@ export async function moveSessionToWorkspace(ctx, sessionId, workspaceId) {
573
612
  /* the cache is derived data */
574
613
  }
575
614
 
576
- return { ok: true, workspace: target.id, path: targetPath, detached, backup };
615
+ return { ok: true, workspace: target.id, path: targetPath, detached, backup, live: wasLive };
577
616
  }
578
617
 
579
618
  /** POST { sessionId, workspaceId } -> move that session to another workspace. */
@@ -659,7 +698,7 @@ export function apply(ctx) {
659
698
  }), "ws-recency: stats route");
660
699
  });
661
700
 
662
- webCtx.inject(["sessionPersistence", "workspaceRegistry"], (moveCtx) => {
701
+ webCtx.inject(["sessionPersistence", "workspaceRegistry", "sessions"], (moveCtx) => {
663
702
  moveMounted = true;
664
703
  webCtx.effect(() => server.register({
665
704
  kind: "exact",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ws-recency",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "Sidebar session management for DeepSeek Harness: workspace groups sorted by latest activity, stale history folded, a global pinned section, follow-up marks, session delete into a recoverable trash, per-session token statistics split by tool, and moving a session to another workspace.",
5
5
  "license": "MIT",
6
6
  "author": "chyxhtc",