dsh-sessions-manager 3.7.7 → 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;
@@ -322,6 +335,13 @@ function remainingRows(visibleTotal, renderedVisible) {
322
335
  const shownCount = Number.isFinite(shown) ? Math.max(0, Math.floor(shown)) : 0;
323
336
  return Math.max(0, Math.max(0, Math.floor(total)) - shownCount);
324
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
+ }
325
345
  function countRenderedVisible(rows, visibleIds) {
326
346
  if (!Array.isArray(rows) || !visibleIds || typeof visibleIds.has !== "function") return 0;
327
347
  let n = 0;
@@ -554,6 +574,10 @@ body[data-ds-dark-theme] .archv{color-scheme:dark}
554
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}
555
575
  .dlg-title{font-size:15px;font-weight:650;color:var(--dsw-alias-label-primary);margin:0}
556
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}
557
581
  .dlg-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
558
582
  /* ---- T4 \u6807\u7B7E\u7F16\u8F91/\u7BA1\u7406 sheet \u4E0E\u7B5B\u9009\u4FDD\u5B58\u63A7\u4EF6\uFF08\u5168\u90E8\u8D70 --dsw token\uFF09 ---- */
559
583
  .dsm-taglist{display:flex;flex-direction:column;gap:2px;max-height:240px;overflow:auto}
@@ -793,6 +817,10 @@ function SessionPanel({ workspacesSvc }) {
793
817
  const [sortBy, setSortBy] = (0, import_react.useState)(() => ["newest", "oldest", "title"].includes(initialPrefs.sortBy) ? initialPrefs.sortBy : "newest");
794
818
  const [selected, setSelected] = (0, import_react.useState)({});
795
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]);
796
824
  const [confirmBatch, setConfirmBatch] = (0, import_react.useState)(false);
797
825
  const [batchMoveOpen, setBatchMoveOpen] = (0, import_react.useState)(false);
798
826
  const [busy, setBusy] = (0, import_react.useState)(null);
@@ -861,6 +889,7 @@ function SessionPanel({ workspacesSvc }) {
861
889
  return next;
862
890
  });
863
891
  const [groupByLineage, setGroupByLineage] = (0, import_react.useState)(() => initialPrefs.groupByLineage !== false);
892
+ const [openOrphans, setOpenOrphans] = (0, import_react.useState)(false);
864
893
  const [tagDefs, setTagDefs] = (0, import_react.useState)([]);
865
894
  const [assignments, setAssignments] = (0, import_react.useState)({});
866
895
  const [tagsState, setTagsState] = (0, import_react.useState)("loading");
@@ -1320,19 +1349,30 @@ function SessionPanel({ workspacesSvc }) {
1320
1349
  const canPurge = actionCapability("physicalPurge", "purge");
1321
1350
  const canMove = actionCapability("relocateSession", "move");
1322
1351
  const canRestoreTrash = actionCapability("restoreIndexedSession", "restoreTrash");
1323
- const archivedList = sessions ? sessions.filter((x) => x.archived) : [];
1324
- const activeList = sessions ? sessions.filter((x) => !x.archived) : [];
1325
- const starredList = starredOf(sessions);
1326
- const emptyList = (0, import_react.useMemo)(() => {
1327
- if (!sessions) return [];
1328
- 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) => {
1329
1363
  const li = lineage[String(x.sessionId)];
1330
1364
  return !!(li && li.empty);
1331
- });
1332
- }, [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]);
1333
1373
  const list = (0, import_react.useMemo)(() => {
1334
1374
  if (filter === "trash") return [];
1335
- 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 || [];
1336
1376
  const tagPassed = applyTagFilter(base, tagsReady ? tagFilter : "");
1337
1377
  const needle = query.trim().toLocaleLowerCase();
1338
1378
  const filtered = tagPassed.filter((item) => {
@@ -1345,14 +1385,15 @@ function SessionPanel({ workspacesSvc }) {
1345
1385
  if (sortBy === "title") return effectiveTitleOf(a, dsmAuthoritativeTitles).localeCompare(effectiveTitleOf(b, dsmAuthoritativeTitles), "zh-CN");
1346
1386
  return Number(b.createdAt || 0) - Number(a.createdAt || 0);
1347
1387
  });
1348
- }, [sessions, filter, query, workspaceFilter, sortBy, emptyList, starredList, tagFilter, tagsReady]);
1388
+ }, [sessions, archivedAll, activeAll, starredAll, emptyAll, filter, query, workspaceFilter, sortBy, tagFilter, tagsReady]);
1349
1389
  const selIds = Object.keys(selected).filter((k) => selected[k]);
