@michengai/dsh-codex-ui 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -5,529 +5,62 @@ window.__ModuleLoader__.load({
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
- let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
10
  let react_dom = require("react-dom");
11
- /** 按用户要求用最窄宽度替代宿主自适应默认;已有有效偏好不重置,拖拽起点沿用宿主存储。 */
12
- function initializeComposerWidth(storage) {
13
- const key = "dsh.conversation.contentWidth";
14
- try {
15
- const saved = Number(storage.getItem(key));
16
- if (Number.isFinite(saved) && saved > 0) return;
17
- storage.setItem(key, String(640));
18
- } catch (error) {
19
- console.warn("[codex-ui] 无法初始化输入区宽度,将使用宿主默认值。", error);
20
- }
21
- }
22
- /** 新建页没有宿主 WidthHandle,补充同一宽度偏好的拖拽入口。 */
23
- function observeHeroWidthHandles(label) {
24
- const mounted = /* @__PURE__ */ new Map();
25
- const style = document.createElement("style");
26
- style.textContent = `[data-phase=hero]:has([data-conversation-scroll]){position:relative}[data-dcu-width-handle]{position:absolute;top:0;bottom:0;width:32px;padding:0;border:0;background:transparent;cursor:col-resize;touch-action:none;z-index:8;outline-offset:-5px}[data-dcu-width-handle=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 16px)}[data-dcu-width-handle=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 16px)}[data-dcu-width-handle]::after{content:'';position:absolute;top:calc(var(--dcu-pointer-y,50%) - 50px);height:100px;width:3px;left:14px;border-radius:3px;background:linear-gradient(transparent,var(--dsw-alias-scrollbar-hover-l1,#888),transparent);opacity:0}[data-dcu-width-handle]:hover::after,[data-dcu-width-handle]:focus-visible::after,[data-dcu-width-handle][data-dragging]::after{opacity:1}[data-phase=hero]:has([data-conversation-composer-overlay]) [data-dcu-width-handle]{display:none}`;
27
- document.head.append(style);
28
- const sync = () => {
29
- for (const [root, dispose] of mounted) if (!root.isConnected || root.dataset.phase !== "hero") {
30
- dispose();
31
- mounted.delete(root);
32
- }
33
- for (const root of document.querySelectorAll("[data-phase=hero]")) {
34
- if (mounted.has(root) || !root.querySelector("[data-conversation-scroll]")) continue;
35
- const clamp = (value) => Math.min(Math.max(640, value), Math.max(640, root.clientWidth - 176));
36
- const current = () => {
37
- const raw = getComputedStyle(root).getPropertyValue("--dsh-chat-user-width");
38
- return clamp(parseFloat(raw) || 640);
39
- };
40
- const publish = (width, save) => {
41
- const value = clamp(width);
42
- root.style.setProperty("--dsh-chat-user-width", `${value}px`);
43
- if (save) try {
44
- localStorage.setItem("dsh.conversation.contentWidth", String(value));
45
- } catch (error) {
46
- console.warn("[codex-ui] 无法保存输入区宽度。", error);
47
- }
48
- };
49
- const handles = ["left", "right"].map((side) => {
50
- const handle = document.createElement("button");
51
- handle.type = "button";
52
- handle.dataset.dcuWidthHandle = side;
53
- handle.setAttribute("aria-label", label);
54
- let origin = 0;
55
- let initial = 640;
56
- let dragging = false;
57
- handle.addEventListener("pointerdown", (event) => {
58
- if (event.button !== 0) return;
59
- event.preventDefault();
60
- origin = event.clientX;
61
- initial = current();
62
- dragging = true;
63
- handle.dataset.dragging = "";
64
- handle.setPointerCapture(event.pointerId);
65
- });
66
- handle.addEventListener("pointermove", (event) => {
67
- handle.style.setProperty("--dcu-pointer-y", `${event.clientY - handle.getBoundingClientRect().top}px`);
68
- if (dragging) publish(initial + (event.clientX - origin) * (side === "right" ? 2 : -2), false);
69
- });
70
- handle.addEventListener("pointerup", (event) => {
71
- if (!dragging) return;
72
- publish(initial + (event.clientX - origin) * (side === "right" ? 2 : -2), true);
73
- dragging = false;
74
- delete handle.dataset.dragging;
75
- handle.releasePointerCapture(event.pointerId);
76
- });
77
- handle.addEventListener("lostpointercapture", () => {
78
- if (dragging) publish(initial, false);
79
- dragging = false;
80
- delete handle.dataset.dragging;
81
- });
82
- handle.addEventListener("keydown", (event) => {
83
- if (![
84
- "ArrowLeft",
85
- "ArrowRight",
86
- "Home"
87
- ].includes(event.key)) return;
88
- event.preventDefault();
89
- const delta = (event.key === "ArrowRight" ? 1 : -1) * (side === "right" ? 1 : -1) * 20;
90
- publish(event.key === "Home" ? 640 : current() + delta, true);
91
- });
92
- root.append(handle);
93
- return handle;
94
- });
95
- mounted.set(root, () => {
96
- handles.forEach((handle) => handle.remove());
97
- });
98
- }
99
- };
100
- const observer = new MutationObserver(sync);
101
- observer.observe(document.body, {
102
- childList: true,
103
- subtree: true,
104
- attributes: true,
105
- attributeFilter: ["data-phase"]
106
- });
107
- sync();
108
- return () => {
109
- observer.disconnect();
110
- mounted.forEach((dispose) => dispose());
111
- mounted.clear();
112
- style.remove();
113
- };
114
- }
115
- //#endregion
116
- //#region src/client/tree-expansion.ts
117
- const WORKSPACE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.workspace-expansion.v1";
118
- const CHANNEL_EXPANSION_STORAGE_KEY = "dsh-codex-ui.channel-expansion.v1";
119
- const SCHEDULE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.schedule-expansion.v1";
120
- const MAX_EXPANSION_ENTRIES = 500;
121
- const MAX_EXPANSION_KEY_LENGTH = 512;
122
- function browserStorage() {
123
- if (typeof window === "undefined") return void 0;
124
- try {
125
- return window.localStorage;
126
- } catch {
127
- return;
128
- }
129
- }
130
- function parseTreeExpansionState(value) {
131
- if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
132
- const entries = Object.entries(value).filter(([key, expanded]) => key.length > 0 && key.length <= MAX_EXPANSION_KEY_LENGTH && typeof expanded === "boolean").slice(0, MAX_EXPANSION_ENTRIES);
133
- return Object.fromEntries(entries);
134
- }
135
- function readTreeExpansionState(storage, key) {
136
- if (storage === void 0) return {};
137
- try {
138
- return parseTreeExpansionState(JSON.parse(storage.getItem(key) ?? "{}"));
139
- } catch {
140
- return {};
141
- }
11
+ //#region src/client/session-navigation.ts
12
+ /** 新版会话控制器不再负责主面板切换;打开会话时同时退出全局面板。 */
13
+ function openConversation(sessions, layout, id) {
14
+ sessions.open(id);
15
+ selectGlobalPanel(layout, null);
142
16
  }
143
- function writeTreeExpansionState(storage, key, state) {
144
- if (storage === void 0) return;
145
- try {
146
- storage.setItem(key, JSON.stringify(parseTreeExpansionState(state)));
147
- } catch {}
17
+ /** 统一检测旧宿主是否提供面板切换能力,保留宿主方法的 this。 */
18
+ function selectGlobalPanel(layout, id) {
19
+ if ("selectPanel" in layout && typeof layout.selectPanel === "function") layout.selectPanel(id);
148
20
  }
149
21
  //#endregion
150
- //#region src/client/settings-navigation.ts
22
+ //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
151
23
  /**
152
- * DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
153
- * 的设置入口触发,再按壳的可访问名称选择页面;宿主升级时可集中替换。
24
+ * @license lucide-react v1.39.0 - ISC
25
+ *
26
+ * This source code is licensed under the ISC license.
27
+ * See the LICENSE file in the root directory of this source tree.
154
28
  */
155
- function pickSettingsSectionButton(buttons, labels) {
156
- for (const label of labels) {
157
- const match = buttons.find((button) => button.textContent?.trim() === label);
158
- if (match !== void 0) return match;
159
- }
160
- }
29
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
30
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
31
+ }).join(" ").trim();
32
+ //#endregion
33
+ //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs
161
34
  /**
162
- * 可选插件未注册设置入口时,直接打开兜底页,避免先展示通用设置并等待导航超时。
35
+ * @license lucide-react v1.39.0 - ISC
36
+ *
37
+ * This source code is licensed under the ISC license.
38
+ * See the LICENSE file in the root directory of this source tree.
163
39
  */
164
- function routeOptionalSettingsSection(available, openRequested, openFallback) {
165
- if (available) {
166
- openRequested();
167
- return;
168
- }
169
- openFallback();
170
- }
171
- let cancelPendingNavigation;
172
- const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
173
- const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
174
- const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
175
- /** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
176
- function openSettingsRoot(root) {
177
- root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
178
- }
179
- function openSettingsSection(root, label, onMissing, onSelected) {
180
- const labels = typeof label === "string" ? [label] : label;
181
- const trigger = root?.querySelector(SETTINGS_TRIGGER_SELECTOR);
182
- if (trigger === null || trigger === void 0) {
183
- onMissing?.();
184
- return;
185
- }
186
- const opening = cancelPendingNavigation !== void 0;
187
- cancelPendingNavigation?.();
188
- const request = new CustomEvent(SETTINGS_OPEN_SECTION_EVENT, {
189
- detail: { labels },
190
- cancelable: true
191
- });
192
- if (!trigger.dispatchEvent(request)) {
193
- onSelected?.();
194
- return;
195
- }
196
- const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
197
- if (!opening && document.querySelector(pageSelector) === null) trigger.click();
198
- let frame;
199
- let finished = false;
200
- const observer = new MutationObserver(() => {
201
- schedule();
202
- });
203
- const cleanup = () => {
204
- if (finished) return;
205
- finished = true;
206
- observer.disconnect();
207
- window.clearTimeout(timeout);
208
- if (frame !== void 0) window.cancelAnimationFrame(frame);
209
- if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
210
- };
211
- const select = () => {
212
- const target = pickSettingsSectionButton([...document.querySelectorAll(`${pageSelector} nav button`)], labels);
213
- if (target === void 0) return false;
214
- cleanup();
215
- target.click();
216
- onSelected?.();
217
- return true;
218
- };
219
- const schedule = () => {
220
- if (finished || frame !== void 0) return;
221
- frame = window.requestAnimationFrame(() => {
222
- frame = void 0;
223
- select();
224
- });
225
- };
226
- const timeout = window.setTimeout(() => {
227
- if (select()) return;
228
- cleanup();
229
- console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
230
- onMissing?.();
231
- }, SETTINGS_NAVIGATION_TIMEOUT_MS);
232
- observer.observe(document.body, {
233
- childList: true,
234
- subtree: true
235
- });
236
- cancelPendingNavigation = cleanup;
237
- schedule();
238
- }
40
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
239
41
  //#endregion
240
- //#region src/client/sidebar-search.ts
241
- /** 按用户可见名称和辅助关键词筛选侧栏搜索结果。 */
242
- function filterSidebarSearchItems(items, query) {
243
- const needle = query.trim().toLocaleLowerCase();
244
- if (needle === "") return [...items];
245
- return items.filter((item) => `${item.label} ${item.keywords}`.toLocaleLowerCase().includes(needle));
246
- }
42
+ //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs
43
+ /**
44
+ * @license lucide-react v1.39.0 - ISC
45
+ *
46
+ * This source code is licensed under the ISC license.
47
+ * See the LICENSE file in the root directory of this source tree.
48
+ */
49
+ const toCamelCase = (string) => string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase());
247
50
  //#endregion
248
- //#region src/client/companion-slots.ts
249
- const EMPTY_COMPANION_TABS = {
250
- channels: false,
251
- schedule: false
252
- };
253
- const reportedSlotErrors = /* @__PURE__ */ new WeakSet();
254
- /** 插槽声明本身不算占用;只有其他插件 register 后才视为已安装。 */
255
- function readSlotEntries(slots, name) {
256
- if (slots === void 0) return [];
257
- const read = slots.entriesOfSlot ?? slots.entries;
258
- if (typeof read !== "function") return [];
259
- try {
260
- return read.call(slots, name) ?? [];
261
- } catch (error) {
262
- if (!reportedSlotErrors.has(slots)) {
263
- reportedSlotErrors.add(slots);
264
- console.warn("[michengai-codex-ui] 无法读取配套插件插槽。", error);
265
- }
266
- return [];
267
- }
268
- }
269
- function slotHasEntries(slots, name) {
270
- return readSlotEntries(slots, name).length > 0;
271
- }
272
- function companionTabAvailability(slots) {
273
- return {
274
- channels: slotHasEntries(slots, "sidebar.channels"),
275
- schedule: slotHasEntries(slots, "sidebar.schedule")
276
- };
277
- }
278
- function sameCompanionTabs(left, right) {
279
- return left.channels === right.channels && left.schedule === right.schedule;
280
- }
281
- /** 给 React useSyncExternalStore 用的配套页签快照源。 */
282
- function createCompanionTabSource(slots) {
283
- let cached = companionTabAvailability(slots);
284
- return {
285
- getSnapshot() {
286
- const next = companionTabAvailability(slots);
287
- if (sameCompanionTabs(next, cached)) return cached;
288
- cached = next;
289
- return cached;
290
- },
291
- subscribe(onStoreChange) {
292
- if (slots === void 0 || typeof slots.subscribe !== "function") return () => {};
293
- const offChannels = slots.subscribe("sidebar.channels", onStoreChange);
294
- const offSchedule = slots.subscribe("sidebar.schedule", onStoreChange);
295
- return () => {
296
- offChannels?.();
297
- offSchedule?.();
298
- };
299
- }
300
- };
301
- }
302
- //#endregion
303
- //#region src/client/channel-brand.tsx
304
- function ChannelBrandIcon({ id }) {
305
- const brand = id.trim().toLowerCase();
306
- if (brand === "telegram") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
307
- className: "dcu-wb-brand",
308
- viewBox: "0 0 24 24",
309
- width: 16,
310
- height: 16,
311
- "aria-hidden": "true",
312
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
313
- fill: "#26A5E4",
314
- d: "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
315
- })
316
- });
317
- if (brand === "weixin") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
318
- className: "dcu-wb-brand",
319
- viewBox: "0 0 48 48",
320
- width: 16,
321
- height: 16,
322
- "aria-hidden": "true",
323
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
324
- fill: "#07C160",
325
- fillRule: "evenodd",
326
- d: "M32.8 18.003 32.5 18C25.732 18 20 22.798 20 29c0 1.007.151 1.976.433 2.894A18 18 0 0 1 18.5 32c-1.809 0-3.54-.274-5.137-.775-.394-.123-1.828.696-3.039 1.389-.927.53-1.724.986-1.824.886-.094-.094.169-.718.476-1.448.446-1.06.986-2.346.664-2.552C6.21 27.305 4 23.866 4 20c0-6.627 6.492-12 14.5-12 7.186 0 13.151 4.326 14.3 10.003M16 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0m7 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4"
327
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
328
- fill: "#07C160",
329
- fillRule: "evenodd",
330
- d: "M44 29c0 3.362-1.908 6.336-4.833 8.149-.13.08.169.858.446 1.583.237.618.459 1.196.387 1.268-.075.075-.802-.327-1.571-.752-.829-.458-1.706-.942-1.871-.888-1.262.413-2.63.64-4.058.64C26.149 39 21 34.523 21 29s5.149-10 11.5-10S44 23.477 44 29m-6-3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0M28.5 27a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"
331
- })]
332
- });
333
- if (brand === "wecom") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
334
- className: "dcu-wb-brand",
335
- viewBox: "4 6 39 34",
336
- width: 16,
337
- height: 16,
338
- "aria-hidden": "true",
339
- children: [
340
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
341
- fill: "#fb6500",
342
- d: "M28.856 31.647a.483.483 0 0 0 .06.738 6.2 6.2 0 0 1 1.911 3.725 2.02 2.02 0 1 0 2.16-2.54 6.2 6.2 0 0 1-3.448-1.922.483.483 0 0 0-.683-.001"
343
- }),
344
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
345
- fill: "#0082ef",
346
- d: "M37.057 28.448a2 2 0 0 0-.58 1.215 6.2 6.2 0 0 1-1.918 3.454.484.484 0 1 0 .738.616 6.2 6.2 0 0 1 3.725-1.91 2.02 2.02 0 1 0-1.96-3.376z"
347
- }),
348
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
349
- fill: "#2dbc00",
350
- d: "M31.366 22.75a2.02 2.02 0 0 0 1.215 3.435 6.2 6.2 0 0 1 3.454 1.918.483.483 0 0 0 .829-.27.48.48 0 0 0-.212-.468 6.2 6.2 0 0 1-1.911-3.726 2.02 2.02 0 0 0-3.375-.889"
351
- }),
352
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
353
- fill: "#fc0",
354
- d: "m30.374 25.907-.037.037a6.2 6.2 0 0 1-3.78 1.978 2.007 2.007 0 0 0-.895 3.374 2.02 2.02 0 0 0 3.435-1.216 6.2 6.2 0 0 1 1.923-3.453.484.484 0 0 0-.646-.72"
355
- }),
356
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
357
- fill: "#0082ef",
358
- d: "M18.17 8.471c-3.624.4-6.908 1.948-9.266 4.367-.938.956-1.7 2.032-2.262 3.182a11.08 11.08 0 0 0 .78 11.188c.64.968 1.693 2.178 2.654 3.037l-.435 3.423-.048.145c-.012.042-.012.09-.018.133l-.012.108.012.11a1.1 1.1 0 0 0 1.657.852h.018l.067-.049 1.04-.52 3.102-1.56a16 16 0 0 0 4.537.623c1.897.004 3.78-.323 5.564-.968a2.014 2.014 0 0 1-1.373-2.11 13.7 13.7 0 0 1-5.721.568l-.309-.042a14 14 0 0 1-2.056-.43 1.4 1.4 0 0 0-1.1.116l-.085.042-2.552 1.5-.109.066c-.06.036-.09.048-.12.048a.176.176 0 0 1-.164-.181l.097-.393.115-.43.181-.707.212-.787a1.07 1.07 0 0 0-.387-1.19 11.2 11.2 0 0 1-2.577-2.686 8.73 8.73 0 0 1-.629-8.818c.46-.92 1.065-1.773 1.815-2.54 1.935-1.997 4.657-3.267 7.669-3.593a14.3 14.3 0 0 1 3.132 0c2.994.344 5.704 1.633 7.627 3.617a10 10 0 0 1 1.796 2.551 8.7 8.7 0 0 1 .901 3.84c0 .14-.012.279-.018.412a2.015 2.015 0 0 1 2.48.29l.09.109a11 11 0 0 0-1.1-5.733 12.3 12.3 0 0 0-2.238-3.182 15.18 15.18 0 0 0-9.229-4.397 17 17 0 0 0-3.739-.01"
359
- })
360
- ]
361
- });
362
- if (brand === "qq") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
363
- className: "dcu-wb-brand",
364
- viewBox: "0 0 24 24",
365
- width: 16,
366
- height: 16,
367
- "aria-hidden": "true",
368
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
369
- fill: "#12B7F5",
370
- d: "M21.395 15.035a40 40 0 0 0-.803-2.264l-1.079-2.695c.001-.032.014-.562.014-.836C19.526 4.632 17.351 0 12 0S4.474 4.632 4.474 9.241c0 .274.013.804.014.836l-1.08 2.695a39 39 0 0 0-.802 2.264c-1.021 3.283-.69 4.643-.438 4.673.54.065 2.103-2.472 2.103-2.472 0 1.469.756 3.387 2.394 4.771-.612.188-1.363.479-1.845.835-.434.32-.379.646-.301.778.343.578 5.883.369 7.482.189 1.6.18 7.14.389 7.483-.189.078-.132.132-.458-.301-.778-.483-.356-1.233-.646-1.846-.836 1.637-1.384 2.393-3.302 2.393-4.771 0 0 1.563 2.537 2.103 2.472.251-.03.581-1.39-.438-4.673"
371
- })
372
- });
373
- if (brand === "dingtalk") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
374
- className: "dcu-wb-brand",
375
- viewBox: "6 6 36 36",
376
- width: 16,
377
- height: 16,
378
- "aria-hidden": "true",
379
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
380
- x: "6",
381
- y: "6",
382
- width: "36",
383
- height: "36",
384
- rx: "8",
385
- fill: "#0285fc"
386
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
387
- fill: "#fff",
388
- d: "m20.178 37.577 3.5-6h-3l2-3c-5.5-1-6.281-3.938-6-4.5.162-.325 2.5 1 6.281 1-8.281-.5-8.281-7-7.781-7.5.423-.424 2.44 1.666 6.564 3.53-9.126-4.314-6.453-11.956-5.064-11.03 3.344 3 9.5 8.5 15 13 .658.538 1 2 0 3.25s-2.5 2.75-3 3.25h2.5z"
389
- })]
390
- });
391
- if (brand === "feishu" || brand === "lark") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
392
- className: "dcu-wb-brand",
393
- viewBox: "0 0 48 48",
394
- width: 16,
395
- height: 16,
396
- "aria-hidden": "true",
397
- children: [
398
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
399
- fill: "#00d6b9",
400
- d: "M10 8c0 1 7 3.5 14.745 16.744 0 0 4.184-4.363 6.255-5.744 1.5-1 2.712-1.332 2.712-1.332C33.712 15.156 29.5 8 28 8z"
401
- }),
402
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
403
- fill: "#163c9a",
404
- d: "M43.5 18.5c-1-.667-3.65-1.771-6.5-1.5a15 15 0 0 0-3.288.668S32.5 18 31 19c-2.07 1.38-6.255 5.744-6.255 5.744-1.428 1.397-3.05 2.732-5.245 3.756 0 0 7 3 11.5 3 5.063 0 7-3.5 7-3.5 1.5-3.305 3.5-7 5.5-9.5"
405
- }),
406
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
407
- fill: "#3370ff",
408
- d: "M4 17.5v17c0 1 6 5.5 15 5.5 10 0 17.05-7.705 19-12 0 0-1.937 3.5-7 3.5-4.5 0-11.5-3-11.5-3-5.117-2.239-10.03-6.577-12.906-9.117C4.974 17.953 4 17.093 4 17.5"
409
- })
410
- ]
411
- });
412
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
413
- className: "dcu-wb-brand",
414
- viewBox: "0 0 16 16",
415
- width: 16,
416
- height: 16,
417
- "aria-hidden": "true",
418
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
419
- cx: "8",
420
- cy: "8",
421
- r: "7",
422
- fill: "#8b949e"
423
- })
424
- });
425
- }
426
- //#endregion
427
- //#region src/client/channel-api.ts
428
- const CHANNELS_ENDPOINT = "/api/dsh-im-connect/channels";
429
- /** DSH 会话头不能写 origin=im,频道会话只靠 id 前缀。 */
430
- function isChannelSession(id) {
431
- return id.startsWith("im:");
432
- }
433
- function text(value, fallback = "") {
434
- return typeof value === "string" && value.trim() !== "" ? value.trim() : fallback;
435
- }
436
- function updatedAt(value) {
437
- if (typeof value === "number" && Number.isFinite(value)) return value;
438
- if (typeof value === "string" && value !== "") {
439
- const parsed = Date.parse(value);
440
- if (Number.isFinite(parsed)) return parsed;
441
- }
442
- }
443
- function parseChannelSession(value) {
444
- if (value === null || typeof value !== "object") return void 0;
445
- const row = value;
446
- const sessionId = text(row.sessionId);
447
- if (sessionId === "") return void 0;
448
- return {
449
- sessionId,
450
- title: text(row.title) || text(row.chatId) || sessionId,
451
- updatedAt: updatedAt(row.updatedAt),
452
- running: row.running === true
453
- };
454
- }
455
- function parseChannelGroups(payload, fallbackLabel = "") {
456
- const root = payload !== null && typeof payload === "object" ? payload : {};
457
- return (Array.isArray(root.groups) ? root.groups : Array.isArray(payload) ? payload : []).flatMap((item, index) => {
458
- if (item === null || typeof item !== "object") return [];
459
- const group = item;
460
- const sessions = Array.isArray(group.sessions) ? group.sessions.flatMap((session) => {
461
- const parsed = parseChannelSession(session);
462
- return parsed === void 0 ? [] : [parsed];
463
- }) : [];
464
- return [{
465
- id: text(group.id, `channel-${index}`),
466
- label: text(group.label, text(group.title, fallbackLabel)),
467
- sessions
468
- }];
469
- });
470
- }
471
- /** 读取 IM 频道分组;失败时交给界面显示空态或错误。 */
472
- async function loadChannelGroups(signal, fallbackLabel = "") {
473
- const response = await fetch(CHANNELS_ENDPOINT, {
474
- cache: "no-store",
475
- signal
476
- });
477
- let payload;
478
- try {
479
- payload = await response.json();
480
- } catch {
481
- throw new Error(response.ok ? "频道会话数据格式无效" : "无法读取频道会话");
482
- }
483
- const root = payload !== null && typeof payload === "object" ? payload : {};
484
- if (!response.ok) throw new Error(text(root.error, "无法读取频道会话"));
485
- if (root.ok === false) throw new Error(text(root.error, "无法读取频道会话"));
486
- return parseChannelGroups(payload, fallbackLabel);
487
- }
488
- //#endregion
489
- //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
51
+ //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs
490
52
  /**
491
53
  * @license lucide-react v1.39.0 - ISC
492
54
  *
493
55
  * This source code is licensed under the ISC license.
494
56
  * See the LICENSE file in the root directory of this source tree.
495
57
  */
