@michengai/dsh-codex-ui 1.1.0 → 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", {
@@ -6002,6 +6032,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
6002
6032
  [data-phase=hero] [class*="_composerHero"]{box-sizing:border-box;flex:1;width:100%;max-width:none;min-width:0;margin-inline:auto;gap:0;padding-bottom:32px}
6003
6033
  [data-phase=hero] [class*="_composerHero"]>:first-child{box-sizing:border-box;flex:1;width:100%;max-width:768px;align-self:center;height:auto;min-height:340px;align-items:center;padding:32px 28px}
6004
6034
  [data-phase=hero] [class*="_composerHero"]>:first-child>[class$="_stack"]{width:100%;max-width:none;min-width:0;align-items:center;gap:32px}
6035
+ [data-phase=hero] [class*="_composerHero"] [class$="_headline"]{grid-template-columns:46px auto auto;font-size:34px;line-height:44px}
6036
+ [data-phase=hero] [class*="_composerHero"] [class$="_fishHitbox"]{width:46px;height:46px}
6037
+ [data-phase=hero] [class*="_composerHero"] [class$="_fishHitbox"]>svg{width:46px;height:auto}
6005
6038
  [data-phase=hero] [class*="_heroWorkspaceRow"]{box-sizing:border-box;flex:none;width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance) - 56px),calc(100% - 56px));align-self:center;justify-content:flex-start;flex-wrap:wrap;gap:8px;min-height:48px;margin:0 28px -10px;padding:6px 12px 16px;border-radius:18px 18px 0 0;background:color-mix(in srgb,var(--dsw-alias-label-primary) 4%,var(--dsw-alias-bg-base))}
6006
6039
  [data-phase=hero] [class*="_heroWorkspaceRow"]>[class$="_workspace"]{min-width:0;max-width:100%;font-weight:400}
6007
6040
  .dcu-home-suggestions{width:100%;color:var(--dsw-alias-label-primary);font:13px/20px var(--dsw-font-family,system-ui)}
@@ -6031,9 +6064,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
6031
6064
  const COMPOSER_TOOL_MENU_STYLE = `
6032
6065
  [class*="_heroWorkspaceRow"] button{min-height:28px;border-radius:999px;font-size:13px;line-height:20px}
6033
6066
  [class*="_heroWorkspaceRow"] button:hover,[class*="_heroWorkspaceRow"] button[aria-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 8%,transparent)}
6034
- :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}
6035
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}
6036
- :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}
6037
6073
  [class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal]){top:auto!important;bottom:calc(100% + 4px)!important}
6038
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}
6039
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}
@@ -6045,6 +6081,12 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6045
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)}
6046
6082
  [data-dcu-tool-empty]{padding:8px 10px;font-size:13px;color:var(--dsw-alias-label-secondary)}
6047
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)}
6048
6090
  `;
6049
6091
  function observeComposerToolMenus(copy) {
6050
6092
  let anchor;
@@ -6151,6 +6193,7 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6151
6193
  }
6152
6194
  if (anchor === void 0 || now() > pendingUntil) return;
6153
6195
  for (const menu of document.querySelectorAll(MENU)) {
6196
+ if (menu.closest("[data-trigger-menu]") !== null) continue;
6154
6197
  if (known.has(menu) || mounted.has(menu) || menu.parentElement?.closest(MENU) !== null) continue;
6155
6198
  if (menu.getClientRects().length === 0) continue;
6156
6199
  mount(menu, anchor);
@@ -6343,7 +6386,12 @@ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [
6343
6386
  [EXTENSIONS_EXPANSION_KEY]: open
6344
6387
  });
6345
6388
  }
