@michengai/dsh-archive-manager 0.1.42 → 0.1.44
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 +13 -0
- package/CHANGELOG.zh-CN.md +13 -0
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/cordis.patch.yml +7 -0
- package/lib/archive-experience.js +41 -7
- package/lib/client.js +332 -198
- package/lib/workspace.js +158 -274
- package/package.json +41 -41
package/lib/client.js
CHANGED
|
@@ -10,18 +10,43 @@
|
|
|
10
10
|
function formatArchiveNavigationError(error, t) {
|
|
11
11
|
return error instanceof ArchiveNavigationError ? t(`archives.${error.code}`) : String(error?.message ?? error);
|
|
12
12
|
}
|
|
13
|
+
function retainInfoSnapshot(sessions, id) {
|
|
14
|
+
if (typeof sessions?.retainInfo !== "function") return;
|
|
15
|
+
const source = sessions.retainInfo(id);
|
|
16
|
+
return typeof source?.getSnapshot === "function" ? source.getSnapshot() : source;
|
|
17
|
+
}
|
|
18
|
+
function mainViewSessionId(list) {
|
|
19
|
+
const byId = list?.byId;
|
|
20
|
+
if (byId === void 0) return;
|
|
21
|
+
for (const session of Object.values(byId)) {
|
|
22
|
+
if ((session?.retainedBy?.mainView ?? 0) > 0) return session.id;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function currentSessionId(list) {
|
|
26
|
+
return mainViewSessionId(list) ?? list?.current;
|
|
27
|
+
}
|
|
28
|
+
function sessionIsCurrent(list, id, sessions) {
|
|
29
|
+
if (id === void 0 || id === "") return false;
|
|
30
|
+
if ((list?.byId?.[id]?.retainedBy?.mainView ?? 0) > 0) return true;
|
|
31
|
+
if ((retainInfoSnapshot(sessions, id)?.retainedBy?.mainView ?? 0) > 0) return true;
|
|
32
|
+
return list?.current === id;
|
|
33
|
+
}
|
|
13
34
|
async function openArchivedConversation(actions, sessionId, restore, isActive = () => true) {
|
|
14
|
-
if (restore)
|
|
35
|
+
if (restore) {
|
|
36
|
+
if (typeof actions.prepare === "function") await actions.prepare(sessionId);
|
|
37
|
+
if (!isActive()) return;
|
|
38
|
+
await actions.restore(sessionId);
|
|
39
|
+
}
|
|
15
40
|
if (isActive()) await actions.open(sessionId);
|
|
16
41
|
}
|
|
17
42
|
function allowArchivedNavigation(navigation, sessions, workspaces, { onOpened = () => {
|
|
18
|
-
}, warn = (...args) => console.warn(...args) } = {}) {
|
|
43
|
+
}, beginNavigation, warn = (...args) => console.warn(...args) } = {}) {
|
|
19
44
|
let allowed;
|
|
20
45
|
const original = navigation?.clearArchivedCurrent;
|
|
21
46
|
const descriptor = navigation && Object.getOwnPropertyDescriptor(navigation, "clearArchivedCurrent");
|
|
47
|
+
const viewing = (id) => sessionIsCurrent(sessions.list.getSnapshot(), id, sessions);
|
|
22
48
|
const wrapped = function(...args) {
|
|
23
|
-
|
|
24
|
-
if (current === allowed && current !== void 0 && workspaces.list.getSnapshot().archivedSessionIds.includes(current)) return false;
|
|
49
|
+
if (allowed !== void 0 && viewing(allowed) && workspaces.list.getSnapshot().archivedSessionIds.includes(allowed)) return false;
|
|
25
50
|
allowed = void 0;
|
|
26
51
|
return original.apply(this, args);
|
|
27
52
|
};
|
|
@@ -42,8 +67,15 @@
|
|
|
42
67
|
warn("archive-manager: \u5F52\u6863\u5BFC\u822A\u9002\u914D\u4E0D\u53EF\u7528\u6216\u5DF2\u88AB\u66FF\u6362\u3002");
|
|
43
68
|
throw new ArchiveNavigationError("navigationUnavailable");
|
|
44
69
|
}
|
|
45
|
-
|
|
46
|
-
if (sessions.
|
|
70
|
+
beginNavigation?.();
|
|
71
|
+
if (typeof sessions.retain === "function" && typeof navigation?.openSession === "function") navigation.openSession(id);
|
|
72
|
+
else if (typeof sessions.open === "function") sessions.open(id);
|
|
73
|
+
else if (typeof navigation?.openSession === "function") navigation.openSession(id);
|
|
74
|
+
else {
|
|
75
|
+
warn("archive-manager: \u5BBF\u4E3B\u672A\u63D0\u4F9B\u4F1A\u8BDD\u6253\u5F00\u63A5\u53E3\u3002");
|
|
76
|
+
throw new ArchiveNavigationError("navigationUnavailable");
|
|
77
|
+
}
|
|
78
|
+
if (!viewing(id)) {
|
|
47
79
|
warn("archive-manager: \u5BBF\u4E3B\u672A\u4FDD\u7559\u76EE\u6807\u4F1A\u8BDD\u3002", { cleanupAvailable: typeof original === "function" });
|
|
48
80
|
throw new ArchiveNavigationError("sessionNotRetained");
|
|
49
81
|
}
|
|
@@ -468,12 +500,6 @@
|
|
|
468
500
|
return value;
|
|
469
501
|
}
|
|
470
502
|
};
|
|
471
|
-
const workspaceIdSchema = {
|
|
472
|
-
parse(value) {
|
|
473
|
-
if (typeof value !== "string" || value.length === 0) throw new TypeError(`workspaceId must be a non-empty string, got ${String(value)}`);
|
|
474
|
-
return value;
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
503
|
const archivedSetSchema = {
|
|
478
504
|
parse(value) {
|
|
479
505
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
|
|
@@ -497,28 +523,6 @@
|
|
|
497
523
|
throw new TypeError("target.scope must be all, ungrouped, workspace with a non-empty workspaceId, or sessions with non-empty sessionIds");
|
|
498
524
|
}
|
|
499
525
|
};
|
|
500
|
-
const unarchivedBatchSchema = {
|
|
501
|
-
parse(value) {
|
|
502
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
|
|
503
|
-
if (!Array.isArray(value.archivedSessionIds) || value.archivedSessionIds.some((id) => typeof id !== "string")) throw new TypeError("archivedSessionIds must be a string array");
|
|
504
|
-
if (!Array.isArray(value.unarchivedSessionIds) || value.unarchivedSessionIds.some((id) => typeof id !== "string")) throw new TypeError("unarchivedSessionIds must be a string array");
|
|
505
|
-
return value;
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
const archiveSessionIdsSchema = {
|
|
509
|
-
parse(value) {
|
|
510
|
-
if (!Array.isArray(value)) throw new TypeError("sessionIds must be an array");
|
|
511
|
-
return [...new Set(value.map((id) => sessionIdSchema.parse(id)))];
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
const archivedWorkspaceBatchSchema = {
|
|
515
|
-
parse(value) {
|
|
516
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
|
|
517
|
-
if (!Array.isArray(value.archivedSessionIds) || value.archivedSessionIds.some((id) => typeof id !== "string")) throw new TypeError("archivedSessionIds must be a string array");
|
|
518
|
-
if (!Array.isArray(value.archivedSessionIdsAdded) || value.archivedSessionIdsAdded.some((id) => typeof id !== "string")) throw new TypeError("archivedSessionIdsAdded must be a string array");
|
|
519
|
-
return value;
|
|
520
|
-
}
|
|
521
|
-
};
|
|
522
526
|
const deletedBatchSchema = {
|
|
523
527
|
parse(value) {
|
|
524
528
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
|
|
@@ -537,6 +541,9 @@
|
|
|
537
541
|
return value;
|
|
538
542
|
}
|
|
539
543
|
};
|
|
544
|
+
function strictCodec(typeSymbol, schema) {
|
|
545
|
+
return { mode: "strict", typeSymbol, create: () => schema, schema };
|
|
546
|
+
}
|
|
540
547
|
const ARCHIVE_MANAGER_REMOTE = {
|
|
541
548
|
package: "@michengai/dsh-archive-manager",
|
|
542
549
|
descriptors: [
|
|
@@ -550,13 +557,9 @@
|
|
|
550
557
|
name: "sessionId",
|
|
551
558
|
wire: "sessionId",
|
|
552
559
|
source: "json",
|
|
553
|
-
codec:
|
|
560
|
+
codec: strictCodec("@deepseek-ai/dsh-session/types#SessionId", sessionIdSchema)
|
|
554
561
|
}],
|
|
555
|
-
result:
|
|
556
|
-
mode: "strict",
|
|
557
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedSessionIds",
|
|
558
|
-
schema: archivedSetSchema
|
|
559
|
-
},
|
|
562
|
+
result: strictCodec("@michengai/dsh-archive-manager/types#ArchivedSessionIds", archivedSetSchema),
|
|
560
563
|
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
561
564
|
},
|
|
562
565
|
{
|
|
@@ -569,70 +572,9 @@
|
|
|
569
572
|
name: "sessionId",
|
|
570
573
|
wire: "sessionId",
|
|
571
574
|
source: "json",
|
|
572
|
-
codec:
|
|
573
|
-
}],
|
|
574
|
-
result: {
|
|
575
|
-
mode: "strict",
|
|
576
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#Deleted",
|
|
577
|
-
schema: deletedSchema
|
|
578
|
-
},
|
|
579
|
-
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
580
|
-
},
|
|
581
|
-
{
|
|
582
|
-
id: "@michengai/dsh-archive-manager#workspaceRegistry/unarchiveSessions",
|
|
583
|
-
service: "workspaceRegistry",
|
|
584
|
-
namespace: "workspaceRegistry",
|
|
585
|
-
method: "unarchiveSessions",
|
|
586
|
-
invocation: { kind: "direct" },
|
|
587
|
-
parameters: [{
|
|
588
|
-
name: "target",
|
|
589
|
-
wire: "target",
|
|
590
|
-
source: "json",
|
|
591
|
-
codec: { mode: "strict", typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedBatchTarget", schema: archivedBatchTargetSchema }
|
|
592
|
-
}],
|
|
593
|
-
result: {
|
|
594
|
-
mode: "strict",
|
|
595
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#UnarchivedBatch",
|
|
596
|
-
schema: unarchivedBatchSchema
|
|
597
|
-
},
|
|
598
|
-
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveSessions",
|
|
602
|
-
service: "workspaceRegistry",
|
|
603
|
-
namespace: "workspaceRegistry",
|
|
604
|
-
method: "archiveSessions",
|
|
605
|
-
invocation: { kind: "direct" },
|
|
606
|
-
parameters: [{
|
|
607
|
-
name: "sessionIds",
|
|
608
|
-
wire: "sessionIds",
|
|
609
|
-
source: "json",
|
|
610
|
-
codec: { mode: "strict", typeSymbol: "@michengai/dsh-archive-manager/types#ArchiveSessionIds", schema: archiveSessionIdsSchema }
|
|
575
|
+
codec: strictCodec("@deepseek-ai/dsh-session/types#SessionId", sessionIdSchema)
|
|
611
576
|
}],
|
|
612
|
-
result:
|
|
613
|
-
mode: "strict",
|
|
614
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedWorkspaceBatch",
|
|
615
|
-
schema: archivedWorkspaceBatchSchema
|
|
616
|
-
},
|
|
617
|
-
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveWorkspaceSessions",
|
|
621
|
-
service: "workspaceRegistry",
|
|
622
|
-
namespace: "workspaceRegistry",
|
|
623
|
-
method: "archiveWorkspaceSessions",
|
|
624
|
-
invocation: { kind: "direct" },
|
|
625
|
-
parameters: [{
|
|
626
|
-
name: "workspaceId",
|
|
627
|
-
wire: "workspaceId",
|
|
628
|
-
source: "json",
|
|
629
|
-
codec: { mode: "strict", typeSymbol: "@deepseek-ai/dsh-workspace/types#WorkspaceId", schema: workspaceIdSchema }
|
|
630
|
-
}],
|
|
631
|
-
result: {
|
|
632
|
-
mode: "strict",
|
|
633
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedWorkspaceBatch",
|
|
634
|
-
schema: archivedWorkspaceBatchSchema
|
|
635
|
-
},
|
|
577
|
+
result: strictCodec("@michengai/dsh-archive-manager/types#Deleted", deletedSchema),
|
|
636
578
|
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
637
579
|
},
|
|
638
580
|
{
|
|
@@ -645,13 +587,9 @@
|
|
|
645
587
|
name: "target",
|
|
646
588
|
wire: "target",
|
|
647
589
|
source: "json",
|
|
648
|
-
codec:
|
|
590
|
+
codec: strictCodec("@michengai/dsh-archive-manager/types#ArchivedBatchTarget", archivedBatchTargetSchema)
|
|
649
591
|
}],
|
|
650
|
-
result:
|
|
651
|
-
mode: "strict",
|
|
652
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#DeletedBatch",
|
|
653
|
-
schema: deletedBatchSchema
|
|
654
|
-
},
|
|
592
|
+
result: strictCodec("@michengai/dsh-archive-manager/types#DeletedBatch", deletedBatchSchema),
|
|
655
593
|
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
656
594
|
},
|
|
657
595
|
{
|
|
@@ -661,11 +599,7 @@
|
|
|
661
599
|
method: "archivedSessionMetadata",
|
|
662
600
|
invocation: { kind: "direct" },
|
|
663
601
|
parameters: [],
|
|
664
|
-
result:
|
|
665
|
-
mode: "strict",
|
|
666
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedSessionMetadata",
|
|
667
|
-
schema: archivedSessionMetadataSchema
|
|
668
|
-
},
|
|
602
|
+
result: strictCodec("@michengai/dsh-archive-manager/types#ArchivedSessionMetadata", archivedSessionMetadataSchema),
|
|
669
603
|
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
670
604
|
}
|
|
671
605
|
]
|
|
@@ -711,7 +645,23 @@
|
|
|
711
645
|
return indexed;
|
|
712
646
|
}
|
|
713
647
|
const FLAT_SESSION_ORDER_KEY = "__flat_session_order__";
|
|
648
|
+
const WORKSPACE_VIEW_PERSIST_KEY = "dsh.archive-manager.workspace.view.v1";
|
|
649
|
+
const LEGACY_WORKSPACE_VIEW_PERSIST_KEY = "dsh.workspace.view.v5";
|
|
650
|
+
function migrateWorkspaceViewPersist(storage) {
|
|
651
|
+
const target = storage ?? globalThis.localStorage;
|
|
652
|
+
if (target == null || typeof target.getItem !== "function" || typeof target.setItem !== "function") return false;
|
|
653
|
+
try {
|
|
654
|
+
if (target.getItem(WORKSPACE_VIEW_PERSIST_KEY) != null) return false;
|
|
655
|
+
const legacy = target.getItem(LEGACY_WORKSPACE_VIEW_PERSIST_KEY);
|
|
656
|
+
if (legacy == null) return false;
|
|
657
|
+
target.setItem(WORKSPACE_VIEW_PERSIST_KEY, legacy);
|
|
658
|
+
return true;
|
|
659
|
+
} catch {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
714
663
|
function createWorkspaceViewStore() {
|
|
664
|
+
migrateWorkspaceViewPersist();
|
|
715
665
|
return (0, _deepseek_ai_dsh_client_store.defineStore)({
|
|
716
666
|
init: () => ({
|
|
717
667
|
groupBy: "workspace",
|
|
@@ -721,7 +671,7 @@
|
|
|
721
671
|
sessionOrderByAccount: {},
|
|
722
672
|
sessionUpdatedAtByAccount: {}
|
|
723
673
|
}),
|
|
724
|
-
persist:
|
|
674
|
+
persist: WORKSPACE_VIEW_PERSIST_KEY,
|
|
725
675
|
actions: {
|
|
726
676
|
setGroupBy: (d, mode) => {
|
|
727
677
|
d.groupBy = mode;
|
|
@@ -754,7 +704,7 @@
|
|
|
754
704
|
function GithubMark16() {
|
|
755
705
|
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" }) });
|
|
756
706
|
}
|
|
757
|
-
function ArchivedSessionsSection({ archiveSessions, sessionStore, workspaceStore, unarchiveSession, deleteSession, unarchiveSessions, deleteArchivedSessions, archivedSessionMetadata, openConversation, viewState, close, t }) {
|
|
707
|
+
function ArchivedSessionsSection({ archiveSessions, sessionStore, workspaceStore, unarchiveSession, deleteSession, unarchiveSessions, deleteArchivedSessions, archivedSessionMetadata, openConversation, focusSessionWorkspace, viewState, close, t }) {
|
|
758
708
|
const sessions = (0, react.useSyncExternalStore)(sessionStore.subscribe, sessionStore.getSnapshot);
|
|
759
709
|
const workspaceState = (0, react.useSyncExternalStore)(workspaceStore.subscribe, workspaceStore.getSnapshot);
|
|
760
710
|
const [archiveTab, setArchiveTab] = (0, react.useState)("archived");
|
|
@@ -799,13 +749,29 @@
|
|
|
799
749
|
navigationPending.current = true;
|
|
800
750
|
setBusy(true);
|
|
801
751
|
setError(null);
|
|
752
|
+
let restored = false;
|
|
802
753
|
try {
|
|
803
|
-
await openArchivedConversation({
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
754
|
+
await openArchivedConversation({
|
|
755
|
+
prepare: restore ? async (id) => {
|
|
756
|
+
await focusSessionWorkspace?.(id);
|
|
757
|
+
} : void 0,
|
|
758
|
+
restore: async (id) => {
|
|
759
|
+
await unarchiveSession(id);
|
|
760
|
+
restored = true;
|
|
761
|
+
},
|
|
762
|
+
open: async (id) => {
|
|
763
|
+
await openConversation(id);
|
|
764
|
+
if (navigationActive.current) close?.();
|
|
765
|
+
}
|
|
766
|
+
}, session.id, restore, () => navigationActive.current);
|
|
807
767
|
} catch (reason) {
|
|
808
|
-
if (navigationActive.current)
|
|
768
|
+
if (!navigationActive.current) return;
|
|
769
|
+
if (restored) {
|
|
770
|
+
setArchiveTab("unarchived");
|
|
771
|
+
const group = groups.find((item) => item.sessions.some((row) => row.id === session.id));
|
|
772
|
+
if (group !== void 0) setProject(group.key);
|
|
773
|
+
}
|
|
774
|
+
setError(formatArchiveNavigationError(reason, t));
|
|
809
775
|
} finally {
|
|
810
776
|
navigationPending.current = false;
|
|
811
777
|
if (navigationActive.current) setBusy(false);
|
|
@@ -836,7 +802,10 @@
|
|
|
836
802
|
setNotice(null);
|
|
837
803
|
try {
|
|
838
804
|
const result = await archiveSessions(archiveTarget);
|
|
839
|
-
setSelectedSessionIds(
|
|
805
|
+
setSelectedSessionIds([]);
|
|
806
|
+
setArchiveTab("archived");
|
|
807
|
+
setProject("all");
|
|
808
|
+
setQuery("");
|
|
840
809
|
setNotice(t("archives.archiveSuccess", { n: result.archivedSessionIdsAdded.length }));
|
|
841
810
|
setArchiveTarget(null);
|
|
842
811
|
setArchiveGroup(null);
|
|
@@ -1150,12 +1119,12 @@
|
|
|
1150
1119
|
const summary = list.byId[id];
|
|
1151
1120
|
if (summary === void 0) continue;
|
|
1152
1121
|
accounted.add(id);
|
|
1153
|
-
if (!sessionVisible(summary, list
|
|
1122
|
+
if (!sessionVisible(summary, currentSessionId(list), archived, showArchived)) continue;
|
|
1154
1123
|
members.push(summary);
|
|
1155
1124
|
}
|
|
1156
1125
|
groups.push(buildGroup(workspace.workspaceId, workspace.workspaceId, workspace.path, Date.parse(workspace.createdAt), workspace.title, members, "account"));
|
|
1157
1126
|
}
|
|
1158
|
-
const stray = list.ids.map((id) => list.byId[id]).filter((s) => s !== void 0 && !accounted.has(s.id) && sessionVisible(s, list
|
|
1127
|
+
const stray = list.ids.map((id) => list.byId[id]).filter((s) => s !== void 0 && !accounted.has(s.id) && sessionVisible(s, currentSessionId(list), archived, showArchived));
|
|
1159
1128
|
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"));
|
|
1160
1129
|
return groups;
|
|
1161
1130
|
}
|
|
@@ -1188,18 +1157,49 @@
|
|
|
1188
1157
|
return visiblePendingKind(kind);
|
|
1189
1158
|
}
|
|
1190
1159
|
const EMPTY_PENDING_INTERACTIONS = /* @__PURE__ */ new Map();
|
|
1160
|
+
const EMPTY_COMPLETED_SESSIONS = /* @__PURE__ */ new Set();
|
|
1161
|
+
const EMPTY_SESSION_STATUS = /* @__PURE__ */ new Map();
|
|
1191
1162
|
function useEmptySessionPendingInteraction(selector) {
|
|
1192
1163
|
return selector(EMPTY_PENDING_INTERACTIONS);
|
|
1193
1164
|
}
|
|
1165
|
+
function useEmptySessionStatus(selector) {
|
|
1166
|
+
return selector(EMPTY_SESSION_STATUS);
|
|
1167
|
+
}
|
|
1168
|
+
function pendingFacts(pendingInteractions) {
|
|
1169
|
+
if (pendingInteractions instanceof Map || pendingInteractions == null) {
|
|
1170
|
+
return { pending: pendingInteractions ?? EMPTY_PENDING_INTERACTIONS, completed: EMPTY_COMPLETED_SESSIONS };
|
|
1171
|
+
}
|
|
1172
|
+
return {
|
|
1173
|
+
pending: pendingInteractions.pending ?? EMPTY_PENDING_INTERACTIONS,
|
|
1174
|
+
completed: pendingInteractions.completed ?? EMPTY_COMPLETED_SESSIONS
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
function factsFromSessionStatus(status) {
|
|
1178
|
+
const pending = /* @__PURE__ */ new Map();
|
|
1179
|
+
const completed = /* @__PURE__ */ new Set();
|
|
1180
|
+
if (status instanceof Map) {
|
|
1181
|
+
for (const [id, entry] of status) {
|
|
1182
|
+
if (entry?.pendingInteraction !== void 0) pending.set(id, entry.pendingInteraction);
|
|
1183
|
+
if (entry?.completionUnread === true) completed.add(id);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
return { pending, completed };
|
|
1187
|
+
}
|
|
1188
|
+
function useSessionUiFacts(usePending, useStatus, preferStatus) {
|
|
1189
|
+
const pending = usePending((s) => s);
|
|
1190
|
+
const status = useStatus((s) => s);
|
|
1191
|
+
return preferStatus ? factsFromSessionStatus(status) : { pending, completed: EMPTY_COMPLETED_SESSIONS };
|
|
1192
|
+
}
|
|
1194
1193
|
function sessionNode(s, descendants, archived, pendingInteractions) {
|
|
1195
|
-
const
|
|
1194
|
+
const facts = pendingFacts(pendingInteractions);
|
|
1195
|
+
const pendingInteraction = pendingInteractionForSession(s, facts.pending);
|
|
1196
1196
|
return {
|
|
1197
1197
|
id: s.id,
|
|
1198
1198
|
title: sessionTitle(s),
|
|
1199
1199
|
blank: s.blank,
|
|
1200
1200
|
running: s.running,
|
|
1201
1201
|
runningSubagentCount: descendants.get(s.id)?.runningCount ?? 0,
|
|
1202
|
-
completed: s.completed === true,
|
|
1202
|
+
completed: s.completed === true || facts.completed.has(s.id),
|
|
1203
1203
|
updatedAt: s.updatedAt,
|
|
1204
1204
|
archived: archived.has(s.id),
|
|
1205
1205
|
...pendingInteraction === void 0 ? {} : { pendingInteraction }
|
|
@@ -1209,7 +1209,8 @@
|
|
|
1209
1209
|
const archived = new Set(archivedSessionIds);
|
|
1210
1210
|
const expandedGroups = new Set(view.expandedGroups);
|
|
1211
1211
|
const descendants = indexSubagentDescendants(list.byId);
|
|
1212
|
-
const
|
|
1212
|
+
const current = currentSessionId(list);
|
|
1213
|
+
const currentGroup = current === void 0 ? void 0 : workspaces.find((w) => w.sessionIds.includes(current))?.workspaceId ?? "";
|
|
1213
1214
|
const groups = [];
|
|
1214
1215
|
for (const g of groupByWorkspace(list, workspaces, archived, view.ungroupedOrder, view.showArchived)) {
|
|
1215
1216
|
const expanded = expandedGroups.has(g.key);
|
|
@@ -1233,7 +1234,7 @@
|
|
|
1233
1234
|
const rows = [];
|
|
1234
1235
|
for (const id of list.ids) {
|
|
1235
1236
|
const s = list.byId[id];
|
|
1236
|
-
if (s === void 0 || !sessionVisible(s, list
|
|
1237
|
+
if (s === void 0 || !sessionVisible(s, currentSessionId(list), archived, showArchived)) continue;
|
|
1237
1238
|
rows.push(s);
|
|
1238
1239
|
}
|
|
1239
1240
|
rows.sort(byRecency);
|
|
@@ -1255,7 +1256,7 @@
|
|
|
1255
1256
|
const local = [];
|
|
1256
1257
|
for (const id of list.ids) {
|
|
1257
1258
|
const summary = list.byId[id];
|
|
1258
|
-
if (summary === void 0 || summary.blank || !sessionVisible(summary, list
|
|
1259
|
+
if (summary === void 0 || summary.blank || !sessionVisible(summary, currentSessionId(list), archived, showArchived)) continue;
|
|
1259
1260
|
if (sessionTitle(summary).toLowerCase().includes(q) || labelOf(summary).toLowerCase().includes(q)) local.push(summary);
|
|
1260
1261
|
}
|
|
1261
1262
|
local.sort(byRecency);
|
|
@@ -1269,12 +1270,13 @@
|
|
|
1269
1270
|
for (const summary of local) include(summary);
|
|
1270
1271
|
for (const item of content.items) {
|
|
1271
1272
|
const summary = list.byId[item.sessionId];
|
|
1272
|
-
if (summary !== void 0 && !summary.blank && sessionVisible(summary, list
|
|
1273
|
+
if (summary !== void 0 && !summary.blank && sessionVisible(summary, currentSessionId(list), archived, showArchived)) include(summary);
|
|
1273
1274
|
}
|
|
1275
|
+
const facts = pendingFacts(pendingInteractions);
|
|
1274
1276
|
return {
|
|
1275
1277
|
items: ordered.slice(0, limit).map((summary) => {
|
|
1276
1278
|
const match = contentBySession.get(summary.id);
|
|
1277
|
-
const pendingInteraction = pendingInteractionForSession(summary,
|
|
1279
|
+
const pendingInteraction = pendingInteractionForSession(summary, facts.pending);
|
|
1278
1280
|
return {
|
|
1279
1281
|
id: summary.id,
|
|
1280
1282
|
title: sessionTitle(summary),
|
|
@@ -1283,7 +1285,7 @@
|
|
|
1283
1285
|
runningSubagentCount: descendants.get(summary.id)?.runningCount ?? 0,
|
|
1284
1286
|
archived: archived.has(summary.id),
|
|
1285
1287
|
...pendingInteraction === void 0 ? {} : { pendingInteraction },
|
|
1286
|
-
completed: summary.completed === true,
|
|
1288
|
+
completed: summary.completed === true || facts.completed.has(summary.id),
|
|
1287
1289
|
...match === void 0 ? {} : { snippet: match.snippet }
|
|
1288
1290
|
};
|
|
1289
1291
|
}),
|
|
@@ -1629,7 +1631,7 @@
|
|
|
1629
1631
|
})]
|
|
1630
1632
|
});
|
|
1631
1633
|
}
|
|
1632
|
-
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onUnarchive, onDeleteSession, drag, flat = false, t }) {
|
|
1634
|
+
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onUnarchive, onDeleteSession, onReveal, drag, flat = false, t }) {
|
|
1633
1635
|
const row = node;
|
|
1634
1636
|
const title = displayTitle(node, t);
|
|
1635
1637
|
const selected = node.id === currentId;
|
|
@@ -1637,6 +1639,12 @@
|
|
|
1637
1639
|
const statuses = sessionStatuses(node, t);
|
|
1638
1640
|
const showStatus = statuses[0].state !== "done" || row.completed;
|
|
1639
1641
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
1642
|
+
const rowRef = (0, react.useRef)(null);
|
|
1643
|
+
(0, react.useEffect)(() => {
|
|
1644
|
+
if (onReveal === void 0) return;
|
|
1645
|
+
rowRef.current?.scrollIntoView({ block: "nearest" });
|
|
1646
|
+
onReveal();
|
|
1647
|
+
}, [onReveal]);
|
|
1640
1648
|
const sessionMenuItems = archived ? [
|
|
1641
1649
|
{
|
|
1642
1650
|
id: "unarchive",
|
|
@@ -1674,6 +1682,7 @@
|
|
|
1674
1682
|
];
|
|
1675
1683
|
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
1676
1684
|
anchor: (0, react_jsx_runtime.jsxs)("div", {
|
|
1685
|
+
ref: rowRef,
|
|
1677
1686
|
className: clsx(Rows_module_css_default.sessionRow, selected && Rows_module_css_default.selected, menuOpen && Rows_module_css_default.menuOpen, flat && !showStatus && Rows_module_css_default.flatSessionRowWithoutStatus, archived && ARCHIVED_CLASSES.row, drag?.marker === "before" && Rows_module_css_default.dropBefore, drag?.marker === "after" && Rows_module_css_default.dropAfter),
|
|
1678
1687
|
role: "treeitem",
|
|
1679
1688
|
"aria-selected": selected,
|
|
@@ -2123,10 +2132,10 @@
|
|
|
2123
2132
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
2124
2133
|
return e.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
2125
2134
|
}
|
|
2126
|
-
function SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onArchiveRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
2135
|
+
function SessionTree({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onArchiveRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed }) {
|
|
2127
2136
|
const list = useSessions((s) => s);
|
|
2128
|
-
const pendingInteractions = useSessionPendingInteraction
|
|
2129
|
-
const current = list
|
|
2137
|
+
const pendingInteractions = useSessionUiFacts(useSessionPendingInteraction, useSessionStatus, preferSessionStatus);
|
|
2138
|
+
const current = currentSessionId(list);
|
|
2130
2139
|
const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)([]);
|
|
2131
2140
|
const [drag, setDrag] = (0, react.useState)(null);
|
|
2132
2141
|
const sessionDropCommitted = (0, react.useRef)(false);
|
|
@@ -2135,6 +2144,7 @@
|
|
|
2135
2144
|
const previousOrderBy = (0, react.useRef)(orderBy);
|
|
2136
2145
|
useNativeDragAcceptance(drag !== null || workspaceDrag !== null);
|
|
2137
2146
|
const currentGroup = current === void 0 ? void 0 : workspaces.find((w) => w.sessionIds.includes(current))?.workspaceId ?? "";
|
|
2147
|
+
const revealGroup = revealSessionId === void 0 ? void 0 : workspaces.find((w) => w.sessionIds.includes(revealSessionId))?.workspaceId ?? "";
|
|
2138
2148
|
(0, react.useEffect)(() => {
|
|
2139
2149
|
if (current === void 0 || currentGroup === void 0 || Object.hasOwn(groupExpansion, currentGroup)) return;
|
|
2140
2150
|
setGroupExpanded(currentGroup, true);
|
|
@@ -2144,6 +2154,14 @@
|
|
|
2144
2154
|
setGroupExpanded,
|
|
2145
2155
|
groupExpansion
|
|
2146
2156
|
]);
|
|
2157
|
+
(0, react.useEffect)(() => {
|
|
2158
|
+
if (revealGroup === void 0 || groupExpansion[revealGroup] === true) return;
|
|
2159
|
+
setGroupExpanded(revealGroup, true);
|
|
2160
|
+
}, [
|
|
2161
|
+
groupExpansion,
|
|
2162
|
+
revealGroup,
|
|
2163
|
+
setGroupExpanded
|
|
2164
|
+
]);
|
|
2147
2165
|
const expandedGroups = (0, react.useMemo)(() => Object.entries(groupExpansion).filter(([, expanded]) => expanded).map(([key]) => key), [groupExpansion]);
|
|
2148
2166
|
const ungroupedSessionIds = (0, react.useMemo)(() => {
|
|
2149
2167
|
const accounted = new Set(workspaces.flatMap((workspace) => workspace.sessionIds));
|
|
@@ -2170,7 +2188,7 @@
|
|
|
2170
2188
|
orderBy,
|
|
2171
2189
|
sortByRecency: orderBy === "updated" && (previousOrder === void 0 || switchedToUpdated)
|
|
2172
2190
|
});
|
|
2173
|
-
if (next.changed) syncSessionOrderAccount(key, next.order.map((id) => id), next.updatedAt);
|
|
2191
|
+
if (next.changed && typeof syncSessionOrderAccount === "function") syncSessionOrderAccount(key, next.order.map((id) => id), next.updatedAt);
|
|
2174
2192
|
}
|
|
2175
2193
|
}, [
|
|
2176
2194
|
list,
|
|
@@ -2205,6 +2223,17 @@
|
|
|
2205
2223
|
expandedGroups,
|
|
2206
2224
|
sessionOrderByAccount
|
|
2207
2225
|
]);
|
|
2226
|
+
(0, react.useEffect)(() => {
|
|
2227
|
+
if (revealSessionId === void 0 || revealGroup === void 0) return;
|
|
2228
|
+
const group = groups.find((candidate) => candidate.key === revealGroup);
|
|
2229
|
+
if (group === void 0 || !group.expanded || !group.sessions.some((row) => row.id === revealSessionId)) return;
|
|
2230
|
+
if (group.sessions.slice(0, COLLAPSED_SESSION_LIMIT).some((row) => row.id === revealSessionId)) return;
|
|
2231
|
+
setExpandedSessionGroups((keys) => keys.includes(revealGroup) ? keys : [...keys, revealGroup]);
|
|
2232
|
+
}, [
|
|
2233
|
+
groups,
|
|
2234
|
+
revealGroup,
|
|
2235
|
+
revealSessionId
|
|
2236
|
+
]);
|
|
2208
2237
|
const now = Date.now();
|
|
2209
2238
|
const commitSessionDrag = (activeDrag, over) => {
|
|
2210
2239
|
if (sessionDropCommitted.current) return;
|
|
@@ -2351,6 +2380,9 @@
|
|
|
2351
2380
|
onArchive: onSessionArchive,
|
|
2352
2381
|
onUnarchive: onSessionUnarchive,
|
|
2353
2382
|
onDeleteSession: onSessionDelete,
|
|
2383
|
+
onReveal: node.id === revealSessionId && group.key === revealGroup ? () => {
|
|
2384
|
+
onSessionRevealed?.(node.id);
|
|
2385
|
+
} : void 0,
|
|
2354
2386
|
drag: {
|
|
2355
2387
|
start: () => {
|
|
2356
2388
|
sessionDropCommitted.current = false;
|
|
@@ -2404,9 +2436,10 @@
|
|
|
2404
2436
|
]
|
|
2405
2437
|
});
|
|
2406
2438
|
}
|
|
2407
|
-
function FlatList({ useSessions, useSessionPendingInteraction, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
2439
|
+
function FlatList({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed }) {
|
|
2408
2440
|
const list = useSessions((s) => s);
|
|
2409
|
-
const pendingInteractions = useSessionPendingInteraction
|
|
2441
|
+
const pendingInteractions = useSessionUiFacts(useSessionPendingInteraction, useSessionStatus, preferSessionStatus);
|
|
2442
|
+
const current = currentSessionId(list);
|
|
2410
2443
|
const baseRows = (0, react.useMemo)(() => deriveFlat(list, archivedSessionIds, pendingInteractions, showArchived), [
|
|
2411
2444
|
list,
|
|
2412
2445
|
archivedSessionIds,
|
|
@@ -2482,7 +2515,7 @@
|
|
|
2482
2515
|
const active = drag !== null;
|
|
2483
2516
|
return (0, react_jsx_runtime.jsx)(SessionNodeItem, {
|
|
2484
2517
|
node,
|
|
2485
|
-
currentId:
|
|
2518
|
+
currentId: current,
|
|
2486
2519
|
now,
|
|
2487
2520
|
onOpen: open,
|
|
2488
2521
|
onRename: onSessionRename,
|
|
@@ -2494,6 +2527,9 @@
|
|
|
2494
2527
|
onArchive: onSessionArchive,
|
|
2495
2528
|
onUnarchive: onSessionUnarchive,
|
|
2496
2529
|
onDeleteSession: onSessionDelete,
|
|
2530
|
+
onReveal: node.id === revealSessionId ? () => {
|
|
2531
|
+
onSessionRevealed?.(node.id);
|
|
2532
|
+
} : void 0,
|
|
2497
2533
|
flat: true,
|
|
2498
2534
|
drag: {
|
|
2499
2535
|
start: () => {
|
|
@@ -2507,8 +2543,8 @@
|
|
|
2507
2543
|
active,
|
|
2508
2544
|
marker: active && drag.over?.id === node.id ? drag.over.half : null,
|
|
2509
2545
|
hover: (half) => {
|
|
2510
|
-
setDrag((
|
|
2511
|
-
...
|
|
2546
|
+
setDrag((current2) => current2 === null ? current2 : {
|
|
2547
|
+
...current2,
|
|
2512
2548
|
over: {
|
|
2513
2549
|
id: node.id,
|
|
2514
2550
|
half
|
|
@@ -2533,9 +2569,9 @@
|
|
|
2533
2569
|
}), (0, react_jsx_runtime.jsx)("span", { className: WorkspaceBrowser_module_css_default.fade })]
|
|
2534
2570
|
});
|
|
2535
2571
|
}
|
|
2536
|
-
function SearchResults({ useSessions, useSessionPendingInteraction, open, workspaces, archivedSessionIds, showArchived, query, remote, resultLimit, t }) {
|
|
2572
|
+
function SearchResults({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, open, workspaces, archivedSessionIds, showArchived, query, remote, resultLimit, t }) {
|
|
2537
2573
|
const list = useSessions((s) => s);
|
|
2538
|
-
const pendingInteractions = useSessionPendingInteraction
|
|
2574
|
+
const pendingInteractions = useSessionUiFacts(useSessionPendingInteraction, useSessionStatus, preferSessionStatus);
|
|
2539
2575
|
const ungroupedLabel = t("group.ungrouped");
|
|
2540
2576
|
const currentRemote = remote.query === query ? remote : {
|
|
2541
2577
|
query,
|
|
@@ -2567,7 +2603,7 @@
|
|
|
2567
2603
|
"aria-label": t("search.results.aria"),
|
|
2568
2604
|
children: results.items.map((result) => (0, react_jsx_runtime.jsx)(SearchResultItem, {
|
|
2569
2605
|
result,
|
|
2570
|
-
currentId: list
|
|
2606
|
+
currentId: currentSessionId(list),
|
|
2571
2607
|
onOpen: open,
|
|
2572
2608
|
t
|
|
2573
2609
|
}, result.id))
|
|
@@ -2594,8 +2630,22 @@
|
|
|
2594
2630
|
}), (0, react_jsx_runtime.jsx)("span", { className: WorkspaceBrowser_module_css_default.fade })]
|
|
2595
2631
|
});
|
|
2596
2632
|
}
|
|
2597
|
-
|
|
2633
|
+
const sidebarReveal = {
|
|
2634
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
2635
|
+
request(sessionId) {
|
|
2636
|
+
for (const listener of this.listeners) listener(sessionId);
|
|
2637
|
+
},
|
|
2638
|
+
subscribe(listener) {
|
|
2639
|
+
this.listeners.add(listener);
|
|
2640
|
+
return () => {
|
|
2641
|
+
this.listeners.delete(listener);
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
function WorkspaceBrowser({ wide, expandSidebar, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, archiveWorkspaceSessions, unarchiveSession, deleteSession, insertSessionBefore, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, renderSlot, t }) {
|
|
2646
|
+
const preferSessionStatus = typeof useSessionStatus === "function";
|
|
2598
2647
|
const useEffectiveSessionPendingInteraction = useSessionPendingInteraction ?? useEmptySessionPendingInteraction;
|
|
2648
|
+
const useEffectiveSessionStatus = useSessionStatus ?? useEmptySessionStatus;
|
|
2599
2649
|
const workspaces = useWorkspaces((state) => state.items);
|
|
2600
2650
|
const workspacePhase = useWorkspaces((state) => state.phase);
|
|
2601
2651
|
const archivedSessionIds = useWorkspaces((state) => state.archivedSessionIds);
|
|
@@ -2608,6 +2658,11 @@
|
|
|
2608
2658
|
const sessionOrderByAccount = useStore((s) => s.sessionOrderByAccount);
|
|
2609
2659
|
const sessionUpdatedAtByAccount = useStore((s) => s.sessionUpdatedAtByAccount);
|
|
2610
2660
|
const archivedSet = (0, react.useMemo)(() => new Set(archivedSessionIds), [archivedSessionIds]);
|
|
2661
|
+
const [revealSessionId, setRevealSessionId] = (0, react.useState)(void 0);
|
|
2662
|
+
(0, react.useEffect)(() => sidebarReveal.subscribe((sessionId) => setRevealSessionId(sessionId)), []);
|
|
2663
|
+
const acknowledgeSessionReveal = (sessionId) => {
|
|
2664
|
+
setRevealSessionId((current) => current === sessionId ? void 0 : current);
|
|
2665
|
+
};
|
|
2611
2666
|
const [archivedToast, setArchivedToast] = (0, react.useState)(null);
|
|
2612
2667
|
const archivedToastSeq = (0, react.useRef)(0);
|
|
2613
2668
|
const showArchivedToast2 = (text) => {
|
|
@@ -3015,7 +3070,14 @@
|
|
|
3015
3070
|
children: wide && (normalizedQuery !== "" ? (0, react_jsx_runtime.jsx)(SearchResults, {
|
|
3016
3071
|
useSessions,
|
|
3017
3072
|
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
3018
|
-
|
|
3073
|
+
useSessionStatus: useEffectiveSessionStatus,
|
|
3074
|
+
preferSessionStatus,
|
|
3075
|
+
open: (sessionId) => {
|
|
3076
|
+
setRevealSessionId(sessionId);
|
|
3077
|
+
setQuery("");
|
|
3078
|
+
setSearchExpanded(false);
|
|
3079
|
+
guardedOpen(sessionId);
|
|
3080
|
+
},
|
|
3019
3081
|
workspaces,
|
|
3020
3082
|
archivedSessionIds,
|
|
3021
3083
|
showArchived,
|
|
@@ -3026,7 +3088,11 @@
|
|
|
3026
3088
|
}) : groupBy === "flat" ? (0, react_jsx_runtime.jsx)(FlatList, {
|
|
3027
3089
|
useSessions,
|
|
3028
3090
|
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
3091
|
+
useSessionStatus: useEffectiveSessionStatus,
|
|
3092
|
+
preferSessionStatus,
|
|
3029
3093
|
open: guardedOpen,
|
|
3094
|
+
revealSessionId,
|
|
3095
|
+
onSessionRevealed: acknowledgeSessionReveal,
|
|
3030
3096
|
forkSession,
|
|
3031
3097
|
onSessionRename,
|
|
3032
3098
|
onSessionArchive,
|
|
@@ -3046,6 +3112,10 @@
|
|
|
3046
3112
|
}) : (0, react_jsx_runtime.jsx)(SessionTree, {
|
|
3047
3113
|
useSessions,
|
|
3048
3114
|
useSessionPendingInteraction: useEffectiveSessionPendingInteraction,
|
|
3115
|
+
useSessionStatus: useEffectiveSessionStatus,
|
|
3116
|
+
preferSessionStatus,
|
|
3117
|
+
revealSessionId,
|
|
3118
|
+
onSessionRevealed: acknowledgeSessionReveal,
|
|
3049
3119
|
onSessionRename,
|
|
3050
3120
|
onSessionArchive,
|
|
3051
3121
|
onSessionUnarchive,
|
|
@@ -3908,8 +3978,7 @@
|
|
|
3908
3978
|
"workspaces",
|
|
3909
3979
|
"locale",
|
|
3910
3980
|
"remote",
|
|
3911
|
-
"typert"
|
|
3912
|
-
...hasSplitClientStore ? ["uiWorkspace"] : []
|
|
3981
|
+
"typert"
|
|
3913
3982
|
];
|
|
3914
3983
|
function bindObservable(source) {
|
|
3915
3984
|
return {
|
|
@@ -3917,18 +3986,58 @@
|
|
|
3917
3986
|
subscribe: source.subscribe.bind(source)
|
|
3918
3987
|
};
|
|
3919
3988
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3989
|
+
function createUnarchiveSession(workspaces, getRegistry) {
|
|
3990
|
+
return async (sessionId) => {
|
|
3991
|
+
if (typeof workspaces?.unarchiveSession === "function") {
|
|
3992
|
+
await workspaces.unarchiveSession(sessionId);
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
const registry = typeof getRegistry === "function" ? getRegistry() : getRegistry;
|
|
3996
|
+
if (registry === void 0) throw new Error("archive-manager remote service is unavailable");
|
|
3997
|
+
const result = await registry.unarchiveSession(sessionId);
|
|
3998
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
3999
|
+
return result.value;
|
|
4000
|
+
};
|
|
4001
|
+
}
|
|
4002
|
+
async function archiveSessionsViaOfficial(workspaces, sessionIds, refresh) {
|
|
4003
|
+
const before = new Set(workspaces.list?.getSnapshot?.()?.archivedSessionIds ?? []);
|
|
4004
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4005
|
+
for (const sessionId of sessionIds) {
|
|
4006
|
+
if (typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) continue;
|
|
4007
|
+
seen.add(sessionId);
|
|
4008
|
+
await workspaces.archiveSession(sessionId);
|
|
4009
|
+
}
|
|
4010
|
+
if (typeof refresh === "function") await refresh();
|
|
4011
|
+
const archivedSessionIds = [...workspaces.list?.getSnapshot?.()?.archivedSessionIds ?? []];
|
|
4012
|
+
return {
|
|
4013
|
+
archivedSessionIds,
|
|
4014
|
+
archivedSessionIdsAdded: archivedSessionIds.filter((id) => !before.has(id))
|
|
4015
|
+
};
|
|
4016
|
+
}
|
|
4017
|
+
async function unarchiveSessionsViaOfficial(workspaces, sessionIds, refresh, unarchive) {
|
|
4018
|
+
const before = new Set(workspaces.list?.getSnapshot?.()?.archivedSessionIds ?? []);
|
|
4019
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4020
|
+
const run = typeof unarchive === "function" ? unarchive : (id) => workspaces.unarchiveSession(id);
|
|
4021
|
+
let archivedSessionIds;
|
|
4022
|
+
for (const sessionId of sessionIds) {
|
|
4023
|
+
if (typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) continue;
|
|
4024
|
+
seen.add(sessionId);
|
|
4025
|
+
const value = await run(sessionId);
|
|
4026
|
+
if (Array.isArray(value?.archivedSessionIds)) archivedSessionIds = [...value.archivedSessionIds];
|
|
4027
|
+
}
|
|
4028
|
+
if (typeof refresh === "function") await refresh();
|
|
4029
|
+
archivedSessionIds ??= [...workspaces.list?.getSnapshot?.()?.archivedSessionIds ?? []];
|
|
4030
|
+
return {
|
|
4031
|
+
archivedSessionIds,
|
|
4032
|
+
unarchivedSessionIds: [...before].filter((id) => !archivedSessionIds.includes(id))
|
|
4033
|
+
};
|
|
3925
4034
|
}
|
|
3926
4035
|
async function apply(ctx) {
|
|
4036
|
+
applyWorkspaceBrowser(ctx);
|
|
3927
4037
|
const remote = ctx.get("remote");
|
|
3928
4038
|
let disposeRemote = () => {
|
|
3929
4039
|
};
|
|
3930
4040
|
if (remote !== void 0) disposeRemote = await remote.$mount(ARCHIVE_MANAGER_REMOTE);
|
|
3931
|
-
applyWorkspaceBrowser(ctx);
|
|
3932
4041
|
return async () => {
|
|
3933
4042
|
await disposeRemote();
|
|
3934
4043
|
};
|
|
@@ -3950,13 +4059,24 @@
|
|
|
3950
4059
|
const uiWorkspaceAt = () => ctx.get("uiWorkspace");
|
|
3951
4060
|
const archiveViewState = {};
|
|
3952
4061
|
let archiveNavigation;
|
|
3953
|
-
|
|
3954
|
-
archiveNavigation = allowArchivedNavigation(
|
|
3955
|
-
onOpened: () => ctx.get("layout")?.selectPanel(null)
|
|
4062
|
+
const attachArchiveNavigation = (navigation) => {
|
|
4063
|
+
archiveNavigation = allowArchivedNavigation(navigation, ctx.sessions, ctx.workspaces, {
|
|
4064
|
+
onOpened: () => ctx.get("layout")?.selectPanel(null),
|
|
4065
|
+
beginNavigation: () => ctx.get("layout")?.beginNavigation?.()
|
|
3956
4066
|
});
|
|
3957
4067
|
return () => archiveNavigation.dispose();
|
|
3958
|
-
}
|
|
3959
|
-
|
|
4068
|
+
};
|
|
4069
|
+
if (typeof ctx.inject === "function") ctx.inject(["uiWorkspace"], (ready) => attachArchiveNavigation(ready.uiWorkspace ?? uiWorkspaceAt()));
|
|
4070
|
+
else ctx.effect(() => attachArchiveNavigation(uiWorkspaceAt()), "archive-manager: explicit archived navigation");
|
|
4071
|
+
const openConversation = (sessionId) => {
|
|
4072
|
+
if (archiveNavigation === void 0) throw new ArchiveNavigationError("navigationUnavailable");
|
|
4073
|
+
sidebarReveal.request(sessionId);
|
|
4074
|
+
return archiveNavigation.open(sessionId);
|
|
4075
|
+
};
|
|
4076
|
+
const focusSessionWorkspace = async (sessionId) => {
|
|
4077
|
+
ctx.get("layout")?.beginNavigation?.();
|
|
4078
|
+
sidebarReveal.request(sessionId);
|
|
4079
|
+
};
|
|
3960
4080
|
const searchSessions = async (query, signal) => {
|
|
3961
4081
|
const result = await ctx.sessions.search(query, signal);
|
|
3962
4082
|
if (!result.ok) throw new Error(result.error.message);
|
|
@@ -3975,17 +4095,16 @@
|
|
|
3975
4095
|
console.warn("archive-manager: restored archived sessions but session list refresh failed:", error);
|
|
3976
4096
|
}
|
|
3977
4097
|
};
|
|
4098
|
+
const unarchiveOne = createUnarchiveSession(ctx.workspaces, () => ctx.get("remote.workspaceRegistry"));
|
|
3978
4099
|
const unarchiveSession = async (sessionId) => {
|
|
3979
|
-
|
|
3980
|
-
if (registry === void 0) throw new Error("archive-manager remote service is unavailable");
|
|
3981
|
-
const result = await registry.unarchiveSession(sessionId);
|
|
3982
|
-
if (!result.ok) throw new Error(result.error.message);
|
|
4100
|
+
await unarchiveOne(sessionId);
|
|
3983
4101
|
await refreshSessionList();
|
|
3984
4102
|
};
|
|
3985
4103
|
const archiveWorkspaceSessions = async (workspaceId) => {
|
|
3986
|
-
const
|
|
3987
|
-
|
|
3988
|
-
|
|
4104
|
+
const items = ctx.workspaces.list?.getSnapshot?.()?.items ?? [];
|
|
4105
|
+
const workspace = items.find((item) => item.workspaceId === workspaceId);
|
|
4106
|
+
if (workspace === void 0) throw new Error(`unknown workspace "${workspaceId}"`);
|
|
4107
|
+
return archiveSessionsViaOfficial(ctx.workspaces, workspace.sessionIds, refreshSessionList);
|
|
3989
4108
|
};
|
|
3990
4109
|
const deleteSession = async (sessionId) => {
|
|
3991
4110
|
const registry = ctx.get("remote.workspaceRegistry");
|
|
@@ -3994,21 +4113,11 @@
|
|
|
3994
4113
|
if (!result.ok) throw new Error(result.error.message);
|
|
3995
4114
|
await refreshSessionList();
|
|
3996
4115
|
};
|
|
3997
|
-
const archiveSessions = async (sessionIds) =>
|
|
3998
|
-
const registry = ctx.get("remote.workspaceRegistry");
|
|
3999
|
-
if (registry === void 0) throw new Error("archive-manager remote service is unavailable");
|
|
4000
|
-
const result = await registry.archiveSessions(sessionIds);
|
|
4001
|
-
if (!result.ok) throw new Error(result.error.message);
|
|
4002
|
-
await refreshSessionList();
|
|
4003
|
-
return result.value;
|
|
4004
|
-
};
|
|
4116
|
+
const archiveSessions = async (sessionIds) => archiveSessionsViaOfficial(ctx.workspaces, sessionIds, refreshSessionList);
|
|
4005
4117
|
const unarchiveSessions = async (target) => {
|
|
4006
|
-
const
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
if (!result.ok) throw new Error(result.error.message);
|
|
4010
|
-
await refreshSessionList();
|
|
4011
|
-
return result.value;
|
|
4118
|
+
const snapshot = ctx.workspaces.list?.getSnapshot?.() ?? { archivedSessionIds: [], items: [] };
|
|
4119
|
+
const sessionIds = deriveArchivedBatchIds(snapshot.archivedSessionIds, snapshot.items, target);
|
|
4120
|
+
return unarchiveSessionsViaOfficial(ctx.workspaces, sessionIds, refreshSessionList, unarchiveOne);
|
|
4012
4121
|
};
|
|
4013
4122
|
const deleteArchivedSessions = async (target) => {
|
|
4014
4123
|
const registry = ctx.get("remote.workspaceRegistry");
|
|
@@ -4046,16 +4155,24 @@
|
|
|
4046
4155
|
searchSessions,
|
|
4047
4156
|
searchResultLimit: ctx.sessions.searchResultLimit,
|
|
4048
4157
|
renameSession: async (sessionId, title) => {
|
|
4158
|
+
const rename = async (session2) => {
|
|
4159
|
+
const result = await session2.rename(title);
|
|
4160
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
4161
|
+
};
|
|
4162
|
+
if (typeof ctx.sessions.using === "function") {
|
|
4163
|
+
await ctx.sessions.using(sessionId, { source: "workspaceOperation" }, (reference) => rename(reference.binding.session));
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4049
4166
|
const session = ctx.sessions.binding(sessionId)?.session;
|
|
4050
4167
|
if (session === void 0) throw new Error(`unknown session "${sessionId}"`);
|
|
4051
|
-
|
|
4052
|
-
if (!result.ok) throw new Error(result.error.message);
|
|
4168
|
+
await rename(session);
|
|
4053
4169
|
},
|
|
4054
4170
|
forkSession: (sessionId) => {
|
|
4055
4171
|
const uiWorkspace = uiWorkspaceAt();
|
|
4056
4172
|
if (typeof uiWorkspace?.forkSession === "function") return uiWorkspace.forkSession(sessionId);
|
|
4057
4173
|
return ctx.sessions.fork({ sessionId, increaseTitle: true }).then((childId) => {
|
|
4058
|
-
|
|
4174
|
+
if (typeof uiWorkspace?.openSession === "function") uiWorkspace.openSession(childId);
|
|
4175
|
+
else ctx.sessions.open(childId);
|
|
4059
4176
|
});
|
|
4060
4177
|
},
|
|
4061
4178
|
renameWorkspace: async (workspaceId, title) => {
|
|
@@ -4079,18 +4196,28 @@
|
|
|
4079
4196
|
createWorkspace: (input) => ctx.workspaces.create(input),
|
|
4080
4197
|
hooks: { directoryFlow: browserFlowSource }
|
|
4081
4198
|
});
|
|
4082
|
-
ctx.slots.inject("sidebar.workspaces", () =>
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4199
|
+
ctx.slots.inject("sidebar.workspaces", () => {
|
|
4200
|
+
const common = {
|
|
4201
|
+
name: "sidebar.workspaces",
|
|
4202
|
+
// 低于官方 0,高于 Codex -1:必须盖住官方三项菜单才能露出删除。
|
|
4203
|
+
priority: -0.5,
|
|
4204
|
+
store: createWorkspaceViewStore(),
|
|
4205
|
+
inject: browserInjected,
|
|
4206
|
+
locale: NS
|
|
4207
|
+
};
|
|
4208
|
+
try {
|
|
4209
|
+
return ctx.slots.register({
|
|
4210
|
+
...common,
|
|
4211
|
+
children: { [DIRECTORY_FLOW_SLOT]: {
|
|
4212
|
+
kind: "single",
|
|
4213
|
+
scope: "root"
|
|
4214
|
+
} }
|
|
4215
|
+
}, WorkspaceBrowser);
|
|
4216
|
+
} catch (error) {
|
|
4217
|
+
console.warn("archive-manager: sidebar registration with directory child failed, retrying without children", error);
|
|
4218
|
+
return ctx.slots.register(common, WorkspaceBrowser);
|
|
4219
|
+
}
|
|
4220
|
+
});
|
|
4094
4221
|
mirrorDirectoryFlow(ctx, DIRECTORY_FLOW_SLOT);
|
|
4095
4222
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
4096
4223
|
name: "settings.section",
|
|
@@ -4109,6 +4236,7 @@
|
|
|
4109
4236
|
deleteArchivedSessions,
|
|
4110
4237
|
archivedSessionMetadata,
|
|
4111
4238
|
openConversation,
|
|
4239
|
+
focusSessionWorkspace,
|
|
4112
4240
|
viewState: archiveViewState,
|
|
4113
4241
|
t: ctx.locale.bind(NS)
|
|
4114
4242
|
})
|
|
@@ -4136,13 +4264,19 @@
|
|
|
4136
4264
|
archiveableWorkspaceSessionCount,
|
|
4137
4265
|
archiveWorkspaceDialogTarget,
|
|
4138
4266
|
archiveWorkspaceDialogFailureState,
|
|
4139
|
-
|
|
4267
|
+
archiveSessionsViaOfficial,
|
|
4268
|
+
unarchiveSessionsViaOfficial,
|
|
4269
|
+
createUnarchiveSession,
|
|
4140
4270
|
createWorkspaceViewStore,
|
|
4271
|
+
migrateWorkspaceViewPersist,
|
|
4272
|
+
WORKSPACE_VIEW_PERSIST_KEY,
|
|
4273
|
+
LEGACY_WORKSPACE_VIEW_PERSIST_KEY,
|
|
4141
4274
|
bindObservable,
|
|
4142
4275
|
hasSplitClientStore,
|
|
4143
4276
|
groupByWorkspace,
|
|
4144
4277
|
byRecency,
|
|
4145
|
-
ARCHIVE_MANAGER_REMOTE
|
|
4278
|
+
ARCHIVE_MANAGER_REMOTE,
|
|
4279
|
+
currentSessionId
|
|
4146
4280
|
};
|
|
4147
4281
|
exports.apply = apply;
|
|
4148
4282
|
exports.inject = inject;
|