@michengai/dsh-codex-ui 1.1.12 → 1.1.13
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 +26 -0
- package/CHANGELOG.zh-CN.md +26 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +587 -188
- package/lib/session-title-plugin.mjs +4 -0
- package/lib/usage-frame.css +1 -1
- package/lib/usage-frame.js +98 -98
- package/package.json +37 -37
package/lib/client.js
CHANGED
|
@@ -8,11 +8,167 @@ window.__ModuleLoader__.load({
|
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
10
|
let react_dom = require("react-dom");
|
|
11
|
+
//#region src/client/session-host.ts
|
|
12
|
+
var UnknownSessionError = class extends Error {
|
|
13
|
+
constructor() {
|
|
14
|
+
super("unknown session");
|
|
15
|
+
this.name = "UnknownSessionError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/** 旧宿主读 list.current;alpha.2 主视图改由 retainedBy.mainView 标记。 */
|
|
19
|
+
function currentSessionId(state) {
|
|
20
|
+
if (state === void 0) return void 0;
|
|
21
|
+
if (typeof state.current === "string" && state.current !== "") return state.current;
|
|
22
|
+
const byId = state.byId ?? {};
|
|
23
|
+
const ids = Array.isArray(state.ids) && state.ids.length > 0 ? state.ids : Object.keys(byId);
|
|
24
|
+
const pick = (id, row) => {
|
|
25
|
+
if (row === void 0 || (row.retainedBy?.mainView ?? 0) <= 0) return void 0;
|
|
26
|
+
const explicit = row.id?.trim();
|
|
27
|
+
return explicit !== void 0 && explicit !== "" ? explicit : id;
|
|
28
|
+
};
|
|
29
|
+
for (const id of ids) {
|
|
30
|
+
const found = pick(id, byId[id]);
|
|
31
|
+
if (found !== void 0) return found;
|
|
32
|
+
}
|
|
33
|
+
for (const id of Object.keys(byId)) {
|
|
34
|
+
if (ids.includes(id)) continue;
|
|
35
|
+
const found = pick(id, byId[id]);
|
|
36
|
+
if (found !== void 0) return found;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** 官方树在全局面板打开时取消会话选中。 */
|
|
40
|
+
function visibleSelectedSessionId(state, panelActive = false) {
|
|
41
|
+
return panelActive ? void 0 : currentSessionId(state);
|
|
42
|
+
}
|
|
43
|
+
function sessionRowUnread(localUnread, status, selected = false) {
|
|
44
|
+
return localUnread || status?.completionUnread === true && !selected;
|
|
45
|
+
}
|
|
46
|
+
function sessionRunningFlags(byId, status) {
|
|
47
|
+
const ids = new Set(Object.keys(byId));
|
|
48
|
+
if (status !== void 0) for (const id of status.keys()) ids.add(id);
|
|
49
|
+
const next = {};
|
|
50
|
+
for (const id of ids) next[id] = sessionIsRunning(byId[id], status?.get(id));
|
|
51
|
+
return next;
|
|
52
|
+
}
|
|
53
|
+
/** 旧宿主看 current 是否空会话;alpha.2 看主视图 retain 的 blank。 */
|
|
54
|
+
function isBlankOnboardingSession(state) {
|
|
55
|
+
if (state?.phase !== "ready") return false;
|
|
56
|
+
const id = currentSessionId(state);
|
|
57
|
+
return id === void 0 || state.byId?.[id]?.blank === true;
|
|
58
|
+
}
|
|
59
|
+
function hostAccess(ctx) {
|
|
60
|
+
return ctx;
|
|
61
|
+
}
|
|
62
|
+
/** 有 reflect 时只 probe,不能硬读未注入服务,否则 Cordis 会挡住插件激活。 */
|
|
63
|
+
function probeService(ctx, name) {
|
|
64
|
+
if (ctx === void 0) return void 0;
|
|
65
|
+
const access = hostAccess(ctx);
|
|
66
|
+
const reflectGet = access.reflect?.get;
|
|
67
|
+
const hasReflect = typeof reflectGet === "function";
|
|
68
|
+
if (hasReflect) try {
|
|
69
|
+
const found = reflectGet.call(access.reflect, name);
|
|
70
|
+
if (found !== void 0) return found;
|
|
71
|
+
} catch {}
|
|
72
|
+
if (typeof access.get === "function") try {
|
|
73
|
+
const found = access.get(name);
|
|
74
|
+
if (found !== void 0) return found;
|
|
75
|
+
} catch {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (hasReflect) return void 0;
|
|
79
|
+
try {
|
|
80
|
+
return access[name];
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function openHostSession(ctx, id) {
|
|
86
|
+
if (id === "") return false;
|
|
87
|
+
const access = hostAccess(ctx);
|
|
88
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
89
|
+
if (typeof uiWorkspace?.openSession === "function") {
|
|
90
|
+
uiWorkspace.openSession(id);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (typeof access.sessions?.retain === "function") return false;
|
|
94
|
+
if (typeof access.sessions?.open === "function") {
|
|
95
|
+
access.sessions.open(id);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
async function withSessionBinding(sessions, sessionId, operation) {
|
|
101
|
+
const host = sessions === void 0 ? void 0 : hostAccess({ sessions }).sessions;
|
|
102
|
+
if (host === void 0) throw new UnknownSessionError();
|
|
103
|
+
if (typeof host.using === "function") return host.using(sessionId, { source: "controllerOperation" }, async (reference) => {
|
|
104
|
+
if (reference.ready !== void 0) await reference.ready;
|
|
105
|
+
if (reference.binding === void 0) throw new UnknownSessionError();
|
|
106
|
+
return operation(reference.binding);
|
|
107
|
+
});
|
|
108
|
+
const existing = host.binding?.(sessionId);
|
|
109
|
+
if (existing !== void 0) return operation(existing);
|
|
110
|
+
if (typeof host.retain !== "function") throw new UnknownSessionError();
|
|
111
|
+
const reference = host.retain(sessionId, { source: "controllerOperation" });
|
|
112
|
+
try {
|
|
113
|
+
if (reference.ready !== void 0) await reference.ready;
|
|
114
|
+
if (reference.binding === void 0) throw new UnknownSessionError();
|
|
115
|
+
return await operation(reference.binding);
|
|
116
|
+
} finally {
|
|
117
|
+
reference.release?.();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function renameHostSession(ctx, sessionId, title) {
|
|
121
|
+
await withSessionBinding(hostAccess(ctx).sessions, sessionId, async (binding) => {
|
|
122
|
+
if (typeof binding.session?.rename !== "function") throw new UnknownSessionError();
|
|
123
|
+
const result = await binding.session.rename(title);
|
|
124
|
+
if (result.ok === false) throw result.error ?? /* @__PURE__ */ new Error("rename failed");
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function forkHostSession(ctx, sessionId) {
|
|
128
|
+
const access = hostAccess(ctx);
|
|
129
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
130
|
+
if (typeof uiWorkspace?.forkSession === "function") {
|
|
131
|
+
await uiWorkspace.forkSession(sessionId);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const childId = await access.sessions?.fork?.({
|
|
135
|
+
sessionId,
|
|
136
|
+
increaseTitle: true
|
|
137
|
+
});
|
|
138
|
+
if (typeof childId === "string" && childId !== "") openHostSession(access, childId);
|
|
139
|
+
}
|
|
140
|
+
async function archiveHostSession(ctx, sessionId) {
|
|
141
|
+
const access = hostAccess(ctx);
|
|
142
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
143
|
+
if (typeof uiWorkspace?.archiveSession === "function") {
|
|
144
|
+
await uiWorkspace.archiveSession(sessionId);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
await access.workspaces?.archiveSession?.(sessionId);
|
|
148
|
+
}
|
|
149
|
+
function mergePendingInteractions(legacy, status) {
|
|
150
|
+
const next = new Map(legacy);
|
|
151
|
+
for (const [id, row] of status) if (row?.pendingInteraction !== void 0) next.set(id, row.pendingInteraction);
|
|
152
|
+
return next;
|
|
153
|
+
}
|
|
154
|
+
function sessionIsRunning(session, status) {
|
|
155
|
+
if (status?.running !== void 0) return status.running === true;
|
|
156
|
+
return session?.running === true;
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
11
159
|
//#region src/client/session-navigation.ts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
160
|
+
function openConversation(host, layout, id) {
|
|
161
|
+
const opened = openHostSession(host, id);
|
|
162
|
+
if (opened) selectGlobalPanel(layout, null);
|
|
163
|
+
return opened;
|
|
164
|
+
}
|
|
165
|
+
/** 先打开再写草稿,避免 using 释放后 composer 换新 binding。 */
|
|
166
|
+
async function openConversationWithDraft(host, layout, sessions, sessionId, writeDraft) {
|
|
167
|
+
return withSessionBinding(sessions, sessionId, (binding) => {
|
|
168
|
+
const opened = openConversation(host, layout, sessionId);
|
|
169
|
+
writeDraft(binding);
|
|
170
|
+
return opened;
|
|
171
|
+
});
|
|
16
172
|
}
|
|
17
173
|
/** 统一检测旧宿主是否提供面板切换能力,保留宿主方法的 this。 */
|
|
18
174
|
function selectGlobalPanel(layout, id) {
|
|
@@ -720,17 +876,112 @@ window.__ModuleLoader__.load({
|
|
|
720
876
|
key: "17ys0d"
|
|
721
877
|
}]]);
|
|
722
878
|
//#endregion
|
|
879
|
+
//#region src/client/settings-navigation.ts
|
|
880
|
+
/**
|
|
881
|
+
* DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
|
|
882
|
+
* 的设置入口触发,再按壳的可访问名称选择页面;宿主升级时可集中替换。
|
|
883
|
+
*/
|
|
884
|
+
function pickSettingsSectionButton(buttons, labels) {
|
|
885
|
+
for (const label of labels) {
|
|
886
|
+
const match = buttons.find((button) => button.textContent?.trim() === label);
|
|
887
|
+
if (match !== void 0) return match;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* 可选插件未注册设置入口时,直接打开兜底页,避免先展示通用设置并等待导航超时。
|
|
892
|
+
*/
|
|
893
|
+
function routeOptionalSettingsSection(available, openRequested, openFallback) {
|
|
894
|
+
if (available) {
|
|
895
|
+
openRequested();
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
openFallback();
|
|
899
|
+
}
|
|
900
|
+
/** 官方 alpha.2 插件管理页占用 sidebar.panellist / main 的同一 id。 */
|
|
901
|
+
const OFFICIAL_PLUGINS_PANEL_ID = "plugins";
|
|
902
|
+
let cancelPendingNavigation;
|
|
903
|
+
const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
|
|
904
|
+
const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
|
|
905
|
+
const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
|
|
906
|
+
/** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
|
|
907
|
+
function openSettingsRoot(root) {
|
|
908
|
+
root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
|
|
909
|
+
}
|
|
910
|
+
function openSettingsSection(root, label, onMissing, onSelected) {
|
|
911
|
+
const labels = typeof label === "string" ? [label] : label;
|
|
912
|
+
const trigger = root?.querySelector(SETTINGS_TRIGGER_SELECTOR);
|
|
913
|
+
if (trigger === null || trigger === void 0) {
|
|
914
|
+
onMissing?.();
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const opening = cancelPendingNavigation !== void 0;
|
|
918
|
+
cancelPendingNavigation?.();
|
|
919
|
+
const request = new CustomEvent(SETTINGS_OPEN_SECTION_EVENT, {
|
|
920
|
+
detail: { labels },
|
|
921
|
+
cancelable: true
|
|
922
|
+
});
|
|
923
|
+
if (!trigger.dispatchEvent(request)) {
|
|
924
|
+
onSelected?.();
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
|
|
928
|
+
if (!opening && document.querySelector(pageSelector) === null) trigger.click();
|
|
929
|
+
let frame;
|
|
930
|
+
let finished = false;
|
|
931
|
+
const observer = new MutationObserver(() => {
|
|
932
|
+
schedule();
|
|
933
|
+
});
|
|
934
|
+
const cleanup = () => {
|
|
935
|
+
if (finished) return;
|
|
936
|
+
finished = true;
|
|
937
|
+
observer.disconnect();
|
|
938
|
+
window.clearTimeout(timeout);
|
|
939
|
+
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
940
|
+
if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
|
|
941
|
+
};
|
|
942
|
+
const select = () => {
|
|
943
|
+
const target = pickSettingsSectionButton([...document.querySelectorAll(`${pageSelector} nav button`)], labels);
|
|
944
|
+
if (target === void 0) return false;
|
|
945
|
+
cleanup();
|
|
946
|
+
target.click();
|
|
947
|
+
onSelected?.();
|
|
948
|
+
return true;
|
|
949
|
+
};
|
|
950
|
+
const schedule = () => {
|
|
951
|
+
if (finished || frame !== void 0) return;
|
|
952
|
+
frame = window.requestAnimationFrame(() => {
|
|
953
|
+
frame = void 0;
|
|
954
|
+
select();
|
|
955
|
+
});
|
|
956
|
+
};
|
|
957
|
+
const timeout = window.setTimeout(() => {
|
|
958
|
+
if (select()) return;
|
|
959
|
+
cleanup();
|
|
960
|
+
console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
|
|
961
|
+
onMissing?.();
|
|
962
|
+
}, SETTINGS_NAVIGATION_TIMEOUT_MS);
|
|
963
|
+
observer.observe(document.body, {
|
|
964
|
+
childList: true,
|
|
965
|
+
subtree: true
|
|
966
|
+
});
|
|
967
|
+
cancelPendingNavigation = cleanup;
|
|
968
|
+
schedule();
|
|
969
|
+
}
|
|
970
|
+
//#endregion
|
|
723
971
|
//#region src/client/global-panels.tsx
|
|
724
972
|
/** 从宿主注册表读取面板元数据;缓存快照以满足 React 外部状态订阅契约。 */
|
|
725
973
|
function createGlobalPanelSource(slots, locale) {
|
|
726
974
|
let cached = [];
|
|
727
975
|
return {
|
|
728
976
|
getSnapshot() {
|
|
729
|
-
const next = slots.entriesOfSlot("sidebar.panellist").flatMap(({ options }) =>
|
|
730
|
-
id
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
977
|
+
const next = slots.entriesOfSlot("sidebar.panellist").flatMap(({ options }) => {
|
|
978
|
+
if (options.id === void 0 || options.id === "plugins") return [];
|
|
979
|
+
return [{
|
|
980
|
+
id: options.id,
|
|
981
|
+
order: options.order ?? 0,
|
|
982
|
+
label: (typeof options.label === "function" ? options.label() : options.label) ?? options.id
|
|
983
|
+
}];
|
|
984
|
+
}).sort((a, b) => a.order - b.order);
|
|
734
985
|
if (next.length !== cached.length || next.some((panel, index) => {
|
|
735
986
|
const previous = cached[index];
|
|
736
987
|
return previous === void 0 || panel.id !== previous.id || panel.label !== previous.label || panel.order !== previous.order;
|
|
@@ -907,96 +1158,6 @@ window.__ModuleLoader__.load({
|
|
|
907
1158
|
} catch {}
|
|
908
1159
|
}
|
|
909
1160
|
//#endregion
|
|
910
|
-
//#region src/client/settings-navigation.ts
|
|
911
|
-
/**
|
|
912
|
-
* DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
|
|
913
|
-
* 的设置入口触发,再按壳的可访问名称选择页面;宿主升级时可集中替换。
|
|
914
|
-
*/
|
|
915
|
-
function pickSettingsSectionButton(buttons, labels) {
|
|
916
|
-
for (const label of labels) {
|
|
917
|
-
const match = buttons.find((button) => button.textContent?.trim() === label);
|
|
918
|
-
if (match !== void 0) return match;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* 可选插件未注册设置入口时,直接打开兜底页,避免先展示通用设置并等待导航超时。
|
|
923
|
-
*/
|
|
924
|
-
function routeOptionalSettingsSection(available, openRequested, openFallback) {
|
|
925
|
-
if (available) {
|
|
926
|
-
openRequested();
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
openFallback();
|
|
930
|
-
}
|
|
931
|
-
let cancelPendingNavigation;
|
|
932
|
-
const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
|
|
933
|
-
const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
|
|
934
|
-
const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
|
|
935
|
-
/** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
|
|
936
|
-
function openSettingsRoot(root) {
|
|
937
|
-
root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
|
|
938
|
-
}
|
|
939
|
-
function openSettingsSection(root, label, onMissing, onSelected) {
|
|
940
|
-
const labels = typeof label === "string" ? [label] : label;
|
|
941
|
-
const trigger = root?.querySelector(SETTINGS_TRIGGER_SELECTOR);
|
|
942
|
-
if (trigger === null || trigger === void 0) {
|
|
943
|
-
onMissing?.();
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
const opening = cancelPendingNavigation !== void 0;
|
|
947
|
-
cancelPendingNavigation?.();
|
|
948
|
-
const request = new CustomEvent(SETTINGS_OPEN_SECTION_EVENT, {
|
|
949
|
-
detail: { labels },
|
|
950
|
-
cancelable: true
|
|
951
|
-
});
|
|
952
|
-
if (!trigger.dispatchEvent(request)) {
|
|
953
|
-
onSelected?.();
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
|
|
957
|
-
if (!opening && document.querySelector(pageSelector) === null) trigger.click();
|
|
958
|
-
let frame;
|
|
959
|
-
let finished = false;
|
|
960
|
-
const observer = new MutationObserver(() => {
|
|
961
|
-
schedule();
|
|
962
|
-
});
|
|
963
|
-
const cleanup = () => {
|
|
964
|
-
if (finished) return;
|
|
965
|
-
finished = true;
|
|
966
|
-
observer.disconnect();
|
|
967
|
-
window.clearTimeout(timeout);
|
|
968
|
-
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
969
|
-
if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
|
|
970
|
-
};
|
|
971
|
-
const select = () => {
|
|
972
|
-
const target = pickSettingsSectionButton([...document.querySelectorAll(`${pageSelector} nav button`)], labels);
|
|
973
|
-
if (target === void 0) return false;
|
|
974
|
-
cleanup();
|
|
975
|
-
target.click();
|
|
976
|
-
onSelected?.();
|
|
977
|
-
return true;
|
|
978
|
-
};
|
|
979
|
-
const schedule = () => {
|
|
980
|
-
if (finished || frame !== void 0) return;
|
|
981
|
-
frame = window.requestAnimationFrame(() => {
|
|
982
|
-
frame = void 0;
|
|
983
|
-
select();
|
|
984
|
-
});
|
|
985
|
-
};
|
|
986
|
-
const timeout = window.setTimeout(() => {
|
|
987
|
-
if (select()) return;
|
|
988
|
-
cleanup();
|
|
989
|
-
console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
|
|
990
|
-
onMissing?.();
|
|
991
|
-
}, SETTINGS_NAVIGATION_TIMEOUT_MS);
|
|
992
|
-
observer.observe(document.body, {
|
|
993
|
-
childList: true,
|
|
994
|
-
subtree: true
|
|
995
|
-
});
|
|
996
|
-
cancelPendingNavigation = cleanup;
|
|
997
|
-
schedule();
|
|
998
|
-
}
|
|
999
|
-
//#endregion
|
|
1000
1161
|
//#region src/client/sidebar-search.ts
|
|
1001
1162
|
/** 按用户可见名称和辅助关键词筛选侧栏搜索结果。 */
|
|
1002
1163
|
function filterSidebarSearchItems(items, query) {
|
|
@@ -1587,9 +1748,20 @@ window.__ModuleLoader__.load({
|
|
|
1587
1748
|
//#endregion
|
|
1588
1749
|
//#region src/client/session-pending.ts
|
|
1589
1750
|
const EMPTY_PENDING_INTERACTIONS = /* @__PURE__ */ new Map();
|
|
1751
|
+
const EMPTY_SESSION_STATUS = /* @__PURE__ */ new Map();
|
|
1590
1752
|
function useEmptySessionPendingInteraction(selector) {
|
|
1591
1753
|
return selector(EMPTY_PENDING_INTERACTIONS);
|
|
1592
1754
|
}
|
|
1755
|
+
function useEmptySessionStatus(selector) {
|
|
1756
|
+
return selector(EMPTY_SESSION_STATUS);
|
|
1757
|
+
}
|
|
1758
|
+
function useHostSessionStatus(useSessionStatus) {
|
|
1759
|
+
return (useSessionStatus ?? useEmptySessionStatus)((state) => state);
|
|
1760
|
+
}
|
|
1761
|
+
/** 旧宿主订阅 pending Store;alpha.2 改走 useSessionStatus。两路都要订阅,避免条件 Hook。 */
|
|
1762
|
+
function useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus) {
|
|
1763
|
+
return mergePendingInteractions((useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state), (useSessionStatus ?? useEmptySessionStatus)((state) => state));
|
|
1764
|
+
}
|
|
1593
1765
|
function visiblePendingKind(kind) {
|
|
1594
1766
|
switch (kind) {
|
|
1595
1767
|
case "approval":
|
|
@@ -2729,6 +2901,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2729
2901
|
function hasConnectWorkspace(value) {
|
|
2730
2902
|
return value !== null && typeof value === "object" && "connectWorkspace" in value && typeof value.connectWorkspace === "function";
|
|
2731
2903
|
}
|
|
2904
|
+
function hasOpenWorkspace(value) {
|
|
2905
|
+
return value !== null && typeof value === "object" && "openWorkspace" in value && typeof value.openWorkspace === "function";
|
|
2906
|
+
}
|
|
2732
2907
|
/** 与 DSH 官方最近工作区策略一致;时间相同时保留 Host 工作区顺序。 */
|
|
2733
2908
|
function recentWorkspaceId(workspaces, sessions) {
|
|
2734
2909
|
let selected;
|
|
@@ -2963,10 +3138,23 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2963
3138
|
lower = after ? rows[index + 1]?.rect.top : edge.rect.top;
|
|
2964
3139
|
} else if (target.matches(".dcu-wb-pin-start,.dcu-wb-pin-end")) {
|
|
2965
3140
|
if (anchor.width <= 0 || anchor.height <= 0) return void 0;
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
3141
|
+
const itemRows = rows.filter((row) => !row.node.matches(".dcu-wb-section-head,.dcu-wb-empty,.dcu-wb-nochat"));
|
|
3142
|
+
if (target.matches(".dcu-wb-pin-end") && itemRows.length > 0) {
|
|
3143
|
+
const last = itemRows[itemRows.length - 1];
|
|
3144
|
+
anchor = last.rect;
|
|
3145
|
+
upper = last.rect.bottom;
|
|
3146
|
+
lower = rows.find((row) => row.rect.top >= last.rect.bottom - .5)?.rect.top;
|
|
3147
|
+
} else if (target.matches(".dcu-wb-pin-start") && itemRows.length > 0) {
|
|
3148
|
+
const first = itemRows[0];
|
|
3149
|
+
anchor = first.rect;
|
|
3150
|
+
lower = first.rect.top;
|
|
3151
|
+
upper = rows.filter((row) => row.rect.bottom <= first.rect.top + .5).at(-1)?.rect.bottom;
|
|
3152
|
+
} else {
|
|
3153
|
+
upper = rows.filter((row) => row.rect.bottom <= anchor.top).at(-1)?.rect.bottom;
|
|
3154
|
+
lower = rows.find((row) => row.rect.top >= anchor.bottom)?.rect.top;
|
|
3155
|
+
if (lower === void 0) lower = anchor.bottom;
|
|
3156
|
+
if (upper === void 0) upper = anchor.top;
|
|
3157
|
+
}
|
|
2970
3158
|
} else return void 0;
|
|
2971
3159
|
const center = upper === void 0 ? lower - 4 : lower === void 0 ? upper + 4 : (upper + lower) / 2;
|
|
2972
3160
|
const box = root.getBoundingClientRect();
|
|
@@ -3145,7 +3333,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3145
3333
|
.dcu-wb-project-head:hover,.dcu-wb-project-head.dcu-wb-menu-open,.dcu-wb-session:hover,.dcu-wb-session.dcu-wb-selected,.dcu-wb-session.dcu-wb-menu-open{background:var(--dcu-sidebar-hover)}.dcu-wb-project.dcu-wb-session-drop>.dcu-wb-project-head{border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.dcu-wb-project.dcu-wb-session-move-drop{border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.dcu-wb-project.dcu-wb-session-move-drop>.dcu-wb-project-head{background:transparent;outline:0}.dcu-wb-project-body>.dcu-wb-session:first-child,.dcu-wb-project-body>.dcu-wb-nochat:first-child{margin-top:4px}.dcu-wb-session+.dcu-wb-session{margin-top:2px}
|
|
3146
3334
|
.dcu-wb-project-head[draggable=true],.dcu-wb-session[draggable=true]{cursor:grab}
|
|
3147
3335
|
.dcu-wb-project-head[draggable=true]:active,.dcu-wb-session[draggable=true]:active{cursor:grabbing}
|
|
3148
|
-
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end,.dcu-wb-pin-start{position:
|
|
3336
|
+
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pinned-list{position:relative}.dcu-wb-pin-end,.dcu-wb-pin-start{position:absolute;left:0;right:0;height:8px;z-index:2;pointer-events:none}.dcu-wb-pin-end.dcu-wb-drop,.dcu-wb-pin-start.dcu-wb-drop{pointer-events:auto}.dcu-wb-pin-start{top:0}.dcu-wb-pin-end{bottom:-8px}.dcu-wb-project.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-pin-start.dcu-wb-drop::before{content:"";position:absolute;z-index:2;left:7px;right:8px;top:-8px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,transparent 1.75px,var(--dsw-alias-state-business-primary) 2px 3.75px,transparent 4px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-pin-start.dcu-wb-drop::before{top:0}.dcu-wb-pinned-list>.dcu-wb-project:first-child.dcu-wb-drop::before{top:-4px}.dcu-wb-project.dcu-wb-drop-after::before,.dcu-wb-session.dcu-wb-drop-after::before{top:auto;bottom:-8px}.dcu-wb-dragging{opacity:.28}.dcu-wb-drag-ghost{position:fixed;top:8px;left:-9999px;z-index:10040;display:flex;align-items:center;gap:8px;max-width:220px;height:30px;padding:0 10px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:var(--dcu-sidebar-hover);box-shadow:0 4px 12px rgba(0,0,0,.24);color:var(--dcu-sidebar-primary);font:14px/20px var(--dcu-font,inherit);white-space:nowrap;pointer-events:none}.dcu-wb-drag-ghost-icon{display:grid;place-items:center;flex:none;width:16px;height:16px;color:var(--dcu-sidebar-icon)}.dcu-wb-drag-ghost-icon svg{display:block;width:16px;height:16px}.dcu-wb-drag-ghost-title{min-width:0;overflow:hidden;text-overflow:ellipsis}
|
|
3149
3337
|
.dcu-wb-folder{display:grid;place-items:center;flex:none;width:16px;height:20px;color:var(--dcu-sidebar-icon)}.dcu-wb-folder.dcu-wb-folder-current{color:var(--dsw-alias-state-business-primary)}.dcu-wb-brand{display:block;width:16px;height:16px}
|
|
3150
3338
|
.dcu-wb-project-title,.dcu-wb-session-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}
|
|
3151
3339
|
.dcu-wb-project-title{flex:1;font-weight:400;color:var(--dcu-sidebar-primary)}
|
|
@@ -3181,7 +3369,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3181
3369
|
.dcu-wb-drop-indicator::before{content:"";position:absolute;left:6px;right:0;top:3px;height:2px;border-radius:999px;background:currentColor}
|
|
3182
3370
|
.dcu-wb-drop-indicator::after{content:"";position:absolute;box-sizing:border-box;left:0;top:0;width:8px;height:8px;border:2px solid currentColor;border-radius:50%}
|
|
3183
3371
|
.dcu-wb-project-body:has(>.dcu-wb-session)::after{content:"";display:block;height:4px;pointer-events:none}
|
|
3184
|
-
.dcu-wb-section-body[data-open=true]:has(.dcu-wb-group-order-drop){overflow:visible}
|
|
3372
|
+
.dcu-wb-section-body[data-open=true]:has(.dcu-wb-group-order-drop),.dcu-wb-section-body[data-open=true]:has(.dcu-wb-pin-end),.dcu-wb-section-body[data-open=true]:has(.dcu-wb-pin-start){overflow:visible}
|
|
3185
3373
|
.dcu-wb-collection-body{padding-left:0}
|
|
3186
3374
|
.dcu-wb-collection-body>.dcu-wb-group-member:first-child{padding-top:4px}
|
|
3187
3375
|
.dcu-wb-collection-body .dcu-wb-project-head{padding-left:8px}
|
|
@@ -3223,10 +3411,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3223
3411
|
function CodexWorkspaceBrowser(props) {
|
|
3224
3412
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HoverShell, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexWorkspaceTree, { ...props }) });
|
|
3225
3413
|
}
|
|
3226
|
-
function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession }) {
|
|
3414
|
+
function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession, panelActive = false }) {
|
|
3227
3415
|
const sessions = useSessions((state) => state);
|
|
3228
3416
|
const now = useSharedNow();
|
|
3229
|
-
const pendingInteractions = (useSessionPendingInteraction
|
|
3417
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
3418
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
3419
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
3230
3420
|
const workspaces = useWorkspaces((state) => state);
|
|
3231
3421
|
const baselinesReady = workspaceBaselinesReady(workspaces, sessions);
|
|
3232
3422
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(storage$1(), WORKSPACE_EXPANSION_STORAGE_KEY));
|
|
@@ -3288,6 +3478,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3288
3478
|
setWorkspaceGroupsState(next);
|
|
3289
3479
|
};
|
|
3290
3480
|
const [unreadSessionIds, setUnreadSessionIds] = (0, react.useState)(() => readSessionIds(storage$1(), SESSION_UNREAD_STORAGE_KEY));
|
|
3481
|
+
const rowUnread = (id) => sessionRowUnread(unreadSessionIds.includes(id), sessionStatus.get(id), selectedId === id);
|
|
3482
|
+
const rowRunning = (id, session) => sessionIsRunning(session ?? sessions.byId[id], sessionStatus.get(id));
|
|
3291
3483
|
const previousSessionRunningRef = (0, react.useRef)();
|
|
3292
3484
|
const [menu, setMenu] = (0, react.useState)();
|
|
3293
3485
|
const [renameTarget, setRenameTarget] = (0, react.useState)();
|
|
@@ -3407,17 +3599,20 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3407
3599
|
}
|
|
3408
3600
|
}, [baselinesReady, workspaces.items]);
|
|
3409
3601
|
(0, react.useEffect)(() => {
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
}, [sessions.current]);
|
|
3602
|
+
if (selectedId !== void 0) setUnreadSessionIds((ids) => ids.filter((id) => id !== selectedId));
|
|
3603
|
+
}, [selectedId]);
|
|
3413
3604
|
(0, react.useEffect)(() => {
|
|
3414
|
-
const next =
|
|
3605
|
+
const next = sessionRunningFlags(sessions.byId, sessionStatus);
|
|
3415
3606
|
const previous = previousSessionRunningRef.current;
|
|
3416
3607
|
previousSessionRunningRef.current = next;
|
|
3417
3608
|
if (previous === void 0) return;
|
|
3418
|
-
const completed = completedBackgroundSessionIds(previous, next,
|
|
3609
|
+
const completed = completedBackgroundSessionIds(previous, next, selectedId);
|
|
3419
3610
|
if (completed.length > 0) setUnreadSessionIds((ids) => [...completed, ...ids.filter((id) => !completed.includes(id))]);
|
|
3420
|
-
}, [
|
|
3611
|
+
}, [
|
|
3612
|
+
selectedId,
|
|
3613
|
+
sessionStatus,
|
|
3614
|
+
sessions.byId
|
|
3615
|
+
]);
|
|
3421
3616
|
const groups = (0, react.useMemo)(() => {
|
|
3422
3617
|
const archived = workspaces.archivedSessionIds;
|
|
3423
3618
|
const visible = (ids) => visibleSessionIds(ids, sessions.byId, archived);
|
|
@@ -3448,7 +3643,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3448
3643
|
(0, react.useEffect)(() => {
|
|
3449
3644
|
const onProject = (event) => {
|
|
3450
3645
|
const detail = event.detail;
|
|
3451
|
-
const current =
|
|
3646
|
+
const current = selectedId;
|
|
3452
3647
|
const workspace = groups.items.find((item) => current !== void 0 && item.visibleIds.includes(String(current)));
|
|
3453
3648
|
if (workspace === void 0 || detail === void 0) return;
|
|
3454
3649
|
if (detail.toggle === true && isShowing("workspace", workspace.workspaceId)) {
|
|
@@ -3461,7 +3656,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3461
3656
|
title: workspace.title,
|
|
3462
3657
|
path: workspace.path,
|
|
3463
3658
|
count: workspace.visibleIds.length,
|
|
3464
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
3659
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3465
3660
|
pinned: pinnedWorkspaceIds.includes(String(workspace.workspaceId)),
|
|
3466
3661
|
left: detail.left,
|
|
3467
3662
|
top: detail.top
|
|
@@ -3469,7 +3664,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3469
3664
|
};
|
|
3470
3665
|
const onMenu = (event) => {
|
|
3471
3666
|
const detail = event.detail;
|
|
3472
|
-
const current =
|
|
3667
|
+
const current = selectedId;
|
|
3473
3668
|
if (current === void 0 || detail === void 0) return;
|
|
3474
3669
|
dismissTip();
|
|
3475
3670
|
if (performance.now() - headerMenuPointerAt.current < 500) {
|
|
@@ -3490,9 +3685,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3490
3685
|
};
|
|
3491
3686
|
}, [
|
|
3492
3687
|
groups.items,
|
|
3493
|
-
sessions.current,
|
|
3494
3688
|
menu,
|
|
3495
3689
|
pinnedWorkspaceIds,
|
|
3690
|
+
selectedId,
|
|
3496
3691
|
unreadSessionIds
|
|
3497
3692
|
]);
|
|
3498
3693
|
const projectPinned = (id) => pinnedWorkspaceIds.includes(String(id));
|
|
@@ -3721,7 +3916,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3721
3916
|
};
|
|
3722
3917
|
const canDelete = canDeleteSession?.() === true;
|
|
3723
3918
|
const sessionMenu = (sessionId, path) => sessionMenuItems(t, {
|
|
3724
|
-
unread:
|
|
3919
|
+
unread: rowUnread(sessionId),
|
|
3725
3920
|
path,
|
|
3726
3921
|
includePath: true,
|
|
3727
3922
|
moveTargets: sessionMoveTargets(groups.items, sessionId).map((target) => ({
|
|
@@ -3776,7 +3971,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3776
3971
|
const renderGroup = (workspace, zone) => {
|
|
3777
3972
|
const expandKey = zone === "pinned" ? `pin:${workspace.workspaceId}` : String(workspace.workspaceId);
|
|
3778
3973
|
const isExpanded = expanded[expandKey] ?? true;
|
|
3779
|
-
const currentSessionId =
|
|
3974
|
+
const currentSessionId = selectedId;
|
|
3780
3975
|
const folder = projectFolderPresentation(isExpanded, workspace.visibleIds.some((id) => id === currentSessionId));
|
|
3781
3976
|
const shownIds = workspace.visibleIds;
|
|
3782
3977
|
const menuOpen = menu?.type === "workspace" && menu.id === workspace.workspaceId;
|
|
@@ -3904,7 +4099,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3904
4099
|
title: workspace.title,
|
|
3905
4100
|
path: workspace.path,
|
|
3906
4101
|
count: workspace.visibleIds.length,
|
|
3907
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
4102
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3908
4103
|
pinned: projectPinned(workspace.workspaceId),
|
|
3909
4104
|
left: box.left,
|
|
3910
4105
|
top: box.top
|
|
@@ -3933,7 +4128,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3933
4128
|
title: workspace.title,
|
|
3934
4129
|
path: workspace.path,
|
|
3935
4130
|
count: workspace.visibleIds.length,
|
|
3936
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
4131
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3937
4132
|
pinned: projectPinned(workspace.workspaceId),
|
|
3938
4133
|
left: box.left,
|
|
3939
4134
|
top: box.top
|
|
@@ -4001,7 +4196,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4001
4196
|
if (session === void 0) return null;
|
|
4002
4197
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, legacyPendingInteraction(session));
|
|
4003
4198
|
const path = session.cwd ?? workspace.path;
|
|
4004
|
-
const selected =
|
|
4199
|
+
const selected = selectedId === id;
|
|
4005
4200
|
const sessionMenuOpen = menu?.type === "session" && menu.id === id;
|
|
4006
4201
|
const sessionMenuAt = sessionMenuOpen && menu.x !== void 0 && menu.y !== void 0 ? {
|
|
4007
4202
|
x: menu.x,
|
|
@@ -4096,8 +4291,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4096
4291
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title: session.displayTitle }),
|
|
4097
4292
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
|
|
4098
4293
|
pendingInteraction,
|
|
4099
|
-
unread:
|
|
4100
|
-
running: session
|
|
4294
|
+
unread: rowUnread(id),
|
|
4295
|
+
running: rowRunning(id, session),
|
|
4101
4296
|
t
|
|
4102
4297
|
}),
|
|
4103
4298
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time: formatCompactTime(session.updatedAt, t, now) }),
|
|
@@ -4556,7 +4751,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4556
4751
|
return mountWorkspaceDropIndicator(treeRef.current);
|
|
4557
4752
|
}, [wide, sorting]);
|
|
4558
4753
|
(0, react.useEffect)(() => {
|
|
4559
|
-
const current =
|
|
4754
|
+
const current = selectedId;
|
|
4560
4755
|
if (current === void 0 || lastRevealedSessionIdRef.current === current) return;
|
|
4561
4756
|
const tree = {
|
|
4562
4757
|
workspaces: workspaces.items.map((item) => ({
|
|
@@ -4577,7 +4772,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4577
4772
|
}, [
|
|
4578
4773
|
pinnedWorkspaceIds,
|
|
4579
4774
|
recentIds,
|
|
4580
|
-
|
|
4775
|
+
selectedId,
|
|
4581
4776
|
workspaceGroups,
|
|
4582
4777
|
workspaces.items
|
|
4583
4778
|
]);
|
|
@@ -4847,15 +5042,15 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4847
5042
|
const session = sessions.byId[id];
|
|
4848
5043
|
if (session === void 0) return null;
|
|
4849
5044
|
const title = session.displayTitle;
|
|
4850
|
-
const unread =
|
|
5045
|
+
const unread = rowUnread(id);
|
|
4851
5046
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, legacyPendingInteraction(session));
|
|
4852
5047
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRow, {
|
|
4853
5048
|
id,
|
|
4854
5049
|
title,
|
|
4855
|
-
selected:
|
|
5050
|
+
selected: selectedId === id,
|
|
4856
5051
|
menuOpen: menu?.type === "session" && menu.id === id,
|
|
4857
5052
|
unread,
|
|
4858
|
-
running: session
|
|
5053
|
+
running: rowRunning(id, session),
|
|
4859
5054
|
pendingInteraction,
|
|
4860
5055
|
time: formatCompactTime(session.updatedAt, t, now),
|
|
4861
5056
|
t,
|
|
@@ -5550,15 +5745,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5550
5745
|
})
|
|
5551
5746
|
});
|
|
5552
5747
|
}
|
|
5553
|
-
function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, menu, setMenu }) {
|
|
5748
|
+
function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, canDeleteSession, panelActive = false, menu, setMenu }) {
|
|
5554
5749
|
const sessions = useSessions((state) => state);
|
|
5555
5750
|
const now = useSharedNow();
|
|
5556
5751
|
const workspaces = useWorkspaces?.((state) => state);
|
|
5557
|
-
const pendingInteractions = (useSessionPendingInteraction
|
|
5752
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
5753
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
5754
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
5558
5755
|
const [groups, setGroups] = (0, react.useState)([]);
|
|
5559
5756
|
const [pollError, setPollError] = (0, react.useState)();
|
|
5560
5757
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), CHANNEL_EXPANSION_STORAGE_KEY));
|
|
5561
|
-
const flags = useSessionFlags(
|
|
5758
|
+
const flags = useSessionFlags(selectedId);
|
|
5562
5759
|
const { showTip, hideTip, dismissTip } = useHoverDispatch();
|
|
5563
5760
|
const { busy, error, setError, run } = useBusyAction(t, () => {
|
|
5564
5761
|
setMenu(void 0);
|
|
@@ -5654,10 +5851,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5654
5851
|
children: group.sessions.map((session) => {
|
|
5655
5852
|
const id = session.sessionId;
|
|
5656
5853
|
const title = session.title;
|
|
5657
|
-
const selected =
|
|
5658
|
-
const
|
|
5854
|
+
const selected = selectedId === id;
|
|
5855
|
+
const status = sessionStatus.get(id);
|
|
5856
|
+
const running = sessionIsRunning({ running: session.running === true || sessions.byId[id]?.running === true }, status);
|
|
5659
5857
|
const updatedAt = session.updatedAt ?? sessions.byId[id]?.updatedAt;
|
|
5660
|
-
const unread = flags.unreadSessionIds.includes(id);
|
|
5858
|
+
const unread = sessionRowUnread(flags.unreadSessionIds.includes(id), status, selected);
|
|
5661
5859
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, sessions.byId[id]?.pendingInteraction);
|
|
5662
5860
|
const moveTargets = moveSession === void 0 || workspaces === void 0 ? void 0 : sessionMoveTargets(workspaces.items, id).map((target) => ({
|
|
5663
5861
|
...target,
|
|
@@ -5826,15 +6024,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5826
6024
|
})]
|
|
5827
6025
|
});
|
|
5828
6026
|
}
|
|
5829
|
-
function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, openTaskSettings, menu, setMenu }) {
|
|
6027
|
+
function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, canDeleteSession, panelActive = false, openTaskSettings, menu, setMenu }) {
|
|
5830
6028
|
const sessions = useSessions((state) => state);
|
|
5831
6029
|
const now = useSharedNow();
|
|
5832
|
-
const pendingInteractions = (useSessionPendingInteraction
|
|
6030
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
6031
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
6032
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
5833
6033
|
const workspaces = useWorkspaces((state) => state);
|
|
5834
6034
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), SCHEDULE_EXPANSION_STORAGE_KEY));
|
|
5835
6035
|
const [groupMenu, setGroupMenu] = (0, react.useState)();
|
|
5836
6036
|
const [archiveGroupTarget, setArchiveGroupTarget] = (0, react.useState)();
|
|
5837
|
-
const flags = useSessionFlags(
|
|
6037
|
+
const flags = useSessionFlags(selectedId);
|
|
5838
6038
|
const { showTip, hideTip, dismissTip } = useHoverDispatch();
|
|
5839
6039
|
const { busy, error, setError, run } = useBusyAction(t, () => {
|
|
5840
6040
|
setMenu(void 0);
|
|
@@ -5963,7 +6163,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5963
6163
|
children: group.sessions.map((session) => {
|
|
5964
6164
|
const id = session.id;
|
|
5965
6165
|
const title = session.title;
|
|
5966
|
-
const
|
|
6166
|
+
const selected = selectedId === id;
|
|
6167
|
+
const status = sessionStatus.get(id);
|
|
6168
|
+
const unread = sessionRowUnread(flags.unreadSessionIds.includes(id), status, selected);
|
|
5967
6169
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, sessions.byId[id]?.pendingInteraction);
|
|
5968
6170
|
const moveTargets = moveSession === void 0 ? void 0 : sessionMoveTargets(workspaces.items ?? [], id).map((target) => ({
|
|
5969
6171
|
...target,
|
|
@@ -5973,10 +6175,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5973
6175
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRow, {
|
|
5974
6176
|
id,
|
|
5975
6177
|
title,
|
|
5976
|
-
selected
|
|
6178
|
+
selected,
|
|
5977
6179
|
menuOpen: menu?.id === id,
|
|
5978
6180
|
unread,
|
|
5979
|
-
running:
|
|
6181
|
+
running: sessionIsRunning(sessions.byId[id], status),
|
|
5980
6182
|
pendingInteraction,
|
|
5981
6183
|
time: session.updatedAt === void 0 ? void 0 : formatCompactTime(session.updatedAt, t, now),
|
|
5982
6184
|
t,
|
|
@@ -6740,7 +6942,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6740
6942
|
});
|
|
6741
6943
|
}
|
|
6742
6944
|
/** 搜索状态与大侧栏隔离:输入、悬停和开关弹窗都不能让工作区树跟着重渲染。 */
|
|
6743
|
-
const SidebarSearch = (0, react.forwardRef)(function SidebarSearch({ imSettingsAvailable, openSession, startSession, t, useSessions, useWorkspaces, settingsSeat }, ref) {
|
|
6945
|
+
const SidebarSearch = (0, react.forwardRef)(function SidebarSearch({ imSettingsAvailable, openPlugins, openSession, startSession, t, useSessions, useWorkspaces, settingsSeat }, ref) {
|
|
6744
6946
|
const [open, setOpen] = (0, react.useState)(false);
|
|
6745
6947
|
const [query, setQuery] = (0, react.useState)("");
|
|
6746
6948
|
const [activeIndex, setActiveIndex] = (0, react.useState)(0);
|
|
@@ -6758,9 +6960,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6758
6960
|
const selectSection = (0, react.useCallback)((label) => {
|
|
6759
6961
|
openSettingsSection(settingsSeat.current, label);
|
|
6760
6962
|
}, [settingsSeat]);
|
|
6761
|
-
const selectPluginSection = (0, react.useCallback)(() => {
|
|
6762
|
-
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.plugins")]);
|
|
6763
|
-
}, [settingsSeat, t]);
|
|
6764
6963
|
const selectExternalSection = (0, react.useCallback)((label) => {
|
|
6765
6964
|
openSettingsSection(settingsSeat.current, label, () => {
|
|
6766
6965
|
selectSection(t("about.nav"));
|
|
@@ -6837,7 +7036,17 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6837
7036
|
keywords: t("search.settings"),
|
|
6838
7037
|
run: () => {
|
|
6839
7038
|
close();
|
|
6840
|
-
|
|
7039
|
+
openPlugins();
|
|
7040
|
+
}
|
|
7041
|
+
},
|
|
7042
|
+
{
|
|
7043
|
+
id: "settings:plugin-config",
|
|
7044
|
+
group: "settings",
|
|
7045
|
+
label: t("settings.pluginConfig"),
|
|
7046
|
+
keywords: t("search.settings"),
|
|
7047
|
+
run: () => {
|
|
7048
|
+
close();
|
|
7049
|
+
openSettingsSection(settingsSeat.current, t("settings.pluginConfig"));
|
|
6841
7050
|
}
|
|
6842
7051
|
},
|
|
6843
7052
|
{
|
|
@@ -6898,10 +7107,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6898
7107
|
}, [
|
|
6899
7108
|
close,
|
|
6900
7109
|
openImSettings,
|
|
7110
|
+
openPlugins,
|
|
6901
7111
|
openSession,
|
|
6902
7112
|
openSettings,
|
|
6903
7113
|
selectExternalSection,
|
|
6904
|
-
selectPluginSection,
|
|
6905
7114
|
selectSection,
|
|
6906
7115
|
sessions.byId,
|
|
6907
7116
|
sessions.ids,
|
|
@@ -7012,10 +7221,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7012
7221
|
});
|
|
7013
7222
|
});
|
|
7014
7223
|
/** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
|
|
7015
|
-
function CodexSidebar({ globalPanels, footerActions, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
7224
|
+
function CodexSidebar({ globalPanels, footerActions, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
7016
7225
|
const panels = (0, react.useSyncExternalStore)(globalPanels?.subscribe ?? subscribeEmptyCompanionTabs, globalPanels?.getSnapshot ?? getEmptyPanels, globalPanels?.getSnapshot ?? getEmptyPanels);
|
|
7017
7226
|
const visibleFooterActions = (0, react.useSyncExternalStore)(footerActions?.subscribe ?? subscribeEmptyCompanionTabs, footerActions?.getSnapshot ?? getEmptyFooterActions, footerActions?.getSnapshot ?? getEmptyFooterActions);
|
|
7018
7227
|
const activePanelId = usePanelInfo((info) => info.activePanelId);
|
|
7228
|
+
const panelActive = activePanelId !== null && activePanelId !== "";
|
|
7019
7229
|
const panelButtons = (wide) => selectPanel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalPanelButtons, {
|
|
7020
7230
|
panels,
|
|
7021
7231
|
activeId: activePanelId,
|
|
@@ -7046,8 +7256,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7046
7256
|
const selectSection = (label) => {
|
|
7047
7257
|
openSettingsSection(settingsSeat.current, label);
|
|
7048
7258
|
};
|
|
7049
|
-
const
|
|
7050
|
-
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.
|
|
7259
|
+
const openPlugins = () => {
|
|
7260
|
+
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.builtinPlugins")]);
|
|
7051
7261
|
};
|
|
7052
7262
|
const selectExternalSection = (label) => {
|
|
7053
7263
|
openSettingsSection(settingsSeat.current, label, () => {
|
|
@@ -7166,10 +7376,17 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7166
7376
|
window.clearTimeout(timer);
|
|
7167
7377
|
};
|
|
7168
7378
|
}, [compact, visualCompact]);
|
|
7169
|
-
const workspaceSlot = (0, react.useMemo)(() =>
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7379
|
+
const workspaceSlot = (0, react.useMemo)(() => {
|
|
7380
|
+
return renderSlot("sidebar.workspaces", {
|
|
7381
|
+
wide: true,
|
|
7382
|
+
expandSidebar,
|
|
7383
|
+
panelActive
|
|
7384
|
+
});
|
|
7385
|
+
}, [
|
|
7386
|
+
expandSidebar,
|
|
7387
|
+
panelActive,
|
|
7388
|
+
renderSlot
|
|
7389
|
+
]);
|
|
7173
7390
|
const scheduleOverviewSlot = (0, react.useMemo)(() => renderSlot("sidebar.schedule", {
|
|
7174
7391
|
wide: true,
|
|
7175
7392
|
expandSidebar,
|
|
@@ -7305,7 +7522,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7305
7522
|
type: "button",
|
|
7306
7523
|
tabIndex: extensionsOpen ? 0 : -1,
|
|
7307
7524
|
onClick: () => {
|
|
7308
|
-
|
|
7525
|
+
openPlugins();
|
|
7309
7526
|
},
|
|
7310
7527
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuIcon, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutline16, { size: 16 }) }), t("sidebar.plugins")]
|
|
7311
7528
|
}),
|
|
@@ -7381,7 +7598,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7381
7598
|
renameSession,
|
|
7382
7599
|
useSessions,
|
|
7383
7600
|
useSessionPendingInteraction,
|
|
7601
|
+
useSessionStatus,
|
|
7384
7602
|
useWorkspaces,
|
|
7603
|
+
panelActive,
|
|
7385
7604
|
t
|
|
7386
7605
|
})
|
|
7387
7606
|
}) : imTab === "schedule" && showSchedule ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -7396,7 +7615,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7396
7615
|
renameSession,
|
|
7397
7616
|
useSessions,
|
|
7398
7617
|
useSessionPendingInteraction,
|
|
7618
|
+
useSessionStatus,
|
|
7399
7619
|
useWorkspaces,
|
|
7620
|
+
panelActive,
|
|
7400
7621
|
t,
|
|
7401
7622
|
overviewContent: scheduleOverviewSlot,
|
|
7402
7623
|
openTaskSettings: (request) => {
|
|
@@ -7469,7 +7690,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7469
7690
|
className: "dcu-icon",
|
|
7470
7691
|
"aria-label": t("sidebar.plugins"),
|
|
7471
7692
|
onClick: () => {
|
|
7472
|
-
|
|
7693
|
+
openPlugins();
|
|
7473
7694
|
},
|
|
7474
7695
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutline16, { size: 16 })
|
|
7475
7696
|
}),
|
|
@@ -7515,6 +7736,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7515
7736
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSearch, {
|
|
7516
7737
|
ref: search,
|
|
7517
7738
|
imSettingsAvailable: showChannels,
|
|
7739
|
+
openPlugins,
|
|
7518
7740
|
settingsSeat,
|
|
7519
7741
|
openSession,
|
|
7520
7742
|
startSession,
|
|
@@ -8054,7 +8276,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8054
8276
|
});
|
|
8055
8277
|
}
|
|
8056
8278
|
function NativeConnectorList({ sessionStore, t }) {
|
|
8057
|
-
const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => sessionStore.getSnapshot()
|
|
8279
|
+
const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => currentSessionId(sessionStore.getSnapshot()));
|
|
8058
8280
|
const [connectors, setConnectors] = (0, react.useState)([]);
|
|
8059
8281
|
const [state, setState] = (0, react.useState)("loading");
|
|
8060
8282
|
const [failure, setFailure] = (0, react.useState)();
|
|
@@ -8209,6 +8431,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8209
8431
|
"settings.search": "搜索设置…",
|
|
8210
8432
|
"settings.personal": "个人",
|
|
8211
8433
|
"settings.integrations": "集成",
|
|
8434
|
+
"settings.pluginConfig": "插件配置",
|
|
8212
8435
|
"settings.records": "记录与应用",
|
|
8213
8436
|
"settings.general": "常规",
|
|
8214
8437
|
"settings.permissions": "权限",
|
|
@@ -8231,6 +8454,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8231
8454
|
"sidebar.skills": "技能",
|
|
8232
8455
|
"sidebar.plugins": "插件",
|
|
8233
8456
|
"sidebar.marketplace": "插件市场",
|
|
8457
|
+
"sidebar.builtinPlugins": "内置插件",
|
|
8234
8458
|
"sidebar.connectors": "连接器",
|
|
8235
8459
|
"sidebar.schedule": "定时任务",
|
|
8236
8460
|
"sidebar.assistant": "IM助理",
|
|
@@ -8497,6 +8721,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8497
8721
|
"settings.search": "Search settings…",
|
|
8498
8722
|
"settings.personal": "Personal",
|
|
8499
8723
|
"settings.integrations": "Integrations",
|
|
8724
|
+
"settings.pluginConfig": "Plugin configuration",
|
|
8500
8725
|
"settings.records": "Records and app",
|
|
8501
8726
|
"settings.general": "General",
|
|
8502
8727
|
"settings.permissions": "Permissions",
|
|
@@ -8519,6 +8744,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8519
8744
|
"sidebar.skills": "Skills",
|
|
8520
8745
|
"sidebar.plugins": "Plugins",
|
|
8521
8746
|
"sidebar.marketplace": "Plugin Market",
|
|
8747
|
+
"sidebar.builtinPlugins": "Built-in plugins",
|
|
8522
8748
|
"sidebar.connectors": "Connectors",
|
|
8523
8749
|
"sidebar.schedule": "Scheduled tasks",
|
|
8524
8750
|
"sidebar.assistant": "IM Assistant",
|
|
@@ -8811,6 +9037,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8811
9037
|
};
|
|
8812
9038
|
const LABEL_ALIASES = [
|
|
8813
9039
|
[["插件市场", "Plugin Market"], "plugins"],
|
|
9040
|
+
[["内置插件", "Built-in plugins"], "plugins"],
|
|
9041
|
+
[["插件配置", "Plugin configuration"], "plugins"],
|
|
8814
9042
|
[["专家", "Experts"], "experts"],
|
|
8815
9043
|
[["技能", "Skills"], "skills"],
|
|
8816
9044
|
[["插件", "Plugins"], "plugins"],
|
|
@@ -9112,6 +9340,160 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
9112
9340
|
}, "michengai-codex-ui: usage navigation");
|
|
9113
9341
|
}
|
|
9114
9342
|
//#endregion
|
|
9343
|
+
//#region src/client/PluginConfigSection.tsx
|
|
9344
|
+
function bindPluginConfigLocale(bind) {
|
|
9345
|
+
const cache = /* @__PURE__ */ new Map();
|
|
9346
|
+
return (ns) => {
|
|
9347
|
+
const existing = cache.get(ns);
|
|
9348
|
+
if (existing !== void 0) return existing;
|
|
9349
|
+
const translate = bind(ns);
|
|
9350
|
+
cache.set(ns, translate);
|
|
9351
|
+
return translate;
|
|
9352
|
+
};
|
|
9353
|
+
}
|
|
9354
|
+
const FORWARDED_CONFIG_SLOTS = /* @__PURE__ */ new Set([
|
|
9355
|
+
"plugins.item",
|
|
9356
|
+
"plugins.bundle.config",
|
|
9357
|
+
"plugins.row.config"
|
|
9358
|
+
]);
|
|
9359
|
+
var SlotEntryBoundary = class extends react.Component {
|
|
9360
|
+
state = { failed: false };
|
|
9361
|
+
static getDerivedStateFromError() {
|
|
9362
|
+
return { failed: true };
|
|
9363
|
+
}
|
|
9364
|
+
render() {
|
|
9365
|
+
return this.state.failed ? this.props.fallback : this.props.children;
|
|
9366
|
+
}
|
|
9367
|
+
};
|
|
9368
|
+
function isSnapshotSource(value) {
|
|
9369
|
+
return typeof value === "object" && value !== null && typeof value.getSnapshot === "function" && typeof value.subscribe === "function";
|
|
9370
|
+
}
|
|
9371
|
+
function hookPropName(name) {
|
|
9372
|
+
return `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
|
|
9373
|
+
}
|
|
9374
|
+
function bindSnapshotSelector(source) {
|
|
9375
|
+
const subscribe = (listener) => source.subscribe(listener);
|
|
9376
|
+
const getSnapshot = () => source.getSnapshot();
|
|
9377
|
+
return function useSelected(selector = (value) => value) {
|
|
9378
|
+
return (0, react.useSyncExternalStore)(subscribe, () => selector(getSnapshot()), () => selector(getSnapshot()));
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
function bindHookSources(hooks, bound) {
|
|
9382
|
+
for (const [name, source] of Object.entries(hooks ?? {})) if (isSnapshotSource(source)) bound[hookPropName(name)] = bindSnapshotSelector(source);
|
|
9383
|
+
}
|
|
9384
|
+
function bindInjectFace(inject) {
|
|
9385
|
+
try {
|
|
9386
|
+
if (typeof inject !== "function") return {};
|
|
9387
|
+
const face = inject();
|
|
9388
|
+
if (typeof face !== "object" || face === null) return {};
|
|
9389
|
+
const { hooks, keyedHooks, ...rest } = face;
|
|
9390
|
+
const bound = { ...rest };
|
|
9391
|
+
if (keyedHooks !== void 0) bound.keyedHooks = keyedHooks;
|
|
9392
|
+
bindHookSources(hooks, bound);
|
|
9393
|
+
bindHookSources(keyedHooks, bound);
|
|
9394
|
+
return bound;
|
|
9395
|
+
} catch {
|
|
9396
|
+
return {};
|
|
9397
|
+
}
|
|
9398
|
+
}
|
|
9399
|
+
function DelegatedOfficialSlot({ slots, name, owner, opts, bindLocale }) {
|
|
9400
|
+
(0, react.useSyncExternalStore)((listener) => slots.subscribe(name, listener), () => slots.getVersion(name));
|
|
9401
|
+
const nodes = slots.entriesOfSlot(name).filter((entry) => opts?.entryKey !== void 0 ? entry.options.key === opts.entryKey : opts?.only === void 0 || entry.options.id === opts.only).flatMap((entry, index) => {
|
|
9402
|
+
if (typeof entry.component !== "function") return [];
|
|
9403
|
+
const t = entry.locale !== void 0 && bindLocale !== void 0 ? bindLocale(entry.locale) : void 0;
|
|
9404
|
+
return [(0, react.createElement)(SlotEntryBoundary, {
|
|
9405
|
+
key: entry.options.key ?? entry.options.id ?? String(index),
|
|
9406
|
+
fallback: opts?.fallback ?? null,
|
|
9407
|
+
children: (0, react.createElement)(entry.component, {
|
|
9408
|
+
...owner,
|
|
9409
|
+
...bindInjectFace(entry.inject),
|
|
9410
|
+
...t === void 0 ? {} : { t }
|
|
9411
|
+
})
|
|
9412
|
+
})];
|
|
9413
|
+
});
|
|
9414
|
+
return nodes.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9415
|
+
"data-slot": name,
|
|
9416
|
+
style: { display: "contents" },
|
|
9417
|
+
children: nodes
|
|
9418
|
+
}) : opts?.fallback ?? null;
|
|
9419
|
+
}
|
|
9420
|
+
function wrapRenderSlot(settingsRenderSlot, slots, bindLocale) {
|
|
9421
|
+
return (name, owner = {}, opts) => {
|
|
9422
|
+
if (slots !== void 0 && FORWARDED_CONFIG_SLOTS.has(name)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DelegatedOfficialSlot, {
|
|
9423
|
+
slots,
|
|
9424
|
+
name,
|
|
9425
|
+
owner,
|
|
9426
|
+
opts,
|
|
9427
|
+
bindLocale
|
|
9428
|
+
});
|
|
9429
|
+
return typeof settingsRenderSlot === "function" ? settingsRenderSlot(name, owner, opts) : null;
|
|
9430
|
+
};
|
|
9431
|
+
}
|
|
9432
|
+
/** 设置里的官方插件管理页副本。官方卡片要 inject 和文案;单卡崩溃不得拆掉整页。 */
|
|
9433
|
+
function PluginConfigSection({ Official, officialLabel, slots, bindLocale, ...official }) {
|
|
9434
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
9435
|
+
className: "dcu-plugin-config",
|
|
9436
|
+
"aria-label": officialLabel,
|
|
9437
|
+
children: (0, react.createElement)(Official, {
|
|
9438
|
+
...official,
|
|
9439
|
+
renderSlot: wrapRenderSlot(official.renderSlot, slots, bindLocale)
|
|
9440
|
+
})
|
|
9441
|
+
});
|
|
9442
|
+
}
|
|
9443
|
+
function createPluginConfigSection(Official, officialLabel, slots, bindLocale) {
|
|
9444
|
+
return function PluginConfigSectionBound(props) {
|
|
9445
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginConfigSection, {
|
|
9446
|
+
Official,
|
|
9447
|
+
officialLabel: officialLabel(),
|
|
9448
|
+
slots,
|
|
9449
|
+
bindLocale,
|
|
9450
|
+
...props
|
|
9451
|
+
});
|
|
9452
|
+
};
|
|
9453
|
+
}
|
|
9454
|
+
//#endregion
|
|
9455
|
+
//#region src/client/plugin-config.ts
|
|
9456
|
+
const PLUGIN_CONFIG_SECTION_ID = "plugin-config";
|
|
9457
|
+
const OFFICIAL_PLUGIN_MANAGER_NS = "pluginManager";
|
|
9458
|
+
function officialPluginsPage(entry) {
|
|
9459
|
+
if (entry === void 0 || entry.options.key !== "plugins") return void 0;
|
|
9460
|
+
if (typeof entry.component !== "function" || typeof entry.inject !== "function" || entry.locale !== OFFICIAL_PLUGIN_MANAGER_NS) return void 0;
|
|
9461
|
+
return entry.component;
|
|
9462
|
+
}
|
|
9463
|
+
function registerPluginConfigSection(ctx) {
|
|
9464
|
+
const t = ctx.locale.bind(NS);
|
|
9465
|
+
ctx.slots.inject("settings.section", () => {
|
|
9466
|
+
let current;
|
|
9467
|
+
let remove;
|
|
9468
|
+
const refresh = () => {
|
|
9469
|
+
const entry = ctx.slots.entriesOfSlot("main").find((item) => item.options.key === OFFICIAL_PLUGINS_PANEL_ID);
|
|
9470
|
+
if (entry === current) return;
|
|
9471
|
+
remove?.();
|
|
9472
|
+
remove = void 0;
|
|
9473
|
+
current = entry;
|
|
9474
|
+
const Official = officialPluginsPage(entry);
|
|
9475
|
+
if (Official === void 0 || entry?.inject === void 0 || entry.locale !== OFFICIAL_PLUGIN_MANAGER_NS) return;
|
|
9476
|
+
remove = ctx.slots.register({
|
|
9477
|
+
name: "settings.section",
|
|
9478
|
+
id: PLUGIN_CONFIG_SECTION_ID,
|
|
9479
|
+
order: 16,
|
|
9480
|
+
label: () => t("settings.pluginConfig"),
|
|
9481
|
+
locale: entry.locale,
|
|
9482
|
+
inject: entry.inject
|
|
9483
|
+
}, createPluginConfigSection(Official, () => t("settings.pluginConfig"), ctx.slots, bindPluginConfigLocale((ns) => {
|
|
9484
|
+
const translate = ctx.locale.bind(ns);
|
|
9485
|
+
return (key, params) => translate(key, params);
|
|
9486
|
+
})));
|
|
9487
|
+
};
|
|
9488
|
+
const unsubscribe = ctx.slots.subscribe("main", refresh);
|
|
9489
|
+
refresh();
|
|
9490
|
+
return () => {
|
|
9491
|
+
unsubscribe();
|
|
9492
|
+
remove?.();
|
|
9493
|
+
};
|
|
9494
|
+
});
|
|
9495
|
+
}
|
|
9496
|
+
//#endregion
|
|
9115
9497
|
//#region src/client/settings-page-model.ts
|
|
9116
9498
|
function settingsGroup(id) {
|
|
9117
9499
|
if (/archive|about|^usage-statistics$/.test(id)) return "records";
|
|
@@ -9213,6 +9595,10 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9213
9595
|
.dcu-settings-inner:has(.dcu-usage-section){height:100%;display:flex;flex-direction:column;padding-bottom:0}
|
|
9214
9596
|
.dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
|
|
9215
9597
|
.dcu-settings-inner:has(.dcu-usage-section)>[data-slot="settings.section"]{display:flex;flex:1;min-height:0;flex-direction:column}
|
|
9598
|
+
.dcu-plugin-config [data-plugin-panel]{height:auto;padding:0;overflow:visible;align-items:stretch;gap:24px}
|
|
9599
|
+
.dcu-plugin-config [data-plugin-panel]>*{max-width:none}
|
|
9600
|
+
.dcu-plugin-config [data-plugin-panel]>header :is(h1,p){display:none}
|
|
9601
|
+
.dcu-plugin-config [data-plugin-panel]>header{justify-content:flex-end}
|
|
9216
9602
|
.dcu-usage-section{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px}
|
|
9217
9603
|
.dcu-usage-section h1{font-size:24px;font-weight:500;margin:0}
|
|
9218
9604
|
.dcu-usage-section p{color:var(--sp-muted)}
|
|
@@ -9273,7 +9659,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9273
9659
|
const rows = (0, react.useSyncExternalStore)(sections.subscribe, sections.getSnapshot);
|
|
9274
9660
|
const steps = (0, react.useSyncExternalStore)(onboarding.subscribe, onboarding.getSnapshot);
|
|
9275
9661
|
const connection = (0, react.useSyncExternalStore)(connectionState.subscribe, connectionState.getSnapshot);
|
|
9276
|
-
const onboardingActive = useSessions((state) =>
|
|
9662
|
+
const onboardingActive = useSessions((state) => isBlankOnboardingSession(state));
|
|
9277
9663
|
const [completed, setCompleted] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
9278
9664
|
const [open, setOpen] = (0, react.useState)(false);
|
|
9279
9665
|
const [activeId, setActiveId] = (0, react.useState)("general");
|
|
@@ -9428,6 +9814,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9428
9814
|
if (main.current !== null) main.current.scrollTop = 0;
|
|
9429
9815
|
}, [active?.id]);
|
|
9430
9816
|
const visible = filterSettingsRows(rows, query);
|
|
9817
|
+
const ownTitle = active?.id === "general" ? t("settings.general") : active?.id === "plugin-config" ? t("settings.pluginConfig") : void 0;
|
|
9431
9818
|
const connectionIndicator = connection === "disconnected" ? "disconnected" : connection === "connecting" ? "connecting" : recovered ? "recovered" : void 0;
|
|
9432
9819
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9433
9820
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: settingsPageStyles }),
|
|
@@ -9537,8 +9924,8 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9537
9924
|
"data-settings-section": active?.id,
|
|
9538
9925
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
9539
9926
|
className: "dcu-settings-heading",
|
|
9540
|
-
"data-own-title":
|
|
9541
|
-
children: [
|
|
9927
|
+
"data-own-title": ownTitle !== void 0,
|
|
9928
|
+
children: [ownTitle !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: ownTitle }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9542
9929
|
className: "dcu-settings-actions",
|
|
9543
9930
|
children: renderSlot("settings.action", {})
|
|
9544
9931
|
})]
|
|
@@ -10470,7 +10857,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10470
10857
|
}
|
|
10471
10858
|
/** Archive Manager replaces the official ui-workspace row with this optional service. */
|
|
10472
10859
|
function startWorkspaceSession(ctx, workspaceId) {
|
|
10473
|
-
const uiWorkspace = ctx
|
|
10860
|
+
const uiWorkspace = probeService(ctx, "uiWorkspace");
|
|
10474
10861
|
if (hasStartSession(uiWorkspace)) {
|
|
10475
10862
|
uiWorkspace.startSession(workspaceId);
|
|
10476
10863
|
return;
|
|
@@ -10483,6 +10870,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10483
10870
|
}
|
|
10484
10871
|
/** 替换 DSH 的官方 sidebar 插槽,不修改 DSH 源码或会话数据。 */
|
|
10485
10872
|
function apply(ctx) {
|
|
10873
|
+
Object.assign(globalThis, { __dcuCurrentSessionId: currentSessionId });
|
|
10486
10874
|
const widthStorage = browserStorage();
|
|
10487
10875
|
if (widthStorage) initializeComposerWidth(widthStorage);
|
|
10488
10876
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
@@ -10494,6 +10882,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10494
10882
|
registerInputHistory(ctx);
|
|
10495
10883
|
registerSettingsPage(ctx);
|
|
10496
10884
|
registerUsageStatistics(ctx);
|
|
10885
|
+
registerPluginConfigSection(ctx);
|
|
10497
10886
|
const connection = ctx.get("connection");
|
|
10498
10887
|
const openPath = (path) => openPathInHost(connection, path);
|
|
10499
10888
|
ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
|
|
@@ -10505,7 +10894,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10505
10894
|
ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
|
|
10506
10895
|
ctx.effect(() => observeOfficialTurnNavigators(), "michengai-codex-ui: official turn navigator");
|
|
10507
10896
|
const newConversationDraft = createDraftPresenceSource(ctx.sessions.list, () => {
|
|
10508
|
-
const id = ctx.sessions.list.getSnapshot()
|
|
10897
|
+
const id = currentSessionId(ctx.sessions.list.getSnapshot());
|
|
10509
10898
|
const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
|
|
10510
10899
|
return binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx).state;
|
|
10511
10900
|
});
|
|
@@ -10545,12 +10934,12 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10545
10934
|
inject: () => ({
|
|
10546
10935
|
newConversationDraft,
|
|
10547
10936
|
prefillNewConversation: (text) => {
|
|
10548
|
-
const id = ctx.sessions.list.getSnapshot()
|
|
10937
|
+
const id = currentSessionId(ctx.sessions.list.getSnapshot());
|
|
10549
10938
|
const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
|
|
10550
10939
|
return prefillNewConversation(binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx), text);
|
|
10551
10940
|
},
|
|
10552
10941
|
openSession: (sessionId) => {
|
|
10553
|
-
openConversation(ctx
|
|
10942
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10554
10943
|
},
|
|
10555
10944
|
startSession: (workspaceId) => {
|
|
10556
10945
|
startWorkspaceSession(ctx, workspaceId);
|
|
@@ -10580,20 +10969,16 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10580
10969
|
locale: NS
|
|
10581
10970
|
}, TurnNavigator));
|
|
10582
10971
|
const forkSession = async (sessionId) => {
|
|
10583
|
-
await runHostAction("fork",
|
|
10584
|
-
const childId = await ctx.sessions.fork({
|
|
10585
|
-
sessionId,
|
|
10586
|
-
increaseTitle: true
|
|
10587
|
-
});
|
|
10588
|
-
openConversation(ctx.sessions, ctx.layout, childId);
|
|
10589
|
-
});
|
|
10972
|
+
await runHostAction("fork", () => forkHostSession(ctx, sessionId));
|
|
10590
10973
|
};
|
|
10591
10974
|
const renameSession = async (sessionId, title) => {
|
|
10592
|
-
const session = ctx.sessions.binding(sessionId)?.session;
|
|
10593
|
-
if (session === void 0) throw new UserFacingError(t("sessions.unknown"));
|
|
10594
10975
|
await runHostAction("rename", async () => {
|
|
10595
|
-
|
|
10596
|
-
|
|
10976
|
+
try {
|
|
10977
|
+
await renameHostSession(ctx, sessionId, title);
|
|
10978
|
+
} catch (reason) {
|
|
10979
|
+
if (reason instanceof UnknownSessionError) throw new UserFacingError(t("sessions.unknown"));
|
|
10980
|
+
throw reason;
|
|
10981
|
+
}
|
|
10597
10982
|
});
|
|
10598
10983
|
};
|
|
10599
10984
|
const deleteSession = async (sessionId) => {
|
|
@@ -10604,7 +10989,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10604
10989
|
if (!result.ok) throw result.error === void 0 ? new UserFacingError(t("sessions.deleteUnavailable")) : result.error;
|
|
10605
10990
|
});
|
|
10606
10991
|
};
|
|
10607
|
-
const archiveSession = (sessionId) => runHostAction("archive", () => ctx
|
|
10992
|
+
const archiveSession = (sessionId) => runHostAction("archive", () => archiveHostSession(ctx, sessionId));
|
|
10608
10993
|
const moveSession = async (sessionId, targetWorkspaceId) => {
|
|
10609
10994
|
try {
|
|
10610
10995
|
await requestSessionMove(sessionId, targetWorkspaceId);
|
|
@@ -10625,22 +11010,36 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10625
11010
|
if (prompt === "") throw new UserFacingError(t("connectors.promptRequired"));
|
|
10626
11011
|
const workspaces = ctx.workspaces.list.getSnapshot();
|
|
10627
11012
|
const sessionSnapshot = ctx.sessions.list.getSnapshot();
|
|
10628
|
-
const
|
|
10629
|
-
const currentWorkspaceId =
|
|
11013
|
+
const selectedSessionId = currentSessionId(sessionSnapshot);
|
|
11014
|
+
const currentWorkspaceId = selectedSessionId === void 0 ? void 0 : workspaces.items.find((workspace) => workspace.sessionIds.includes(selectedSessionId))?.workspaceId;
|
|
10630
11015
|
const baselinesReady = workspaceBaselinesReady(workspaces, sessionSnapshot);
|
|
10631
11016
|
const targetWorkspaceId = currentWorkspaceId ?? (baselinesReady ? recentWorkspaceId(workspaces.items, sessionSnapshot.byId) : void 0);
|
|
10632
11017
|
if (targetWorkspaceId === void 0 && !baselinesReady) throw new UserFacingError(t("connectors.workspacesLoading"));
|
|
10633
11018
|
if (targetWorkspaceId === void 0) throw new UserFacingError(t("connectors.workspaceRequired"));
|
|
10634
|
-
const uiWorkspace = ctx
|
|
10635
|
-
const workspaceNavigation = hasConnectWorkspace(uiWorkspace) ? uiWorkspace : hasConnectWorkspace(ctx.workspaces) ? ctx.workspaces : void 0;
|
|
10636
|
-
if (workspaceNavigation === void 0) throw new UserFacingError(t("connectors.workspaceUnavailable"));
|
|
10637
|
-
const sessionId = await workspaceNavigation.connectWorkspace(targetWorkspaceId);
|
|
11019
|
+
const uiWorkspace = probeService(ctx, "uiWorkspace");
|
|
10638
11020
|
const conversation = ctx.get("conversation");
|
|
10639
11021
|
if (conversation === void 0) throw new UserFacingError(t("connectors.conversationUnavailable"));
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
11022
|
+
try {
|
|
11023
|
+
if (hasOpenWorkspace(uiWorkspace)) {
|
|
11024
|
+
await Promise.resolve(uiWorkspace.openWorkspace(targetWorkspaceId, (id) => {
|
|
11025
|
+
const binding = ctx.sessions.binding(id);
|
|
11026
|
+
if (binding?.ctx === void 0) throw new UnknownSessionError();
|
|
11027
|
+
conversation.input.for(binding.ctx).setDraft(prompt);
|
|
11028
|
+
}));
|
|
11029
|
+
selectGlobalPanel(ctx.layout, null);
|
|
11030
|
+
return;
|
|
11031
|
+
}
|
|
11032
|
+
const workspaceNavigation = hasConnectWorkspace(uiWorkspace) ? uiWorkspace : hasConnectWorkspace(ctx.workspaces) ? ctx.workspaces : void 0;
|
|
11033
|
+
if (workspaceNavigation === void 0) throw new UserFacingError(t("connectors.workspaceUnavailable"));
|
|
11034
|
+
const sessionId = await workspaceNavigation.connectWorkspace(targetWorkspaceId);
|
|
11035
|
+
await openConversationWithDraft(ctx, ctx.layout, ctx.sessions, sessionId, (binding) => {
|
|
11036
|
+
if (binding.ctx === void 0) throw new UnknownSessionError();
|
|
11037
|
+
conversation.input.for(binding.ctx).setDraft(prompt);
|
|
11038
|
+
});
|
|
11039
|
+
} catch (reason) {
|
|
11040
|
+
if (reason instanceof UnknownSessionError) throw new UserFacingError(t("connectors.sessionPending"));
|
|
11041
|
+
throw reason;
|
|
11042
|
+
}
|
|
10644
11043
|
};
|
|
10645
11044
|
ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
|
|
10646
11045
|
name: "sidebar.workspaces",
|
|
@@ -10655,7 +11054,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10655
11054
|
moveSession,
|
|
10656
11055
|
openPath,
|
|
10657
11056
|
openSession: (sessionId) => {
|
|
10658
|
-
openConversation(ctx
|
|
11057
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10659
11058
|
},
|
|
10660
11059
|
renameSession,
|
|
10661
11060
|
renameWorkspace: (workspaceId, title) => ctx.workspaces.rename(workspaceId, title),
|
|
@@ -10674,7 +11073,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10674
11073
|
const openDeepLink = () => {
|
|
10675
11074
|
if (opened || ctx.sessions.list.getSnapshot().byId[sessionId] === void 0) return;
|
|
10676
11075
|
opened = true;
|
|
10677
|
-
openConversation(ctx
|
|
11076
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10678
11077
|
};
|
|
10679
11078
|
openDeepLink();
|
|
10680
11079
|
return ctx.sessions.list.subscribe(openDeepLink);
|