496
- const mergeClasses = (...classes) => classes.filter((className, index, array) => {
497
- return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
498
- }).join(" ").trim();
58
+ const toPascalCase = (string) => {
59
+ const camelCase = toCamelCase(string);
60
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
61
+ };
499
62
  //#endregion
500
- //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs
501
- /**
502
- * @license lucide-react v1.39.0 - ISC
503
- *
504
- * This source code is licensed under the ISC license.
505
- * See the LICENSE file in the root directory of this source tree.
506
- */
507
- const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
508
- //#endregion
509
- //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs
510
- /**
511
- * @license lucide-react v1.39.0 - ISC
512
- *
513
- * This source code is licensed under the ISC license.
514
- * See the LICENSE file in the root directory of this source tree.
515
- */
516
- const toCamelCase = (string) => string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase());
517
- //#endregion
518
- //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs
519
- /**
520
- * @license lucide-react v1.39.0 - ISC
521
- *
522
- * This source code is licensed under the ISC license.
523
- * See the LICENSE file in the root directory of this source tree.
524
- */
525
- const toPascalCase = (string) => {
526
- const camelCase = toCamelCase(string);
527
- return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
528
- };
529
- //#endregion
530
- //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/defaultAttributes.mjs
63
+ //#region node_modules/.pnpm/lucide-react@1.39.0_react@18.3.1/node_modules/lucide-react/dist/esm/defaultAttributes.mjs
531
64
  /**
532
65
  * @license lucide-react v1.39.0 - ISC
533
66
  *
@@ -1187,6 +720,532 @@ window.__ModuleLoader__.load({
1187
720
  key: "17ys0d"
1188
721
  }]]);
1189
722
  //#endregion
723
+ //#region src/client/global-panels.tsx
724
+ /** 从宿主注册表读取面板元数据;缓存快照以满足 React 外部状态订阅契约。 */
725
+ function createGlobalPanelSource(slots, locale) {
726
+ let cached = [];
727
+ return {
728
+ getSnapshot() {
729
+ const next = slots.entriesOfSlot("sidebar.panellist").flatMap(({ options }) => options.id === void 0 ? [] : [{
730
+ id: options.id,
731
+ order: options.order ?? 0,
732
+ label: (typeof options.label === "function" ? options.label() : options.label) ?? options.id
733
+ }]).sort((a, b) => a.order - b.order);
734
+ if (next.length !== cached.length || next.some((panel, index) => {
735
+ const previous = cached[index];
736
+ return previous === void 0 || panel.id !== previous.id || panel.label !== previous.label || panel.order !== previous.order;
737
+ })) cached = next;
738
+ return cached;
739
+ },
740
+ subscribe(listener) {
741
+ const offSlots = slots.subscribe("sidebar.panellist", listener);
742
+ const offLocale = locale.subscribe(listener);
743
+ return () => {
744
+ offSlots();
745
+ offLocale();
746
+ };
747
+ }
748
+ };
749
+ }
750
+ /** 展开和紧凑侧栏共享同一导航行为,null 回到已有会话而非新建会话。 */
751
+ function GlobalPanelButtons({ panels, activeId, wide, conversationLabel, selectPanel, renderIcon }) {
752
+ if (panels.length === 0) return null;
753
+ const button = (id, label, icon) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
754
+ type: "button",
755
+ className: wide ? "dcu-global-panel" : "dcu-icon dcu-global-panel",
756
+ "aria-label": label,
757
+ title: wide ? void 0 : label,
758
+ "aria-current": activeId === id ? "page" : void 0,
759
+ onClick: () => selectPanel(id),
760
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
761
+ className: "dcu-menu-icon",
762
+ "aria-hidden": "true",
763
+ children: icon
764
+ }), wide && label]
765
+ }, id ?? "conversation");
766
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [button(null, conversationLabel, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageSquare, {
767
+ size: 16,
768
+ strokeWidth: 1.6
769
+ })), panels.map((panel) => button(panel.id, panel.label, renderIcon(panel.id, activeId === panel.id)))] });
770
+ }
771
+ /** 按用户要求用最窄宽度替代宿主自适应默认;已有有效偏好不重置,拖拽起点沿用宿主存储。 */
772
+ function initializeComposerWidth(storage) {
773
+ const key = "dsh.conversation.contentWidth";
774
+ try {
775
+ const saved = Number(storage.getItem(key));
776
+ if (Number.isFinite(saved) && saved > 0) return;
777
+ storage.setItem(key, String(640));
778
+ } catch (error) {
779
+ console.warn("[codex-ui] 无法初始化输入区宽度,将使用宿主默认值。", error);
780
+ }
781
+ }
782
+ /** 新建页没有宿主 WidthHandle,补充同一宽度偏好的拖拽入口。 */
783
+ function observeHeroWidthHandles(label) {
784
+ const mounted = /* @__PURE__ */ new Map();
785
+ const style = document.createElement("style");
786
+ style.textContent = `[data-phase=hero]:has([data-conversation-scroll]){position:relative}[data-dcu-width-handle]{position:absolute;top:0;bottom:0;width:32px;padding:0;border:0;background:transparent;cursor:col-resize;touch-action:none;z-index:8;outline-offset:-5px}[data-dcu-width-handle=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 16px)}[data-dcu-width-handle=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 16px)}[data-dcu-width-handle]::after{content:'';position:absolute;top:calc(var(--dcu-pointer-y,50%) - 50px);height:100px;width:3px;left:14px;border-radius:3px;background:linear-gradient(transparent,var(--dsw-alias-scrollbar-hover-l1,#888),transparent);opacity:0}[data-dcu-width-handle]:hover::after,[data-dcu-width-handle]:focus-visible::after,[data-dcu-width-handle][data-dragging]::after{opacity:1}[data-phase=hero]:has([data-conversation-composer-overlay]) [data-dcu-width-handle]{display:none}`;
787
+ document.head.append(style);
788
+ const sync = () => {
789
+ for (const [root, dispose] of mounted) if (!root.isConnected || root.dataset.phase !== "hero") {
790
+ dispose();
791
+ mounted.delete(root);
792
+ }
793
+ for (const root of document.querySelectorAll("[data-phase=hero]")) {
794
+ if (mounted.has(root) || !root.querySelector("[data-conversation-scroll]")) continue;
795
+ const clamp = (value) => Math.min(Math.max(640, value), Math.max(640, root.clientWidth - 176));
796
+ const current = () => {
797
+ const raw = getComputedStyle(root).getPropertyValue("--dsh-chat-user-width");
798
+ return clamp(parseFloat(raw) || 640);
799
+ };
800
+ const publish = (width, save) => {
801
+ const value = clamp(width);
802
+ root.style.setProperty("--dsh-chat-user-width", `${value}px`);
803
+ if (save) try {
804
+ localStorage.setItem("dsh.conversation.contentWidth", String(value));
805
+ } catch (error) {
806
+ console.warn("[codex-ui] 无法保存输入区宽度。", error);
807
+ }
808
+ };
809
+ const handles = ["left", "right"].map((side) => {
810
+ const handle = document.createElement("button");
811
+ handle.type = "button";
812
+ handle.dataset.dcuWidthHandle = side;
813
+ handle.setAttribute("aria-label", label);
814
+ let origin = 0;
815
+ let initial = 640;
816
+ let dragging = false;
817
+ handle.addEventListener("pointerdown", (event) => {
818
+ if (event.button !== 0) return;
819
+ event.preventDefault();
820
+ origin = event.clientX;
821
+ initial = current();
822
+ dragging = true;
823
+ handle.dataset.dragging = "";
824
+ handle.setPointerCapture(event.pointerId);
825
+ });
826
+ handle.addEventListener("pointermove", (event) => {
827
+ handle.style.setProperty("--dcu-pointer-y", `${event.clientY - handle.getBoundingClientRect().top}px`);
828
+ if (dragging) publish(initial + (event.clientX - origin) * (side === "right" ? 2 : -2), false);
829
+ });
830
+ handle.addEventListener("pointerup", (event) => {
831
+ if (!dragging) return;
832
+ publish(initial + (event.clientX - origin) * (side === "right" ? 2 : -2), true);
833
+ dragging = false;
834
+ delete handle.dataset.dragging;
835
+ handle.releasePointerCapture(event.pointerId);
836
+ });
837
+ handle.addEventListener("lostpointercapture", () => {
838
+ if (dragging) publish(initial, false);
839
+ dragging = false;
840
+ delete handle.dataset.dragging;
841
+ });
842
+ handle.addEventListener("keydown", (event) => {
843
+ if (![
844
+ "ArrowLeft",
845
+ "ArrowRight",
846
+ "Home"
847
+ ].includes(event.key)) return;
848
+ event.preventDefault();
849
+ const delta = (event.key === "ArrowRight" ? 1 : -1) * (side === "right" ? 1 : -1) * 20;
850
+ publish(event.key === "Home" ? 640 : current() + delta, true);
851
+ });
852
+ root.append(handle);
853
+ return handle;
854
+ });
855
+ mounted.set(root, () => {
856
+ handles.forEach((handle) => handle.remove());
857
+ });
858
+ }
859
+ };
860
+ const observer = new MutationObserver(sync);
861
+ observer.observe(document.body, {
862
+ childList: true,
863
+ subtree: true,
864
+ attributes: true,
865
+ attributeFilter: ["data-phase"]
866
+ });
867
+ sync();
868
+ return () => {
869
+ observer.disconnect();
870
+ mounted.forEach((dispose) => dispose());
871
+ mounted.clear();
872
+ style.remove();
873
+ };
874
+ }
875
+ //#endregion
876
+ //#region src/client/tree-expansion.ts
877
+ const WORKSPACE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.workspace-expansion.v1";
878
+ const CHANNEL_EXPANSION_STORAGE_KEY = "dsh-codex-ui.channel-expansion.v1";
879
+ const SCHEDULE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.schedule-expansion.v1";
880
+ const MAX_EXPANSION_ENTRIES = 500;
881
+ const MAX_EXPANSION_KEY_LENGTH = 512;
882
+ function browserStorage() {
883
+ if (typeof window === "undefined") return void 0;
884
+ try {
885
+ return window.localStorage;
886
+ } catch {
887
+ return;
888
+ }
889
+ }
890
+ function parseTreeExpansionState(value) {
891
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
892
+ const entries = Object.entries(value).filter(([key, expanded]) => key.length > 0 && key.length <= MAX_EXPANSION_KEY_LENGTH && typeof expanded === "boolean").slice(0, MAX_EXPANSION_ENTRIES);
893
+ return Object.fromEntries(entries);
894
+ }
895
+ function readTreeExpansionState(storage, key) {
896
+ if (storage === void 0) return {};
897
+ try {
898
+ return parseTreeExpansionState(JSON.parse(storage.getItem(key) ?? "{}"));
899
+ } catch {
900
+ return {};
901
+ }
902
+ }
903
+ function writeTreeExpansionState(storage, key, state) {
904
+ if (storage === void 0) return;
905
+ try {
906
+ storage.setItem(key, JSON.stringify(parseTreeExpansionState(state)));
907
+ } catch {}
908
+ }
909
+ //#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
+ //#region src/client/sidebar-search.ts
1001
+ /** 按用户可见名称和辅助关键词筛选侧栏搜索结果。 */
1002
+ function filterSidebarSearchItems(items, query) {
1003
+ const needle = query.trim().toLocaleLowerCase();
1004
+ if (needle === "") return [...items];
1005
+ return items.filter((item) => `${item.label} ${item.keywords}`.toLocaleLowerCase().includes(needle));
1006
+ }
1007
+ //#endregion
1008
+ //#region src/client/companion-slots.ts
1009
+ const EMPTY_COMPANION_TABS = {
1010
+ channels: false,
1011
+ schedule: false
1012
+ };
1013
+ const reportedSlotErrors = /* @__PURE__ */ new WeakSet();
1014
+ /** 插槽声明本身不算占用;只有其他插件 register 后才视为已安装。 */
1015
+ function readSlotEntries(slots, name) {
1016
+ if (slots === void 0) return [];
1017
+ const read = slots.entriesOfSlot ?? slots.entries;
1018
+ if (typeof read !== "function") return [];
1019
+ try {
1020
+ return read.call(slots, name) ?? [];
1021
+ } catch (error) {
1022
+ if (!reportedSlotErrors.has(slots)) {
1023
+ reportedSlotErrors.add(slots);
1024
+ console.warn("[michengai-codex-ui] 无法读取配套插件插槽。", error);
1025
+ }
1026
+ return [];
1027
+ }
1028
+ }
1029
+ function slotHasEntries(slots, name) {
1030
+ return readSlotEntries(slots, name).length > 0;
1031
+ }
1032
+ function companionTabAvailability(slots) {
1033
+ return {
1034
+ channels: slotHasEntries(slots, "sidebar.channels"),
1035
+ schedule: slotHasEntries(slots, "sidebar.schedule")
1036
+ };
1037
+ }
1038
+ function sameCompanionTabs(left, right) {
1039
+ return left.channels === right.channels && left.schedule === right.schedule;
1040
+ }
1041
+ /** 给 React useSyncExternalStore 用的配套页签快照源。 */
1042
+ function createCompanionTabSource(slots) {
1043
+ let cached = companionTabAvailability(slots);
1044
+ return {
1045
+ getSnapshot() {
1046
+ const next = companionTabAvailability(slots);
1047
+ if (sameCompanionTabs(next, cached)) return cached;
1048
+ cached = next;
1049
+ return cached;
1050
+ },
1051
+ subscribe(onStoreChange) {
1052
+ if (slots === void 0 || typeof slots.subscribe !== "function") return () => {};
1053
+ const offChannels = slots.subscribe("sidebar.channels", onStoreChange);
1054
+ const offSchedule = slots.subscribe("sidebar.schedule", onStoreChange);
1055
+ return () => {
1056
+ offChannels?.();
1057
+ offSchedule?.();
1058
+ };
1059
+ }
1060
+ };
1061
+ }
1062
+ //#endregion
1063
+ //#region src/client/channel-brand.tsx
1064
+ function ChannelBrandIcon({ id }) {
1065
+ const brand = id.trim().toLowerCase();
1066
+ if (brand === "telegram") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1067
+ className: "dcu-wb-brand",
1068
+ viewBox: "0 0 24 24",
1069
+ width: 16,
1070
+ height: 16,
1071
+ "aria-hidden": "true",
1072
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1073
+ fill: "#26A5E4",
1074
+ d: "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
1075
+ })
1076
+ });
1077
+ if (brand === "weixin") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1078
+ className: "dcu-wb-brand",
1079
+ viewBox: "0 0 48 48",
1080
+ width: 16,
1081
+ height: 16,
1082
+ "aria-hidden": "true",
1083
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1084
+ fill: "#07C160",
1085
+ fillRule: "evenodd",
1086
+ d: "M32.8 18.003 32.5 18C25.732 18 20 22.798 20 29c0 1.007.151 1.976.433 2.894A18 18 0 0 1 18.5 32c-1.809 0-3.54-.274-5.137-.775-.394-.123-1.828.696-3.039 1.389-.927.53-1.724.986-1.824.886-.094-.094.169-.718.476-1.448.446-1.06.986-2.346.664-2.552C6.21 27.305 4 23.866 4 20c0-6.627 6.492-12 14.5-12 7.186 0 13.151 4.326 14.3 10.003M16 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0m7 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4"
1087
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1088
+ fill: "#07C160",
1089
+ fillRule: "evenodd",
1090
+ d: "M44 29c0 3.362-1.908 6.336-4.833 8.149-.13.08.169.858.446 1.583.237.618.459 1.196.387 1.268-.075.075-.802-.327-1.571-.752-.829-.458-1.706-.942-1.871-.888-1.262.413-2.63.64-4.058.64C26.149 39 21 34.523 21 29s5.149-10 11.5-10S44 23.477 44 29m-6-3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0M28.5 27a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"
1091
+ })]
1092
+ });
1093
+ if (brand === "wecom") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1094
+ className: "dcu-wb-brand",
1095
+ viewBox: "4 6 39 34",
1096
+ width: 16,
1097
+ height: 16,
1098
+ "aria-hidden": "true",
1099
+ children: [
1100
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1101
+ fill: "#fb6500",
1102
+ d: "M28.856 31.647a.483.483 0 0 0 .06.738 6.2 6.2 0 0 1 1.911 3.725 2.02 2.02 0 1 0 2.16-2.54 6.2 6.2 0 0 1-3.448-1.922.483.483 0 0 0-.683-.001"
1103
+ }),
1104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1105
+ fill: "#0082ef",
1106
+ d: "M37.057 28.448a2 2 0 0 0-.58 1.215 6.2 6.2 0 0 1-1.918 3.454.484.484 0 1 0 .738.616 6.2 6.2 0 0 1 3.725-1.91 2.02 2.02 0 1 0-1.96-3.376z"
1107
+ }),
1108
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1109
+ fill: "#2dbc00",
1110
+ d: "M31.366 22.75a2.02 2.02 0 0 0 1.215 3.435 6.2 6.2 0 0 1 3.454 1.918.483.483 0 0 0 .829-.27.48.48 0 0 0-.212-.468 6.2 6.2 0 0 1-1.911-3.726 2.02 2.02 0 0 0-3.375-.889"
1111
+ }),
1112
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1113
+ fill: "#fc0",
1114
+ d: "m30.374 25.907-.037.037a6.2 6.2 0 0 1-3.78 1.978 2.007 2.007 0 0 0-.895 3.374 2.02 2.02 0 0 0 3.435-1.216 6.2 6.2 0 0 1 1.923-3.453.484.484 0 0 0-.646-.72"
1115
+ }),
1116
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1117
+ fill: "#0082ef",
1118
+ d: "M18.17 8.471c-3.624.4-6.908 1.948-9.266 4.367-.938.956-1.7 2.032-2.262 3.182a11.08 11.08 0 0 0 .78 11.188c.64.968 1.693 2.178 2.654 3.037l-.435 3.423-.048.145c-.012.042-.012.09-.018.133l-.012.108.012.11a1.1 1.1 0 0 0 1.657.852h.018l.067-.049 1.04-.52 3.102-1.56a16 16 0 0 0 4.537.623c1.897.004 3.78-.323 5.564-.968a2.014 2.014 0 0 1-1.373-2.11 13.7 13.7 0 0 1-5.721.568l-.309-.042a14 14 0 0 1-2.056-.43 1.4 1.4 0 0 0-1.1.116l-.085.042-2.552 1.5-.109.066c-.06.036-.09.048-.12.048a.176.176 0 0 1-.164-.181l.097-.393.115-.43.181-.707.212-.787a1.07 1.07 0 0 0-.387-1.19 11.2 11.2 0 0 1-2.577-2.686 8.73 8.73 0 0 1-.629-8.818c.46-.92 1.065-1.773 1.815-2.54 1.935-1.997 4.657-3.267 7.669-3.593a14.3 14.3 0 0 1 3.132 0c2.994.344 5.704 1.633 7.627 3.617a10 10 0 0 1 1.796 2.551 8.7 8.7 0 0 1 .901 3.84c0 .14-.012.279-.018.412a2.015 2.015 0 0 1 2.48.29l.09.109a11 11 0 0 0-1.1-5.733 12.3 12.3 0 0 0-2.238-3.182 15.18 15.18 0 0 0-9.229-4.397 17 17 0 0 0-3.739-.01"
1119
+ })
1120
+ ]
1121
+ });
1122
+ if (brand === "qq") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1123
+ className: "dcu-wb-brand",
1124
+ viewBox: "0 0 24 24",
1125
+ width: 16,
1126
+ height: 16,
1127
+ "aria-hidden": "true",
1128
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1129
+ fill: "#12B7F5",
1130
+ d: "M21.395 15.035a40 40 0 0 0-.803-2.264l-1.079-2.695c.001-.032.014-.562.014-.836C19.526 4.632 17.351 0 12 0S4.474 4.632 4.474 9.241c0 .274.013.804.014.836l-1.08 2.695a39 39 0 0 0-.802 2.264c-1.021 3.283-.69 4.643-.438 4.673.54.065 2.103-2.472 2.103-2.472 0 1.469.756 3.387 2.394 4.771-.612.188-1.363.479-1.845.835-.434.32-.379.646-.301.778.343.578 5.883.369 7.482.189 1.6.18 7.14.389 7.483-.189.078-.132.132-.458-.301-.778-.483-.356-1.233-.646-1.846-.836 1.637-1.384 2.393-3.302 2.393-4.771 0 0 1.563 2.537 2.103 2.472.251-.03.581-1.39-.438-4.673"
1131
+ })
1132
+ });
1133
+ if (brand === "dingtalk") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1134
+ className: "dcu-wb-brand",
1135
+ viewBox: "6 6 36 36",
1136
+ width: 16,
1137
+ height: 16,
1138
+ "aria-hidden": "true",
1139
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
1140
+ x: "6",
1141
+ y: "6",
1142
+ width: "36",
1143
+ height: "36",
1144
+ rx: "8",
1145
+ fill: "#0285fc"
1146
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1147
+ fill: "#fff",
1148
+ d: "m20.178 37.577 3.5-6h-3l2-3c-5.5-1-6.281-3.938-6-4.5.162-.325 2.5 1 6.281 1-8.281-.5-8.281-7-7.781-7.5.423-.424 2.44 1.666 6.564 3.53-9.126-4.314-6.453-11.956-5.064-11.03 3.344 3 9.5 8.5 15 13 .658.538 1 2 0 3.25s-2.5 2.75-3 3.25h2.5z"
1149
+ })]
1150
+ });
1151
+ if (brand === "feishu" || brand === "lark") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1152
+ className: "dcu-wb-brand",
1153
+ viewBox: "0 0 48 48",
1154
+ width: 16,
1155
+ height: 16,
1156
+ "aria-hidden": "true",
1157
+ children: [
1158
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1159
+ fill: "#00d6b9",
1160
+ d: "M10 8c0 1 7 3.5 14.745 16.744 0 0 4.184-4.363 6.255-5.744 1.5-1 2.712-1.332 2.712-1.332C33.712 15.156 29.5 8 28 8z"
1161
+ }),
1162
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1163
+ fill: "#163c9a",
1164
+ d: "M43.5 18.5c-1-.667-3.65-1.771-6.5-1.5a15 15 0 0 0-3.288.668S32.5 18 31 19c-2.07 1.38-6.255 5.744-6.255 5.744-1.428 1.397-3.05 2.732-5.245 3.756 0 0 7 3 11.5 3 5.063 0 7-3.5 7-3.5 1.5-3.305 3.5-7 5.5-9.5"
1165
+ }),
1166
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1167
+ fill: "#3370ff",
1168
+ d: "M4 17.5v17c0 1 6 5.5 15 5.5 10 0 17.05-7.705 19-12 0 0-1.937 3.5-7 3.5-4.5 0-11.5-3-11.5-3-5.117-2.239-10.03-6.577-12.906-9.117C4.974 17.953 4 17.093 4 17.5"
1169
+ })
1170
+ ]
1171
+ });
1172
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1173
+ className: "dcu-wb-brand",
1174
+ viewBox: "0 0 16 16",
1175
+ width: 16,
1176
+ height: 16,
1177
+ "aria-hidden": "true",
1178
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1179
+ cx: "8",
1180
+ cy: "8",
1181
+ r: "7",
1182
+ fill: "#8b949e"
1183
+ })
1184
+ });
1185
+ }
1186
+ //#endregion
1187
+ //#region src/client/channel-api.ts
1188
+ const CHANNELS_ENDPOINT = "/api/dsh-im-connect/channels";
1189
+ /** DSH 会话头不能写 origin=im,频道会话只靠 id 前缀。 */
1190
+ function isChannelSession(id) {
1191
+ return id.startsWith("im:");
1192
+ }
1193
+ function text(value, fallback = "") {
1194
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : fallback;
1195
+ }
1196
+ function updatedAt(value) {
1197
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1198
+ if (typeof value === "string" && value !== "") {
1199
+ const parsed = Date.parse(value);
1200
+ if (Number.isFinite(parsed)) return parsed;
1201
+ }
1202
+ }
1203
+ function parseChannelSession(value) {
1204
+ if (value === null || typeof value !== "object") return void 0;
1205
+ const row = value;
1206
+ const sessionId = text(row.sessionId);
1207
+ if (sessionId === "") return void 0;
1208
+ return {
1209
+ sessionId,
1210
+ title: text(row.title) || text(row.chatId) || sessionId,
1211
+ updatedAt: updatedAt(row.updatedAt),
1212
+ running: row.running === true
1213
+ };
1214
+ }
1215
+ function parseChannelGroups(payload, fallbackLabel = "") {
1216
+ const root = payload !== null && typeof payload === "object" ? payload : {};
1217
+ return (Array.isArray(root.groups) ? root.groups : Array.isArray(payload) ? payload : []).flatMap((item, index) => {
1218
+ if (item === null || typeof item !== "object") return [];
1219
+ const group = item;
1220
+ const sessions = Array.isArray(group.sessions) ? group.sessions.flatMap((session) => {
1221
+ const parsed = parseChannelSession(session);
1222
+ return parsed === void 0 ? [] : [parsed];
1223
+ }) : [];
1224
+ return [{
1225
+ id: text(group.id, `channel-${index}`),
1226
+ label: text(group.label, text(group.title, fallbackLabel)),
1227
+ sessions
1228
+ }];
1229
+ });
1230
+ }
1231
+ /** 读取 IM 频道分组;失败时交给界面显示空态或错误。 */
1232
+ async function loadChannelGroups(signal, fallbackLabel = "") {
1233
+ const response = await fetch(CHANNELS_ENDPOINT, {
1234
+ cache: "no-store",
1235
+ signal
1236
+ });
1237
+ let payload;
1238
+ try {
1239
+ payload = await response.json();
1240
+ } catch {
1241
+ throw new Error(response.ok ? "频道会话数据格式无效" : "无法读取频道会话");
1242
+ }
1243
+ const root = payload !== null && typeof payload === "object" ? payload : {};
1244
+ if (!response.ok) throw new Error(text(root.error, "无法读取频道会话"));
1245
+ if (root.ok === false) throw new Error(text(root.error, "无法读取频道会话"));
1246
+ return parseChannelGroups(payload, fallbackLabel);
1247
+ }
1248
+ //#endregion
1190
1249
  //#region src/client/session-tree.tsx
