dsh-ws-recency 0.9.1 → 0.9.2
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 +4 -2
- package/client.js +56 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,9 @@ DSH 已经把**组内**会话按 `updatedAt` 倒序排好了(排序方式 =
|
|
|
12
12
|
|
|
13
13
|
会话超过 `foldDays`(默认 **3 天**)没有更新就折叠起来;整个工作区都过期时,它只剩一行工作区标题——需要翻历史时点开就行。
|
|
14
14
|
|
|
15
|
-
-
|
|
15
|
+
- **每组一个控件**:宿主的「展开其余 N 条会话」被隐藏,由插件的 `展开历史 N` / `收起历史` 接管。N = 宿主还没渲染的行 + 已折叠的过期行;
|
|
16
|
+
- 点「展开历史」→ 插件逐轮驱动宿主那个隐藏按钮(每轮它会多渲染 5 条,剩下 ≤5 条时一次全出),直到整组都渲染出来,同时展开过期行——**一次点到全展开**;
|
|
17
|
+
- 点「收起历史」→ 重新折叠过期行(宿主已渲染的部分仍由插件按时间折叠,不会丢失);
|
|
16
18
|
- 选中 / 运行中 / 等待处理的会话**永不折叠**(可在设置里关掉这个豁免);
|
|
17
19
|
- 空白草稿行(新会话)不参与折叠判断;
|
|
18
20
|
- 每 5 分钟自动重算一次,所以跨过 3 天边界的会话会自己折叠,不用刷新。
|
|
@@ -96,7 +98,7 @@ dsh plugin --profile <profile> add github:chyxhtc/dsh-ws-recency
|
|
|
96
98
|
或固定版本的预构建包:
|
|
97
99
|
|
|
98
100
|
```powershell
|
|
99
|
-
dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.9.
|
|
101
|
+
dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.9.2/dsh-ws-recency-0.9.2.tgz
|
|
100
102
|
```
|
|
101
103
|
|
|
102
104
|
装完把 `dsh-ws-recency` 加进 `~/.hypers-work/profiles/<profile>/package.json` 的 `dsh.profile.bundles`,重启应用。
|
package/client.js
CHANGED
|
@@ -69,6 +69,8 @@
|
|
|
69
69
|
var MIN_DAYS = 1;
|
|
70
70
|
var MAX_DAYS = 90;
|
|
71
71
|
var DEFAULT_DAYS = 3;
|
|
72
|
+
/** Safety stop for driving the host's own "show more" (5 rows per click). */
|
|
73
|
+
var MAX_EXPAND_CLICKS = 40;
|
|
72
74
|
var TICK_MS = 5 * 60 * 1000;
|
|
73
75
|
|
|
74
76
|
var data = { sessions: null, workspaces: null, settings: null, statuses: null, actions: null, service: null, t: null };
|
|
@@ -82,6 +84,7 @@
|
|
|
82
84
|
var dots = new Set();
|
|
83
85
|
var pinHidden = new Set();
|
|
84
86
|
var pinHost = null;
|
|
87
|
+
var expandClicks = new Map();
|
|
85
88
|
var expandedSections = new Set();
|
|
86
89
|
var headerMarked = new WeakSet();
|
|
87
90
|
var disposed = false;
|
|
@@ -91,6 +94,7 @@
|
|
|
91
94
|
"[" + ROOT_ATTR + '="true"]>*{flex:0 0 auto}',
|
|
92
95
|
"[" + HIDDEN_ATTR + '="true"]{display:none !important}',
|
|
93
96
|
"[" + PIN_HIDDEN_ATTR + '="true"]{display:none !important}',
|
|
97
|
+
'[class*="' + OVERFLOW_TOKEN + '"]{display:none !important}',
|
|
94
98
|
".wsr-pin{display:flex;flex-direction:column;flex:0 0 auto;padding:2px 0 6px;margin-bottom:4px;border-bottom:.5px solid var(--dsw-alias-border-l2)}",
|
|
95
99
|
".wsr-pin-head{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary);padding:4px 12px 2px}",
|
|
96
100
|
".wsr-pin-row{display:flex;align-items:center;gap:8px;height:30px;padding:0 12px;border-radius:6px;cursor:pointer}",
|
|
@@ -364,6 +368,22 @@
|
|
|
364
368
|
return session !== undefined && session !== null && session.blank === true;
|
|
365
369
|
}
|
|
366
370
|
|
|
371
|
+
/** The host's own "show more" button, hidden by CSS but still clickable. */
|
|
372
|
+
function overflowButtonOf(section) {
|
|
373
|
+
if (typeof section.querySelector !== "function") return null;
|
|
374
|
+
return section.querySelector('button[class*="' + OVERFLOW_TOKEN + '"]');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** The count the host reports on its own button, 0 when there is none. */
|
|
378
|
+
function labelNumber(button) {
|
|
379
|
+
if (button === null || button === undefined) return 0;
|
|
380
|
+
var text = typeof button.textContent === "string" ? button.textContent : "";
|
|
381
|
+
var match = /\d+/.exec(text);
|
|
382
|
+
if (match === null) return 0;
|
|
383
|
+
var value = Number(match[0]);
|
|
384
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
367
387
|
/** Collapsing a group resets its fold state, so the click is observed. */
|
|
368
388
|
function markHeader(header, key) {
|
|
369
389
|
if (typeof header.addEventListener !== "function" || headerMarked.has(header)) return;
|
|
@@ -411,6 +431,13 @@
|
|
|
411
431
|
* Fold the rows the host rendered that have not changed for `foldDays`, and
|
|
412
432
|
* offer the group's own control to bring them back. A workspace whose every
|
|
413
433
|
* session is that old therefore renders as a bare header.
|
|
434
|
+
*
|
|
435
|
+
* The host's own "show more" button is hidden (CSS) and driven from here: it
|
|
436
|
+
* only renders five rows at a time and cannot collapse once everything is
|
|
437
|
+
* rendered, which made "show more" look broken next to a fold. Expanding the
|
|
438
|
+
* group now clicks that hidden button once per pass until the host has
|
|
439
|
+
* rendered every session, so one click reveals everything; collapsing just
|
|
440
|
+
* folds the stale rows again.
|
|
414
441
|
*/
|
|
415
442
|
function foldRows(entries, settings, sessions, now) {
|
|
416
443
|
var cutoff = now - settings.foldDays * DAY;
|
|
@@ -418,9 +445,29 @@
|
|
|
418
445
|
var entry = entries[i];
|
|
419
446
|
var section = entry.section;
|
|
420
447
|
var rows = rowElements(section);
|
|
448
|
+
var hostButton = overflowButtonOf(section);
|
|
421
449
|
markHeader(entry.header, entry.key);
|
|
422
450
|
|
|
423
451
|
var expanded = expandedSections.has(entry.key);
|
|
452
|
+
var hostHidden = hostButton === null ? 0 : labelNumber(hostButton);
|
|
453
|
+
var hostExpanded = hostButton !== null
|
|
454
|
+
&& typeof hostButton.getAttribute === "function"
|
|
455
|
+
&& hostButton.getAttribute("aria-expanded") === "true";
|
|
456
|
+
if (expanded && hostButton !== null && !hostExpanded) {
|
|
457
|
+
/* The host renders five more per click (or everything when five or
|
|
458
|
+
fewer remain) and reports `aria-expanded` once nothing is hidden.
|
|
459
|
+
Stopping on that flag is what keeps the loop from collapsing the
|
|
460
|
+
very thing it just expanded - a click on an expanded host button
|
|
461
|
+
resets the watermark. */
|
|
462
|
+
var used = expandClicks.get(entry.key) || 0;
|
|
463
|
+
if (used < MAX_EXPAND_CLICKS) {
|
|
464
|
+
expandClicks.set(entry.key, used + 1);
|
|
465
|
+
hostButton.click();
|
|
466
|
+
}
|
|
467
|
+
} else if (!expanded) {
|
|
468
|
+
expandClicks.delete(entry.key);
|
|
469
|
+
}
|
|
470
|
+
|
|
424
471
|
var folded = 0;
|
|
425
472
|
for (var j = 0; j < rows.length; j += 1) {
|
|
426
473
|
var row = rows[j];
|
|
@@ -439,22 +486,22 @@
|
|
|
439
486
|
}
|
|
440
487
|
}
|
|
441
488
|
|
|
442
|
-
/*
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
"show history" control whenever something is folded. */
|
|
489
|
+
/* ONE control per group: its count is everything the group still hides,
|
|
490
|
+
both the rows the host did not render and the stale rows this plugin
|
|
491
|
+
folded. Expanding drives the hidden host button until nothing is left
|
|
492
|
+
unrendered, so one click reveals the whole group. */
|
|
493
|
+
var remaining = folded + hostHidden;
|
|
448
494
|
if (expanded) {
|
|
449
495
|
(function (entryKey) {
|
|
450
496
|
ensureToggle(section, entryKey, t("fold.hide"), function () {
|
|
451
497
|
expandedSections.delete(entryKey);
|
|
498
|
+
expandClicks.delete(entryKey);
|
|
452
499
|
schedule();
|
|
453
500
|
});
|
|
454
501
|
})(entry.key);
|
|
455
|
-
} else if (
|
|
502
|
+
} else if (remaining > 0) {
|
|
456
503
|
(function (entryKey) {
|
|
457
|
-
ensureToggle(section, entryKey, t("fold.show", { n:
|
|
504
|
+
ensureToggle(section, entryKey, t("fold.show", { n: remaining }), function () {
|
|
458
505
|
expandedSections.add(entryKey);
|
|
459
506
|
schedule();
|
|
460
507
|
});
|
|
@@ -913,6 +960,7 @@
|
|
|
913
960
|
pinHidden.clear();
|
|
914
961
|
if (pinHost !== null && pinHost.parentElement !== null) pinHost.remove();
|
|
915
962
|
pinHost = null;
|
|
963
|
+
expandClicks.clear();
|
|
916
964
|
roots.forEach(function (root) { root.removeAttribute(ROOT_ATTR); });
|
|
917
965
|
roots.clear();
|
|
918
966
|
var marked = document.querySelectorAll("[" + STATE_ATTR + "]");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ws-recency",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
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",
|