@michengai/dsh-codex-ui 1.0.0 → 1.1.1

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
@@ -7,6 +7,146 @@ window.__ModuleLoader__.load({
7
7
  let react = require("react");
8
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
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
+ }
142
+ }
143
+ function writeTreeExpansionState(storage, key, state) {
144
+ if (storage === void 0) return;
145
+ try {
146
+ storage.setItem(key, JSON.stringify(parseTreeExpansionState(state)));
147
+ } catch {}
148
+ }
149
+ //#endregion
10
150
  //#region src/client/settings-navigation.ts
11
151
  /**
12
152
  * DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
@@ -31,6 +171,7 @@ window.__ModuleLoader__.load({
31
171
  let cancelPendingNavigation;
32
172
  const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
33
173
  const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
174
+ const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
34
175
  /** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
35
176
  function openSettingsRoot(root) {
36
177
  root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
@@ -44,6 +185,14 @@ window.__ModuleLoader__.load({
44
185
  }
45
186
  const opening = cancelPendingNavigation !== void 0;
46
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
+ }
47
196
  const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
48
197
  if (!opening && document.querySelector(pageSelector) === null) trigger.click();
49
198
  let frame;
@@ -522,6 +671,82 @@ window.__ModuleLoader__.load({
522
671
  * This source code is licensed under the ISC license.
523
672
  * See the LICENSE file in the root directory of this source tree.
524
673
  */