1191
1250
  function PinIcon() {
1192
1251
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pin, {
@@ -1864,39 +1923,21 @@ window.__ModuleLoader__.load({
1864
1923
  }
1865
1924
  //#endregion
1866
1925
  //#region src/client/conversation-bubbles.ts
1867
- /** 撤回旧版 Codex 用户卡片,恢复 DSH 官方问题气泡。 */
1926
+ /** 撤回旧版用户卡片和长文本展开覆盖,恢复 DSH 官方气泡。 */
1868
1927
  const USER_BUBBLE_STYLE_ID = "dcu-user-bubble-style";
1869
1928
  const USER_BUBBLE_EXPAND_STYLE_ID = "dcu-user-bubble-expand-style";
1870
- const USER_BUBBLE_EXPAND_STYLE = `
1871
- [data-time-hover-root]:not([data-turn-tail]),[data-time-hover-root]:not([data-turn-tail])>:first-child{overflow:visible!important}
1872
- [data-dcu-expandable-user-bubble]{max-height:none!important;overflow:visible!important;display:block!important;white-space:pre-wrap!important;overflow-wrap:anywhere!important;word-break:break-word!important;text-overflow:clip!important;-webkit-line-clamp:unset!important;-webkit-box-orient:initial!important}
1873
- `;
1874
- function ensureExpandableStyle(doc) {
1875
- if (doc.getElementById("dcu-user-bubble-expand-style") !== null) return;
1876
- const style = doc.createElement("style");
1877
- style.id = USER_BUBBLE_EXPAND_STYLE_ID;
1878
- style.textContent = USER_BUBBLE_EXPAND_STYLE;
1879
- doc.head.append(style);
1880
- }
1881
- function matchingElements(root, selector) {
1882
- const items = [...root.querySelectorAll(selector)];
1883
- if (root instanceof HTMLElement && root.matches(selector)) items.unshift(root);
1884
- return items;
1885
- }
1886
- function markExpandableUserBubbles(root) {
1887
- for (const row of matchingElements(root, "[data-time-hover-root]:not([data-turn-tail])")) {
1888
- const bubble = row.firstElementChild?.lastElementChild;
1889
- if (!(bubble instanceof HTMLElement) || bubble.textContent?.trim() === "") continue;
1890
- bubble.dataset.dcuExpandableUserBubble = "";
1891
- }
1892
- }
1893
1929
  function restoreOfficialUserBubbles(root) {
1894
1930
  const doc = "getElementById" in root ? root : root.ownerDocument;
1895
1931
  doc?.getElementById(USER_BUBBLE_STYLE_ID)?.remove();
1896
- if (doc !== void 0 && doc !== null && doc.head !== null) ensureExpandableStyle(doc);
1932
+ doc?.getElementById(USER_BUBBLE_EXPAND_STYLE_ID)?.remove();
1897
1933
  for (const card of root.querySelectorAll("[data-dcu-user-card]")) card.remove();
1898
- for (const source of root.querySelectorAll("[data-dcu-user-source]")) delete source.dataset.dcuUserSource;
1899
- markExpandableUserBubbles(root);
1934
+ const selector = "[data-dcu-user-source],[data-dcu-expandable-user-bubble]";
1935
+ const sources = [...root.querySelectorAll(selector)];
1936
+ if (root instanceof HTMLElement && root.matches(selector)) sources.unshift(root);
1937
+ for (const source of sources) {
1938
+ source.removeAttribute("data-dcu-user-source");
1939
+ source.removeAttribute("data-dcu-expandable-user-bubble");
1940
+ }
1900
1941
  }
1901
1942
  //#endregion
1902
1943
  //#region src/client/conversation-header.ts
@@ -1911,6 +1952,8 @@ header:has([data-dcu-inline-tabs]) [class*="crumbs"]{order:1;flex:1;min-width:0}
1911
1952
  header:has([data-dcu-inline-tabs]) [class*="headerActions"]{order:2;flex:none}
1912
1953
  header [data-dcu-inline-tabs]{box-sizing:border-box;order:3;flex:none;display:flex;align-items:center;gap:0;margin:0;padding:0;height:28px;position:relative;z-index:1;overflow:hidden;border:1px solid var(--dsw-alias-border-subtle,rgba(255,255,255,.12));border-radius:8px;background:var(--dsw-alias-background-secondary,rgba(255,255,255,.025))}
1913
1954
  header:has([data-dcu-inline-tabs]) [class*="headerUtilities"]{order:4;flex:none}
1955
+ /* 新版角落插槽被 display:contents 摊平后,需要独立排序并撤销嵌套布局的边距补偿。 */
1956
+ header:has([data-dcu-inline-tabs]) [data-conversation-header-corner]{order:5;flex:none;margin-left:0;margin-right:0}
1914
1957
  header [data-dcu-tab-slider]{position:absolute;left:0;top:0;height:26px;border-radius:7px;background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#4c8dff) 18%,transparent);pointer-events:none;z-index:0;opacity:0;transform:translateX(0);width:0;transition:transform 240ms cubic-bezier(.16,1,.3,1),width 240ms cubic-bezier(.16,1,.3,1),opacity 160ms ease}
1915
1958
  /* 顶栏统一使用 34px 控件带:与宿主扩展常用的 top:3px + 28px 图标按钮同心。
1916
1959
  better-sidebar 0.18.0 收起时会把开关组改到 14px(按官方 padding-top:12px 算),
@@ -1921,12 +1964,7 @@ header [data-dcu-inline-tabs] [role=tab]{box-sizing:border-box;position:relative
1921
1964
  header [data-dcu-inline-tabs] [role=tab][aria-selected=true],header [data-dcu-inline-tabs] [role=tab][data-state=active]{color:var(--dsw-alias-button-info-fill,#4c8dff);font-weight:500}
1922
1965
  header [data-dcu-inline-tabs] [role=tab]+[role=tab]{border-left:1px solid var(--dsw-alias-border-subtle,rgba(255,255,255,.08))}
1923
1966
  header [data-dcu-inline-tabs] [role=tab]:after,header [data-dcu-inline-tabs] [role=tab]:before{display:none!important;content:none!important;background:transparent!important;height:0!important}
1924
- header [data-dcu-inline-tabs] [role=tab]:focus-visible,header [data-dcu-session-log-download]:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#4c8dff);outline-offset:-2px}
1925
- header [data-dcu-session-log-download]{appearance:none;min-width:28px;width:28px;height:28px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary,currentColor);display:inline-grid;place-items:center;cursor:pointer}
1926
- header [data-dcu-session-log-download]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,currentColor)}
1927
- header [data-dcu-session-log-download]:disabled{color:var(--dsw-alias-label-dimmed,currentColor);cursor:wait}
1928
- header [data-dcu-session-log-download] > span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
1929
- header [data-dcu-session-log-download] svg{width:16px;height:16px;flex:none}
1967
+ header [data-dcu-inline-tabs] [role=tab]:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#4c8dff);outline-offset:-2px}
1930
1968
  header [data-dcu-title-folder],header [data-dcu-title-more]{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-tertiary,currentColor);display:inline-grid;place-items:center;padding:0;cursor:pointer;border-radius:4px}
1931
1969
  header [data-dcu-title-folder]{width:16px;height:20px}
1932
1970
  header [data-dcu-title-more]{width:20px;height:20px}
@@ -1946,18 +1984,6 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1946
1984
  tabs.dataset.dcuInlineTabs = "";
1947
1985
  return true;
1948
1986
  }
1949
- /** 把宿主的 Session log 胶囊标记成紧凑下载按钮;保留文本供无障碍名称使用。 */
1950
- function decorateSessionLogDownload(root) {
1951
- const button = root.querySelector("header [class*=\"headerUtilities\"] button[class*=\"sessionLogButton\"]");
1952
- if (button === null || button.dataset.dcuSessionLogDownload === "") return false;
1953
- button.dataset.dcuSessionLogDownload = "";
1954
- const label = button.querySelector("span")?.textContent?.trim();
1955
- if (label !== void 0 && label !== "") {
1956
- if (!button.hasAttribute("aria-label")) button.setAttribute("aria-label", label);
1957
- if (!button.hasAttribute("title")) button.setAttribute("title", label);
1958
- }
1959
- return true;
1960
- }
1961
1987
  function emit(name, target, extra = {}) {
1962
1988
  const box = target.getBoundingClientRect();
1963
1989
  target.dispatchEvent(new CustomEvent(name, {
@@ -2104,7 +2130,6 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2104
2130
  }
2105
2131
  syncTabSlider(doc);
2106
2132
  decorateConversationTitle(doc);
2107
- decorateSessionLogDownload(doc);
2108
2133
  }
2109
2134
  } finally {
2110
2135
  applying = false;
@@ -5342,6 +5367,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5342
5367
  document.removeEventListener("visibilitychange", onVisibilityChange);
5343
5368
  };
5344
5369
  }, [t]);
5370
+ const archived = new Set(workspaces?.archivedSessionIds ?? []);
5371
+ const visibleGroups = groups.map((group) => ({
5372
+ ...group,
5373
+ sessions: group.sessions.filter((session) => !archived.has(session.sessionId))
5374
+ })).filter((group) => group.sessions.length > 0);
5345
5375
  const banner = pollError ?? error;
5346
5376
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5347
5377
  className: "dcu-wb",
@@ -5357,11 +5387,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5357
5387
  role: "alert",
5358
5388
  children: banner
5359
5389
  }),
5360
- pollError === void 0 && groups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5390
+ pollError === void 0 && visibleGroups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5361
5391
  className: "dcu-wb-empty",
5362
5392
  children: t("channels.empty")
5363
5393
  }),