6389
+ const emptyPanels = [];
6390
+ const getEmptyPanels = () => emptyPanels;
6391
+ const useLegacyPanelInfo = (selector) => selector({ activePanelId: null });
6346
6392
  const stylesheet$3 = `
6393
+ .dcu-global-panel[aria-current=page]{background:var(--dcu-sidebar-hover);font-weight:600}
6394
+
6347
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)}
6348
6396
  /* 滤镜只作用于背景,避免为设置和搜索等 fixed 后代创建侧栏包含块。 */
6349
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}}
@@ -6395,6 +6443,8 @@ body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu
6395
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}
6396
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}
6397
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}
6398
6448
  [data-conversation-scroll] [data-input-mirror]{min-height:44px}
6399
6449
  [data-conversation-scroll] [data-composer-card] [data-input-scroll]{margin-right:0}
6400
6450
  [data-conversation-scroll] [data-input-scroll] [data-lexical-editor=true]{min-height:44px;padding:0 12px}
@@ -6411,9 +6461,8 @@ body[data-ds-dark-theme] [data-conversation-scroll]{--dcu-composer-bg:var(--dsw-
6411
6461
  @media(forced-colors:active){[data-conversation-scroll] [data-composer-card]{outline:1px solid CanvasText}}
6412
6462
  html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:has([data-dcu-official-turn-navigator]) .dcu-turn-navigator{display:none}
6413
6463
  [data-dcu-official-turn-navigator]{right:auto!important;left:calc(12px - (var(--dsh-composer-side-clearance) + 16px))!important}
6414
- [data-dcu-official-turn-mark]{inset:0 auto 0 0!important}
6415
- [data-dcu-official-turn-mark]:before{right:auto!important;left:0!important}
6416
- [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}
6417
6466
  `;
6418
6467
  function MenuIcon({ children }) {
6419
6468
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -6723,7 +6772,20 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6723
6772
  });
6724
6773
  });
