dsh-sessions-manager 3.7.3 → 3.7.5
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.en.md +7 -0
- package/README.md +7 -0
- package/lib/client.js +115 -11
- package/lib/client.js.map +2 -2
- package/lib/index.js +116 -9
- package/lib/index.js.map +3 -3
- package/package.json +1 -1
- package/src/active-session.js +87 -0
- package/src/auto-archive.js +9 -2
- package/src/client/index.jsx +132 -10
- package/src/index.js +88 -6
package/README.en.md
CHANGED
|
@@ -91,6 +91,7 @@ DSH 0.1.5 upgrades the session log format to **v3**, and 0.1.7 upgrades it again
|
|
|
91
91
|
- Migration is **one-way, with no downgrade read**: after opening sessions on a newer runtime, rolling the runtime back makes those sessions unreadable. Back up `~/.dsh/sessions` before a rollback.
|
|
92
92
|
- Only **supported** old logs are migrated; unknown events or corrupted data are **refused without any repair**. Such sessions surface as `SessionFormatUnsupportedMigrationError` / `SessionFormatError` on read/move — the plugin cannot repair them and reports the error verbatim.
|
|
93
93
|
- **Since 0.1.7 newly created sessions strictly require a v4 header**: from v3.7.2 this plugin re-samples the session header against the current backend's format during cross-workspace moves — sessions created in older formats (v3 and earlier) can be moved again, and the relocated copy lands directly on the current format (verified end-to-end against a real v3 log). Earlier plugin versions fail to move such sessions on 0.1.7.
|
|
94
|
+
- **0.2.0 is still v4**: the current format version is **probed dynamically** from the backend's format catalog package (never hardcoded), so 0.1.7 and 0.2.0 share one code path.
|
|
94
95
|
|
|
95
96
|
## Screenshots
|
|
96
97
|
|
|
@@ -212,6 +213,12 @@ lib/client.js pre-built client (ModuleLoader CJS handshake)
|
|
|
212
213
|
- `0.1.3-alpha.1`: snapshot lists and chunked `SessionHandle` read flows are supported. Permanent purge and cross-workspace move are available through guarded path derivation + write-ownership probes (see the behavior notes below), and disable themselves whenever a safe path cannot be verified; other management capabilities are unaffected. The panel shows the effective capabilities.
|
|
213
214
|
- `0.1.5-rc.1` / `0.1.5-rc.2` (both verified): the session log format is upgraded to **v3** and this plugin is adapted — it reads the **highest generation** (matching the runtime), tolerates v0/v2/v3 generations side by side, follows the new `SessionHandle.read()` shape (`{ eventState, events }`), moves sessions as **whole-directory moves** (reclaiming superseded-generation copies automatically), and queues moves for sessions DSH holds open (see "Moving an active session" above).
|
|
214
215
|
- `0.1.7-rc.2` (verified): the session format is upgraded again to **v4** and the format catalog moves to its own package; this plugin is adapted — reads go through the official automatic migration, and cross-workspace moves re-sample the header against the backend's current format (sessions created on older formats can be moved again, and the relocated copy lands on the current format).
|
|
216
|
+
- `0.2.0-rc.1` / `0.2.0-rc.2` (both verified):
|
|
217
|
+
- Still format **v4** (the version is probed from the backend's format catalog, never hardcoded).
|
|
218
|
+
- `ctx.sessions` is now a session **data-stream** service with no `open`: opening a session goes through the official `uiWorkspace.openSession` — the settings panel's "open session" action and subagent navigation are both adapted (issue #12).
|
|
219
|
+
- Install gate: 0.2.0 validates the `@deepseek-ai/dsh*` ranges in a plugin's `peerDependencies`; this plugin widened them to `>=0.1.0-rc.6`, which passes on both `0.1.7-rc.2` and `0.2.0-rc.2` (issue #13).
|
|
220
|
+
- `ctx.storageDomain` is the **domain data form** in 0.2.0: writes are schema-validated and durable before they resolve. This plugin only writes fields that exist in the official domain schema, verified end-to-end against a **real domain + real WorkspaceRegistry** (archive / restore / list / storage stats / cross-workspace move) with a read-back from the storage medium to prove the archive state really persisted.
|
|
221
|
+
- Active-session detection: since 0.1.7 the host exposes no "current session" accessor (all three historical probes come back empty), so the **client reports the open session id every 15 seconds** and the host trusts it only within a 45-second freshness window. It backs two guards: refusing to move the session you are looking at (409 / queued) and skipping it in auto-archive. A stopped heartbeat (panel closed, tab hidden, process gone) means "cannot prove it is active" — the move is allowed rather than locking the session forever.
|
|
215
222
|
- Unverified future runtimes expose only capabilities the plugin can safely identify; method presence alone is not presented as behavioral compatibility.
|
|
216
223
|
|
|
217
224
|
### Behavior differences and degradations on the SessionHandle era (`0.1.3+`)
|
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ DSH 0.1.5 把会话日志格式升级到 **v3**,0.1.7 再升到 **v4**,均
|
|
|
91
91
|
- 迁移**单向、不支持降级读取**:升级并打开过会话之后,把 runtime 回滚到旧版本会导致那些会话无法读取。回滚前请先备份 `~/.dsh/sessions`。
|
|
92
92
|
- 官方只迁移**受支持的旧日志**;遇到未知事件或损坏数据会**拒绝迁移且不做任何修复**。这类会话在插件里会表现为读取/移动报 `SessionFormatUnsupportedMigrationError` / `SessionFormatError`——插件无法代修,只能如实报错(可先确认该会话是否确实异常,再决定保留或删除)。
|
|
93
93
|
- **0.1.7 起新建会话严格要求 v4 头部**:本插件自 v3.7.2 起在跨工作区移动时自动按当前后端的格式重新采样会话头——旧格式(v3 及更早)会话可以正常移动,且移动后的副本直接落在当前格式(已用真实 v3 旧日志端到端实测)。更早的插件版本在 0.1.7 上移动旧格式会话会失败。
|
|
94
|
+
- **0.2.0 仍是 v4**:当前格式版本由插件从后端的格式目录包**动态探测**(不写死版本号),所以 0.1.7 / 0.2.0 共用同一套处理。
|
|
94
95
|
|
|
95
96
|
## 截图
|
|
96
97
|
|
|
@@ -213,6 +214,12 @@ lib/client.js 预构建 client(ModuleLoader CJS handshake)
|
|
|
213
214
|
- `0.1.5-rc.1` / `0.1.5-rc.2`(已实测):会话日志格式升级到 **v3**,本插件已适配——按**最高代**读取(与官方一致)、v0/v2/v3 多代共存、跟随 `SessionHandle.read()` 的新返回结构
|
|
214
215
|
(`{ eventState, events }`)、跨工作区移动按**整目录搬运**并自动回收被取代的旧代副本;被 DSH 打开着的会话改为**排队延迟移动**(见上文「移动活跃会话」)。
|
|
215
216
|
- `0.1.7-rc.2`(已实测):会话格式再升 **v4**,格式版本目录拆分到独立包;本插件已适配——读取走官方自动迁移,跨工作区移动自动按后端当前格式重采样会话头(旧格式会话可正常移动,落盘即当前格式)。
|
|
217
|
+
- `0.2.0-rc.1` / `0.2.0-rc.2`(均已实测):
|
|
218
|
+
- 会话格式仍为 **v4**(版本由后端格式目录包动态探测,不写死)。
|
|
219
|
+
- `ctx.sessions` 已退化为会话**数据流**服务(不再提供 `open`):打开会话改走官方 `uiWorkspace.openSession`——设置面板与侧栏的「打开会话」、子代理导航均已适配(issue #12)。
|
|
220
|
+
- 安装门禁:0.2.0 会校验插件 `peerDependencies` 中的 `@deepseek-ai/dsh*` 版本范围,本插件已放宽为 `>=0.1.0-rc.6`,`0.1.7-rc.2` 与 `0.2.0-rc.2` 通过(issue #13)。
|
|
221
|
+
- 存储域(`ctx.storageDomain`)在 0.2.0 是**领域数据形式**:写入经 schema 校验并在返回前落盘。本插件只写官方域 schema 内的字段,已用**真实域 + 真实 WorkspaceRegistry** 端到端实测(归档 / 恢复 / 列表 / 存储统计 / 跨工作区移动),并回到磁盘介质核验归档状态真的持久化。
|
|
222
|
+
- 活跃会话判定:0.1.7 起 host 侧不再有「当前会话」访问器(三个历史探测全部落空),改由**客户端每 15 秒上报**当前会话 id、host 只在 45 秒新鲜期内采信;用于「移动正在看的会话」(409 / 排队)与「自动归档跳过当前会话」两条保护。心跳停止(面板关闭、标签页隐藏、进程退出)即视为无法证明活跃,放行移动而不是把会话永久锁死。
|
|
216
223
|
- 未经验证的未来 Runtime 默认只开放能够识别的安全能力;插件不会用方法存在与否冒充行为兼容。
|
|
217
224
|
|
|
218
225
|
### 新版 Runtime(SessionHandle 世代,`0.1.3+`)的行为差异与降级说明
|
package/lib/client.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
apply: () => apply,
|
|
34
|
+
dsmActiveSessionId: () => dsmActiveSessionId,
|
|
34
35
|
inject: () => inject
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -329,7 +330,8 @@ var CSS = `
|
|
|
329
330
|
.archv{--dsm-radius-tag:9px;--dsm-radius-ctl:9px;--dsm-radius-sheet:10px;--dsm-radius-card:12px;display:flex;flex-direction:column;gap:4px;max-width:800px;padding:8px 2px 28px}
|
|
330
331
|
.archv-head{display:flex;align-items:center;gap:10px;margin:0 0 2px}
|
|
331
332
|
.archv-title{font-size:16px;font-weight:650;color:var(--dsw-alias-label-primary);letter-spacing:-0.01em;margin:0}
|
|
332
|
-
.archv-stamp{font-size:11px;font-weight:500;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-secondary);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:2px 8px;white-space:nowrap;cursor:
|
|
333
|
+
.archv-stamp{font-size:11px;font-weight:500;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-secondary);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:2px 8px;white-space:nowrap;cursor:pointer;transition:color .15s ease,border-color .15s ease}
|
|
334
|
+
.archv-stamp:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3)}
|
|
333
335
|
.archv-count{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-subtle);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:1px 8px;flex:none}
|
|
334
336
|
.archv-sub{font-size:12px;line-height:1.55;color:var(--dsw-alias-label-tertiary);margin:0 0 12px;max-width:64ch}
|
|
335
337
|
.archv-err{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 12px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary) 40%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 8%,transparent);border-radius:var(--dsm-radius-sheet);color:var(--dsw-alias-state-error-primary);font-size:12px;margin-bottom:10px}
|
|
@@ -354,8 +356,11 @@ var CSS = `
|
|
|
354
356
|
.sess-fbtn-on{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3)}
|
|
355
357
|
.sess-tools{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;margin:0 0 8px}
|
|
356
358
|
.sess-tools-4{grid-template-columns:repeat(auto-fit,minmax(132px,1fr))}
|
|
357
|
-
/* T4 \u8D77\u641C\u7D22\u884C\u6709 5 \u4E2A\u5B57\u6BB5\uFF08\u641C\u7D22/\u5DE5\u4F5C\u533A/\u6807\u7B7E/\u6392\u5E8F/\u5206\u7EC4\uFF09\uFF1A\
|
|
358
|
-
|
|
359
|
+
/* T4 \u8D77\u641C\u7D22\u884C\u6709 5 \u4E2A\u5B57\u6BB5\uFF08\u641C\u7D22/\u5DE5\u4F5C\u533A/\u6807\u7B7E/\u6392\u5E8F/\u5206\u7EC4\uFF09\uFF1A\u56FA\u5B9A 5 \u5217 + minmax(0,1fr)
|
|
360
|
+
\u4E00\u884C\u6392\u6EE1\u2014\u2014auto-fit(minmax(124px,\u2026)) \u5728\u9762\u677F\u5BBD\u5EA6\u4E0D\u8DB3 5\xD7124+gap \u65F6\u4F1A\u628A\u6700\u540E
|
|
361
|
+
\u4E00\u5217\u6324\u5230\u7B2C\u4E8C\u884C\uFF08\u5206\u7EC4\u5B64\u884C\uFF09\u3002minmax(0,1fr) \u5141\u8BB8\u5217\u5747\u5206\u6536\u7F29\uFF0Cselect/input
|
|
362
|
+
\u5404\u81EA\u622A\u65AD\uFF1B<640px \u4ECD\u7531\u4E0B\u65B9\u65AD\u70B9\u6536\u6210\u5355\u5217\u3002 */
|
|
363
|
+
.sess-tools-5{grid-template-columns:repeat(5,minmax(0,1fr))}
|
|
359
364
|
.dsm-kids{display:flex;flex-direction:column;gap:6px;margin:10px 0 2px;margin-left:43px;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l3)}
|
|
360
365
|
.dsm-kid .dsm-kids{margin-left:8px;margin-top:6px}
|
|
361
366
|
.dsm-kids-toggle{appearance:none;min-height:22px;padding:0 9px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-business-primary) 40%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent);color:var(--dsw-alias-state-business-primary);border-radius:var(--dsm-radius-tag);font:inherit;font-size:11px;font-weight:500;cursor:pointer;flex:none;white-space:nowrap}
|
|
@@ -614,6 +619,49 @@ async function dsmOpenSessionById(childId, directParentId) {
|
|
|
614
619
|
}
|
|
615
620
|
return "failed";
|
|
616
621
|
}
|
|
622
|
+
var DSM_CLIENT_ID = (() => {
|
|
623
|
+
try {
|
|
624
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
625
|
+
} catch (e) {
|
|
626
|
+
}
|
|
627
|
+
return `c${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
628
|
+
})();
|
|
629
|
+
function dsmActiveSessionId() {
|
|
630
|
+
try {
|
|
631
|
+
if (!dsmClientCtx || typeof dsmClientCtx.get !== "function") return null;
|
|
632
|
+
const ui = dsmClientCtx.get("uiWorkspace");
|
|
633
|
+
if (ui) {
|
|
634
|
+
const snap = ui.selection && typeof ui.selection.getSnapshot === "function" ? ui.selection.getSnapshot() : null;
|
|
635
|
+
if (snap && snap.sessionId != null) return String(snap.sessionId);
|
|
636
|
+
const ref = ui.mainReference;
|
|
637
|
+
if (ref && ref.sessionId != null) return String(ref.sessionId);
|
|
638
|
+
}
|
|
639
|
+
const native = dsmClientCtx.get("sessions");
|
|
640
|
+
if (native && native.list && typeof native.list.getSnapshot === "function") {
|
|
641
|
+
const snap = native.list.getSnapshot();
|
|
642
|
+
if (snap && snap.current != null) return String(snap.current);
|
|
643
|
+
}
|
|
644
|
+
} catch (e) {
|
|
645
|
+
}
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
var DSM_ACTIVE_HEARTBEAT_MS = 15e3;
|
|
649
|
+
var DSM_ACTIVE_MIN_REPORT_MS = 3e4;
|
|
650
|
+
var dsmLastActiveReport = { id: null, at: 0 };
|
|
651
|
+
async function reportActiveSession(force) {
|
|
652
|
+
const id = dsmActiveSessionId();
|
|
653
|
+
const now = Date.now();
|
|
654
|
+
if (!force && id === dsmLastActiveReport.id && now - dsmLastActiveReport.at < DSM_ACTIVE_MIN_REPORT_MS) return;
|
|
655
|
+
dsmLastActiveReport = { id, at: now };
|
|
656
|
+
try {
|
|
657
|
+
await postJSON("/archived-sessions/active-session", { clientId: DSM_CLIENT_ID, sessionId: id });
|
|
658
|
+
} catch (e) {
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async function postActiveAware(path, body) {
|
|
662
|
+
await reportActiveSession(true).catch(() => null);
|
|
663
|
+
return postJSON(path, body);
|
|
664
|
+
}
|
|
617
665
|
var NAV_CSS = `
|
|
618
666
|
[data-dsh-nav-sessions] > svg:first-child { display: none; }
|
|
619
667
|
[data-dsh-nav-sessions]::before {
|
|
@@ -1018,6 +1066,33 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1018
1066
|
setToast({ msg, kind: kind === "err" ? "err" : "ok" });
|
|
1019
1067
|
timer.current = setTimeout(() => setToast(null), toastDurationFor(msg, kind));
|
|
1020
1068
|
};
|
|
1069
|
+
const copyBuildStamp = async () => {
|
|
1070
|
+
const full = String(capabilities && capabilities.buildStamp || "");
|
|
1071
|
+
if (!full) return;
|
|
1072
|
+
try {
|
|
1073
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
1074
|
+
await navigator.clipboard.writeText(full);
|
|
1075
|
+
showToast("\u5DF2\u590D\u5236\u5B8C\u6574\u7248\u672C\u53F7 " + full, "ok");
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
throw new Error("clipboard unavailable");
|
|
1079
|
+
} catch (e) {
|
|
1080
|
+
try {
|
|
1081
|
+
const ta = document.createElement("textarea");
|
|
1082
|
+
ta.value = full;
|
|
1083
|
+
ta.style.position = "fixed";
|
|
1084
|
+
ta.style.opacity = "0";
|
|
1085
|
+
document.body.appendChild(ta);
|
|
1086
|
+
ta.select();
|
|
1087
|
+
const ok = document.execCommand("copy");
|
|
1088
|
+
document.body.removeChild(ta);
|
|
1089
|
+
if (!ok) throw new Error("execCommand failed");
|
|
1090
|
+
showToast("\u5DF2\u590D\u5236\u5B8C\u6574\u7248\u672C\u53F7 " + full, "ok");
|
|
1091
|
+
} catch (e2) {
|
|
1092
|
+
showToast("\u590D\u5236\u5931\u8D25\uFF0C\u5B8C\u6574\u7248\u672C\u53F7\uFF1A" + full, "err");
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1021
1096
|
const refresh = () => {
|
|
1022
1097
|
setError(null);
|
|
1023
1098
|
Promise.all([
|
|
@@ -1492,7 +1567,7 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1492
1567
|
}
|
|
1493
1568
|
setBusy(it.sessionId);
|
|
1494
1569
|
setError(null);
|
|
1495
|
-
|
|
1570
|
+
postActiveAware("/archived-sessions/move", { sessionId: it.sessionId, targetPath }).then((r) => {
|
|
1496
1571
|
setBusy(null);
|
|
1497
1572
|
setOpenMove(null);
|
|
1498
1573
|
setMoveMode("existing");
|
|
@@ -1549,7 +1624,7 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1549
1624
|
setBusy("__batch__");
|
|
1550
1625
|
setError(null);
|
|
1551
1626
|
setRetry(null);
|
|
1552
|
-
|
|
1627
|
+
postActiveAware("/archived-sessions/move-many", { sessionIds: ids, targetPath }).then((r) => {
|
|
1553
1628
|
setBusy(null);
|
|
1554
1629
|
setBatchMoveOpen(false);
|
|
1555
1630
|
setMoveMode("existing");
|
|
@@ -1717,8 +1792,20 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1717
1792
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: CSS }),
|
|
1718
1793
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-head", children: [
|
|
1719
1794
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "archv-title", children: "\u4F1A\u8BDD\u7BA1\u7406" }),
|
|
1720
|
-
capabilities && capabilities.buildStamp ? /* @__PURE__ */ (0, import_jsx_runtime.
|
|
1721
|
-
|
|
1795
|
+
capabilities && capabilities.buildStamp ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1796
|
+
"span",
|
|
1797
|
+
{
|
|
1798
|
+
className: "archv-stamp",
|
|
1799
|
+
role: "button",
|
|
1800
|
+
"aria-label": "\u590D\u5236\u5B8C\u6574\u7248\u672C\u53F7",
|
|
1801
|
+
title: capabilities.buildStamp,
|
|
1802
|
+
onClick: copyBuildStamp,
|
|
1803
|
+
children: [
|
|
1804
|
+
"v",
|
|
1805
|
+
String(capabilities.buildStamp).split("+")[0]
|
|
1806
|
+
]
|
|
1807
|
+
}
|
|
1808
|
+
) : null,
|
|
1722
1809
|
sessions !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-count", "aria-label": `${sessions.length} \u4E2A\u4F1A\u8BDD`, children: sessions.length })
|
|
1723
1810
|
] }),
|
|
1724
1811
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "archv-sub", children: "\u7EDF\u4E00\u7BA1\u7406\u5168\u90E8\u4F1A\u8BDD\uFF1A\u5F52\u6863 / \u6062\u590D / \u79FB\u52A8\u5230\u5176\u4ED6\u5DE5\u4F5C\u533A / \u4F1A\u8BDD\u8BE6\u60C5 / \u6279\u91CF\u64CD\u4F5C\uFF0C\u5220\u9664\u4F1A\u5148\u8FDB\u5165\u56DE\u6536\u7AD9\uFF0C\u53EF\u5728\u56DE\u6536\u7AD9\u5185\u6062\u590D\u6216\u5F7B\u5E95\u6E05\u7406\u3002" }),
|
|
@@ -2064,8 +2151,8 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
2064
2151
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sess-field", children: [
|
|
2065
2152
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dsm-group", children: "\u5206\u7EC4" }),
|
|
2066
2153
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { id: "dsm-group", value: groupByLineage ? "lineage" : "flat", onChange: (e) => setGroupByLineage(e.target.value === "lineage"), title: "\u8840\u7F18\u5206\u7EC4\uFF1A\u5B50\u4EE3\u7406\u6298\u53E0\u3001\u5206\u652F\u805A\u62E2\u6210\u7EC4\uFF1B\u5E73\u94FA\uFF1A\u4E0E DSH \u539F\u751F\u4E00\u81F4\uFF0C\u5168\u90E8\u5E76\u5217", children: [
|
|
2067
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "lineage", children: "\u8840\u7F18\uFF08\u6298\u53E0\
|
|
2068
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "flat", children: "\u5E73\u94FA\uFF08\
|
|
2154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "lineage", children: "\u8840\u7F18\uFF08\u6298\u53E0\uFF09" }),
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "flat", children: "\u5E73\u94FA\uFF08\u5E76\u5217\uFF09" })
|
|
2069
2156
|
] })
|
|
2070
2157
|
] })
|
|
2071
2158
|
] }),
|
|
@@ -3069,7 +3156,7 @@ function installSidebarSessionMenuAug() {
|
|
|
3069
3156
|
e.preventDefault();
|
|
3070
3157
|
closeSub();
|
|
3071
3158
|
closeMenu();
|
|
3072
|
-
|
|
3159
|
+
postActiveAware("/archived-sessions/move", { sessionId: info.id, targetPath: w.path }).then((r2) => {
|
|
3073
3160
|
const label = w.title || pathName(w.path) || "\u76EE\u6807\u5DE5\u4F5C\u533A";
|
|
3074
3161
|
if (r2 && r2.queued) {
|
|
3075
3162
|
toast(r2.notes && r2.notes.length ? r2.notes.join(" ") : "\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u5DF2\u6392\u961F\u5F85\u79FB\u52A8\uFF1B\u91CD\u542F DSH \u540E\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF08\u8BF7\u5148\u522B\u6253\u5F00\u5B83\uFF09\u3002");
|
|
@@ -3768,7 +3855,7 @@ function installSidebarWorkspaceDrag() {
|
|
|
3768
3855
|
clearVisuals();
|
|
3769
3856
|
row.classList.add("dsm-drag-busy");
|
|
3770
3857
|
try {
|
|
3771
|
-
const result = await
|
|
3858
|
+
const result = await postActiveAware("/archived-sessions/move", { sessionId: item.sessionId, targetPath: target.path });
|
|
3772
3859
|
if (result && result.queued) {
|
|
3773
3860
|
await dsmLoadTrashIds();
|
|
3774
3861
|
toast(result.notes && result.notes.length ? result.notes.join(" ") : "\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u5DF2\u6392\u961F\u5F85\u79FB\u52A8\uFF1B\u91CD\u542F DSH \u540E\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF08\u8BF7\u5148\u522B\u6253\u5F00\u5B83\uFF09\u3002");
|
|
@@ -3824,6 +3911,23 @@ function installSidebarWorkspaceDrag() {
|
|
|
3824
3911
|
function apply(ctx) {
|
|
3825
3912
|
dsmClientCtx = ctx;
|
|
3826
3913
|
dsmLoadCapabilities();
|
|
3914
|
+
const beat = () => {
|
|
3915
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
3916
|
+
reportActiveSession(false).catch(() => {
|
|
3917
|
+
});
|
|
3918
|
+
};
|
|
3919
|
+
beat();
|
|
3920
|
+
const beatTimer = setInterval(beat, DSM_ACTIVE_HEARTBEAT_MS);
|
|
3921
|
+
const beatAc = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
3922
|
+
if (beatAc && typeof document !== "undefined" && document.addEventListener) {
|
|
3923
|
+
document.addEventListener("visibilitychange", () => {
|
|
3924
|
+
if (!document.hidden) beat();
|
|
3925
|
+
}, { signal: beatAc.signal });
|
|
3926
|
+
}
|
|
3927
|
+
ctx.effect(() => () => {
|
|
3928
|
+
clearInterval(beatTimer);
|
|
3929
|
+
if (beatAc) beatAc.abort();
|
|
3930
|
+
});
|
|
3827
3931
|
installSettingsNavIcons(ctx);
|
|
3828
3932
|
installSidebarSessionMenuAug();
|
|
3829
3933
|
const disposeSidebarDots = installSidebarStatusDots();
|