674
+ const Bug = createLucideIcon("bug", [
675
+ ["path", {
676
+ d: "M12 20v-9",
677
+ key: "1qisl0"
678
+ }],
679
+ ["path", {
680
+ d: "M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z",
681
+ key: "uouzyp"
682
+ }],
683
+ ["path", {
684
+ d: "M14.12 3.88 16 2",
685
+ key: "qol33r"
686
+ }],
687
+ ["path", {
688
+ d: "M21 21a4 4 0 0 0-3.81-4",
689
+ key: "1b0z45"
690
+ }],
691
+ ["path", {
692
+ d: "M21 5a4 4 0 0 1-3.55 3.97",
693
+ key: "5cxbf6"
694
+ }],
695
+ ["path", {
696
+ d: "M22 13h-4",
697
+ key: "1jl80f"
698
+ }],
699
+ ["path", {
700
+ d: "M3 21a4 4 0 0 1 3.81-4",
701
+ key: "1fjd4g"
702
+ }],
703
+ ["path", {
704
+ d: "M3 5a4 4 0 0 0 3.55 3.97",
705
+ key: "1d7oge"
706
+ }],
707
+ ["path", {
708
+ d: "M6 13H2",
709
+ key: "82j7cp"
710
+ }],
711
+ ["path", {
712
+ d: "m8 2 1.88 1.88",
713
+ key: "fmnt4t"
714
+ }],
715
+ ["path", {
716
+ d: "M9 7.13V6a3 3 0 1 1 6 0v1.13",
717
+ key: "1vgav8"
718
+ }]
719
+ ]);
720
+ /**
721
+ * @license lucide-react v1.39.0 - ISC
722
+ *
723
+ * This source code is licensed under the ISC license.
724
+ * See the LICENSE file in the root directory of this source tree.
725
+ */
726
+ const ChartColumn = createLucideIcon("chart-column", [
727
+ ["path", {
728
+ d: "M3 3v16a2 2 0 0 0 2 2h16",
729
+ key: "c24i48"
730
+ }],
731
+ ["path", {
732
+ d: "M18 17V9",
733
+ key: "2bz60n"
734
+ }],
735
+ ["path", {
736
+ d: "M13 17V5",
737
+ key: "1frdt8"
738
+ }],
739
+ ["path", {
740
+ d: "M8 17v-3",
741
+ key: "17ska0"
742
+ }]
743
+ ]);
744
+ /**
745
+ * @license lucide-react v1.39.0 - ISC
746
+ *
747
+ * This source code is licensed under the ISC license.
748
+ * See the LICENSE file in the root directory of this source tree.
749
+ */
525
750
  const CircleQuestionMark = createLucideIcon("circle-question-mark", [
526
751
  ["circle", {
527
752
  cx: "12",
@@ -670,6 +895,26 @@ window.__ModuleLoader__.load({
670
895
  * This source code is licensed under the ISC license.
671
896
  * See the LICENSE file in the root directory of this source tree.
672
897
  */
898
+ const Hammer = createLucideIcon("hammer", [
899
+ ["path", {
900
+ d: "m15 12-9.373 9.373a1 1 0 0 1-3.001-3L12 9",
901
+ key: "1hayfq"
902
+ }],
903
+ ["path", {
904
+ d: "m18 15 4-4",
905
+ key: "16gjal"
906
+ }],
907
+ ["path", {
908
+ d: "m21.5 11.5-1.914-1.914A2 2 0 0 1 19 8.172v-.344a2 2 0 0 0-.586-1.414l-1.657-1.657A6 6 0 0 0 12.516 3H9l1.243 1.243A6 6 0 0 1 12 8.485V10l2 2h1.172a2 2 0 0 1 1.414.586L18.5 14.5",
909
+ key: "15ts47"
910
+ }]
911
+ ]);
912
+ /**
913
+ * @license lucide-react v1.39.0 - ISC
914
+ *
915
+ * This source code is licensed under the ISC license.
916
+ * See the LICENSE file in the root directory of this source tree.
917
+ */
673
918
  const Link = createLucideIcon("link", [["path", {
674
919
  d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
675
920
  key: "1cjeqo"
@@ -733,6 +978,34 @@ window.__ModuleLoader__.load({
733
978
  * This source code is licensed under the ISC license.
734
979
  * See the LICENSE file in the root directory of this source tree.
735
980
  */
981
+ const ScanLine = createLucideIcon("scan-line", [
982
+ ["path", {
983
+ d: "M3 7V5a2 2 0 0 1 2-2h2",
984
+ key: "aa7l1z"
985
+ }],
986
+ ["path", {
987
+ d: "M17 3h2a2 2 0 0 1 2 2v2",
988
+ key: "4qcy5o"
989
+ }],
990
+ ["path", {
991
+ d: "M21 17v2a2 2 0 0 1-2 2h-2",
992
+ key: "6vwrx8"
993
+ }],
994
+ ["path", {
995
+ d: "M7 21H5a2 2 0 0 1-2-2v-2",
996
+ key: "ioqczr"
997
+ }],
998
+ ["path", {
999
+ d: "M7 12h10",
1000
+ key: "b7w52i"
1001
+ }]
1002
+ ]);
1003
+ /**
1004
+ * @license lucide-react v1.39.0 - ISC
1005
+ *
1006
+ * This source code is licensed under the ISC license.
1007
+ * See the LICENSE file in the root directory of this source tree.
1008
+ */
736
1009
  const Search = createLucideIcon("search", [["path", {
737
1010
  d: "m21 21-4.34-4.34",
738
1011
  key: "14j7rj"
@@ -866,6 +1139,44 @@ window.__ModuleLoader__.load({
866
1139
  * This source code is licensed under the ISC license.
867
1140
  * See the LICENSE file in the root directory of this source tree.
868
1141
  */
1142
+ const Telescope = createLucideIcon("telescope", [
1143
+ ["path", {
1144
+ d: "m10.065 12.493-6.18 1.318a.934.934 0 0 1-1.108-.702l-.537-2.15a1.07 1.07 0 0 1 .691-1.265l13.504-4.44",
1145
+ key: "k4qptu"
1146
+ }],
1147
+ ["path", {
1148
+ d: "m13.56 11.747 4.332-.924",
1149
+ key: "19l80z"
1150
+ }],
1151
+ ["path", {
1152
+ d: "m16 21-3.105-6.21",
1153
+ key: "7oh9d"
1154
+ }],
1155
+ ["path", {
1156
+ d: "M16.485 5.94a2 2 0 0 1 1.455-2.425l1.09-.272a1 1 0 0 1 1.212.727l1.515 6.06a1 1 0 0 1-.727 1.213l-1.09.272a2 2 0 0 1-2.425-1.455z",
1157
+ key: "m7xp4m"
1158
+ }],
1159
+ ["path", {
1160
+ d: "m6.158 8.633 1.114 4.456",
1161
+ key: "74o979"
1162
+ }],
1163
+ ["path", {
1164
+ d: "m8 21 3.105-6.21",
1165
+ key: "1fvxut"
1166
+ }],
1167
+ ["circle", {
1168
+ cx: "12",
1169
+ cy: "13",
1170
+ r: "2",
1171
+ key: "1c1ljs"
1172
+ }]
1173
+ ]);
1174
+ /**
1175
+ * @license lucide-react v1.39.0 - ISC
1176
+ *
1177
+ * This source code is licensed under the ISC license.
1178
+ * See the LICENSE file in the root directory of this source tree.
1179
+ */
869
1180
  const User = createLucideIcon("user", [["path", {
870
1181
  d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",
871
1182
  key: "975kel"
@@ -2212,40 +2523,6 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2212
2523
  return fallback !== void 0 && fallback.trim() !== "" ? fallback : void 0;
2213
2524
  }
2214
2525
  //#endregion
2215
- //#region src/client/tree-expansion.ts
2216
- const WORKSPACE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.workspace-expansion.v1";
2217
- const CHANNEL_EXPANSION_STORAGE_KEY = "dsh-codex-ui.channel-expansion.v1";
2218
- const SCHEDULE_EXPANSION_STORAGE_KEY = "dsh-codex-ui.schedule-expansion.v1";
2219
- const MAX_EXPANSION_ENTRIES = 500;
2220
- const MAX_EXPANSION_KEY_LENGTH = 512;
2221
- function browserStorage() {
2222
- if (typeof window === "undefined") return void 0;
2223
- try {
2224
- return window.localStorage;
2225
- } catch {
2226
- return;
2227
- }
2228
- }
2229
- function parseTreeExpansionState(value) {
2230
- if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
2231
- 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);
2232
- return Object.fromEntries(entries);
2233
- }
2234
- function readTreeExpansionState(storage, key) {
2235
- if (storage === void 0) return {};
2236
- try {
2237
- return parseTreeExpansionState(JSON.parse(storage.getItem(key) ?? "{}"));
2238
- } catch {
2239
- return {};
2240
- }
2241
- }
2242
- function writeTreeExpansionState(storage, key, state) {
2243
- if (storage === void 0) return;
2244
- try {
2245
- storage.setItem(key, JSON.stringify(parseTreeExpansionState(state)));
2246
- } catch {}
2247
- }
2248
- //#endregion
2249
2526
  //#region src/client/workspace-compat.ts
2250
2527
  function hasStartSession(value) {
2251
2528
  return value !== null && typeof value === "object" && "startSession" in value && typeof value.startSession === "function";
@@ -2648,7 +2925,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2648
2925
  const stylesheet$4 = `
2649
2926
  .dcu-wb{--dcu-wb-inset:8px;display:flex;flex:1;min-height:0;flex-direction:column;padding:4px var(--dcu-wb-inset) 8px;color:var(--dcu-sidebar-primary)}
2650
2927
  .dcu-wb *{box-sizing:border-box}
2651
- .dcu-wb-tree{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding-bottom:16px;scrollbar-gutter:auto;user-select:none;-webkit-user-select:none}
2928
+ .dcu-wb-tree{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding-bottom:16px;scrollbar-gutter:auto;scrollbar-width:none;user-select:none;-webkit-user-select:none}
2929
+ .dcu-wb-tree::-webkit-scrollbar{display:none}
2652
2930
  .dcu-wb-section+.dcu-wb-section{margin-top:12px}
2653
2931
  .dcu-wb-section-head{position:relative;display:flex;align-items:center;min-height:24px;padding:0;border-radius:6px}.dcu-wb-section-head:hover .dcu-wb-actions{display:flex}.dcu-wb-section-label{position:relative;display:flex;align-items:center;gap:4px;flex:1;min-width:0;min-height:24px;border:0;padding:2px 4px 2px 12px;background:transparent;color:var(--dcu-sidebar-tertiary);font:13px/20px var(--dcu-font,inherit);font-weight:400;letter-spacing:0;text-align:left;cursor:pointer}.dcu-wb-section-caret{display:grid;place-items:center;flex:none;width:12px;height:12px;color:currentColor;opacity:0;transform:rotate(0deg);transform-origin:50% 50%;transition:opacity 120ms ease,transform 160ms ease}.dcu-wb-section-head .dcu-wb-section-caret{position:absolute;left:0;top:6px}.dcu-wb-section-caret svg{display:block}.dcu-wb-section-head:hover .dcu-wb-section-caret,.dcu-wb-section-label:focus-visible .dcu-wb-section-caret{opacity:.78}.dcu-wb-section-label[aria-expanded=true] .dcu-wb-section-caret{transform:rotate(90deg)}.dcu-wb-section-body{display:block}.dcu-wb-section-body[data-open=false]{display:none}.dcu-wb-section-body>div{min-height:0}.dcu-wb-section-body[data-open=true]>div{animation:dcu-wb-section-in 140ms cubic-bezier(.16,1,.3,1)}@keyframes dcu-wb-section-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion:reduce){.dcu-wb-section-caret{transition:none}.dcu-wb-section-body[data-open=true]>div{animation:none}}
2654
2932
  .dcu-wb-project{position:relative;min-width:0}
@@ -5714,6 +5992,343 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5714
5992
  } catch {}
5715
5993
  }
5716
5994
  //#endregion
5995
+ //#region src/client/new-conversation-style.ts
5996
+ /** 新建页底部输入布局;保留宿主节点、插槽与 active 会话底部信息。 */
5997
+ const NEW_CONVERSATION_STYLE = `
5998
+ [data-phase=hero]:has([data-conversation-scroll]){container:dcu-new-conversation / inline-size}
5999
+ [data-phase=hero] [data-conversation-scroll][class]{--dsh-composer-side-clearance:16px;justify-content:flex-start;scrollbar-gutter:stable both-edges}
6000
+ [data-phase=hero] [data-composer-seat]{flex:1 0 auto;min-height:100%}
6001
+ [data-phase=hero] [data-composer-seat]>:has([class*="_composerHero"]){display:flex;flex:1;flex-direction:column}
6002
+ [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
+ [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
+ [data-phase=hero] [class*="_composerHero"]>:first-child>[class$="_stack"]{width:100%;max-width:none;min-width:0;align-items:center;gap:32px}
6005
+ [data-phase=hero] [class*="_composerHero"] [class$="_headline"]{grid-template-columns:46px auto auto;font-size:34px;line-height:44px}
6006
+ [data-phase=hero] [class*="_composerHero"] [class$="_fishHitbox"]{width:46px;height:46px}
6007
+ [data-phase=hero] [class*="_composerHero"] [class$="_fishHitbox"]>svg{width:46px;height:auto}
6008
+ [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))}
6009
+ [data-phase=hero] [class*="_heroWorkspaceRow"]>[class$="_workspace"]{min-width:0;max-width:100%;font-weight:400}
6010
+ .dcu-home-suggestions{width:100%;color:var(--dsw-alias-label-primary);font:13px/20px var(--dsw-font-family,system-ui)}
6011
+ .dcu-home-cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
6012
+ .dcu-home-card{appearance:none;display:flex;flex-direction:column;justify-content:space-between;gap:22px;min-width:0;min-height:106px;padding:16px;border:1px solid color-mix(in srgb,var(--dsw-alias-label-primary) 10%,transparent);border-radius:20px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer;transition:background-color 150ms,border-color 150ms}
6013
+ .dcu-home-card:hover,.dcu-home-card[aria-pressed=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 5%,transparent);border-color:color-mix(in srgb,var(--dsw-alias-label-primary) 20%,transparent)}
6014
+ .dcu-home-card svg{width:16px;height:16px;flex:none;color:var(--dcu-home-icon)}
6015
+ .dcu-home-card:focus-visible,.dcu-home-task:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:3px}
6016
+ .dcu-home-details,.dcu-home-status{display:grid}
6017
+ .dcu-home-suggestions[data-has-draft=true]{visibility:hidden;pointer-events:none}
6018
+ .dcu-home-tasks{grid-area:1/1;display:flex;flex-wrap:wrap;align-content:start;gap:8px;margin-top:16px}
6019
+ .dcu-home-details>[data-active=false],.dcu-home-status>[data-active=false]{visibility:hidden;pointer-events:none}
6020
+ .dcu-home-task{appearance:none;border:1px solid color-mix(in srgb,var(--dsw-alias-label-primary) 12%,transparent);border-radius:10px;padding:8px 12px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
6021
+ .dcu-home-task:hover{background:color-mix(in srgb,var(--dsw-alias-label-primary) 5%,transparent)}
6022
+ .dcu-home-hint{grid-area:1/1;margin:12px 0 0;color:var(--dsw-alias-label-secondary)}
6023
+ @container dcu-new-conversation (width < 640px){
6024
+ .dcu-home-cards{grid-template-columns:repeat(2,minmax(0,1fr))}
6025
+ [data-phase=hero] [class*="_composerHero"]>:first-child{padding:32px 24px;min-height:420px}
6026
+ }
6027
+ @media(prefers-reduced-motion:reduce){.dcu-home-card{transition:none}}
6028
+ `;
6029
+ //#endregion
6030
+ //#region src/client/composer-tool-menus.ts
6031
+ /** 只适配由输入区工具触发的菜单;保留原条目、选择回调及目录创建流程。 */
6032
+ const TOOL = "[class*=\"_heroWorkspaceRow\"] button,[data-composer-card] button[aria-haspopup],[data-composer-card] button[aria-expanded]";
6033
+ const MENU = "[role=\"menu\"],[role=\"listbox\"]";
6034
+ const COMPOSER_TOOL_MENU_STYLE = `
6035
+ [class*="_heroWorkspaceRow"] button{min-height:28px;border-radius:999px;font-size:13px;line-height:20px}
6036
+ [class*="_heroWorkspaceRow"] button:hover,[class*="_heroWorkspaceRow"] button[aria-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 8%,transparent)}
6037
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]){box-sizing:border-box;min-width:0!important;width:262px;max-width:calc(100vw - 24px);max-height:var(--dcu-tool-menu-height,360px)!important;padding:5px!important;border-radius:18px!important;background:#fff!important;color:var(--dsw-alias-label-primary);box-shadow:0 8px 32px #0002,0 0 0 1px #0000000a!important;display:flex;flex-direction:column;gap:0;z-index:1100}
6038
+ [data-dcu-tool-menu=portal]{position:fixed!important;left:var(--dcu-tool-menu-x)!important;top:var(--dcu-tool-menu-y)!important;bottom:auto!important;right:auto!important}
6039
+ :is([data-dcu-tool-menu=inline],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal])){width:320px;translate:var(--dcu-tool-menu-shift,0px) 0}
6040
+ [class*="_heroWorkspaceRow"] [data-gitgraph-popover]:not([data-dcu-tool-menu=portal]){top:auto!important;bottom:calc(100% + 4px)!important}
6041
+ body[data-ds-dark-theme] :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]){background:#292929!important;box-shadow:0 8px 32px #0003,0 0 0 1px #ffffff08!important}
6042
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover])>[class*="_viewport"]{min-height:0;max-height:none;overflow-y:auto;scrollbar-width:thin}
6043
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) :is([role=menuitem],[role=menuitemradio],[role=menuitemcheckbox],[role=option]){box-sizing:border-box;min-height:28px;padding:4px 9px;gap:8px;border-radius:8px;font-size:13px;line-height:20px}
6044
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) :is([role=menuitem],[role=menuitemradio],[role=option]):hover:not(:disabled),:is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) [class*="_selected"],:is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) [aria-selected=true],:is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) [aria-checked=true]{background:color-mix(in srgb,var(--dsw-alias-label-primary) 10%,transparent)}
6045
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) [class*="_itemIcon"] svg{width:16px;height:16px}
6046
+ :is([data-dcu-tool-menu],[class*="_heroWorkspaceRow"] [data-gitgraph-popover]) [class*="_footer"]{flex:none;margin-top:5px;padding-top:5px;border-top:1px solid color-mix(in srgb,var(--dsw-alias-label-primary) 10%,transparent)}
6047
+ [data-dcu-tool-filter]{box-sizing:border-box;flex:none;width:100%;height:32px;padding:4px 10px;margin:0 0 1px;border:0;border-radius:8px;outline:none;background:transparent;color:inherit;font:13px/20px var(--dsw-font-family,system-ui)}
6048
+ [data-dcu-tool-filter]:focus-visible{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dsw-alias-label-primary) 20%,transparent)}
6049
+ [data-dcu-tool-empty]{padding:8px 10px;font-size:13px;color:var(--dsw-alias-label-secondary)}
6050
+ [data-dcu-tool-filtered]{display:none!important}
6051
+ `;
6052
+ function observeComposerToolMenus(copy) {
6053
+ let anchor;
6054
+ let known = /* @__PURE__ */ new Set();
6055
+ let pendingUntil = 0;
6056
+ const mounted = /* @__PURE__ */ new Map();
6057
+ const now = () => Date.now();
6058
+ function capture(event) {
6059
+ const target = event.target instanceof Element ? event.target.closest(TOOL) : null;
6060
+ if (target === null || target.closest("[data-conversation-scroll]") === null) return;
6061
+ anchor = target;
6062
+ known = new Set(document.querySelectorAll(MENU));
6063
+ pendingUntil = now() + 1e3;
6064
+ }
6065
+ function mount(menu, trigger) {
6066
+ const portal = getComputedStyle(menu).position === "fixed";
6067
+ menu.setAttribute("data-dcu-tool-menu", portal ? "portal" : "inline");
6068
+ const isProject = trigger.matches("[class*=\"_heroWorkspaceRow\"]>button:first-child");
6069
+ const viewport = menu.querySelector(":scope>[class*=\"_viewport\"]");
6070
+ let input;
6071
+ let empty;
6072
+ if (isProject && viewport !== null && menu.querySelector("input") === null) {
6073
+ input = document.createElement("input");
6074
+ input.type = "search";
6075
+ input.placeholder = copy.search;
6076
+ input.setAttribute("aria-label", copy.search);
6077
+ input.setAttribute("data-dcu-tool-filter", "");
6078
+ empty = document.createElement("div");
6079
+ empty.setAttribute("data-dcu-tool-empty", "");
6080
+ empty.setAttribute("role", "status");
6081
+ empty.textContent = copy.empty;
6082
+ empty.hidden = true;
6083
+ menu.prepend(input);
6084
+ viewport.after(empty);
6085
+ input.addEventListener("input", () => {
6086
+ const query = input.value.trim().toLocaleLowerCase();
6087
+ let count = 0;
6088
+ for (const row of viewport.children) {
6089
+ const match = (row.textContent ?? "").toLocaleLowerCase().includes(query);
6090
+ row.toggleAttribute("data-dcu-tool-filtered", !match);
6091
+ if (match) count++;
6092
+ }
6093
+ empty.hidden = count > 0;
6094
+ place();
6095
+ });
6096
+ input.addEventListener("keydown", (event) => {
6097
+ if (event.key !== "ArrowDown" && event.key !== "Enter") return;
6098
+ const first = viewport.querySelector(":scope>:not([data-dcu-tool-filtered]) button:not(:disabled)");
6099
+ if (first !== null) {
6100
+ event.preventDefault();
6101
+ event.stopPropagation();
6102
+ first.focus();
6103
+ if (event.key === "Enter") first.click();
6104
+ }
6105
+ });
6106
+ }
6107
+ function place() {
6108
+ if (!trigger.isConnected || !menu.isConnected) return;
6109
+ const rect = trigger.getBoundingClientRect();
6110
+ const above = rect.top - 16;
6111
+ const below = window.innerHeight - rect.bottom - 16;
6112
+ const topSide = above >= Math.min(260, below);
6113
+ menu.style.setProperty("--dcu-tool-menu-height", `${Math.max(60, Math.min(360, topSide ? above : below))}px`);
6114
+ if (!portal) {
6115
+ const previous = parseFloat(menu.style.getPropertyValue("--dcu-tool-menu-shift")) || 0;
6116
+ const bounds = menu.getBoundingClientRect();
6117
+ const naturalLeft = bounds.left - previous;
6118
+ const left = Math.max(12, Math.min(naturalLeft, window.innerWidth - bounds.width - 12));
6119
+ menu.style.setProperty("--dcu-tool-menu-shift", `${left - naturalLeft}px`);
6120
+ return;
6121
+ }
6122
+ const bounds = menu.getBoundingClientRect();
6123
+ const x = Math.max(12, Math.min(rect.left, window.innerWidth - bounds.width - 12));
6124
+ const y = Math.max(12, topSide ? rect.top - bounds.height - 4 : rect.bottom + 4);
6125
+ menu.style.setProperty("--dcu-tool-menu-x", `${x}px`);
6126
+ menu.style.setProperty("--dcu-tool-menu-y", `${y}px`);
6127
+ }
6128
+ const resize = new ResizeObserver(place);
6129
+ resize.observe(menu);
6130
+ resize.observe(trigger);
6131
+ window.addEventListener("resize", place);
6132
+ window.addEventListener("scroll", place, true);
6133
+ place();
6134
+ mounted.set(menu, () => {
6135
+ resize.disconnect();
6136
+ window.removeEventListener("resize", place);
6137
+ window.removeEventListener("scroll", place, true);
6138
+ input?.remove();
6139
+ empty?.remove();
6140
+ menu.querySelectorAll("[data-dcu-tool-filtered]").forEach((row) => row.removeAttribute("data-dcu-tool-filtered"));
6141
+ menu.removeAttribute("data-dcu-tool-menu");
6142
+ for (const property of [
6143
+ "--dcu-tool-menu-x",
6144
+ "--dcu-tool-menu-y",
6145
+ "--dcu-tool-menu-height",
6146
+ "--dcu-tool-menu-shift"
6147
+ ]) menu.style.removeProperty(property);
6148
+ });
6149
+ }
6150
+ function sync() {
6151
+ for (const [menu, dispose] of mounted) if (!menu.isConnected) {
6152
+ dispose();
6153
+ mounted.delete(menu);
6154
+ }
6155
+ if (anchor === void 0 || now() > pendingUntil) return;
6156
+ for (const menu of document.querySelectorAll(MENU)) {
6157
+ if (known.has(menu) || mounted.has(menu) || menu.parentElement?.closest(MENU) !== null) continue;
6158
+ if (menu.getClientRects().length === 0) continue;
6159
+ mount(menu, anchor);
6160
+ pendingUntil = 0;
6161
+ break;
6162
+ }
6163
+ }
6164
+ const observer = new MutationObserver(sync);
6165
+ observer.observe(document.body, {
6166
+ childList: true,
6167
+ subtree: true
6168
+ });
6169
+ document.addEventListener("pointerdown", capture, true);
6170
+ document.addEventListener("keydown", captureKey, true);
6171
+ function captureKey(event) {
6172
+ if ([
6173
+ "Enter",
6174
+ " ",
6175
+ "ArrowDown"
6176
+ ].includes(event.key)) capture(event);
6177
+ }
6178
+ return () => {
6179
+ observer.disconnect();
6180
+ document.removeEventListener("pointerdown", capture, true);
6181
+ document.removeEventListener("keydown", captureKey, true);
6182
+ mounted.forEach((dispose) => dispose());
6183
+ mounted.clear();
6184
+ };
6185
+ }
6186
+ //#endregion
6187
+ //#region src/client/NewConversationSuggestions.tsx
6188
+ const categories = [
6189
+ {
6190
+ id: "explore",
6191
+ label: "home.explore",
6192
+ tasks: [{
6193
+ label: "home.explore.task1",
6194
+ prompt: "home.explore.prompt1"
6195
+ }, {
6196
+ label: "home.explore.task2",
6197
+ prompt: "home.explore.prompt2"
6198
+ }],
6199
+ Icon: Telescope,
6200
+ color: "#27aaff"
6201
+ },
6202
+ {
6203
+ id: "build",
6204
+ label: "home.build",
6205
+ tasks: [{
6206
+ label: "home.build.task1",
6207
+ prompt: "home.build.prompt1"
6208
+ }, {
6209
+ label: "home.build.task2",
6210
+ prompt: "home.build.prompt2"
6211
+ }],
6212
+ Icon: Hammer,
6213
+ color: "#a478e8"
6214
+ },
6215
+ {
6216
+ id: "review",
6217
+ label: "home.review",
6218
+ tasks: [{
6219
+ label: "home.review.task1",
6220
+ prompt: "home.review.prompt1"
6221
+ }, {
6222
+ label: "home.review.task2",
6223
+ prompt: "home.review.prompt2"
6224
+ }],
6225
+ Icon: ScanLine,
6226
+ color: "#44bd83"
6227
+ },
6228
+ {
6229
+ id: "fix",
6230
+ label: "home.fix",
6231
+ tasks: [{
6232
+ label: "home.fix.task1",
6233
+ prompt: "home.fix.prompt1"
6234
+ }, {
6235
+ label: "home.fix.task2",
6236
+ prompt: "home.fix.prompt2"
6237
+ }],
6238
+ Icon: Bug,
6239
+ color: "#f48235"
6240
+ }
6241
+ ];
6242
+ const hints = {
6243
+ workspace: "home.workspace",
6244
+ draft: "home.draft",
6245
+ busy: "home.busy"
6246
+ };
6247
+ const emptyDraft = {
6248
+ getSnapshot: () => false,
6249
+ subscribe: () => () => {}
6250
+ };
6251
+ /** 只向宿主标题容器贡献自己的 React portal,不搬动标题、工具条或编辑器。 */
6252
+ function NewConversationSuggestions({ t, prefill, draftSource = emptyDraft }) {
6253
+ const hasDraft = (0, react.useSyncExternalStore)(draftSource.subscribe, draftSource.getSnapshot, emptyDraft.getSnapshot);
6254
+ const [target, setTarget] = (0, react.useState)(null);
6255
+ (0, react.useEffect)(() => {
6256
+ const sync = () => setTarget(document.querySelector("[data-phase=hero] [class*=\"_composerHero\"]>:first-child>[class$=\"_stack\"]"));
6257
+ sync();
6258
+ const observer = new MutationObserver(sync);
6259
+ observer.observe(document.body, {
6260
+ childList: true,
6261
+ subtree: true,
6262
+ attributes: true,
6263
+ attributeFilter: ["data-phase"]
6264
+ });
6265
+ return () => observer.disconnect();
6266
+ }, []);
6267
+ return target === null ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SuggestionCards, {
6268
+ t,
6269
+ prefill,
6270
+ hasDraft
6271
+ }), target);
6272
+ }
6273
+ function SuggestionCards({ t, prefill, hasDraft = false }) {
6274
+ const [selected, setSelected] = (0, react.useState)();
6275
+ const [hint, setHint] = (0, react.useState)("ready");
6276
+ function fill(text) {
6277
+ const result = prefill?.(text) ?? "workspace";
6278
+ setHint(result);
6279
+ if (result === "ready") document.querySelector("[data-phase=hero] [data-lexical-editor=true]")?.focus();
6280
+ if (result === "workspace") document.querySelector("[data-phase=hero] [class*=\"_heroWorkspaceRow\"]>button")?.click();
6281
+ }
6282
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6283
+ className: "dcu-home-suggestions",
6284
+ "data-has-draft": hasDraft,
6285
+ "aria-hidden": hasDraft,
6286
+ "aria-label": t("home.suggestions"),
6287
+ children: [
6288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6289
+ className: "dcu-home-cards",
6290
+ children: categories.map(({ id, label, Icon, color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6291
+ type: "button",
6292
+ disabled: hasDraft,
6293
+ className: "dcu-home-card",
6294
+ style: { "--dcu-home-icon": color },
6295
+ "aria-pressed": selected === id,
6296
+ onClick: () => {
6297
+ setSelected(selected === id ? void 0 : id);
6298
+ setHint("ready");
6299
+ },
6300
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { "aria-hidden": "true" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(label) })]
6301
+ }, id))
6302
+ }),
6303
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6304
+ className: "dcu-home-details",
6305
+ children: categories.map((category) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6306
+ className: "dcu-home-tasks",
6307
+ "data-active": selected === category.id,
6308
+ "aria-hidden": selected !== category.id,
6309
+ children: category.tasks.map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6310
+ type: "button",
6311
+ className: "dcu-home-task",
6312
+ disabled: hasDraft || selected !== category.id,
6313
+ onClick: () => fill(t(task.prompt)),
6314
+ children: t(task.label)
6315
+ }, task.label))
6316
+ }, category.id))
6317
+ }),
6318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6319
+ className: "dcu-home-status",
6320
+ children: Object.keys(hints).map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6321
+ className: "dcu-home-hint",
6322
+ "data-active": hint === key,
6323
+ "aria-hidden": hint !== key,
6324
+ role: hint === key ? "status" : void 0,
6325
+ children: t(hints[key])
6326
+ }, key))
6327
+ })
6328
+ ]
6329
+ });
6330
+ }
6331
+ //#endregion
5717
6332
  //#region src/client/CodexSidebar.tsx
5718
6333
  const subscribeEmptyCompanionTabs = () => () => {};
5719
6334
  const getEmptyCompanionTabs = () => EMPTY_COMPANION_TABS;
@@ -5732,7 +6347,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5732
6347
  });
5733
6348
  }
5734
6349
  const stylesheet$3 = `
5735
- .dcu-root{--dcu-font:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei UI",sans-serif;--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:#eef7f5;color:var(--dcu-sidebar-primary);font:14px/20px var(--dcu-font)}body[data-ds-dark-theme] .dcu-root{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)}
6350
+ .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)}
5736
6351
  /* 滤镜只作用于背景,避免为设置和搜索等 fixed 后代创建侧栏包含块。 */
5737
6352
  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}}
5738
6353
  body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu-compact-shell,body[data-we-sidebar-glass] .dcu-foot{position:relative}
@@ -5780,7 +6395,23 @@ body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu
5780
6395
  .dcu-native-workspaces{flex-direction:column}.dcu-native-workspaces>[data-mcp-connector-top-mount=true]{flex:none}.dcu-root .mcpConnectorLauncher,.dcu-root [data-mcp-connector-top-mount=true]{display:none!important}
5781
6396
  .dcu-dependency-notice{margin:0 10px 8px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;padding:8px;color:var(--dcu-sidebar-secondary);font-size:12px;line-height:18px}
5782
6397
  .dcu-search-scrim{position:fixed;z-index:10020;inset:0;display:flex;justify-content:center;align-items:flex-start;padding:72px 20px;background:color-mix(in srgb,#000 48%,transparent);animation:dcu-search-scrim-in 140ms ease-out}.dcu-search-dialog{width:min(560px,100%);max-height:min(640px,calc(100vh - 120px));overflow:auto;border:1px solid var(--dcu-sidebar-border);border-radius:16px;padding:10px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv4);animation:dcu-search-dialog-in 180ms cubic-bezier(.16,1,.3,1)}@keyframes dcu-search-scrim-in{from{opacity:0}to{opacity:1}}@keyframes dcu-search-dialog-in{from{opacity:0;transform:translateY(-6px) scale(.985)}to{opacity:1}}.dcu-search-input{margin-bottom:8px}.dcu-search-section{padding:6px 0}.dcu-search-title{padding:0 8px 4px;color:var(--dcu-sidebar-tertiary);font-size:12px;font-weight:600}.dcu-search-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;width:100%;min-height:34px;border:0;border-radius:8px;padding:6px 8px;background:transparent;color:var(--dcu-sidebar-primary);font:inherit;text-align:left;cursor:pointer}.dcu-search-row:hover,.dcu-search-row[data-active=true]{background:var(--dcu-sidebar-hover)}.dcu-search-main{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dcu-search-detail{max-width:160px;overflow:hidden;color:var(--dcu-sidebar-tertiary);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.dcu-search-empty{padding:18px 8px;color:var(--dcu-sidebar-tertiary);font-size:13px}@media (prefers-reduced-motion:reduce){.dcu-expanded-shell,.dcu-root.dcu-compact .dcu-compact-shell,.dcu-foot,.dcu-search-scrim,.dcu-search-dialog,.dcu-extension-panel,.dcu-extension-leading svg{animation:none;transition:none}}
5783
- [data-conversation-scroll]{--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:24px}[data-conversation-scroll] [data-composer-card]{min-height:96px;padding-top:10px;border-radius:16px;box-shadow:var(--dsw-shadow-lv3);transition:border-color 180ms ease,box-shadow 180ms ease}[data-conversation-scroll] [data-composer-card]:focus-within{border-color:var(--dsw-alias-button-info-fill);box-shadow:0 0 0 2px var(--dsw-static-deepseek-50),var(--dsw-shadow-lv3)}[data-conversation-scroll] [data-input-mirror]{min-height:44px}@media (prefers-reduced-motion:reduce){[data-conversation-scroll] [data-composer-card]{transition:none}}
6398
+ [data-conversation-scroll]{--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:24px;--dcu-composer-bg:var(--dsw-specific-input-major,#fff);--dcu-composer-shadow:0 0 0 1px #0000000a,0 2px 8px #0000000a,0 4px 80px 8px #00000006}
6399
+ body[data-ds-dark-theme] [data-conversation-scroll]{--dcu-composer-bg:var(--dsw-alias-bg-layer-2,#242424);--dcu-composer-shadow:inset 0 0 1px #fff3}
6400
+ [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)}
6401
+ [data-conversation-scroll] [data-input-mirror]{min-height:44px}
6402
+ [data-conversation-scroll] [data-composer-card] [data-input-scroll]{margin-right:0}
6403
+ [data-conversation-scroll] [data-input-scroll] [data-lexical-editor=true]{min-height:44px;padding:0 12px}
6404
+ [data-conversation-scroll] [data-composer-placeholder]{inset:0 12px auto}
6405
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div{padding:0 8px 8px;gap:5px}
6406
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div>div{gap:4px}
6407
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div>div>div{gap:4px}
6408
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div :is(button,select):not([role]){min-height:28px;height:28px}
6409
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div button[class$=_primary]{width:28px;transform:none;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base)}
6410
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div button[class$=_primary]:hover:not(:disabled){background:var(--dsw-alias-label-secondary)}
6411
+ [data-conversation-scroll] [data-composer-card]>[data-input-scroll]+div :is(button,select):focus-visible{outline:2px solid var(--dsw-alias-label-secondary);outline-offset:2px}
6412
+ @supports(corner-shape:superellipse(1.5)){[data-conversation-scroll] [data-composer-card]{border-radius:25px;corner-shape:superellipse(1.5)}}
6413
+ @media(max-width:639px){[data-conversation-scroll]{--dcu-composer-shadow:0 0 0 1px #0000000a,0 2px 8px #0000000a,0 4px 40px 8px #00000006}}
6414
+ @media(forced-colors:active){[data-conversation-scroll] [data-composer-card]{outline:1px solid CanvasText}}
5784
6415
  html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:has([data-dcu-official-turn-navigator]) .dcu-turn-navigator{display:none}
5785
6416
  [data-dcu-official-turn-navigator]{right:auto!important;left:calc(12px - (var(--dsh-composer-side-clearance) + 16px))!important}
5786
6417
  [data-dcu-official-turn-mark]{inset:0 auto 0 0!important}
@@ -6095,7 +6726,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6095
6726
  });
6096
6727
  });
6097
6728
  /** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
6098
- function CodexSidebar({ collapsed, width, openSession, startSession, toggleSidebar, archiveSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces }) {
6729
+ function CodexSidebar({ collapsed, width, openSession, startSession, toggleSidebar, archiveSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
6099
6730
  const compact = collapsed || width < 80;
6100
6731
  const [visualCompact, setVisualCompact] = (0, react.useState)(compact);
6101
6732
  const [collapsing, setCollapsing] = (0, react.useState)(false);
@@ -6272,6 +6903,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6272
6903
  "aria-label": t("sidebar.label"),
6273
6904
  children: [
6274
6905
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: stylesheet$3 }),
6906
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: NEW_CONVERSATION_STYLE }),
6907
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: COMPOSER_TOOL_MENU_STYLE }),
6908
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewConversationSuggestions, {
6909
+ t,
6910
+ prefill: prefillNewConversation,
6911
+ draftSource: newConversationDraft
6912
+ }),
6275
6913
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6276
6914
  className: "dcu-expanded-shell",
6277
6915
  children: [
@@ -6615,6 +7253,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6615
7253
  id: "schedule",
6616
7254
  packageName: "@michengai/dsh-automation"
6617
7255
  },
7256
+ {
7257
+ id: "pet",
7258
+ packageName: "@michengai/dsh-codex-pet"
7259
+ },
6618
7260
  {
6619
7261
  id: "btw",
6620
7262
  packageName: "@michengai/dsh-btw"
@@ -7177,9 +7819,56 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7177
7819
  /** 本插件独占的界面文案命名空间。 */
7178
7820
  const NS = "michengai.codexUi";
7179
7821
  const zh = {
7822
+ "home.resizeInput": "拖动调整输入区宽度",
7823
+ "home.projectSearch": "搜索项目",
7824
+ "home.projectEmpty": "没有匹配的项目",
7825
+ "home.suggestions": "开始一项任务",
7826
+ "home.workspace": "请先选择工作区,再选择任务。",
7827
+ "home.draft": "已保留当前草稿和附件;清空输入后可填入任务建议。",
7828
+ "home.busy": "当前输入正在处理中,请稍后再试。",
7829
+ "home.explore": "探索并理解代码",
7830
+ "home.build": "构建新功能、应用或工具",
7831
+ "home.review": "审查代码并提出修改建议",
7832
+ "home.fix": "修复问题和失败",
7833
+ "home.explore.task1": "了解项目结构",
7834
+ "home.explore.prompt1": "请探索当前工作区的代码,解释项目结构、主要入口和模块之间的关系。",
7835
+ "home.explore.task2": "理解一项功能",
7836
+ "home.explore.prompt2": "我想了解一项功能的实现。先问我具体是哪项功能,再沿调用关系解释。",
7837
+ "home.build.task1": "实现一项新功能",
7838
+ "home.build.prompt1": "我想在当前项目中实现一项新功能。先和我确认需求与验收标准,再实施。",
7839
+ "home.build.task2": "构建一个小工具",
7840
+ "home.build.prompt2": "我想构建一个小工具。先问我目标、输入和输出,再结合当前项目提出方案。",
7841
+ "home.review.task1": "评审当前改动",
7842
+ "home.review.prompt1": "请评审当前工作区的未提交改动,优先指出真实缺陷、回归风险和缺少的测试;先不要修改。",
7843
+ "home.review.task2": "检查代码质量",
7844
+ "home.review.prompt2": "请检查当前项目的代码质量,给出有源码依据的改进建议,先评估不改动。",
7845
+ "home.fix.task1": "排查一个问题",
7846
+ "home.fix.prompt1": "我遇到了一个问题。先问我复现步骤、预期和实际表现,再定位根因并修复。",
7847
+ "home.fix.task2": "修复失败的测试",
7848
+ "home.fix.prompt2": "请运行当前项目适用的测试,定位失败根因并做最小修复,保留有效的回归覆盖。",
7849
+ "host.transcript.normal": "标准",
7850
+ "host.transcript.compact": "紧凑",
7851
+ "host.command.compact": "压缩较早的对话历史",
7852
+ "host.command.export": "将当前会话日志下载为 ZIP 压缩包",
7853
+ "host.command.feedback": "记录对当前会话的反馈",
7854
+ "host.command.goal": "设置或查看长时间任务的目标",
7855
+ "host.command.permission": "切换权限预设(沙箱模式与审批策略)",
7856
+ "host.command.plan": "进入或退出计划模式",
7857
+ "usage.title": "使用统计",
7858
+ "usage.loading": "正在加载费用面板…",
7859
+ "usage.failed": "费用面板暂时无法嵌入,可重试或打开原弹窗。",
7860
+ "usage.closed": "费用面板已关闭。",
7861
+ "usage.reopen": "重新打开费用面板",
7862
+ "usage.retry": "重试",
7863
+ "usage.original": "打开原弹窗",
7180
7864
  "settings.title": "设置",
7181
7865
  "settings.back": "返回应用",
7182
7866
  "settings.openDocument": "打开配置文件",
7867
+ "settings.advanced": "高级",
7868
+ "settings.documentTitle": "配置文件",
7869
+ "settings.documentDescription": "在外部编辑器中查看和编辑配置",
7870
+ "settings.documentOpen": "打开",
7871
+ "settings.documentOpening": "打开中…",
7183
7872
  "settings.openDocumentError": "无法打开配置文件",
7184
7873
  "settings.search": "搜索设置…",
7185
7874
  "settings.personal": "个人",
@@ -7344,7 +8033,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7344
8033
  "about.feature.conversation": "保留原生消息、工具调用、输入、权限和模型选择,仅调整容器视觉",
7345
8034
  "about.feature.navigator": "当前会话提供轮次缩略导航,可快速跳转至每一次用户提问",
7346
8035
  "about.dependencies": "配套管理插件",
7347
- "about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM、定时任务、BTW 和第三方插件市场。",
8036
+ "about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM、定时任务、宠物、BTW、Simplify 和第三方插件市场。",
7348
8037
  "about.loading": "正在读取依赖安装状态…",
7349
8038
  "about.statusFailed": "暂时无法读取依赖安装状态。",
7350
8039
  "about.refreshFailed": "依赖状态刷新失败,当前显示上次成功读取的结果。",
@@ -7384,6 +8073,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7384
8073
  "about.dependency.archive": "归档会话",
7385
8074
  "about.dependency.im": "IM助理",
7386
8075
  "about.dependency.schedule": "定时任务",
8076
+ "about.dependency.pet": "Codex 宠物",
7387
8077
  "about.dependency.btw": "BTW 旁问",
7388
8078
  "about.dependency.simplify": "Simplify",
7389
8079
  "about.dependency.market": "插件市场",
@@ -7406,9 +8096,56 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7406
8096
  "meta.locale": "zh-CN"
7407
8097
  };
7408
8098
  const en = {
8099
+ "home.resizeInput": "Drag to resize the input area",
8100
+ "home.projectSearch": "Search projects",
8101
+ "home.projectEmpty": "No matching projects",
8102
+ "home.suggestions": "Start a task",
8103
+ "home.workspace": "Choose a workspace first, then select a task.",
8104
+ "home.draft": "Your draft and attachments are preserved. Clear the input to use a suggestion.",
8105
+ "home.busy": "The input is busy. Please try again shortly.",
8106
+ "home.explore": "Explore and understand code",
8107
+ "home.build": "Build features, apps, or tools",
8108
+ "home.review": "Review code and suggest changes",
8109
+ "home.fix": "Fix bugs and failures",
8110
+ "home.explore.task1": "Explain the project structure",
8111
+ "home.explore.prompt1": "Explore this workspace and explain its structure, main entry points, and module relationships.",
8112
+ "home.explore.task2": "Understand a feature",
8113
+ "home.explore.prompt2": "Help me understand a feature. First ask which feature, then explain its implementation and call flow.",
8114
+ "home.build.task1": "Implement a feature",
8115
+ "home.build.prompt1": "Help me implement a feature in this project. First clarify requirements and acceptance criteria.",
8116
+ "home.build.task2": "Build a small tool",
8117
+ "home.build.prompt2": "Help me build a small tool. First ask about its goal, inputs, and outputs, then propose an approach.",
8118
+ "home.review.task1": "Review current changes",
8119
+ "home.review.prompt1": "Review uncommitted changes for bugs, regressions, and missing tests. Do not modify files yet.",
8120
+ "home.review.task2": "Inspect code quality",
8121
+ "home.review.prompt2": "Inspect code quality in this project and suggest improvements grounded in the source. Assess only; do not edit.",
8122
+ "home.fix.task1": "Investigate a bug",
8123
+ "home.fix.prompt1": "Help me fix a bug. First ask for reproduction steps, expected behavior, and actual behavior.",
8124
+ "home.fix.task2": "Fix failing tests",
8125
+ "home.fix.prompt2": "Run the applicable project tests, identify failure causes, and make minimal fixes with meaningful regression coverage.",
8126
+ "host.transcript.normal": "Normal",
8127
+ "host.transcript.compact": "Compact",
8128
+ "host.command.compact": "Compact older conversation history",
8129
+ "host.command.export": "Download this Session log as a ZIP archive",
8130
+ "host.command.feedback": "record feedback about this session",
8131
+ "host.command.goal": "set or view the goal for a long-running task",
8132
+ "host.command.permission": "Switch the permission preset (sandbox mode + approval policy)",
8133
+ "host.command.plan": "Enter or leave plan mode",
8134
+ "usage.title": "Usage statistics",
8135
+ "usage.loading": "Loading billing dashboard…",
8136
+ "usage.failed": "The embedded dashboard is unavailable. Retry or open the original dialog.",
8137
+ "usage.closed": "The billing dashboard is closed.",
8138
+ "usage.reopen": "Reopen billing dashboard",
8139
+ "usage.retry": "Retry",
8140
+ "usage.original": "Open original dialog",
7409
8141
  "settings.title": "Settings",
7410
8142
  "settings.back": "Back to app",
7411
8143
  "settings.openDocument": "Open configuration file",
8144
+ "settings.advanced": "Advanced",
8145
+ "settings.documentTitle": "Configuration file",
8146
+ "settings.documentDescription": "View and edit configuration in an external editor",
8147
+ "settings.documentOpen": "Open",
8148
+ "settings.documentOpening": "Opening…",
7412
8149
  "settings.openDocumentError": "Could not open configuration file",
7413
8150
  "settings.search": "Search settings…",
7414
8151
  "settings.personal": "Personal",
@@ -7573,7 +8310,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7573
8310
  "about.feature.conversation": "Keeps native messages, tool calls, composer, permissions, and model selection while refining the container visuals",
7574
8311
  "about.feature.navigator": "Navigate directly to each user prompt with the current conversation turn navigator",
7575
8312
  "about.dependencies": "Companion management plugins",
7576
- "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.",
8313
+ "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.",
7577
8314
  "about.loading": "Loading dependency status…",
7578
8315
  "about.statusFailed": "Dependency status is temporarily unavailable.",
7579
8316
  "about.refreshFailed": "Dependency status refresh failed. Showing the last successful result.",
@@ -7613,6 +8350,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7613
8350
  "about.dependency.archive": "Archived conversations",
7614
8351
  "about.dependency.im": "IM Assistant",
7615
8352
  "about.dependency.schedule": "Scheduled tasks",
8353
+ "about.dependency.pet": "Codex Pet",
7616
8354
  "about.dependency.btw": "BTW",
7617
8355
  "about.dependency.simplify": "Simplify",
7618
8356
  "about.dependency.market": "Plugin Market",
@@ -7769,9 +8507,216 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7769
8507
  };
7770
8508
  }
7771
8509
  //#endregion
8510
+ //#region src/usage-frame/contract.ts
8511
+ /** 同源费用承载页与宿主之间的最小能力桥;不暴露 Context 或远程服务全集。 */
8512
+ const USAGE_FRAME_PATH = "/api/dsh-codex-ui/usage/frame";
8513
+ const BILLING_ENTRY_ID = "usage-billing";
8514
+ //#endregion
8515
+ //#region src/client/UsageStatisticsSection.tsx
8516
+ /** 设置中的费用原面板承载区;不重建图表、计费或原面板的业务逻辑。 */
8517
+ function UsageStatisticsSection({ useStore, actions, billing, close, openOriginal, t }) {
8518
+ const snapshot = useStore((state) => state);
8519
+ const latest = (0, react.useRef)(snapshot);
8520
+ const listeners = (0, react.useRef)(/* @__PURE__ */ new Set());
8521
+ const frame = (0, react.useRef)(null);
8522
+ const [attempt, setAttempt] = (0, react.useState)(0);
8523
+ const [state, setState] = (0, react.useState)("loading");
8524
+ const disposeTheme = (0, react.useRef)(() => {});
8525
+ const timer = (0, react.useRef)(void 0);
8526
+ (0, react.useEffect)(() => {
8527
+ latest.current = snapshot;
8528
+ listeners.current.forEach((listener) => listener());
8529
+ }, [snapshot]);
8530
+ (0, react.useEffect)(() => {
8531
+ setState("loading");
8532
+ timer.current = setTimeout(() => {
8533
+ setState("failed");
8534
+ }, 15e3);
8535
+ return () => {
8536
+ clearTimeout(timer.current);
8537
+ disposeTheme.current();
8538
+ listeners.current.clear();
8539
+ };
8540
+ }, [attempt]);
8541
+ (0, react.useEffect)(() => {
8542
+ if ((state === "closed" || state === "failed") && document.activeElement === frame.current) frame.current?.parentElement?.querySelector("button")?.focus();
8543
+ }, [state]);
8544
+ const connect = () => {
8545
+ const target = frame.current?.contentWindow;
8546
+ if (!target) return;
8547
+ try {
8548
+ if (target.location.origin !== location.origin || target.location.pathname !== "/api/dsh-codex-ui/usage/frame") throw new Error("费用承载页地址不匹配");
8549
+ const document = target.document;
8550
+ if (!target.dcuUsageRuntimeReady || !document.getElementById("billing-root")) throw new Error("费用承载页未正确加载");
8551
+ const sync = () => {
8552
+ document.body.toggleAttribute("data-ds-dark-theme", window.document.body.hasAttribute("data-ds-dark-theme"));
8553
+ document.documentElement.lang = window.document.documentElement.lang;
8554
+ const tokens = getComputedStyle(window.document.body);
8555
+ for (const key of tokens) if (key.startsWith("--dsw-")) document.body.style.setProperty(key, tokens.getPropertyValue(key));
8556
+ };
8557
+ sync();
8558
+ disposeTheme.current();
8559
+ const observer = new MutationObserver(sync);
8560
+ observer.observe(window.document.body, {
8561
+ attributes: true,
8562
+ attributeFilter: [
8563
+ "data-ds-dark-theme",
8564
+ "class",
8565
+ "style"
8566
+ ]
8567
+ });
8568
+ disposeTheme.current = () => observer.disconnect();
8569
+ target.dcuUsageHost = {
8570
+ getSnapshot: () => latest.current,
8571
+ subscribe: (listener) => {
8572
+ listeners.current.add(listener);
8573
+ return () => {
8574
+ listeners.current.delete(listener);
8575
+ };
8576
+ },
8577
+ actions,
8578
+ ...billing,
8579
+ close,
8580
+ dismissed: () => {
8581
+ clearTimeout(timer.current);
8582
+ setState((current) => current === "failed" ? current : "closed");
8583
+ },
8584
+ focusOutside: (backward) => {
8585
+ const page = frame.current?.closest("[data-dcu-settings-page]");
8586
+ if (!page || !frame.current) return;
8587
+ const controls = [...page.querySelectorAll("button,input,select,textarea,a[href],[tabindex]")].filter((element) => element.tabIndex >= 0 && !element.matches(":disabled") && !element.closest("[inert]") && element.getClientRects().length > 0);
8588
+ controls[(controls.indexOf(frame.current) + (backward ? -1 : 1) + controls.length) % controls.length]?.focus();
8589
+ },
8590
+ ready: () => {
8591
+ clearTimeout(timer.current);
8592
+ setState((current) => current === "failed" ? current : "ready");
8593
+ },
8594
+ failed: (message) => {
8595
+ console.warn("[michengai-codex-ui] 费用承载失败:%s", message);
8596
+ clearTimeout(timer.current);
8597
+ setState("failed");
8598
+ }
8599
+ };
8600
+ target.postMessage({ type: "dcu-usage-init" }, location.origin);
8601
+ } catch (error) {
8602
+ console.warn("[michengai-codex-ui] 无法连接费用承载页", error);
8603
+ clearTimeout(timer.current);
8604
+ setState("failed");
8605
+ }
8606
+ };
8607
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
8608
+ className: "dcu-usage-section",
8609
+ "aria-label": t("usage.title"),
8610
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: t("usage.title") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8611
+ className: "dcu-usage-stage",
8612
+ "aria-busy": state === "loading",
8613
+ children: [
8614
+ state === "loading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8615
+ className: "dcu-usage-loading",
8616
+ role: "status",
8617
+ children: t("usage.loading")
8618
+ }),
8619
+ state === "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8620
+ role: "status",
8621
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("usage.closed") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8622
+ onClick: () => setAttempt((value) => value + 1),
8623
+ children: t("usage.reopen")
8624
+ })]
8625
+ }),
8626
+ state === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8627
+ role: "alert",
8628
+ children: [
8629
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("usage.failed") }),
8630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8631
+ onClick: () => {
8632
+ setAttempt((value) => value + 1);
8633
+ },
8634
+ children: t("usage.retry")
8635
+ }),
8636
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8637
+ onClick: () => {
8638
+ close();
8639
+ requestAnimationFrame(openOriginal);
8640
+ },
8641
+ children: t("usage.original")
8642
+ })
8643
+ ]
8644
+ }),
8645
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
8646
+ ref: frame,
8647
+ title: t("usage.title"),
8648
+ src: USAGE_FRAME_PATH,
8649
+ onLoad: connect,
8650
+ "aria-hidden": state !== "ready",
8651
+ tabIndex: state === "ready" ? 0 : -1,
8652
+ style: { visibility: state === "ready" ? "visible" : "hidden" },
8653
+ className: "dcu-usage-frame"
8654
+ }, attempt)
8655
+ ]
8656
+ })]
8657
+ });
8658
+ }
8659
+ //#endregion
8660
+ //#region src/client/usage-statistics.ts
8661
+ function registerUsageStatistics(ctx) {
8662
+ const t = ctx.locale.bind(NS);
8663
+ ctx.slots.inject("settings.section", () => {
8664
+ let current;
8665
+ let remove;
8666
+ const refresh = () => {
8667
+ const entry = ctx.slots.entriesOfSlot("sidebar.footer.action").find((item) => item.options.id === BILLING_ENTRY_ID);
8668
+ if (entry === current) return;
8669
+ remove?.();
8670
+ remove = void 0;
8671
+ current = entry;
8672
+ if (!entry?.store || typeof entry.store === "function" || !entry.locale || !entry.inject) return;
8673
+ const face = entry.inject();
8674
+ if (typeof face.checkModels !== "function" || typeof face.publishCosts !== "function") return;
8675
+ const billing = {
8676
+ translate: ctx.locale.bind(entry.locale),
8677
+ checkModels: face.checkModels,
8678
+ publishCosts: face.publishCosts
8679
+ };
8680
+ remove = ctx.slots.register({
8681
+ name: "settings.section",
8682
+ id: "usage-statistics",
8683
+ order: 90,
8684
+ label: () => t("usage.title"),
8685
+ locale: NS,
8686
+ store: entry.store,
8687
+ inject: () => ({
8688
+ billing,
8689
+ openOriginal: () => {
8690
+ ctx.get("billingMetrics")?.openDashboard?.();
8691
+ }
8692
+ })
8693
+ }, UsageStatisticsSection);
8694
+ };
8695
+ const unsubscribe = ctx.slots.subscribe("sidebar.footer.action", refresh);
8696
+ refresh();
8697
+ return () => {
8698
+ unsubscribe();
8699
+ remove?.();
8700
+ };
8701
+ });
8702
+ ctx.effect(() => {
8703
+ const onClick = (event) => {
8704
+ if (!(event.target instanceof Element) || !event.target.closest(".dcu-footer-actions [data-testid=\"billing-trigger\"],.dcu-footer-actions [data-testid=\"billing-rail-button\"]")) return;
8705
+ if (!ctx.slots.entriesOfSlot("settings.section").some((entry) => entry.options.id === "usage-statistics")) return;
8706
+ const seat = document.querySelector(".dcu-settings-seat");
8707
+ if (!seat?.querySelector("[data-dcu-settings-trigger]")) return;
8708
+ event.preventDefault();
8709
+ event.stopPropagation();
8710
+ openSettingsSection(seat, t("usage.title"));
8711
+ };
8712
+ document.addEventListener("click", onClick, true);
8713
+ return () => document.removeEventListener("click", onClick, true);
8714
+ }, "michengai-codex-ui: usage navigation");
8715
+ }
8716
+ //#endregion
7772
8717
  //#region src/client/settings-page-model.ts
