dsh-ws-recency 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -3
  2. package/client.js +13 -70
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,8 +12,7 @@ DSH 已经把**组内**会话按 `updatedAt` 倒序排好了(排序方式 =
12
12
 
13
13
  会话超过 `foldDays`(默认 **3 天**)没有更新就折叠起来;整个工作区都过期时,它只剩一行工作区标题——需要翻历史时点开就行。
14
14
 
15
- - **每组只有一个控件**:宿主自己还有没渲染的行时,用它的「展开其余 N 条会话」(N 已含被折叠的行);宿主把该组渲染完了时,才出现插件的 `展开历史 N` / `收起历史`;
16
- - 点宿主的「展开其余」会同时放出被折叠的行;它变成「收起」时,折叠也一并复原;
15
+ - **两个控件各管一件事**:宿主的「展开其余 N 条会话」负责让**宿主渲染**更多行(数字由宿主自己报,插件不再改写它);插件的 `展开历史 N` / `收起历史` 只负责把**已渲染但过期**的行折叠起来,点两次就是展开、收起一对;
17
16
  - 选中 / 运行中 / 等待处理的会话**永不折叠**(可在设置里关掉这个豁免);
18
17
  - 空白草稿行(新会话)不参与折叠判断;
19
18
  - 每 5 分钟自动重算一次,所以跨过 3 天边界的会话会自己折叠,不用刷新。
@@ -97,7 +96,7 @@ dsh plugin --profile <profile> add github:chyxhtc/dsh-ws-recency
97
96
  或固定版本的预构建包:
98
97
 
99
98
  ```powershell
100
- dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.9.0/dsh-ws-recency-0.9.0.tgz
99
+ dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.9.1/dsh-ws-recency-0.9.1.tgz
101
100
  ```
102
101
 
103
102
  装完把 `dsh-ws-recency` 加进 `~/.hypers-work/profiles/<profile>/package.json` 的 `dsh.profile.bundles`,重启应用。
package/client.js CHANGED
@@ -78,13 +78,11 @@
78
78
  var written = new Set();
79
79
  var roots = new Set();
80
80
  var hidden = new Set();
81
- var labelled = new Set();
82
81
  var toggles = new Set();
83
82
  var dots = new Set();
84
83
  var pinHidden = new Set();
85
84
  var pinHost = null;
86
85
  var expandedSections = new Set();
87
- var clickMarked = new WeakSet();
88
86
  var headerMarked = new WeakSet();
89
87
  var disposed = false;
90
88
 
@@ -325,11 +323,6 @@
325
323
  return out;
326
324
  }
327
325
 
328
- function overflowButtonOf(section) {
329
- if (typeof section.querySelector !== "function") return null;
330
- return section.querySelector('button[class*="' + OVERFLOW_TOKEN + '"]');
331
- }
332
-
333
326
  function isActiveRow(row) {
334
327
  if (typeof row.querySelector !== "function") return false;
335
328
  return row.querySelector('[data-state="ongoing"], [data-state="warning"]') !== null;
@@ -371,55 +364,7 @@
371
364
  return session !== undefined && session !== null && session.blank === true;
372
365
  }
373
366
 