6725
6774
  /** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
6726
- 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
+ });
6727
6789
  const compact = collapsed || width < 80;
6728
6790
  const [visualCompact, setVisualCompact] = (0, react.useState)(compact);
6729
6791
  const [collapsing, setCollapsing] = (0, react.useState)(false);
@@ -6943,6 +7005,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6943
7005
  className: "dcu-menu",
6944
7006
  "aria-label": t("sidebar.mainMenu"),
6945
7007
  children: [
7008
+ panelButtons(true),
6946
7009
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6947
7010
  type: "button",
6948
7011
  onClick: () => {
@@ -7121,6 +7184,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7121
7184
  className: "dcu-compact-nav",
7122
7185
  "aria-label": t("sidebar.mainMenu"),
7123
7186
  children: [
7187
+ panelButtons(false),
7124
7188
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7125
7189
  type: "button",
7126
7190
  className: "dcu-icon",
@@ -7250,6 +7314,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7250
7314
  id: "schedule",
7251
7315
  packageName: "@michengai/dsh-automation"
7252
7316
  },
7317
+ {
7318
+ id: "pet",
7319
+ packageName: "@michengai/dsh-codex-pet"
7320
+ },
7253
7321
  {
7254
7322
  id: "btw",
7255
7323
  packageName: "@michengai/dsh-btw"
@@ -7633,8 +7701,14 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7633
7701
  const stylesheet$1 = `
7634
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}
7635
7703
  `;
7636
- 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)}`;
7637
- 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
+ `;
7638
7712
  function isConnector(value) {
7639
7713
  if (value === null || typeof value !== "object") return false;
7640
7714
  const item = value;
@@ -7654,7 +7728,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7654
7728
  style.dataset.michengaiHostTheme = "true";
7655
7729
  doc.head.append(style);
7656
7730
  }
7657
- style.textContent = document.body.hasAttribute("data-ds-dark-theme") ? frameDarkTheme : frameLightTheme;
7731
+ style.textContent = (document.body.hasAttribute("data-ds-dark-theme") ? frameDarkTheme : frameLightTheme) + frameSurfaceTheme;
7658
7732
  }
7659
7733
  function ConnectorMarket({ startPromptSession, t }) {
7660
7734
  const frameRef = (0, react.useRef)(null);
@@ -7839,14 +7913,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7839
7913
  "home.fix.prompt1": "我遇到了一个问题。先问我复现步骤、预期和实际表现,再定位根因并修复。",
7840
7914
  "home.fix.task2": "修复失败的测试",
7841
7915
  "home.fix.prompt2": "请运行当前项目适用的测试,定位失败根因并做最小修复,保留有效的回归覆盖。",
7842
- "host.transcript.normal": "标准",
7843
- "host.transcript.compact": "紧凑",
7844
- "host.command.compact": "压缩较早的对话历史",
7845
- "host.command.export": "将当前会话日志下载为 ZIP 压缩包",
7846
- "host.command.feedback": "记录对当前会话的反馈",
7847
- "host.command.goal": "设置或查看长时间任务的目标",
7848
- "host.command.permission": "切换权限预设(沙箱模式与审批策略)",
7849
- "host.command.plan": "进入或退出计划模式",
7850
7916
  "usage.title": "使用统计",
7851
7917
  "usage.loading": "正在加载费用面板…",
7852
7918
  "usage.failed": "费用面板暂时无法嵌入,可重试或打开原弹窗。",
@@ -8026,7 +8092,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8026
8092
  "about.feature.conversation": "保留原生消息、工具调用、输入、权限和模型选择,仅调整容器视觉",
8027
8093
  "about.feature.navigator": "当前会话提供轮次缩略导航,可快速跳转至每一次用户提问",
8028
8094
  "about.dependencies": "配套管理插件",
8029
- "about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM、定时任务、BTW 和第三方插件市场。",
8095
+ "about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM、定时任务、宠物、BTW、Simplify 和第三方插件市场。",
8030
8096
  "about.loading": "正在读取依赖安装状态…",
8031
8097
  "about.statusFailed": "暂时无法读取依赖安装状态。",
8032
8098
  "about.refreshFailed": "依赖状态刷新失败,当前显示上次成功读取的结果。",
@@ -8066,6 +8132,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8066
8132
  "about.dependency.archive": "归档会话",
8067
8133
  "about.dependency.im": "IM助理",
8068
8134
  "about.dependency.schedule": "定时任务",
8135
+ "about.dependency.pet": "Codex 宠物",
8069
8136
  "about.dependency.btw": "BTW 旁问",
8070
8137
  "about.dependency.simplify": "Simplify",
8071
8138
  "about.dependency.market": "插件市场",
@@ -8115,14 +8182,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8115
8182
  "home.fix.prompt1": "Help me fix a bug. First ask for reproduction steps, expected behavior, and actual behavior.",
8116
8183
  "home.fix.task2": "Fix failing tests",
8117
8184
  "home.fix.prompt2": "Run the applicable project tests, identify failure causes, and make minimal fixes with meaningful regression coverage.",
8118
- "host.transcript.normal": "Normal",
8119
- "host.transcript.compact": "Compact",
8120
- "host.command.compact": "Compact older conversation history",
8121
- "host.command.export": "Download this Session log as a ZIP archive",
8122
- "host.command.feedback": "record feedback about this session",
8123
- "host.command.goal": "set or view the goal for a long-running task",
8124
- "host.command.permission": "Switch the permission preset (sandbox mode + approval policy)",
8125
- "host.command.plan": "Enter or leave plan mode",
8126
8185
  "usage.title": "Usage statistics",
8127
8186
  "usage.loading": "Loading billing dashboard…",
8128
8187
  "usage.failed": "The embedded dashboard is unavailable. Retry or open the original dialog.",
@@ -8302,7 +8361,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8302
8361
  "about.feature.conversation": "Keeps native messages, tool calls, composer, permissions, and model selection while refining the container visuals",
8303
8362
  "about.feature.navigator": "Navigate directly to each user prompt with the current conversation turn navigator",
8304
8363
  "about.dependencies": "Companion management plugins",
8305
- "about.dependenciesDescription": "Install or update each companion separately, or install missing plugins and update old versions in one action. Check Codex UI, expert, skill, archive, IM, scheduled-task, BTW, and marketplace plugins on their own.",
8364
+ "about.dependenciesDescription": "Install or update each companion separately, or install missing plugins and update old versions in one action. Check Codex UI, expert, skill, archive, IM, scheduled-task, pet, BTW, Simplify, and marketplace plugins on their own.",
8306
8365
  "about.loading": "Loading dependency status…",
8307
8366
  "about.statusFailed": "Dependency status is temporarily unavailable.",
8308
8367
  "about.refreshFailed": "Dependency status refresh failed. Showing the last successful result.",
@@ -8342,6 +8401,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8342
8401
  "about.dependency.archive": "Archived conversations",
8343
8402
  "about.dependency.im": "IM Assistant",
8344
8403
  "about.dependency.schedule": "Scheduled tasks",
8404
+ "about.dependency.pet": "Codex Pet",
8345
8405
  "about.dependency.btw": "BTW",
8346
8406
  "about.dependency.simplify": "Simplify",
8347
8407
  "about.dependency.market": "Plugin Market",
@@ -8797,10 +8857,13 @@ html[data-dsh-native-backdrop=mica] #root>[data-slot=root]>div>div:has(>[data-sl
8797
8857
  html[data-dsh-native-backdrop=mica] #root :is([class$="_centerCol"],[class$="_detailsCol"]){background:var(--dsw-alias-bg-base,#fff)}
8798
8858
  html[data-dsh-native-backdrop=mica] :is(.dcu-root,.dcu-settings-nav){background:rgba(255,255,255,.18)}
8799
8859
  html[data-dsh-native-backdrop=mica] body[data-ds-dark-theme] :is(.dcu-root,.dcu-settings-nav){background:rgba(20,23,22,.18)}
8800
- html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page) [inert]{visibility:hidden}
8860
+ /* 会话折叠容器显式设了 visible,必须同时隐藏隔离分支的后代,避免穿透透明设置页。 */
8861
+ html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page) :is([inert],[inert] *){visibility:hidden!important}
8862
+ /* 同步隐藏本设置页隔离的外部 portal,保留引导模态及其他组件自己的 inert 语义。 */
8863
+ body:has(.dcu-settings-page) :is([data-dcu-settings-isolated],[data-dcu-settings-isolated] *){visibility:hidden!important}
8801
8864
  html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page){background:transparent}
