minecodex 2.0.51 → 2.0.53
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/composer-expand/src/injection-source.mjs +3 -3
- package/features/composer-expand/src/native.mjs +23 -1
- package/features/file-navigation/src/adapters/codex/modules.mjs +23 -2
- package/features/file-navigation/src/injection-source.mjs +3 -3
- package/features/images/src/adapters/codex/native-image-modules.mjs +11 -4
- package/features/images/src/adapters/codex/rspack-modules.mjs +148 -0
- package/features/images/src/library-prompt-source.mjs +3 -2
- package/features/markdown-reading/src/adapters/codex/links.mjs +10 -1
- package/features/markdown-reading/src/adapters/codex/rich-text.mjs +12 -0
- package/features/markdown-reading/src/injection-source.mjs +6 -4
- package/features/mermaid-diagrams/src/adapters/codex/native.mjs +15 -0
- package/features/mermaid-diagrams/src/injection-source.mjs +6 -5
- package/features/model-slider/src/adapters/codex/controller.mjs +57 -2
- package/features/model-slider/src/frontend/install.mjs +49 -43
- package/features/quick-chat/src/adapters/codex/rspack.mjs +50 -0
- package/features/quick-chat/src/adapters/codex/shortcut.mjs +8 -1
- package/features/quick-chat/src/adapters/codex/sidebar.mjs +5 -1
- package/features/quick-chat/src/injection-source.mjs +3 -2
- package/features/session-status/src/session-status.mjs +9 -3
- package/features/sites/src/adapters/codex/renderer.mjs +2 -2
- package/package.json +1 -1
- package/packages/cli/src/control-server.mjs +4 -5
- package/packages/cli/src/npm-adapter.mjs +4 -4
- package/packages/codex-adapter/src/markdown/block-actions.mjs +4 -1
- package/packages/codex-adapter/src/markdown/editor-api.mjs +26 -1
- package/packages/codex-adapter/src/markdown/rspack.mjs +74 -0
- package/packages/codex-adapter/src/markdown/toc-native.mjs +4 -1
- package/packages/codex-adapter/src/renderer/modules.mjs +79 -0
- package/packages/plugin/assets/app.js +2 -2
- package/packages/plugin/assets/prompts.js +1 -1
|
@@ -16,6 +16,11 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
16
16
|
const modelSelectorOriginalToggleLabels = new Map();
|
|
17
17
|
const modelSelectorGenericContainers = new Map();
|
|
18
18
|
const modelSelectorNativeToggleHandlers = new Map();
|
|
19
|
+
// 原生 CSS 模块类名:26.1029 起改用不带下划线的 Name-hash 形式。
|
|
20
|
+
function hasNativeClass(element, name) {
|
|
21
|
+
const tokens = String(element?.className ?? "").split(/\s+/);
|
|
22
|
+
return tokens.some((token) => token.startsWith(`_${name}_`) || token.startsWith(`${name}-`));
|
|
23
|
+
}
|
|
19
24
|
const modelSelectorPositionObservers = new Map();
|
|
20
25
|
const modelSelectorMenuSizeFrames = new Map();
|
|
21
26
|
const modelSelectorOpeningFrames = new Map();
|
|
@@ -63,15 +68,15 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
63
68
|
max-height: var(--codex-model-slider-menu-max-height) !important;
|
|
64
69
|
overflow-y: auto;
|
|
65
70
|
}
|
|
66
|
-
[data-codex-model-slider-trigger] [class*="
|
|
71
|
+
[data-codex-model-slider-trigger] [class*="ModelPickerTriggerModelLabel"] {
|
|
67
72
|
min-width: 0; max-width: 110px; flex-shrink: 1; overflow: hidden; text-overflow: ellipsis;
|
|
68
73
|
}
|
|
69
|
-
[data-codex-model-slider-trigger] [class*="
|
|
74
|
+
[data-codex-model-slider-trigger] [class*="ModelPickerTriggerModelText"] {
|
|
70
75
|
min-width: 0; max-width: 110px; overflow: hidden; text-overflow: ellipsis;
|
|
71
76
|
}
|
|
72
77
|
html[data-codex-model-slider-catalog-ready]
|
|
73
78
|
[data-codex-model-slider-trigger]
|
|
74
|
-
[class*="
|
|
79
|
+
[class*="ModelPickerTriggerModelText"]:not([data-codex-model-slider-trigger-label]):has(+ [data-codex-model-slider-trigger-label]) {
|
|
75
80
|
display: none !important;
|
|
76
81
|
}
|
|
77
82
|
[data-codex-model-slider-trigger-label] {
|
|
@@ -83,26 +88,26 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
83
88
|
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [data-codex-model-slider-trigger-label] {
|
|
84
89
|
max-width: none; overflow: visible; text-overflow: clip; flex-shrink: 0;
|
|
85
90
|
}
|
|
86
|
-
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="
|
|
91
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="ModelPickerTriggerModelLabel"] {
|
|
87
92
|
max-width: none; overflow: visible; flex-shrink: 0;
|
|
88
93
|
}
|
|
89
|
-
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="
|
|
94
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="ModelPickerTriggerContent"] {
|
|
90
95
|
max-width: none !important;
|
|
91
96
|
}
|
|
92
|
-
[data-codex-model-slider-trigger][data-codex-model-slider-trigger-placeholder] [class*="
|
|
97
|
+
[data-codex-model-slider-trigger][data-codex-model-slider-trigger-placeholder] [class*="ModelPickerTriggerContent"] {
|
|
93
98
|
width: 160px; min-width: 160px !important; max-width: 160px;
|
|
94
99
|
}
|
|
95
100
|
/* 打开时先完成占位态,避免原生 crossfade 的宽度动画带动弹层。 */
|
|
96
|
-
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] [class*="
|
|
101
|
+
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] [class*="ModelPickerTriggerContent"] > span:has(> span > [class*="ModelPickerTriggerPlaceholder"]) {
|
|
97
102
|
width: 160px !important;
|
|
98
103
|
}
|
|
99
|
-
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] span:has(> [class*="
|
|
104
|
+
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] span:has(> [class*="ModelPickerTriggerPlaceholder"]) {
|
|
100
105
|
opacity: 1 !important;
|
|
101
106
|
}
|
|
102
|
-
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] [class*="
|
|
107
|
+
[data-codex-model-slider-trigger][data-state="open"][data-codex-model-slider-trigger-placeholder] [class*="ModelPickerTriggerLabel"] {
|
|
103
108
|
visibility: hidden;
|
|
104
109
|
}
|
|
105
|
-
[data-codex-model-slider-trigger] [class*="
|
|
110
|
+
[data-codex-model-slider-trigger] [class*="ModelPickerTriggerEffortLabel"] {
|
|
106
111
|
display: inline-flex; align-items: center; align-self: center;
|
|
107
112
|
}
|
|
108
113
|
html[data-codex-model-slider-selecting-effort] [role="menu"][data-state="open"]:not(:has([data-reasoning-slider])) {
|
|
@@ -185,12 +190,13 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
185
190
|
}
|
|
186
191
|
|
|
187
192
|
function nativeCssModuleClass(tokenName, root = document) {
|
|
188
|
-
|
|
189
|
-
const
|
|
193
|
+
// 26.1029 起原生类名改为 Name-hash,旧版带下划线包裹。
|
|
194
|
+
const pattern = new RegExp(`^(?:_${tokenName}_|${tokenName}-)[A-Za-z0-9_-]+$`);
|
|
195
|
+
const live = Array.from(root.querySelectorAll(`[class*="_${tokenName}_"], [class*="${tokenName}-"]`))
|
|
190
196
|
.flatMap((element) => Array.from(element.classList))
|
|
191
197
|
.find((name) => pattern.test(name));
|
|
192
198
|
if (live) return live;
|
|
193
|
-
const selectorPattern = new RegExp(`\\.(_${tokenName}_[A-Za-z0-9_-]+)`);
|
|
199
|
+
const selectorPattern = new RegExp(`\\.((?:_${tokenName}_|${tokenName}-)[A-Za-z0-9_-]+)`);
|
|
194
200
|
const find = (rules) => {
|
|
195
201
|
for (const rule of rules ?? []) {
|
|
196
202
|
const match = String(rule.selectorText ?? "").match(selectorPattern);
|
|
@@ -296,9 +302,9 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
296
302
|
|
|
297
303
|
function captureNativeFastIcon() {
|
|
298
304
|
// 原生控件每次只渲染当前状态;状态切换后按控件本身更新缓存。
|
|
299
|
-
const nativeContent = Array.from(document.querySelectorAll('[class*="_FastModeToggleContent_"]'))
|
|
305
|
+
const nativeContent = Array.from(document.querySelectorAll(':is([class*="_FastModeToggleContent_"], [class*="FastModeToggleContent-"])'))
|
|
300
306
|
.find((content) => !content.closest("[data-codex-model-slider-generic]"));
|
|
301
|
-
const toggle = nativeContent?.closest('[class*="_FastModeToggle_"]');
|
|
307
|
+
const toggle = nativeContent?.closest(':is([class*="_FastModeToggle_"], [class*="FastModeToggle-"])');
|
|
302
308
|
const state = toggle?.getAttribute("data-fast-mode-enabled") === "true" ? "active" : "inactive";
|
|
303
309
|
const svg = nativeContent?.querySelector("svg");
|
|
304
310
|
const current = modelSelectorNativeFastIcons?.[state];
|
|
@@ -341,11 +347,11 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
341
347
|
// 直接读取已就绪的图标存储(启动时由 bundle/持久化填充,运行期由
|
|
342
348
|
// captureNativeFastIcon 升级为 DOM 克隆),避免再次触发捕获造成递归。
|
|
343
349
|
// 优先克隆当前面板的图标;切换瞬间使用缓存时,也沿用原生图标尺寸。
|
|
344
|
-
const nativeContents = Array.from(document.querySelectorAll('[class*="_FastModeToggleContent_"]'))
|
|
350
|
+
const nativeContents = Array.from(document.querySelectorAll(':is([class*="_FastModeToggleContent_"], [class*="FastModeToggleContent-"])'))
|
|
345
351
|
.filter((content) => !content.closest("[data-codex-model-slider-generic]"));
|
|
346
352
|
const nativeContent = nativeContents.find((content) => (
|
|
347
353
|
(content.getAttribute("data-fast-mode-enabled")
|
|
348
|
-
?? content.closest('[class*="_FastModeToggle_"]')?.getAttribute("data-fast-mode-enabled")) === String(active)
|
|
354
|
+
?? content.closest(':is([class*="_FastModeToggle_"], [class*="FastModeToggle-"])')?.getAttribute("data-fast-mode-enabled")) === String(active)
|
|
349
355
|
));
|
|
350
356
|
const nativeSvg = nativeContent?.querySelector("svg") ?? nativeContents[0]?.querySelector("svg");
|
|
351
357
|
const template = nativeContent?.querySelector("svg")
|
|
@@ -458,7 +464,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
458
464
|
|
|
459
465
|
function nativeModelValue(menu) {
|
|
460
466
|
const toggle = menu?.querySelector("[data-model-picker-view-toggle]");
|
|
461
|
-
const toggleModelLabel = toggle?.querySelector('[class*="_ViewToggleModelLabel_"]');
|
|
467
|
+
const toggleModelLabel = toggle?.querySelector(':is([class*="_ViewToggleModelLabel_"], [class*="ViewToggleModelLabel-"])');
|
|
462
468
|
const toggleValues = String(
|
|
463
469
|
toggle?.hasAttribute("data-model-picker-view-toggle")
|
|
464
470
|
? (toggleModelLabel?.textContent ?? toggle.innerText)
|
|
@@ -1113,7 +1119,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1113
1119
|
if (!record) return false;
|
|
1114
1120
|
if (record.closing && !immediate) return true;
|
|
1115
1121
|
record.reveal?.cancel();
|
|
1116
|
-
const placeholder = record.trigger?.querySelector('[class*="
|
|
1122
|
+
const placeholder = record.trigger?.querySelector('[class*="ModelPickerTriggerPlaceholder"]');
|
|
1117
1123
|
const placeholderNode = placeholder && firstVisibleTextNode(placeholder);
|
|
1118
1124
|
if (placeholderNode && record.placeholderText != null) {
|
|
1119
1125
|
placeholderNode.nodeValue = record.placeholderText;
|
|
@@ -1297,7 +1303,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1297
1303
|
renderEnhancedModelMenu(menu, selector);
|
|
1298
1304
|
|
|
1299
1305
|
const trigger = nativeComposerTrigger();
|
|
1300
|
-
const placeholder = trigger?.querySelector('[class*="
|
|
1306
|
+
const placeholder = trigger?.querySelector('[class*="ModelPickerTriggerPlaceholder"]');
|
|
1301
1307
|
const placeholderNode = placeholder && firstVisibleTextNode(placeholder);
|
|
1302
1308
|
const placeholderText = placeholderNode?.nodeValue ?? null;
|
|
1303
1309
|
// 保留产品行为:模型列表打开时 chip 显示 Select model。只能原地更新
|
|
@@ -1446,7 +1452,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1446
1452
|
const edgeCorrection = correction * Math.max(0, edgeScale);
|
|
1447
1453
|
nativeRange.style.transform = `translateX(calc(${progress - 100}% + ${edgeCorrection}px))`;
|
|
1448
1454
|
nativeThumb.style.left = `calc(${progress}% + ${correction}px)`;
|
|
1449
|
-
const particleClip = rail.querySelector('[class*="_FastParticleClip_"]');
|
|
1455
|
+
const particleClip = rail.querySelector(':is([class*="_FastParticleClip_"], [class*="FastParticleClip-"])');
|
|
1450
1456
|
if (particleClip) particleClip.style.clipPath = `inset(0 calc(${100 - progress}% - ${edgeCorrection}px) 0 0)`;
|
|
1451
1457
|
}
|
|
1452
1458
|
rail.style.setProperty("--codex-model-slider-progress", `${progress}%`);
|
|
@@ -1462,7 +1468,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1462
1468
|
rail?.setAttribute("data-max", value);
|
|
1463
1469
|
effortText?.setAttribute("data-maximum", value);
|
|
1464
1470
|
fastButton?.setAttribute("data-max-power-selection", value);
|
|
1465
|
-
const maxEffects = rail?.querySelector('[class*="_MaxEffects_"]');
|
|
1471
|
+
const maxEffects = rail?.querySelector(':is([class*="_MaxEffects_"], [class*="MaxEffects-"])');
|
|
1466
1472
|
if (maxEffects) {
|
|
1467
1473
|
maxEffects.style.opacity = maximum ? "1" : "0";
|
|
1468
1474
|
if (maximum) maxEffects.style.transform = "translateX(0)";
|
|
@@ -1493,9 +1499,9 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1493
1499
|
}
|
|
1494
1500
|
|
|
1495
1501
|
function syncNativeFastParticles(rail, enabled, entering = false) {
|
|
1496
|
-
const track = Array.from(rail.children).find((element) =>
|
|
1502
|
+
const track = Array.from(rail.children).find((element) => hasNativeClass(element, "Track"));
|
|
1497
1503
|
if (!track) return;
|
|
1498
|
-
const staticParticles = rail.querySelector('[class*="_ParticleTransition_"]');
|
|
1504
|
+
const staticParticles = rail.querySelector(':is([class*="_ParticleTransition_"], [class*="ParticleTransition-"])');
|
|
1499
1505
|
if (staticParticles && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
1500
1506
|
staticParticles.__codexStaticParticleFade?.cancel();
|
|
1501
1507
|
staticParticles.style.opacity = enabled ? "0" : "1";
|
|
@@ -1507,7 +1513,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1507
1513
|
);
|
|
1508
1514
|
}
|
|
1509
1515
|
}
|
|
1510
|
-
track.querySelectorAll('[class*="_FastParticleClip_"]').forEach((element) => element.remove());
|
|
1516
|
+
track.querySelectorAll(':is([class*="_FastParticleClip_"], [class*="FastParticleClip-"])').forEach((element) => element.remove());
|
|
1511
1517
|
if (!enabled || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1512
1518
|
const clipClass = nativeCssModuleClass("FastParticleClip");
|
|
1513
1519
|
const particlesClass = nativeCssModuleClass("FastTrackParticles");
|
|
@@ -1540,7 +1546,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1540
1546
|
return path;
|
|
1541
1547
|
}));
|
|
1542
1548
|
clip.append(particles);
|
|
1543
|
-
const tickRail = Array.from(track.children).find((element) =>
|
|
1549
|
+
const tickRail = Array.from(track.children).find((element) => hasNativeClass(element, "TickRail"));
|
|
1544
1550
|
track.insertBefore(clip, tickRail ?? null);
|
|
1545
1551
|
// 重建粒子层后按当前档位恢复裁剪,避免重开面板时覆盖整条滑轨。
|
|
1546
1552
|
setGenericSliderVisual(rail, valueNow, valueMax + 1);
|
|
@@ -1615,13 +1621,13 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1615
1621
|
root.setAttribute("data-max", "false");
|
|
1616
1622
|
root.setAttribute("data-endpoint-labels-visible", "false");
|
|
1617
1623
|
const range = Array.from(root.querySelectorAll("span")).find((element) => (
|
|
1618
|
-
|
|
1624
|
+
hasNativeClass(element, "Range")
|
|
1619
1625
|
));
|
|
1620
1626
|
const thumbScale = Array.from(root.querySelectorAll("span")).find((element) => (
|
|
1621
|
-
|
|
1627
|
+
hasNativeClass(element, "ThumbScale")
|
|
1622
1628
|
));
|
|
1623
1629
|
const tickRail = Array.from(root.querySelectorAll("div")).find((element) => (
|
|
1624
|
-
|
|
1630
|
+
hasNativeClass(element, "TickRail")
|
|
1625
1631
|
));
|
|
1626
1632
|
const tickTemplate = tickRail?.querySelector("span");
|
|
1627
1633
|
if (!range || !thumbScale || !tickRail || !tickTemplate) return null;
|
|
@@ -1680,29 +1686,29 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1680
1686
|
copyCanvas();
|
|
1681
1687
|
canvasTimer = setInterval(copyCanvas, 80);
|
|
1682
1688
|
}
|
|
1683
|
-
const sourceEffects = source.querySelector('[class*="_MaxEffects_"]');
|
|
1684
|
-
const cloneEffects = clone.querySelector('[class*="_MaxEffects_"]');
|
|
1689
|
+
const sourceEffects = source.querySelector(':is([class*="_MaxEffects_"], [class*="MaxEffects-"])');
|
|
1690
|
+
const cloneEffects = clone.querySelector(':is([class*="_MaxEffects_"], [class*="MaxEffects-"])');
|
|
1685
1691
|
if (!sourceEffects || !cloneEffects) return { disconnect };
|
|
1686
1692
|
const sync = () => {
|
|
1687
1693
|
if (!source.isConnected || !shell.isConnected) {
|
|
1688
1694
|
disconnect();
|
|
1689
1695
|
return;
|
|
1690
1696
|
}
|
|
1691
|
-
const sourceTransition = sourceEffects.querySelector('[class*="_ParticleTransition_"]');
|
|
1692
|
-
let cloneTransition = cloneEffects.querySelector('[class*="_ParticleTransition_"]');
|
|
1697
|
+
const sourceTransition = sourceEffects.querySelector(':is([class*="_ParticleTransition_"], [class*="ParticleTransition-"])');
|
|
1698
|
+
let cloneTransition = cloneEffects.querySelector(':is([class*="_ParticleTransition_"], [class*="ParticleTransition-"])');
|
|
1693
1699
|
if (!sourceTransition) {
|
|
1694
1700
|
if (clone.querySelector("[data-fast-mode]")?.getAttribute("data-fast-mode") !== "true") {
|
|
1695
1701
|
cloneTransition?.remove();
|
|
1696
1702
|
}
|
|
1697
1703
|
return;
|
|
1698
1704
|
}
|
|
1699
|
-
const sourceParticles = sourceTransition.querySelectorAll('[class*="_TrackParticle_"]');
|
|
1700
|
-
let cloneParticles = cloneTransition?.querySelectorAll('[class*="_TrackParticle_"]');
|
|
1705
|
+
const sourceParticles = sourceTransition.querySelectorAll(':is([class*="_TrackParticle_"], [class*="TrackParticle-"])');
|
|
1706
|
+
let cloneParticles = cloneTransition?.querySelectorAll(':is([class*="_TrackParticle_"], [class*="TrackParticle-"])');
|
|
1701
1707
|
if (!cloneTransition || sourceParticles.length !== cloneParticles.length) {
|
|
1702
1708
|
cloneTransition?.remove();
|
|
1703
1709
|
cloneTransition = sourceTransition.cloneNode(true);
|
|
1704
1710
|
cloneEffects.append(cloneTransition);
|
|
1705
|
-
cloneParticles = cloneTransition.querySelectorAll('[class*="_TrackParticle_"]');
|
|
1711
|
+
cloneParticles = cloneTransition.querySelectorAll(':is([class*="_TrackParticle_"], [class*="TrackParticle-"])');
|
|
1706
1712
|
}
|
|
1707
1713
|
cloneTransition.setAttribute("style", sourceTransition.getAttribute("style") ?? "");
|
|
1708
1714
|
sourceParticles.forEach((particle, index) => {
|
|
@@ -1862,7 +1868,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1862
1868
|
viewControls.append(modelButton);
|
|
1863
1869
|
}
|
|
1864
1870
|
|
|
1865
|
-
const nativeReset = parentMenu.firstElementChild?.querySelector('[class*="_ResetToDefault_"]');
|
|
1871
|
+
const nativeReset = parentMenu.firstElementChild?.querySelector(':is([class*="_ResetToDefault_"], [class*="ResetToDefault-"])');
|
|
1866
1872
|
if (nativeReset) {
|
|
1867
1873
|
const reset = nativeReset.cloneNode(true);
|
|
1868
1874
|
reset.setAttribute("role", "button");
|
|
@@ -1870,7 +1876,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
1870
1876
|
reset.setAttribute("data-codex-model-slider-reset", "");
|
|
1871
1877
|
reset.removeAttribute("data-radix-collection-item");
|
|
1872
1878
|
reset.addEventListener("click", () => {
|
|
1873
|
-
const currentReset = parentMenu.firstElementChild?.querySelector('[class*="_ResetToDefault_"]');
|
|
1879
|
+
const currentReset = parentMenu.firstElementChild?.querySelector(':is([class*="_ResetToDefault_"], [class*="ResetToDefault-"])');
|
|
1874
1880
|
invokeNativeMenuItemSelect(currentReset);
|
|
1875
1881
|
queueEnsure();
|
|
1876
1882
|
});
|
|
@@ -2092,7 +2098,7 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
2092
2098
|
const existing = parentMenu.querySelector(":scope > [data-codex-model-slider-generic]");
|
|
2093
2099
|
const nativeTemplateReady = Boolean(
|
|
2094
2100
|
parentMenu.firstElementChild
|
|
2095
|
-
?.querySelector("[data-model-picker-power-slider] [class*='_TickRail_'] > span"),
|
|
2101
|
+
?.querySelector("[data-model-picker-power-slider] :is([class*='_TickRail_'], [class*='TickRail-']) > span"),
|
|
2096
2102
|
);
|
|
2097
2103
|
const templateWaitCount = Number(parentMenu.getAttribute("data-codex-model-slider-template-wait") ?? 0);
|
|
2098
2104
|
if (nativeModel?.slug.toLowerCase().startsWith("gpt-") && !nativeTemplateReady && templateWaitCount < 3) {
|
|
@@ -2212,8 +2218,8 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
2212
2218
|
if (trigger.querySelector("[data-codex-model-slider-trigger-label]")) return;
|
|
2213
2219
|
const raw = trigger.getAttribute("data-codex-model-slider-trigger-raw");
|
|
2214
2220
|
if (!raw) return;
|
|
2215
|
-
const anchor = trigger.querySelector('[class*="
|
|
2216
|
-
?? trigger.querySelector('[class*="
|
|
2221
|
+
const anchor = trigger.querySelector('[class*="ModelPickerTriggerLabel"]')
|
|
2222
|
+
?? trigger.querySelector('[class*="ModelPickerTriggerContent"]');
|
|
2217
2223
|
if (!anchor) return;
|
|
2218
2224
|
const displayLabel = document.createElement("span");
|
|
2219
2225
|
displayLabel.setAttribute("data-codex-model-slider-trigger-label", "");
|
|
@@ -2235,14 +2241,14 @@ export function installModelSlider(signal, { feature, ui, createIcon, requestRef
|
|
|
2235
2241
|
modelSelectorTriggerObservers.set(trigger, observer);
|
|
2236
2242
|
}
|
|
2237
2243
|
const openPlaceholder = trigger.getAttribute("data-state") === "open"
|
|
2238
|
-
&& trigger.querySelector('[class*="
|
|
2244
|
+
&& trigger.querySelector('[class*="ModelPickerTriggerPlaceholder"]');
|
|
2239
2245
|
if (openPlaceholder && modelSelectorControllerMenu?.trigger === trigger && !modelSelectorControllerMenu.closing) {
|
|
2240
2246
|
const textNode = firstVisibleTextNode(openPlaceholder);
|
|
2241
2247
|
const label = locale === "zh-CN" ? "选择模型" : "Select model";
|
|
2242
2248
|
if (textNode && textNode.nodeValue !== label) textNode.nodeValue = label;
|
|
2243
2249
|
}
|
|
2244
2250
|
const nativeLabels = Array.from(trigger.querySelectorAll(
|
|
2245
|
-
'[class*="
|
|
2251
|
+
'[class*="ModelPickerTriggerModelText"]:not([data-codex-model-slider-trigger-label])',
|
|
2246
2252
|
));
|
|
2247
2253
|
if (!nativeLabels.length) {
|
|
2248
2254
|
trigger.setAttribute("data-codex-model-slider-trigger", "");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// 从已注册的原生模块与导出表解析角色,不执行模块工厂或依赖压缩名称。
|
|
2
|
+
export function loadRspackQuickChatBindings(registry, commandCatalog) {
|
|
3
|
+
const catalog=registry.module(source=>/\{id:[`"']temporaryChat[`"'],titleIntlId:/.test(source),'Quick Chat command catalog');
|
|
4
|
+
const native=commandCatalog(catalog.source);
|
|
5
|
+
if (native) return {native};
|
|
6
|
+
const entry=registry.module(source=>/has-opened-quick-chat-v1/.test(source)&&/chatgpt\.quick-chat/.test(source),'Quick Chat lifecycle');
|
|
7
|
+
const exported=local=>{
|
|
8
|
+
if (!local) throw new Error('quick-chat-lifecycle-contract-unavailable');
|
|
9
|
+
const escaped=local.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
|
|
10
|
+
const key=entry.source.match(new RegExp(`([\\w$]+):\\(\\)=>${escaped}(?=[,}])`))?.[1];
|
|
11
|
+
const value=key && registry.exports(entry)[key];
|
|
12
|
+
if (value==null) throw new Error('quick-chat-lifecycle-export-unavailable');
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
const open=registry.value(entry,(value,source)=>typeof value==='function'&&/chatgpt\.quick-chat/.test(source)&&/\.get\(([\w$]+)\)\|\|/.test(source),'Quick Chat open');
|
|
16
|
+
const source=String(open);
|
|
17
|
+
const create=exported(source.match(/null==[\w$]+\?([\w$]+)\([\w$]+,[\w$]+\):/)?.[1]);
|
|
18
|
+
const state=exported(source.match(/\.get\(([\w$]+)\)\|\|/)?.[1]);
|
|
19
|
+
const bindings={native,open,create,isOpen:scope=>scope.get(state)};
|
|
20
|
+
if (typeof create!=='function') throw new Error('quick-chat-lifecycle-contract-unavailable');
|
|
21
|
+
try {
|
|
22
|
+
const discard=registry.value(entry,(value,source)=>typeof value==='function'&&/draftKey:/.test(source)&&/content:null/.test(source)&&/conversationId,""/.test(source),'Quick Chat discard');
|
|
23
|
+
const actions=String(discard).match(/let ([\w$]+)=([\w$]+)\.get\(([\w$]+)\);([\w$]+)\(\2\),\2\.set\(\3,null\),null!=\1&&\(\(0,([\w$]+\.[\w$]+)\)\(\2,\{draftKey:\1\.conversationId,content:null\}\),\(0,([\w$]+\.[\w$]+)\)\(\2,\1\.conversationId,""\),\2\.set\(([\w$]+\.[\w$]+),\1\.conversationId,\[\]\)/);
|
|
24
|
+
if (!actions) throw new Error('quick-chat-close-contract-unavailable');
|
|
25
|
+
const session=exported(actions[3]),close=exported(actions[4]);
|
|
26
|
+
const draft=registry.binding(entry,actions[5]),text=registry.binding(entry,actions[6]),attachments=registry.binding(entry,actions[7]);
|
|
27
|
+
if ([close,draft,text].some(value=>typeof value!=='function')) throw new Error('quick-chat-close-contract-unavailable');
|
|
28
|
+
bindings.close=(scope,id)=>{
|
|
29
|
+
if (scope.get(session)?.conversationId!==id) return false;
|
|
30
|
+
draft(scope,{draftKey:id,content:null});text(scope,id,'');scope.set(attachments,id,[]);close(scope);return true;
|
|
31
|
+
};
|
|
32
|
+
} catch { /* 关闭协议独立失效时仍保留打开能力。 */ }
|
|
33
|
+
try {
|
|
34
|
+
const modeEntry=registry.module(source=>/conversationDetailMode/.test(source)&&/"work":"codex"/.test(source),'Quick Chat product mode');
|
|
35
|
+
const modes=Object.values(registry.exports(modeEntry));
|
|
36
|
+
if (modes.length===1) bindings.mode=scope=>scope.get(modes[0]);
|
|
37
|
+
} catch { /* 无模式 selector 时只使用可见模式选择器。 */ }
|
|
38
|
+
return bindings;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function loadRspackQuickChatIcon(registry) {
|
|
42
|
+
const entry=registry.module(source=>/"data-floating-chat-surface":/.test(source)&&/minimizedIcon:/.test(source),'Quick Chat floating surface');
|
|
43
|
+
const local=entry.source.match(/minimizedIcon:([\w$]+)/)?.[1];
|
|
44
|
+
const escaped=local?.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
|
|
45
|
+
const reference=escaped&&entry.source.match(new RegExp(`children:${escaped}\\?\\?\\(0,[\\w$]+\\.jsx\\)\\(([\\w$]+\\.[\\w$]+),\\{\\}\\)`))?.[1];
|
|
46
|
+
if (!reference) throw new Error('quick-chat-icon-contract-unavailable');
|
|
47
|
+
const icon=registry.binding(entry,reference);
|
|
48
|
+
if (typeof icon?.createElement!=='function') throw new Error('quick-chat-icon-contract-unavailable');
|
|
49
|
+
return icon;
|
|
50
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {loadRspackQuickChatBindings} from "./rspack.mjs";
|
|
2
|
+
import { findCodexModule, codexModuleRegistry } from '../../../../../packages/codex-adapter/src/renderer/modules.mjs';
|
|
2
3
|
import {quickChatLifecycleActions, quickChatScope} from "./lifecycle.mjs";
|
|
3
4
|
// 通过原生能力检查与已有会话分支定位打开动作,不依赖构建哈希或压缩名称。
|
|
4
5
|
export function quickChatOpenExport(source) {
|
|
@@ -99,6 +100,12 @@ export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
|
99
100
|
}
|
|
100
101
|
async function load() {
|
|
101
102
|
codex.report('quick-chat-shortcut', false, 'quick-chat-module-pending');
|
|
103
|
+
const registry=await codexModuleRegistry({signal:loading.signal,waitForEntry:true,read:async url=>(await fetch(url,{signal:loading.signal})).text()});
|
|
104
|
+
if (registry) {
|
|
105
|
+
const bindings=loadRspackQuickChatBindings(registry,quickChatNativeCommand);
|
|
106
|
+
if (!bindings.native && !bindings.close) codex.report('quick-chat-close',false,'quick-chat-close-contract-unavailable');
|
|
107
|
+
return bindings;
|
|
108
|
+
}
|
|
102
109
|
const url=await findCodexModule('app-initial',{signal:loading.signal,waitForEntry:true});
|
|
103
110
|
if (!url) throw new Error('quick-chat-module-unavailable');
|
|
104
111
|
const source = await (await fetch(url, {signal:loading.signal})).text();
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {loadRspackQuickChatIcon} from "./rspack.mjs";
|
|
2
|
+
import { findCodexModule, codexModuleRegistry } from '../../../../../packages/codex-adapter/src/renderer/modules.mjs';
|
|
2
3
|
export async function loadQuickChatSidebarIcon(signal) {
|
|
4
|
+
signal.throwIfAborted();
|
|
5
|
+
const registry=await codexModuleRegistry({signal,waitForEntry:true,read:async url=>(await fetch(url,{signal})).text()});
|
|
6
|
+
if (registry) return loadRspackQuickChatIcon(registry);
|
|
3
7
|
const initialUrl = await findCodexModule('app-initial',{signal});
|
|
4
8
|
if (!initialUrl) throw new Error('quick-chat-icon-module-unavailable');
|
|
5
9
|
const initial = await (await fetch(initialUrl,{signal})).text();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {loadRspackQuickChatBindings,loadRspackQuickChatIcon} from "./adapters/codex/rspack.mjs";
|
|
2
|
+
import { findCodexModule, codexModuleRegistry } from '../../../packages/codex-adapter/src/renderer/modules.mjs';
|
|
2
3
|
import {quickChatLifecycleActions, quickChatScope} from "./adapters/codex/lifecycle.mjs";
|
|
3
4
|
import {quickChatHistoryVisible} from "./adapters/codex/history.mjs";
|
|
4
5
|
import { readFile } from "node:fs/promises";
|
|
@@ -10,7 +11,7 @@ import { installQuickChatSidebar } from "./frontend/sidebar.mjs";
|
|
|
10
11
|
import { createHistoryTracker } from "./domain/history.mjs";
|
|
11
12
|
export async function createPageScriptSource() {
|
|
12
13
|
const source = await readFile(new URL("./frontend/entry.mjs", import.meta.url), "utf8");
|
|
13
|
-
const functions = [findCodexModule, quickChatHistoryVisible, loadQuickChatSidebarIcon, createQuickChatSidebarAdapter, installQuickChatSidebar,
|
|
14
|
+
const functions = [findCodexModule, codexModuleRegistry, loadRspackQuickChatBindings, loadRspackQuickChatIcon, quickChatHistoryVisible, loadQuickChatSidebarIcon, createQuickChatSidebarAdapter, installQuickChatSidebar,
|
|
14
15
|
quickChatLifecycleActions, quickChatScope, quickChatOpenExport, quickChatLifecycleExports, quickChatNativeCommand, installQuickChatShortcut, createQuickChatAdapter,
|
|
15
16
|
createSubmissionTracker, createHistoryTracker];
|
|
16
17
|
return functions.map(fn => `const ${fn.name}=${fn.toString()};`).join('\n') + '\n' + source;
|
|
@@ -269,6 +269,7 @@ collapse.innerHTML = '<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" st
|
|
|
269
269
|
collapse.addEventListener("click", () => { setGlobalExpanded(false); trigger.focus(); hideTooltip(); }, { signal });
|
|
270
270
|
root.append(collapse);
|
|
271
271
|
let snapshot = null;
|
|
272
|
+
let logSnapshot = null;
|
|
272
273
|
// 统计刷新会重建浮窗,复用图标节点以保留 tooltip 的悬浮锚点。
|
|
273
274
|
const tpsInfo = document.createElement("button");
|
|
274
275
|
tpsInfo.type = "button";
|
|
@@ -499,7 +500,8 @@ function ensurePosition() {
|
|
|
499
500
|
activeThreadId = threadId;
|
|
500
501
|
nativeContext = emptyNativeContext();
|
|
501
502
|
// 会话建立后先展示占位,不让日志落盘速度决定状态栏是否出现。
|
|
502
|
-
|
|
503
|
+
logSnapshot = threadId ? { threadId } : null;
|
|
504
|
+
snapshot = logSnapshot;
|
|
503
505
|
closePanel();
|
|
504
506
|
render();
|
|
505
507
|
requestRefresh();
|
|
@@ -532,8 +534,12 @@ function ensurePosition() {
|
|
|
532
534
|
}
|
|
533
535
|
syncVisibility(composer);
|
|
534
536
|
}
|
|
537
|
+
// 原生上下文不可用时保留日志口径,避免环退化为占位。
|
|
538
|
+
function withNativeContext(current, native) {
|
|
539
|
+
return !current || native.contextPercent == null ? current : { ...current, ...native };
|
|
540
|
+
}
|
|
535
541
|
function render() {
|
|
536
|
-
|
|
542
|
+
snapshot = withNativeContext(logSnapshot, nativeContext);
|
|
537
543
|
syncVisibility(findComposer());
|
|
538
544
|
if (root.hidden) return;
|
|
539
545
|
trigger.querySelector("[data-context-progress]").setAttribute("stroke-dashoffset", String(100 - (snapshot.contextPercent ?? 0)));
|
|
@@ -587,7 +593,7 @@ const receiver = {
|
|
|
587
593
|
if (revision <= lastRevision) return;
|
|
588
594
|
lastRevision = revision;
|
|
589
595
|
}
|
|
590
|
-
|
|
596
|
+
logSnapshot = value;
|
|
591
597
|
render();
|
|
592
598
|
scheduleRefresh();
|
|
593
599
|
},
|
|
@@ -31,8 +31,8 @@ function pageInfo() {
|
|
|
31
31
|
if (!visible(content)) return null;
|
|
32
32
|
const native = nativeProps(list || content.querySelector("button") || content.querySelector("p") || content.lastElementChild?.lastElementChild, p => "viewMode" in p && "shared" in p);
|
|
33
33
|
const grid = native ? native.viewMode === "grid" : !!page.querySelector('button[aria-label="Grid view"][aria-pressed="true"],button[aria-label="网格视图"][aria-pressed="true"]');
|
|
34
|
-
const ownershipTabs=[...page.querySelectorAll('[role="tablist"]')].find(node=>!node.closest(`[${owned}]`)&&nativeProps(node,p=>p.tabs?.some(tab=>tab.key==="owned")&&p.tabs?.some(tab=>tab.key
|
|
35
|
-
const ownership=ownershipTabs&&nativeProps(ownershipTabs,p=>p.tabs?.some(tab=>tab.key==="owned")&&p.tabs?.some(tab=>tab.key
|
|
34
|
+
const ownershipTabs=[...page.querySelectorAll('[role="tablist"]')].find(node=>!node.closest(`[${owned}]`)&&nativeProps(node,p=>p.tabs?.some(tab=>tab.key==="owned")&&p.tabs?.some(tab=>["shared","pinned"].includes(tab.key))));
|
|
35
|
+
const ownership=ownershipTabs&&nativeProps(ownershipTabs,p=>p.tabs?.some(tab=>tab.key==="owned")&&p.tabs?.some(tab=>["shared","pinned"].includes(tab.key)));
|
|
36
36
|
const shared = ownership ? ownership.selectedKey === "shared" : native ? !!native.shared : [...page.querySelectorAll("button[aria-pressed=true]")].some(b => /Shared with you|与你共享|與你共用/.test(b.textContent));
|
|
37
37
|
const create = [...(plus ? page : page.firstElementChild).querySelectorAll("button")].find(b => visible(b) && (plus ? /^(Create Site|创建站点|创建新站点|建立網站)$/ : /^(New|新建|新增)$/).test(b.textContent.trim()) && !b.hasAttribute(owned));
|
|
38
38
|
codex.report("sites-page",true);
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
import { BrowserExchangeStore } from "./browser-exchange.mjs";
|
|
9
9
|
import { FEATURE_IDS, readConfig, updateFeature } from "./config.mjs";
|
|
10
10
|
import { normalizeRuntimeReady } from "./runtime-manager.mjs";
|
|
11
|
+
import { createNpmAdapter } from "./npm-adapter.mjs";
|
|
11
12
|
|
|
12
13
|
import { createDataTransfer, MAX_TRANSFER_BYTES } from "./data-transfer/service.mjs";
|
|
13
14
|
|
|
@@ -327,11 +328,9 @@ export async function createControlServer({
|
|
|
327
328
|
return;
|
|
328
329
|
}
|
|
329
330
|
if (request.method === "GET" && url.pathname === "/api/update") {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
});
|
|
333
|
-
if (!registryResponse.ok) throw Object.assign(new Error("Update check failed"), { statusCode: 502 });
|
|
334
|
-
const latest = String((await registryResponse.json()).version ?? "");
|
|
331
|
+
// 与 mcx update 共用 npm 配置,保留用户的 registry、代理和证书设置。
|
|
332
|
+
const latest = await createNpmAdapter().viewLatestVersion();
|
|
333
|
+
if (!latest) throw Object.assign(new Error("Update check failed"), { statusCode: 502 });
|
|
335
334
|
json(response, 200, {
|
|
336
335
|
current: packageMetadata.version,
|
|
337
336
|
latest,
|
|
@@ -7,17 +7,17 @@ import { promisify } from "node:util";
|
|
|
7
7
|
const defaultExecFile = promisify(execFileCallback);
|
|
8
8
|
|
|
9
9
|
export function createNpmAdapter({ execFile = defaultExecFile, tempRoot = os.tmpdir(), platform = process.platform } = {}) {
|
|
10
|
-
function runNpm(args) {
|
|
11
|
-
if (platform !== "win32") return execFile("npm", args);
|
|
10
|
+
function runNpm(args, options = {}) {
|
|
11
|
+
if (platform !== "win32") return execFile("npm", args, options);
|
|
12
12
|
// npm.cmd 需要命令解释器;字面量参数经编码传递,避免路径被当成脚本。
|
|
13
13
|
const quote = (value) => "'" + String(value).replaceAll("'", "''") + "'";
|
|
14
14
|
const script = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; $ErrorActionPreference='Stop'; & npm.cmd "
|
|
15
15
|
+ args.map(quote).join(" ") + "; exit $LASTEXITCODE";
|
|
16
|
-
return execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")]);
|
|
16
|
+
return execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], options);
|
|
17
17
|
}
|
|
18
18
|
return {
|
|
19
19
|
async viewLatestVersion() {
|
|
20
|
-
const { stdout } = await runNpm(["view", "minecodex", "version"]);
|
|
20
|
+
const { stdout } = await runNpm(["view", "minecodex", "version", "--fetch-retries=0", "--fetch-timeout=8000"], { timeout: 12_000 });
|
|
21
21
|
return stdout.trim();
|
|
22
22
|
},
|
|
23
23
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {loadRspackMarkdownTableActions} from './rspack.mjs';
|
|
2
|
+
import { findCodexModule, codexModuleRegistry } from '../renderer/modules.mjs';
|
|
2
3
|
import { loadNativeMarkdownRenderer } from './markdown-native.mjs';
|
|
3
4
|
|
|
4
5
|
export function markdownExportAlias(source, name) {
|
|
@@ -14,6 +15,8 @@ export function markdownExportAlias(source, name) {
|
|
|
14
15
|
|
|
15
16
|
// 从 Chat Markdown 的公开组件发现悬浮操作栏和控件,不绑定构建 hash。
|
|
16
17
|
export async function loadNativeMarkdownTableActions(native) {
|
|
18
|
+
const registry=await codexModuleRegistry();
|
|
19
|
+
if(registry)return loadRspackMarkdownTableActions(registry,native);
|
|
17
20
|
const url = await findCodexModule('app-initial');
|
|
18
21
|
if (!url) throw new Error('native-table-actions-module-unavailable');
|
|
19
22
|
const response = await fetch(url);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { findCodexModule } from '../renderer/modules.mjs';
|
|
1
|
+
import { findCodexModule, codexModuleRegistry } from '../renderer/modules.mjs';
|
|
2
2
|
// 使用当前编辑器所属的原生 CodeMirror 实例,避免引入第二套编辑器依赖。
|
|
3
3
|
export async function loadMarkdownListAPI(view) {
|
|
4
|
+
const registry=await codexModuleRegistry();
|
|
5
|
+
if (registry) return loadRspackMarkdownListAPI(registry,view);
|
|
4
6
|
const urls=await findCodexModule('dist',{all:true});
|
|
5
7
|
for (const url of urls) {
|
|
6
8
|
const exports = Object.values(await import(url));
|
|
@@ -24,3 +26,26 @@ export async function loadMarkdownListAPI(view) {
|
|
|
24
26
|
}
|
|
25
27
|
throw new Error('native-markdown-list-api-unavailable');
|
|
26
28
|
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
export function loadRspackMarkdownListAPI(registry,view) {
|
|
32
|
+
const values=[...new Set(registry.entries.flatMap(entry=>{
|
|
33
|
+
let exports;
|
|
34
|
+
try {exports=Object.values(registry.exports(entry));} catch {return [];}
|
|
35
|
+
return exports.includes(view.constructor)||exports.includes(view.state.constructor)?exports:[];
|
|
36
|
+
}))];
|
|
37
|
+
const requireRole=(predicate,role)=>{
|
|
38
|
+
const matches=values.filter(predicate);
|
|
39
|
+
if(matches.length!==1)throw new Error(`native-codemirror-${role}-unavailable`);
|
|
40
|
+
return matches[0];
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
Decoration:requireRole(value=>value?.line&&value?.replace&&value?.mark,'decoration'),
|
|
44
|
+
ViewPlugin:requireRole(value=>value?.fromClass&&value?.define,'view-plugin'),
|
|
45
|
+
StateEffect:requireRole(value=>value?.appendConfig&&value?.reconfigure,'state-effect'),
|
|
46
|
+
Compartment:requireRole(value=>value?.prototype?.reconfigure&&value?.prototype?.of&&value?.prototype?.get,'compartment'),
|
|
47
|
+
WidgetType:requireRole(value=>value?.prototype?.eq&&value?.prototype?.ignoreEvent&&value?.prototype?.updateDOM,'widget'),
|
|
48
|
+
StateField:requireRole(value=>value?.define&&value?.prototype?.slot&&value?.prototype?.init&&value?.prototype?.create,'state-field'),
|
|
49
|
+
Prec:requireRole(value=>value?.highest&&value?.lowest&&value?.high,'precedence'),
|
|
50
|
+
};
|
|
51
|
+
}
|