7773
8718
  function settingsGroup(id) {
7774
- if (/archive|about/.test(id)) return "records";
8719
+ if (/archive|about|^usage-statistics$/.test(id)) return "records";
7775
8720
  if (/^(general|appearance|theme|language|shortcuts|voice|account)$/.test(id)) return "personal";
7776
8721
  return "integrations";
7777
8722
  }
@@ -7788,14 +8733,15 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7788
8733
  //#region src/client/settings-page-styles.ts
7789
8734
  /** Codex 设置页的局部 tokens 与布局,不覆盖宿主其他弹窗。 */
7790
8735
  const settingsPageStyles = `
7791
- .dcu-settings-page{--sp-bg:#fff;--sp-nav:#f5f5f5;--sp-card:#fafafa;--sp-border:#e5e5e5;--sp-text:#303030;--sp-muted:#737373;--sp-hover:#e9e9e9;--sp-active:#e4e4e4;position:fixed;inset:0;z-index:1000;display:grid;grid-template-columns:240px minmax(0,1fr);background:var(--sp-bg);color:var(--sp-text);font:14px/1.5 var(--dcu-font,system-ui);text-align:left;isolation:isolate}
7792
- body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--sp-card:#232323;--sp-border:#333;--sp-text:#dedede;--sp-muted:#a1a1a1;--sp-hover:#292c2b;--sp-active:#303332;color-scheme:dark}
8736
+ .dcu-settings-page{--sp-bg:#fff;--sp-nav:var(--dcu-sidebar-background,#eef7f5);--sp-card:#fafafa;--sp-border:#e5e5e5;--sp-text:#303030;--sp-muted:#737373;--sp-hover:#e9e9e9;--sp-active:#e4e4e4;position:fixed;inset:0;z-index:1000;display:grid;grid-template-columns:clamp(240px,var(--dcu-sidebar-expanded-width,275px),min(520px,calc(100vw - 320px))) minmax(0,1fr);background:var(--sp-bg);color:var(--sp-text);font:14px/1.5 var(--dcu-font,system-ui);text-align:left;isolation:isolate}
8737
+ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:var(--dcu-sidebar-background,#1d2120);--sp-card:#232323;--sp-border:#333;--sp-text:#dedede;--sp-muted:#a1a1a1;--sp-hover:#292c2b;--sp-active:#303332;color-scheme:dark}
7793
8738
  .dcu-settings-page *{box-sizing:border-box}
7794
8739
  .dcu-settings-page button,.dcu-settings-page input{font:inherit}
7795
8740
  .dcu-settings-page button{cursor:pointer}
7796
8741
  .dcu-settings-page :focus-visible{outline:2px solid #459cff;outline-offset:3px}
7797
- .dcu-settings-nav{display:flex;flex-direction:column;min-height:0;padding:18px 8px;background:var(--sp-nav);border-right:1px solid var(--sp-border);overflow-y:auto}
7798
- .dcu-settings-back{display:flex;align-items:center;gap:8px;width:100%;padding:8px;border:0;border-radius:7px;background:transparent;color:var(--sp-text);text-align:left}
8742
+ .dcu-settings-nav{--sp-text:var(--dcu-sidebar-navigation,#4e5253);--sp-muted:var(--dcu-sidebar-secondary,#676b6c);--sp-hover:var(--dcu-sidebar-hover,#dfe8e5);--sp-active:var(--dcu-sidebar-hover,#dfe8e5);--sp-border:var(--dcu-sidebar-border,rgba(37,46,41,.10));display:flex;flex-direction:column;min-height:0;padding:18px 8px;background:var(--sp-nav);box-shadow:inset -1px 0 var(--sp-border);overflow-y:auto}
8743
+ body[data-ds-dark-theme] .dcu-settings-nav{--sp-text:var(--dcu-sidebar-navigation,#b9bab9);--sp-muted:var(--dcu-sidebar-secondary,#909191);--sp-hover:var(--dcu-sidebar-hover,#303432);--sp-active:var(--dcu-sidebar-hover,#303432);--sp-border:var(--dcu-sidebar-border,rgba(255,255,255,.08))}
8744
+ .dcu-settings-back{display:flex;align-items:center;flex-shrink:0;gap:8px;width:100%;height:30px;padding:5px 8px;border:0;border-radius:10px;background:transparent;color:var(--sp-text);text-align:left}
7799
8745
  .dcu-settings-back:hover,.dcu-settings-link:hover{background:var(--sp-hover)}
7800
8746
  .dcu-settings-search{display:flex;align-items:center;gap:8px;padding:5px 9px;margin:12px 0 18px;background:var(--sp-hover);border:1px solid transparent;border-radius:8px;color:var(--sp-muted)}
7801
8747
  .dcu-settings-search:focus-within{border-color:#459cff}
@@ -7803,17 +8749,22 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7803
8749
  .dcu-settings-search input[type=search]{appearance:none;padding:0;border-radius:0;box-shadow:none;line-height:20px}
7804
8750
  .dcu-settings-search input:focus,.dcu-settings-search input:focus-visible{outline:none;box-shadow:none}
7805
8751
  .dcu-settings-search input::placeholder{color:var(--sp-muted)}
7806
- .dcu-settings-group{margin:0 0 22px}
7807
- .dcu-settings-group-label{margin:0 8px 6px;color:var(--sp-muted);font-size:12px;font-weight:500}
7808
- .dcu-settings-link{display:flex;align-items:center;gap:9px;min-height:32px;width:100%;padding:5px 9px;border:0;border-radius:8px;background:transparent;color:var(--sp-text);text-align:left;font-size:14px!important}
8752
+ .dcu-settings-group{flex-shrink:0;margin:0 0 16px}
8753
+ .dcu-settings-group-label{margin:0 8px 4px;color:var(--sp-muted);font-size:12px;font-weight:500}
8754
+ .dcu-settings-link{display:flex;align-items:center;gap:8px;height:30px;min-height:30px;min-width:0;width:100%;padding:5px 8px;border:0;border-radius:10px;overflow:hidden;background:transparent;color:var(--sp-text);text-align:left;font-size:14px!important}
8755
+ /* Codex Desktop SidebarItem / SidebarSection:30px 行高、1px 行距、内收焦点圈。 */
8756
+ .dcu-settings-link+.dcu-settings-link{margin-top:1px}
8757
+ .dcu-settings-back:focus-visible,.dcu-settings-link:focus-visible{outline-offset:-2px}
8758
+ @supports(corner-shape:superellipse(1.5)){.dcu-settings-back,.dcu-settings-link{border-radius:12.5px;corner-shape:superellipse(1.5)}}
7809
8759
  .dcu-settings-link[aria-current=page]{background:var(--sp-active)}
7810
- .dcu-settings-link svg{flex:none;opacity:.9}
8760
+ .dcu-settings-link svg{flex:none;color:var(--dcu-sidebar-icon,var(--sp-text));opacity:1}
7811
8761
  .dcu-settings-link span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
7812
8762
  .dcu-settings-empty{padding:8px;color:var(--sp-muted);font-size:13px}
7813
8763
  .dcu-settings-main{min-width:0;min-height:0;overflow:auto;overscroll-behavior:contain;background:var(--sp-bg);scrollbar-width:thin;scrollbar-color:var(--sp-border) transparent}
7814
- .dcu-settings-inner{width:min(100%,864px);margin:0 auto;padding:32px 48px}
8764
+ .dcu-settings-inner{width:min(100%,864px);margin:0 auto;padding:48px 48px}
7815
8765
  .dcu-settings-heading{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-bottom:24px}
7816
- .dcu-settings-heading h1{margin:0;font-size:24px;line-height:32px;font-weight:600;letter-spacing:-.4px}
8766
+ .dcu-settings-heading h1,.dcu-settings-inner:is([data-settings-section=models],[data-settings-section=plugins],[data-settings-section=agent-presets]) [class$="_section"]>h2:is([class$="_title"],[class$="_heading"]){margin:0;font-size:24px;line-height:32px;font-weight:600;letter-spacing:-.4px}
8767
+ .dcu-settings-inner:is([data-settings-section=models],[data-settings-section=plugins],[data-settings-section=agent-presets]) [class$="_section"]>p[class$="_intro"]{margin:0;font-size:14px;line-height:22px}
7817
8768
  .dcu-settings-heading[data-own-title=false]{justify-content:flex-end;margin-bottom:16px}
7818
8769
  .dcu-settings-heading:not(:has(h1,button,a,[role=button])){display:none}
7819
8770
  .dcu-settings-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;color:var(--sp-muted)}
@@ -7826,6 +8777,13 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7826
8777
  .dcu-settings-row>[data-slot]>*{padding:12px 0!important;border-bottom:0!important;margin:0!important;min-width:0}
7827
8778
  .dcu-settings-row button{font-size:13px;border-radius:8px}
7828
8779
  .dcu-settings-row input{max-width:100%}
8780
+ .dcu-settings-document{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 0;font-size:14px;line-height:20px}
8781
+ .dcu-settings-document-copy{min-width:0}
8782
+ .dcu-settings-document p{margin:4px 0 0;font-size:12px;color:var(--sp-muted);overflow-wrap:anywhere}
8783
+ .dcu-settings-document button{flex:none;min-height:36px;padding:8px 16px;border:0;border-radius:8px;background:var(--sp-hover);color:var(--sp-text);font:inherit;font-size:13px;cursor:pointer;transition:background .15s}
8784
+ .dcu-settings-document button:hover:not(:disabled){background:color-mix(in srgb,var(--sp-text) 14%,transparent)}
8785
+ .dcu-settings-document button:focus-visible{outline:2px solid var(--sp-muted);outline-offset:3px}
8786
+ .dcu-settings-document button:disabled{opacity:.55;cursor:wait}
7829
8787
  .dcu-settings-trigger{appearance:none;box-sizing:border-box;display:flex;align-items:center;border:0;border-radius:8px;background:transparent;color:var(--dcu-sidebar-navigation,inherit);height:36px;min-height:36px;padding:0 4px;width:100%;font:400 14px/20px var(--dcu-font,system-ui);text-align:left;cursor:pointer;transition:background-color 160ms ease,color 160ms ease,transform 120ms ease}
7830
8788
  .dcu-settings-trigger-content{display:grid;grid-template-columns:20px minmax(0,1fr);column-gap:8px;align-items:center;width:100%;min-width:0}
7831
8789
  .dcu-settings-trigger-content svg{display:block;width:16px;height:16px;color:var(--dcu-sidebar-icon,currentColor);transition:transform 220ms cubic-bezier(.16,1,.3,1)}
@@ -7842,6 +8800,27 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7842
8800
  @keyframes dcu-settings-enter{from{opacity:0}to{opacity:1}}
7843
8801
  @keyframes dcu-settings-nav-enter{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}
7844
8802
  @keyframes dcu-settings-content-enter{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
8803
+ /* 只有 Desktop 明确提供系统背景材质时才贯通透明层,普通浏览器保持实色。 */
8804
+ html[data-dsh-native-backdrop=mica]:has(.dcu-root),html[data-dsh-native-backdrop=mica]:has(.dcu-root) body,html[data-dsh-native-backdrop=mica] #root,html[data-dsh-native-backdrop=mica] #root>[data-slot=root],html[data-dsh-native-backdrop=mica] #root>[data-slot=root]>div{background:transparent!important}
8805
+ html[data-dsh-native-backdrop=mica] #root>[data-slot=root]>div>div:has(>[data-slot=sidebar]){background:transparent!important}
8806
+ html[data-dsh-native-backdrop=mica] #root :is([class$="_centerCol"],[class$="_detailsCol"]){background:var(--dsw-alias-bg-base,#fff)}
8807
+ html[data-dsh-native-backdrop=mica] :is(.dcu-root,.dcu-settings-nav){background:rgba(255,255,255,.18)}
8808
+ html[data-dsh-native-backdrop=mica] body[data-ds-dark-theme] :is(.dcu-root,.dcu-settings-nav){background:rgba(20,23,22,.18)}
8809
+ /* 会话折叠容器显式设了 visible,必须同时隐藏隔离分支的后代,避免穿透透明设置页。 */
8810
+ html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page) :is([inert],[inert] *){visibility:hidden!important}
8811
+ /* 同步隐藏本设置页隔离的外部 portal,保留引导模态及其他组件自己的 inert 语义。 */
8812
+ body:has(.dcu-settings-page) :is([data-dcu-settings-isolated],[data-dcu-settings-isolated] *){visibility:hidden!important}
8813
+ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-backdrop=mica] .dcu-root:has(.dcu-settings-page){background:transparent}
8814
+
8815
+ .dcu-settings-inner:has(.dcu-usage-section){width:100%;height:100%;max-width:1280px;display:flex;flex-direction:column;padding-bottom:0}
8816
+ .dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
8817
+ .dcu-settings-inner:has(.dcu-usage-section)>[data-slot="settings.section"]{display:flex;flex:1;min-height:0;flex-direction:column}
8818
+ .dcu-usage-section{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px}
8819
+ .dcu-usage-section h1{font-size:24px;font-weight:500;margin:0}
8820
+ .dcu-usage-section p{color:var(--sp-muted)}
8821
+ .dcu-usage-stage{position:relative;flex:1;min-height:420px;background:var(--sp-bg)}
8822
+ .dcu-usage-loading{position:absolute;inset:0;display:grid;place-items:center;margin:0}
8823
+ .dcu-usage-frame{position:absolute;inset:0;display:block;width:100%;height:100%;border:0;background:var(--sp-bg)}
7845
8824
  @media(prefers-reduced-motion:reduce){.dcu-settings-trigger,.dcu-settings-trigger-content svg,.dcu-settings-back,.dcu-settings-link{transition:none}.dcu-settings-trigger:hover svg,.dcu-settings-trigger:active{transform:none}.dcu-settings-page,.dcu-settings-nav,.dcu-settings-inner{animation:none}}
7846
8825
  .dcu-settings-page [data-slot="settings.section"]{min-width:0}
7847
8826
  .dcu-settings-inner:has(.dcu-connector-frame){height:100%;display:flex;flex-direction:column}
@@ -7849,8 +8828,8 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7849
8828
  .dcu-settings-page .dcu-connectors:has(>.dcu-connector-frame){display:flex;flex-direction:column;flex:1 1 0;min-height:0}
7850
8829
  .dcu-settings-page .dcu-connector-frame{flex:1 1 0;min-height:0;height:100%}
7851
8830
 
7852
- @media(max-width:900px){.dcu-settings-page{grid-template-columns:200px minmax(0,1fr)}.dcu-settings-inner{padding:24px 28px}.dcu-settings-heading{align-items:flex-start;flex-direction:column;gap:12px}}
7853
- @media(max-width:600px){.dcu-settings-page{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}.dcu-settings-nav{padding:8px 12px;max-height:220px;border-right:0;border-bottom:1px solid var(--sp-border)}.dcu-settings-search{margin:6px 0}.dcu-settings-groups{display:flex;gap:8px;overflow-x:auto;flex:none}.dcu-settings-group{display:flex;gap:4px;margin:0;flex:none}.dcu-settings-group-label{display:none}.dcu-settings-link{width:auto;min-height:40px;flex:none}.dcu-settings-inner{padding:24px 16px}.dcu-settings-heading{margin-bottom:28px}.dcu-settings-heading h1{font-size:22px}.dcu-settings-card{padding:0 12px}.dcu-settings-row>[data-slot]>*{flex-wrap:wrap;gap:12px!important}.dcu-settings-general-group{margin-bottom:32px}}
8831
+ @media(max-width:900px){.dcu-settings-inner{padding:32px 28px}.dcu-settings-heading{align-items:flex-start;flex-direction:column;gap:12px}}
8832
+ @media(max-width:600px){.dcu-settings-page{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}.dcu-settings-nav{padding:8px 12px;max-height:220px;border-right:0;border-bottom:1px solid var(--sp-border)}.dcu-settings-search{margin:6px 0}.dcu-settings-groups{display:flex;gap:8px;overflow-x:auto;flex:none}.dcu-settings-group{display:flex;gap:4px;margin:0;flex:none}.dcu-settings-group-label{display:none}.dcu-settings-link{width:auto;min-height:40px;flex:none}.dcu-settings-link+.dcu-settings-link{margin-top:0}.dcu-settings-inner{padding:32px 16px}.dcu-settings-heading{margin-bottom:28px}.dcu-settings-heading h1,.dcu-settings-inner:is([data-settings-section=models],[data-settings-section=plugins],[data-settings-section=agent-presets]) [class$="_section"]>h2:is([class$="_title"],[class$="_heading"]){font-size:22px}.dcu-settings-card{padding:0 12px}.dcu-settings-row>[data-slot]>*{flex-wrap:wrap;gap:12px!important}.dcu-settings-general-group{margin-bottom:32px}}
7854
8833
  `;
