minecodex 1.0.4 → 1.0.6
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/features/hide-upsell-banner/README.md +2 -1
- package/features/hide-upsell-banner/src/hide-upsell-banner.mjs +9 -10
- package/features/images/README.md +1 -0
- package/features/images/codex-feature.json +1 -1
- package/features/images/web/app.js +30 -0
- package/features/images/web/index.html +5 -0
- package/features/images/web/styles.css +9 -0
- package/features/model-slider/codex-feature.json +3 -0
- package/package.json +1 -1
- package/packages/runtime-host/src/codex-runtime.mjs +278 -48
- package/packages/runtime-host/src/feature-registry.mjs +1 -0
|
@@ -9,6 +9,7 @@ Toolbar 入口,由 `CodexRuntimeHost` 在渲染进程内注入一段脚本。
|
|
|
9
9
|
功能范围:
|
|
10
10
|
|
|
11
11
|
- 仅隐藏横幅的 GUI 显示(`aside` 卡片,`display: none`);
|
|
12
|
+
- 只以 `aside` 和中英文额度耗尽标题识别,不依赖易变的卡片 class、升级、购买 Credit 或使用重置文案;
|
|
12
13
|
- 不拦截、不篡改额度查询接口(`account/rateLimits/read` 与 app-server
|
|
13
14
|
JSON-RPC 流量保持原样);
|
|
14
15
|
- 横幅重新渲染时由 `MutationObserver` 持续处理,不会闪烁后残留;
|
|
@@ -23,5 +24,5 @@ npm test
|
|
|
23
24
|
## 适配说明
|
|
24
25
|
|
|
25
26
|
这是非官方 CDP / DOM Adapter 的功能声明。Codex 私有 DOM 的适配实现统一留在
|
|
26
|
-
`CodexRuntimeHost
|
|
27
|
+
`CodexRuntimeHost`;本功能只声明横幅的识别规则(`aside` + 耗尽标题)与
|
|
27
28
|
隐藏动作。
|
|
@@ -13,16 +13,15 @@ function isUpsellBanner(element) {
|
|
|
13
13
|
if (!(element instanceof window.HTMLElement)) return false;
|
|
14
14
|
const text = (element.innerText ?? "").trim();
|
|
15
15
|
if (!text) return false;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|| /
|
|
23
|
-
|| /Codex
|
|
24
|
-
|
|
25
|
-
return titleMatch && actionMatch;
|
|
16
|
+
const title = (
|
|
17
|
+
element.querySelector("h1, h2, h3, [role='heading']")?.innerText
|
|
18
|
+
?? text.split("\n", 1)[0]
|
|
19
|
+
).trim();
|
|
20
|
+
return /out of Codex(?: and Work)? usage/i.test(title)
|
|
21
|
+
|| /out of Codex messages/i.test(title)
|
|
22
|
+
|| /Codex (?:message )?usage limit reached/i.test(title)
|
|
23
|
+
|| /Codex.*(?:用量|使用量|使用额度|额度|消息).*(?:用完|用尽|耗尽|已达|达到.*上限|上限)/i.test(title)
|
|
24
|
+
|| /(?:已达到|达到|已用完|已用尽|耗尽).{0,20}Codex.{0,20}(?:用量|使用量|额度|消息|上限)/i.test(title);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
function hideBanner(element) {
|
|
@@ -79,6 +79,7 @@ HTTP + Images UI
|
|
|
79
79
|
- 支持 Codex 的明亮 / 暗黑主题,并监听根节点 theme class 与 style 变化。
|
|
80
80
|
- 用户修改 accent、ink 或 surface 后,新的 resolved tokens 会同步到 iframe,不需要重新读取或猜测内部配置文件位置。
|
|
81
81
|
- 侧边栏 Images 入口克隆原生 Plugins 控件的布局与状态,再替换为 Codex 图标体系中的独立 Image 图标;iframe 内不导入 Codex 私有 React 模块或 hashed CSS bundle,以免 Codex 更新后直接失效。
|
|
82
|
+
- 原生左侧栏隐藏时,Images 标题左侧显示同源图标入口;点击由 RuntimeHost 转发给原生侧栏开关,恢复后入口自动隐藏。
|
|
82
83
|
|
|
83
84
|
取证、token Interface 和代码复用边界见 [`docs/CODEX_DESIGN_LANGUAGE.md`](docs/CODEX_DESIGN_LANGUAGE.md)。
|
|
84
85
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"pageScript": {
|
|
17
17
|
"resource": "src/chatgpt-image-source-page.mjs"
|
|
18
18
|
},
|
|
19
|
-
"hostActions": ["import-generated-image", "create-image-edit-thread"],
|
|
19
|
+
"hostActions": ["import-generated-image", "create-image-edit-thread", "open-sidebar"],
|
|
20
20
|
"placement": {
|
|
21
21
|
"after": "sites",
|
|
22
22
|
"order": 10
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const shell = document.querySelector(".library-shell");
|
|
2
|
+
const libraryHeader = document.querySelector(".library-header");
|
|
3
|
+
const sidebarOpenButton = document.querySelector(".sidebar-open-button");
|
|
2
4
|
const scrollArea = document.querySelector(".library-scroll");
|
|
3
5
|
const grid = document.querySelector(".image-grid");
|
|
4
6
|
const pageSentinel = document.querySelector(".page-sentinel");
|
|
@@ -141,9 +143,26 @@ function announce(message) {
|
|
|
141
143
|
});
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
function applySidebarState(payload) {
|
|
147
|
+
const available = Boolean(payload?.available);
|
|
148
|
+
const open = Boolean(payload?.open);
|
|
149
|
+
const label = typeof payload?.label === "string" && payload.label.trim()
|
|
150
|
+
? payload.label.trim()
|
|
151
|
+
: "Show sidebar";
|
|
152
|
+
const visible = available && !open;
|
|
153
|
+
const leading = Number(payload?.leading);
|
|
154
|
+
sidebarOpenButton.hidden = !visible;
|
|
155
|
+
sidebarOpenButton.setAttribute("aria-label", label);
|
|
156
|
+
sidebarOpenButton.title = label;
|
|
157
|
+
libraryHeader.style.paddingLeft = visible && Number.isFinite(leading)
|
|
158
|
+
? `${Math.max(8, leading)}px`
|
|
159
|
+
: "";
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
window.addEventListener("message", (event) => {
|
|
145
163
|
if (event.source !== window.parent) return;
|
|
146
164
|
if (event.data?.type === "codex-personal:theme") applyHostTheme(event.data);
|
|
165
|
+
if (event.data?.type === "codex-personal:sidebar-state") applySidebarState(event.data);
|
|
147
166
|
if (["codex-personal:surface-active", "codex-personal:surface-visibility"].includes(event.data?.type)) {
|
|
148
167
|
setHostSurfaceActive(event.data.active ?? event.data.visible);
|
|
149
168
|
}
|
|
@@ -974,6 +993,17 @@ densitySlider.addEventListener("input", () => {
|
|
|
974
993
|
});
|
|
975
994
|
|
|
976
995
|
groupButton.addEventListener("click", () => toggleThreadGrouping().catch(console.error));
|
|
996
|
+
sidebarOpenButton.addEventListener("click", async () => {
|
|
997
|
+
sidebarOpenButton.disabled = true;
|
|
998
|
+
try {
|
|
999
|
+
await requestHostAction("open-sidebar", {});
|
|
1000
|
+
applySidebarState({ available: true, open: true, label: sidebarOpenButton.title });
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
announce(error.message);
|
|
1003
|
+
} finally {
|
|
1004
|
+
sidebarOpenButton.disabled = false;
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
977
1007
|
|
|
978
1008
|
document.addEventListener("click", (event) => {
|
|
979
1009
|
if (!event.target.closest(".source-filter")) closeToolbarPopups();
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
<section class="library-pane">
|
|
12
12
|
<header class="library-header">
|
|
13
13
|
<div class="identity">
|
|
14
|
+
<button class="icon-button sidebar-open-button" type="button" aria-label="Show sidebar" title="Show sidebar" hidden>
|
|
15
|
+
<svg class="sidebar-toggle-icon" viewBox="0 0 20 20" aria-hidden="true">
|
|
16
|
+
<path d="M6.83496 3.99992C6.38353 4.00411 6.01421 4.0122 5.69824 4.03801C5.31232 4.06954 5.03904 4.12266 4.82227 4.20012L4.62207 4.28606C4.18264 4.50996 3.81498 4.85035 3.55859 5.26848L3.45605 5.45207C3.33013 5.69922 3.25006 6.01354 3.20801 6.52824C3.16533 7.05065 3.16504 7.71885 3.16504 8.66301V11.3271C3.16504 12.2712 3.16533 12.9394 3.20801 13.4618C3.25006 13.9766 3.33013 14.2909 3.45605 14.538L3.55859 14.7216C3.81498 15.1397 4.18266 15.4801 4.62207 15.704L4.82227 15.79C5.03904 15.8674 5.31234 15.9205 5.69824 15.9521C6.01398 15.9779 6.383 15.986 6.83398 15.9902L6.83496 3.99992ZM18.165 11.3271C18.165 12.2493 18.1653 12.9811 18.1172 13.5702C18.0745 14.0924 17.9916 14.5472 17.8125 14.9648L17.7295 15.1415C17.394 15.8 16.8834 16.3511 16.2568 16.7353L15.9814 16.8896C15.5157 17.1268 15.0069 17.2285 14.4102 17.2773C13.821 17.3254 13.0893 17.3251 12.167 17.3251H7.83301C6.91071 17.3251 6.17898 17.3254 5.58984 17.2773C5.06757 17.2346 4.61294 17.1508 4.19531 16.9716L4.01855 16.8896C3.36014 16.5541 2.80898 16.0434 2.4248 15.4169L2.27051 15.1415C2.03328 14.6758 1.93158 14.167 1.88281 13.5702C1.83468 12.9811 1.83496 12.2493 1.83496 11.3271V8.66301C1.83496 7.74072 1.83468 7.00898 1.88281 6.41985C1.93157 5.82309 2.03329 5.31432 2.27051 4.84856L2.4248 4.57317C2.80898 3.94666 3.36012 3.436 4.01855 3.10051L4.19531 3.0175C4.61285 2.83843 5.06771 2.75548 5.58984 2.71281C6.17898 2.66468 6.91071 2.66496 7.83301 2.66496H12.167C13.0893 2.66496 13.821 2.66468 14.4102 2.71281C15.0069 2.76157 15.5157 2.86329 15.9814 3.10051L16.2568 3.25481C16.8833 3.63898 17.394 4.19012 17.7295 4.84856L17.8125 5.02531C17.9916 5.44285 18.0745 5.89771 18.1172 6.41985C18.1653 7.00898 18.165 7.74072 18.165 8.66301V11.3271ZM8.16406 15.995H12.167C13.1112 15.995 13.7794 15.9947 14.3018 15.9521C14.8164 15.91 15.1308 15.8299 15.3779 15.704L15.5615 15.6015C15.9797 15.3451 16.32 14.9774 16.5439 14.538L16.6299 14.3378C16.7074 14.121 16.7605 13.8478 16.792 13.4618C16.8347 12.9394 16.835 12.2712 16.835 11.3271V8.66301C16.835 7.71885 16.8347 7.05065 16.792 6.52824C16.7605 6.14232 16.7073 5.86904 16.6299 5.65227L16.5439 5.45207C16.32 5.01264 15.9796 4.64498 15.5615 4.3886L15.3779 4.28606C15.1308 4.16013 14.8165 4.08006 14.3018 4.03801C13.7794 3.99533 13.1112 3.99504 12.167 3.99504H8.16406C8.16407 3.99667 8.16504 3.99829 8.16504 3.99992L8.16406 15.995Z"></path>
|
|
17
|
+
</svg>
|
|
18
|
+
</button>
|
|
14
19
|
<h1>Images</h1>
|
|
15
20
|
</div>
|
|
16
21
|
<button class="icon-button rescan-button" type="button" aria-label="Refresh images" title="Refresh images">
|
|
@@ -240,6 +240,15 @@ button { color: inherit; }
|
|
|
240
240
|
gap: 7px;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
.sidebar-open-button { flex: 0 0 auto; }
|
|
244
|
+
.sidebar-open-button[hidden] { display: none; }
|
|
245
|
+
|
|
246
|
+
.sidebar-toggle-icon {
|
|
247
|
+
width: 16px;
|
|
248
|
+
height: 16px;
|
|
249
|
+
fill: currentColor;
|
|
250
|
+
}
|
|
251
|
+
|
|
243
252
|
h1,
|
|
244
253
|
h2,
|
|
245
254
|
h3,
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"maxVisibleItems": 6,
|
|
18
18
|
"favoriteStorageKey": "codex-model-slider:favorites:v1",
|
|
19
19
|
"reasoningEffortOverrides": {
|
|
20
|
+
"command-code/Qwen-Qwen3.8-Flash": ["low", "medium", "xhigh"],
|
|
21
|
+
"command-code/xai-grok-4.6": ["low", "medium", "high", "xhigh"],
|
|
22
|
+
"command-code/xiaomi-mimo-v2.5": ["low", "medium", "high", "xhigh"],
|
|
20
23
|
"opencode-go/hy3": ["low", "medium", "high"],
|
|
21
24
|
"opencode-go/muse-spark-1.2-contributor": ["low", "medium", "high", "xhigh"]
|
|
22
25
|
},
|
package/package.json
CHANGED
|
@@ -144,6 +144,13 @@ export function createInjectionSource(features, {
|
|
|
144
144
|
scheduled: ["scheduled", "计划任务"],
|
|
145
145
|
plugins: ["plugins", "插件"],
|
|
146
146
|
};
|
|
147
|
+
const nativeToolbarLabels = {
|
|
148
|
+
summary: ["Toggle summary", "切换摘要"],
|
|
149
|
+
pinnedSummary: ["Toggle pinned summary", "切换固定摘要"],
|
|
150
|
+
bottomPanel: ["Toggle bottom panel", "切换底部面板"],
|
|
151
|
+
sidePanel: ["Toggle side panel", "切换侧边面板"],
|
|
152
|
+
temporaryChat: ["temporary chat", "临时聊天", "临时对话"],
|
|
153
|
+
};
|
|
147
154
|
const themeTokenNames = [
|
|
148
155
|
"--codex-base-accent",
|
|
149
156
|
"--codex-base-ink",
|
|
@@ -170,6 +177,7 @@ export function createInjectionSource(features, {
|
|
|
170
177
|
"--color-background-elevated-primary-opaque",
|
|
171
178
|
"--color-background-primary-ghost-hover",
|
|
172
179
|
"--color-chart-blue",
|
|
180
|
+
"--color-chart-purple",
|
|
173
181
|
"--color-background-panel",
|
|
174
182
|
"--color-background-control",
|
|
175
183
|
"--color-background-primary-solid",
|
|
@@ -300,7 +308,6 @@ export function createInjectionSource(features, {
|
|
|
300
308
|
let nativeTabCapabilityPromise = null;
|
|
301
309
|
let nativeTabCapability = null;
|
|
302
310
|
let nativeTabCapabilityError = null;
|
|
303
|
-
const modelSelectorOriginalItems = new Map();
|
|
304
311
|
const modelSelectorOriginalToggleLabels = new Map();
|
|
305
312
|
const modelSelectorGenericContainers = new Map();
|
|
306
313
|
const modelSelectorNativeToggleHandlers = new Map();
|
|
@@ -328,9 +335,11 @@ export function createInjectionSource(features, {
|
|
|
328
335
|
[data-codex-model-slider-menu] { width: 264px !important; min-width: 264px; overflow-x: hidden; }
|
|
329
336
|
[data-codex-model-slider-controller-menu] {
|
|
330
337
|
position: absolute !important;
|
|
331
|
-
|
|
338
|
+
left: 50%;
|
|
332
339
|
bottom: 0;
|
|
340
|
+
transform: translateX(-50%) !important;
|
|
333
341
|
z-index: 10;
|
|
342
|
+
padding: 6px;
|
|
334
343
|
background-color: var(--color-surface-elevated-secondary);
|
|
335
344
|
-webkit-backdrop-filter: none;
|
|
336
345
|
backdrop-filter: none;
|
|
@@ -340,10 +349,10 @@ export function createInjectionSource(features, {
|
|
|
340
349
|
overflow-y: auto;
|
|
341
350
|
}
|
|
342
351
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerModelLabel_"] {
|
|
343
|
-
max-width:
|
|
352
|
+
min-width: 0; max-width: 110px; flex-shrink: 1; overflow: hidden; text-overflow: ellipsis;
|
|
344
353
|
}
|
|
345
354
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerModelText_"] {
|
|
346
|
-
overflow:
|
|
355
|
+
min-width: 0; max-width: 110px; overflow: hidden; text-overflow: ellipsis;
|
|
347
356
|
}
|
|
348
357
|
html[data-codex-model-slider-catalog-ready]
|
|
349
358
|
[data-codex-intelligence-trigger]
|
|
@@ -351,11 +360,37 @@ export function createInjectionSource(features, {
|
|
|
351
360
|
display: none !important;
|
|
352
361
|
}
|
|
353
362
|
[data-codex-model-slider-trigger-label] {
|
|
354
|
-
display: inline;
|
|
363
|
+
display: inline-block; min-width: 0; max-width: 110px;
|
|
364
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
365
|
+
}
|
|
366
|
+
/* 展示真实模型名/思考强度时:芯片 HUG 内容,长名称不被截断;
|
|
367
|
+
仅 "Select model / Select effort" 占位态沿用原生宽度。 */
|
|
368
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [data-codex-model-slider-trigger-label] {
|
|
369
|
+
max-width: none; overflow: visible; text-overflow: clip; flex-shrink: 0;
|
|
370
|
+
}
|
|
371
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="_ModelPickerTriggerModelLabel_"] {
|
|
372
|
+
max-width: none; overflow: visible; flex-shrink: 0;
|
|
373
|
+
}
|
|
374
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="_ModelPickerTriggerContent_"] {
|
|
375
|
+
max-width: none !important;
|
|
376
|
+
}
|
|
377
|
+
[data-codex-model-slider-trigger][data-codex-model-slider-trigger-placeholder] [class*="_ModelPickerTriggerContent_"] {
|
|
378
|
+
width: 160px; min-width: 160px !important; max-width: 160px;
|
|
355
379
|
}
|
|
356
380
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerEffortLabel_"] {
|
|
357
381
|
display: inline-flex; align-items: center; align-self: center;
|
|
358
382
|
}
|
|
383
|
+
/* 无 Fast 模式时,模型按钮 wrapper 居中,不再按有 Fast 的左对齐策略排布。 */
|
|
384
|
+
[data-codex-model-slider-has-fast="false"] [data-codex-model-slider-model-button] {
|
|
385
|
+
box-sizing: border-box; width: 100%; max-width: 100%; margin-inline: auto;
|
|
386
|
+
flex: 0 1 100%; justify-content: center;
|
|
387
|
+
}
|
|
388
|
+
[data-codex-model-slider-has-fast="false"] [data-codex-model-slider-model-button] > span {
|
|
389
|
+
width: 100%; min-width: 0;
|
|
390
|
+
}
|
|
391
|
+
[data-codex-model-slider-has-fast="false"] > :has(> [data-codex-model-slider-model-button])::before {
|
|
392
|
+
display: none !important; content: none !important;
|
|
393
|
+
}
|
|
359
394
|
html[data-codex-model-slider-selecting-effort] [role="menu"][data-state="open"]:not(:has([data-reasoning-slider])) {
|
|
360
395
|
visibility: hidden !important; opacity: 0 !important; animation: none !important; pointer-events: none !important;
|
|
361
396
|
}
|
|
@@ -365,6 +400,10 @@ export function createInjectionSource(features, {
|
|
|
365
400
|
[data-codex-model-slider-copy] { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 1px; }
|
|
366
401
|
[data-codex-model-slider-name] { overflow: hidden; color: var(--color-text-foreground); text-overflow: ellipsis; white-space: nowrap; }
|
|
367
402
|
[data-codex-model-slider-provider] { overflow: hidden; color: var(--color-text-foreground-tertiary); font-size: 11px; line-height: 14px; text-overflow: ellipsis; white-space: nowrap; }
|
|
403
|
+
[data-codex-model-slider-model-label] {
|
|
404
|
+
display: -webkit-box; min-width: 0; overflow: hidden; overflow-wrap: anywhere;
|
|
405
|
+
-webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal;
|
|
406
|
+
}
|
|
368
407
|
[data-codex-model-slider-item] { position: relative; }
|
|
369
408
|
[data-codex-model-slider-item][data-codex-model-slider-selected] { background: var(--color-token-list-hover-background); }
|
|
370
409
|
[data-codex-model-slider-star] {
|
|
@@ -381,8 +420,14 @@ export function createInjectionSource(features, {
|
|
|
381
420
|
content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 40px; z-index: 1;
|
|
382
421
|
}
|
|
383
422
|
[data-codex-model-slider-star] svg { position: relative; z-index: 2; width: 16px; height: 16px; pointer-events: none; }
|
|
384
|
-
[data-codex-model-slider-divider] {
|
|
385
|
-
|
|
423
|
+
[data-codex-model-slider-divider] {
|
|
424
|
+
height: 0; border-top: 1px solid var(--color-token-border, var(--color-border));
|
|
425
|
+
margin: 6px 8px;
|
|
426
|
+
}
|
|
427
|
+
[data-codex-model-slider-generic-menu] {
|
|
428
|
+
overflow-x: hidden;
|
|
429
|
+
transform: translateX(var(--codex-model-slider-menu-center-shift, 0px)) !important;
|
|
430
|
+
}
|
|
386
431
|
[data-codex-model-slider-generic] { box-sizing: border-box; width: 100%; }
|
|
387
432
|
[data-codex-model-slider-fast] { margin-left: auto; border: 0; background: transparent; cursor: pointer; }
|
|
388
433
|
[data-codex-model-slider-fast]:focus-visible { outline: 2px solid var(--color-border-focus); outline-offset: 1px; }
|
|
@@ -474,11 +519,20 @@ export function createInjectionSource(features, {
|
|
|
474
519
|
&& rect.height > 0;
|
|
475
520
|
}
|
|
476
521
|
|
|
522
|
+
function hasNativeToolbarLabel(button, key) {
|
|
523
|
+
const label = String(button?.getAttribute("aria-label") ?? "").trim().toLowerCase();
|
|
524
|
+
return nativeToolbarLabels[key].some((candidate) => (
|
|
525
|
+
key === "temporaryChat"
|
|
526
|
+
? label.includes(candidate.toLowerCase())
|
|
527
|
+
: label === candidate.toLowerCase()
|
|
528
|
+
));
|
|
529
|
+
}
|
|
530
|
+
|
|
477
531
|
function nativeSummaryButton() {
|
|
478
532
|
return Array.from(document.querySelectorAll("button")).find((button) => (
|
|
479
533
|
(
|
|
480
|
-
button
|
|
481
|
-
|| button
|
|
534
|
+
hasNativeToolbarLabel(button, "summary")
|
|
535
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary")
|
|
482
536
|
)
|
|
483
537
|
&& isVisibleToolbarControl(button)
|
|
484
538
|
)) ?? null;
|
|
@@ -486,32 +540,34 @@ export function createInjectionSource(features, {
|
|
|
486
540
|
|
|
487
541
|
function nativeBottomPanelButton() {
|
|
488
542
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
489
|
-
if (button
|
|
543
|
+
if (!hasNativeToolbarLabel(button, "bottomPanel")) return false;
|
|
490
544
|
return isVisibleToolbarControl(button);
|
|
491
545
|
}) ?? null;
|
|
492
546
|
}
|
|
493
547
|
|
|
494
548
|
function nativeSidePanelButton() {
|
|
495
549
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
496
|
-
if (button
|
|
550
|
+
if (!hasNativeToolbarLabel(button, "sidePanel")) return false;
|
|
497
551
|
return isVisibleToolbarControl(button);
|
|
498
552
|
}) ?? null;
|
|
499
553
|
}
|
|
500
554
|
|
|
501
555
|
function nativeTemporaryChatButton() {
|
|
502
556
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
503
|
-
if (
|
|
557
|
+
if (!hasNativeToolbarLabel(button, "temporaryChat")) return false;
|
|
504
558
|
return isVisibleToolbarControl(button);
|
|
505
559
|
}) ?? null;
|
|
506
560
|
}
|
|
507
561
|
|
|
508
562
|
function structuralToolbarAnchor() {
|
|
509
563
|
const buttons = Array.from(document.querySelectorAll("button"));
|
|
510
|
-
return buttons.find((button) =>
|
|
511
|
-
?? buttons.find((button) =>
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
564
|
+
return buttons.find((button) => hasNativeToolbarLabel(button, "temporaryChat"))
|
|
565
|
+
?? buttons.find((button) => (
|
|
566
|
+
hasNativeToolbarLabel(button, "summary")
|
|
567
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary")
|
|
568
|
+
))
|
|
569
|
+
?? buttons.find((button) => hasNativeToolbarLabel(button, "bottomPanel"))
|
|
570
|
+
?? buttons.find((button) => hasNativeToolbarLabel(button, "sidePanel"))
|
|
515
571
|
?? null;
|
|
516
572
|
}
|
|
517
573
|
|
|
@@ -605,8 +661,8 @@ export function createInjectionSource(features, {
|
|
|
605
661
|
function isNativeSummaryButton(element) {
|
|
606
662
|
if (!(element instanceof Element)) return false;
|
|
607
663
|
const button = element.closest("button");
|
|
608
|
-
return button
|
|
609
|
-
|| button
|
|
664
|
+
return hasNativeToolbarLabel(button, "summary")
|
|
665
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary");
|
|
610
666
|
}
|
|
611
667
|
|
|
612
668
|
function mainContentViewport() {
|
|
@@ -1055,7 +1111,9 @@ export function createInjectionSource(features, {
|
|
|
1055
1111
|
})).filter((level) => level.effort);
|
|
1056
1112
|
const allowed = selector?.reasoningEffortOverrides?.[identity.raw.toLowerCase()];
|
|
1057
1113
|
const supportedReasoningLevels = allowed
|
|
1058
|
-
? nativeReasoningLevels.
|
|
1114
|
+
? (nativeReasoningLevels.length
|
|
1115
|
+
? nativeReasoningLevels.filter((level) => allowed.includes(level.effort))
|
|
1116
|
+
: allowed.map((effort) => ({ effort })))
|
|
1059
1117
|
: nativeReasoningLevels;
|
|
1060
1118
|
const currentReasoningLevel = String(controller?.reasoningEffort ?? "").toLowerCase();
|
|
1061
1119
|
return {
|
|
@@ -1451,6 +1509,16 @@ export function createInjectionSource(features, {
|
|
|
1451
1509
|
if (!items.length) return;
|
|
1452
1510
|
const favorites = loadModelFavorites(selector);
|
|
1453
1511
|
items.forEach((item) => { item.style.display = ""; });
|
|
1512
|
+
if (!menu.hasAttribute("data-codex-model-slider-controller-menu")) {
|
|
1513
|
+
if (!modelSelectorMenuSizeFrames.has(menu)) {
|
|
1514
|
+
const frame = requestAnimationFrame(() => {
|
|
1515
|
+
modelSelectorMenuSizeFrames.delete(menu);
|
|
1516
|
+
sizeModelMenuViewport(menu, selector.maxVisibleItems);
|
|
1517
|
+
});
|
|
1518
|
+
modelSelectorMenuSizeFrames.set(menu, frame);
|
|
1519
|
+
}
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1454
1522
|
const starred = items.filter((item) => favorites.has(item.dataset.codexModelSliderRaw));
|
|
1455
1523
|
const ordinary = items.filter((item) => !favorites.has(item.dataset.codexModelSliderRaw));
|
|
1456
1524
|
const desired = items.slice().sort((a, b) => compareEnhancedModelItems(a, b, favorites));
|
|
@@ -1528,6 +1596,7 @@ export function createInjectionSource(features, {
|
|
|
1528
1596
|
rawValue = null,
|
|
1529
1597
|
selected = null,
|
|
1530
1598
|
scheduleReturn = true,
|
|
1599
|
+
owned = false,
|
|
1531
1600
|
} = {}) {
|
|
1532
1601
|
const observedRaw = rawValue ?? modelItemRawValue(item);
|
|
1533
1602
|
if (!observedRaw) return;
|
|
@@ -1541,16 +1610,21 @@ export function createInjectionSource(features, {
|
|
|
1541
1610
|
item.dataset.codexModelSliderOrder = String(index);
|
|
1542
1611
|
item.dataset.codexModelSliderIdentitySource = catalogModel ? "catalog" : nativeDescriptor ? "native" : "visible";
|
|
1543
1612
|
if (item.querySelector("[data-codex-model-slider-row]")) return;
|
|
1544
|
-
if (!modelSelectorOriginalItems.has(item)) modelSelectorOriginalItems.set(item, item.innerHTML);
|
|
1545
|
-
|
|
1546
|
-
const identity = modelIdentity(raw);
|
|
1547
|
-
const display = modelDisplayLabel(identity, selector);
|
|
1548
|
-
const provider = providerLabel(identity.provider, selector);
|
|
1549
|
-
const brand = brandForModel(identity, selector);
|
|
1550
1613
|
item.toggleAttribute(
|
|
1551
1614
|
"data-codex-model-slider-selected",
|
|
1552
1615
|
selected ?? Boolean(item.querySelector("svg")),
|
|
1553
1616
|
);
|
|
1617
|
+
if (!owned) {
|
|
1618
|
+
if (scheduleReturn && !item.hasAttribute("data-codex-model-slider-return-listener")) {
|
|
1619
|
+
item.setAttribute("data-codex-model-slider-return-listener", "");
|
|
1620
|
+
item.addEventListener("click", scheduleModelSliderReturn);
|
|
1621
|
+
}
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
const identity = modelIdentity(raw);
|
|
1625
|
+
const display = modelDisplayLabel(identity, selector);
|
|
1626
|
+
const provider = providerLabel(identity.provider, selector);
|
|
1627
|
+
const brand = brandForModel(identity, selector);
|
|
1554
1628
|
const favorites = loadModelFavorites(selector);
|
|
1555
1629
|
const starred = favorites.has(raw);
|
|
1556
1630
|
const row = document.createElement("span");
|
|
@@ -1728,10 +1802,15 @@ export function createInjectionSource(features, {
|
|
|
1728
1802
|
function closeControllerModelMenu() {
|
|
1729
1803
|
const record = modelSelectorControllerMenu;
|
|
1730
1804
|
if (!record) return false;
|
|
1805
|
+
const placeholder = document.querySelector(
|
|
1806
|
+
'[data-codex-intelligence-trigger] [class*="_ModelPickerTriggerPlaceholder_"]',
|
|
1807
|
+
);
|
|
1808
|
+
if (placeholder && record.placeholderText != null) {
|
|
1809
|
+
placeholder.textContent = record.placeholderText;
|
|
1810
|
+
}
|
|
1731
1811
|
record.button.setAttribute("aria-expanded", "false");
|
|
1732
1812
|
record.parentMenu.style.position = record.position;
|
|
1733
1813
|
record.parentMenu.style.overflow = record.overflow;
|
|
1734
|
-
for (const item of modelMenuItems(record.menu)) modelSelectorOriginalItems.delete(item);
|
|
1735
1814
|
record.menu.remove();
|
|
1736
1815
|
modelSelectorControllerMenu = null;
|
|
1737
1816
|
return true;
|
|
@@ -1772,6 +1851,7 @@ export function createInjectionSource(features, {
|
|
|
1772
1851
|
rawValue: String(model.model),
|
|
1773
1852
|
selected: String(model.model) === String(controller.model),
|
|
1774
1853
|
scheduleReturn: false,
|
|
1854
|
+
owned: true,
|
|
1775
1855
|
});
|
|
1776
1856
|
menu.append(item);
|
|
1777
1857
|
});
|
|
@@ -1809,10 +1889,17 @@ export function createInjectionSource(features, {
|
|
|
1809
1889
|
});
|
|
1810
1890
|
renderEnhancedModelMenu(menu, selector);
|
|
1811
1891
|
|
|
1892
|
+
const placeholder = document.querySelector(
|
|
1893
|
+
'[data-codex-intelligence-trigger] [class*="_ModelPickerTriggerPlaceholder_"]',
|
|
1894
|
+
);
|
|
1895
|
+
const placeholderText = placeholder?.textContent ?? null;
|
|
1896
|
+
if (placeholder) placeholder.textContent = locale === "zh-CN" ? "选择模型" : "Select model";
|
|
1897
|
+
|
|
1812
1898
|
modelSelectorControllerMenu = {
|
|
1813
1899
|
menu,
|
|
1814
1900
|
parentMenu,
|
|
1815
1901
|
button: modelButton,
|
|
1902
|
+
placeholderText,
|
|
1816
1903
|
position: parentMenu.style.position,
|
|
1817
1904
|
overflow: parentMenu.style.overflow,
|
|
1818
1905
|
};
|
|
@@ -2083,6 +2170,8 @@ export function createInjectionSource(features, {
|
|
|
2083
2170
|
"ViewToggle",
|
|
2084
2171
|
"ViewToggleContent",
|
|
2085
2172
|
"ViewToggleIcon",
|
|
2173
|
+
"ViewToggleModelLabel",
|
|
2174
|
+
"ViewToggleEffortLabel",
|
|
2086
2175
|
"ViewControls",
|
|
2087
2176
|
"FastModeToggle",
|
|
2088
2177
|
"FastModeToggleContent",
|
|
@@ -2096,6 +2185,11 @@ export function createInjectionSource(features, {
|
|
|
2096
2185
|
shell.setAttribute("data-reduced-motion", String(matchMedia("(prefers-reduced-motion: reduce)").matches));
|
|
2097
2186
|
shell.setAttribute("data-transitions-ready", "false");
|
|
2098
2187
|
const nativeRow = nativeModelPickerRow(parentMenu);
|
|
2188
|
+
const controller = nativeComposerModelController();
|
|
2189
|
+
const fastOption = controller?.serviceTierOptions?.find((option) => option?.value === "priority") ?? null;
|
|
2190
|
+
const nativeModel = nativeCatalogModelFor(identity);
|
|
2191
|
+
const supportsFast = Boolean(nativeModel?.slug.toLowerCase().startsWith("gpt-") && fastOption);
|
|
2192
|
+
shell.setAttribute("data-codex-model-slider-has-fast", String(supportsFast));
|
|
2099
2193
|
const modelButton = document.createElement("div");
|
|
2100
2194
|
modelButton.className = classes.ViewToggle;
|
|
2101
2195
|
modelButton.setAttribute("role", "button");
|
|
@@ -2107,14 +2201,31 @@ export function createInjectionSource(features, {
|
|
|
2107
2201
|
const buttonContent = document.createElement("span");
|
|
2108
2202
|
buttonContent.className = classes.ViewToggleContent;
|
|
2109
2203
|
const buttonLabel = document.createElement("span");
|
|
2204
|
+
buttonLabel.className = classes.ViewToggleModelLabel;
|
|
2205
|
+
buttonLabel.setAttribute("data-codex-model-slider-model-label", "");
|
|
2110
2206
|
buttonLabel.textContent = modelDisplayLabel(identity, selector);
|
|
2111
|
-
const
|
|
2207
|
+
const effortText = selectedEffortVisible ? document.createElement("span") : null;
|
|
2208
|
+
if (effortText) {
|
|
2209
|
+
effortText.className = classes.ViewToggleEffortLabel;
|
|
2210
|
+
effortText.textContent = effortLabel(selectedEffort);
|
|
2211
|
+
effortText.setAttribute("data-accent", "true");
|
|
2212
|
+
effortText.setAttribute("data-maximum", String(selectedEffort === "ultra"));
|
|
2213
|
+
}
|
|
2214
|
+
// 0.152.1 起原生头行 aria-label 为 "Select model",nativeModelPickerRow
|
|
2215
|
+
// 不再命中;优先从 view-toggle 行取 chevron,旧结构走原路径兜底。
|
|
2216
|
+
const nativeChevron = (
|
|
2217
|
+
parentMenu?.querySelector("[data-model-picker-view-toggle] svg")
|
|
2218
|
+
?? nativeRow?.querySelector("svg")
|
|
2219
|
+
)?.cloneNode(true);
|
|
2112
2220
|
if (nativeChevron) {
|
|
2113
2221
|
nativeChevron.className.baseVal = classes.ViewToggleIcon;
|
|
2114
2222
|
nativeChevron.setAttribute("aria-hidden", "true");
|
|
2115
|
-
buttonContent.append(buttonLabel
|
|
2223
|
+
buttonContent.append(buttonLabel);
|
|
2224
|
+
if (effortText) buttonContent.append(effortText);
|
|
2225
|
+
buttonContent.append(nativeChevron);
|
|
2116
2226
|
} else {
|
|
2117
2227
|
buttonContent.append(buttonLabel);
|
|
2228
|
+
if (effortText) buttonContent.append(effortText);
|
|
2118
2229
|
}
|
|
2119
2230
|
modelButton.append(buttonContent);
|
|
2120
2231
|
const openModels = () => openControllerModelMenu(parentMenu, modelButton, selector);
|
|
@@ -2129,10 +2240,6 @@ export function createInjectionSource(features, {
|
|
|
2129
2240
|
viewControls.className = classes.ViewControls;
|
|
2130
2241
|
viewControls.setAttribute("data-expanded", "false");
|
|
2131
2242
|
viewControls.setAttribute("data-ultra-warning-visible", "false");
|
|
2132
|
-
const controller = nativeComposerModelController();
|
|
2133
|
-
const fastOption = controller?.serviceTierOptions?.find((option) => option?.value === "priority") ?? null;
|
|
2134
|
-
const nativeModel = nativeCatalogModelFor(identity);
|
|
2135
|
-
const supportsFast = Boolean(nativeModel?.slug.toLowerCase().startsWith("gpt-") && fastOption);
|
|
2136
2243
|
const fastEnabled = Boolean(
|
|
2137
2244
|
supportsFast && (
|
|
2138
2245
|
controller.selectedServiceTier?.id === (fastOption.tier?.id ?? "priority")
|
|
@@ -2283,6 +2390,20 @@ export function createInjectionSource(features, {
|
|
|
2283
2390
|
return shell;
|
|
2284
2391
|
}
|
|
2285
2392
|
|
|
2393
|
+
function centerGenericModelPicker(parentMenu) {
|
|
2394
|
+
const trigger = document.querySelector("[data-codex-intelligence-trigger]");
|
|
2395
|
+
if (!trigger) return;
|
|
2396
|
+
const menuRect = parentMenu.getBoundingClientRect();
|
|
2397
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2398
|
+
if (!(menuRect.width > 0 && triggerRect.width > 0)) return;
|
|
2399
|
+
const previousShift = Number.parseFloat(
|
|
2400
|
+
parentMenu.style.getPropertyValue("--codex-model-slider-menu-center-shift"),
|
|
2401
|
+
) || 0;
|
|
2402
|
+
const unshiftedCenter = menuRect.left + (menuRect.width / 2) - previousShift;
|
|
2403
|
+
const nextShift = triggerRect.left + (triggerRect.width / 2) - unshiftedCenter;
|
|
2404
|
+
parentMenu.style.setProperty("--codex-model-slider-menu-center-shift", `${nextShift}px`);
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2286
2407
|
function enhanceGenericModelPicker(parentMenu, selector) {
|
|
2287
2408
|
const identity = modelIdentity(nativeModelValue(parentMenu));
|
|
2288
2409
|
const model = modelDefinitionFor(identity, selector);
|
|
@@ -2334,7 +2455,10 @@ export function createInjectionSource(features, {
|
|
|
2334
2455
|
const canUpgradeFallback = Boolean(
|
|
2335
2456
|
existing?.querySelector("[data-codex-model-slider-fallback]") && nativeTemplateReady,
|
|
2336
2457
|
);
|
|
2337
|
-
if (existing?.getAttribute("data-codex-model-slider-generic") === key && !canUpgradeFallback)
|
|
2458
|
+
if (existing?.getAttribute("data-codex-model-slider-generic") === key && !canUpgradeFallback) {
|
|
2459
|
+
centerGenericModelPicker(parentMenu);
|
|
2460
|
+
return true;
|
|
2461
|
+
}
|
|
2338
2462
|
existing?.remove();
|
|
2339
2463
|
const nativeContainer = parentMenu.firstElementChild;
|
|
2340
2464
|
if (!nativeContainer) return false;
|
|
@@ -2347,12 +2471,14 @@ export function createInjectionSource(features, {
|
|
|
2347
2471
|
nativeContainer.style.display = "none";
|
|
2348
2472
|
shell.setAttribute("data-codex-model-slider-generic", key);
|
|
2349
2473
|
parentMenu.append(shell);
|
|
2474
|
+
centerGenericModelPicker(parentMenu);
|
|
2350
2475
|
return true;
|
|
2351
2476
|
}
|
|
2352
2477
|
|
|
2353
2478
|
function restoreGenericModelPicker(parentMenu) {
|
|
2354
2479
|
parentMenu.querySelector(":scope > [data-codex-model-slider-generic]")?.remove();
|
|
2355
2480
|
parentMenu.removeAttribute("data-codex-model-slider-generic-menu");
|
|
2481
|
+
parentMenu.style.removeProperty("--codex-model-slider-menu-center-shift");
|
|
2356
2482
|
const nativeContainer = parentMenu.firstElementChild;
|
|
2357
2483
|
if (nativeContainer && modelSelectorGenericContainers.has(nativeContainer)) {
|
|
2358
2484
|
nativeContainer.style.display = modelSelectorGenericContainers.get(nativeContainer);
|
|
@@ -2361,10 +2487,10 @@ export function createInjectionSource(features, {
|
|
|
2361
2487
|
}
|
|
2362
2488
|
|
|
2363
2489
|
function enhanceNativeModelPicker(parentMenu, selector) {
|
|
2490
|
+
if (enhanceGenericModelPicker(parentMenu, selector)) return;
|
|
2364
2491
|
const toggle = parentMenu.querySelector("[data-model-picker-view-toggle]");
|
|
2365
2492
|
if (toggle) {
|
|
2366
|
-
//
|
|
2367
|
-
restoreGenericModelPicker(parentMenu);
|
|
2493
|
+
// 私有 DOM 无法满足 MCX shell 契约时,保留原生菜单作为降级路径。
|
|
2368
2494
|
const raw = nativeModelValue(parentMenu);
|
|
2369
2495
|
const textNode = firstVisibleTextNode(toggle);
|
|
2370
2496
|
if (raw && textNode) {
|
|
@@ -2393,7 +2519,26 @@ export function createInjectionSource(features, {
|
|
|
2393
2519
|
}
|
|
2394
2520
|
return;
|
|
2395
2521
|
}
|
|
2396
|
-
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
// 原生 ModelText 重建前的空窗期:立即插回 MCX 标签,避免关盒后芯片
|
|
2525
|
+
// 长时间失去模型名。
|
|
2526
|
+
function restoreTriggerLabelWithoutNative(trigger, selector) {
|
|
2527
|
+
if (trigger.getAttribute("data-state") !== "closed") return;
|
|
2528
|
+
if (trigger.querySelector("[data-codex-model-slider-trigger-label]")) return;
|
|
2529
|
+
const raw = trigger.getAttribute("data-codex-model-slider-trigger-raw");
|
|
2530
|
+
if (!raw) return;
|
|
2531
|
+
const anchor = trigger.querySelector('[class*="_ModelPickerTriggerLabel_"]')
|
|
2532
|
+
?? trigger.querySelector('[class*="_ModelPickerTriggerContent_"]');
|
|
2533
|
+
if (!anchor) return;
|
|
2534
|
+
const displayLabel = document.createElement("span");
|
|
2535
|
+
displayLabel.setAttribute("data-codex-model-slider-trigger-label", "");
|
|
2536
|
+
displayLabel.textContent = modelDisplayLabel(modelIdentity(raw), selector);
|
|
2537
|
+
anchor.prepend(displayLabel);
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
function isComposerModelPlaceholder(value) {
|
|
2541
|
+
return /^(select\s+(model|effort)|选择\s*(模型|思考强度))$/i.test(String(value ?? "").trim());
|
|
2397
2542
|
}
|
|
2398
2543
|
|
|
2399
2544
|
function enhanceComposerModelTrigger(selector) {
|
|
@@ -2408,7 +2553,15 @@ export function createInjectionSource(features, {
|
|
|
2408
2553
|
const nativeLabels = Array.from(trigger.querySelectorAll(
|
|
2409
2554
|
'[class*="_ModelPickerTriggerModelText_"]:not([data-codex-model-slider-trigger-label])',
|
|
2410
2555
|
));
|
|
2411
|
-
if (!nativeLabels.length)
|
|
2556
|
+
if (!nativeLabels.length) {
|
|
2557
|
+
trigger.setAttribute("data-codex-model-slider-trigger", "");
|
|
2558
|
+
trigger.toggleAttribute(
|
|
2559
|
+
"data-codex-model-slider-trigger-placeholder",
|
|
2560
|
+
isComposerModelPlaceholder(trigger.innerText),
|
|
2561
|
+
);
|
|
2562
|
+
restoreTriggerLabelWithoutNative(trigger, selector);
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2412
2565
|
const visibleValue = String(nativeLabels.at(-1)?.textContent ?? "").trim();
|
|
2413
2566
|
const previousRaw = trigger.getAttribute("data-codex-model-slider-trigger-raw") ?? "";
|
|
2414
2567
|
const previousLabel = previousRaw
|
|
@@ -2419,16 +2572,30 @@ export function createInjectionSource(features, {
|
|
|
2419
2572
|
const label = modelDisplayLabel(modelIdentity(raw), selector);
|
|
2420
2573
|
trigger.setAttribute("data-codex-model-slider-trigger", "");
|
|
2421
2574
|
trigger.setAttribute("data-codex-model-slider-trigger-raw", raw);
|
|
2575
|
+
// 区分占位态(Select model / Select effort)与真实模型态:占位态沿用
|
|
2576
|
+
// 原生宽度契约,真实模型态让芯片 HUG 完整名称,避免第三方长名被截断。
|
|
2577
|
+
const placeholder = isComposerModelPlaceholder(label);
|
|
2578
|
+
trigger.toggleAttribute("data-codex-model-slider-trigger-placeholder", placeholder);
|
|
2422
2579
|
for (const nativeLabel of nativeLabels) {
|
|
2423
2580
|
let displayLabel = nativeLabel.nextElementSibling;
|
|
2424
2581
|
if (!displayLabel?.hasAttribute("data-codex-model-slider-trigger-label")) {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
displayLabel.
|
|
2582
|
+
// 空窗期回插等场景会在别处留下现成的 MCX 标签,优先移动复用,
|
|
2583
|
+
// 避免恢复后出现两个可见名称把芯片撑宽。
|
|
2584
|
+
displayLabel = trigger.querySelector("[data-codex-model-slider-trigger-label]");
|
|
2585
|
+
if (!displayLabel) {
|
|
2586
|
+
displayLabel = document.createElement("span");
|
|
2587
|
+
displayLabel.className = nativeLabel.className;
|
|
2588
|
+
displayLabel.setAttribute("data-codex-model-slider-trigger-label", "");
|
|
2589
|
+
}
|
|
2428
2590
|
nativeLabel.after(displayLabel);
|
|
2429
2591
|
}
|
|
2430
2592
|
if (displayLabel.textContent !== label) displayLabel.textContent = label;
|
|
2431
2593
|
}
|
|
2594
|
+
// 原生开合的临时 min-width 钉定与弹层水平居中都基于对 Measurement
|
|
2595
|
+
// 探针的测量;把探针文本同步为 MCX 显示标签,原生机制即可测得
|
|
2596
|
+
// 真实显示宽度(含 110px 名称上限与 160px Content 上限)。
|
|
2597
|
+
const measurement = trigger.querySelector('[class*="_ModelPickerTriggerMeasurement_"]');
|
|
2598
|
+
if (measurement && measurement.textContent !== label) measurement.textContent = label;
|
|
2432
2599
|
}
|
|
2433
2600
|
|
|
2434
2601
|
function ensureModelSelector() {
|
|
@@ -2485,9 +2652,7 @@ export function createInjectionSource(features, {
|
|
|
2485
2652
|
modelSelectorSuppressOutsidePointerSequence = false;
|
|
2486
2653
|
modelSelectorPendingReturn = false;
|
|
2487
2654
|
document.documentElement.removeAttribute("data-codex-model-slider-selecting-effort");
|
|
2488
|
-
for (const
|
|
2489
|
-
if (!item.isConnected) continue;
|
|
2490
|
-
item.innerHTML = html;
|
|
2655
|
+
for (const item of document.querySelectorAll("[data-codex-model-slider-item]")) {
|
|
2491
2656
|
item.style.removeProperty("display");
|
|
2492
2657
|
for (const name of [
|
|
2493
2658
|
"data-codex-model-slider-raw",
|
|
@@ -2524,7 +2689,6 @@ export function createInjectionSource(features, {
|
|
|
2524
2689
|
document.querySelectorAll("[data-codex-model-slider-trigger-label]").forEach((element) => element.remove());
|
|
2525
2690
|
document.documentElement.removeAttribute("data-codex-model-slider-catalog-ready");
|
|
2526
2691
|
modelSelectorStyle.remove();
|
|
2527
|
-
modelSelectorOriginalItems.clear();
|
|
2528
2692
|
modelSelectorOriginalToggleLabels.clear();
|
|
2529
2693
|
modelSelectorGenericContainers.clear();
|
|
2530
2694
|
modelSelectorNativeToggleHandlers.clear();
|
|
@@ -2568,6 +2732,33 @@ export function createInjectionSource(features, {
|
|
|
2568
2732
|
}, record.origin);
|
|
2569
2733
|
}
|
|
2570
2734
|
|
|
2735
|
+
function nativeSidebarTrigger() {
|
|
2736
|
+
const triggers = Array.from(document.querySelectorAll(
|
|
2737
|
+
'button[data-app-shell-sidebar-trigger="true"]',
|
|
2738
|
+
));
|
|
2739
|
+
return triggers.find((button) => isVisibleToolbarControl(button)) ?? triggers[0] ?? null;
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
function sidebarState() {
|
|
2743
|
+
const trigger = nativeSidebarTrigger();
|
|
2744
|
+
const expanded = trigger?.getAttribute("aria-expanded");
|
|
2745
|
+
const triggerRect = trigger?.getBoundingClientRect();
|
|
2746
|
+
return {
|
|
2747
|
+
available: Boolean(trigger),
|
|
2748
|
+
open: expanded === null ? sidebarRight() > 0 : expanded === "true",
|
|
2749
|
+
label: trigger?.getAttribute("aria-label") ?? "Show sidebar",
|
|
2750
|
+
leading: triggerRect?.left ?? 16,
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
function postSidebarState(record, state = sidebarState()) {
|
|
2755
|
+
if (!record || record.kind !== "page") return;
|
|
2756
|
+
record.frame.contentWindow?.postMessage({
|
|
2757
|
+
type: "codex-personal:sidebar-state",
|
|
2758
|
+
...state,
|
|
2759
|
+
}, record.origin);
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2571
2762
|
function registerSurface(key, feature, kind, surfaceUrl, element, frame, detailId = null) {
|
|
2572
2763
|
const record = {
|
|
2573
2764
|
key,
|
|
@@ -2587,6 +2778,7 @@ export function createInjectionSource(features, {
|
|
|
2587
2778
|
frame.addEventListener("load", () => {
|
|
2588
2779
|
queueTheme();
|
|
2589
2780
|
postSurfaceActive(record, activePageFeatureId === record.featureId && !record.element.hidden);
|
|
2781
|
+
postSidebarState(record);
|
|
2590
2782
|
});
|
|
2591
2783
|
requestSurfaceLoad(record);
|
|
2592
2784
|
return record;
|
|
@@ -2695,8 +2887,16 @@ export function createInjectionSource(features, {
|
|
|
2695
2887
|
}
|
|
2696
2888
|
|
|
2697
2889
|
function updatePageSurfacePositions() {
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2890
|
+
const state = sidebarState();
|
|
2891
|
+
const left = `${state.open ? Math.max(0, sidebarRight()) : 0}px`;
|
|
2892
|
+
for (const [featureId, surface] of pageSurfaces) {
|
|
2893
|
+
surface.style.left = left;
|
|
2894
|
+
postSidebarState(surfaceRecords.get(surfaceKey(featureId, "page")), state);
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
function syncAfterNativeSidebarToggle() {
|
|
2899
|
+
queueMicrotask(updatePageSurfacePositions);
|
|
2700
2900
|
}
|
|
2701
2901
|
|
|
2702
2902
|
function threadIdentity() {
|
|
@@ -4010,6 +4210,15 @@ export function createInjectionSource(features, {
|
|
|
4010
4210
|
});
|
|
4011
4211
|
return;
|
|
4012
4212
|
}
|
|
4213
|
+
if (action === "open-sidebar") {
|
|
4214
|
+
const trigger = nativeSidebarTrigger();
|
|
4215
|
+
if (!trigger) throw new Error("The native sidebar control was not found");
|
|
4216
|
+
const state = sidebarState();
|
|
4217
|
+
if (!state.open) trigger.click();
|
|
4218
|
+
queueMicrotask(() => postSidebarState(record, { ...state, open: true }));
|
|
4219
|
+
respondToSurface(record, requestId, { ok: true, result: { opened: true } });
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4013
4222
|
if (action === "resolve-file-paths") {
|
|
4014
4223
|
const getPathForFile = window.electronBridge?.getPathForFile;
|
|
4015
4224
|
if (typeof getPathForFile !== "function") {
|
|
@@ -4068,6 +4277,9 @@ export function createInjectionSource(features, {
|
|
|
4068
4277
|
document.addEventListener(
|
|
4069
4278
|
"click",
|
|
4070
4279
|
(event) => {
|
|
4280
|
+
if (event.target.closest?.('[data-app-shell-sidebar-trigger="true"]')) {
|
|
4281
|
+
syncAfterNativeSidebarToggle();
|
|
4282
|
+
}
|
|
4071
4283
|
if (
|
|
4072
4284
|
modelSelectorControllerMenu
|
|
4073
4285
|
&& !modelSelectorControllerMenu.menu.contains(event.target)
|
|
@@ -4133,6 +4345,7 @@ export function createInjectionSource(features, {
|
|
|
4133
4345
|
if (event.data.type === "codex-personal:ready") {
|
|
4134
4346
|
record.ready = true;
|
|
4135
4347
|
queueTheme();
|
|
4348
|
+
postSidebarState(record);
|
|
4136
4349
|
if (record.kind === "modal") {
|
|
4137
4350
|
record.frame.focus();
|
|
4138
4351
|
record.frame.contentWindow?.postMessage({
|
|
@@ -4170,7 +4383,24 @@ export function createInjectionSource(features, {
|
|
|
4170
4383
|
updatePageSurfacePositions();
|
|
4171
4384
|
updateResponsiveSummaryPresentation();
|
|
4172
4385
|
}, { signal: lifetime.signal });
|
|
4173
|
-
const ensureObserver = new MutationObserver(
|
|
4386
|
+
const ensureObserver = new MutationObserver((mutations) => {
|
|
4387
|
+
queueEnsure();
|
|
4388
|
+
const sidebarTriggerChanged = mutations.some((mutation) => {
|
|
4389
|
+
if (
|
|
4390
|
+
mutation.type === "attributes"
|
|
4391
|
+
&& mutation.target.matches?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4392
|
+
) return true;
|
|
4393
|
+
return mutation.type === "childList"
|
|
4394
|
+
&& [...mutation.addedNodes, ...mutation.removedNodes].some((node) => (
|
|
4395
|
+
node instanceof Element
|
|
4396
|
+
&& (
|
|
4397
|
+
node.matches?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4398
|
+
|| node.querySelector?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4399
|
+
)
|
|
4400
|
+
));
|
|
4401
|
+
});
|
|
4402
|
+
if (sidebarTriggerChanged) updatePageSurfacePositions();
|
|
4403
|
+
});
|
|
4174
4404
|
ensureObserver.observe(document.documentElement, {
|
|
4175
4405
|
childList: true,
|
|
4176
4406
|
subtree: true,
|