8802
8865
 
8803
- .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}
8804
8867
  .dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
8805
8868
  .dcu-settings-inner:has(.dcu-usage-section)>[data-slot="settings.section"]{display:flex;flex:1;min-height:0;flex-direction:column}
8806
8869
  .dcu-usage-section{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px}
@@ -8954,8 +9017,12 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
8954
9017
  for (const child of element.children) if (child instanceof HTMLElement && !/^(STYLE|SCRIPT|LINK)$/.test(child.tagName)) isolate(child);
8955
9018
  return;
8956
9019
  }
8957
- hidden.set(element, element.inert);
9020
+ hidden.set(element, {
9021
+ inert: element.inert,
9022
+ marker: element.getAttribute("data-dcu-settings-isolated")
9023
+ });
8958
9024
  element.inert = true;
9025
+ element.setAttribute("data-dcu-settings-isolated", "");
8959
9026
  };
8960
9027
  let branch = page.current;
8961
9028
  while (branch.parentElement !== null) {
@@ -8994,7 +9061,11 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
8994
9061
  document.removeEventListener("keydown", onKeyDown, true);
8995
9062
  document.removeEventListener("keydown", wrapFocus);
8996
9063
  document.removeEventListener("focusin", keepFocus);
8997
- for (const [element, inert] of hidden) element.inert = inert;
9064
+ for (const [element, previous] of hidden) {
9065
+ element.inert = previous.inert;
9066
+ if (previous.marker === null) element.removeAttribute("data-dcu-settings-isolated");
9067
+ else element.setAttribute("data-dcu-settings-isolated", previous.marker);
9068
+ }
8998
9069
  };
8999
9070
  }, [
9000
9071
  open,
@@ -9375,224 +9446,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9375
9446
  }, CodexGeneralSettings));
9376
9447
  }
9377
9448
  //#endregion
