dsh-sessions-manager 3.7.6 → 3.7.8

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/lib/client.js CHANGED
@@ -178,6 +178,19 @@ function noticeToastPlan(raw, seenIds, max = 2) {
178
178
  ackIds: shown.map((n) => String(n.id))
179
179
  };
180
180
  }
181
+ function foldOrphanSubagents(items, lineage) {
182
+ const list = Array.isArray(items) ? items : [];
183
+ const table = lineage && typeof lineage === "object" ? lineage : {};
184
+ const rows = [];
185
+ const orphans = [];
186
+ for (const it of list) {
187
+ const id = it && it.sessionId != null ? String(it.sessionId) : "";
188
+ const info = id ? table[id] : null;
189
+ if (info && info.origin === "subagent") orphans.push(it);
190
+ else rows.push(it);
191
+ }
192
+ return { rows, orphans };
193
+ }
181
194
  function branchTimeKey(item) {
182
195
  const c = Number(item && item.createdAt);
183
196
  if (Number.isFinite(c) && c > 0) return c;
@@ -314,6 +327,68 @@ function filterShapeFromSaved(item) {
314
327
  if (tag === "" && f.tag !== "") degraded.push("tag");
315
328
  return { view, workspace, sort, tag, degraded };
316
329
  }
330
+ function remainingRows(visibleTotal, renderedVisible) {
331
+ if (visibleTotal == null || visibleTotal === "") return null;
332
+ const total = Number(visibleTotal);
333
+ if (!Number.isFinite(total)) return null;
334
+ const shown = Number(renderedVisible);
335
+ const shownCount = Number.isFinite(shown) ? Math.max(0, Math.floor(shown)) : 0;
336
+ return Math.max(0, Math.max(0, Math.floor(total)) - shownCount);
337
+ }
338
+ function collapsedVisibleTotal(groupCount, trashInGroup) {
339
+ if (groupCount == null || trashInGroup == null) return null;
340
+ const total = Number(groupCount);
341
+ const trash = Number(trashInGroup);
342
+ if (!Number.isFinite(total) || !Number.isFinite(trash)) return null;
343
+ return Math.max(0, Math.floor(total) - Math.max(0, Math.floor(trash)));
344
+ }
345
+ function countRenderedVisible(rows, visibleIds) {
346
+ if (!Array.isArray(rows) || !visibleIds || typeof visibleIds.has !== "function") return 0;
347
+ let n = 0;
348
+ for (const row of rows) {
349
+ if (!row || row.pluginHidden) continue;
350
+ if (row.id && visibleIds.has(row.id)) n++;
351
+ }
352
+ return n;
353
+ }
354
+ function aliveSessionCount(sessions, hiddenIds) {
355
+ if (!Array.isArray(sessions) || !sessions.length) return null;
356
+ let alive = 0;
357
+ let seen = 0;
358
+ for (const node of sessions) {
359
+ if (!node || node.id == null) continue;
360
+ const id = String(node.id);
361
+ if (!id) continue;
362
+ seen++;
363
+ if (node.blank) continue;
364
+ if (hiddenIds && typeof hiddenIds.has === "function" && hiddenIds.has(id)) continue;
365
+ alive++;
366
+ }
367
+ return seen === 0 ? null : alive;
368
+ }
369
+ function overflowPlan(text, more) {
370
+ const raw = typeof text === "string" ? text : "";
371
+ const unknown = more == null || !Number.isFinite(Number(more));
372
+ const remaining = unknown ? 0 : Math.max(0, Math.floor(Number(more)));
373
+ const m = raw.match(/(\d[\d,]*)/);
374
+ const base = m ? Number(m[1].replace(/,/g, "")) : null;
375
+ if (base === null || unknown) {
376
+ return { text: raw, hide: false, base, more: unknown ? null : remaining, changed: false };
377
+ }
378
+ if (remaining === 0) {
379
+ return { text: raw, hide: base > 0, base, more: 0, changed: false };
380
+ }
381
+ if (remaining === base) {
382
+ return { text: raw, hide: false, base, more: remaining, changed: false };
383
+ }
384
+ return {
385
+ text: raw.slice(0, m.index) + String(remaining) + raw.slice(m.index + m[1].length),
386
+ hide: false,
387
+ base,
388
+ more: remaining,
389
+ changed: true
390
+ };
391
+ }
317
392
 
318
393
  // src/client/index.jsx
319
394
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -499,6 +574,10 @@ body[data-ds-dark-theme] .archv{color-scheme:dark}
499
574
  .dlg{width:min(420px,92vw);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l3);border-radius:14px;padding:18px;box-shadow:0 16px 48px rgb(0 0 0/.28);display:flex;flex-direction:column;gap:12px}
500
575
  .dlg-title{font-size:15px;font-weight:650;color:var(--dsw-alias-label-primary);margin:0}
501
576
  .dlg-text{font-size:13px;line-height:1.6;color:var(--dsw-alias-label-secondary);margin:0;word-break:break-all}
577
+ /* issue #18 \u7B2C 4 \u6761\uFF1A\u5220\u9664\u786E\u8BA4\u6846\u91CC\u7684\u300C\u8FDE\u5E26\u5B50\u4EE3\u7406\u300D\u52FE\u9009\u884C\u3002\u4E0E\u9762\u677F\u5176\u5B83\u52FE\u9009\u9879
578
+ \u540C\u4E00\u5957\u89C6\u89C9\u8BED\u8A00\uFF0813px / \u4E2D\u6027\u6807\u7B7E\u8272 / 8px \u95F4\u8DDD\uFF09\uFF0C\u4E0D\u81EA\u9020\u6309\u94AE\u6837\u5F0F\u3002 */
579
+ .dlg-check{display:flex;align-items:flex-start;gap:8px;font-size:13px;line-height:1.55;color:var(--dsw-alias-label-secondary);cursor:pointer}
580
+ .dlg-check input{margin:2px 0 0;flex:none}
502
581
  .dlg-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
503
582
  /* ---- T4 \u6807\u7B7E\u7F16\u8F91/\u7BA1\u7406 sheet \u4E0E\u7B5B\u9009\u4FDD\u5B58\u63A7\u4EF6\uFF08\u5168\u90E8\u8D70 --dsw token\uFF09 ---- */
504
583
  .dsm-taglist{display:flex;flex-direction:column;gap:2px;max-height:240px;overflow:auto}
@@ -738,6 +817,10 @@ function SessionPanel({ workspacesSvc }) {
738
817
  const [sortBy, setSortBy] = (0, import_react.useState)(() => ["newest", "oldest", "title"].includes(initialPrefs.sortBy) ? initialPrefs.sortBy : "newest");
739
818
  const [selected, setSelected] = (0, import_react.useState)({});
740
819
  const [delTarget, setDelTarget] = (0, import_react.useState)(null);
820
+ const [cascadeSub, setCascadeSub] = (0, import_react.useState)(true);
821
+ (0, import_react.useEffect)(() => {
822
+ if (delTarget) setCascadeSub(true);
823
+ }, [delTarget]);
741
824
  const [confirmBatch, setConfirmBatch] = (0, import_react.useState)(false);
742
825
  const [batchMoveOpen, setBatchMoveOpen] = (0, import_react.useState)(false);
743
826
  const [busy, setBusy] = (0, import_react.useState)(null);
@@ -806,6 +889,7 @@ function SessionPanel({ workspacesSvc }) {
806
889
  return next;
807
890
  });
808
891
  const [groupByLineage, setGroupByLineage] = (0, import_react.useState)(() => initialPrefs.groupByLineage !== false);
892
+ const [openOrphans, setOpenOrphans] = (0, import_react.useState)(false);
809
893
  const [tagDefs, setTagDefs] = (0, import_react.useState)([]);
810
894
  const [assignments, setAssignments] = (0, import_react.useState)({});
811
895
  const [tagsState, setTagsState] = (0, import_react.useState)("loading");
@@ -1265,19 +1349,30 @@ function SessionPanel({ workspacesSvc }) {
1265
1349
  const canPurge = actionCapability("physicalPurge", "purge");
1266
1350
  const canMove = actionCapability("relocateSession", "move");
1267
1351
  const canRestoreTrash = actionCapability("restoreIndexedSession", "restoreTrash");
1268
- const archivedList = sessions ? sessions.filter((x) => x.archived) : [];
1269
- const activeList = sessions ? sessions.filter((x) => !x.archived) : [];
1270
- const starredList = starredOf(sessions);
1271
- const emptyList = (0, import_react.useMemo)(() => {
1272
- if (!sessions) return [];
1273
- return sessions.filter((x) => {
1352
+ const isSubagentItem = (0, import_react.useCallback)((item) => {
1353
+ const li = item ? lineage[String(item.sessionId)] : null;
1354
+ return !!(li && li.origin === "subagent");
1355
+ }, [lineage]);
1356
+ const { archivedAll, activeAll, starredAll, emptyAll } = (0, import_react.useMemo)(() => ({
1357
+ archivedAll: sessions ? sessions.filter((x) => x.archived) : [],
1358
+ activeAll: sessions ? sessions.filter((x) => !x.archived) : [],
1359
+ starredAll: starredOf(sessions),
1360
+ // issue #6 之三:空白会话单分一类。空白判定来自宿主血缘快照(sizeBytes 阈值
1361
+ // 实测校准),与侧栏「空白」标记同源——两处永远不会各说各话。
1362
+ emptyAll: sessions ? sessions.filter((x) => {
1274
1363
  const li = lineage[String(x.sessionId)];
1275
1364
  return !!(li && li.empty);
1276
- });
1277
- }, [sessions, lineage]);
1365
+ }) : []
1366
+ }), [sessions, lineage]);
1367
+ const topOnly = (0, import_react.useCallback)((arr) => groupByLineage ? arr.filter((x) => !isSubagentItem(x)) : arr, [groupByLineage, isSubagentItem]);
1368
+ const archivedList = (0, import_react.useMemo)(() => topOnly(archivedAll), [topOnly, archivedAll]);
1369
+ const activeList = (0, import_react.useMemo)(() => topOnly(activeAll), [topOnly, activeAll]);
1370
+ const starredList = (0, import_react.useMemo)(() => topOnly(starredAll), [topOnly, starredAll]);
1371
+ const emptyList = (0, import_react.useMemo)(() => topOnly(emptyAll), [topOnly, emptyAll]);
1372
+ const totalTopCount = (0, import_react.useMemo)(() => topOnly(sessions || []).length, [topOnly, sessions]);
1278
1373
  const list = (0, import_react.useMemo)(() => {
1279
1374
  if (filter === "trash") return [];
1280
- const base = filter === "archived" ? archivedList : filter === "active" ? activeList : filter === "starred" ? starredList : filter === "empty" ? emptyList : sessions || [];
1375
+ const base = filter === "archived" ? archivedAll : filter === "active" ? activeAll : filter === "starred" ? starredAll : filter === "empty" ? emptyAll : sessions || [];
1281
1376
  const tagPassed = applyTagFilter(base, tagsReady ? tagFilter : "");
1282
1377
  const needle = query.trim().toLocaleLowerCase();
1283
1378
  const filtered = tagPassed.filter((item) => {
@@ -1290,14 +1385,15 @@ function SessionPanel({ workspacesSvc }) {
1290
1385
  if (sortBy === "title") return effectiveTitleOf(a, dsmAuthoritativeTitles).localeCompare(effectiveTitleOf(b, dsmAuthoritativeTitles), "zh-CN");
1291
1386
  return Number(b.createdAt || 0) - Number(a.createdAt || 0);
1292
1387
  });
1293
- }, [sessions, filter, query, workspaceFilter, sortBy, emptyList, starredList, tagFilter, tagsReady]);
1388
+ }, [sessions, archivedAll, activeAll, starredAll, emptyAll, filter, query, workspaceFilter, sortBy, tagFilter, tagsReady]);
1294
1389
  const selIds = Object.keys(selected).filter((k) => selected[k]);