5364
- groups.map((group) => {
5394
+ visibleGroups.map((group) => {
5365
5395
  const isExpanded = expanded[group.id] ?? true;
5366
5396
  const label = channelLabel(group.id, group.label, t);
5367
5397
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -6034,9 +6064,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
6034
6064
  const COMPOSER_TOOL_MENU_STYLE = `
6035
6065
  [class*="_heroWorkspaceRow"] button{min-height:28px;border-radius:999px;font-size:13px;line-height:20px}
6036
6066
  [class*="_heroWorkspaceRow"] button:hover,[class*="_heroWorkspaceRow"] button[aria-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 8%,transparent)}
6037
- :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]){box-sizing:border-box;min-width:0!important;width:262px;max-width:calc(100vw - 24px);max-height:var(--dcu-tool-menu-height,360px)!important;padding:5px!important;border-radius:18px!important;background:#fff!important;color:var(--dsw-alias-label-primary);box-shadow:0 8px 32px #0002,0 0 0 1px #0000000a!important;display:flex;flex-direction:column;gap:0;z-index:1100}
6067
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]){box-sizing:border-box;max-height:var(--dcu-tool-menu-height,360px)!important;padding:5px!important;border-radius:18px!important;background:#fff!important;color:var(--dsw-alias-label-primary);box-shadow:0 8px 32px #0002,0 0 0 1px #0000000a!important;display:flex;flex-direction:column;gap:0;z-index:1100}
6068
+ /* 原生菜单保留宿主宽度约束;Git 弹窗沿用独立尺寸,避免观察器标记前后跳变。 */
6069
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover])[data-gitgraph-popover]{min-width:0!important;width:262px;max-width:calc(100vw - 24px)}
6070
+ :is([data-dcu-tool-menu=inline],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal]))[data-gitgraph-popover]{width:320px}
6038
6071
  [data-dcu-tool-menu=portal]{position:fixed!important;left:var(--dcu-tool-menu-x)!important;top:var(--dcu-tool-menu-y)!important;bottom:auto!important;right:auto!important}
6039
- :is([data-dcu-tool-menu=inline],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal])){width:320px;translate:var(--dcu-tool-menu-shift,0px) 0}
6072
+ :is([data-dcu-tool-menu=inline],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal])){translate:var(--dcu-tool-menu-shift,0px) 0}
6040
6073
  [class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal]){top:auto!important;bottom:calc(100% + 4px)!important}
6041
6074
  body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]){background:#292929!important;box-shadow:0 8px 32px #0003,0 0 0 1px #ffffff08!important}
6042
6075
  :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover])>[class*="_viewport"]{min-height:0;max-height:none;overflow-y:auto;scrollbar-width:thin}
@@ -6048,6 +6081,12 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6048
6081
  [data-dcu-tool-filter]:focus-visible{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dsw-alias-label-primary) 20%,transparent)}
6049
6082
  [data-dcu-tool-empty]{padding:8px 10px;font-size:13px;color:var(--dsw-alias-label-secondary)}
6050
6083
  [data-dcu-tool-filtered]{display:none!important}
6084
+ /* 建议菜单单独换肤:外框跟随宿主输入区,保留宿主定位和动态高度,不给内部列表套固定宽度。 */
6085
+ [data-conversation-scroll] [data-trigger-menu]{box-sizing:border-box;left:0;right:0;width:auto;min-width:0;max-width:none;padding:5px;border-radius:18px;background:#fff;box-shadow:0 8px 32px #0002,0 0 0 1px #0000000a}
6086
+ body[data-ds-dark-theme] [data-conversation-scroll] [data-trigger-menu]{background:#292929;box-shadow:0 8px 32px #0003,0 0 0 1px #ffffff08}
6087
+ [data-conversation-scroll] [data-trigger-menu]>[role=listbox]{box-sizing:border-box;width:100%;min-width:0;align-self:stretch;scrollbar-width:thin}
6088
+ [data-conversation-scroll] [data-trigger-menu] [role=option]{box-sizing:border-box;width:100%;min-width:0;min-height:28px;padding:4px 9px;gap:8px;border-radius:8px;font-size:13px;line-height:20px}
6089
+ [data-conversation-scroll] [data-trigger-menu] [role=option][aria-selected=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 10%,transparent)}
6051
6090
  `;
6052
6091
  function observeComposerToolMenus(copy) {
6053
6092
  let anchor;
@@ -6154,6 +6193,7 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6154
6193
  }
6155
6194
  if (anchor === void 0 || now() > pendingUntil) return;
6156
6195
  for (const menu of document.querySelectorAll(MENU)) {
6196
+ if (menu.closest("[data-trigger-menu]") !== null) continue;
6157
6197
  if (known.has(menu) || mounted.has(menu) || menu.parentElement?.closest(MENU) !== null) continue;
6158
6198
  if (menu.getClientRects().length === 0) continue;
6159
6199
  mount(menu, anchor);
@@ -6346,7 +6386,12 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6346
6386
  [EXTENSIONS_EXPANSION_KEY]: open
6347
6387
  });
6348
6388
  }
6389
+ const emptyPanels = [];
6390
+ const getEmptyPanels = () => emptyPanels;
6391
+ const useLegacyPanelInfo = (selector) => selector({ activePanelId: null });
6349
6392
  const stylesheet$3 = `
6393
+ .dcu-global-panel[aria-current=page]{background:var(--dcu-sidebar-hover);font-weight:600}
6394
+
6350
6395
  .dcu-root{--dcu-font:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei UI",sans-serif;--dcu-sidebar-background:#eef7f5;--dcu-sidebar-primary:#393d3e;--dcu-sidebar-secondary:#676b6c;--dcu-sidebar-tertiary:#9a9f9f;--dcu-sidebar-navigation:#4e5253;--dcu-sidebar-icon:#4e5253;--dcu-sidebar-hover:#dfe8e5;--dcu-sidebar-border:rgba(37,46,41,.10);--dcu-tip-bg:#ffffff;--dcu-tip-shadow:0 10px 32px rgba(31,39,36,.22);width:100%;height:100%;min-width:0;box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden;background:var(--dcu-sidebar-background);color:var(--dcu-sidebar-primary);font:14px/20px var(--dcu-font)}body[data-ds-dark-theme] .dcu-root{--dcu-sidebar-background:#1d2120;--dcu-sidebar-primary:#b9bab9;--dcu-sidebar-secondary:#909191;--dcu-sidebar-tertiary:#666867;--dcu-sidebar-navigation:#b9bab9;--dcu-sidebar-icon:#afafaf;--dcu-sidebar-hover:#303432;--dcu-sidebar-border:rgba(255,255,255,.08);--dcu-tip-bg:#2a2a2a;--dcu-tip-shadow:0 10px 30px rgba(0,0,0,.28)}
6351
6396
  /* 滤镜只作用于背景,避免为设置和搜索等 fixed 后代创建侧栏包含块。 */
6352
6397
  body[data-we-sidebar-glass] .dcu-root{position:relative;background:transparent}body[data-we-sidebar-glass] .dcu-root::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;background-color:color-mix(in srgb,var(--we-sidebar-color,#fff) calc(var(--we-sidebar-alpha,.15)*.66*100%),transparent);background-image:linear-gradient(180deg,rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.14)),rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.04)) 38%,rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.01)));-webkit-backdrop-filter:blur(var(--we-sidebar-blur,16px)) saturate(var(--we-sidebar-saturate,1.8)) brightness(var(--we-glass-brightness,1.04)) contrast(1.01);backdrop-filter:blur(var(--we-sidebar-blur,16px)) saturate(var(--we-sidebar-saturate,1.8)) brightness(var(--we-glass-brightness,1.04)) contrast(1.01);box-shadow:inset 0 1px 0 rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.32)),inset 0 -1px 0 rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.08)),inset 0 0 0 .5px rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.06))}body[data-ds-dark-theme][data-we-sidebar-glass] .dcu-root::before{background-color:color-mix(in srgb,var(--we-sidebar-color,#fff) calc(var(--we-sidebar-alpha,.15)*.33*100%),transparent)}body[data-we-appwindow][data-we-sidebar-glass] .dcu-root::before{-webkit-backdrop-filter:none;backdrop-filter:none}@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){body[data-we-sidebar-glass] .dcu-root{background:#eef7f5}body[data-ds-dark-theme][data-we-sidebar-glass] .dcu-root{background:#1d2120}body[data-we-sidebar-glass] .dcu-root::before{display:none}}
@@ -6398,6 +6443,8 @@ body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu
6398
6443
  [data-conversation-scroll]{--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:24px;--dcu-composer-bg:var(--dsw-specific-input-major,#fff);--dcu-composer-shadow:0 0 0 1px #0000000a,0 2px 8px #0000000a,0 4px 80px 8px #00000006}
6399
6444
  body[data-ds-dark-theme] [data-conversation-scroll]{--dcu-composer-bg:var(--dsw-alias-bg-layer-2,#242424);--dcu-composer-shadow:inset 0 0 1px #fff3}
6400
6445
  [data-conversation-scroll] [data-composer-card]{padding-top:8px;gap:4px;border:0;border-radius:20px;background:var(--dcu-composer-bg);box-shadow:var(--dcu-composer-shadow)}
6446
+ /* 官方附件轨道用 -6px 抵消 12px 行间距;本皮肤为 4px,改为 +2px 保留附件到正文的 6px。 */
6447
+ [data-conversation-scroll] [data-composer-card]>[data-slot="conversation.input.attachments"]>:is([class$="_rail"],[class*="_rail_"]){margin-bottom:2px}
6401
6448
  [data-conversation-scroll] [data-input-mirror]{min-height:44px}
6402
6449
  [data-conversation-scroll] [data-composer-card] [data-input-scroll]{margin-right:0}
6403
6450
  [data-conversation-scroll] [data-input-scroll] [data-lexical-editor=true]{min-height:44px;padding:0 12px}
@@ -6414,9 +6461,8 @@ body[data-ds-dark-theme] [data-conversation-scroll]{--dcu-composer-bg:var(--dsw-
6414
6461
  @media(forced-colors:active){[data-conversation-scroll] [data-composer-card]{outline:1px solid CanvasText}}
6415
6462
  html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:has([data-dcu-official-turn-navigator]) .dcu-turn-navigator{display:none}
6416
6463
  [data-dcu-official-turn-navigator]{right:auto!important;left:calc(12px - (var(--dsh-composer-side-clearance) + 16px))!important}
6417
- [data-dcu-official-turn-mark]{inset:0 auto 0 0!important}
6418
- [data-dcu-official-turn-mark]:before{right:auto!important;left:0!important}
6419
- [data-dcu-official-turn-tooltip]{right:auto!important;left:calc(100% + 10px)!important;animation:none!important}
6464
+ /* 左移后的预览朝聊天内容区展开,外观和动画继续使用宿主规则。 */
6465
+ [data-dcu-official-turn-navigator] [role=tooltip]{right:auto!important;left:calc(100% + 10px)!important}
6420
6466
  `;
6421
6467
  function MenuIcon({ children }) {
6422
6468
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -6726,7 +6772,20 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6726
6772
  });
6727
6773
  });
