@michengai/dsh-archive-manager 0.1.22 → 0.1.24
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/CHANGELOG.md +14 -0
- package/CHANGELOG.zh-CN.md +14 -0
- package/lib/client.js +75 -25
- package/lib/projcache.js +48 -14
- package/lib/workspace.js +16 -3
- package/package.json +29 -13
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
Published release notes are retained below; new versions are added without removing earlier entries.
|
|
6
6
|
|
|
7
|
+
## 0.1.24 — 2026-09-02
|
|
8
|
+
|
|
9
|
+
- Upgraded the development test stack to DSH `0.1.2-alpha.5` and `@deepseek-ai/cordis` `4.0.2`, while retaining the existing `>=0.1.0-rc.5 <0.2.0` DSH runtime peer declarations.
|
|
10
|
+
- Switched primary client integration tests to the current `dsh-client-store` contract and retained a tested optional `dsh-client-runtime` fallback for older hosts.
|
|
11
|
+
- Added a reproducible pnpm alpha-resolution policy that disables automatic peer installation and records the approved newly published packages.
|
|
12
|
+
|
|
13
|
+
## 0.1.23 — 2026-09-01
|
|
14
|
+
|
|
15
|
+
- Fixed missing sidebar pending-state indicators on DSH `v0.1.2-alpha.2`: workspace rows now read pending UI interactions from the `ui-session` `pendingInteractions` Map.
|
|
16
|
+
- Whitelisted the official visible pending states (`question`, `approval`, and `plan-review`) before passing them to row rendering, so unknown future states are ignored safely.
|
|
17
|
+
- Kept the legacy `SessionSummary.pendingInteraction` fallback and added regression coverage for grouped, flat, and search result rows.
|
|
18
|
+
|
|
19
|
+
Published package: [`@michengai/dsh-archive-manager@0.1.23`](https://www.npmjs.com/package/@michengai/dsh-archive-manager/v/0.1.23).
|
|
20
|
+
|
|
7
21
|
## 0.1.22 — 2026-09-01
|
|
8
22
|
|
|
9
23
|
- Added arbitrary archived-chat selection in **Settings → Archived**, including per-row checkboxes, select-all for the current filtered results, cross-project selection, batch restore, and confirmed batch permanent deletion.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
以下发布说明会持续保留;新增版本时不再删除较早记录。
|
|
6
6
|
|
|
7
|
+
## 0.1.24 — 2026-09-02
|
|
8
|
+
|
|
9
|
+
- 将开发测试依赖升级至 DSH `0.1.2-alpha.5` 与 `@deepseek-ai/cordis` `4.0.2`,同时保留原有的 DSH 运行时 peer 声明 `>=0.1.0-rc.5 <0.2.0`。
|
|
10
|
+
- 客户端集成测试以当前 `dsh-client-store` 为主路径,并保留经过测试的可选 `dsh-client-runtime` 回退,兼容旧版宿主。
|
|
11
|
+
- 新增可复现的 pnpm alpha 解析策略:关闭自动安装 peer,并记录已批准的刚发布依赖。
|
|
12
|
+
|
|
13
|
+
## 0.1.23 — 2026-09-01
|
|
14
|
+
|
|
15
|
+
- 修复 DSH `v0.1.2-alpha.2` 后会话侧栏“等待回答 / 等待审批”状态点不显示的问题:侧栏行现在从 `ui-session` 的 `pendingInteractions` Map 读取待处理交互状态。
|
|
16
|
+
- 对 `question`、`approval`、`plan-review` 三种官方可见状态做白名单透传,未知状态会被忽略,避免触发行渲染断言。
|
|
17
|
+
- 保留旧版 `SessionSummary.pendingInteraction` 兜底,并补充分组、扁平列表和搜索结果三条路径的回归测试。
|
|
18
|
+
|
|
19
|
+
已发布包:[`@michengai/dsh-archive-manager@0.1.23`](https://www.npmjs.com/package/@michengai/dsh-archive-manager/v/0.1.23)。
|
|
20
|
+
|
|
7
21
|
## 0.1.22 — 2026-09-01
|
|
8
22
|
|
|
9
23
|
- 在「设置 → 已归档」新增任意多选:每行复选框、全选当前筛选结果、跨项目保留选择、批量恢复和确认后的批量永久删除。
|
package/lib/client.js
CHANGED
|
@@ -284,6 +284,10 @@ window.__ModuleLoader__.load({
|
|
|
284
284
|
}
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
|
+
/** GitHub 品牌标识未由宿主图标库提供,内联以保持离线可用和主题适配。 */
|
|
288
|
+
function GithubMark16() {
|
|
289
|
+
return (0, react_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": true, focusable: "false", children: (0, react_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M8 0a8 8 0 0 0-2.53 15.59c.4.074.547-.173.547-.385 0-.19-.007-.693-.01-1.36-2.226.484-2.695-1.073-2.695-1.073-.364-.924-.89-1.17-.89-1.17-.726-.496.055-.486.055-.486.803.056 1.225.824 1.225.824.714 1.223 1.872.87 2.328.665.072-.517.28-.87.508-1.07-1.777-.202-3.645-.888-3.645-3.956 0-.874.31-1.588.823-2.148-.083-.202-.357-1.017.078-2.12 0 0 .672-.215 2.2.82A7.65 7.65 0 0 1 8 4.8c.68.003 1.365.092 2.004.27 1.527-1.035 2.197-.82 2.197-.82.437 1.103.162 1.918.08 2.12.513.56.822 1.274.822 2.148 0 3.076-1.872 3.752-3.654 3.95.288.248.544.735.544 1.482 0 1.07-.01 1.932-.01 2.195 0 .214.144.463.55.384A8.001 8.001 0 0 0 8 0Z" }) });
|
|
290
|
+
}
|
|
287
291
|
/**
|
|
288
292
|
* 归档多选原型。保留既有设置页作为兼容回退,原型直接使用相同宿主
|
|
289
293
|
* 批量接口,因此其恢复、删除和并发安全语义与原有项目级操作一致。
|
|
@@ -423,10 +427,10 @@ window.__ModuleLoader__.load({
|
|
|
423
427
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
424
428
|
className: "dsham_settings",
|
|
425
429
|
"aria-label": t("archives.title"),
|
|
426
|
-
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS + ARCHIVE_SETTINGS_SELECTION_CSS }), (0, react_jsx_runtime.jsxs)("header", {
|
|
430
|
+
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS + ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS + ARCHIVE_SETTINGS_SELECTION_CSS + ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS }), (0, react_jsx_runtime.jsxs)("header", {
|
|
427
431
|
className: "dsham_settingsHeader",
|
|
428
432
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
429
|
-
|
|
433
|
+
children: [(0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsTitleRow", children: [(0, react_jsx_runtime.jsx)("h2", { children: t("archives.title") }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsLinks", children: [(0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager", target: "_blank", rel: "noreferrer", "aria-label": t("archives.viewProject"), children: [(0, react_jsx_runtime.jsx)(GithubMark16, {}), t("archives.viewProject")] }), (0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager/issues", target: "_blank", rel: "noreferrer", "aria-label": t("archives.feedback"), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, {}), t("archives.feedback")] })] })] }), (0, react_jsx_runtime.jsx)("p", { className: "dsham_settingsIntro", children: t("archives.description") })]
|
|
430
434
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
431
435
|
className: "dsham_settingsHeaderActions",
|
|
432
436
|
children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsRestoreAll", disabled: busy || allBatchSessionIds.length === 0, onClick: () => onBatchUnarchive(allBatchTarget), children: t("archives.restoreAll") }), (0, react_jsx_runtime.jsxs)("button", { type: "button", className: "dsham_settingsDanger", disabled: busy || allBatchSessionIds.length === 0, onClick: () => setDeleteTarget({ kind: "batch", target: allBatchTarget, title: t("archives.allProjects"), count: allBatchSessionIds.length }), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}), t("archives.deleteAll")] })]
|
|
@@ -468,7 +472,7 @@ window.__ModuleLoader__.load({
|
|
|
468
472
|
closeLabel: t("close"),
|
|
469
473
|
title: deleteDialogTitle,
|
|
470
474
|
...deleteDialogDescription === void 0 ? {} : { description: deleteDialogDescription },
|
|
471
|
-
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeDelete, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: confirmDelete, children: deleteConfirmLabel })] }),
|
|
475
|
+
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeDelete, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", className: "dsham_settingsDeleteConfirm", disabled: busy, onClick: confirmDelete, children: deleteConfirmLabel })] }),
|
|
472
476
|
children: busy && (0, react_jsx_runtime.jsx)("div", { role: "status", children: deleteTarget?.kind === "batch" ? t("archives.deleteBatchPending") : t("deleteSession.pending") })
|
|
473
477
|
})]
|
|
474
478
|
});
|
|
@@ -496,8 +500,8 @@ window.__ModuleLoader__.load({
|
|
|
496
500
|
* @param cwd - directory path, or undefined for the ungrouped bucket.
|
|
497
501
|
* @returns basename, the raw cwd when it has no basename, or the ungrouped label.
|
|
498
502
|
*/
|
|
499
|
-
function workspaceLabel(cwd) {
|
|
500
|
-
if (cwd === void 0 || cwd === "") return
|
|
503
|
+
function workspaceLabel(cwd, ungroupedLabel = UNGROUPED_LABEL) {
|
|
504
|
+
if (cwd === void 0 || cwd === "") return ungroupedLabel;
|
|
501
505
|
const base = cwd.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
|
|
502
506
|
return base !== void 0 && base !== "" ? base : cwd;
|
|
503
507
|
}
|
|
@@ -603,7 +607,26 @@ window.__ModuleLoader__.load({
|
|
|
603
607
|
if (stray.length > 0) groups.push(buildGroup("", void 0, void 0, void 0, UNGROUPED_LABEL, ungroupedOrder === void 0 ? stray : orderedUngrouped(stray, ungroupedOrder), ungroupedOrder === void 0 ? "recency" : "account"));
|
|
604
608
|
return groups;
|
|
605
609
|
}
|
|
606
|
-
|
|
610
|
+
/** 只把侧栏已支持的待处理交互类型交给行渲染,避免未知类型触发断言。 */
|
|
611
|
+
function visiblePendingKind(kind) {
|
|
612
|
+
switch (kind) {
|
|
613
|
+
case "approval":
|
|
614
|
+
case "plan-review":
|
|
615
|
+
case "question": return kind;
|
|
616
|
+
default: return;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
function pendingInteractionForSession(session, pendingInteractions) {
|
|
620
|
+
const entry = pendingInteractions.get(session.id);
|
|
621
|
+
const kind = entry === void 0 ? session.pendingInteraction : entry.kind;
|
|
622
|
+
return visiblePendingKind(kind);
|
|
623
|
+
}
|
|
624
|
+
const EMPTY_PENDING_INTERACTIONS = /* @__PURE__ */ new Map();
|
|
625
|
+
function useEmptySessionPendingInteraction(selector) {
|
|
626
|
+
return selector(EMPTY_PENDING_INTERACTIONS);
|
|
627
|
+
}
|
|
628
|
+
function sessionNode(s, descendants, archived, pendingInteractions) {
|
|
629
|
+
const pendingInteraction = pendingInteractionForSession(s, pendingInteractions);
|
|
607
630
|
return {
|
|
608
631
|
id: s.id,
|
|
609
632
|
title: sessionTitle(s),
|
|
@@ -613,7 +636,7 @@ window.__ModuleLoader__.load({
|
|
|
613
636
|
completed: s.completed === true,
|
|
614
637
|
updatedAt: s.updatedAt,
|
|
615
638
|
archived: archived.has(s.id),
|
|
616
|
-
...
|
|
639
|
+
...pendingInteraction === void 0 ? {} : { pendingInteraction }
|
|
617
640
|
};
|
|
618
641
|
}
|
|
619
642
|
/**
|
|
@@ -628,10 +651,11 @@ window.__ModuleLoader__.load({
|
|
|
628
651
|
* @param list - sessions list snapshot (`current` feeds containsCurrent).
|
|
629
652
|
* @param workspaces - real workspaces in stable Host order.
|
|
630
653
|
* @param archivedSessionIds - registry-global archive set.
|
|
654
|
+
* @param pendingInteractions - pending UI interactions by Session.
|
|
631
655
|
* @param view - local expansion arrays and the show-archived toggle.
|
|
632
656
|
* @returns group sections in render order.
|
|
633
657
|
*/
|
|
634
|
-
function deriveGroups(list, workspaces, archivedSessionIds, view) {
|
|
658
|
+
function deriveGroups(list, workspaces, archivedSessionIds, pendingInteractions, view) {
|
|
635
659
|
const archived = new Set(archivedSessionIds);
|
|
636
660
|
const expandedGroups = new Set(view.expandedGroups);
|
|
637
661
|
const descendants = indexSubagentDescendants(list.byId);
|
|
@@ -648,7 +672,7 @@ window.__ModuleLoader__.load({
|
|
|
648
672
|
sessionCount: g.sessions.length,
|
|
649
673
|
expanded,
|
|
650
674
|
containsCurrent: g.key === currentGroup,
|
|
651
|
-
sessions: expanded ? g.sessions.map((session) => sessionNode(session, descendants, archived)) : []
|
|
675
|
+
sessions: expanded ? g.sessions.map((session) => sessionNode(session, descendants, archived, pendingInteractions)) : []
|
|
652
676
|
});
|
|
653
677
|
}
|
|
654
678
|
return groups;
|
|
@@ -662,10 +686,11 @@ window.__ModuleLoader__.load({
|
|
|
662
686
|
* (see {@link deriveSearchResults}).
|
|
663
687
|
* @param list - sessions list snapshot.
|
|
664
688
|
* @param archivedSessionIds - registry-global archive set.
|
|
689
|
+
* @param pendingInteractions - pending UI interactions by Session.
|
|
665
690
|
* @param showArchived - "show archived" view toggle.
|
|
666
691
|
* @returns flat rows in render order.
|
|
667
692
|
*/
|
|
668
|
-
function deriveFlat(list, archivedSessionIds, showArchived) {
|
|
693
|
+
function deriveFlat(list, archivedSessionIds, pendingInteractions, showArchived) {
|
|
669
694
|
const archived = new Set(archivedSessionIds);
|
|
670
695
|
const descendants = indexSubagentDescendants(list.byId);
|
|
671
696
|
const rows = [];
|
|
@@ -675,7 +700,7 @@ window.__ModuleLoader__.load({
|
|
|
675
700
|
rows.push(s);
|
|
676
701
|
}
|
|
677
702
|
rows.sort(byRecency);
|
|
678
|
-
return rows.map((session) => sessionNode(session, descendants, archived));
|
|
703
|
+
return rows.map((session) => sessionNode(session, descendants, archived, pendingInteractions));
|
|
679
704
|
}
|
|
680
705
|
/**
|
|
681
706
|
* Merge immediate title/Workspace substring matches with ranked Host content
|
|
@@ -686,12 +711,14 @@ window.__ModuleLoader__.load({
|
|
|
686
711
|
* @param workspaces - Workspace membership and display labels.
|
|
687
712
|
* @param query - caller text; surrounding whitespace is ignored.
|
|
688
713
|
* @param archivedSessionIds - registry-global archive set.
|
|
714
|
+
* @param pendingInteractions - pending UI interactions by Session.
|
|
689
715
|
* @param content - ranked Host content-search page.
|
|
690
716
|
* @param limit - protocol-owned maximum merged row count.
|
|
691
717
|
* @param showArchived - "show archived" view toggle.
|
|
718
|
+
* @param ungroupedLabel - 未归属工作区会话的本地化回退标签。
|
|
692
719
|
* @returns bounded deduplicated flat rows and a refine-query hint bit.
|
|
693
720
|
*/
|
|
694
|
-
function deriveSearchResults(list, workspaces, query, archivedSessionIds, content, limit, showArchived) {
|
|
721
|
+
function deriveSearchResults(list, workspaces, query, archivedSessionIds, pendingInteractions, content, limit, showArchived, ungroupedLabel = UNGROUPED_LABEL) {
|
|
695
722
|
const q = query.trim().toLowerCase();
|
|
696
723
|
if (q === "") return {
|
|
697
724
|
items: [],
|
|
@@ -701,7 +728,7 @@ window.__ModuleLoader__.load({
|
|
|
701
728
|
const descendants = indexSubagentDescendants(list.byId);
|
|
702
729
|
const workspaceBySession = /* @__PURE__ */ new Map();
|
|
703
730
|
for (const workspace of workspaces) for (const sessionId of workspace.sessionIds) if (!workspaceBySession.has(sessionId)) workspaceBySession.set(sessionId, workspace.title);
|
|
704
|
-
const labelOf = (summary) => workspaceBySession.get(summary.id) ?? workspaceLabel(summary.cwd);
|
|
731
|
+
const labelOf = (summary) => workspaceBySession.get(summary.id) ?? workspaceLabel(summary.cwd, ungroupedLabel);
|
|
705
732
|
const contentBySession = /* @__PURE__ */ new Map();
|
|
706
733
|
for (const item of content.items) if (!contentBySession.has(item.sessionId)) contentBySession.set(item.sessionId, item);
|
|
707
734
|
const local = [];
|
|
@@ -726,6 +753,7 @@ window.__ModuleLoader__.load({
|
|
|
726
753
|
return {
|
|
727
754
|
items: ordered.slice(0, limit).map((summary) => {
|
|
728
755
|
const match = contentBySession.get(summary.id);
|
|
756
|
+
const pendingInteraction = pendingInteractionForSession(summary, pendingInteractions);
|
|
729
757
|
return {
|
|
730
758
|
id: summary.id,
|
|
731
759
|
title: sessionTitle(summary),
|
|
@@ -733,7 +761,7 @@ window.__ModuleLoader__.load({
|
|
|
733
761
|
running: summary.running,
|
|
734
762
|
runningSubagentCount: descendants.get(summary.id)?.runningCount ?? 0,
|
|
735
763
|
archived: archived.has(summary.id),
|
|
736
|
-
...
|
|
764
|
+
...pendingInteraction === void 0 ? {} : { pendingInteraction },
|
|
737
765
|
completed: summary.completed === true,
|
|
738
766
|
...match === void 0 ? {} : { snippet: match.snippet }
|
|
739
767
|
};
|
|
@@ -1713,8 +1741,9 @@ window.__ModuleLoader__.load({
|
|
|
1713
1741
|
return e.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
1714
1742
|
}
|
|
1715
1743
|
/** The scrolling session tree; unmounting drops the sessions subscription and expand-all state. */
|
|
1716
|
-
function SessionTree({ useSessions, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
1744
|
+
function SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
1717
1745
|
const list = useSessions((s) => s);
|
|
1746
|
+
const pendingInteractions = useSessionPendingInteraction((s) => s);
|
|
1718
1747
|
const current = list.current;
|
|
1719
1748
|
const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)([]);
|
|
1720
1749
|
const [drag, setDrag] = (0, react.useState)(null);
|
|
@@ -1781,7 +1810,7 @@ window.__ModuleLoader__.load({
|
|
|
1781
1810
|
});
|
|
1782
1811
|
}, [sessionOrderByAccount, workspaces]);
|
|
1783
1812
|
const orderedUngroupedSessionIds = (0, react.useMemo)(() => reconciledSessionOrder(ungroupedSessionIds, sessionOrderByAccount[""]), [sessionOrderByAccount, ungroupedSessionIds]);
|
|
1784
|
-
const groups = (0, react.useMemo)(() => deriveGroups(list, orderedWorkspaces, archivedSessionIds, {
|
|
1813
|
+
const groups = (0, react.useMemo)(() => deriveGroups(list, orderedWorkspaces, archivedSessionIds, pendingInteractions, {
|
|
1785
1814
|
expandedGroups,
|
|
1786
1815
|
showArchived,
|
|
1787
1816
|
...sessionOrderByAccount[""] === void 0 ? {} : { ungroupedOrder: sessionOrderByAccount[""] }
|
|
@@ -1789,6 +1818,7 @@ window.__ModuleLoader__.load({
|
|
|
1789
1818
|
list,
|
|
1790
1819
|
orderedWorkspaces,
|
|
1791
1820
|
archivedSessionIds,
|
|
1821
|
+
pendingInteractions,
|
|
1792
1822
|
showArchived,
|
|
1793
1823
|
expandedGroups,
|
|
1794
1824
|
sessionOrderByAccount
|
|
@@ -1990,9 +2020,15 @@ window.__ModuleLoader__.load({
|
|
|
1990
2020
|
});
|
|
1991
2021
|
}
|
|
1992
2022
|
/** The flat "In one list" body: every session is one draggable top-level row. */
|
|
1993
|
-
function FlatList({ useSessions, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
2023
|
+
function FlatList({ useSessions, useSessionPendingInteraction, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
1994
2024
|
const list = useSessions((s) => s);
|
|
1995
|
-
const
|
|
2025
|
+
const pendingInteractions = useSessionPendingInteraction((s) => s);
|
|
2026
|
+
const baseRows = (0, react.useMemo)(() => deriveFlat(list, archivedSessionIds, pendingInteractions, showArchived), [
|
|
2027
|
+
list,
|
|
2028
|
+
archivedSessionIds,
|
|
2029
|
+
pendingInteractions,
|
|
2030
|
+
showArchived
|
|
2031
|
+
]);
|
|
1996
2032
|
const sessionIds = (0, react.useMemo)(() => baseRows.map((row) => row.id), [baseRows]);
|
|
1997
2033
|
const previousOrderBy = (0, react.useRef)(orderBy);
|
|
1998
2034
|
(0, react.useEffect)(() => {
|
|
@@ -2114,22 +2150,26 @@ window.__ModuleLoader__.load({
|
|
|
2114
2150
|
});
|
|
2115
2151
|
}
|
|
2116
2152
|
/** Flat search body: local metadata matches plus the current Host result page. */
|
|
2117
|
-
function SearchResults({ useSessions, open, workspaces, archivedSessionIds, showArchived, query, remote, resultLimit, t }) {
|
|
2153
|
+
function SearchResults({ useSessions, useSessionPendingInteraction, open, workspaces, archivedSessionIds, showArchived, query, remote, resultLimit, t }) {
|
|
2118
2154
|
const list = useSessions((s) => s);
|
|
2155
|
+
const pendingInteractions = useSessionPendingInteraction((s) => s);
|
|
2156
|
+
const ungroupedLabel = t("group.ungrouped");
|
|
2119
2157
|
const currentRemote = remote.query === query ? remote : {
|
|
2120
2158
|
query,
|
|
2121
2159
|
status: "loading",
|
|
2122
2160
|
items: [],
|
|
2123
2161
|
hasMore: false
|
|
2124
2162
|
};
|
|
2125
|
-
const results = (0, react.useMemo)(() => deriveSearchResults(list, workspaces, query, archivedSessionIds, currentRemote, resultLimit, showArchived), [
|
|
2163
|
+
const results = (0, react.useMemo)(() => deriveSearchResults(list, workspaces, query, archivedSessionIds, pendingInteractions, currentRemote, resultLimit, showArchived, ungroupedLabel), [
|
|
2126
2164
|
list,
|
|
2127
2165
|
workspaces,
|
|
2128
2166
|
query,
|
|
2129
2167
|
archivedSessionIds,
|
|
2168
|
+
pendingInteractions,
|
|
2130
2169
|
currentRemote,
|
|
2131
2170
|
resultLimit,
|
|
2132
|
-
showArchived
|
|
2171
|
+
showArchived,
|
|
2172
|
+
ungroupedLabel
|
|
2133
2173
|
]);
|
|
2134
2174
|
const pending = currentRemote.status === "loading";
|
|
2135
2175
|
const failed = currentRemote.status === "error";
|
|
@@ -2176,7 +2216,8 @@ window.__ModuleLoader__.load({
|
|
|
2176
2216
|
* @param props - composed slot props (shell owner share + store + injected actions).
|
|
2177
2217
|
* @returns the region element tree.
|
|
2178
2218
|
*/
|
|
2179
|
-
function WorkspaceBrowser({ wide, expandSidebar, useSessions, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, unarchiveSession, deleteSession, insertSessionBefore, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, renderSlot, t }) {
|
|
2219
|
+
function WorkspaceBrowser({ wide, expandSidebar, useSessions, useSessionPendingInteraction, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, unarchiveSession, deleteSession, insertSessionBefore, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, renderSlot, t }) {
|
|
2220
|
+
const useEffectiveSessionPendingInteraction = useSessionPendingInteraction ?? useEmptySessionPendingInteraction;
|
|
2180
2221
|
const workspaces = useWorkspaces((state) => state.items);
|
|
2181
2222
|
const workspacePhase = useWorkspaces((state) => state.phase);
|
|
2182
2223
|
const archivedSessionIds = useWorkspaces((state) => state.archivedSessionIds);
|
|
@@ -2571,6 +2612,7 @@ window.__ModuleLoader__.load({
|
|
|
2571
2612
|
className: WorkspaceBrowser_module_css_default.listArea,
|
|
2572
2613
|
children: wide && (normalizedQuery !== "" ? (0, react_jsx_runtime.jsx)(SearchResults, {
|
|
2573
2614
|
useSessions,
|
|
2615
|
+
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
2574
2616
|
open: guardedOpen,
|
|
2575
2617
|
workspaces,
|
|
2576
2618
|
archivedSessionIds,
|
|
@@ -2581,6 +2623,7 @@ window.__ModuleLoader__.load({
|
|
|
2581
2623
|
t
|
|
2582
2624
|
}) : groupBy === "flat" ? (0, react_jsx_runtime.jsx)(FlatList, {
|
|
2583
2625
|
useSessions,
|
|
2626
|
+
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
2584
2627
|
open: guardedOpen,
|
|
2585
2628
|
forkSession,
|
|
2586
2629
|
onSessionRename,
|
|
@@ -2600,6 +2643,7 @@ window.__ModuleLoader__.load({
|
|
|
2600
2643
|
t
|
|
2601
2644
|
}) : (0, react_jsx_runtime.jsx)(SessionTree, {
|
|
2602
2645
|
useSessions,
|
|
2646
|
+
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
2603
2647
|
onSessionRename,
|
|
2604
2648
|
onSessionArchive,
|
|
2605
2649
|
onSessionUnarchive,
|
|
@@ -2812,13 +2856,15 @@ window.__ModuleLoader__.load({
|
|
|
2812
2856
|
//#region dsh-archive-manager: settings section
|
|
2813
2857
|
const ARCHIVE_SETTINGS_CSS = ".dsham_settings{box-sizing:border-box;width:min(100%,760px);margin:0 auto;padding:0 0 32px;color:var(--dsw-alias-label-primary)}.dsham_settingsHeader{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:12px}.dsham_settings h2{margin:0;font-size:20px;font-weight:650;letter-spacing:-.2px;line-height:28px}.dsham_settingsIntro{margin:4px 0 0;max-width:42em;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.dsham_settingsDanger{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:0 12px;color:var(--dsw-alias-state-error-primary);background:transparent;border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsDanger:hover{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 20%,transparent)}.dsham_settingsToolbar{display:flex;gap:8px;margin-bottom:16px}.dsham_settingsSearch{display:flex;align-items:center;gap:8px;min-width:0;flex:1;height:32px;padding:0 12px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-button-elevated-fill));border:1px solid var(--dsw-alias-border-l2);border-radius:8px}.dsham_settingsSearch:focus-within{border-color:var(--dsw-alias-label-tertiary)}.dsham_settingsSearch input{width:100%;min-width:0;padding:0;color:var(--dsw-alias-label-primary);background:transparent;border:0;outline:0;font:inherit;font-size:12px}.dsham_settingsSearch input::placeholder{color:var(--dsw-alias-label-tertiary)}.dsham_settingsFilter{position:relative;min-width:168px;flex:none}.dsham_selectTrigger{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:32px;padding:0 10px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-button-elevated-fill));border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;line-height:20px;text-align:left}.dsham_selectTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.dsham_selectTrigger:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dsham_selectTrigger[aria-expanded='true']{border-color:var(--dsw-alias-state-success-primary)}.dsham_selectValue{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dsham_selectCaret{flex:none;width:12px;height:12px;color:var(--dsw-alias-label-tertiary)}.dsham_selectMenu{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;box-sizing:border-box;min-width:100%;max-height:280px;overflow:auto;padding:4px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-2));box-shadow:var(--dsw-shadow-lv3)}.dsham_selectOption{box-sizing:border-box;display:flex;align-items:center;width:100%;min-height:32px;padding:0 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer}.dsham_selectOption:hover,.dsham_selectOption[data-active='true']{background:var(--dsw-alias-interactive-bg-hover)}.dsham_selectOption[aria-selected='true']{color:var(--dsw-alias-state-success-primary)}.dsham_settingsGroup{margin:0 0 20px}.dsham_settingsGroupHeading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 14px}.dsham_settingsGroupTitle{display:flex;align-items:center;gap:8px;min-width:0;margin:0;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.dsham_settingsGroupTitle svg{flex:none;color:var(--dsw-alias-label-secondary)}.dsham_settingsCount{flex:none;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsham_settingsList{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-button-elevated-fill))}.dsham_settingsRow{display:flex;align-items:center;gap:12px;min-height:60px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dsham_settingsRow:last-child{border-bottom:0}.dsham_settingsContent{min-width:0;flex:1}.dsham_settingsTitle{overflow:hidden;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.dsham_settingsMeta{margin-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px}.dsham_settingsActions{display:flex;align-items:center;gap:8px}.dsham_settingsAction{min-height:32px;padding:0 12px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsAction:hover{filter:brightness(1.12)}.dsham_settingsDelete{display:flex;align-items:center;justify-content:center;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:transparent;border:0;border-radius:8px;cursor:pointer}.dsham_settingsDelete:hover{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsEmpty{padding:28px 8px;color:var(--dsw-alias-label-secondary);text-align:center}.dsham_settingsError{margin-top:10px;color:var(--dsw-alias-state-error-primary);font-size:12px}@media(max-width:720px){.dsham_settings{width:100%;margin:28px auto 48px;padding:0 16px}.dsham_settingsHeader{margin-bottom:28px}.dsham_settingsToolbar{flex-wrap:wrap;margin-bottom:28px}.dsham_settingsSearch{flex-basis:100%}.dsham_settingsFilter{flex:1;min-width:0}.dsham_settingsGroup{margin-bottom:32px}.dsham_settingsRow{padding:10px 12px}.dsham_settingsActions{gap:4px}}";
|
|
2814
2858
|
const ARCHIVE_SETTINGS_BATCH_CSS = ".dsham_settingsHeaderActions,.dsham_settingsGroupMeta{display:flex;align-items:center;gap:8px;flex:none}.dsham_settingsRestoreAll{display:inline-flex;align-items:center;min-height:32px;padding:0 12px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsRestoreAll:hover{background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsRestoreAll:disabled,.dsham_settingsDanger:disabled,.dsham_settingsGroupMenu:disabled{cursor:not-allowed;opacity:.5}.dsham_settingsGroupMenu{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;color:var(--dsw-alias-label-tertiary);background:transparent;border:0;border-radius:8px;cursor:pointer}.dsham_settingsGroupMenu:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsStatus{margin-top:10px;color:var(--dsw-alias-label-secondary);font-size:12px}@media(max-width:720px){.dsham_settingsHeader{flex-direction:column}.dsham_settingsHeaderActions{align-self:flex-end}}";
|
|
2859
|
+
const ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS = ".dsham_settingsTitleRow{display:flex;align-items:center;gap:8px;min-width:0}.dsham_settingsLinks{display:flex;align-items:center;gap:4px}.dsham_settingsExternalLink{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:0 8px;color:var(--dsw-alias-label-secondary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap}.dsham_settingsExternalLink:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsExternalLink:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dsham_settingsExternalLink svg{flex:none}@media(max-width:720px){.dsham_settingsTitleRow{flex-wrap:wrap}}";
|
|
2860
|
+
const ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS = ".dsham_settingsDeleteConfirm{color:var(--dsw-alias-state-error-primary)!important;background:transparent!important;border-color:var(--dsw-alias-state-error-primary)!important}.dsham_settingsDeleteConfirm:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 20%,transparent)!important}.dsham_settingsDeleteConfirm:focus-visible{outline:2px solid var(--dsw-alias-state-error-secondary);outline-offset:2px}.dsham_settingsDeleteConfirm:disabled{cursor:not-allowed;opacity:.5}";
|
|
2815
2861
|
const ARCHIVE_SETTINGS_SELECTION_CSS = ".dsham_settingsSelection{display:flex;align-items:center;gap:10px;min-height:40px;margin:-8px 0 16px;padding:4px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-button-elevated-fill))}.dsham_settingsSelectionToggle{display:inline-flex;align-items:center;gap:8px;min-width:0;color:var(--dsw-alias-label-primary);font-size:13px;cursor:pointer}.dsham_settingsCheckbox{width:16px;height:16px;margin:0;accent-color:#3b82f6}.dsham_settingsSelectionCount{margin-right:auto;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsham_settingsSelectionAction{min-height:28px;padding:0 10px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;cursor:pointer;font:inherit;font-size:12px;font-weight:500}.dsham_settingsSelectionAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsSelectionDelete{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.dsham_settingsSelectionAction:disabled{cursor:not-allowed;opacity:.5}@media(max-width:720px){.dsham_settingsSelection{flex-wrap:wrap}.dsham_settingsSelectionCount{margin-right:0}.dsham_settingsSelectionAction{margin-left:auto}.dsham_settingsSelectionAction+.dsham_settingsSelectionAction{margin-left:-2px}}";
|
|
2816
2862
|
const ARCHIVE_SETTINGS_LAYOUT_OVERRIDE = ".dsham_settings{margin:0 auto!important}@media(max-width:720px){.dsham_settings{margin:0 auto!important}}";
|
|
2817
2863
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify("dsh-archive-manager/ArchiveSettings.layout.css") + "]") === null) {
|
|
2818
2864
|
const tag = document.createElement("style");
|
|
2819
2865
|
tag.dataset.plugin = "@michengai/dsh-archive-manager";
|
|
2820
2866
|
tag.dataset.pluginCss = "dsh-archive-manager/ArchiveSettings.layout.css";
|
|
2821
|
-
tag.textContent = ARCHIVE_SETTINGS_LAYOUT_OVERRIDE;
|
|
2867
|
+
tag.textContent = ARCHIVE_SETTINGS_LAYOUT_OVERRIDE + ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS;
|
|
2822
2868
|
document.head.appendChild(tag);
|
|
2823
2869
|
}
|
|
2824
2870
|
/** 设置页筛选/排序:自定义菜单,避免原生 select 弹出系统浅色下拉。 */
|
|
@@ -3254,7 +3300,7 @@ window.__ModuleLoader__.load({
|
|
|
3254
3300
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
3255
3301
|
className: "dsham_settings",
|
|
3256
3302
|
"aria-label": t("archives.title"),
|
|
3257
|
-
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS }), (0, react_jsx_runtime.jsxs)("header", { className: "dsham_settingsHeader", children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("h2", { children: t("archives.title") }), (0, react_jsx_runtime.jsx)("p", { className: "dsham_settingsIntro", children: t("archives.description") })] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsHeaderActions", children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsRestoreAll", disabled: busy || allBatchSessionIds.length === 0, onClick: () => onBatchUnarchive(allBatchTarget), children: t("archives.restoreAll") }), (0, react_jsx_runtime.jsxs)("button", { type: "button", className: "dsham_settingsDanger", disabled: busy || allBatchSessionIds.length === 0, onClick: () => setDeleteTarget({ kind: "batch", target: allBatchTarget, title: t("archives.allProjects"), count: allBatchSessionIds.length }), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}), t("archives.deleteAll")] })] })] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsToolbar", children: [(0, react_jsx_runtime.jsxs)("label", { className: "dsham_settingsSearch", children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, {}), (0, react_jsx_runtime.jsx)("input", { type: "search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: t("archives.searchPlaceholder"), "aria-label": t("archives.searchPlaceholder") })] }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, { value: "created", label: t("archives.sortCreated") }, { value: "alphabetical", label: t("archives.sortAlphabetical") }], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") })] }), groups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.empty") }) : filteredGroups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.emptyFiltered") }) : filteredGroups.map((group) => {
|
|
3303
|
+
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS + ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS }), (0, react_jsx_runtime.jsxs)("header", { className: "dsham_settingsHeader", children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsTitleRow", children: [(0, react_jsx_runtime.jsx)("h2", { children: t("archives.title") }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsLinks", children: [(0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager", target: "_blank", rel: "noreferrer", "aria-label": t("archives.viewProject"), children: [(0, react_jsx_runtime.jsx)(GithubMark16, {}), t("archives.viewProject")] }), (0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager/issues", target: "_blank", rel: "noreferrer", "aria-label": t("archives.feedback"), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, {}), t("archives.feedback")] })] })] }), (0, react_jsx_runtime.jsx)("p", { className: "dsham_settingsIntro", children: t("archives.description") })] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsHeaderActions", children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsRestoreAll", disabled: busy || allBatchSessionIds.length === 0, onClick: () => onBatchUnarchive(allBatchTarget), children: t("archives.restoreAll") }), (0, react_jsx_runtime.jsxs)("button", { type: "button", className: "dsham_settingsDanger", disabled: busy || allBatchSessionIds.length === 0, onClick: () => setDeleteTarget({ kind: "batch", target: allBatchTarget, title: t("archives.allProjects"), count: allBatchSessionIds.length }), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}), t("archives.deleteAll")] })] })] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsToolbar", children: [(0, react_jsx_runtime.jsxs)("label", { className: "dsham_settingsSearch", children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, {}), (0, react_jsx_runtime.jsx)("input", { type: "search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: t("archives.searchPlaceholder"), "aria-label": t("archives.searchPlaceholder") })] }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, { value: "created", label: t("archives.sortCreated") }, { value: "alphabetical", label: t("archives.sortAlphabetical") }], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") })] }), groups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.empty") }) : filteredGroups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.emptyFiltered") }) : filteredGroups.map((group) => {
|
|
3258
3304
|
const target = archivedBatchTargetForGroup(group.key);
|
|
3259
3305
|
const count = deriveArchivedBatchIds(workspaceState.archivedSessionIds, workspaceState.items, target).length;
|
|
3260
3306
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -3276,7 +3322,7 @@ window.__ModuleLoader__.load({
|
|
|
3276
3322
|
closeLabel: t("close"),
|
|
3277
3323
|
title: deleteDialogTitle,
|
|
3278
3324
|
...deleteDialogDescription === void 0 ? {} : { description: deleteDialogDescription },
|
|
3279
|
-
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeDelete, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: confirmDelete, children: deleteConfirmLabel })] }),
|
|
3325
|
+
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeDelete, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", className: "dsham_settingsDeleteConfirm", disabled: busy, onClick: confirmDelete, children: deleteConfirmLabel })] }),
|
|
3280
3326
|
children: busy && (0, react_jsx_runtime.jsx)("div", { role: "status", children: deleteTarget?.kind === "batch" ? t("archives.deleteBatchPending") : t("deleteSession.pending") })
|
|
3281
3327
|
})]
|
|
3282
3328
|
});
|
|
@@ -3321,6 +3367,8 @@ window.__ModuleLoader__.load({
|
|
|
3321
3367
|
"archived.notOpenable": "已归档,取消归档后可继续对话",
|
|
3322
3368
|
"archives.title": "已归档的聊天",
|
|
3323
3369
|
"archives.description": "管理已归档的会话。",
|
|
3370
|
+
"archives.viewProject": "GitHub",
|
|
3371
|
+
"archives.feedback": "问题反馈",
|
|
3324
3372
|
"archives.empty": "暂无已归档会话",
|
|
3325
3373
|
"archives.emptyFiltered": "没有匹配的已归档聊天",
|
|
3326
3374
|
"archives.searchPlaceholder": "搜索已归档聊天",
|
|
@@ -3445,6 +3493,8 @@ window.__ModuleLoader__.load({
|
|
|
3445
3493
|
"archived.notOpenable": "This session is archived. Unarchive it to continue the conversation.",
|
|
3446
3494
|
"archives.title": "Archived chats",
|
|
3447
3495
|
"archives.description": "Manage archived sessions.",
|
|
3496
|
+
"archives.viewProject": "GitHub",
|
|
3497
|
+
"archives.feedback": "Issues",
|
|
3448
3498
|
"archives.empty": "No archived sessions.",
|
|
3449
3499
|
"archives.emptyFiltered": "No archived chats match your filters.",
|
|
3450
3500
|
"archives.searchPlaceholder": "Search archived chats",
|
package/lib/projcache.js
CHANGED
|
@@ -25,17 +25,23 @@ const storedCheckpointRecord = checkpointRecord.extend({
|
|
|
25
25
|
});
|
|
26
26
|
const safeDomainInput = {
|
|
27
27
|
name: "session_projcache_archive_manager",
|
|
28
|
-
version:
|
|
28
|
+
version: 2,
|
|
29
29
|
tables: { sessions: domainTable(storedCheckpointRecord) },
|
|
30
30
|
...(projectionCacheDomainSpec.layout === "per-record" ? { layout: "per-record" } : {})
|
|
31
31
|
};
|
|
32
32
|
const safeProjectionCacheDomainSpec = defineDomain(safeDomainInput);
|
|
33
33
|
|
|
34
34
|
/** The last official whole-file cache format used by DSH rc.2. */
|
|
35
|
+
const legacyCheckpointRecord = checkpointRecord.extend({
|
|
36
|
+
identity: checkpointIdentity.partial({
|
|
37
|
+
isSeeded: true,
|
|
38
|
+
inheritedEventCount: true
|
|
39
|
+
})
|
|
40
|
+
});
|
|
35
41
|
const legacyProjectionCacheDomainSpec = defineDomain({
|
|
36
42
|
name: "session_projcache",
|
|
37
43
|
version: 3,
|
|
38
|
-
tables: { sessions: domainTable(
|
|
44
|
+
tables: { sessions: domainTable(legacyCheckpointRecord) }
|
|
39
45
|
});
|
|
40
46
|
|
|
41
47
|
function projectionCacheStorageKey(sessionId) {
|
|
@@ -107,12 +113,42 @@ async function readSourceRecords(ctx, spec, label) {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* 旧版记录没有完整身份时,只能安全补齐未播种会话的零继承切点。
|
|
118
|
+
* 播种会话无法从头部反推出精确切点,宁可跳过并按需重建。
|
|
119
|
+
*/
|
|
120
|
+
function normalizeLegacyRecord(record) {
|
|
121
|
+
if (record === null || typeof record !== "object" || record.identity === null || typeof record.identity !== "object") return void 0;
|
|
122
|
+
const identity = record.identity;
|
|
123
|
+
const inheritedEventCount = identity.inheritedEventCount;
|
|
124
|
+
const validOffset = Number.isSafeInteger(inheritedEventCount) && inheritedEventCount >= 0;
|
|
125
|
+
if (identity.isSeeded === true) {
|
|
126
|
+
if (!validOffset) return void 0;
|
|
127
|
+
return record;
|
|
128
|
+
}
|
|
129
|
+
if (identity.isSeeded !== void 0 && identity.isSeeded !== false) return void 0;
|
|
130
|
+
if (inheritedEventCount !== void 0 && inheritedEventCount !== 0) return void 0;
|
|
131
|
+
return {
|
|
132
|
+
...record,
|
|
133
|
+
identity: {
|
|
134
|
+
...identity,
|
|
135
|
+
isSeeded: false,
|
|
136
|
+
inheritedEventCount: 0
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
110
141
|
async function importMissingRecords(ctx, target, records, label) {
|
|
111
142
|
let imported = 0;
|
|
112
143
|
for (const [sessionId, record] of records) {
|
|
113
144
|
if (target.has(sessionId)) continue;
|
|
114
145
|
try {
|
|
115
|
-
|
|
146
|
+
const normalized = normalizeLegacyRecord(record);
|
|
147
|
+
if (normalized === void 0) {
|
|
148
|
+
ctx.logger.warn(`archive-manager projcache: ${label} row "${sessionId}" import skipped because its lifecycle identity is incomplete`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
await target.put(sessionId, normalized);
|
|
116
152
|
imported += 1;
|
|
117
153
|
} catch (error) {
|
|
118
154
|
ctx.logger.warn(`archive-manager projcache: ${label} row "${sessionId}" import failed: ${String(error)}`);
|
|
@@ -122,22 +158,20 @@ async function importMissingRecords(ctx, target, records, label) {
|
|
|
122
158
|
}
|
|
123
159
|
|
|
124
160
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* fall through to the current source; source-open failures stay fail-soft.
|
|
128
|
-
* Imports are add-only: a newer compatibility-domain checkpoint always wins,
|
|
129
|
-
* and a partially completed import resumes on the next startup.
|
|
161
|
+
* 合并官方新版逐会话缓存与旧版整文件缓存。归档管理器自身记录最高优先,
|
|
162
|
+
* 新版记录优先于旧版;任一来源失败时仍继续尝试另一个来源。
|
|
130
163
|
*/
|
|
131
164
|
async function importPreviousProjectionCache(ctx, target) {
|
|
132
165
|
const legacy = await readSourceRecords(ctx, legacyProjectionCacheDomainSpec, "legacy v3");
|
|
133
|
-
if (!legacy.opened) return 0;
|
|
134
|
-
if (legacy.records.length > 0) return importMissingRecords(ctx, target, legacy.records, "legacy v3");
|
|
135
166
|
const sameSpec = projectionCacheDomainSpec.version === legacyProjectionCacheDomainSpec.version
|
|
136
167
|
&& projectionCacheDomainSpec.layout === legacyProjectionCacheDomainSpec.layout;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
168
|
+
let imported = 0;
|
|
169
|
+
if (!sameSpec) {
|
|
170
|
+
const current = await readSourceRecords(ctx, projectionCacheDomainSpec, "current");
|
|
171
|
+
if (current.opened) imported += await importMissingRecords(ctx, target, current.records, "current");
|
|
172
|
+
}
|
|
173
|
+
if (legacy.opened) imported += await importMissingRecords(ctx, target, legacy.records, "legacy v3");
|
|
174
|
+
return imported;
|
|
141
175
|
}
|
|
142
176
|
//#region lib/types/index.js
|
|
143
177
|
/**
|
package/lib/workspace.js
CHANGED
|
@@ -279,14 +279,27 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
279
279
|
if (cache === void 0 || typeof cache.cachedSnapshot !== "function" || typeof cache.put !== "function") return false;
|
|
280
280
|
if (persistence === void 0 || typeof persistence.readFrom !== "function" || projections === void 0 || typeof projections.restore !== "function") return false;
|
|
281
281
|
try {
|
|
282
|
-
|
|
282
|
+
// 未播种会话的继承事件数恒为零,先查缓存可避免读取完整会话原文。
|
|
283
|
+
if (!header.isSeeded && cache.cachedSnapshot(header, 0) !== void 0) return false;
|
|
283
284
|
const stored = await persistence.readFrom(header.id, 0);
|
|
284
285
|
const meta = stored.meta ?? header;
|
|
285
|
-
|
|
286
|
+
if (meta.isSeeded === true && stored.inheritedEventCount === void 0) {
|
|
287
|
+
this.ctx.logger.warn(`archive-manager: projection repair for seeded archived session "${header.id}" skipped because its inherited event count is unavailable`);
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
const inheritedEventCount = stored.inheritedEventCount ?? 0;
|
|
291
|
+
if (meta.isSeeded !== true && inheritedEventCount !== 0) {
|
|
292
|
+
this.ctx.logger.warn(`archive-manager: projection repair for unseeded archived session "${header.id}" skipped because its inherited event count is not zero`);
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
if (cache.cachedSnapshot(meta, inheritedEventCount) !== void 0) return false;
|
|
296
|
+
const restored = projections.restore({}, stored.events, 0, meta, inheritedEventCount);
|
|
286
297
|
if (restored === void 0 || typeof restored !== "object" || restored.checkpoint === void 0) return false;
|
|
287
298
|
await cache.put(header.id, {
|
|
288
299
|
createdAt: meta.createdAt,
|
|
289
|
-
...meta.cwd === void 0 ? {} : { cwd: meta.cwd }
|
|
300
|
+
...(meta.cwd === void 0 ? {} : { cwd: meta.cwd }),
|
|
301
|
+
isSeeded: meta.isSeeded ?? false,
|
|
302
|
+
inheritedEventCount
|
|
290
303
|
}, restored.checkpoint);
|
|
291
304
|
return true;
|
|
292
305
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-archive-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "NPM-installable DSH Web plugin for managing archived sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.21.0",
|
|
@@ -36,14 +36,15 @@
|
|
|
36
36
|
"@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.5 <0.2.0",
|
|
37
37
|
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.5 <0.2.0",
|
|
38
38
|
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.5 <0.2.0",
|
|
39
|
+
"@deepseek-ai/dsh-client-store": ">=0.1.0-rc.5 <0.2.0",
|
|
39
40
|
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.0-rc.5 <0.2.0",
|
|
40
41
|
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.5 <0.2.0",
|
|
41
42
|
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.0-rc.5 <0.2.0",
|
|
42
43
|
"@deepseek-ai/dsh-client-ui-workspace": ">=0.1.0-rc.5 <0.2.0",
|
|
43
44
|
"@deepseek-ai/dsh-session": ">=0.1.0-rc.5 <0.2.0",
|
|
44
45
|
"@deepseek-ai/dsh-session-projection-cache": ">=0.1.0-rc.5 <0.2.0",
|
|
45
|
-
"@deepseek-ai/dsh-storage-domain": ">=0.1.0-rc.5 <0.2.0",
|
|
46
46
|
"@deepseek-ai/dsh-spill-local": ">=0.1.0-rc.5 <0.2.0",
|
|
47
|
+
"@deepseek-ai/dsh-storage-domain": ">=0.1.0-rc.5 <0.2.0",
|
|
47
48
|
"@deepseek-ai/dsh-typert-protocol": ">=0.1.0-rc.5 <0.2.0",
|
|
48
49
|
"@deepseek-ai/dsh-typert-registry": ">=0.1.0-rc.5 <0.2.0",
|
|
49
50
|
"@deepseek-ai/dsh-workspace": ">=0.1.0-rc.5 <0.2.0"
|
|
@@ -51,20 +52,35 @@
|
|
|
51
52
|
"peerDependenciesMeta": {
|
|
52
53
|
"@deepseek-ai/dsh-client-runtime": {
|
|
53
54
|
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"@deepseek-ai/dsh-client-store": {
|
|
57
|
+
"optional": true
|
|
54
58
|
}
|
|
55
59
|
},
|
|
56
60
|
"devDependencies": {
|
|
57
|
-
"@deepseek-ai/cordis": "4.0.
|
|
58
|
-
"@deepseek-ai/dsh-api-gateway": "0.1.
|
|
59
|
-
"@deepseek-ai/dsh-client-
|
|
60
|
-
"@deepseek-ai/dsh-client-
|
|
61
|
-
"@deepseek-ai/dsh-client-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-
|
|
65
|
-
"@deepseek-ai/dsh-
|
|
66
|
-
"@deepseek-ai/dsh-
|
|
67
|
-
"@deepseek-ai/dsh-
|
|
61
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
62
|
+
"@deepseek-ai/dsh-api-gateway": "0.1.2-alpha.5",
|
|
63
|
+
"@deepseek-ai/dsh-client-connection": "0.1.2-alpha.5",
|
|
64
|
+
"@deepseek-ai/dsh-client-locale": "0.1.2-alpha.5",
|
|
65
|
+
"@deepseek-ai/dsh-client-store": "0.1.2-alpha.5",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-alpha.5",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-alpha.5",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.2-alpha.5",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-alpha.5",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.1.2-alpha.5",
|
|
71
|
+
"@deepseek-ai/dsh-invariants": "0.1.2-alpha.5",
|
|
72
|
+
"@deepseek-ai/dsh-scope": "0.1.2-alpha.5",
|
|
73
|
+
"@deepseek-ai/dsh-session": "0.1.2-alpha.5",
|
|
74
|
+
"@deepseek-ai/dsh-session-persistence": "0.1.2-alpha.5",
|
|
75
|
+
"@deepseek-ai/dsh-session-projection": "0.1.2-alpha.5",
|
|
76
|
+
"@deepseek-ai/dsh-session-projection-cache": "0.1.2-alpha.5",
|
|
77
|
+
"@deepseek-ai/dsh-spill": "0.1.2-alpha.5",
|
|
78
|
+
"@deepseek-ai/dsh-spill-local": "0.1.2-alpha.5",
|
|
79
|
+
"@deepseek-ai/dsh-storage": "0.1.2-alpha.5",
|
|
80
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.2-alpha.5",
|
|
81
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.2-alpha.5",
|
|
82
|
+
"@deepseek-ai/dsh-typert-registry": "0.1.2-alpha.5",
|
|
83
|
+
"@deepseek-ai/dsh-workspace": "0.1.2-alpha.5",
|
|
68
84
|
"react": "18.3.1",
|
|
69
85
|
"react-dom": "18.3.1"
|
|
70
86
|
},
|