7855
8834
  //#endregion
7856
8835
  //#region src/client/settings-focus.ts
@@ -7876,6 +8855,7 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7876
8855
  editor: "settings.editor"
7877
8856
  };
7878
8857
  function sectionIcon(id) {
8858
+ if (id === "usage-statistics") return ChartColumn;
7879
8859
  if (id === "market" || id === "plugin-marketplace") return Store;
7880
8860
  if (id === "better-sidebar" || id === "sidebar-cards") return PanelRight;
7881
8861
  if (/model/.test(id)) return Cpu;
@@ -7937,6 +8917,24 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7937
8917
  setActiveId(id);
7938
8918
  setOpen(true);
7939
8919
  }, []);
8920
+ (0, react.useEffect)(() => {
8921
+ const element = trigger.current;
8922
+ const navigate = (event) => {
8923
+ const labels = event.detail?.labels;
8924
+ if (!Array.isArray(labels)) return;
8925
+ const row = labels.flatMap((label) => rows.filter((item) => (item.id === "general" ? t("settings.general") : item.label) === label))[0];
8926
+ if (!row) return;
8927
+ event.preventDefault();
8928
+ setQuery("");
8929
+ openSection(row.id);
8930
+ };
8931
+ element?.addEventListener(SETTINGS_OPEN_SECTION_EVENT, navigate);
8932
+ return () => element?.removeEventListener(SETTINGS_OPEN_SECTION_EVENT, navigate);
8933
+ }, [
8934
+ rows,
8935
+ t,
8936
+ openSection
8937
+ ]);
7940
8938
  (0, react.useEffect)(() => () => {
7941
8939
  exitAnimation.current?.cancel();
7942
8940
  }, []);