6728
6774
  /** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
6729
- function CodexSidebar({ collapsed, width, openSession, startSession, toggleSidebar, archiveSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
6775
+ function CodexSidebar({ globalPanels, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
6776
+ const panels = (0, react.useSyncExternalStore)(globalPanels?.subscribe ?? subscribeEmptyCompanionTabs, globalPanels?.getSnapshot ?? getEmptyPanels, globalPanels?.getSnapshot ?? getEmptyPanels);
6777
+ const activePanelId = usePanelInfo((info) => info.activePanelId);
6778
+ const panelButtons = (wide) => selectPanel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalPanelButtons, {
6779
+ panels,
6780
+ activeId: activePanelId,
6781
+ wide,
6782
+ conversationLabel: t("sidebar.tasksTab"),
6783
+ selectPanel,
6784
+ renderIcon: (id, active) => renderSlot("sidebar.panellist", {
6785
+ size: 16,
6786
+ active
6787
+ }, { only: id })
6788
+ });
6730
6789
  const compact = collapsed || width < 80;
6731
6790
  const [visualCompact, setVisualCompact] = (0, react.useState)(compact);
6732
6791
  const [collapsing, setCollapsing] = (0, react.useState)(false);
@@ -6946,6 +7005,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6946
7005
  className: "dcu-menu",
6947
7006
  "aria-label": t("sidebar.mainMenu"),
6948
7007
  children: [
7008
+ panelButtons(true),
6949
7009
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6950
7010
  type: "button",
6951
7011
  onClick: () => {
@@ -7124,6 +7184,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7124
7184
  className: "dcu-compact-nav",
7125
7185
  "aria-label": t("sidebar.mainMenu"),
7126
7186
  children: [
7187
+ panelButtons(false),
7127
7188
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7128
7189
  type: "button",
7129
7190
  className: "dcu-icon",
@@ -7640,8 +7701,14 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7640
7701
  const stylesheet$1 = `
7641
7702
  .dcu-connectors{color:var(--dsw-alias-label-primary)}.dcu-connectors h2{margin:0;font-size:18px}.dcu-connectors p{margin:6px 0 18px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-frame{display:block;width:100%;height:clamp(420px,calc(100vh - 160px),700px);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-base);color-scheme:light dark}.dcu-connector-list{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:9px}.dcu-connector{padding:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dcu-connector:last-child{border-bottom:0}.dcu-connector-head{display:flex;align-items:center;gap:8px;font-weight:650}.dcu-connector-meta{margin:3px 0 8px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-tool{padding:5px 0 0 24px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-tool span{display:block;margin-top:1px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-empty{padding:20px 8px;color:var(--dsw-alias-label-secondary);text-align:center}
7642
7703
  `;
7643
- const frameLightTheme = `:root{color-scheme:light;--bg:#f8f9fb;--card:#fff;--line:#e5e7eb;--text:#111827;--text-2:#4b5563;--muted:#9ca3af;--accent:#4f46e5;--accent-hover:#4338ca;--accent-light:#eef2ff;--ok:#059669;--ok-bg:#ecfdf5;--warn:#d97706;--warn-bg:#fffbeb;--bad:#dc2626;--bad-bg:#fef2f2;--shadow:0 1px 3px rgba(0,0,0,.08),0 1px 2px rgba(0,0,0,.06);--shadow-lg:0 10px 25px rgba(0,0,0,.1)}`;
7644
- const frameDarkTheme = `:root{color-scheme:dark;--bg:#111318;--card:#1b1e25;--line:#30343d;--text:#f3f4f6;--text-2:#c4c8d0;--muted:#8e96a3;--accent:#818cf8;--accent-hover:#6366f1;--accent-light:#252750;--ok:#34d399;--ok-bg:#0d3027;--warn:#fbbf24;--warn-bg:#35280b;--bad:#f87171;--bad-bg:#3b171b;--shadow:0 1px 3px rgba(0,0,0,.35);--shadow-lg:0 16px 35px rgba(0,0,0,.45)}`;
7704
+ const frameLightTheme = `:root{color-scheme:light;--bg:#fff;--card:#fafafa;--line:#e5e5e5;--text:#303030;--text-2:#737373;--muted:#767676;--accent:#303030;--accent-hover:#171717;--accent-light:#e9e9e9;--dcu-action:#303030;--dcu-action-hover:#171717;--dcu-on-action:#fff;--ok:#059669;--ok-bg:#ecfdf5;--warn:#d97706;--warn-bg:#fffbeb;--bad:#dc2626;--bad-bg:#fef2f2;--shadow:0 1px 3px rgba(0,0,0,.08),0 1px 2px rgba(0,0,0,.06);--shadow-lg:0 10px 25px rgba(0,0,0,.1)}`;
7705
+ const frameDarkTheme = `:root{color-scheme:dark;--bg:#181818;--card:#232323;--line:#333;--text:#dedede;--text-2:#a1a1a1;--muted:#929292;--accent:#dedede;--accent-hover:#fff;--accent-light:#303332;--dcu-action:#383838;--dcu-action-hover:#454545;--dcu-on-action:#eee;--ok:#34d399;--ok-bg:#0d3027;--warn:#fbbf24;--warn-bg:#35280b;--bad:#f87171;--bad-bg:#3b171b;--shadow:0 1px 3px rgba(0,0,0,.35);--shadow-lg:0 16px 35px rgba(0,0,0,.45)}`;
7706
+ const frameSurfaceTheme = `
7707
+ .card.featured{border-color:var(--line)}
7708
+ .card:hover,.card.featured:hover{border-color:var(--muted)}
7709
+ .btn:not(.ghost):not(.danger):not(.status-warning):not(.status-bad),.icon-btn.primary,.btn-primary,.prompt-item .send-btn{background:var(--dcu-action);border-color:var(--dcu-action);color:var(--dcu-on-action)}
7710
+ .btn:not(.ghost):not(.danger):not(.status-warning):not(.status-bad):hover,.icon-btn.primary:hover,.btn-primary:hover,.prompt-item .send-btn:hover{background:var(--dcu-action-hover);border-color:var(--dcu-action-hover)}
7711
+ `;
7645
7712
  function isConnector(value) {
7646
7713
  if (value === null || typeof value !== "object") return false;
7647
7714
  const item = value;
@@ -7661,7 +7728,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7661
7728
  style.dataset.michengaiHostTheme = "true";
7662
7729
  doc.head.append(style);
7663
7730
  }
7664
- style.textContent = document.body.hasAttribute("data-ds-dark-theme") ? frameDarkTheme : frameLightTheme;
7731
+ style.textContent = (document.body.hasAttribute("data-ds-dark-theme") ? frameDarkTheme : frameLightTheme) + frameSurfaceTheme;
7665
7732
  }
7666
7733
  function ConnectorMarket({ startPromptSession, t }) {
7667
7734
  const frameRef = (0, react.useRef)(null);
@@ -7846,14 +7913,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7846
7913
  "home.fix.prompt1": "我遇到了一个问题。先问我复现步骤、预期和实际表现,再定位根因并修复。",
7847
7914
  "home.fix.task2": "修复失败的测试",
7848
7915
  "home.fix.prompt2": "请运行当前项目适用的测试,定位失败根因并做最小修复,保留有效的回归覆盖。",
7849
- "host.transcript.normal": "标准",
7850
- "host.transcript.compact": "紧凑",
7851
- "host.command.compact": "压缩较早的对话历史",
7852
- "host.command.export": "将当前会话日志下载为 ZIP 压缩包",
7853
- "host.command.feedback": "记录对当前会话的反馈",
7854
- "host.command.goal": "设置或查看长时间任务的目标",
7855
- "host.command.permission": "切换权限预设(沙箱模式与审批策略)",
7856
- "host.command.plan": "进入或退出计划模式",
7857
7916
  "usage.title": "使用统计",
7858
7917
  "usage.loading": "正在加载费用面板…",
7859
7918
  "usage.failed": "费用面板暂时无法嵌入,可重试或打开原弹窗。",
@@ -8123,14 +8182,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8123
8182
  "home.fix.prompt1": "Help me fix a bug. First ask for reproduction steps, expected behavior, and actual behavior.",
8124
8183
  "home.fix.task2": "Fix failing tests",
8125
8184
  "home.fix.prompt2": "Run the applicable project tests, identify failure causes, and make minimal fixes with meaningful regression coverage.",
8126
- "host.transcript.normal": "Normal",
8127
- "host.transcript.compact": "Compact",
8128
- "host.command.compact": "Compact older conversation history",
8129
- "host.command.export": "Download this Session log as a ZIP archive",
8130
- "host.command.feedback": "record feedback about this session",
8131
- "host.command.goal": "set or view the goal for a long-running task",
8132
- "host.command.permission": "Switch the permission preset (sandbox mode + approval policy)",
8133
- "host.command.plan": "Enter or leave plan mode",
8134
8185
  "usage.title": "Usage statistics",
8135
8186
  "usage.loading": "Loading billing dashboard…",
8136
8187
  "usage.failed": "The embedded dashboard is unavailable. Retry or open the original dialog.",
@@ -8812,7 +8863,7 @@ html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page) :is([inert
8812
8863
  body:has(.dcu-settings-page) :is([data-dcu-settings-isolated],[data-dcu-settings-isolated] *){visibility:hidden!important}
8813
8864
  html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page){background:transparent}
8814
8865
 
8815
- .dcu-settings-inner:has(.dcu-usage-section){width:100%;height:100%;max-width:1280px;display:flex;flex-direction:column;padding-bottom:0}
8866
+ .dcu-settings-inner:has(.dcu-usage-section){height:100%;display:flex;flex-direction:column;padding-bottom:0}
8816
8867
  .dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
8817
8868
  .dcu-settings-inner:has(.dcu-usage-section)>[data-slot="settings.section"]{display:flex;flex:1;min-height:0;flex-direction:column}
8818
8869
  .dcu-usage-section{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px}
@@ -9395,224 +9446,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9395
9446
  }, CodexGeneralSettings));
9396
9447
  }
9397
9448
  //#endregion
9398
- //#region src/client/permission-labels.ts
9399
- const PERMISSION_LABELS = [
9400
- {
9401
- aliases: [
9402
- "Read Only",
9403
- "preset.readOnly",
9404
- "只读"
9405
- ],
9406
- en: "Read Only",
9407
- zh: "只读"
9408
- },
9409
- {
9410
- aliases: [
9411
- "Workspace Write",
9412
- "preset.workspaceWrite",
9413
- "工作区写入"
9414
- ],
9415
- en: "Workspace Write",
9416
- zh: "工作区写入"
9417
- },
9418
- {
9419
- aliases: [
9420
- "Full access",
9421
- "preset.fullAccess",
9422
- "完全访问"
9423
- ],
9424
- en: "Full access",
9425
- zh: "完全访问"
9426
- }
9427
- ];
9428
- const INTERACTIVE_SELECTOR = "button, [role=\"menuitem\"], [role=\"menuitemradio\"], [role=\"option\"]";
9429
- function targetLabel(value, activeLocale) {
9430
- const definition = PERMISSION_LABELS.find((item) => item.aliases.includes(value));
9431
- if (definition === void 0) return void 0;
9432
- return activeLocale.toLowerCase().startsWith("zh") ? definition.zh : definition.en;
9433
- }
9434
- function applyPermissionLabel(element, activeLocale) {
9435
- const document = element.ownerDocument;
9436
- const showText = document.defaultView?.NodeFilter.SHOW_TEXT ?? 4;
9437
- const walker = document.createTreeWalker(element, showText);
9438
- let changed = false;
9439
- let node = walker.nextNode();
9440
- while (node !== null) {
9441
- const value = node.nodeValue ?? "";
9442
- const trimmed = value.trim();
9443
- const next = targetLabel(trimmed, activeLocale);
9444
- if (next !== void 0 && next !== trimmed) {
9445
- node.nodeValue = value.replace(trimmed, next);
9446
- changed = true;
9447
- }
9448
- node = walker.nextNode();
9449
- }
9450
- return changed;
9451
- }
9452
- /** 只修正权限选择控件里的内置预设名称,不改动正文或自定义权限名称。 */
9453
- function localizePermissionLabels(root, activeLocale) {
9454
- let changed = 0;
9455
- const rootElement = root.nodeType === 1 ? root : void 0;
9456
- const elements = rootElement?.matches(INTERACTIVE_SELECTOR) === true ? [rootElement, ...rootElement.querySelectorAll(INTERACTIVE_SELECTOR)] : [...root.querySelectorAll(INTERACTIVE_SELECTOR)];
9457
- for (const element of elements) if (applyPermissionLabel(element, activeLocale)) changed += 1;
9458
- return changed;
9459
- }
9460
- /** 兼容宿主设置页和 Chat 中由官方组件直接输出的英文权限名称。 */
9461
- function observePermissionLabels(locale) {
9462
- if (typeof document === "undefined" || document.body === null) return () => {};
9463
- let applying = false;
9464
- let frame;
9465
- const pendingRoots = /* @__PURE__ */ new Set([document]);
9466
- const apply = () => {
9467
- if (applying) return;
9468
- applying = true;
9469
- const active = [
9470
- locale.getSnapshot?.().active,
9471
- document.documentElement.lang,
9472
- window.navigator.language
9473
- ].find((value) => typeof value === "string" && value.trim() !== "") ?? "zh";
9474
- const roots = [...pendingRoots];
9475
- pendingRoots.clear();
9476
- try {
9477
- for (const root of roots) localizePermissionLabels(root, active);
9478
- } finally {
9479
- applying = false;
9480
- }
9481
- };
9482
- const schedule = () => {
9483
- if (frame !== void 0) return;
9484
- frame = window.requestAnimationFrame(() => {
9485
- frame = void 0;
9486
- apply();
9487
- });
9488
- };
9489
- apply();
9490
- const observer = new MutationObserver((records) => {
9491
- for (const record of records) {
9492
- const control = (record.target.nodeType === 1 ? record.target : record.target.parentElement)?.closest(INTERACTIVE_SELECTOR);
9493
- if (control !== null && control !== void 0) pendingRoots.add(control);
9494
- for (const node of record.addedNodes) {
9495
- if (!(node instanceof Element)) continue;
9496
- if (node.matches(INTERACTIVE_SELECTOR) || node.querySelector(INTERACTIVE_SELECTOR) !== null) pendingRoots.add(node);
9497
- }
9498
- }
9499
- if (pendingRoots.size > 0) schedule();
9500
- });
9501
- observer.observe(document.body, {
9502
- childList: true,
9503
- characterData: true,
9504
- subtree: true
9505
- });
9506
- const unsubscribe = locale.subscribe?.(() => {
9507
- pendingRoots.add(document);
9508
- schedule();
9509
- }) ?? (() => {});
9510
- return () => {
9511
- observer.disconnect();
9512
- unsubscribe();
9513
- if (frame !== void 0) window.cancelAnimationFrame(frame);
9514
- };
9515
- }
9516
- //#endregion
9517
- //#region src/client/host-copy.ts
9518
- const commands = {
9519
- compact: ["Compact older conversation history", "host.command.compact"],
9520
- export: ["Download this Session log as a ZIP archive", "host.command.export"],
9521
- feedback: ["record feedback about this session", "host.command.feedback"],
9522
- goal: ["set or view the goal for a long-running task", "host.command.goal"],
9523
- permission: ["Switch the permission preset (sandbox mode + approval policy)", "host.command.permission"],
9524
- plan: ["Enter or leave plan mode", "host.command.plan"]
9525
- };
9526
- const transcript = {
9527
- Normal: "host.transcript.normal",
9528
- Compact: "host.transcript.compact"
9529
- };
9530
- /** 只补译已核对的宿主控件文本;保留原 Text 节点、事件和业务状态。 */
9531
- function observeHostCopy(locale, t) {
9532
- const owned = /* @__PURE__ */ new Map();
9533
- const replace = (element, original, key) => {
9534
- const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
9535
- let node;
9536
- while ((node = walker.nextNode()) !== null) {
9537
- if (node.nodeValue?.trim() !== original) continue;
9538
- const text = node;
9539
- const rendered = text.data.replace(original, t(key));
9540
- owned.set(text, {
9541
- original: text.data,
9542
- rendered,
9543
- key
9544
- });
9545
- if (text.data !== rendered) text.data = rendered;
9546
- }
9547
- };
9548
- const apply = () => {
9549
- for (const [node, state] of owned) {
9550
- if (!node.isConnected || node.data !== state.rendered) {
9551
- owned.delete(node);
9552
- continue;
9553
- }
9554
- const next = state.original.replace(state.original.trim(), t(state.key));
9555
- if (node.data !== next) node.data = next;
9556
- state.rendered = next;
9557
- }
9558
- const selector = document.querySelector("[data-dcu-settings-item=\"transcript-view\"] button[aria-haspopup=\"menu\"]");
9559
- if (selector) {
9560
- for (const [original, key] of Object.entries(transcript)) replace(selector, original, key);
9561
- if (selector.getAttribute("aria-expanded") === "true") for (const menu of document.querySelectorAll("[role=\"menu\"]")) {
9562
- const items = [...menu.querySelectorAll("[role=\"menuitem\"],[role=\"menuitemradio\"]")];
9563
- const labels = items.map((item) => item.textContent?.trim());
9564
- if (items.length !== 2 || !["Normal", t("host.transcript.normal")].some((label) => labels.includes(label)) || !["Compact", t("host.transcript.compact")].some((label) => labels.includes(label))) continue;
9565
- for (const item of items) for (const [original, key] of Object.entries(transcript)) replace(item, original, key);
9566
- }
9567
- }
9568
- for (const option of document.querySelectorAll("[data-trigger-menu] button[role=\"option\"]")) {
9569
- const spans = [...option.children].filter((child) => child.tagName === "SPAN" && child.getAttribute("aria-hidden") !== "true");
9570
- const name = spans[0]?.textContent?.trim();
9571
- if (!name || !Object.hasOwn(commands, name) || !spans[1]) continue;
9572
- const [original, key] = commands[name];
9573
- replace(spans[1], original, key);
9574
- }
9575
- };
9576
- const scope = "[data-trigger-menu],[data-dcu-settings-item=\"transcript-view\"],[role=\"menu\"]";
9577
- const roots = /* @__PURE__ */ new Map();
9578
- const discover = () => {
9579
- for (const [element, observer] of roots) if (!element.isConnected) {
9580
- observer.disconnect();
9581
- roots.delete(element);
9582
- }
9583
- for (const element of document.querySelectorAll(scope)) {
9584
- if (roots.has(element)) continue;
9585
- const observer = new MutationObserver(apply);
9586
- observer.observe(element, {
9587
- subtree: true,
9588
- childList: true,
9589
- characterData: true,
9590
- attributes: true,
9591
- attributeFilter: ["aria-expanded"]
9592
- });
9593
- roots.set(element, observer);
9594
- }
9595
- apply();
9596
- };
9597
- const observer = new MutationObserver((records) => {
9598
- if (records.some((record) => [...record.addedNodes, ...record.removedNodes].some((node) => node instanceof Element && (node.matches(scope) || node.querySelector(scope) !== null)))) discover();
9599
- });
9600
- discover();
9601
- observer.observe(document.body, {
9602
- subtree: true,
9603
- childList: true
9604
- });
9605
- const unsubscribe = locale.subscribe(apply);
9606
- return () => {
9607
- observer.disconnect();
9608
- roots.forEach((observer) => observer.disconnect());
9609
- roots.clear();
9610
- unsubscribe();
9611
- for (const [node, state] of owned) if (node.data === state.rendered) node.data = state.original;
9612
- owned.clear();
9613
- };
9614
- }
9615
- //#endregion
9616
9449
  //#region src/client/official-turn-navigator.ts