374
- /**
375
- * Rewrite the host button's count so it reports what is really hidden: the
376
- * host counts only the rows it did not render, and the fold hides a few more.
377
- */
378
- function rewriteLabel(button, extraHidden) {
379
- if (button === null || button === undefined) return;
380
- if (typeof button.textContent !== "string" || button.dataset === undefined) return;
381
- var base = button.dataset.wsrBase;
382
- if (typeof base !== "string") {
383
- base = button.textContent;
384
- button.dataset.wsrBase = base;
385
- labelled.add(button);
386
- }
387
- var match = /\d+/.exec(base);
388
- if (match === null) return;
389
- var hostCount = Number(match[0]);
390
- if (!Number.isFinite(hostCount)) return;
391
- var total = hostCount + extraHidden;
392
- var text = total <= 0 ? base : base.slice(0, match.index) + String(total) + base.slice(match.index + match[0].length);
393
- if (button.textContent !== text) button.textContent = text;
394
- }
395
-
396
- function releaseLabel(button) {
397
- if (button === null || button === undefined || button.dataset === undefined) return;
398
- var base = button.dataset.wsrBase;
399
- if (typeof base === "string") {
400
- if (button.textContent !== base) button.textContent = base;
401
- delete button.dataset.wsrBase;
402
- }
403
- labelled.delete(button);
404
- }
405
-
406
- function markButton(button, key) {
407
- if (typeof button.addEventListener !== "function" || clickMarked.has(button)) return;
408
- clickMarked.add(button);
409
- button.addEventListener("click", function () {
410
- if (disposed) return;
411
- /* The host's own control is the only one while it exists, so it has to
412
- carry the fold too: `aria-expanded` still reads the pre-click state
413
- (React delegates at the root, this listener runs first), which is
414
- exactly what decides whether the click reveals or hides. */
415
- var expanded = typeof button.getAttribute === "function"
416
- && button.getAttribute("aria-expanded") === "true";
417
- if (expanded) expandedSections.delete(key);
418
- else expandedSections.add(key);
419
- schedule();
420
- });
421
- }
422
-
367
+ /** Collapsing a group resets its fold state, so the click is observed. */
423
368
  function markHeader(header, key) {
424
369
  if (typeof header.addEventListener !== "function" || headerMarked.has(header)) return;
425
370
  headerMarked.add(header);
@@ -441,11 +386,15 @@
441
386
  button.addEventListener("click", function (event) {
442
387
  if (disposed) return;
443
388
  if (event !== undefined && typeof event.stopPropagation === "function") event.stopPropagation();
444
- onClick();
389
+ var current = button.wsrOnClick;
390
+ if (typeof current === "function") current();
445
391
  });
446
392
  section.appendChild(button);
447
393
  toggles.add(button);
448
394
  }
395
+ /* The handler is refreshed every pass: the button toggles between "show"
396
+ and "hide", and a captured first callback would only ever show. */
397
+ button.wsrOnClick = onClick;
449
398
  if (button.textContent !== label) button.textContent = label;
450
399
  return button;
451
400
  }
@@ -469,10 +418,7 @@
469
418
  var entry = entries[i];
470
419
  var section = entry.section;
471
420
  var rows = rowElements(section);
472
- var hostButton = overflowButtonOf(section);
473
421
  markHeader(entry.header, entry.key);
474
- if (hostButton !== null) markButton(hostButton, entry.key);
475
- releaseLabel(hostButton);
476
422
 
477
423
  var expanded = expandedSections.has(entry.key);
478
424
  var folded = 0;
@@ -493,14 +439,13 @@
493
439
  }
494
440
  }
495
441
 
496
- /* ONE control per group: while the host offers its own "show more"
497
- button, that button is the control (its count already carries the
498
- folded rows below). Only a group the host finished rendering gets
499
- this plugin's own toggle. */
500
- if (hostButton !== null) {
501
- dropToggle(section);
502
- rewriteLabel(hostButton, expanded ? 0 : folded);
503
- } else if (expanded) {
442
+ /* The host's own "show more" button and this fold are two different
443
+ things: the host decides which rows it RENDERS, this plugin decides
444
+ which rendered rows stay VISIBLE. Touching the host's label or its
445
+ click made the two fight (a count nobody could trust, and a collapse
446
+ that never came back), so they stay separate: the group gets its own
447
+ "show history" control whenever something is folded. */
448
+ if (expanded) {
504
449
  (function (entryKey) {
505
450
  ensureToggle(section, entryKey, t("fold.hide"), function () {
506
451
  expandedSections.delete(entryKey);
@@ -958,8 +903,6 @@
958
903
  if (element.removeAttribute !== undefined) element.removeAttribute(HIDDEN_ATTR);
959
904
  });
960
905
  hidden.clear();
961
- labelled.forEach(function (button) { releaseLabel(button); });
962
- labelled.clear();
963
906
  toggles.forEach(function (button) { button.remove(); });
964
907
  toggles.clear();
965
908
  dots.forEach(function (dot) { dot.remove(); });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ws-recency",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
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, and session delete into a recoverable trash.",
5
5
  "license": "MIT",
6
6
  "author": "chyxhtc",