1350
1390
  const showSessionList = filter !== "trash";
1351
- const { topList, kidsOf, foldedCount, branchGroupsOf, branchFolded, branchGroupCount } = (0, import_react.useMemo)(() => {
1352
- 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: [] };
1353
1393
  const kids = foldSubagents(list, lineage);
1354
1394
  const br = foldBranches(kids.topList, lineage);
1355
- 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 };
1356
1397
  }, [list, lineage, groupByLineage]);
1357
1398
  const matchIds = (0, import_react.useMemo)(() => {
1358
1399
  const needle = query.trim().toLocaleLowerCase();
@@ -1361,6 +1402,8 @@ function SessionPanel({ workspacesSvc }) {
1361
1402
  }, [sessions, query]);
1362
1403
  const kidsHit = (parentId) => !!(matchIds && (kidsOf.get(String(parentId)) || []).some((k) => matchIds.has(String(k.sessionId))));
1363
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;
1364
1407
  const syntheticCount = groupByLineage ? topList.reduce((n, it) => n + (it && it.syntheticRoot ? 1 : 0), 0) : 0;
1365
1408
  const kidsBadge = (sessionId) => {
1366
1409
  if (!groupByLineage) return null;
@@ -1385,6 +1428,29 @@ function SessionPanel({ workspacesSvc }) {
1385
1428
  );
1386
1429
  };
1387
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]);
1388
1454
  const branchBadge = (sessionId) => {
1389
1455
  const li = lineage[String(sessionId)];
1390
1456
  if (!li || li.origin === "subagent" || !li.parentSession) return null;
@@ -1494,8 +1560,8 @@ function SessionPanel({ workspacesSvc }) {
1494
1560
  const clearSel = () => setSelected({});
1495
1561
  const selectAll = () => {
1496
1562
  const o = {};
1497
- list.forEach((x) => {
1498
- o[x.sessionId] = true;
1563
+ topList.forEach((x) => {
1564
+ if (x && x.sessionId != null && !x.syntheticRoot) o[x.sessionId] = true;
1499
1565
  });
1500
1566
  setSelected(o);
1501
1567
  };
@@ -1515,13 +1581,14 @@ function SessionPanel({ workspacesSvc }) {
1515
1581
  const doDeleteConfirmed = () => {
1516
1582
  if (!delTarget || busy) return;
1517
1583
  setBusy(delTarget.sessionId);
1518
- postJSON("/archived-sessions/delete", { sessionId: delTarget.sessionId }).then(() => {
1584
+ postJSON("/archived-sessions/delete", { sessionId: delTarget.sessionId, cascadeSubagents: cascadeSub }).then((r) => {
1519
1585
  setBusy(null);
1520
1586
  const n = delTarget.title || delTarget.sessionId;
1521
- showToast(`\u5DF2\u5220\u9664 ${n}\uFF08\u5DF2\u79FB\u5165\u56DE\u6536\u7AD9\uFF09`);
1522
- 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)]);
1523
1590
  setDelTarget(null);
1524
- setSessions((s) => s && s.filter((x) => String(x.sessionId) !== sid));
1591
+ setSessions((s) => s && s.filter((x) => !gone.has(String(x.sessionId))));
1525
1592
  loadTrash();
1526
1593
  dsmLoadTrashIds();
1527
1594
  }).catch((e) => {
@@ -1612,7 +1679,9 @@ function SessionPanel({ workspacesSvc }) {
1612
1679
  setTrashBusy(sid);
1613
1680
  postJSON("/archived-sessions/trash/restore", { sessionId: sid }).then((r) => {
1614
1681
  setTrashBusy(null);
1615
- 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` : ""));
1616
1685
  loadTrash();
1617
1686
  refresh();
1618
1687
  }).catch((e) => {
@@ -1701,7 +1770,8 @@ function SessionPanel({ workspacesSvc }) {
1701
1770
  postJSON("/archived-sessions/" + action, { sessionIds: selIds }).then((r) => {
1702
1771
  setBusy(null);
1703
1772
  const n = r && (r.archived || r.restored || r.deleted) || selIds.length;
1704
- 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` : ""}`);
1705
1775
  refresh();
1706
1776
  }).catch((e) => {
1707
1777
  setBusy(null);
@@ -1906,7 +1976,7 @@ function SessionPanel({ workspacesSvc }) {
1906
1976
  ]
1907
1977
  }
1908
1978
  ) : null,
1909
- 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 })
1910
1980
  ] }),
1911
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" }),
1912
1982
  error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-err", role: "alert", children: [
@@ -1935,7 +2005,7 @@ function SessionPanel({ workspacesSvc }) {
1935
2005
  setConfirmBatch(false);
1936
2006
  }, children: [
1937
2007
  "\u5168\u90E8 (",
1938
- sessions.length,
2008
+ totalTopCount,
1939
2009
  ")"
1940
2010
  ] }),
1941
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: () => {
@@ -2261,7 +2331,7 @@ function SessionPanel({ workspacesSvc }) {
2261
2331
  "\u663E\u793A ",
2262
2332
  topList.length - syntheticCount,
2263
2333
  " \u4E2A\u4F1A\u8BDD",
2264
- 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` : ""
2265
2335
  ] }),
2266
2336
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsm-fbar", children: [
2267
2337
  saveFilterOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
@@ -2334,9 +2404,9 @@ function SessionPanel({ workspacesSvc }) {
2334
2404
  ] })
2335
2405
  ] })
2336
2406
  ] }),