9617
9450
  const OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE = "data-dcu-official-turn-navigator";
9618
9451
  const OFFICIAL_TURN_MARK_ATTRIBUTE = "data-dcu-official-turn-mark";
@@ -9622,10 +9455,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9622
9455
  function isOfficialTurnNavigator(element) {
9623
9456
  return element instanceof HTMLElement && element.tagName === "NAV" && element.style.getPropertyValue("--turn-natural-height") !== "" && element.querySelector("button[type=\"button\"][aria-label]") !== null;
9624
9457
  }
9625
- function markOfficialTurnNavigatorParts(navigator) {
9626
- for (const button of navigator.querySelectorAll("button[type=\"button\"][aria-label]")) button.setAttribute(OFFICIAL_TURN_MARK_ATTRIBUTE, "true");
9627
- for (const tooltip of navigator.querySelectorAll("[role=\"tooltip\"]")) tooltip.setAttribute(OFFICIAL_TURN_TOOLTIP_ATTRIBUTE, "true");
9628
- }
9629
9458
  /** 标记实际挂载的官方轮次导航,避免依赖宿主样式文件名或会话 DOM 层级。 */
9630
9459
  function markOfficialTurnNavigators(root = document) {
9631
9460
  for (const element of root.querySelectorAll(`[${OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE}]`)) {
@@ -9639,7 +9468,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9639
9468
  for (const element of root.querySelectorAll("nav")) {
9640
9469
  if (!isOfficialTurnNavigator(element)) continue;
9641
9470
  element.setAttribute(OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE, "true");
9642
- markOfficialTurnNavigatorParts(element);
9643
9471
  }
9644
9472
  return root.querySelectorAll(`[${OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE}]`).length;
9645
9473
  }
@@ -10034,6 +9862,12 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10034
9862
  }