@@ -7968,8 +8966,12 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
7968
8966
  for (const child of element.children) if (child instanceof HTMLElement && !/^(STYLE|SCRIPT|LINK)$/.test(child.tagName)) isolate(child);
7969
8967
  return;
7970
8968
  }
7971
- hidden.set(element, element.inert);
8969
+ hidden.set(element, {
8970
+ inert: element.inert,
8971
+ marker: element.getAttribute("data-dcu-settings-isolated")
8972
+ });
7972
8973
  element.inert = true;
8974
+ element.setAttribute("data-dcu-settings-isolated", "");
7973
8975
  };
7974
8976
  let branch = page.current;
7975
8977
  while (branch.parentElement !== null) {
@@ -8008,7 +9010,11 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8008
9010
  document.removeEventListener("keydown", onKeyDown, true);
8009
9011
  document.removeEventListener("keydown", wrapFocus);
8010
9012
  document.removeEventListener("focusin", keepFocus);
8011
- for (const [element, inert] of hidden) element.inert = inert;
9013
+ for (const [element, previous] of hidden) {
9014
+ element.inert = previous.inert;
9015
+ if (previous.marker === null) element.removeAttribute("data-dcu-settings-isolated");
9016
+ else element.setAttribute("data-dcu-settings-isolated", previous.marker);
9017
+ }
8012
9018
  };
