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.
- package/README.md +2 -3
- package/client.js +13 -70
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,8 +12,7 @@ DSH 已经把**组内**会话按 `updatedAt` 倒序排好了(排序方式 =
|
|
|
12
12
|
|
|
13
13
|
会话超过 `foldDays`(默认 **3 天**)没有更新就折叠起来;整个工作区都过期时,它只剩一行工作区标题——需要翻历史时点开就行。
|
|
14
14
|
|
|
15
|
-
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
/*
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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.
|
|
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",
|