10035
9863
  };
10036
9864
  //#endregion
9865
+ //#region src/client/draft-attachments.ts
9866
+ /** 统一旧版图片草稿与 0.1.5 的通用附件草稿,保护已有附件不被历史召回覆盖。 */
9867
+ function hasDraftAttachments(state) {
9868
+ return (state.attachmentIds?.length ?? 0) > 0 || (state.imageIds?.length ?? 0) > 0;
9869
+ }
9870
+ //#endregion
10037
9871
  //#region src/client/input-history-keyboard.ts
10038
9872
  /** 只处理当前输入框的历史按键,保持 IME、菜单和富内容的原有行为。 */
10039
9873
  function bindHistoryKeys(editor, adapter) {
@@ -10145,7 +9979,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10145
9979
  let previous = input.state.getSnapshot();
10146
9980
  const offInput = input.state.subscribe(() => {
10147
9981
  const next = input.state.getSnapshot();
10148
- if (previous.phase === "submitting" && next.phase === "plain" && next.draft === "" && previous.imageIds.length === 0 && previous.occurrences.length === 0) history.add(scope, previous.draft);
9982
+ if (previous.phase === "submitting" && next.phase === "plain" && next.draft === "" && !hasDraftAttachments(previous) && previous.occurrences.length === 0) history.add(scope, previous.draft);
10149
9983
  previous = next;
10150
9984
  });
10151
9985
  let editor;
@@ -10162,7 +9996,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10162
9996
  setDraft: (text) => input.setDraft(text),
10163
9997
  blocked: () => {
10164
9998
  const state = input.state.getSnapshot();
10165
- return state.phase === "adjudicating" || state.phase === "submitting" || state.imageIds.length > 0 || state.occurrences.length > 0 || menu.getSnapshot().open;
9999
+ return state.phase === "adjudicating" || state.phase === "submitting" || hasDraftAttachments(state) || state.occurrences.length > 0 || menu.getSnapshot().open;
10166
10000
  }
10167
10001
  });