2337
- showSessionList && list.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sess-batch" + (selIds.length > 0 ? " sess-batch-pin" : ""), children: [
2338
- /* @__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` }),
2339
- /* @__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" }),
2340
2410
  selIds.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2341
2411
  filter === "archived" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2342
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" }),
@@ -2414,311 +2484,372 @@ function SessionPanel({ workspacesSvc }) {
2414
2484
  ] })
2415
2485
  ] })
2416
2486
  ] }),
2417
- 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) => {
2418
- if (it && it.syntheticRoot) {
2419
- const root = String(it.syntheticRoot);
2420
- const members = branchGroupsOf.get(root) || [];
2421
- const open = !!openBranches[root] || branchHit(root);
2422
- const srcTitle = dsmAuthoritativeTitles.get(root);
2423
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsm-src-head", role: "listitem", children: [
2424
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2425
- "button",
2426
- {
2427
- type: "button",
2428
- className: "dsm-kids-toggle",
2429
- "aria-expanded": open,
2430
- 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",
2431
- onClick: () => toggleBranch(root),
2432
- children: [
2433
- open ? "\u25BE" : "\u25B8",
2434
- " ",
2435
- members.length,
2436
- " \u5206\u652F"
2437
- ]
2438
- }
2439
- ),
2440
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-src-name", title: root, children: "\u6765\u6E90\uFF1A" + (srcTitle || shortId(root)) })
2441
- ] }, it.sessionId);
2442
- }
2443
- const date = fmtDate(it.createdAt);
2444
- const expanded = openMove === it.sessionId || openTags === it.sessionId;
2445
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-card" + (expanded ? " archv-card-exp" : ""), role: "listitem", children: [
2446
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-row", children: [
2447
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2448
- "input",
2449
- {
2450
- type: "checkbox",
2451
- className: "archv-check",
2452
- checked: !!selected[it.sessionId],
2453
- onChange: () => toggle(it.sessionId),
2454
- "aria-label": "\u9009\u62E9 " + (it.title || it.sessionId)
2455
- }
2456
- ),
2457
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2458
- "button",
2459
- {
2460
- type: "button",
2461
- className: "archv-star" + (it.starred ? " archv-star-on" : ""),
2462
- "aria-pressed": !!it.starred,
2463
- "aria-label": (it.starred ? "\u53D6\u6D88\u6536\u85CF " : "\u6536\u85CF ") + (it.title || it.sessionId),
2464
- title: it.starred ? "\u53D6\u6D88\u6536\u85CF" : "\u6536\u85CF",
2465
- onClick: (e) => {
2466
- e.stopPropagation();
2467
- toggleStar(it);
2468
- },
2469
- 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" }) })
2470
- }
2471
- ),
2472
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-body", children: [
2473
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-main", children: [
2474
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-titlerow", children: [
2475
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-name", title: it.title || "", children: it.title || "(\u65E0\u6807\u9898)" }),
2476
- branchBadge(it.sessionId),
2477
- emptyBadge(it.sessionId),
2478
- tagChips(it.sessionId),
2479
- kidsBadge(it.sessionId),
2480
- branchGroupBadge(it.sessionId),
2481
- /* @__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) => {
2482
- e.stopPropagation();
2483
- copySessionId(it.sessionId);
2484
- }, 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)) })
2485
2518
  ] }),
2486
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-meta", children: [
2487
- 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" }),
2488
- workspaceTag(it),
2489
- date && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2490
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-dot", children: "\xB7" }),
2491
- /* @__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
+ ] })
2492
2573
  ] })
2493
- ] })
2494
- ] }),
2495
- rowMenu(it)
2496
- ] })
2497
- ] }),
2498
- groupByLineage && renderKids(it.sessionId, 0),
2499
- groupByLineage && renderBranchGroup(it.sessionId),
2500
- expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet", role: "region", "aria-label": "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A", children: [
2501
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet-head", children: [
2502
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "mv-sheet-title", children: "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A" }),
2503
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "mv-sheet-close", "aria-label": "\u5173\u95ED", onClick: () => setOpenMove(null), children: "\xD7" })
2504
- ] }),
2505
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-seg", role: "tablist", children: [
2506
- /* @__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" }),
2507
- /* @__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" })
2508
- ] }),
2509
- moveMode === "existing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2510
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-target-ws", children: "\u76EE\u6807\u5DE5\u4F5C\u533A" }),
2511
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { id: "mv-target-ws", value: targetWs, onChange: (e) => setTargetWs(e.target.value), children: [
2512
- workspaces.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\uFF08\u6682\u65E0\u5DE5\u4F5C\u533A\uFF09" }),
2513
- workspaces.map((w) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", { value: w.workspaceId, children: [
2514
- w.title,
2515
- " \xB7 ",
2516
- w.path
2517
- ] }, w.workspaceId))
2518
- ] })
2519
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2520
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mv-field-label", htmlFor: "mv-new-path", children: "\u65B0\u5DE5\u4F5C\u533A\u76EE\u5F55\u8DEF\u5F84" }),
2521
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-browse-row", children: [
2522
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2523
- "input",
2524
- {
2525
- id: "mv-new-path",
2526
- type: "text",
2527
- value: newPath,
2528
- onChange: (e) => setNewPath(e.target.value),
2529
- placeholder: "\u4F8B\u5982 /Users/you/Projects/demo \u6216 ~/demo"
2530
- }
2531
- ),
2532
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2533
- "button",
2534
- {
2535
- type: "button",
2536
- className: "archv-btn",
2537
- onClick: pickDirectory,
2538
- disabled: busy !== null || picking || !workspacesSvc,
2539
- 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",
2540
- children: picking ? "\u9009\u62E9\u4E2D\u2026" : "\u6D4F\u89C8\u2026"
2541
- }
2542
- )
2574
+ ] }),
2575
+ rowMenu(it)
2543
2576
  ] })
2544
2577
  ] }),
2545
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-foot", children: [
2546
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", onClick: () => setOpenMove(null), children: "\u53D6\u6D88" }),
2547
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "archv-btn archv-go", disabled: busy !== null, onClick: () => doMove(it), children: [
2548
- busy === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "archv-spin", "aria-hidden": "true" }),
2549
- "\u786E\u8BA4\u79FB\u52A8"
2550
- ] })
2551
- ] })
2552
- ] }),
2553
- openTags === it.sessionId && (() => {
2554
- const cur = Array.isArray(assignments[String(it.sessionId)]) ? assignments[String(it.sessionId)] : [];
2555
- const locked = tagBusy !== null || !tagsReady;
2556
- 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: [
2557
2581
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-sheet-head", children: [
2558
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { className: "mv-sheet-title", children: [
2559
- "\u4F1A\u8BDD\u6807\u7B7E \xB7 ",
2560
- it.title || shortId(it.sessionId)
2561
- ] }),
2562
- /* @__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" })
2584
+ ] }),
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" })
2563
2588
  ] }),
2564
- 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) => {
2565
- const checked = cur.some((id) => String(id) === String(t.id));
2566
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dsm-tagcheck", children: [
2567
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked, disabled: locked, onChange: () => toggleTagFor(it.sessionId, t.id) }),
2568
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-tagcheck-name", title: t.name, children: t.name })
2569
- ] }, String(t.id));
2570
- }) }),
2571
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-field", children: [
2572
- /* @__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" }),
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" }),
2573
2601
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mv-browse-row", children: [
2574
2602
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2575
2603
  "input",
2576
2604
  {
2577
- id: "dsm-tag-attach-" + String(it.sessionId),
2605
+ id: "mv-new-path",
2578
2606
  type: "text",
2579
- value: cardTagName,
2580
- disabled: locked,
2581
- maxLength: 24,
2582
- placeholder: "\u6807\u7B7E\u540D\uFF08\u4E0D\u80FD\u542B\u659C\u6760\uFF0C\u6700\u957F 24 \u5B57\uFF09",
2583
- onChange: (e) => setCardTagName(e.target.value),
2584
- onKeyDown: (e) => {
2585
- if (e.key === "Enter") {
2586
- e.preventDefault();
2587
- createTagAndAttach(it.sessionId);
2588
- }
2589
- }
2607
+ value: newPath,
2608
+ onChange: (e) => setNewPath(e.target.value),
2609
+ placeholder: "\u4F8B\u5982 /Users/you/Projects/demo \u6216 ~/demo"
2590
2610
  }
2591
2611
  ),
2592
- /* @__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
+ )
2593
2623
  ] })
2594
2624
  ] }),
2595
- /* @__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" })
2596
- ] });
2597
- })(),
2598
- openDetails === it.sessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet", role: "region", "aria-label": "\u4F1A\u8BDD\u8BE6\u60C5", children: [
2599
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sheet-head", children: [
2600
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "dtl-sheet-title", children: "\u4F1A\u8BDD\u8BE6\u60C5" }),
2601
- /* @__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
+ ] })
2602
2632
  ] }),
2603
- 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)) }) : (() => {
2604
- const d = details[it.sessionId];
2605
- if (!d) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-paths", children: "\u6682\u65E0\u8BE6\u60C5" });
2606
- const st = d.stats || {};
2607
- const tools = st.toolCounts ? Object.entries(st.toolCounts).sort((a, b) => b[1] - a[1]).slice(0, 10) : [];
2608
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2609
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-grid", children: [
2610
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2611
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u78C1\u76D8\u5360\u7528" }),
2612
- /* @__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)
2613
2641
  ] }),
2614
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2615
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u8F6E\u6B21 / \u6B65\u9AA4" }),
2616
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2617
- st.turns ?? 0,
2618
- " / ",
2619
- 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
+ ] })
2620
2725
  ] })
2621
2726
  ] }),
2622
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2623
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u7528\u6237 / \u52A9\u624B" }),
2624
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2625
- st.userMessages ?? 0,
2626
- " / ",
2627
- st.assistantMessages ?? 0
2628
- ] })
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)) })
2629
2734
  ] }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2631
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u5DE5\u5177\u8C03\u7528" }),
2632
- /* @__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)) })
2633
2741
  ] }),
2634
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2635
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u56FE\u7247\u9644\u4EF6" }),
2636
- /* @__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)) })
2637
2757
  ] }),
2638
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-cell", children: [
2639
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtl-k", children: "\u521B\u5EFA / \u66F4\u65B0" }),
2640
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-v", children: [
2641
- fmtDate(d.createdAt) || "\u2014",
2642
- " \xB7 ",
2643
- 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
+ ] })
2644
2777
  ] })
2645
- ] })
2646
- ] }),
2647
- tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2648
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5DE5\u5177\u4F7F\u7528" }),
2649
- /* @__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: [
2650
- t,
2651
- " \xD7",
2652
- c
2653
- ] }, t)) })
2654
- ] }),
2655
- st.fetches && st.fetches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2656
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u641C\u7D22 / \u6293\u53D6" }),
2657
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: st.fetches.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2658
- f.tool,
2659
- f.query ? ` \u300C${f.query}\u300D` : ""
2660
- ] }, i)) })
2661
- ] }),
2662
- d.files && d.files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2663
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec-t", children: [
2664
- "\u5199\u8FC7\u7684\u6587\u4EF6\uFF08",
2665
- d.files.length,
2666
- "\uFF09"
2667
2778
  ] }),
2668
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dtl-list", children: d.files.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
2669
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: f.path }),
2670
- " ",
2671
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dtl-filetool", children: [
2672
- "(",
2673
- f.tool,
2674
- ")"
2675
- ] })
2676
- ] }, i)) })
2677
- ] }),
2678
- 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: [
2679
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u8840\u7F18" }),
2680
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-paths", children: [
2681
- d.lineage.parentSessionId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2682
- "\u7236\u4F1A\u8BDD: ",
2683
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.parentSessionId })
2684
- ] }),
2685
- d.lineage.children && d.lineage.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2686
- "\u5B50\u4F1A\u8BDD (",
2687
- d.lineage.children.length,
2688
- "): ",
2689
- /* @__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" })
2690
2794
  ] }),
2691
- d.lineage.subagents && d.lineage.subagents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
2692
- "\u5B50\u4EE3\u7406 (",
2693
- d.lineage.subagents.length,
2694
- "): ",
2695
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: d.lineage.subagents.join(", ") })
2696
- ] })
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" })
2697
2796
  ] })
2698
- ] }),
2699
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-sec", children: [
2700
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-sec-t", children: "\u5BFC\u51FA" }),
2701
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtl-export", children: [
2702
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2703
- "a",
2704
- {
2705
- className: "archv-btn",
2706
- href: `/api/session.export?sessionId=${encodeURIComponent(it.sessionId)}&includeDescendants=true`,
2707
- onClick: (e) => e.stopPropagation(),
2708
- style: zipOk ? void 0 : { pointerEvents: "none", opacity: 0.45 },
2709
- 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",
2710
- children: "\u4E0B\u8F7D\u539F\u59CB\u65E5\u5FD7 (ZIP)"
2711
- }
2712
- ),
2713
- /* @__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" })
2714
- ] }),
2715
- /* @__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" })
2716
- ] })
2717
- ] });
2718
- })()
2719
- ] })
2720
- ] }, it.sessionId);
2721
- }) }) : 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
2722
2853
  ] }),
2723
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 }),
2724
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: [
@@ -2728,6 +2859,14 @@ function SessionPanel({ workspacesSvc }) {
2728
2859
  delTarget.title || delTarget.sessionId,
2729
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"
2730
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
+ ] }),
2731
2870
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dlg-actions", children: [
2732
2871
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: busy !== null, onClick: () => setDelTarget(null), children: "\u53D6\u6D88" }),
2733
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" })
@@ -2933,6 +3072,7 @@ function dsmToggleManual(id) {
2933
3072
  if (dsmRepaintDots) dsmRepaintDots();
2934
3073
  }
2935
3074
  var dsmTrashIds = null;
3075
+ var dsmTrashCountByCwd = null;
2936
3076
  var dsmServerPurgedIds = /* @__PURE__ */ new Set();