9378
- //#region src/client/permission-labels.ts
9379
- const PERMISSION_LABELS = [
9380
- {
9381
- aliases: [
9382
- "Read Only",
9383
- "preset.readOnly",
9384
- "只读"
9385
- ],
9386
- en: "Read Only",
9387
- zh: "只读"
9388
- },
9389
- {
9390
- aliases: [
9391
- "Workspace Write",
9392
- "preset.workspaceWrite",
9393
- "工作区写入"
9394
- ],
9395
- en: "Workspace Write",
9396
- zh: "工作区写入"
9397
- },
9398
- {
9399
- aliases: [
9400
- "Full access",
9401
- "preset.fullAccess",
9402
- "完全访问"
9403
- ],
9404
- en: "Full access",
9405
- zh: "完全访问"
9406
- }
9407
- ];
9408
- const INTERACTIVE_SELECTOR = "button, [role=\"menuitem\"], [role=\"menuitemradio\"], [role=\"option\"]";
9409
- function targetLabel(value, activeLocale) {
9410
- const definition = PERMISSION_LABELS.find((item) => item.aliases.includes(value));
9411
- if (definition === void 0) return void 0;
9412
- return activeLocale.toLowerCase().startsWith("zh") ? definition.zh : definition.en;
9413
- }
9414
- function applyPermissionLabel(element, activeLocale) {
9415
- const document = element.ownerDocument;
9416
- const showText = document.defaultView?.NodeFilter.SHOW_TEXT ?? 4;
9417
- const walker = document.createTreeWalker(element, showText);
9418
- let changed = false;
9419
- let node = walker.nextNode();
9420
- while (node !== null) {
9421
- const value = node.nodeValue ?? "";
9422
- const trimmed = value.trim();
9423
- const next = targetLabel(trimmed, activeLocale);
9424
- if (next !== void 0 && next !== trimmed) {
9425
- node.nodeValue = value.replace(trimmed, next);
9426
- changed = true;
9427
- }
9428
- node = walker.nextNode();
9429
- }
9430
- return changed;
9431
- }
9432
- /** 只修正权限选择控件里的内置预设名称,不改动正文或自定义权限名称。 */
9433
- function localizePermissionLabels(root, activeLocale) {
9434
- let changed = 0;
9435
- const rootElement = root.nodeType === 1 ? root : void 0;
9436
- const elements = rootElement?.matches(INTERACTIVE_SELECTOR) === true ? [rootElement, ...rootElement.querySelectorAll(INTERACTIVE_SELECTOR)] : [...root.querySelectorAll(INTERACTIVE_SELECTOR)];
9437
- for (const element of elements) if (applyPermissionLabel(element, activeLocale)) changed += 1;
9438
- return changed;
9439
- }
9440
- /** 兼容宿主设置页和 Chat 中由官方组件直接输出的英文权限名称。 */
9441
- function observePermissionLabels(locale) {
9442
- if (typeof document === "undefined" || document.body === null) return () => {};
9443
- let applying = false;
9444
- let frame;
9445
- const pendingRoots = /* @__PURE__ */ new Set([document]);
9446
- const apply = () => {
9447
- if (applying) return;
9448
- applying = true;
9449
- const active = [
9450
- locale.getSnapshot?.().active,
9451
- document.documentElement.lang,
9452
- window.navigator.language
9453
- ].find((value) => typeof value === "string" && value.trim() !== "") ?? "zh";
9454
- const roots = [...pendingRoots];
9455
- pendingRoots.clear();
9456
- try {
9457
- for (const root of roots) localizePermissionLabels(root, active);
9458
- } finally {
9459
- applying = false;
9460
- }
9461
- };
9462
- const schedule = () => {
9463
- if (frame !== void 0) return;
9464
- frame = window.requestAnimationFrame(() => {
9465
- frame = void 0;
9466
- apply();
9467
- });
9468
- };
9469
- apply();
9470
- const observer = new MutationObserver((records) => {
9471
- for (const record of records) {
9472
- const control = (record.target.nodeType === 1 ? record.target : record.target.parentElement)?.closest(INTERACTIVE_SELECTOR);
9473
- if (control !== null && control !== void 0) pendingRoots.add(control);
9474
- for (const node of record.addedNodes) {
9475
- if (!(node instanceof Element)) continue;
9476
- if (node.matches(INTERACTIVE_SELECTOR) || node.querySelector(INTERACTIVE_SELECTOR) !== null) pendingRoots.add(node);
9477
- }
9478
- }
9479
- if (pendingRoots.size > 0) schedule();
9480
- });
9481
- observer.observe(document.body, {
9482
- childList: true,
9483
- characterData: true,
9484
- subtree: true
9485
- });
9486
- const unsubscribe = locale.subscribe?.(() => {
9487
- pendingRoots.add(document);
9488
- schedule();
9489
- }) ?? (() => {});
9490
- return () => {
9491
- observer.disconnect();
9492
- unsubscribe();
9493
- if (frame !== void 0) window.cancelAnimationFrame(frame);
9494
- };
9495
- }
9496
- //#endregion
9497
- //#region src/client/host-copy.ts
9498
- const commands = {
9499
- compact: ["Compact older conversation history", "host.command.compact"],
9500
- export: ["Download this Session log as a ZIP archive", "host.command.export"],
9501
- feedback: ["record feedback about this session", "host.command.feedback"],
9502
- goal: ["set or view the goal for a long-running task", "host.command.goal"],
9503
- permission: ["Switch the permission preset (sandbox mode + approval policy)", "host.command.permission"],
9504
- plan: ["Enter or leave plan mode", "host.command.plan"]
9505
- };
9506
- const transcript = {
9507
- Normal: "host.transcript.normal",
9508
- Compact: "host.transcript.compact"
9509
- };
9510
- /** 只补译已核对的宿主控件文本;保留原 Text 节点、事件和业务状态。 */
9511
- function observeHostCopy(locale, t) {
9512
- const owned = /* @__PURE__ */ new Map();
9513
- const replace = (element, original, key) => {
9514
- const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
9515
- let node;
9516
- while ((node = walker.nextNode()) !== null) {
9517
- if (node.nodeValue?.trim() !== original) continue;
9518
- const text = node;
9519
- const rendered = text.data.replace(original, t(key));
9520
- owned.set(text, {
9521
- original: text.data,
9522
- rendered,
9523
- key
9524
- });
9525
- if (text.data !== rendered) text.data = rendered;
9526
- }
9527
- };
9528
- const apply = () => {
9529
- for (const [node, state] of owned) {
9530
- if (!node.isConnected || node.data !== state.rendered) {
9531
- owned.delete(node);
9532
- continue;
9533
- }
9534
- const next = state.original.replace(state.original.trim(), t(state.key));
9535
- if (node.data !== next) node.data = next;
9536
- state.rendered = next;
9537
- }
9538
- const selector = document.querySelector("[data-dcu-settings-item=\"transcript-view\"] button[aria-haspopup=\"menu\"]");
9539
- if (selector) {
9540
- for (const [original, key] of Object.entries(transcript)) replace(selector, original, key);
9541
- if (selector.getAttribute("aria-expanded") === "true") for (const menu of document.querySelectorAll("[role=\"menu\"]")) {
9542
- const items = [...menu.querySelectorAll("[role=\"menuitem\"],[role=\"menuitemradio\"]")];
9543
- const labels = items.map((item) => item.textContent?.trim());
9544
- 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;
9545
- for (const item of items) for (const [original, key] of Object.entries(transcript)) replace(item, original, key);
9546
- }
9547
- }
9548
- for (const option of document.querySelectorAll("[data-trigger-menu] button[role=\"option\"]")) {
9549
- const spans = [...option.children].filter((child) => child.tagName === "SPAN" && child.getAttribute("aria-hidden") !== "true");
9550
- const name = spans[0]?.textContent?.trim();
9551
- if (!name || !Object.hasOwn(commands, name) || !spans[1]) continue;
9552
- const [original, key] = commands[name];
9553
- replace(spans[1], original, key);
9554
- }
9555
- };
9556
- const scope = "[data-trigger-menu],[data-dcu-settings-item=\"transcript-view\"],[role=\"menu\"]";
9557
- const roots = /* @__PURE__ */ new Map();
9558
- const discover = () => {
9559
- for (const [element, observer] of roots) if (!element.isConnected) {
9560
- observer.disconnect();
9561
- roots.delete(element);
9562
- }
9563
- for (const element of document.querySelectorAll(scope)) {
9564
- if (roots.has(element)) continue;
9565
- const observer = new MutationObserver(apply);
9566
- observer.observe(element, {
9567
- subtree: true,
9568
- childList: true,
9569
- characterData: true,
9570
- attributes: true,
9571
- attributeFilter: ["aria-expanded"]
9572
- });
9573
- roots.set(element, observer);
9574
- }
9575
- apply();
9576
- };
9577
- const observer = new MutationObserver((records) => {
9578
- if (records.some((record) => [...record.addedNodes, ...record.removedNodes].some((node) => node instanceof Element && (node.matches(scope) || node.querySelector(scope) !== null)))) discover();
9579
- });
9580
- discover();
9581
- observer.observe(document.body, {
9582
- subtree: true,
9583
- childList: true
9584
- });
9585
- const unsubscribe = locale.subscribe(apply);
9586
- return () => {
9587
- observer.disconnect();
9588
- roots.forEach((observer) => observer.disconnect());
9589
- roots.clear();
9590
- unsubscribe();
9591
- for (const [node, state] of owned) if (node.data === state.rendered) node.data = state.original;
9592
- owned.clear();
9593
- };
9594
- }
9595
- //#endregion
9596
9449
  //#region src/client/official-turn-navigator.ts