10168
10002
  };
@@ -10251,7 +10085,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10251
10085
  if (input === void 0) return "workspace";
10252
10086
  const state = input.state.getSnapshot();
10253
10087
  if (state.phase !== "plain") return "busy";
10254
- if (state.draft.trim() !== "" || state.imageIds.length > 0 || state.occurrences.length > 0) return "draft";
10088
+ if (state.draft.trim() !== "" || hasDraftAttachments(state) || state.occurrences.length > 0) return "draft";
10255
10089
  input.setDraft(text);
10256
10090
  return "ready";
10257
10091
  }
@@ -10308,12 +10142,10 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10308
10142
  const openPath = (path) => openPathInHost(connection, path);
10309
10143
  ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
10310
10144
  ctx.effect(() => observeSettingsNavIcons(), "michengai-codex-ui: settings nav icons");
10311
- ctx.effect(() => observePermissionLabels(ctx.locale), "michengai-codex-ui: permission labels");
10312
10145
  ctx.effect(() => observeComposerToolMenus({
10313
10146
  search: t("home.projectSearch"),
10314
10147
  empty: t("home.projectEmpty")
10315
10148
  }), "michengai-codex-ui: composer tool menus");
10316
- ctx.effect(() => observeHostCopy(ctx.locale, t), "michengai-codex-ui: host copy");
10317
10149
  ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
10318
10150
  ctx.effect(() => observeOfficialTurnNavigators(), "michengai-codex-ui: official turn navigator");
10319
10151
  const newConversationDraft = createDraftPresenceSource(ctx.sessions.list, () => {
@@ -10322,11 +10154,16 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10322
10154
  return binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx).state;
10323
10155
  });
10324
10156
  const companionSlots = createCompanionTabSource(ctx.slots);
10157
+ const globalPanels = createGlobalPanelSource(ctx.slots, ctx.locale);
10325
10158
  ctx.slots.inject("sidebar", () => ctx.slots.register({
10326
10159
  name: "sidebar",
10327
10160
  registrant: "michengai-codex-ui",
10328
10161
  locale: NS,
10329
10162
  children: {
10163
+ "sidebar.panellist": {
10164
+ kind: "list",
10165
+ scope: "root"
10166
+ },
10330
10167
  "sidebar.workspaces": {
10331
10168
  kind: "single",
10332
10169
  scope: "root"
@@ -10356,7 +10193,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10356
10193
  return prefillNewConversation(binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx), text);
10357
10194
  },
10358
10195
  openSession: (sessionId) => {
10359
- ctx.sessions.open(sessionId);
10196
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10360
10197
  },
10361
10198
  startSession: (workspaceId) => {
10362
10199
  startWorkspaceSession(ctx, workspaceId);
@@ -10370,7 +10207,11 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10370
10207
  moveSession,
10371
10208
  renameSession,
10372
10209
  openPath,
10373
- companionSlots
10210
+ companionSlots,
10211
+ globalPanels,
10212
+ selectPanel: (id) => {
10213
+ selectGlobalPanel(ctx.layout, id);
10214
+ }
10374
10215
  })
10375
10216
  }, CodexSidebar));
10376
10217
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
@@ -10385,7 +10226,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10385
10226
  sessionId,
10386
10227
  increaseTitle: true
10387
10228
  });
10388
- ctx.sessions.open(childId);
10229
+ openConversation(ctx.sessions, ctx.layout, childId);
10389
10230
  });
10390
10231
  };
10391
10232
  const renameSession = async (sessionId, title) => {
@@ -10440,7 +10281,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10440
10281
  const binding = ctx.sessions.binding(sessionId);
10441
10282
  if (binding === void 0) throw new UserFacingError(t("connectors.sessionPending"));
10442
10283
  conversation.input.for(binding.ctx).setDraft(prompt);
10443
- ctx.sessions.open(sessionId);
10284
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10444
10285
  };
10445
10286
  ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
10446
10287
  name: "sidebar.workspaces",
@@ -10454,7 +10295,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10454
10295
  moveSession,
10455
10296
  openPath,
10456
10297
  openSession: (sessionId) => {
10457
- ctx.sessions.open(sessionId);
10298
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10458
10299
  },
10459
10300
  renameSession,
10460
10301
  renameWorkspace: (workspaceId, title) => ctx.workspaces.rename(workspaceId, title),
@@ -10473,7 +10314,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10473
10314
  const openDeepLink = () => {
10474
10315
  if (opened || ctx.sessions.list.getSnapshot().byId[sessionId] === void 0) return;
10475
10316
  opened = true;
10476
- ctx.sessions.open(sessionId);
10317
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10477
10318
  };
10478
10319
  openDeepLink();
10479
10320
  return ctx.sessions.list.subscribe(openDeepLink);