8013
9019
  }, [
8014
9020
  open,
@@ -8031,7 +9037,7 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8031
9037
  "aria-expanded": open,
8032
9038
  "aria-label": t("settings.title"),
8033
9039
  onClick: () => {
8034
- setOpen(true);
9040
+ openSection("general");
8035
9041
  },
8036
9042
  children: renderSlot("settings.trigger", { wide })
8037
9043
  }),
@@ -8126,6 +9132,7 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8126
9132
  className: "dcu-settings-main",
8127
9133
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8128
9134
  className: "dcu-settings-inner",
9135
+ "data-settings-section": active?.id,
8129
9136
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
8130
9137
  className: "dcu-settings-heading",
8131
9138
  "data-own-title": active?.id === "general",
@@ -8153,9 +9160,9 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8153
9160
  /** 每条偏好仍由原插件渲染和保存,只为公共条目添加可扩展的分组容器。 */
8154
9161
  function CodexGeneralSettings({ items, renderSlot, t }) {
8155
9162
  const rows = (0, react.useSyncExternalStore)(items.subscribe, items.getSnapshot);
8156
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9163
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8157
9164
  className: "dcu-settings-general",
8158
- children: [
9165
+ children: [[
8159
9166
  "permissions",
8160
9167
  "general",
8161
9168
  "editor"
@@ -8167,11 +9174,12 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8167
9174
  className: "dcu-settings-card",
8168
9175
  children: entries.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8169
9176
  className: "dcu-settings-row",
9177
+ "data-dcu-settings-item": row.id,
8170
9178
  children: renderSlot("settings.general.item", {}, { only: row.id })
8171
9179
  }, row.id))
8172
9180
  })]