9597
9450
  const OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE = "data-dcu-official-turn-navigator";
9598
9451
  const OFFICIAL_TURN_MARK_ATTRIBUTE = "data-dcu-official-turn-mark";
@@ -9602,10 +9455,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9602
9455
  function isOfficialTurnNavigator(element) {
9603
9456
  return element instanceof HTMLElement && element.tagName === "NAV" && element.style.getPropertyValue("--turn-natural-height") !== "" && element.querySelector("button[type=\"button\"][aria-label]") !== null;
9604
9457
  }
9605
- function markOfficialTurnNavigatorParts(navigator) {
9606
- for (const button of navigator.querySelectorAll("button[type=\"button\"][aria-label]")) button.setAttribute(OFFICIAL_TURN_MARK_ATTRIBUTE, "true");
9607
- for (const tooltip of navigator.querySelectorAll("[role=\"tooltip\"]")) tooltip.setAttribute(OFFICIAL_TURN_TOOLTIP_ATTRIBUTE, "true");
9608
- }
9609
9458
  /** 标记实际挂载的官方轮次导航,避免依赖宿主样式文件名或会话 DOM 层级。 */
9610
9459
  function markOfficialTurnNavigators(root = document) {
9611
9460
  for (const element of root.querySelectorAll(`[${OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE}]`)) {
@@ -9619,7 +9468,6 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
9619
9468
  for (const element of root.querySelectorAll("nav")) {
9620
9469
  if (!isOfficialTurnNavigator(element)) continue;
9621
9470
  element.setAttribute(OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE, "true");
9622
- markOfficialTurnNavigatorParts(element);
9623
9471
  }
9624
9472
  return root.querySelectorAll(`[${OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE}]`).length;
9625
9473
  }
@@ -10014,6 +9862,12 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10014
9862
  }
