minecodex 0.1.20 → 0.2.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/features/images/codex-feature.json +5 -0
- package/features/images/src/chatgpt-image-source-page.mjs +207 -0
- package/features/images/src/chatgpt-image-source.mjs +42 -0
- package/features/images/src/http-server.mjs +92 -3
- package/features/images/src/image-library.mjs +171 -4
- package/features/images/web/app.js +35 -13
- package/features/model-slider/codex-feature.json +5 -1
- package/package.json +1 -1
- package/packages/cli/src/chatgpt-launch-coordinator.mjs +27 -1
- package/packages/cli/src/platform.mjs +0 -12
- package/packages/cli/src/runtime-manager.mjs +25 -28
- package/packages/runtime-host/src/codex-runtime.mjs +326 -96
- package/packages/runtime-host/src/feature-registry.mjs +56 -10
|
@@ -37,7 +37,7 @@ export function responsiveSummaryVisibleSurface({ displayMode, isPinned, isPopov
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function responsiveSummaryContentShift({ displayMode, isPinned }, layout = RESPONSIVE_SUMMARY_LAYOUT) {
|
|
40
|
-
return displayMode
|
|
40
|
+
return displayMode !== "overlay" && isPinned
|
|
41
41
|
? -(layout.panelWidth + layout.panelInset) / 2
|
|
42
42
|
: 0;
|
|
43
43
|
}
|
|
@@ -78,6 +78,18 @@ function requireDeclaredLoopbackSurface(feature, value) {
|
|
|
78
78
|
return url;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
export function pageScriptServiceOrigin(feature) {
|
|
82
|
+
if (!feature.pageScript || !feature.surfaceUrl || !feature.healthUrl) return null;
|
|
83
|
+
const surfaceUrl = new URL(feature.surfaceUrl);
|
|
84
|
+
const healthUrl = new URL(feature.healthUrl);
|
|
85
|
+
if (
|
|
86
|
+
surfaceUrl.origin !== healthUrl.origin
|
|
87
|
+
|| surfaceUrl.protocol !== "http:"
|
|
88
|
+
|| !LOOPBACK_SURFACE_HOSTS.has(surfaceUrl.hostname)
|
|
89
|
+
) return null;
|
|
90
|
+
return surfaceUrl.origin;
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
function findFrameByName(frameTree, frameName) {
|
|
82
94
|
if (frameTree.frame?.name === frameName) return frameTree.frame;
|
|
83
95
|
for (const child of frameTree.childFrames ?? []) {
|
|
@@ -127,9 +139,6 @@ export function createInjectionSource(features, {
|
|
|
127
139
|
const pinnedSurfaceMarker = "data-codex-personal-pinned-summary";
|
|
128
140
|
const modalSurfaceMarker = "data-codex-personal-modal";
|
|
129
141
|
const promptPreviewMarker = "data-codex-personal-prompt-preview";
|
|
130
|
-
const threadShiftStyle = document.createElement("style");
|
|
131
|
-
threadShiftStyle.setAttribute("data-codex-personal-summary-shift-style", "");
|
|
132
|
-
threadShiftStyle.textContent = "[data-codex-personal-summary-shift] { transform: none !important; --thread-wide-block-inline-shift: 0px !important; }";
|
|
133
142
|
const nativeLabels = {
|
|
134
143
|
sites: ["sites", "站点"],
|
|
135
144
|
scheduled: ["scheduled", "计划任务"],
|
|
@@ -254,7 +263,7 @@ export function createInjectionSource(features, {
|
|
|
254
263
|
const modelSelectorFeature = features.find(
|
|
255
264
|
(feature) => feature.entry?.kind === "composer-model-selector",
|
|
256
265
|
) ?? null;
|
|
257
|
-
const pageScriptFeatures = features.filter((feature) => feature.
|
|
266
|
+
const pageScriptFeatures = features.filter((feature) => feature.pageScript);
|
|
258
267
|
const pageSurfaces = new Map();
|
|
259
268
|
const pinnedSurfaces = new Map();
|
|
260
269
|
const surfaceRecords = new Map();
|
|
@@ -273,9 +282,9 @@ export function createInjectionSource(features, {
|
|
|
273
282
|
let savedComposerThread = null;
|
|
274
283
|
let currentThread = null;
|
|
275
284
|
let currentSummaryDisplayMode = null;
|
|
276
|
-
let
|
|
277
|
-
let shiftedThreadOriginal = null;
|
|
285
|
+
let shiftedConversationOwners = [];
|
|
278
286
|
let mainContentObserver = null;
|
|
287
|
+
let toolbarReadiness = null;
|
|
279
288
|
const domObservers = [];
|
|
280
289
|
const pageScriptCleanups = [];
|
|
281
290
|
const pendingHostActions = new Map();
|
|
@@ -304,6 +313,7 @@ export function createInjectionSource(features, {
|
|
|
304
313
|
let modelSelectorFastControlVisible = false;
|
|
305
314
|
// 持久化脏标记:仅在图标实际变化时写一次 localStorage。
|
|
306
315
|
let modelSelectorNativeFastIconsDirty = false;
|
|
316
|
+
const modelSelectorFastIconStorageKey = "codex-model-slider:fast-icons:v1";
|
|
307
317
|
const modelSelectorStyle = document.createElement("style");
|
|
308
318
|
modelSelectorStyle.setAttribute("data-codex-model-slider-style", "");
|
|
309
319
|
modelSelectorStyle.textContent = `
|
|
@@ -384,7 +394,7 @@ export function createInjectionSource(features, {
|
|
|
384
394
|
document.documentElement.append(modelSelectorStyle);
|
|
385
395
|
// 启动阶段就解析 Fast 图标:先读持久化的原生克隆,再从 app bundle 静态提取兜底,
|
|
386
396
|
// 避免首次会话必须等用户点开弹窗后 DOM 里才出现图标。
|
|
387
|
-
const persistedIcons = loadPersistedNativeFastIcons();
|
|
397
|
+
const persistedIcons = loadPersistedNativeFastIcons(modelSelectorFastIconStorageKey);
|
|
388
398
|
if (persistedIcons) {
|
|
389
399
|
modelSelectorNativeFastIcons = persistedIcons;
|
|
390
400
|
modelSelectorNativeFastIconSources = {};
|
|
@@ -404,9 +414,16 @@ export function createInjectionSource(features, {
|
|
|
404
414
|
"window",
|
|
405
415
|
"document",
|
|
406
416
|
"MutationObserver",
|
|
417
|
+
"config",
|
|
407
418
|
`"use strict";\n${source}`,
|
|
408
419
|
);
|
|
409
|
-
const cleanup = installer(
|
|
420
|
+
const cleanup = installer(
|
|
421
|
+
lifetime.signal,
|
|
422
|
+
window,
|
|
423
|
+
document,
|
|
424
|
+
MutationObserver,
|
|
425
|
+
feature.pageScript.config ?? {},
|
|
426
|
+
);
|
|
410
427
|
if (typeof cleanup === "function") pageScriptCleanups.push(cleanup);
|
|
411
428
|
} catch (error) {
|
|
412
429
|
console.warn(`[codex-personal] page-script feature failed: ${feature.id}`, error);
|
|
@@ -471,6 +488,57 @@ export function createInjectionSource(features, {
|
|
|
471
488
|
}) ?? null;
|
|
472
489
|
}
|
|
473
490
|
|
|
491
|
+
function structuralToolbarAnchor() {
|
|
492
|
+
const buttons = Array.from(document.querySelectorAll("button"));
|
|
493
|
+
return buttons.find((button) => /temporary chat/i.test(button.getAttribute("aria-label") ?? ""))
|
|
494
|
+
?? buttons.find((button) => new Set(["Toggle summary", "Toggle pinned summary"])
|
|
495
|
+
.has(button.getAttribute("aria-label")))
|
|
496
|
+
?? buttons.find((button) => button.getAttribute("aria-label") === "Toggle bottom panel")
|
|
497
|
+
?? buttons.find((button) => button.getAttribute("aria-label") === "Toggle side panel")
|
|
498
|
+
?? null;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function stopToolbarReadiness() {
|
|
502
|
+
if (!toolbarReadiness) return;
|
|
503
|
+
toolbarReadiness.observer.disconnect();
|
|
504
|
+
if (toolbarReadiness.retryTimer != null) clearTimeout(toolbarReadiness.retryTimer);
|
|
505
|
+
if (toolbarReadiness.deadlineTimer != null) clearTimeout(toolbarReadiness.deadlineTimer);
|
|
506
|
+
toolbarReadiness = null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function ensureToolbarReadiness(candidate) {
|
|
510
|
+
const thread = threadIdentity();
|
|
511
|
+
if (toolbarReadiness?.candidate === candidate && toolbarReadiness.thread === thread) return;
|
|
512
|
+
stopToolbarReadiness();
|
|
513
|
+
const record = {
|
|
514
|
+
candidate,
|
|
515
|
+
thread,
|
|
516
|
+
attempts: 0,
|
|
517
|
+
retryTimer: null,
|
|
518
|
+
deadlineTimer: null,
|
|
519
|
+
observer: null,
|
|
520
|
+
};
|
|
521
|
+
const wake = () => {
|
|
522
|
+
if (toolbarReadiness !== record) return;
|
|
523
|
+
queueEnsure();
|
|
524
|
+
};
|
|
525
|
+
record.observer = new ResizeObserver(wake);
|
|
526
|
+
record.observer.observe(candidate);
|
|
527
|
+
const header = candidate.closest("header");
|
|
528
|
+
if (header) record.observer.observe(header);
|
|
529
|
+
const retry = () => {
|
|
530
|
+
if (toolbarReadiness !== record || record.attempts >= 8) return;
|
|
531
|
+
record.attempts += 1;
|
|
532
|
+
wake();
|
|
533
|
+
record.retryTimer = setTimeout(retry, 75);
|
|
534
|
+
};
|
|
535
|
+
record.retryTimer = setTimeout(retry, 75);
|
|
536
|
+
record.deadlineTimer = setTimeout(() => {
|
|
537
|
+
if (toolbarReadiness === record) stopToolbarReadiness();
|
|
538
|
+
}, 1_500);
|
|
539
|
+
toolbarReadiness = record;
|
|
540
|
+
}
|
|
541
|
+
|
|
474
542
|
function toolbarControlRoot(button) {
|
|
475
543
|
return button?.parentElement?.parentElement ?? button?.parentElement ?? button ?? null;
|
|
476
544
|
}
|
|
@@ -525,8 +593,10 @@ export function createInjectionSource(features, {
|
|
|
525
593
|
}
|
|
526
594
|
|
|
527
595
|
function mainContentViewport() {
|
|
528
|
-
|
|
596
|
+
const composer = currentComposer();
|
|
597
|
+
return composer?.closest("main[data-app-shell-main-surface]")
|
|
529
598
|
?? document.querySelector("main[data-app-shell-main-surface]")
|
|
599
|
+
?? document.querySelector("[data-app-shell-main-content-layout]")
|
|
530
600
|
?? document.querySelector("main");
|
|
531
601
|
}
|
|
532
602
|
|
|
@@ -666,8 +736,6 @@ export function createInjectionSource(features, {
|
|
|
666
736
|
return null;
|
|
667
737
|
}
|
|
668
738
|
|
|
669
|
-
const modelSelectorFastIconStorageKey = "codex-model-slider:fast-icons:v1";
|
|
670
|
-
|
|
671
739
|
function persistNativeFastIcons() {
|
|
672
740
|
if (!modelSelectorNativeFastIcons || !modelSelectorNativeFastIconsDirty) return;
|
|
673
741
|
try {
|
|
@@ -682,22 +750,29 @@ export function createInjectionSource(features, {
|
|
|
682
750
|
}
|
|
683
751
|
}
|
|
684
752
|
|
|
685
|
-
function loadPersistedNativeFastIcons() {
|
|
753
|
+
function loadPersistedNativeFastIcons(storageKey) {
|
|
754
|
+
let stored;
|
|
686
755
|
try {
|
|
687
|
-
|
|
688
|
-
if (!payload || typeof payload !== "object") return null;
|
|
689
|
-
const icons = {};
|
|
690
|
-
for (const [state, markup] of Object.entries(payload)) {
|
|
691
|
-
if (typeof markup !== "string") continue;
|
|
692
|
-
const container = document.createElement("template");
|
|
693
|
-
container.innerHTML = markup;
|
|
694
|
-
const svg = container.content.querySelector("svg");
|
|
695
|
-
if (svg) icons[state] = svg;
|
|
696
|
-
}
|
|
697
|
-
return Object.keys(icons).length ? icons : null;
|
|
756
|
+
stored = localStorage.getItem(storageKey);
|
|
698
757
|
} catch {
|
|
699
758
|
return null;
|
|
700
759
|
}
|
|
760
|
+
let payload;
|
|
761
|
+
try {
|
|
762
|
+
payload = JSON.parse(stored ?? "null");
|
|
763
|
+
} catch {
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
if (!payload || typeof payload !== "object") return null;
|
|
767
|
+
const icons = {};
|
|
768
|
+
for (const [state, markup] of Object.entries(payload)) {
|
|
769
|
+
if (typeof markup !== "string") continue;
|
|
770
|
+
const container = document.createElement("template");
|
|
771
|
+
container.innerHTML = markup;
|
|
772
|
+
const svg = container.content.querySelector("svg");
|
|
773
|
+
if (svg) icons[state] = svg;
|
|
774
|
+
}
|
|
775
|
+
return Object.keys(icons).length ? icons : null;
|
|
701
776
|
}
|
|
702
777
|
|
|
703
778
|
function extractFastIconPath(source, prefix) {
|
|
@@ -911,14 +986,16 @@ export function createInjectionSource(features, {
|
|
|
911
986
|
(option) => String(option.thinkingEffort ?? "") === String(selected.thinkingEffort ?? ""),
|
|
912
987
|
);
|
|
913
988
|
const selectedEffort = selectedOption ? effortFor(selectedOption) : (efforts[0] ?? "instant");
|
|
989
|
+
const defaultEffort = String(version.defaultReasoningEffort ?? efforts[0] ?? "instant").toLowerCase();
|
|
914
990
|
const models = [{
|
|
915
991
|
model: String(selected.slug ?? ""),
|
|
916
992
|
displayName: String(version?.label ?? selected.slug ?? ""),
|
|
917
|
-
defaultReasoningEffort:
|
|
993
|
+
defaultReasoningEffort: defaultEffort,
|
|
918
994
|
supportedReasoningEfforts: efforts.map((effort) => ({ reasoningEffort: effort })),
|
|
919
995
|
}];
|
|
920
996
|
return {
|
|
921
997
|
models,
|
|
998
|
+
reasoningEffort: selectedEffort,
|
|
922
999
|
onSelectReasoningEffort(effort) {
|
|
923
1000
|
const target = options.find((option) => effortFor(option) === String(effort).toLowerCase());
|
|
924
1001
|
if (!target) return;
|
|
@@ -930,8 +1007,9 @@ export function createInjectionSource(features, {
|
|
|
930
1007
|
};
|
|
931
1008
|
}
|
|
932
1009
|
|
|
933
|
-
function nativeCatalogModelFor(identity) {
|
|
934
|
-
const
|
|
1010
|
+
function nativeCatalogModelFor(identity, selector = modelSelectorFeature?.modelSelector) {
|
|
1011
|
+
const controller = nativeComposerModelController();
|
|
1012
|
+
const models = controller?.models ?? [];
|
|
935
1013
|
const exact = models.find((model) => String(model.model ?? "").toLowerCase() === identity.raw.toLowerCase());
|
|
936
1014
|
const target = comparableModelLabel(identity.backend);
|
|
937
1015
|
const aliases = exact ? [] : models.filter((model) => (
|
|
@@ -939,13 +1017,25 @@ export function createInjectionSource(features, {
|
|
|
939
1017
|
));
|
|
940
1018
|
const model = exact ?? (aliases.length === 1 ? aliases[0] : null);
|
|
941
1019
|
if (!model) return null;
|
|
1020
|
+
const nativeReasoningLevels = (model.supportedReasoningEfforts ?? []).map((level) => ({
|
|
1021
|
+
effort: String(level?.reasoningEffort ?? level?.effort ?? level ?? "").toLowerCase(),
|
|
1022
|
+
})).filter((level) => level.effort);
|
|
1023
|
+
const allowed = selector?.reasoningEffortOverrides?.[identity.raw.toLowerCase()];
|
|
1024
|
+
const supportedReasoningLevels = allowed
|
|
1025
|
+
? nativeReasoningLevels.filter((level) => allowed.includes(level.effort))
|
|
1026
|
+
: nativeReasoningLevels;
|
|
1027
|
+
const currentReasoningLevel = String(controller?.reasoningEffort ?? "").toLowerCase();
|
|
942
1028
|
return {
|
|
943
1029
|
slug: String(model.model ?? ""),
|
|
944
1030
|
displayName: String(model.displayName ?? model.model ?? ""),
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1031
|
+
currentReasoningLevel: nativeReasoningLevels.some(
|
|
1032
|
+
(level) => level.effort === currentReasoningLevel,
|
|
1033
|
+
) ? currentReasoningLevel : null,
|
|
1034
|
+
currentReasoningLevelVisible: supportedReasoningLevels.some(
|
|
1035
|
+
(level) => level.effort === currentReasoningLevel,
|
|
1036
|
+
),
|
|
1037
|
+
defaultReasoningLevel: String(model.defaultReasoningEffort ?? "").toLowerCase(),
|
|
1038
|
+
supportedReasoningLevels,
|
|
949
1039
|
};
|
|
950
1040
|
}
|
|
951
1041
|
|
|
@@ -1591,6 +1681,9 @@ export function createInjectionSource(features, {
|
|
|
1591
1681
|
}
|
|
1592
1682
|
|
|
1593
1683
|
function selectNativeEffort(parentMenu, effort) {
|
|
1684
|
+
const identity = modelIdentity(nativeModelValue(parentMenu));
|
|
1685
|
+
const model = modelDefinitionFor(identity, modelSelectorFeature?.modelSelector);
|
|
1686
|
+
if (!model?.supportedReasoningLevels?.some((level) => level.effort === String(effort).toLowerCase())) return;
|
|
1594
1687
|
const controller = nativeComposerModelController();
|
|
1595
1688
|
if (typeof controller?.onSelectReasoningEffort === "function") {
|
|
1596
1689
|
controller.onSelectReasoningEffort(effort);
|
|
@@ -1666,6 +1759,24 @@ export function createInjectionSource(features, {
|
|
|
1666
1759
|
rail.setAttribute("aria-valuenow", String(index));
|
|
1667
1760
|
}
|
|
1668
1761
|
|
|
1762
|
+
function neutralizeStaleSliderVisual(rail) {
|
|
1763
|
+
for (const selector of [
|
|
1764
|
+
"[data-codex-model-slider-native-range]",
|
|
1765
|
+
"[data-codex-model-slider-native-thumb]",
|
|
1766
|
+
"[data-codex-model-slider-range]",
|
|
1767
|
+
"[data-codex-model-slider-thumb]",
|
|
1768
|
+
]) {
|
|
1769
|
+
rail.querySelectorAll(selector).forEach((element) => {
|
|
1770
|
+
element.style.setProperty("visibility", "hidden");
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
rail.querySelectorAll("[data-codex-model-slider-tick]").forEach((tick) => {
|
|
1774
|
+
tick.removeAttribute("data-selected");
|
|
1775
|
+
});
|
|
1776
|
+
rail.removeAttribute("aria-valuenow");
|
|
1777
|
+
rail.style.removeProperty("--codex-model-slider-progress");
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1669
1780
|
function nativeParticleSeed(index, salt) {
|
|
1670
1781
|
const value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;
|
|
1671
1782
|
return value - Math.floor(value);
|
|
@@ -1792,7 +1903,8 @@ export function createInjectionSource(features, {
|
|
|
1792
1903
|
|
|
1793
1904
|
function createGenericModelSlider(parentMenu, selector, identity, model, selectedEffort) {
|
|
1794
1905
|
const efforts = model.supportedReasoningLevels.map((level) => level.effort);
|
|
1795
|
-
const selectedIndex =
|
|
1906
|
+
const selectedIndex = efforts.indexOf(selectedEffort);
|
|
1907
|
+
const selectedEffortVisible = selectedIndex >= 0;
|
|
1796
1908
|
const classes = Object.fromEntries([
|
|
1797
1909
|
"Menu",
|
|
1798
1910
|
"ViewToggle",
|
|
@@ -1890,7 +2002,20 @@ export function createInjectionSource(features, {
|
|
|
1890
2002
|
rail.setAttribute("aria-label", locale === "zh-CN" ? "推理强度" : "Reasoning effort");
|
|
1891
2003
|
rail.setAttribute("aria-valuemin", "0");
|
|
1892
2004
|
rail.setAttribute("aria-valuemax", String(efforts.length - 1));
|
|
1893
|
-
rail.setAttribute("aria-valuetext",
|
|
2005
|
+
rail.setAttribute("aria-valuetext", selectedEffortVisible
|
|
2006
|
+
? effortLabel(selectedEffort)
|
|
2007
|
+
: (locale === "zh-CN" ? "当前档位不可用" : "Current effort unavailable"));
|
|
2008
|
+
rail.toggleAttribute("data-stale-reasoning-effort", !selectedEffortVisible);
|
|
2009
|
+
if (!selectedEffortVisible) {
|
|
2010
|
+
rail.setAttribute("aria-disabled", "true");
|
|
2011
|
+
rail.removeAttribute("tabindex");
|
|
2012
|
+
neutralizeStaleSliderVisual(rail);
|
|
2013
|
+
const staleView = document.createElement("div");
|
|
2014
|
+
staleView.className = classes.SimpleView;
|
|
2015
|
+
staleView.append(nativeSlider ?? rail);
|
|
2016
|
+
shell.append(viewControls, staleView);
|
|
2017
|
+
return shell;
|
|
2018
|
+
}
|
|
1894
2019
|
if (!nativeSlider) {
|
|
1895
2020
|
const track = document.createElement("div");
|
|
1896
2021
|
track.setAttribute("data-codex-model-slider-track", "");
|
|
@@ -1986,7 +2111,7 @@ export function createInjectionSource(features, {
|
|
|
1986
2111
|
// 控制器推导的任务内实际 effort 优先,避免子任务/主任务切换后触发器属性滞后;
|
|
1987
2112
|
// 触发器属性仅在控制器无法解析时作为实时回退,静态目录默认值最后兜底。
|
|
1988
2113
|
const nativeModel = nativeCatalogModelFor(identity);
|
|
1989
|
-
const selectedEffort = nativeModel?.
|
|
2114
|
+
const selectedEffort = nativeModel?.currentReasoningLevel
|
|
1990
2115
|
?? document.querySelector("[data-codex-intelligence-trigger]")
|
|
1991
2116
|
?.getAttribute("data-selected-reasoning-effort")
|
|
1992
2117
|
?? model.defaultReasoningLevel
|
|
@@ -2357,9 +2482,11 @@ export function createInjectionSource(features, {
|
|
|
2357
2482
|
}
|
|
2358
2483
|
if (next === currentThread) return;
|
|
2359
2484
|
currentThread = next;
|
|
2485
|
+
stopToolbarReadiness();
|
|
2360
2486
|
savedComposerRange = null;
|
|
2361
2487
|
savedComposerThread = null;
|
|
2362
2488
|
hidePinnedSurfaces();
|
|
2489
|
+
queueEnsure();
|
|
2363
2490
|
}
|
|
2364
2491
|
|
|
2365
2492
|
function currentComposer() {
|
|
@@ -2560,24 +2687,23 @@ export function createInjectionSource(features, {
|
|
|
2560
2687
|
}
|
|
2561
2688
|
}
|
|
2562
2689
|
|
|
2563
|
-
function threadScrollContent() {
|
|
2564
|
-
const scrollContainer = mainContentViewport()?.querySelector(".thread-scroll-container");
|
|
2565
|
-
return scrollContainer?.firstElementChild instanceof HTMLElement
|
|
2566
|
-
? scrollContainer.firstElementChild
|
|
2567
|
-
: null;
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
2690
|
function restoreThreadContentShift() {
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2691
|
+
for (const { element, shift, translate } of shiftedConversationOwners) {
|
|
2692
|
+
if (!element.isConnected) continue;
|
|
2693
|
+
if (shift.value) {
|
|
2694
|
+
element.style.setProperty(
|
|
2695
|
+
"--thread-wide-block-inline-shift",
|
|
2696
|
+
shift.value,
|
|
2697
|
+
shift.priority,
|
|
2698
|
+
);
|
|
2699
|
+
} else {
|
|
2700
|
+
element.style.removeProperty("--thread-wide-block-inline-shift");
|
|
2701
|
+
}
|
|
2702
|
+
if (translate.value) element.style.setProperty("translate", translate.value, translate.priority);
|
|
2703
|
+
else element.style.removeProperty("translate");
|
|
2577
2704
|
element.removeAttribute("data-codex-personal-summary-shift");
|
|
2578
2705
|
}
|
|
2579
|
-
|
|
2580
|
-
shiftedThreadOriginal = null;
|
|
2706
|
+
shiftedConversationOwners = [];
|
|
2581
2707
|
}
|
|
2582
2708
|
|
|
2583
2709
|
function applyThreadContentShift(value) {
|
|
@@ -2585,45 +2711,40 @@ export function createInjectionSource(features, {
|
|
|
2585
2711
|
restoreThreadContentShift();
|
|
2586
2712
|
return;
|
|
2587
2713
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
if (!
|
|
2714
|
+
const viewport = mainContentViewport();
|
|
2715
|
+
const owners = viewport
|
|
2716
|
+
? Array.from(viewport.querySelectorAll('[style*="--thread-wide-block-inline-shift"]'))
|
|
2717
|
+
: [];
|
|
2718
|
+
if (!owners.length) {
|
|
2593
2719
|
restoreThreadContentShift();
|
|
2594
2720
|
return;
|
|
2595
2721
|
}
|
|
2596
|
-
if (
|
|
2722
|
+
if (
|
|
2723
|
+
shiftedConversationOwners.length !== owners.length
|
|
2724
|
+
|| owners.some((owner, index) => shiftedConversationOwners[index]?.element !== owner)
|
|
2725
|
+
) {
|
|
2597
2726
|
restoreThreadContentShift();
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
priority: content.style.getPropertyPriority("position"),
|
|
2727
|
+
shiftedConversationOwners = owners.map((owner) => ({
|
|
2728
|
+
element: owner,
|
|
2729
|
+
shift: {
|
|
2730
|
+
value: owner.style.getPropertyValue("--thread-wide-block-inline-shift"),
|
|
2731
|
+
priority: owner.style.getPropertyPriority("--thread-wide-block-inline-shift"),
|
|
2604
2732
|
},
|
|
2605
|
-
|
|
2606
|
-
value:
|
|
2607
|
-
priority:
|
|
2733
|
+
translate: {
|
|
2734
|
+
value: owner.style.getPropertyValue("translate"),
|
|
2735
|
+
priority: owner.style.getPropertyPriority("translate"),
|
|
2608
2736
|
},
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2737
|
+
}));
|
|
2738
|
+
}
|
|
2739
|
+
for (const owner of owners) {
|
|
2740
|
+
owner.style.setProperty(
|
|
2741
|
+
"--thread-wide-block-inline-shift",
|
|
2742
|
+
`${Number(value)}px`,
|
|
2743
|
+
"important",
|
|
2744
|
+
);
|
|
2745
|
+
owner.style.setProperty("translate", `${Number(value)}px 0`, "important");
|
|
2746
|
+
owner.setAttribute("data-codex-personal-summary-shift", String(value));
|
|
2614
2747
|
}
|
|
2615
|
-
const duration = reducedMotion() ? 0 : 300;
|
|
2616
|
-
content.style.setProperty("transition", duration
|
|
2617
|
-
? "left 300ms cubic-bezier(.2,.8,.2,1)"
|
|
2618
|
-
: "none", "important");
|
|
2619
|
-
content.style.setProperty("position", "relative", "important");
|
|
2620
|
-
content.style.setProperty("left", `${value}px`, "important");
|
|
2621
|
-
content.setAttribute("data-codex-personal-summary-shift", String(value));
|
|
2622
|
-
if (duration) window.setTimeout(() => {
|
|
2623
|
-
if (content.getAttribute("data-codex-personal-summary-shift") !== String(value)) return;
|
|
2624
|
-
content.style.setProperty("transition", "none", "important");
|
|
2625
|
-
content.style.setProperty("left", `${value}px`, "important");
|
|
2626
|
-
}, duration + 50);
|
|
2627
2748
|
}
|
|
2628
2749
|
|
|
2629
2750
|
function setSummarySurfaceVisible(surface, visible, mode) {
|
|
@@ -2728,7 +2849,7 @@ export function createInjectionSource(features, {
|
|
|
2728
2849
|
surface.setAttribute("data-codex-personal-summary-presentation", displayMode);
|
|
2729
2850
|
setSummarySurfaceVisible(surface, true, displayMode);
|
|
2730
2851
|
|
|
2731
|
-
const shift = displayMode
|
|
2852
|
+
const shift = displayMode !== "overlay"
|
|
2732
2853
|
? -(layout.panelWidth + layout.panelInset) / 2
|
|
2733
2854
|
: 0;
|
|
2734
2855
|
applyThreadContentShift(shift);
|
|
@@ -3373,8 +3494,12 @@ export function createInjectionSource(features, {
|
|
|
3373
3494
|
const detail = feature?.detailTabs?.find((candidate) => candidate.id === detailId);
|
|
3374
3495
|
if (!feature || !detail) throw new Error("The requested detail Tab is not registered");
|
|
3375
3496
|
const result = await openNativeDetailTab(feature, detail);
|
|
3376
|
-
if (!result)
|
|
3377
|
-
|
|
3497
|
+
if (!result) {
|
|
3498
|
+
const error = nativeTabCapabilityError
|
|
3499
|
+
?? new Error("Codex native right-panel tabs are unavailable");
|
|
3500
|
+
error.code = "NATIVE_TAB_UNAVAILABLE";
|
|
3501
|
+
throw error;
|
|
3502
|
+
}
|
|
3378
3503
|
return result;
|
|
3379
3504
|
}
|
|
3380
3505
|
|
|
@@ -3489,13 +3614,20 @@ export function createInjectionSource(features, {
|
|
|
3489
3614
|
}
|
|
3490
3615
|
|
|
3491
3616
|
function ensureToolbarEntries() {
|
|
3492
|
-
if (!toolbarFeatures.length)
|
|
3617
|
+
if (!toolbarFeatures.length) {
|
|
3618
|
+
stopToolbarReadiness();
|
|
3619
|
+
return;
|
|
3620
|
+
}
|
|
3493
3621
|
const temporaryChatButton = nativeTemporaryChatButton();
|
|
3494
3622
|
const summaryButton = nativeSummaryButton();
|
|
3495
3623
|
const bottomPanelButton = nativeBottomPanelButton();
|
|
3496
3624
|
const sidePanelButton = nativeSidePanelButton();
|
|
3497
3625
|
const anchorButton = temporaryChatButton ?? summaryButton ?? bottomPanelButton ?? sidePanelButton;
|
|
3498
|
-
if (!anchorButton)
|
|
3626
|
+
if (!anchorButton) {
|
|
3627
|
+
const candidate = structuralToolbarAnchor();
|
|
3628
|
+
if (candidate) ensureToolbarReadiness(candidate);
|
|
3629
|
+
return;
|
|
3630
|
+
}
|
|
3499
3631
|
const anchorRoot = toolbarControlRoot(anchorButton);
|
|
3500
3632
|
// The bottom/side-panel toggles sit in narrow fixed containers that
|
|
3501
3633
|
// travel with the native panels. Entries anchored to them must live in
|
|
@@ -3506,7 +3638,10 @@ export function createInjectionSource(features, {
|
|
|
3506
3638
|
const useFallbackAnchor = anchorButton === sidePanelButton || anchorButton === bottomPanelButton;
|
|
3507
3639
|
const summaryGroup = useFallbackAnchor ? null : nativeSummaryToolbarGroup(anchorButton);
|
|
3508
3640
|
let targetGroup = summaryGroup ?? ensureFallbackSummaryToolbarGroup(anchorButton);
|
|
3509
|
-
if (!targetGroup)
|
|
3641
|
+
if (!targetGroup) {
|
|
3642
|
+
ensureToolbarReadiness(anchorButton);
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3510
3645
|
let cursor = useFallbackAnchor ? null : anchorRoot;
|
|
3511
3646
|
for (const feature of toolbarFeatures) {
|
|
3512
3647
|
const entries = Array.from(document.querySelectorAll(`[${entryMarker}="${feature.id}"]`));
|
|
@@ -3542,6 +3677,11 @@ export function createInjectionSource(features, {
|
|
|
3542
3677
|
if (!used) group.remove();
|
|
3543
3678
|
});
|
|
3544
3679
|
}
|
|
3680
|
+
if (toolbarFeatures.every((feature) => findEntry(feature.id)?.isConnected)) {
|
|
3681
|
+
stopToolbarReadiness();
|
|
3682
|
+
} else {
|
|
3683
|
+
ensureToolbarReadiness(anchorButton);
|
|
3684
|
+
}
|
|
3545
3685
|
}
|
|
3546
3686
|
|
|
3547
3687
|
function ensureEntries() {
|
|
@@ -3600,6 +3740,13 @@ export function createInjectionSource(features, {
|
|
|
3600
3740
|
}, record.origin);
|
|
3601
3741
|
}
|
|
3602
3742
|
|
|
3743
|
+
function hostActionFailure(error) {
|
|
3744
|
+
return {
|
|
3745
|
+
code: typeof error?.code === "string" ? error.code : "HOST_ACTION_FAILED",
|
|
3746
|
+
message: error?.message ?? "Host action failed",
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3603
3750
|
async function handleSurfaceHostAction(record, message) {
|
|
3604
3751
|
const feature = featureById.get(record.featureId);
|
|
3605
3752
|
const { requestId, action, payload = {} } = message;
|
|
@@ -3663,7 +3810,7 @@ export function createInjectionSource(features, {
|
|
|
3663
3810
|
} catch (error) {
|
|
3664
3811
|
respondToSurface(record, requestId, {
|
|
3665
3812
|
ok: false,
|
|
3666
|
-
error:
|
|
3813
|
+
error: hostActionFailure(error),
|
|
3667
3814
|
});
|
|
3668
3815
|
}
|
|
3669
3816
|
}
|
|
@@ -3831,9 +3978,9 @@ export function createInjectionSource(features, {
|
|
|
3831
3978
|
if (ensureFrame != null) cancelAnimationFrame(ensureFrame);
|
|
3832
3979
|
if (ensureTimer != null) clearTimeout(ensureTimer);
|
|
3833
3980
|
for (const observer of domObservers) observer.disconnect();
|
|
3981
|
+
stopToolbarReadiness();
|
|
3834
3982
|
mainContentObserver?.observer.disconnect();
|
|
3835
3983
|
restoreThreadContentShift();
|
|
3836
|
-
threadShiftStyle.remove();
|
|
3837
3984
|
for (const root of document.querySelectorAll("[data-codex-personal-toolbar-entry]")) root.remove();
|
|
3838
3985
|
for (const group of document.querySelectorAll("[data-codex-personal-summary-toolbar-group]")) group.remove();
|
|
3839
3986
|
for (const surface of pageSurfaces.values()) surface.remove();
|
|
@@ -3864,7 +4011,15 @@ export function createInjectionSource(features, {
|
|
|
3864
4011
|
detailTabs: feature.detailTabs ?? [],
|
|
3865
4012
|
hostActions: feature.hostActions ?? [],
|
|
3866
4013
|
modelSelector: feature.modelSelector ?? null,
|
|
3867
|
-
pageScript: feature.pageScript
|
|
4014
|
+
pageScript: feature.pageScript ? {
|
|
4015
|
+
...feature.pageScript,
|
|
4016
|
+
config: {
|
|
4017
|
+
serviceOrigin: pageScriptServiceOrigin(feature),
|
|
4018
|
+
bindingName,
|
|
4019
|
+
bindingToken,
|
|
4020
|
+
featureId: feature.id,
|
|
4021
|
+
},
|
|
4022
|
+
} : null,
|
|
3868
4023
|
}));
|
|
3869
4024
|
return `(${install.toString()})(${JSON.stringify({
|
|
3870
4025
|
version: RUNTIME_VERSION,
|
|
@@ -3886,7 +4041,9 @@ export function createRuntimeReadyContract({
|
|
|
3886
4041
|
runtimeSessionId,
|
|
3887
4042
|
}) {
|
|
3888
4043
|
const discovered = Boolean(renderer.discovered);
|
|
4044
|
+
const discoveredTargets = Math.max(0, Number(renderer.discoveredTargets) || 0);
|
|
3889
4045
|
const injectedTargets = Math.max(0, Number(renderer.injectedTargets) || 0);
|
|
4046
|
+
const targetFailures = Array.isArray(renderer.targetFailures) ? renderer.targetFailures : [];
|
|
3890
4047
|
const active = Boolean(renderer.active) && discovered && injectedTargets > 0;
|
|
3891
4048
|
return {
|
|
3892
4049
|
pid,
|
|
@@ -3904,8 +4061,11 @@ export function createRuntimeReadyContract({
|
|
|
3904
4061
|
})),
|
|
3905
4062
|
renderer: {
|
|
3906
4063
|
discovered,
|
|
4064
|
+
discoveredTargets,
|
|
3907
4065
|
injectedTargets,
|
|
3908
4066
|
active,
|
|
4067
|
+
healthy: active && targetFailures.length === 0 && injectedTargets === discoveredTargets,
|
|
4068
|
+
targetFailures,
|
|
3909
4069
|
runtimeSessionId: renderer.runtimeSessionId ?? runtimeSessionId,
|
|
3910
4070
|
},
|
|
3911
4071
|
};
|
|
@@ -4106,6 +4266,8 @@ export class CodexRuntime {
|
|
|
4106
4266
|
this.onStatusChange = onStatusChange;
|
|
4107
4267
|
this.onManagedCodexPidChange = onManagedCodexPidChange;
|
|
4108
4268
|
this.injectedTargets = new Set();
|
|
4269
|
+
this.rendererTargetIds = new Set();
|
|
4270
|
+
this.targetFailures = new Map();
|
|
4109
4271
|
this.clients = new Map();
|
|
4110
4272
|
this.scriptIds = new Map();
|
|
4111
4273
|
this.bindingTokens = new Map();
|
|
@@ -4159,10 +4321,21 @@ export class CodexRuntime {
|
|
|
4159
4321
|
|
|
4160
4322
|
getRendererStatus() {
|
|
4161
4323
|
const injectedTargets = this.injectedTargets.size;
|
|
4324
|
+
const discoveredTargets = this.rendererTargetIds.size;
|
|
4325
|
+
const targetFailures = Array.from(this.targetFailures, ([targetId, failure]) => ({
|
|
4326
|
+
targetId,
|
|
4327
|
+
attempts: failure.attempts,
|
|
4328
|
+
state: "retrying",
|
|
4329
|
+
lastFailure: failure.lastFailure,
|
|
4330
|
+
})).sort((left, right) => left.targetId.localeCompare(right.targetId));
|
|
4331
|
+
const active = !this.stopping && this.rendererDiscovered && injectedTargets > 0;
|
|
4162
4332
|
return {
|
|
4163
4333
|
discovered: this.rendererDiscovered,
|
|
4334
|
+
discoveredTargets,
|
|
4164
4335
|
injectedTargets,
|
|
4165
|
-
active
|
|
4336
|
+
active,
|
|
4337
|
+
healthy: active && targetFailures.length === 0 && injectedTargets === discoveredTargets,
|
|
4338
|
+
targetFailures,
|
|
4166
4339
|
runtimeSessionId: this.runtimeSessionId,
|
|
4167
4340
|
};
|
|
4168
4341
|
}
|
|
@@ -4173,8 +4346,11 @@ export class CodexRuntime {
|
|
|
4173
4346
|
if (
|
|
4174
4347
|
previous
|
|
4175
4348
|
&& previous.discovered === status.discovered
|
|
4349
|
+
&& previous.discoveredTargets === status.discoveredTargets
|
|
4176
4350
|
&& previous.injectedTargets === status.injectedTargets
|
|
4177
4351
|
&& previous.active === status.active
|
|
4352
|
+
&& previous.healthy === status.healthy
|
|
4353
|
+
&& JSON.stringify(previous.targetFailures) === JSON.stringify(status.targetFailures)
|
|
4178
4354
|
&& previous.runtimeSessionId === status.runtimeSessionId
|
|
4179
4355
|
) return;
|
|
4180
4356
|
this.lastRendererStatus = status;
|
|
@@ -4218,6 +4394,8 @@ export class CodexRuntime {
|
|
|
4218
4394
|
this.bindingTokens.clear();
|
|
4219
4395
|
this.hostActionChains.clear();
|
|
4220
4396
|
this.injectedTargets.clear();
|
|
4397
|
+
this.rendererTargetIds.clear();
|
|
4398
|
+
this.targetFailures.clear();
|
|
4221
4399
|
this.rendererDiscovered = false;
|
|
4222
4400
|
this.browserClient?.socket.close();
|
|
4223
4401
|
this.browserClient = null;
|
|
@@ -4581,6 +4759,10 @@ export class CodexRuntime {
|
|
|
4581
4759
|
});
|
|
4582
4760
|
return;
|
|
4583
4761
|
}
|
|
4762
|
+
if (request.action === "import-generated-image") {
|
|
4763
|
+
await this.importGeneratedImage(feature, request.payload);
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4584
4766
|
try {
|
|
4585
4767
|
if (request.action !== "attach-file") throw new Error("Unsupported native Host action");
|
|
4586
4768
|
const result = await this.attachFileToComposer(client, request.payload?.path, request.requestId);
|
|
@@ -4593,6 +4775,22 @@ export class CodexRuntime {
|
|
|
4593
4775
|
}
|
|
4594
4776
|
}
|
|
4595
4777
|
|
|
4778
|
+
async importGeneratedImage(feature, payload) {
|
|
4779
|
+
const origin = pageScriptServiceOrigin(feature);
|
|
4780
|
+
if (!origin) throw new Error("Generated image import service is unavailable");
|
|
4781
|
+
const response = await this.fetchImpl(new URL("/api/import-generated-image", origin), {
|
|
4782
|
+
method: "POST",
|
|
4783
|
+
headers: {
|
|
4784
|
+
"Content-Type": "application/json",
|
|
4785
|
+
Origin: CODEX_APP_ORIGIN,
|
|
4786
|
+
},
|
|
4787
|
+
body: JSON.stringify(payload),
|
|
4788
|
+
});
|
|
4789
|
+
if (!response?.ok) {
|
|
4790
|
+
throw new Error(`Generated image import returned HTTP ${response?.status ?? "error"}`);
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4596
4794
|
async refreshTargets() {
|
|
4597
4795
|
let response;
|
|
4598
4796
|
try {
|
|
@@ -4619,8 +4817,14 @@ export class CodexRuntime {
|
|
|
4619
4817
|
.filter((target) => target.type === "page" && target.url === "app://-/index.html")
|
|
4620
4818
|
.map((target) => target.id),
|
|
4621
4819
|
);
|
|
4820
|
+
this.rendererTargetIds = liveRendererIds;
|
|
4622
4821
|
let removedTarget = false;
|
|
4623
|
-
|
|
4822
|
+
const trackedTargetIds = new Set([
|
|
4823
|
+
...this.injectedTargets,
|
|
4824
|
+
...this.clients.keys(),
|
|
4825
|
+
...this.targetFailures.keys(),
|
|
4826
|
+
]);
|
|
4827
|
+
for (const id of trackedTargetIds) {
|
|
4624
4828
|
if (liveRendererIds.has(id)) continue;
|
|
4625
4829
|
removedTarget = true;
|
|
4626
4830
|
this.clients.get(id)?.socket.close();
|
|
@@ -4629,6 +4833,7 @@ export class CodexRuntime {
|
|
|
4629
4833
|
this.bindingTokens.delete(id);
|
|
4630
4834
|
this.hostActionChains.delete(id);
|
|
4631
4835
|
this.injectedTargets.delete(id);
|
|
4836
|
+
this.targetFailures.delete(id);
|
|
4632
4837
|
}
|
|
4633
4838
|
const rendererDiscovered = liveRendererIds.size > 0;
|
|
4634
4839
|
const rendererChanged = rendererDiscovered !== this.rendererDiscovered;
|
|
@@ -4639,8 +4844,12 @@ export class CodexRuntime {
|
|
|
4639
4844
|
if (target.type !== "page" || target.url !== "app://-/index.html" || this.injectedTargets.has(target.id)) {
|
|
4640
4845
|
continue;
|
|
4641
4846
|
}
|
|
4642
|
-
const
|
|
4847
|
+
const previousFailure = this.targetFailures.get(target.id);
|
|
4848
|
+
if (previousFailure && Date.now() < previousFailure.nextRetryAt) continue;
|
|
4849
|
+
let client;
|
|
4850
|
+
let scriptIdentifier = null;
|
|
4643
4851
|
try {
|
|
4852
|
+
client = await this.connectClient(target.webSocketDebuggerUrl);
|
|
4644
4853
|
await Promise.all([
|
|
4645
4854
|
client.send("Page.enable"),
|
|
4646
4855
|
client.send("Runtime.enable"),
|
|
@@ -4662,6 +4871,7 @@ export class CodexRuntime {
|
|
|
4662
4871
|
const script = await client.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
4663
4872
|
source: createDocumentBootstrapSource(source),
|
|
4664
4873
|
});
|
|
4874
|
+
scriptIdentifier = script.identifier;
|
|
4665
4875
|
await waitForExpression(
|
|
4666
4876
|
client,
|
|
4667
4877
|
`document.readyState === "interactive" || document.readyState === "complete"`,
|
|
@@ -4674,15 +4884,33 @@ export class CodexRuntime {
|
|
|
4674
4884
|
+ ` && window.__codexPersonalRuntime?.sessionId === ${JSON.stringify(this.runtimeSessionId)}`,
|
|
4675
4885
|
);
|
|
4676
4886
|
this.clients.set(target.id, client);
|
|
4677
|
-
this.scriptIds.set(target.id,
|
|
4887
|
+
this.scriptIds.set(target.id, scriptIdentifier);
|
|
4678
4888
|
this.injectedTargets.add(target.id);
|
|
4889
|
+
this.targetFailures.delete(target.id);
|
|
4679
4890
|
this.notifyStatusChange();
|
|
4680
4891
|
} catch (error) {
|
|
4681
4892
|
this.bindingTokens.delete(target.id);
|
|
4682
|
-
client
|
|
4683
|
-
|
|
4893
|
+
if (client) {
|
|
4894
|
+
if (scriptIdentifier) {
|
|
4895
|
+
await client.send("Page.removeScriptToEvaluateOnNewDocument", {
|
|
4896
|
+
identifier: scriptIdentifier,
|
|
4897
|
+
}).catch(() => {});
|
|
4898
|
+
}
|
|
4899
|
+
await client.send("Runtime.removeBinding", { name: HOST_BINDING_NAME }).catch(() => {});
|
|
4900
|
+
client.socket.close();
|
|
4901
|
+
}
|
|
4902
|
+
const attempts = (previousFailure?.attempts ?? 0) + 1;
|
|
4903
|
+
const retryDelay = Math.min(5_000, 250 * (2 ** Math.min(attempts - 1, 5)));
|
|
4904
|
+
this.targetFailures.set(target.id, {
|
|
4905
|
+
attempts,
|
|
4906
|
+
lastFailure: error.message,
|
|
4907
|
+
nextRetryAt: Date.now() + retryDelay,
|
|
4908
|
+
});
|
|
4909
|
+
this.logger.warn?.(`Renderer injection failed for ${target.id}; retrying`, error.message);
|
|
4910
|
+
this.notifyStatusChange();
|
|
4684
4911
|
}
|
|
4685
4912
|
}
|
|
4913
|
+
this.notifyStatusChange();
|
|
4686
4914
|
}
|
|
4687
4915
|
|
|
4688
4916
|
async stop() {
|
|
@@ -4712,6 +4940,8 @@ export class CodexRuntime {
|
|
|
4712
4940
|
this.bindingTokens.clear();
|
|
4713
4941
|
this.hostActionChains.clear();
|
|
4714
4942
|
this.injectedTargets.clear();
|
|
4943
|
+
this.rendererTargetIds.clear();
|
|
4944
|
+
this.targetFailures.clear();
|
|
4715
4945
|
this.rendererDiscovered = false;
|
|
4716
4946
|
this.notifyStatusChange();
|
|
4717
4947
|
this.monitorPromise = null;
|