8173
9181
  }, group);
8174
- })
9182
+ }), renderSlot("settings.general.footer", {})]
8175
9183
  });
8176
9184
  }
8177
9185
  //#endregion
@@ -8210,17 +9218,35 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8210
9218
  setOpening(false);
8211
9219
  }
8212
9220
  };
8213
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8214
- role: "alert",
8215
- children: t("settings.openDocumentError")
8216
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8217
- type: "button",
8218
- disabled: opening,
8219
- onClick: () => {
8220
- open();
8221
- },
8222
- children: t("settings.openDocument")
8223
- })] });
9221
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9222
+ className: "dcu-settings-general-group",
9223
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: t("settings.advanced") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9224
+ className: "dcu-settings-card",
9225
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9226
+ className: "dcu-settings-document",
9227
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9228
+ className: "dcu-settings-document-copy",
9229
+ children: [
9230
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("settings.documentTitle") }),
9231
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("settings.documentDescription") }),
9232
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9233
+ role: "alert",
9234
+ children: t("settings.openDocumentError")
9235
+ })
9236
+ ]
9237
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9238
+ type: "button",
9239
+ "aria-label": t("settings.openDocument"),
9240
+ "aria-busy": opening,
9241
+ disabled: opening,
9242
+ onClick: () => {
9243
+ open();
9244
+ },
9245
+ children: t(opening ? "settings.documentOpening" : "settings.documentOpen")
9246
+ })]
9247
+ })
9248
+ })]
9249
+ });
8224
9250
  }