10015
9863
  };
10016
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
10017
9871
  //#region src/client/input-history-keyboard.ts
10018
9872
  /** 只处理当前输入框的历史按键,保持 IME、菜单和富内容的原有行为。 */
10019
9873
  function bindHistoryKeys(editor, adapter) {
@@ -10125,7 +9979,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10125
9979
  let previous = input.state.getSnapshot();
10126
9980
  const offInput = input.state.subscribe(() => {
10127
9981
  const next = input.state.getSnapshot();
10128
- 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);
10129
9983
  previous = next;
10130
9984
  });
10131
9985
  let editor;
@@ -10142,7 +9996,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10142
9996
  setDraft: (text) => input.setDraft(text),
10143
9997
  blocked: () => {
10144
9998
  const state = input.state.getSnapshot();
10145
- 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;
10146
10000
  }
10147
10001
  });
10148
10002
  };
@@ -10231,7 +10085,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10231
10085
  if (input === void 0) return "workspace";
10232
10086
  const state = input.state.getSnapshot();
10233
10087
  if (state.phase !== "plain") return "busy";
10234
- 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";
10235
10089
  input.setDraft(text);
10236
10090
  return "ready";
10237
10091
  }
@@ -10288,12 +10142,10 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10288
10142
  const openPath = (path) => openPathInHost(connection, path);