2937
3077
  var dsmAuthoritativeTitles = /* @__PURE__ */ new Map();
2938
3078
  var dsmTrashTick = 0;
@@ -3008,6 +3148,7 @@ async function dsmLoadTrashIds() {
3008
3148
  try {
3009
3149
  const r = await postJSON("/archived-sessions/sidebar-state", {});
3010
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;
3011
3152
  dsmServerPurgedIds = new Set((r && r.purgedSessionIds || []).map(String));
3012
3153
  for (const id of [...dsmPendingPurged]) {
3013
3154
  if (dsmServerPurgedIds.has(id)) dsmPendingPurged.delete(id);
@@ -3489,6 +3630,44 @@ function installSidebarStatusDots() {
3489
3630
  }
3490
3631
  return true;
3491
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
+ };
3492
3671
  function dsmSyncEmptyGroups(purgedNow) {
3493
3672
  let rows = null;
3494
3673
  try {
@@ -3509,14 +3688,10 @@ function installSidebarStatusDots() {
3509
3688
  };
3510
3689
  rows.forEach((row) => {
3511
3690
  try {
3512
- const scope = row.parentElement;
3691
+ const scope = groupContainerOf(row);
3513
3692
  if (!scope || scope === document.body) return;
3514
- if (typeof scope.getAttribute !== "function" || scope.getAttribute("role")) return;
3515
3693
  let rendered = 0;
3516
- for (const el of scope.children) {
3517
- if (el === row || !el.getAttribute) continue;
3518
- if (el.getAttribute("role") !== "treeitem") continue;
3519
- if (!(el.getAttribute("data-row-key") || "").startsWith("session:")) continue;
3694
+ for (const el of groupSessionRows(scope, row)) {
3520
3695
  if (el.hasAttribute(DSM_HIDDEN_ATTR)) continue;
3521
3696
  rendered++;
3522
3697
  }
@@ -3542,12 +3717,10 @@ function installSidebarStatusDots() {
3542
3717
  let n = 0;
3543
3718
  let firstKey = "";
3544
3719
  let lastKey = "";
3545
- for (const el of scope.children) {
3546
- if (el === btn || !el.getAttribute) continue;
3547
- const k = el.getAttribute("data-row-key") || "";
3548
- if (!k.startsWith("session:")) continue;
3720
+ for (const el of groupSessionRows(scope, btn)) {
3549
3721
  if (el.hasAttribute(DSM_HIDDEN_ATTR)) continue;
3550
3722
  n++;
3723
+ const k = el.getAttribute("data-row-key") || "";
3551
3724
  if (!firstKey) firstKey = k;
3552
3725
  lastKey = k;
3553
3726
  }
@@ -3568,13 +3741,21 @@ function installSidebarStatusDots() {
3568
3741
  const sig = overflowSignature(scope, btn, purgedNow);
3569
3742
  if (OVERFLOW_SIGS.get(btn) === sig) return;
3570
3743
  const key = (btn.getAttribute("data-row-key") || "").slice("overflow:".length);
3744
+ const wsKey = "workspace:" + key;
3571
3745
  let wsRow = null;
3572
3746
  for (const el of scope.children) {
3573
- if (el.getAttribute && el.getAttribute("data-row-key") === "workspace:" + key) {
3747
+ if (el.getAttribute && el.getAttribute("data-row-key") === wsKey) {
3574
3748
  wsRow = el;
3575
3749
  break;
3576
3750
  }
3577
3751
  }
3752
+ if (!wsRow) {
3753
+ try {
3754
+ wsRow = scope.querySelector('[data-row-key="' + wsKey.replace(/"/g, '\\"') + '"]');
3755
+ } catch (e) {
3756
+ wsRow = null;
3757
+ }
3758
+ }
3578
3759
  const group = wsRow ? sidebarAdapter.recognizeGroupQuiet(wsRow) : null;
3579
3760
  const nodes = group && Array.isArray(group.sessions) ? group.sessions : null;
3580
3761
  if (!nodes) {
@@ -3582,8 +3763,10 @@ function installSidebarStatusDots() {
3582
3763
  OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3583
3764
  return;
3584
3765
  }
3766
+ const groupCount = group && typeof group.sessionCount === "number" ? group.sessionCount : null;
3767
+ const collapsed = !nodes.length && groupCount != null && groupCount > 0;
3585
3768
  const ids = /* @__PURE__ */ new Set();
3586
- for (const node of nodes) {
3769
+ for (const node of nodes && nodes.length ? nodes : []) {
3587
3770
  if (!node || node.blank) continue;
3588
3771
  const id = node.id != null ? String(node.id) : "";
3589
3772
  if (!id) continue;
@@ -3593,18 +3776,34 @@ function installSidebarStatusDots() {
3593
3776
  ids.add(id);
3594
3777
  }
3595
3778
  const rendered = [];
3596
- for (const el of scope.children) {
3597
- if (el === btn || !el.getAttribute) continue;
3598
- if (el.getAttribute("role") !== "treeitem") continue;
3779
+ for (const el of groupSessionRows(scope, btn)) {
3599
3780
  const k = el.getAttribute("data-row-key") || "";
3600
- if (!k.startsWith("session:")) continue;
3601
3781
  rendered.push({ id: k.slice("session:".length), pluginHidden: el.hasAttribute(DSM_HIDDEN_ATTR) });
3602
3782
  }
3603
- if (!nodes.length || !ids.size && rendered.length) {
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) {
3604
3789
  restoreOverflowButton(btn);
3605
3790
  OVERFLOW_SIGS.set(btn, overflowSignature(scope, btn, purgedNow));
3606
3791
  return;
3607
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
+ }
3608
3807
  const renderedVisible = countRenderedVisible(rendered, ids);
3609
3808
  const more = remainingRows(ids.size, renderedVisible);
3610
3809
  applyOverflowPlan(btn, more, "\u53EF\u89C1 " + ids.size + " / \u5DF2\u6E32\u67D3 " + renderedVisible);