1295
1390
  const showSessionList = filter !== "trash";
1296
- const { topList, kidsOf, foldedCount, branchGroupsOf, branchFolded, branchGroupCount } = (0, import_react.useMemo)(() => {
1297
- if (!groupByLineage) return { topList: list, kidsOf: /* @__PURE__ */ new Map(), foldedCount: 0, branchGroupsOf: /* @__PURE__ */ new Map(), branchFolded: 0, branchGroupCount: 0 };
1391
+ const { topList, kidsOf, foldedCount, branchGroupsOf, branchFolded, branchGroupCount, orphanSubagents } = (0, import_react.useMemo)(() => {
1392
+ if (!groupByLineage) return { topList: list, kidsOf: /* @__PURE__ */ new Map(), foldedCount: 0, branchGroupsOf: /* @__PURE__ */ new Map(), branchFolded: 0, branchGroupCount: 0, orphanSubagents: [] };
1298
1393
  const kids = foldSubagents(list, lineage);
1299
1394
  const br = foldBranches(kids.topList, lineage);
1300
- return { topList: br.topList, kidsOf: kids.kidsOf, foldedCount: kids.foldedCount, branchGroupsOf: br.branchGroupsOf, branchFolded: br.foldedCount, branchGroupCount: br.groupCount };
1395
+ const { rows, orphans } = foldOrphanSubagents(br.topList, lineage);
1396
+ return { topList: rows, kidsOf: kids.kidsOf, foldedCount: kids.foldedCount, branchGroupsOf: br.branchGroupsOf, branchFolded: br.foldedCount, branchGroupCount: br.groupCount, orphanSubagents: orphans };
1301
1397
  }, [list, lineage, groupByLineage]);
1302
1398
  const matchIds = (0, import_react.useMemo)(() => {
1303
1399
  const needle = query.trim().toLocaleLowerCase();
@@ -1306,6 +1402,8 @@ function SessionPanel({ workspacesSvc }) {
1306
1402
  }, [sessions, query]);
1307
1403
  const kidsHit = (parentId) => !!(matchIds && (kidsOf.get(String(parentId)) || []).some((k) => matchIds.has(String(k.sessionId))));
1308
1404
  const branchHit = (rootId) => !!(matchIds && (branchGroupsOf.get(String(rootId)) || []).some((m) => matchIds.has(String(m.sessionId))));
1405
+ const orphanHit = !!(matchIds && orphanSubagents.some((k) => matchIds.has(String(k.sessionId))));
1406
+ const orphanOpen = openOrphans || orphanHit;
1309
1407
  const syntheticCount = groupByLineage ? topList.reduce((n, it) => n + (it && it.syntheticRoot ? 1 : 0), 0) : 0;
1310
1408
  const kidsBadge = (sessionId) => {
1311
1409
  if (!groupByLineage) return null;
@@ -1330,6 +1428,29 @@ function SessionPanel({ workspacesSvc }) {
1330
1428
  );
1331
1429
  };
1332
1430
  const sessionsById = (0, import_react.useMemo)(() => new Map((sessions || []).map((x) => [String(x.sessionId), x])), [sessions]);
1431
+ const delCascadeCount = (0, import_react.useMemo)(() => {
1432
+ if (!delTarget) return 0;
1433
+ const childMap = /* @__PURE__ */ new Map();
1434
+ for (const [id, li] of Object.entries(lineage || {})) {
1435
+ if (!li || li.origin !== "subagent" || !li.parentSession) continue;
1436
+ const p = String(li.parentSession);
1437
+ if (!childMap.has(p)) childMap.set(p, []);
1438
+ childMap.get(p).push(String(id));
1439
+ }
1440
+ const seen = /* @__PURE__ */ new Set([String(delTarget.sessionId)]);
1441
+ const queue = [String(delTarget.sessionId)];
1442
+ let n = 0;
1443
+ while (queue.length) {
1444
+ const cur = queue.shift();
1445
+ for (const kid of childMap.get(cur) || []) {
1446
+ if (seen.has(kid)) continue;
1447
+ seen.add(kid);
1448
+ n++;
1449
+ queue.push(kid);
1450
+ }
1451
+ }
1452
+ return n;
1453
+ }, [delTarget, lineage]);
1333
1454
  const branchBadge = (sessionId) => {
1334
1455
  const li = lineage[String(sessionId)];
1335
1456
  if (!li || li.origin === "subagent" || !li.parentSession) return null;
@@ -1439,8 +1560,8 @@ function SessionPanel({ workspacesSvc }) {
1439
1560
  const clearSel = () => setSelected({});
1440
1561
  const selectAll = () => {
1441
1562
  const o = {};
1442
- list.forEach((x) => {
1443
- o[x.sessionId] = true;
1563
+ topList.forEach((x) => {
1564
+ if (x && x.sessionId != null && !x.syntheticRoot) o[x.sessionId] = true;
1444
1565
  });
1445
1566
  setSelected(o);
1446
1567
  };
@@ -1460,13 +1581,14 @@ function SessionPanel({ workspacesSvc }) {
1460
1581
  const doDeleteConfirmed = () => {
1461
1582
  if (!delTarget || busy) return;
1462
1583
  setBusy(delTarget.sessionId);
1463
- postJSON("/archived-sessions/delete", { sessionId: delTarget.sessionId }).then(() => {
1584
+ postJSON("/archived-sessions/delete", { sessionId: delTarget.sessionId, cascadeSubagents: cascadeSub }).then((r) => {
1464
1585
  setBusy(null);
1465
1586
  const n = delTarget.title || delTarget.sessionId;
1466
- showToast(`\u5DF2\u5220\u9664 ${n}\uFF08\u5DF2\u79FB\u5165\u56DE\u6536\u7AD9\uFF09`);
1467
- const sid = String(delTarget.sessionId);
1587
+ const cascaded = Number(r && r.cascaded || 0);
1588
+ showToast(`\u5DF2\u5220\u9664 ${n}${cascaded ? `\uFF08\u8FDE\u540C ${cascaded} \u4E2A\u5B50\u4EE3\u7406\u4F1A\u8BDD\uFF09` : ""}\uFF08\u5DF2\u79FB\u5165\u56DE\u6536\u7AD9\uFF09`);
1589
+ const gone = /* @__PURE__ */ new Set([String(delTarget.sessionId), ...(r && r.cascadedIds || []).map(String)]);
1468
1590
  setDelTarget(null);
1469
- setSessions((s) => s && s.filter((x) => String(x.sessionId) !== sid));
1591
+ setSessions((s) => s && s.filter((x) => !gone.has(String(x.sessionId))));
1470
1592
  loadTrash();
1471
1593
  dsmLoadTrashIds();
1472
1594
  }).catch((e) => {
@@ -1557,7 +1679,9 @@ function SessionPanel({ workspacesSvc }) {
1557
1679
  setTrashBusy(sid);
1558
1680
  postJSON("/archived-sessions/trash/restore", { sessionId: sid }).then((r) => {
1559
1681
  setTrashBusy(null);
1560
- showToast(r && r.workspaceGone ? "\u5DF2\u6062\u590D\u4F1A\u8BDD\uFF08\u539F\u5DE5\u4F5C\u533A\u5DF2\u5220\u9664\uFF0C\u4F1A\u8BDD\u6682\u5F52\u300C\u672A\u5206\u7EC4\u300D\uFF09" : "\u5DF2\u6062\u590D\u4F1A\u8BDD");
1682
+ const cascaded = Number(r && r.cascaded || 0);
1683
+ const base = r && r.workspaceGone ? "\u5DF2\u6062\u590D\u4F1A\u8BDD\uFF08\u539F\u5DE5\u4F5C\u533A\u5DF2\u5220\u9664\uFF0C\u4F1A\u8BDD\u6682\u5F52\u300C\u672A\u5206\u7EC4\u300D\uFF09" : "\u5DF2\u6062\u590D\u4F1A\u8BDD";
1684
+ showToast(base + (cascaded ? `\uFF0C\u8FDE\u540C ${cascaded} \u4E2A\u5B50\u4EE3\u7406\u4F1A\u8BDD` : ""));
1561
1685
  loadTrash();
1562
1686
  refresh();
1563
1687
  }).catch((e) => {
@@ -1646,7 +1770,8 @@ function SessionPanel({ workspacesSvc }) {
1646
1770
  postJSON("/archived-sessions/" + action, { sessionIds: selIds }).then((r) => {
1647
1771
  setBusy(null);
1648
1772
  const n = r && (r.archived || r.restored || r.deleted) || selIds.length;
1649
- showToast(`\u5DF2\u5904\u7406 ${n} \u4E2A\u4F1A\u8BDD`);
1773
+ const cascaded = Number(r && r.cascaded || 0);
1774
+ showToast(`\u5DF2\u5904\u7406 ${n} \u4E2A\u4F1A\u8BDD${cascaded ? `\uFF08\u8FDE\u540C ${cascaded} \u4E2A\u5B50\u4EE3\u7406\u4F1A\u8BDD\uFF09` : ""}`);
1650
1775
  refresh();
1651
1776
  }).catch((e) => {
1652
1777
  setBusy(null);
@@ -1851,7 +1976,7 @@ function SessionPanel({ workspacesSvc }) {
1851
1976
  ]
1852
1977
  }
1853
1978
  ) : null,
1854
- sessions !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-count", "aria-label": `${sessions.length} \u4E2A\u4F1A\u8BDD`, children: sessions.length })
1979
+ sessions !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-count", title: groupByLineage ? "\u5B50\u4EE3\u7406\u4F1A\u8BDD\u6298\u53E0\u5728\u7236\u4F1A\u8BDD\u4E0B\uFF0C\u4E0D\u8BA1\u5165\u6B64\u6570" : void 0, "aria-label": `${totalTopCount} \u4E2A\u4F1A\u8BDD`, children: totalTopCount })
1855
1980
  ] }),
1856
1981
  /* @__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" }),
1857
1982
  error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-err", role: "alert", children: [
@@ -1880,7 +2005,7 @@ function SessionPanel({ workspacesSvc }) {
1880
2005
  setConfirmBatch(false);
1881
2006
  }, children: [
1882
2007
  "\u5168\u90E8 (",
1883
- sessions.length,
2008
+ totalTopCount,
1884
2009
  ")"
1885
2010
  ] }),
1886
2011
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", role: "tab", "aria-selected": filter === "active", className: "sess-fbtn" + (filter === "active" ? " sess-fbtn-on" : ""), onClick: () => {
@@ -2206,7 +2331,7 @@ function SessionPanel({ workspacesSvc }) {
2206
2331
  "\u663E\u793A ",
2207
2332
  topList.length - syntheticCount,
2208
2333
  " \u4E2A\u4F1A\u8BDD",
2209
- foldedCount || branchFolded ? `\uFF0C\u53E6\u6709 ${[foldedCount ? `${foldedCount} \u4E2A\u5B50\u4EE3\u7406\u6298\u53E0\u5728\u7236\u4F1A\u8BDD\u4E0B` : "", branchFolded ? `${branchFolded} \u4E2A\u5206\u652F\u805A\u6210 ${branchGroupCount} \u7EC4` : ""].filter(Boolean).join("\u3001")}` : query || workspaceFilter !== "all" || tagFilter ? `\uFF0C\u5171 ${filter === "archived" ? archivedList.length : filter === "active" ? activeList.length : filter === "starred" ? starredList.length : filter === "empty" ? emptyList.length : sessions.length} \u4E2A` : topList.length !== list.length ? `\uFF0C\u5171 ${list.length} \u4E2A` : ""
2334
+ foldedCount || branchFolded ? `\uFF0C\u53E6\u6709 ${[foldedCount ? `${foldedCount} \u4E2A\u5B50\u4EE3\u7406\u6298\u53E0\u5728\u7236\u4F1A\u8BDD\u4E0B` : "", branchFolded ? `${branchFolded} \u4E2A\u5206\u652F\u805A\u6210 ${branchGroupCount} \u7EC4` : ""].filter(Boolean).join("\u3001")}` : query || workspaceFilter !== "all" || tagFilter ? `\uFF0C\u5171 ${filter === "archived" ? archivedList.length : filter === "active" ? activeList.length : filter === "starred" ? starredList.length : filter === "empty" ? emptyList.length : totalTopCount} \u4E2A` : topList.length !== list.length ? `\uFF0C\u5171 ${list.length} \u4E2A` : ""
2210
2335
  ] }),
2211
2336
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsm-fbar", children: [
2212
2337
  saveFilterOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
@@ -2279,9 +2404,9 @@ function SessionPanel({ workspacesSvc }) {
2279
2404
  ] })
2280
2405
  ] })
2281
2406
  ] }),
2282
- showSessionList && list.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sess-batch" + (selIds.length > 0 ? " sess-batch-pin" : ""), children: [
2283
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sess-btntext", children: selIds.length ? `\u5DF2\u9009 ${selIds.length} \u9879` : filter === "archived" ? `\u5171 ${archivedList.length} \u4E2A\u5F52\u6863\u4F1A\u8BDD` : filter === "starred" ? `\u5171 ${starredList.length} \u4E2A\u6536\u85CF\u4F1A\u8BDD` : `\u5171 ${sessions.length} \u4E2A\u4F1A\u8BDD\uFF08\u6D3B\u52A8 ${activeList.length} / \u5DF2\u5F52\u6863 ${archivedList.length}\uFF09` }),
2284
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: list.length === 0, onClick: selectAll, children: "\u5168\u9009" }),
2407
+ showSessionList && (topList.length > 0 || orphanSubagents.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sess-batch" + (selIds.length > 0 ? " sess-batch-pin" : ""), children: [
2408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sess-btntext", children: selIds.length ? `\u5DF2\u9009 ${selIds.length} \u9879` : filter === "archived" ? `\u5171 ${archivedList.length} \u4E2A\u5F52\u6863\u4F1A\u8BDD` : filter === "starred" ? `\u5171 ${starredList.length} \u4E2A\u6536\u85CF\u4F1A\u8BDD` : `\u5171 ${totalTopCount} \u4E2A\u4F1A\u8BDD\uFF08\u6D3B\u52A8 ${activeList.length} / \u5DF2\u5F52\u6863 ${archivedList.length}\uFF09` }),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: topList.length === 0, title: groupByLineage ? "\u9009\u4E2D\u5F53\u524D\u5217\u8868\u7684\u4F1A\u8BDD\u884C\uFF08\u6298\u53E0\u4E2D\u7684\u5B50\u4EE3\u7406\u4E0E\u5206\u652F\u6210\u5458\u4E0D\u4F1A\u88AB\u9009\u4E2D\uFF09" : void 0, onClick: selectAll, children: "\u5168\u9009" }),
2285
2410
  selIds.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2286
2411
  filter === "archived" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2287
2412
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: busy !== null, onClick: () => doBatch("restore-many"), children: "\u6062\u590D\u6240\u9009" }),
@@ -2359,311 +2484,372 @@ function SessionPanel({ workspacesSvc }) {
2359
2484
  ] })
2360
2485
  ] })
2361
2486
  ] }),
2362
- showSessionList && list.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-empty", children: query || workspaceFilter !== "all" || tagFilter ? "\u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD\u3002\u8BF7\u8C03\u6574\u641C\u7D22\u8BCD\u3001\u6807\u7B7E\u6216\u5DE5\u4F5C\u533A\u7B5B\u9009\u3002" : filter === "archived" ? "\u76EE\u524D\u6CA1\u6709\u5F52\u6863\u4F1A\u8BDD\u3002\u5728\u201C\u5168\u90E8\u201D\u91CC\u9009\u4E2D\u4F1A\u8BDD\u70B9\u201C\u5F52\u6863\u201D\u5373\u53EF\u6536\u7EB3\u8FDB\u6765\u3002" : filter === "active" ? "\u76EE\u524D\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD\u3002" : filter === "starred" ? "\u8FD8\u6CA1\u6709\u6536\u85CF\u7684\u4F1A\u8BDD\u3002\u70B9\u51FB\u4F1A\u8BDD\u5DE6\u4FA7\u7684\u661F\u6807\u5373\u53EF\u6536\u85CF\u3002" : filter === "empty" ? "\u6CA1\u6709\u7A7A\u767D\u4F1A\u8BDD\u3002\u65B0\u5F00\u4F1A\u8BDD\u8FD8\u6CA1\u4EA7\u751F\u5185\u5BB9\u65F6\u4F1A\u5F52\u5230\u8FD9\u91CC\uFF0C\u4FA7\u680F\u4F1A\u81EA\u52A8\u9690\u85CF\u5B83\u4EEC\u3002" : "\u6682\u65E0\u53EF\u7BA1\u7406\u7684\u4F1A\u8BDD\u3002" }) : showSessionList ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-list", role: "list", children: topList.map((it) => {
2363
- if (it && it.syntheticRoot) {
2364
- const root = String(it.syntheticRoot);
2365
- const members = branchGroupsOf.get(root) || [];
2366
- const open = !!openBranches[root] || branchHit(root);
2367
- const srcTitle = dsmAuthoritativeTitles.get(root);
2368
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsm-src-head", role: "listitem", children: [
2369
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2370
- "button",
2371
- {
2372
- type: "button",
2373
- className: "dsm-kids-toggle",
2374
- "aria-expanded": open,
2375
- title: (open ? "\u6536\u8D77 " : "\u5C55\u5F00 ") + members.length + " \u4E2A\u5206\u652F\u4F1A\u8BDD\uFF08\u6765\u6E90\u4F1A\u8BDD\u4E0D\u5728\u5F53\u524D\u5217\u8868\uFF09",
2376
- onClick: () => toggleBranch(root),
2377
- children: [
2378
- open ? "\u25BE" : "\u25B8",
2379
- " ",
2380
- members.length,
2381
- " \u5206\u652F"
2382
- ]
2383
- }
2384
- ),
2385
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-src-name", title: root, children: "\u6765\u6E90\uFF1A" + (srcTitle || shortId(root)) })
2386
- ] }, it.sessionId);
2387
- }
2388
- const date = fmtDate(it.createdAt);
2389
- const expanded = openMove === it.sessionId || openTags === it.sessionId;
2390
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-card" + (expanded ? " archv-card-exp" : ""), role: "listitem", children: [
2391
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-row", children: [
2392
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2393
- "input",
2394
- {
2395
- type: "checkbox",
2396
- className: "archv-check",
2397
- checked: !!selected[it.sessionId],
2398
- onChange: () => toggle(it.sessionId),
2399
- "aria-label": "\u9009\u62E9 " + (it.title || it.sessionId)
2400
- }
2401
- ),
2402
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2403
- "button",
2404
- {
2405
- type: "button",
2406
- className: "archv-star" + (it.starred ? " archv-star-on" : ""),
2407
- "aria-pressed": !!it.starred,
2408
- "aria-label": (it.starred ? "\u53D6\u6D88\u6536\u85CF " : "\u6536\u85CF ") + (it.title || it.sessionId),
2409
- title: it.starred ? "\u53D6\u6D88\u6536\u85CF" : "\u6536\u85CF",
2410
- onClick: (e) => {
2411
- e.stopPropagation();
2412
- toggleStar(it);
2413
- },
2414
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "18", height: "18", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2.5l2.9 5.9 6.6.9-4.8 4.6 1.2 6.5-5.9-3.1-5.9 3.1 1.2-6.5L2.5 9.3l6.6-.9z" }) })
2415
- }
2416
- ),
2417
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-body", children: [
2418
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-main", children: [
2419
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-titlerow", children: [
2420
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-name", title: it.title || "", children: it.title || "(\u65E0\u6807\u9898)" }),
2421
- branchBadge(it.sessionId),
2422
- emptyBadge(it.sessionId),
2423
- tagChips(it.sessionId),
2424
- kidsBadge(it.sessionId),
2425
- branchGroupBadge(it.sessionId),
2426
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-id" + (copiedId === it.sessionId ? " archv-id-copied" : ""), title: it.sessionId + "\uFF08\u70B9\u51FB\u590D\u5236\u5B8C\u6574 ID\uFF09", "aria-label": "\u590D\u5236\u4F1A\u8BDD ID " + it.sessionId, onClick: (e) => {
2427
- e.stopPropagation();
2428
- copySessionId(it.sessionId);
2429
- }, children: copiedId === it.sessionId ? "\u5DF2\u590D\u5236" : shortId(it.sessionId) })
2487
+ showSessionList && topList.length === 0 && orphanSubagents.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-empty", children: query || workspaceFilter !== "all" || tagFilter ? "\u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD\u3002\u8BF7\u8C03\u6574\u641C\u7D22\u8BCD\u3001\u6807\u7B7E\u6216\u5DE5\u4F5C\u533A\u7B5B\u9009\u3002" : filter === "archived" ? "\u76EE\u524D\u6CA1\u6709\u5F52\u6863\u4F1A\u8BDD\u3002\u5728\u201C\u5168\u90E8\u201D\u91CC\u9009\u4E2D\u4F1A\u8BDD\u70B9\u201C\u5F52\u6863\u201D\u5373\u53EF\u6536\u7EB3\u8FDB\u6765\u3002" : filter === "active" ? "\u76EE\u524D\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD\u3002" : filter === "starred" ? "\u8FD8\u6CA1\u6709\u6536\u85CF\u7684\u4F1A\u8BDD\u3002\u70B9\u51FB\u4F1A\u8BDD\u5DE6\u4FA7\u7684\u661F\u6807\u5373\u53EF\u6536\u85CF\u3002" : filter === "empty" ? "\u6CA1\u6709\u7A7A\u767D\u4F1A\u8BDD\u3002\u65B0\u5F00\u4F1A\u8BDD\u8FD8\u6CA1\u4EA7\u751F\u5185\u5BB9\u65F6\u4F1A\u5F52\u5230\u8FD9\u91CC\uFF0C\u4FA7\u680F\u4F1A\u81EA\u52A8\u9690\u85CF\u5B83\u4EEC\u3002" : "\u6682\u65E0\u53EF\u7BA1\u7406\u7684\u4F1A\u8BDD\u3002" }) : showSessionList ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-list", role: "list", children: [
2488
+ topList.map((it) => {
2489
+ if (it && it.syntheticRoot) {
2490
+ const root = String(it.syntheticRoot);
2491
+ const members = branchGroupsOf.get(root) || [];
2492
+ const open = !!openBranches[root] || branchHit(root);
2493
+ const srcTitle = dsmAuthoritativeTitles.get(root);
2494
+ return (
2495
+ // issue #18 第 2 条:合成头先前在这里提前 return,只渲染按钮与
2496
+ // 「来源:」,展开时什么都不会出现(成员列表只挂在普通卡片的
2497
+ // renderBranchGroup 上)。这里补上同一个成员渲染器——按钮、
2498
+ // 展开状态、搜索命中展开都复用分支组的既有语义。
2499
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
2500
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsm-src-head", role: "listitem", children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2502
+ "button",
2503
+ {
2504
+ type: "button",
2505
+ className: "dsm-kids-toggle",
2506
+ "aria-expanded": open,
2507
+ title: (open ? "\u6536\u8D77 " : "\u5C55\u5F00 ") + members.length + " \u4E2A\u5206\u652F\u4F1A\u8BDD\uFF08\u6765\u6E90\u4F1A\u8BDD\u4E0D\u5728\u5F53\u524D\u5217\u8868\uFF09",
2508
+ onClick: () => toggleBranch(root),
2509
+ children: [
2510
+ open ? "\u25BE" : "\u25B8",
2511
+ " ",
2512
+ members.length,
2513
+ " \u5206\u652F"
2514
+ ]
2515
+ }
2516
+ ),
2517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-src-name", title: root, children: "\u6765\u6E90\uFF1A" + (srcTitle || shortId(root)) })
2430
2518
  ] }),
2431
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-meta", children: [
2432
- it.archived ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-wtag archv-wgone", children: "\u5DF2\u5F52\u6863" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-wtag archv-active", children: "\u6D3B\u52A8" }),
2433
- workspaceTag(it),
2434
- date && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2435
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-dot", children: "\xB7" }),
2436
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-date", children: date })
2519
+ renderBranchGroup(root)
2520
+ ] }, it.sessionId)
2521
+ );
2522
+ }
2523
+ const date = fmtDate(it.createdAt);
2524
+ const expanded = openMove === it.sessionId || openTags === it.sessionId;
2525
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-card" + (expanded ? " archv-card-exp" : ""), role: "listitem", children: [
2526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-row", children: [
2527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2528
+ "input",
2529
+ {
2530
+ type: "checkbox",
2531
+ className: "archv-check",
2532
+ checked: !!selected[it.sessionId],
2533
+ onChange: () => toggle(it.sessionId),
2534
+ "aria-label": "\u9009\u62E9 " + (it.title || it.sessionId)
2535
+ }
2536
+ ),
2537
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2538
+ "button",
2539
+ {
2540
+ type: "button",
2541
+ className: "archv-star" + (it.starred ? " archv-star-on" : ""),
2542
+ "aria-pressed": !!it.starred,
2543
+ "aria-label": (it.starred ? "\u53D6\u6D88\u6536\u85CF " : "\u6536\u85CF ") + (it.title || it.sessionId),
2544
+ title: it.starred ? "\u53D6\u6D88\u6536\u85CF" : "\u6536\u85CF",
2545
+ onClick: (e) => {
2546
+ e.stopPropagation();
2547
+ toggleStar(it);
2548
+ },
2549
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "18", height: "18", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2.5l2.9 5.9 6.6.9-4.8 4.6 1.2 6.5-5.9-3.1-5.9 3.1 1.2-6.5L2.5 9.3l6.6-.9z" }) })
2550
+ }
2551
+ ),
2552
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-body", children: [
2553
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-main", children: [
2554
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-titlerow", children: [
2555
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-name", title: it.title || "", children: it.title || "(\u65E0\u6807\u9898)" }),
2556
+ branchBadge(it.sessionId),
2557
+ emptyBadge(it.sessionId),
2558
+ tagChips(it.sessionId),
2559
+ kidsBadge(it.sessionId),
2560
+ branchGroupBadge(it.sessionId),
2561
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-id" + (copiedId === it.sessionId ? " archv-id-copied" : ""), title: it.sessionId + "\uFF08\u70B9\u51FB\u590D\u5236\u5B8C\u6574 ID\uFF09", "aria-label": "\u590D\u5236\u4F1A\u8BDD ID " + it.sessionId, onClick: (e) => {
2562
+ e.stopPropagation();
2563
+ copySessionId(it.sessionId);
2564
+ }, children: copiedId === it.sessionId ? "\u5DF2\u590D\u5236" : shortId(it.sessionId) })
2565
+ ] }),
2566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-meta", children: [
2567
+ it.archived ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-wtag archv-wgone", children: "\u5DF2\u5F52\u6863" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-wtag archv-active", children: "\u6D3B\u52A8" }),
2568
+ workspaceTag(it),
2569
+ date && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2570
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-dot", children: "\xB7" }),
2571
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-date", children: date })
2572
+ ] })
2437
2573
  ] })
2438
- ] })
2439
- ] }),
2440
- rowMenu(it)
2441
- ] })
2442
- ] }),
2443
- groupByLineage && renderKids(it.sessionId, 0),
2444
- groupByLineage && renderBranchGroup(it.sessionId),
2445
- expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet", role: "region", "aria-label": "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A", children: [
2446
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet-head", children: [
2447
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "mv-sheet-title", children: "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A" }),
2448
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED", onClick: () => setOpenMove(null), children: "\xD7" })
2449
- ] }),
2450
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-seg", role: "tablist", children: [
2451
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": moveMode === "existing", className: "mv-segbtn" + (moveMode === "existing" ? " mv-segbtn-on" : ""), onClick: () => setMoveMode("existing"), children: "\u5DF2\u6709\u5DE5\u4F5C\u533A" }),
2452
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": moveMode === "new", className: "mv-segbtn" + (moveMode === "new" ? " mv-segbtn-on" : ""), onClick: () => setMoveMode("new"), children: "\u65B0\u5EFA\u76EE\u5F55" })
2453
- ] }),
2454
- moveMode === "existing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2455
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-target-ws", children: "\u76EE\u6807\u5DE5\u4F5C\u533A" }),
2456
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { id: "mv-target-ws", value: targetWs, onChange: (e) => setTargetWs(e.target.value), children: [
2457
- workspaces.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\uFF08\u6682\u65E0\u5DE5\u4F5C\u533A\uFF09" }),
2458
- workspaces.map((w) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", { value: w.workspaceId, children: [
2459
- w.title,
2460
- " \xB7 ",
2461
- w.path
2462
- ] }, w.workspaceId))
2463
- ] })
2464
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2465
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-new-path", children: "\u65B0\u5DE5\u4F5C\u533A\u76EE\u5F55\u8DEF\u5F84" }),
2466
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-browse-row", children: [
2467
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2468
- "input",
2469
- {
2470
- id: "mv-new-path",
2471
- type: "text",
2472
- value: newPath,
2473
- onChange: (e) => setNewPath(e.target.value),
2474
- placeholder: "\u4F8B\u5982 /Users/you/Projects/demo \u6216 ~/demo"
2475
- }
2476
- ),
2477
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2478
- "button",
2479
- {
2480
- type: "button",
2481
- className: "archv-btn",
2482
- onClick: pickDirectory,
2483
- disabled: busy !== null || picking || !workspacesSvc,
2484
- title: !workspacesSvc ? "\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9" : "\u6253\u5F00\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9\u7A97\u53E3",
2485
- children: picking ? "\u9009\u62E9\u4E2D\u2026" : "\u6D4F\u89C8\u2026"
2486
- }
2487
- )
2574
+ ] }),
2575
+ rowMenu(it)
2488
2576
  ] })
2489
2577
  ] }),
2490
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-foot", children: [
2491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", onClick: () => setOpenMove(null), children: "\u53D6\u6D88" }),
2492
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "archv-btn archv-go", disabled: busy !== null, onClick: () => doMove(it), children: [
2493
- busy === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-spin", "aria-hidden": "true" }),
2494
- "\u786E\u8BA4\u79FB\u52A8"
2495
- ] })
2496
- ] })
2497
- ] }),
2498
- openTags === it.sessionId && (() => {
2499
- const cur = Array.isArray(assignments[String(it.sessionId)]) ? assignments[String(it.sessionId)] : [];
2500
- const locked = tagBusy !== null || !tagsReady;
2501
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet", role: "region", "aria-label": "\u4F1A\u8BDD\u6807\u7B7E", children: [
2578
+ groupByLineage && renderKids(it.sessionId, 0),
2579
+ groupByLineage && renderBranchGroup(it.sessionId),
2580
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet", role: "region", "aria-label": "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A", children: [
2502
2581
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet-head", children: [
2503
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { className: "mv-sheet-title", children: [
2504
- "\u4F1A\u8BDD\u6807\u7B7E \xB7 ",
2505
- it.title || shortId(it.sessionId)
2506
- ] }),
2507
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED", onClick: () => setOpenTags(null), children: "\xD7" })
2582
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "mv-sheet-title", children: "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A" }),
2583
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED", onClick: () => setOpenMove(null), children: "\xD7" })
2508
2584
  ] }),
2509
- tagDefs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "\u8FD8\u6CA1\u6709\u6807\u7B7E\uFF0C\u5728\u4E0B\u65B9\u65B0\u5EFA\u7B2C\u4E00\u4E2A\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsm-taglist", children: tagDefs.map((t) => {
2510
- const checked = cur.some((id) => String(id) === String(t.id));
2511
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dsm-tagcheck", children: [
2512
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked, disabled: locked, onChange: () => toggleTagFor(it.sessionId, t.id) }),
2513
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-tagcheck-name", title: t.name, children: t.name })
2514
- ] }, String(t.id));
2515
- }) }),
2516
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2517
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "dsm-tag-attach-" + String(it.sessionId), children: "\u65B0\u5EFA\u6807\u7B7E\u5E76\u8D34\u4E0A" }),
2585
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-seg", role: "tablist", children: [
2586
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": moveMode === "existing", className: "mv-segbtn" + (moveMode === "existing" ? " mv-segbtn-on" : ""), onClick: () => setMoveMode("existing"), children: "\u5DF2\u6709\u5DE5\u4F5C\u533A" }),
2587
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": moveMode === "new", className: "mv-segbtn" + (moveMode === "new" ? " mv-segbtn-on" : ""), onClick: () => setMoveMode("new"), children: "\u65B0\u5EFA\u76EE\u5F55" })
2588
+ ] }),
2589
+ moveMode === "existing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2590
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-target-ws", children: "\u76EE\u6807\u5DE5\u4F5C\u533A" }),
2591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { id: "mv-target-ws", value: targetWs, onChange: (e) => setTargetWs(e.target.value), children: [
2592
+ workspaces.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\uFF08\u6682\u65E0\u5DE5\u4F5C\u533A\uFF09" }),
2593
+ workspaces.map((w) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", { value: w.workspaceId, children: [
2594
+ w.title,
2595
+ " \xB7 ",
2596
+ w.path
2597
+ ] }, w.workspaceId))
2598
+ ] })
2599
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2600
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-new-path", children: "\u65B0\u5DE5\u4F5C\u533A\u76EE\u5F55\u8DEF\u5F84" }),
2518
2601
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-browse-row", children: [
2519
2602
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2520
2603
  "input",
2521
2604
  {
2522
- id: "dsm-tag-attach-" + String(it.sessionId),
2605
+ id: "mv-new-path",
2523
2606
  type: "text",
2524
- value: cardTagName,
2525
- disabled: locked,
2526
- maxLength: 24,
2527
- placeholder: "\u6807\u7B7E\u540D\uFF08\u4E0D\u80FD\u542B\u659C\u6760\uFF0C\u6700\u957F 24 \u5B57\uFF09",
2528
- onChange: (e) => setCardTagName(e.target.value),
2529
- onKeyDown: (e) => {
2530
- if (e.key === "Enter") {
2531
- e.preventDefault();
2532
- createTagAndAttach(it.sessionId);
2533
- }
2534
- }
2607
+ value: newPath,
2608
+ onChange: (e) => setNewPath(e.target.value),
2609
+ placeholder: "\u4F8B\u5982 /Users/you/Projects/demo \u6216 ~/demo"
2535
2610
  }
2536
2611
  ),
2537
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: locked || !cardTagName.trim(), title: locked && !tagsReady ? "\u6807\u7B7E\u6570\u636E\u672A\u80FD\u52A0\u8F7D\uFF0C\u6682\u65F6\u65E0\u6CD5\u65B0\u5EFA\u6807\u7B7E" : "\u65B0\u5EFA\u8FD9\u4E2A\u6807\u7B7E\u5E76\u7ACB\u5373\u8D34\u5230\u5F53\u524D\u4F1A\u8BDD", onClick: () => createTagAndAttach(it.sessionId), children: "\u8D34\u4E0A" })
2612
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2613
+ "button",
2614
+ {
2615
+ type: "button",
2616
+ className: "archv-btn",
2617
+ onClick: pickDirectory,
2618
+ disabled: busy !== null || picking || !workspacesSvc,
2619
+ title: !workspacesSvc ? "\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9" : "\u6253\u5F00\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9\u7A97\u53E3",
2620
+ children: picking ? "\u9009\u62E9\u4E2D\u2026" : "\u6D4F\u89C8\u2026"
2621
+ }
2622
+ )
2538
2623
  ] })
2539
2624
  ] }),
2540
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "\u52FE\u9009\u5373\u65F6\u751F\u6548\uFF1B\u5355\u4E2A\u4F1A\u8BDD\u7684\u6807\u7B7E\u6570\u91CF\u4EE5\u670D\u52A1\u7AEF\u4E0A\u9650\u4E3A\u51C6\uFF0C\u8D85\u65F6\u4F1A\u63D0\u793A\u5E76\u56DE\u9000\u3002" })
2541
- ] });
2542
- })(),
2543
- openDetails === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet", role: "region", "aria-label": "\u4F1A\u8BDD\u8BE6\u60C5", children: [
2544
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet-head", children: [
2545
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "dtl-sheet-title", children: "\u4F1A\u8BDD\u8BE6\u60C5" }),
2546
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED\u8BE6\u60C5", onClick: () => setOpenDetails(null), children: "\xD7" })
2625
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-foot", children: [
2626
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", onClick: () => setOpenMove(null), children: "\u53D6\u6D88" }),
2627
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "archv-btn archv-go", disabled: busy !== null, onClick: () => doMove(it), children: [
2628
+ busy === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-spin", "aria-hidden": "true" }),
2629
+ "\u786E\u8BA4\u79FB\u52A8"
2630
+ ] })
2631
+ ] })
2547
2632
  ] }),
2548
- detailsLoading === it.sessionId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-skel", "aria-label": "\u52A0\u8F7D\u4E2D", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-skel-card" }, i)) }) : (() => {
2549
- const d = details[it.sessionId];
2550
- if (!d) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-paths", children: "\u6682\u65E0\u8BE6\u60C5" });
2551
- const st = d.stats || {};
2552
- const tools = st.toolCounts ? Object.entries(st.toolCounts).sort((a, b) => b[1] - a[1]).slice(0, 10) : [];
2553
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2554
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-grid", children: [
2555
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2556
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u78C1\u76D8\u5360\u7528" }),
2557
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: fmtBytes(d.sizeBytes) || "\u2014" })
2633
+ openTags === it.sessionId && (() => {
2634
+ const cur = Array.isArray(assignments[String(it.sessionId)]) ? assignments[String(it.sessionId)] : [];
2635
+ const locked = tagBusy !== null || !tagsReady;
2636
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet", role: "region", "aria-label": "\u4F1A\u8BDD\u6807\u7B7E", children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet-head", children: [
2638
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { className: "mv-sheet-title", children: [
2639
+ "\u4F1A\u8BDD\u6807\u7B7E \xB7 ",
2640
+ it.title || shortId(it.sessionId)
2558
2641
  ] }),
2559
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2560
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u8F6E\u6B21 / \u6B65\u9AA4" }),
2561
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2562
- st.turns ?? 0,
2563
- " / ",
2564
- st.steps ?? 0
2642
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED", onClick: () => setOpenTags(null), children: "\xD7" })
2643
+ ] }),
2644
+ tagDefs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "\u8FD8\u6CA1\u6709\u6807\u7B7E\uFF0C\u5728\u4E0B\u65B9\u65B0\u5EFA\u7B2C\u4E00\u4E2A\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsm-taglist", children: tagDefs.map((t) => {
2645
+ const checked = cur.some((id) => String(id) === String(t.id));
2646
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dsm-tagcheck", children: [
2647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked, disabled: locked, onChange: () => toggleTagFor(it.sessionId, t.id) }),
2648
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-tagcheck-name", title: t.name, children: t.name })
2649
+ ] }, String(t.id));
2650
+ }) }),
2651
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "dsm-tag-attach-" + String(it.sessionId), children: "\u65B0\u5EFA\u6807\u7B7E\u5E76\u8D34\u4E0A" }),
2653
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-browse-row", children: [
2654
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2655
+ "input",
2656
+ {
2657
+ id: "dsm-tag-attach-" + String(it.sessionId),
2658
+ type: "text",
2659
+ value: cardTagName,
2660
+ disabled: locked,
2661
+ maxLength: 24,
2662
+ placeholder: "\u6807\u7B7E\u540D\uFF08\u4E0D\u80FD\u542B\u659C\u6760\uFF0C\u6700\u957F 24 \u5B57\uFF09",
2663
+ onChange: (e) => setCardTagName(e.target.value),
2664
+ onKeyDown: (e) => {
2665
+ if (e.key === "Enter") {
2666
+ e.preventDefault();
2667
+ createTagAndAttach(it.sessionId);
2668
+ }
2669
+ }
2670
+ }
2671
+ ),
2672
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: locked || !cardTagName.trim(), title: locked && !tagsReady ? "\u6807\u7B7E\u6570\u636E\u672A\u80FD\u52A0\u8F7D\uFF0C\u6682\u65F6\u65E0\u6CD5\u65B0\u5EFA\u6807\u7B7E" : "\u65B0\u5EFA\u8FD9\u4E2A\u6807\u7B7E\u5E76\u7ACB\u5373\u8D34\u5230\u5F53\u524D\u4F1A\u8BDD", onClick: () => createTagAndAttach(it.sessionId), children: "\u8D34\u4E0A" })
2673
+ ] })
2674
+ ] }),
2675
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "\u52FE\u9009\u5373\u65F6\u751F\u6548\uFF1B\u5355\u4E2A\u4F1A\u8BDD\u7684\u6807\u7B7E\u6570\u91CF\u4EE5\u670D\u52A1\u7AEF\u4E0A\u9650\u4E3A\u51C6\uFF0C\u8D85\u65F6\u4F1A\u63D0\u793A\u5E76\u56DE\u9000\u3002" })
2676
+ ] });
2677
+ })(),
2678
+ openDetails === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet", role: "region", "aria-label": "\u4F1A\u8BDD\u8BE6\u60C5", children: [
2679
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet-head", children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "dtl-sheet-title", children: "\u4F1A\u8BDD\u8BE6\u60C5" }),
2681
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED\u8BE6\u60C5", onClick: () => setOpenDetails(null), children: "\xD7" })
2682
+ ] }),
2683
+ detailsLoading === it.sessionId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-skel", "aria-label": "\u52A0\u8F7D\u4E2D", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-skel-card" }, i)) }) : (() => {
2684
+ const d = details[it.sessionId];
2685
+ if (!d) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-paths", children: "\u6682\u65E0\u8BE6\u60C5" });
2686
+ const st = d.stats || {};
2687
+ const tools = st.toolCounts ? Object.entries(st.toolCounts).sort((a, b) => b[1] - a[1]).slice(0, 10) : [];
2688
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2689
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-grid", children: [
2690
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2691
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u78C1\u76D8\u5360\u7528" }),
2692
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: fmtBytes(d.sizeBytes) || "\u2014" })
2693
+ ] }),
2694
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u8F6E\u6B21 / \u6B65\u9AA4" }),
2696
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2697
+ st.turns ?? 0,
2698
+ " / ",
2699
+ st.steps ?? 0
2700
+ ] })
2701
+ ] }),
2702
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u7528\u6237 / \u52A9\u624B" }),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2705
+ st.userMessages ?? 0,
2706
+ " / ",
2707
+ st.assistantMessages ?? 0
2708
+ ] })
2709
+ ] }),
2710
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2711
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u5DE5\u5177\u8C03\u7528" }),
2712
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: st.toolCalls ?? 0 })
2713
+ ] }),
2714
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u56FE\u7247\u9644\u4EF6" }),
2716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: st.attachments ?? 0 })
2717
+ ] }),
2718
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2719
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u521B\u5EFA / \u66F4\u65B0" }),
2720
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2721
+ fmtDate(d.createdAt) || "\u2014",
2722
+ " \xB7 ",
2723
+ fmtDate(d.updatedAt) || "\u2014"
2724
+ ] })
2565
2725
  ] })
2566
2726
  ] }),
2567
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2568
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u7528\u6237 / \u52A9\u624B" }),
2569
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2570
- st.userMessages ?? 0,
2571
- " / ",
2572
- st.assistantMessages ?? 0
2573
- ] })
2727
+ tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2728
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5DE5\u5177\u4F7F\u7528" }),
2729
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-tags", children: tools.map(([t, c]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-tag", children: [
2730
+ t,
2731
+ " \xD7",
2732
+ c
2733
+ ] }, t)) })
2574
2734
  ] }),
2575
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2576
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u5DE5\u5177\u8C03\u7528" }),
2577
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: st.toolCalls ?? 0 })
2735
+ st.fetches && st.fetches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2736
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u641C\u7D22 / \u6293\u53D6" }),
2737
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: st.fetches.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2738
+ f.tool,
2739
+ f.query ? ` \u300C${f.query}\u300D` : ""
2740
+ ] }, i)) })
2578
2741
  ] }),
2579
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2580
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u56FE\u7247\u9644\u4EF6" }),
2581
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-v", children: st.attachments ?? 0 })
2742
+ d.files && d.files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2743
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec-t", children: [
2744
+ "\u5199\u8FC7\u7684\u6587\u4EF6\uFF08",
2745
+ d.files.length,
2746
+ "\uFF09"
2747
+ ] }),
2748
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: d.files.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2749
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: f.path }),
2750
+ " ",
2751
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-filetool", children: [
2752
+ "(",
2753
+ f.tool,
2754
+ ")"
2755
+ ] })
2756
+ ] }, i)) })
2582
2757
  ] }),
2583
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2584
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u521B\u5EFA / \u66F4\u65B0" }),
2585
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2586
- fmtDate(d.createdAt) || "\u2014",
2587
- " \xB7 ",
2588
- fmtDate(d.updatedAt) || "\u2014"
2758
+ d.lineage && (d.lineage.parentSessionId || d.lineage.children && d.lineage.children.length > 0 || d.lineage.subagents && d.lineage.subagents.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2759
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u8840\u7F18" }),
2760
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-paths", children: [
2761
+ d.lineage.parentSessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2762
+ "\u7236\u4F1A\u8BDD: ",
2763
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.parentSessionId })
2764
+ ] }),
2765
+ d.lineage.children && d.lineage.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2766
+ "\u5B50\u4F1A\u8BDD (",
2767
+ d.lineage.children.length,
2768
+ "): ",
2769
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.children.join(", ") })
2770
+ ] }),
2771
+ d.lineage.subagents && d.lineage.subagents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2772
+ "\u5B50\u4EE3\u7406 (",
2773
+ d.lineage.subagents.length,
2774
+ "): ",
2775
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.subagents.join(", ") })
2776
+ ] })
2589
2777
  ] })
2590
- ] })
2591
- ] }),
2592
- tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2593
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5DE5\u5177\u4F7F\u7528" }),
2594
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-tags", children: tools.map(([t, c]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-tag", children: [
2595
- t,
2596
- " \xD7",
2597
- c
2598
- ] }, t)) })
2599
- ] }),
2600
- st.fetches && st.fetches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2601
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u641C\u7D22 / \u6293\u53D6" }),
2602
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: st.fetches.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2603
- f.tool,
2604
- f.query ? ` \u300C${f.query}\u300D` : ""
2605
- ] }, i)) })
2606
- ] }),
2607
- d.files && d.files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2608
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec-t", children: [
2609
- "\u5199\u8FC7\u7684\u6587\u4EF6\uFF08",
2610
- d.files.length,
2611
- "\uFF09"
2612
2778
  ] }),
2613
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: d.files.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2614
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: f.path }),
2615
- " ",
2616
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-filetool", children: [
2617
- "(",
2618
- f.tool,
2619
- ")"
2620
- ] })
2621
- ] }, i)) })
2622
- ] }),
2623
- d.lineage && (d.lineage.parentSessionId || d.lineage.children && d.lineage.children.length > 0 || d.lineage.subagents && d.lineage.subagents.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2624
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u8840\u7F18" }),
2625
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-paths", children: [
2626
- d.lineage.parentSessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2627
- "\u7236\u4F1A\u8BDD: ",
2628
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.parentSessionId })
2629
- ] }),
2630
- d.lineage.children && d.lineage.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2631
- "\u5B50\u4F1A\u8BDD (",
2632
- d.lineage.children.length,
2633
- "): ",
2634
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.children.join(", ") })
2779
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2780
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5BFC\u51FA" }),
2781
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-export", children: [
2782
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2783
+ "a",
2784
+ {
2785
+ className: "archv-btn",
2786
+ href: `/api/session.export?sessionId=${encodeURIComponent(it.sessionId)}&includeDescendants=true`,
2787
+ onClick: (e) => e.stopPropagation(),
2788
+ style: zipOk ? void 0 : { pointerEvents: "none", opacity: 0.45 },
2789
+ title: zipOk ? "\u542B\u5B50\u4F1A\u8BDD\u4E0E\u9644\u4EF6\uFF0C\u7531 DSH \u63D0\u4F9B" : "\u5F53\u524D\u6301\u4E45\u5316\u540E\u7AEF\u4E0D\u652F\u6301\u539F\u59CB\u65E5\u5FD7\u5BFC\u51FA",
2790
+ children: "\u4E0B\u8F7D\u539F\u59CB\u65E5\u5FD7 (ZIP)"
2791
+ }
2792
+ ),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: mdBusy === it.sessionId, onClick: () => exportMarkdown(it), children: mdBusy === it.sessionId ? "\u751F\u6210\u4E2D\u2026" : "\u5BFC\u51FA Markdown" })
2635
2794
  ] }),
2636
- d.lineage.subagents && d.lineage.subagents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2637
- "\u5B50\u4EE3\u7406 (",
2638
- d.lineage.subagents.length,
2639
- "): ",
2640
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.subagents.join(", ") })
2641
- ] })
2795
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "ZIP \u542B\u5B50\u4F1A\u8BDD\u4E0E\u9644\u4EF6\uFF0C\u7531 DSH \u63D0\u4F9B \xB7 Markdown \u4E3A\u672C\u63D2\u4EF6\u751F\u6210\u7684\u53EF\u8BFB\u5BF9\u8BDD\u8BB0\u5F55" })
2642
2796
  ] })
2643
- ] }),
2644
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2645
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5BFC\u51FA" }),
2646
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-export", children: [
2647
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2648
- "a",
2649
- {
2650
- className: "archv-btn",
2651
- href: `/api/session.export?sessionId=${encodeURIComponent(it.sessionId)}&includeDescendants=true`,
2652
- onClick: (e) => e.stopPropagation(),
2653
- style: zipOk ? void 0 : { pointerEvents: "none", opacity: 0.45 },
2654
- title: zipOk ? "\u542B\u5B50\u4F1A\u8BDD\u4E0E\u9644\u4EF6\uFF0C\u7531 DSH \u63D0\u4F9B" : "\u5F53\u524D\u6301\u4E45\u5316\u540E\u7AEF\u4E0D\u652F\u6301\u539F\u59CB\u65E5\u5FD7\u5BFC\u51FA",
2655
- children: "\u4E0B\u8F7D\u539F\u59CB\u65E5\u5FD7 (ZIP)"
2656
- }
2657
- ),
2658
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: mdBusy === it.sessionId, onClick: () => exportMarkdown(it), children: mdBusy === it.sessionId ? "\u751F\u6210\u4E2D\u2026" : "\u5BFC\u51FA Markdown" })
2659
- ] }),
2660
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "ZIP \u542B\u5B50\u4F1A\u8BDD\u4E0E\u9644\u4EF6\uFF0C\u7531 DSH \u63D0\u4F9B \xB7 Markdown \u4E3A\u672C\u63D2\u4EF6\u751F\u6210\u7684\u53EF\u8BFB\u5BF9\u8BDD\u8BB0\u5F55" })
2661
- ] })
2662
- ] });
2663
- })()
2664
- ] })
2665
- ] }, it.sessionId);
2666
- }) }) : null
2797
+ ] });
2798
+ })()
2799
+ ] })
2800
+ ] }, it.sessionId);
2801
+ }),
2802
+ groupByLineage && orphanSubagents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-card dsm-orphan-card", role: "listitem", children: [
2803
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-body", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-main", children: [
2804
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-titlerow", children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2806
+ "button",
2807
+ {
2808
+ type: "button",
2809
+ className: "dsm-kids-toggle",
2810
+ "aria-expanded": orphanOpen,
2811
+ title: (orphanOpen ? "\u6536\u8D77 " : "\u5C55\u5F00 ") + orphanSubagents.length + " \u4E2A\u672A\u5F52\u5C5E\u7684\u5B50\u4EE3\u7406\u4F1A\u8BDD",
2812
+ onClick: () => setOpenOrphans(!openOrphans),
2813
+ children: [
2814
+ orphanOpen ? "\u25BE" : "\u25B8",
2815
+ " ",
2816
+ orphanSubagents.length,
2817
+ " \u5B50\u4EE3\u7406"
2818
+ ]
2819
+ }
2820
+ ),
2821
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-name", children: "\u672A\u5F52\u5C5E\u7684\u5B50\u4EE3\u7406\u4F1A\u8BDD" })
2822
+ ] }),
2823
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-meta", children: [
2824
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-wtag archv-wgone", children: "\u7236\u4F1A\u8BDD\u4E0D\u5728\u5F53\u524D\u5217\u8868" }),
2825
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-dot", children: "\xB7" }),
2826
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-date", children: "\u4E0D\u518D\u6DF7\u8FDB\u4E0A\u9762\u7684\u4F1A\u8BDD\u5217\u8868\uFF1B\u5C55\u5F00\u540E\u53EF\u6253\u5F00 / \u5F52\u6863 / \u5220\u9664" })
2827
+ ] })
2828
+ ] }) }) }),
2829
+ orphanOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsm-kids", "aria-label": "\u672A\u5F52\u5C5E\u5B50\u4EE3\u7406\u4F1A\u8BDD", children: orphanSubagents.map((k) => {
2830
+ const li = lineage[String(k.sessionId)];
2831
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsm-kid", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsm-kid-row", children: [
2832
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-kid-name", title: k.title || k.sessionId, children: k.title || "(\u65E0\u6807\u9898)" }),
2833
+ emptyBadge(k.sessionId),
2834
+ tagChips(k.sessionId),
2835
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsm-kid-meta", children: [
2836
+ k.archived ? "\u5DF2\u5F52\u6863" : "\u6D3B\u52A8",
2837
+ fmtDate(k.createdAt) ? ` \xB7 ${fmtDate(k.createdAt)}` : ""
2838
+ ] }),
2839
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsm-kid-acts", children: [
2840
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: busy !== null, title: "\u5207\u6362\u5230\u8FD9\u4E2A\u5B50\u4EE3\u7406\u4F1A\u8BDD\uFF08\u8BBE\u7F6E\u9762\u677F\u6321\u7740\u4F1A\u8BDD\u533A\uFF0C\u5173\u6389\u5373\u53EF\u770B\u5230\uFF09", onClick: async () => {
2841
+ const name = k.title || String(k.sessionId).slice(0, 8) + "\u2026";
2842
+ const res = await dsmOpenSessionById(k.sessionId, li && li.parentSession || null);
2843
+ const msg = openSubagentToast(res, name, "panel");
2844
+ showToast(msg.text, msg.kind);
2845
+ }, children: "\u6253\u5F00" }),
2846
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: busy !== null, onClick: () => act(k.archived ? "restore" : "archive", k), children: k.archived ? "\u6062\u590D" : "\u5F52\u6863" }),
2847
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", disabled: busy !== null, title: "\u79FB\u5165\u56DE\u6536\u7AD9\uFF0C\u53EF\u5728\u56DE\u6536\u7AD9\u6062\u590D", onClick: () => setDelTarget(k), children: "\u5220\u9664" })
2848
+ ] })
2849
+ ] }) }, k.sessionId);
2850
+ }) })
2851
+ ] })
2852
+ ] }) : null
2667
2853
  ] }),
2668
2854
  toast && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "archv-status" + (toast.kind === "err" ? " archv-status-err" : "") + (String(toast.msg).length > 28 ? " archv-status-long" : ""), role: "status", title: "\u70B9\u51FB\u5173\u95ED", onClick: () => setToast(null), children: toast.msg }),
2669
2855
  delTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dlg-backdrop", onClick: () => setDelTarget(null), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: dialogRef, className: "dlg", role: "alertdialog", "aria-modal": "true", "aria-label": "\u5220\u9664\u4F1A\u8BDD", onClick: (e) => e.stopPropagation(), children: [
@@ -2673,6 +2859,14 @@ function SessionPanel({ workspacesSvc }) {
2673
2859
  delTarget.title || delTarget.sessionId,
2674
2860
  "\u300D\uFF1F\u5C06\u79FB\u5165\u56DE\u6536\u7AD9\uFF0C\u53EF\u5728\u672C\u9875\u5E95\u90E8\u300C\u56DE\u6536\u7AD9\u300D\u4E2D\u6062\u590D\u6216\u5F7B\u5E95\u5220\u9664\u3002"
2675
2861
  ] }),
2862
+ delCascadeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dlg-check", children: [
2863
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: cascadeSub, disabled: busy !== null, onChange: (e) => setCascadeSub(e.target.checked) }),
2864
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
2865
+ "\u540C\u65F6\u5220\u9664\u5B83\u7684 ",
2866
+ delCascadeCount,
2867
+ " \u4E2A\u5B50\u4EE3\u7406\u4F1A\u8BDD\uFF08\u5B50\u4EE3\u7406\u751F\u547D\u5468\u671F\u8DDF\u968F\u7236\u4F1A\u8BDD\uFF09\u3002\u53D6\u6D88\u52FE\u9009\u5219\u4FDD\u7559\uFF0C\u5B83\u4EEC\u4F1A\u6536\u8FDB\u300C\u672A\u5F52\u5C5E\u7684\u5B50\u4EE3\u7406\u4F1A\u8BDD\u300D\u5361\u7247\uFF0C\u4ECD\u53EF\u5355\u72EC\u5904\u7406\u3002"
2868
+ ] })
2869
+ ] }),
2676
2870
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dlg-actions", children: [
2677
2871
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: busy !== null, onClick: () => setDelTarget(null), children: "\u53D6\u6D88" }),
2678
2872
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", disabled: busy !== null, onClick: doDeleteConfirmed, children: "\u79FB\u5165\u56DE\u6536\u7AD9" })
@@ -2878,6 +3072,7 @@ function dsmToggleManual(id) {
2878
3072
  if (dsmRepaintDots) dsmRepaintDots();
2879
3073
  }
2880
3074
  var dsmTrashIds = null;
3075
+ var dsmTrashCountByCwd = null;
2881
3076
  var dsmServerPurgedIds = /* @__PURE__ */ new Set();
2882
3077
  var dsmAuthoritativeTitles = /* @__PURE__ */ new Map();
2883
3078
  var dsmTrashTick = 0;
@@ -2953,6 +3148,7 @@ async function dsmLoadTrashIds() {
2953
3148
  try {
2954
3149
  const r = await postJSON("/archived-sessions/sidebar-state", {});
2955
3150
  dsmTrashIds = new Set((r && r.trashedSessionIds || []).map(String));
3151
+ dsmTrashCountByCwd = r && r.trashedCountByCwd && typeof r.trashedCountByCwd === "object" ? new Map(Object.entries(r.trashedCountByCwd).map(([k, v]) => [String(k), Number(v) || 0])) : null;
2956
3152
  dsmServerPurgedIds = new Set((r && r.purgedSessionIds || []).map(String));
2957
3153
  for (const id of [...dsmPendingPurged]) {
2958
3154
  if (dsmServerPurgedIds.has(id)) dsmPendingPurged.delete(id);
@@ -3013,6 +3209,22 @@ function dsmTeardownSidebarAug() {
3013
3209
  } catch (e) {
3014
3210
  }
3015
3211
  }
3212
+ try {
3213
+ document.querySelectorAll("[data-dsm-hidden]").forEach((row) => {
3214
+ row.style.display = "";
3215
+ row.removeAttribute("data-dsm-hidden");
3216
+ });
3217
+ document.querySelectorAll("[data-dsm-overflow-hidden], [data-dsm-overflow-base]").forEach((btn) => {
3218
+ const base = btn.getAttribute("data-dsm-overflow-base");
3219
+ if (base != null && btn.textContent !== base) btn.textContent = base;
3220
+ btn.style.display = "";
3221
+ btn.removeAttribute("data-dsm-overflow-hidden");
3222
+ btn.removeAttribute("data-dsm-overflow-base");
3223
+ btn.removeAttribute("data-dsm-overflow-write");
3224
+ btn.removeAttribute("data-dsm-overflow-ver");
3225
+ });
3226
+ } catch (e) {
3227
+ }
3016
3228
  try {
3017
3229
  document.querySelectorAll("[data-dsm-group-hidden]").forEach((owner) => {
3018
3230
  owner.style.display = owner.dataset.dsmPrevDisplay || "";
@@ -3054,13 +3266,25 @@ function createSidebarAdapter() {
3054
3266
  }
3055
3267
  return out;
3056
3268
  };
3269
+ const recognizeGroupQuiet = (row) => {
3270
+ if (disabled || !row || typeof row !== "object") return null;
3271
+ let f = findFiber(row);
3272
+ let guard = 0;
3273
+ while (f && guard++ < 300) {
3274
+ const props = f.memoizedProps;
3275
+ if (props && props.group && typeof props.group === "object") return props.group;
3276
+ f = f.return;
3277
+ }
3278
+ return null;
3279
+ };
3057
3280
  return {
3058
3281
  version: SIDEBAR_ADAPTER_VERSION,
3059
3282
  get disabled() {
3060
3283
  return disabled;
3061
3284
  },
3062
3285
  findFiber,
3063
- recognize
3286
+ recognize,
3287
+ recognizeGroupQuiet
3064
3288
  };
3065
3289
  }
3066
3290
  var sidebarAdapter = createSidebarAdapter();
@@ -3337,6 +3561,21 @@ function installSidebarSessionMenuAug() {
3337
3561
  function installSidebarStatusDots() {
3338
3562
  if (typeof document === "undefined") return;
3339
3563
  const DOT = "data-dsm-dot";
3564
+ const DSM_HIDDEN_ATTR = "data-dsm-hidden";
3565
+ const GROUP_UNIT_ATTR = "data-dsm-group-hidden";
3566
+ const DSM_OVERFLOW_BASE = "data-dsm-overflow-base";
3567
+ const DSM_OVERFLOW_WRITE = "data-dsm-overflow-write";
3568
+ const DSM_OVERFLOW_VER = "data-dsm-overflow-ver";
3569
+ const DSM_OVERFLOW_HIDDEN = "data-dsm-overflow-hidden";
3570
+ let overflowDebugged = false;
3571
+ const debugOverflowOnce = (msg) => {
3572
+ if (overflowDebugged) return;
3573
+ overflowDebugged = true;
3574
+ try {
3575
+ console.debug("[dsh-sessions-manager] \u5C55\u5F00\u8BA1\u6570\uFF1A" + msg);
3576
+ } catch (e) {
3577
+ }
3578
+ };
3340
3579
  if (!document.querySelector("style[data-dsm=aug]")) {
3341
3580
  const s = document.createElement("style");
3342
3581
  s.dataset.dsm = "aug";
@@ -3367,36 +3606,258 @@ function installSidebarStatusDots() {
3367
3606
  };
3368
3607
  const manualUnread = dsmLoadManual();
3369
3608
  const titleBaselines = /* @__PURE__ */ new WeakMap();
3370
- function dsmSyncEmptyGroups() {
3371
- let groups = null;
3609
+ const setGroupHidden = (scope, hidden) => {
3610
+ if (hidden) {
3611
+ if (!scope.hasAttribute(GROUP_UNIT_ATTR)) {
3612
+ scope.dataset.dsmPrevDisplay = scope.style.display || "";
3613
+ scope.setAttribute(GROUP_UNIT_ATTR, "");
3614
+ }
3615
+ if (scope.style.display !== "none") scope.style.display = "none";
3616
+ return;
3617
+ }
3618
+ if (!scope.hasAttribute(GROUP_UNIT_ATTR)) return;
3619
+ const prev = scope.dataset.dsmPrevDisplay || "";
3620
+ if (scope.style.display !== prev) scope.style.display = prev;
3621
+ scope.removeAttribute(GROUP_UNIT_ATTR);
3622
+ delete scope.dataset.dsmPrevDisplay;
3623
+ };
3624
+ const isShownWithin = (el, stopAt) => {
3625
+ let node = el;
3626
+ while (node && node !== stopAt) {
3627
+ if (node.style && node.style.display === "none") return false;
3628
+ if (node.hasAttribute && (node.hasAttribute(GROUP_UNIT_ATTR) || node.hasAttribute(DSM_HIDDEN_ATTR))) return false;
3629
+ node = node.parentElement;
3630
+ }
3631
+ return true;
3632
+ };
3633
+ const groupSessionRows = (scope, btn) => {
3634
+ const out = [];
3635
+ if (!scope || !scope.children) return out;
3636
+ for (const el of scope.children) {
3637
+ if (el === btn || !el.getAttribute) continue;
3638
+ const k = el.getAttribute("data-row-key") || "";
3639
+ if (el.getAttribute("role") === "treeitem" && k.startsWith("session:")) out.push(el);
3640
+ }
3641
+ if (out.length) return out;
3642
+ let rows = null;
3643
+ try {
3644
+ rows = scope.querySelectorAll('[role="treeitem"][data-row-key^="session:"]');
3645
+ } catch (e) {
3646
+ return out;
3647
+ }
3648
+ for (const el of rows) {
3649
+ let owner = el.parentElement;
3650
+ let ok = true;
3651
+ while (owner && owner !== scope) {
3652
+ if (owner.getAttribute && owner.getAttribute("role") === "group") {
3653
+ ok = false;
3654
+ break;
3655
+ }
3656
+ owner = owner.parentElement;
3657
+ }
3658
+ if (ok) out.push(el);
3659
+ }
3660
+ return out;
3661
+ };
3662
+ const groupContainerOf = (row) => {
3663
+ let el = row ? row.parentElement : null;
3664
+ for (let depth = 0; el && depth < 4; depth++) {
3665
+ if (typeof el.getAttribute !== "function") return null;
3666
+ if (!el.getAttribute("role")) return el;
3667
+ el = el.parentElement;
3668
+ }
3669
+ return null;
3670
+ };
3671
+ function dsmSyncEmptyGroups(purgedNow) {
3672
+ let rows = null;
3372
3673
  try {
3373
- groups = document.querySelectorAll('[role="group"]');
3674
+ rows = document.querySelectorAll('[role="treeitem"][data-row-key^="workspace:"]');
3374
3675
  } catch (e) {
3375
3676
  return;
3376
3677
  }
3377
- if (!groups || !groups.length) return;
3378
- groups.forEach((g) => {
3379
- const items = g.querySelectorAll('[role="treeitem"]');
3380
- if (!items.length) return;
3381
- let visible = 0;
3382
- items.forEach((it) => {
3383
- if (it.style.display !== "none") visible++;
3384
- });
3385
- const owner = g.closest('[role="treeitem"]') || g;
3386
- if (visible === 0) {
3387
- if (!owner.hasAttribute("data-dsm-group-hidden")) {
3388
- owner.dataset.dsmPrevDisplay = owner.style.display || "";
3389
- owner.setAttribute("data-dsm-group-hidden", "");
3678
+ if (!rows || !rows.length) return;
3679
+ const purged = purgedNow instanceof Set ? purgedNow : /* @__PURE__ */ new Set();
3680
+ let hiddenIds = null;
3681
+ const hiddenIdSet = () => {
3682
+ if (hiddenIds) return hiddenIds;
3683
+ hiddenIds = /* @__PURE__ */ new Set();
3684
+ if (dsmTrashIds) for (const id of dsmTrashIds) hiddenIds.add(id);
3685
+ for (const id of purged) hiddenIds.add(id);
3686
+ for (const [id, info] of dsmLineage.entries()) if (info && info.empty) hiddenIds.add(id);
3687
+ return hiddenIds;
3688
+ };
3689
+ rows.forEach((row) => {
3690
+ try {
3691
+ const scope = groupContainerOf(row);
3692
+ if (!scope || scope === document.body) return;
3693
+ let rendered = 0;
3694
+ for (const el of groupSessionRows(scope, row)) {
3695
+ if (el.hasAttribute(DSM_HIDDEN_ATTR)) continue;
3696
+ rendered++;
3390
3697
  }
3391
- if (owner.style.display !== "none") owner.style.display = "none";
3392
- } else if (owner.hasAttribute("data-dsm-group-hidden")) {
3393
- const prev = owner.dataset.dsmPrevDisplay || "";
3394
- if (owner.style.display !== prev) owner.style.display = prev;
3395
- owner.removeAttribute("data-dsm-group-hidden");
3396
- delete owner.dataset.dsmPrevDisplay;
3698
+ if (rendered > 0) {
3699
+ setGroupHidden(scope, false);
3700
+ return;
3701
+ }
3702
+ for (const nested of scope.querySelectorAll('[data-row-key^="workspace:"]')) {
3703
+ if (nested === row) continue;
3704
+ if (!isShownWithin(nested, scope)) continue;
3705
+ setGroupHidden(scope, false);
3706
+ return;
3707
+ }
3708
+ const group = sidebarAdapter.recognizeGroupQuiet(row);
3709
+ const sessions = group && Array.isArray(group.sessions) ? group.sessions : null;
3710
+ setGroupHidden(scope, aliveSessionCount(sessions, hiddenIdSet()) === 0);
3711
+ } catch (e) {
3397
3712
  }
3398
3713
  });
3399
3714
  }
3715
+ const OVERFLOW_SIGS = /* @__PURE__ */ new WeakMap();
3716
+ const overflowSignature = (scope, btn, purgedNow) => {
3717
+ let n = 0;
3718
+ let firstKey = "";
3719
+ let lastKey = "";
3720
+ for (const el of groupSessionRows(scope, btn)) {
3721
+ if (el.hasAttribute(DSM_HIDDEN_ATTR)) continue;
3722
+ n++;
3723
+ const k = el.getAttribute("data-row-key") || "";
3724
+ if (!firstKey) firstKey = k;
3725
+ lastKey = k;
3726
+ }
3727
+ return n + "|" + firstKey + "|" + lastKey + "|" + (btn.textContent || "") + "|" + (btn.style.display || "") + "|" + (dsmTrashIds ? dsmTrashIds.size : -1) + "|" + purgedNow.size + "|" + dsmLineage.size;
3728
+ };
3729
+ function dsmSyncOverflowLabels(purgedNow) {
3730
+ let buttons = null;
3731
+ try {
3732
+ buttons = document.querySelectorAll('[data-row-key^="overflow:"]');
3733
+ } catch (e) {
3734
+ return;
3735
+ }
3736
+ if (!buttons || !buttons.length) return;
3737
+ try {
3738
+ buttons.forEach((btn) => {
3739
+ const scope = btn.parentElement;
3740
+ if (!scope || !scope.children) return;
3741
+ const sig = overflowSignature(scope, btn, purgedNow);
3742
+ if (OVERFLOW_SIGS.get(btn) === sig) return;
3743
+ const key = (btn.getAttribute("data-row-key") || "").slice("overflow:".length);
3744
+ const wsKey = "workspace:" + key;
3745
+ let wsRow = null;
3746
+ for (const el of scope.children) {
3747
+ if (el.getAttribute && el.getAttribute("data-row-key") === wsKey) {
3748
+ wsRow = el;
3749
+ break;
3750
+ }
3751
+ }
3752
+ if (!wsRow) {
3753
+ try {
3754
+ wsRow = scope.querySelector('[data-row-key="' + wsKey.replace(/"/g, '\\"') + '"]');
3755
+ } catch (e) {
3756
+ wsRow = null;
3757
+ }
3758
+ }
3759
+ const group = wsRow ? sidebarAdapter.recognizeGroupQuiet(wsRow) : null;
3760
+ const nodes = group && Array.isArray(group.sessions) ? group.sessions : null;
3761
+ if (!nodes) {
3762
+ restoreOverflowButton(btn);
3763
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3764
+ return;
3765
+ }
3766
+ const groupCount = group && typeof group.sessionCount === "number" ? group.sessionCount : null;
3767
+ const collapsed = !nodes.length && groupCount != null && groupCount > 0;
3768
+ const ids = /* @__PURE__ */ new Set();
3769
+ for (const node of nodes && nodes.length ? nodes : []) {
3770
+ if (!node || node.blank) continue;
3771
+ const id = node.id != null ? String(node.id) : "";
3772
+ if (!id) continue;
3773
+ if (dsmTrashIds && dsmTrashIds.has(id) || purgedNow.has(id)) continue;
3774
+ const li = dsmLineage.get(id);
3775
+ if (li && li.empty) continue;
3776
+ ids.add(id);
3777
+ }
3778
+ const rendered = [];
3779
+ for (const el of groupSessionRows(scope, btn)) {
3780
+ const k = el.getAttribute("data-row-key") || "";
3781
+ rendered.push({ id: k.slice("session:".length), pluginHidden: el.hasAttribute(DSM_HIDDEN_ATTR) });
3782
+ }
3783
+ if (!nodes.length && !collapsed) {
3784
+ restoreOverflowButton(btn);
3785
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3786
+ return;
3787
+ }
3788
+ if (!ids.size && rendered.length) {
3789
+ restoreOverflowButton(btn);
3790
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3791
+ return;
3792
+ }
3793
+ if (collapsed) {
3794
+ const wsCwd = group && typeof group.cwd === "string" ? group.cwd : null;
3795
+ const trashInGroup = wsCwd != null && dsmTrashCountByCwd ? dsmTrashCountByCwd.get(wsCwd) || 0 : null;
3796
+ const visibleTotal = collapsedVisibleTotal(groupCount, trashInGroup);
3797
+ if (visibleTotal == null) {
3798
+ restoreOverflowButton(btn);
3799
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3800
+ return;
3801
+ }
3802
+ const more2 = remainingRows(visibleTotal, 0);
3803
+ applyOverflowPlan(btn, more2, "\u6298\u53E0 \u603B\u6570 " + groupCount + " / \u56DE\u6536\u7AD9 " + trashInGroup);
3804
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3805
+ return;
3806
+ }
3807
+ const renderedVisible = countRenderedVisible(rendered, ids);
3808
+ const more = remainingRows(ids.size, renderedVisible);
3809
+ applyOverflowPlan(btn, more, "\u53EF\u89C1 " + ids.size + " / \u5DF2\u6E32\u67D3 " + renderedVisible);
3810
+ OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3811
+ });
3812
+ } catch (e) {
3813
+ try {
3814
+ console.debug("[dsh-sessions-manager] \u5C55\u5F00\u8BA1\u6570\u6821\u51C6\u8DF3\u8FC7\uFF1A" + (e && e.message));
3815
+ } catch (e2) {
3816
+ }
3817
+ }
3818
+ }
3819
+ function applyOverflowPlan(btn, more, detail) {
3820
+ const raw = btn.textContent || "";
3821
+ const ver = String(SIDEBAR_ADAPTER_VERSION);
3822
+ const fresh = btn.getAttribute(DSM_OVERFLOW_VER) === ver;
3823
+ const last = fresh ? btn.getAttribute(DSM_OVERFLOW_WRITE) : null;
3824
+ let baseline = fresh ? btn.getAttribute(DSM_OVERFLOW_BASE) : null;
3825
+ if (baseline == null || raw !== last) baseline = raw;
3826
+ btn.setAttribute(DSM_OVERFLOW_BASE, baseline);
3827
+ btn.setAttribute(DSM_OVERFLOW_VER, ver);
3828
+ const bm = baseline.match(/(\d[\d,]*)/);
3829
+ const upstream = bm ? Number(bm[1].replace(/,/g, "")) : null;
3830
+ if (more != null && upstream != null && upstream > 0 && more > upstream) {
3831
+ more = upstream;
3832
+ debugOverflowOnce((detail || "") + "\uFF0C\u8D85\u8FC7\u4E0A\u6E38\u8BA1\u6570 " + upstream + "\uFF0C\u5DF2\u6309\u4E0A\u6E38\u8BA1\u6570\u6536\u655B");
3833
+ }
3834
+ const plan = overflowPlan(baseline, more);
3835
+ if (plan.hide) {
3836
+ if (btn.style.display !== "none") btn.style.display = "none";
3837
+ if (!btn.hasAttribute(DSM_OVERFLOW_HIDDEN)) btn.setAttribute(DSM_OVERFLOW_HIDDEN, "");
3838
+ btn.setAttribute(DSM_OVERFLOW_WRITE, baseline);
3839
+ return;
3840
+ }
3841
+ if (btn.hasAttribute(DSM_OVERFLOW_HIDDEN)) {
3842
+ btn.style.display = "";
3843
+ btn.removeAttribute(DSM_OVERFLOW_HIDDEN);
3844
+ }
3845
+ if (plan.changed) {
3846
+ if (btn.textContent !== plan.text) btn.textContent = plan.text;
3847
+ btn.setAttribute(DSM_OVERFLOW_WRITE, plan.text);
3848
+ } else {
3849
+ if (btn.textContent !== baseline) btn.textContent = baseline;
3850
+ btn.setAttribute(DSM_OVERFLOW_WRITE, baseline);
3851
+ }
3852
+ }
3853
+ function restoreOverflowButton(btn) {
3854
+ const verbatim = btn.getAttribute(DSM_OVERFLOW_BASE);
3855
+ if (verbatim != null && btn.textContent !== verbatim) btn.textContent = verbatim;
3856
+ if (btn.hasAttribute(DSM_OVERFLOW_HIDDEN)) {
3857
+ btn.style.display = "";
3858
+ btn.removeAttribute(DSM_OVERFLOW_HIDDEN);
3859
+ }
3860
+ }
3400
3861
  const paint = () => {
3401
3862
  if (sidebarAdapter.disabled) return;
3402
3863
  const activeId = activeRowId();
@@ -3427,6 +3888,7 @@ function installSidebarStatusDots() {
3427
3888
  const purged = purgedNow;
3428
3889
  if (dsmTrashIds && dsmTrashIds.has(id) || purged.has(id)) {
3429
3890
  if (row.style.display !== "none") row.style.display = "none";
3891
+ if (row.getAttribute(DSM_HIDDEN_ATTR) !== "trash") row.setAttribute(DSM_HIDDEN_ATTR, "trash");
3430
3892
  const d = row.querySelector("[" + DOT + "]");
3431
3893
  if (d) d.remove();
3432
3894
  dsmDropSubList(row, id);
@@ -3449,12 +3911,14 @@ function installSidebarStatusDots() {
3449
3911
  }
3450
3912
  if (hideLineage) {
3451
3913
  if (row.style.display !== "none") row.style.display = "none";
3914
+ if (row.getAttribute(DSM_HIDDEN_ATTR) !== "empty") row.setAttribute(DSM_HIDDEN_ATTR, "empty");
3452
3915
  const d = row.querySelector("[" + DOT + "]");
3453
3916
  if (d) d.remove();
3454
3917
  dsmDropSubList(row, id);
3455
3918
  return;
3456
3919
  }
3457
3920
  if (row.style.display === "none") row.style.display = "";
3921
+ if (row.hasAttribute(DSM_HIDDEN_ATTR)) row.removeAttribute(DSM_HIDDEN_ATTR);
3458
3922
  if (!isEmpty && li && li.parentSession && li.origin !== "subagent") {
3459
3923
  const parentTitle = dsmAuthoritativeTitles.get(li.parentSession);
3460
3924
  const tip = parentTitle ? "\u5206\u652F\u4E8E\uFF1A" + parentTitle : "\u5206\u652F\u4F1A\u8BDD\uFF08\u70B9\u51FB\u67E5\u770B\u6765\u6E90\u4F1A\u8BDD\uFF09";
@@ -3581,7 +4045,8 @@ function installSidebarStatusDots() {
3581
4045
  }
3582
4046
  dot.style.background = color;
3583
4047
  });
3584
- dsmSyncEmptyGroups();
4048
+ dsmSyncEmptyGroups(purgedNow);
4049
+ dsmSyncOverflowLabels(purgedNow);
3585
4050
  };
3586
4051
  dsmRepaintDots = paint;
3587
4052
  const paintToast = (msg, kind) => {