10289
10143
  ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
10290
10144
  ctx.effect(() => observeSettingsNavIcons(), "michengai-codex-ui: settings nav icons");
10291
- ctx.effect(() => observePermissionLabels(ctx.locale), "michengai-codex-ui: permission labels");
10292
10145
  ctx.effect(() => observeComposerToolMenus({
10293
10146
  search: t("home.projectSearch"),
10294
10147
  empty: t("home.projectEmpty")
10295
10148
  }), "michengai-codex-ui: composer tool menus");
10296
- ctx.effect(() => observeHostCopy(ctx.locale, t), "michengai-codex-ui: host copy");
10297
10149
  ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
10298
10150
  ctx.effect(() => observeOfficialTurnNavigators(), "michengai-codex-ui: official turn navigator");
10299
10151
  const newConversationDraft = createDraftPresenceSource(ctx.sessions.list, () => {
@@ -10302,11 +10154,16 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10302
10154
  return binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx).state;
10303
10155
  });
10304
10156
  const companionSlots = createCompanionTabSource(ctx.slots);
10157
+ const globalPanels = createGlobalPanelSource(ctx.slots, ctx.locale);
10305
10158
  ctx.slots.inject("sidebar", () => ctx.slots.register({
10306
10159
  name: "sidebar",
10307
10160
  registrant: "michengai-codex-ui",
10308
10161
  locale: NS,
10309
10162
  children: {
10163
+ "sidebar.panellist": {
10164
+ kind: "list",
10165
+ scope: "root"
10166
+ },
10310
10167
  "sidebar.workspaces": {
10311
10168
  kind: "single",
10312
10169
  scope: "root"
@@ -10336,7 +10193,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10336
10193
  return prefillNewConversation(binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx), text);
10337
10194
  },
10338
10195
  openSession: (sessionId) => {
10339
- ctx.sessions.open(sessionId);
10196
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10340
10197
  },
10341
10198
  startSession: (workspaceId) => {
10342
10199
  startWorkspaceSession(ctx, workspaceId);
@@ -10350,7 +10207,11 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10350
10207
  moveSession,
10351
10208
  renameSession,
10352
10209
  openPath,
10353
- companionSlots
10210
+ companionSlots,
10211
+ globalPanels,
10212
+ selectPanel: (id) => {
10213
+ selectGlobalPanel(ctx.layout, id);
10214
+ }
10354
10215
  })
10355
10216
  }, CodexSidebar));
10356
10217
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
@@ -10365,7 +10226,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10365
10226
  sessionId,
10366
10227
  increaseTitle: true
10367
10228
  });
10368
- ctx.sessions.open(childId);
10229
+ openConversation(ctx.sessions, ctx.layout, childId);
10369
10230
  });
10370
10231
  };
10371
10232
  const renameSession = async (sessionId, title) => {
@@ -10420,7 +10281,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10420
10281
  const binding = ctx.sessions.binding(sessionId);
10421
10282
  if (binding === void 0) throw new UserFacingError(t("connectors.sessionPending"));
10422
10283
  conversation.input.for(binding.ctx).setDraft(prompt);
10423
- ctx.sessions.open(sessionId);
10284
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10424
10285
  };
10425
10286
  ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
10426
10287
  name: "sidebar.workspaces",
@@ -10434,7 +10295,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10434
10295
  moveSession,
10435
10296
  openPath,
10436
10297
  openSession: (sessionId) => {
10437
- ctx.sessions.open(sessionId);
10298
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10438
10299
  },
10439
10300
  renameSession,
10440
10301
  renameWorkspace: (workspaceId, title) => ctx.workspaces.rename(workspaceId, title),
@@ -10453,7 +10314,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
10453
10314
  const openDeepLink = () => {
10454
10315
  if (opened || ctx.sessions.list.getSnapshot().byId[sessionId] === void 0) return;
10455
10316
  opened = true;
10456
- ctx.sessions.open(sessionId);
10317
+ openConversation(ctx.sessions, ctx.layout, sessionId);
10457
10318
  };
10458
10319
  openDeepLink();
10459
10320
  return ctx.sessions.list.subscribe(openDeepLink);