8225
9251
  //#endregion
8226
9252
  //#region src/client/settings-page-registration.ts
@@ -8288,8 +9314,8 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8288
9314
  const remote = settingsCtx.get("remote");
8289
9315
  if (!remote.$host.isLoopback) return;
8290
9316
  const describe = settingsCtx.settingsScope.describe();
8291
- settingsCtx.slots.inject("settings.action", () => !owned ? () => {} : settingsCtx.slots.register({
8292
- name: "settings.action",
9317
+ settingsCtx.slots.inject("settings.general.footer", () => !owned ? () => {} : settingsCtx.slots.register({
9318
+ name: "settings.general.footer",
8293
9319
  id: "open-document",
8294
9320
  locale: NS,
8295
9321
  inject: () => ({
@@ -8355,10 +9381,16 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8355
9381
  order: 0,
8356
9382
  locale: NS,
8357
9383
  label: () => t("settings.general"),
8358
- children: { "settings.general.item": {
8359
- kind: "list",
8360
- scope: "root"
8361
- } },
9384
+ children: {
9385
+ "settings.general.item": {
9386
+ kind: "list",
9387
+ scope: "root"
9388
+ },
9389
+ "settings.general.footer": {
9390
+ kind: "list",
9391
+ scope: "root"
9392
+ }
9393
+ },
8362
9394
  inject: () => ({ items })
8363
9395
  }, CodexGeneralSettings));
8364
9396
  }
@@ -8482,6 +9514,105 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
8482
9514
  };
8483
9515
  }
8484
9516
  //#endregion
9517
+ //#region src/client/host-copy.ts
9518
+ const commands = {
9519
+ compact: ["Compact older conversation history", "host.command.compact"],
9520
+ export: ["Download this Session log as a ZIP archive", "host.command.export"],
9521
+ feedback: ["record feedback about this session", "host.command.feedback"],
9522
+ goal: ["set or view the goal for a long-running task", "host.command.goal"],
9523
+ permission: ["Switch the permission preset (sandbox mode + approval policy)", "host.command.permission"],
9524
+ plan: ["Enter or leave plan mode", "host.command.plan"]
9525
+ };
9526
+ const transcript = {
9527
+ Normal: "host.transcript.normal",
9528
+ Compact: "host.transcript.compact"
9529
+ };
9530
+ /** 只补译已核对的宿主控件文本;保留原 Text 节点、事件和业务状态。 */
9531
+ function observeHostCopy(locale, t) {
9532
+ const owned = /* @__PURE__ */ new Map();
9533
+ const replace = (element, original, key) => {
9534
+ const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
9535
+ let node;
9536
+ while ((node = walker.nextNode()) !== null) {
9537
+ if (node.nodeValue?.trim() !== original) continue;
9538
+ const text = node;
9539
+ const rendered = text.data.replace(original, t(key));
9540
+ owned.set(text, {
9541
+ original: text.data,
9542
+ rendered,
9543
+ key
9544
+ });
9545
+ if (text.data !== rendered) text.data = rendered;
9546
+ }
9547
+ };
9548
+ const apply = () => {
9549
+ for (const [node, state] of owned) {
9550
+ if (!node.isConnected || node.data !== state.rendered) {
9551
+ owned.delete(node);
9552
+ continue;
9553
+ }
9554
+ const next = state.original.replace(state.original.trim(), t(state.key));
9555
+ if (node.data !== next) node.data = next;
9556
+ state.rendered = next;
9557
+ }
9558
+ const selector = document.querySelector("[data-dcu-settings-item=\"transcript-view\"] button[aria-haspopup=\"menu\"]");
9559
+ if (selector) {
9560
+ for (const [original, key] of Object.entries(transcript)) replace(selector, original, key);
9561
+ if (selector.getAttribute("aria-expanded") === "true") for (const menu of document.querySelectorAll("[role=\"menu\"]")) {
9562
+ const items = [...menu.querySelectorAll("[role=\"menuitem\"],[role=\"menuitemradio\"]")];
9563
+ const labels = items.map((item) => item.textContent?.trim());
9564
+ if (items.length !== 2 || !["Normal", t("host.transcript.normal")].some((label) => labels.includes(label)) || !["Compact", t("host.transcript.compact")].some((label) => labels.includes(label))) continue;
9565
+ for (const item of items) for (const [original, key] of Object.entries(transcript)) replace(item, original, key);
9566
+ }
9567
+ }
9568
+ for (const option of document.querySelectorAll("[data-trigger-menu] button[role=\"option\"]")) {
9569
+ const spans = [...option.children].filter((child) => child.tagName === "SPAN" && child.getAttribute("aria-hidden") !== "true");
9570
+ const name = spans[0]?.textContent?.trim();
9571
+ if (!name || !Object.hasOwn(commands, name) || !spans[1]) continue;
9572
+ const [original, key] = commands[name];
9573
+ replace(spans[1], original, key);
9574
+ }
9575
+ };
9576
+ const scope = "[data-trigger-menu],[data-dcu-settings-item=\"transcript-view\"],[role=\"menu\"]";
9577
+ const roots = /* @__PURE__ */ new Map();
9578
+ const discover = () => {
9579
+ for (const [element, observer] of roots) if (!element.isConnected) {
9580
+ observer.disconnect();
9581
+ roots.delete(element);
9582
+ }
9583
+ for (const element of document.querySelectorAll(scope)) {
9584
+ if (roots.has(element)) continue;
9585
+ const observer = new MutationObserver(apply);
9586
+ observer.observe(element, {
9587
+ subtree: true,
9588
+ childList: true,
9589
+ characterData: true,
9590
+ attributes: true,
9591
+ attributeFilter: ["aria-expanded"]
9592
+ });
9593
+ roots.set(element, observer);
9594
+ }
9595
+ apply();
9596
+ };
9597
+ const observer = new MutationObserver((records) => {
9598
+ if (records.some((record) => [...record.addedNodes, ...record.removedNodes].some((node) => node instanceof Element && (node.matches(scope) || node.querySelector(scope) !== null)))) discover();
9599
+ });
9600
+ discover();
9601
+ observer.observe(document.body, {
9602
+ subtree: true,
9603
+ childList: true
9604
+ });
9605
+ const unsubscribe = locale.subscribe(apply);
9606
+ return () => {
9607
+ observer.disconnect();
9608
+ roots.forEach((observer) => observer.disconnect());
9609
+ roots.clear();
9610
+ unsubscribe();
9611
+ for (const [node, state] of owned) if (node.data === state.rendered) node.data = state.original;
9612
+ owned.clear();
9613
+ };
9614
+ }
9615
+ //#endregion
8485
9616
  //#region src/client/official-turn-navigator.ts
8486
9617
  const OFFICIAL_TURN_NAVIGATOR_ATTRIBUTE = "data-dcu-official-turn-navigator";
8487
9618
  const OFFICIAL_TURN_MARK_ATTRIBUTE = "data-dcu-official-turn-mark";
@@ -9089,6 +10220,42 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
9089
10220
  }, InputHistoryHint));
9090
10221
  }
9091
10222
  //#endregion
10223
+ //#region src/client/new-conversation-draft.ts
10224
+ /** 跟随当前会话的原草稿状态,覆盖输入、粘贴、历史召回和任务预填。 */
10225
+ function createDraftPresenceSource(selection, resolve) {
10226
+ return {
10227
+ getSnapshot: () => (resolve()?.getSnapshot().draft.length ?? 0) > 0,
10228
+ subscribe: (listener) => {
10229
+ let current;
10230
+ let offInput = () => {};
10231
+ const bind = () => {
10232
+ const next = resolve();
10233
+ if (next !== current) {
10234
+ offInput();
10235
+ current = next;
10236
+ offInput = next?.subscribe(listener) ?? (() => {});
10237
+ }
10238
+ listener();
10239
+ };
10240
+ const offSelection = selection.subscribe(bind);
10241
+ bind();
10242
+ return () => {
10243
+ offSelection();
10244
+ offInput();
10245
+ };
10246
+ }
10247
+ };
10248
+ }
10249
+ /** 任务建议只能填入空闲且空白的草稿,不覆盖附件、提及或正在提交的内容。 */
10250
+ function prefillNewConversation(input, text) {
10251
+ if (input === void 0) return "workspace";
10252
+ const state = input.state.getSnapshot();
10253
+ if (state.phase !== "plain") return "busy";
10254
+ if (state.draft.trim() !== "" || state.imageIds.length > 0 || state.occurrences.length > 0) return "draft";
10255
+ input.setDraft(text);
10256
+ return "ready";
10257
+ }
10258
+ //#endregion
9092
10259
  //#region src/client/index.ts
9093
10260
  const inject = [
9094
10261
  "slots",
@@ -9126,20 +10293,34 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
9126
10293
  }
9127
10294
  /** 替换 DSH 的官方 sidebar 插槽,不修改 DSH 源码或会话数据。 */
9128
10295
  function apply(ctx) {
10296
+ const widthStorage = browserStorage();
10297
+ if (widthStorage) initializeComposerWidth(widthStorage);
9129
10298
  ctx.effect(() => ctx.locale.register(NS, {
9130
10299
  zh,
9131
10300
  en
9132
10301
  }), "michengai-codex-ui: dictionaries");
9133
10302
  const t = ctx.locale.bind(NS);
10303
+ ctx.effect(() => observeHeroWidthHandles(t("home.resizeInput")), "michengai-codex-ui: hero width handles");
9134
10304
  registerInputHistory(ctx);
9135
10305
  registerSettingsPage(ctx);
10306
+ registerUsageStatistics(ctx);
9136
10307
  const connection = ctx.get("connection");
9137
10308
  const openPath = (path) => openPathInHost(connection, path);
9138
10309
  ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
9139
10310
  ctx.effect(() => observeSettingsNavIcons(), "michengai-codex-ui: settings nav icons");
9140
10311
  ctx.effect(() => observePermissionLabels(ctx.locale), "michengai-codex-ui: permission labels");
10312
+ ctx.effect(() => observeComposerToolMenus({
10313
+ search: t("home.projectSearch"),
10314
+ empty: t("home.projectEmpty")
10315
+ }), "michengai-codex-ui: composer tool menus");
10316
+ ctx.effect(() => observeHostCopy(ctx.locale, t), "michengai-codex-ui: host copy");
9141
10317
  ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
9142
10318
  ctx.effect(() => observeOfficialTurnNavigators(), "michengai-codex-ui: official turn navigator");
10319
+ const newConversationDraft = createDraftPresenceSource(ctx.sessions.list, () => {
10320
+ const id = ctx.sessions.list.getSnapshot().current;
10321
+ const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
10322
+ return binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx).state;
10323
+ });
9143
10324
  const companionSlots = createCompanionTabSource(ctx.slots);
9144
10325
  ctx.slots.inject("sidebar", () => ctx.slots.register({
9145
10326
  name: "sidebar",
@@ -9168,6 +10349,12 @@ body[data-ds-dark-theme] .dcu-settings-page{--sp-bg:#181818;--sp-nav:#202322;--s
9168
10349
  }
9169
10350
  },
9170
10351
  inject: () => ({
10352
+ newConversationDraft,
10353
+ prefillNewConversation: (text) => {
10354
+ const id = ctx.sessions.list.getSnapshot().current;
10355
+ const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
10356
+ return prefillNewConversation(binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx), text);
10357
+ },
9171
10358
  openSession: (sessionId) => {
9172
10359
  ctx.sessions.open(sessionId);
9173
10360
  },