minecodex 0.1.6 → 0.1.8
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 +1 -1
- package/features/images/web/app.js +3 -3
- package/features/images/web/styles.css +1 -0
- package/features/model-slider/codex-feature.json +1 -1
- package/features/notes/codex-feature.json +1 -1
- package/features/notes/web/app.js +1 -1
- package/features/notes/web/styles.css +1 -1
- package/package.json +1 -1
- package/packages/runtime-host/src/codex-runtime.mjs +46 -192
|
@@ -303,9 +303,9 @@ function layoutMasonry() {
|
|
|
303
303
|
const cards = [...grid.children];
|
|
304
304
|
if (!cards.length) return;
|
|
305
305
|
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
|
|
306
|
+
// Existing spans do not affect the intrinsic card boxes because the grid
|
|
307
|
+
// aligns items to the start. Clearing them here would collapse the 1px row
|
|
308
|
+
// grid and clamp the user's scroll position before the new spans are applied.
|
|
309
309
|
const blockGap = Number.parseFloat(getComputedStyle(cards[0]).marginBottom);
|
|
310
310
|
const spans = cards.map((card) => (
|
|
311
311
|
Math.ceil((card.getBoundingClientRect().height + blockGap) / rowHeight)
|
|
@@ -835,7 +835,7 @@ body[data-surface="editor"] #app {
|
|
|
835
835
|
.modal-editor-fields input:focus-visible,
|
|
836
836
|
.modal-editor-fields textarea:focus-visible {
|
|
837
837
|
outline: none;
|
|
838
|
-
box-shadow:
|
|
838
|
+
box-shadow: none;
|
|
839
839
|
}
|
|
840
840
|
|
|
841
841
|
.modal-command:focus-visible {
|
package/package.json
CHANGED
|
@@ -51,12 +51,25 @@ function declaredSurfaceUrls(feature) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function requireDeclaredLoopbackSurface(feature, value) {
|
|
54
|
-
if (typeof value !== "string"
|
|
54
|
+
if (typeof value !== "string") {
|
|
55
55
|
throw Object.assign(new Error("Surface URL is not declared by this feature"), {
|
|
56
56
|
code: "SURFACE_URL_NOT_ALLOWED",
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
const url = new URL(value);
|
|
60
|
+
const matchesDeclaredDocument = Array.from(declaredSurfaceUrls(feature), (declared) => new URL(declared))
|
|
61
|
+
.some((declared) => (
|
|
62
|
+
declared.origin === url.origin
|
|
63
|
+
&& declared.username === url.username
|
|
64
|
+
&& declared.password === url.password
|
|
65
|
+
&& declared.pathname === url.pathname
|
|
66
|
+
&& declared.hash === url.hash
|
|
67
|
+
));
|
|
68
|
+
if (!matchesDeclaredDocument) {
|
|
69
|
+
throw Object.assign(new Error("Surface URL is not declared by this feature"), {
|
|
70
|
+
code: "SURFACE_URL_NOT_ALLOWED",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
60
73
|
if (url.protocol !== "http:" || !LOOPBACK_SURFACE_HOSTS.has(url.hostname)) {
|
|
61
74
|
throw Object.assign(new Error("Surface URL must use an exact loopback HTTP origin"), {
|
|
62
75
|
code: "SURFACE_URL_NOT_ALLOWED",
|
|
@@ -235,15 +248,12 @@ export function createInjectionSource(features, {
|
|
|
235
248
|
const pageSurfaces = new Map();
|
|
236
249
|
const pinnedSurfaces = new Map();
|
|
237
250
|
const surfaceRecords = new Map();
|
|
238
|
-
const openTabs = new Map();
|
|
239
251
|
const nativeDetailComponents = new Map();
|
|
240
252
|
const nativeDetailSurfaceKeys = new Map();
|
|
241
253
|
const nativeOpenTabSessions = new Set();
|
|
242
254
|
const summaryStates = new Map();
|
|
243
255
|
let activePageFeatureId = null;
|
|
244
256
|
let activePinnedFeatureId = null;
|
|
245
|
-
let activeTabKey = null;
|
|
246
|
-
let tabHost = null;
|
|
247
257
|
let ensureQueued = false;
|
|
248
258
|
let ensureFrame = null;
|
|
249
259
|
let ensureTimer = null;
|
|
@@ -2541,7 +2551,7 @@ export function createInjectionSource(features, {
|
|
|
2541
2551
|
|
|
2542
2552
|
closePromptPreview({ immediate: true });
|
|
2543
2553
|
closeModalSurface();
|
|
2544
|
-
const editorUrl = new URL(sourceRecord.
|
|
2554
|
+
const editorUrl = new URL(sourceRecord.surfaceUrl);
|
|
2545
2555
|
editorUrl.searchParams.set("surface", "editor");
|
|
2546
2556
|
editorUrl.searchParams.set("kind", kind);
|
|
2547
2557
|
if (typeof payload.id === "string" && payload.id) editorUrl.searchParams.set("id", payload.id);
|
|
@@ -2759,12 +2769,32 @@ export function createInjectionSource(features, {
|
|
|
2759
2769
|
return null;
|
|
2760
2770
|
}
|
|
2761
2771
|
|
|
2772
|
+
async function waitForCurrentTaskScope() {
|
|
2773
|
+
const deadline = performance.now() + 2_000;
|
|
2774
|
+
do {
|
|
2775
|
+
const scope = currentTaskScope();
|
|
2776
|
+
if (scope) return scope;
|
|
2777
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
2778
|
+
} while (performance.now() < deadline);
|
|
2779
|
+
return null;
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
async function waitForNativeTabModuleUrl() {
|
|
2783
|
+
const deadline = performance.now() + 2_000;
|
|
2784
|
+
do {
|
|
2785
|
+
const moduleUrl = nativeTabModuleUrl();
|
|
2786
|
+
if (moduleUrl) return moduleUrl;
|
|
2787
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
2788
|
+
} while (performance.now() < deadline);
|
|
2789
|
+
return null;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2762
2792
|
async function loadNativeTabCapability() {
|
|
2763
2793
|
if (nativeTabCapability) return nativeTabCapability;
|
|
2764
2794
|
if (nativeTabCapabilityPromise) return nativeTabCapabilityPromise;
|
|
2765
2795
|
nativeTabCapabilityPromise = (async () => {
|
|
2766
2796
|
try {
|
|
2767
|
-
const moduleUrl =
|
|
2797
|
+
const moduleUrl = await waitForNativeTabModuleUrl();
|
|
2768
2798
|
if (!moduleUrl) throw new Error("Codex app-initial modulepreload was not found");
|
|
2769
2799
|
const appModule = await import(moduleUrl);
|
|
2770
2800
|
if (typeof appModule.Gtt !== "function") {
|
|
@@ -2797,7 +2827,9 @@ export function createInjectionSource(features, {
|
|
|
2797
2827
|
return null;
|
|
2798
2828
|
}
|
|
2799
2829
|
})();
|
|
2800
|
-
|
|
2830
|
+
const capability = await nativeTabCapabilityPromise;
|
|
2831
|
+
if (!capability) nativeTabCapabilityPromise = null;
|
|
2832
|
+
return capability;
|
|
2801
2833
|
}
|
|
2802
2834
|
|
|
2803
2835
|
function nativeDetailIcon(feature, detail, jsx) {
|
|
@@ -2894,7 +2926,7 @@ export function createInjectionSource(features, {
|
|
|
2894
2926
|
async function openNativeDetailTab(feature, detail) {
|
|
2895
2927
|
const capability = await loadNativeTabCapability();
|
|
2896
2928
|
if (!capability) return null;
|
|
2897
|
-
const scope =
|
|
2929
|
+
const scope = await waitForCurrentTaskScope();
|
|
2898
2930
|
if (!scope) {
|
|
2899
2931
|
nativeTabCapabilityError = new Error("The current Codex Task scope was not found");
|
|
2900
2932
|
return null;
|
|
@@ -2936,14 +2968,12 @@ export function createInjectionSource(features, {
|
|
|
2936
2968
|
|
|
2937
2969
|
nativeTabCapabilityError = null;
|
|
2938
2970
|
if (focusedExisting) reloadNativeDetailIfUnready(feature, detail);
|
|
2939
|
-
const fallbackKey = `${feature.id}:${detail.id}`;
|
|
2940
|
-
if (openTabs.has(fallbackKey)) closeDetailTab(fallbackKey);
|
|
2941
2971
|
return { tabId, focusedExisting, presentation: "native" };
|
|
2942
2972
|
}
|
|
2943
2973
|
|
|
2944
2974
|
function detailTabCapability() {
|
|
2945
2975
|
return {
|
|
2946
|
-
presentation: nativeTabCapability ? "native" : "
|
|
2976
|
+
presentation: nativeTabCapability ? "native" : "unavailable",
|
|
2947
2977
|
moduleAsset: nativeTabCapability?.moduleAsset ?? null,
|
|
2948
2978
|
error: nativeTabCapabilityError?.message ?? null,
|
|
2949
2979
|
openNativeTabs: nativeOpenTabSessions.size,
|
|
@@ -2961,185 +2991,14 @@ export function createInjectionSource(features, {
|
|
|
2961
2991
|
nativeDetailSurfaceKeys.clear();
|
|
2962
2992
|
}
|
|
2963
2993
|
|
|
2964
|
-
function updateTabHostGeometry() {
|
|
2965
|
-
if (!tabHost?.isConnected) return;
|
|
2966
|
-
const width = Math.min(620, Math.max(360, innerWidth * 0.44));
|
|
2967
|
-
tabHost.style.width = `${Math.min(width, Math.max(300, innerWidth - 72))}px`;
|
|
2968
|
-
}
|
|
2969
|
-
|
|
2970
|
-
function createTabHost() {
|
|
2971
|
-
const host = document.createElement("aside");
|
|
2972
|
-
host.setAttribute("data-codex-personal-tab-host", "right");
|
|
2973
|
-
host.setAttribute("aria-label", locale === "zh-CN" ? "CodexNotes 工作区标签页" : "CodexNotes workspace tabs");
|
|
2974
|
-
host.style.cssText = [
|
|
2975
|
-
"position:fixed",
|
|
2976
|
-
"top:46px",
|
|
2977
|
-
"bottom:0",
|
|
2978
|
-
"right:0",
|
|
2979
|
-
"z-index:42",
|
|
2980
|
-
"display:flex",
|
|
2981
|
-
"flex-direction:column",
|
|
2982
|
-
"min-width:300px",
|
|
2983
|
-
"background:var(--color-token-main-surface-primary)",
|
|
2984
|
-
"border-left:0.5px solid var(--color-border)",
|
|
2985
|
-
"box-shadow:-8px 0 16px -12px rgba(0,0,0,.24)",
|
|
2986
|
-
].join(";");
|
|
2987
|
-
const header = document.createElement("div");
|
|
2988
|
-
header.style.cssText = [
|
|
2989
|
-
"height:46px",
|
|
2990
|
-
"display:flex",
|
|
2991
|
-
"align-items:center",
|
|
2992
|
-
"padding:0 8px",
|
|
2993
|
-
"flex:0 0 auto",
|
|
2994
|
-
"background:var(--color-token-main-surface-primary)",
|
|
2995
|
-
].join(";");
|
|
2996
|
-
const strip = document.createElement("div");
|
|
2997
|
-
strip.setAttribute("data-app-shell-tab-strip-controller", "right");
|
|
2998
|
-
strip.setAttribute("data-codex-personal-tab-strip", "true");
|
|
2999
|
-
strip.setAttribute("role", "tablist");
|
|
3000
|
-
strip.style.cssText = "display:flex;align-items:center;gap:4px;min-width:0;flex:1;overflow-x:auto;height:100%";
|
|
3001
|
-
header.append(strip);
|
|
3002
|
-
const panels = document.createElement("div");
|
|
3003
|
-
panels.setAttribute("data-codex-personal-tab-panels", "true");
|
|
3004
|
-
panels.style.cssText = "position:relative;min-height:0;flex:1;background:var(--color-token-main-surface-primary)";
|
|
3005
|
-
host.append(header, panels);
|
|
3006
|
-
document.body.append(host);
|
|
3007
|
-
tabHost = host;
|
|
3008
|
-
updateTabHostGeometry();
|
|
3009
|
-
return host;
|
|
3010
|
-
}
|
|
3011
|
-
|
|
3012
|
-
function activateTab(key) {
|
|
3013
|
-
const record = openTabs.get(key);
|
|
3014
|
-
if (!record) return;
|
|
3015
|
-
activeTabKey = key;
|
|
3016
|
-
for (const [candidateKey, candidate] of openTabs) {
|
|
3017
|
-
const active = candidateKey === key;
|
|
3018
|
-
candidate.tabButton.setAttribute("aria-selected", String(active));
|
|
3019
|
-
candidate.tab.style.setProperty(
|
|
3020
|
-
"--app-shell-tab-background",
|
|
3021
|
-
active
|
|
3022
|
-
? "color-mix(in srgb, var(--color-text-foreground) 5%, var(--color-token-main-surface-primary))"
|
|
3023
|
-
: "transparent",
|
|
3024
|
-
);
|
|
3025
|
-
candidate.panel.hidden = !active;
|
|
3026
|
-
}
|
|
3027
|
-
record.tabButton.focus({ preventScroll: true });
|
|
3028
|
-
queueTheme();
|
|
3029
|
-
}
|
|
3030
|
-
|
|
3031
|
-
function closeDetailTab(key) {
|
|
3032
|
-
const record = openTabs.get(key);
|
|
3033
|
-
if (!record) return;
|
|
3034
|
-
const keys = Array.from(openTabs.keys());
|
|
3035
|
-
const index = keys.indexOf(key);
|
|
3036
|
-
record.tab.remove();
|
|
3037
|
-
record.panel.remove();
|
|
3038
|
-
removeSurfaceRecord(record.surfaceRecordKey);
|
|
3039
|
-
openTabs.delete(key);
|
|
3040
|
-
if (openTabs.size === 0) {
|
|
3041
|
-
tabHost?.remove();
|
|
3042
|
-
tabHost = null;
|
|
3043
|
-
activeTabKey = null;
|
|
3044
|
-
updateResponsiveSummaryPresentation();
|
|
3045
|
-
return;
|
|
3046
|
-
}
|
|
3047
|
-
if (activeTabKey === key) {
|
|
3048
|
-
const remainingKeys = Array.from(openTabs.keys());
|
|
3049
|
-
activateTab(remainingKeys[Math.min(index, remainingKeys.length - 1)]);
|
|
3050
|
-
}
|
|
3051
|
-
updateResponsiveSummaryPresentation();
|
|
3052
|
-
}
|
|
3053
|
-
|
|
3054
|
-
function createDetailTab(feature, detail) {
|
|
3055
|
-
const host = tabHost?.isConnected ? tabHost : createTabHost();
|
|
3056
|
-
const strip = host.querySelector("[data-codex-personal-tab-strip]");
|
|
3057
|
-
const panels = host.querySelector("[data-codex-personal-tab-panels]");
|
|
3058
|
-
const key = `${feature.id}:${detail.id}`;
|
|
3059
|
-
const stableId = `${feature.id}-${detail.id}`;
|
|
3060
|
-
|
|
3061
|
-
const tab = document.createElement("div");
|
|
3062
|
-
tab.setAttribute("data-app-shell-tab-controller", "right");
|
|
3063
|
-
tab.setAttribute("data-tab-id", stableId);
|
|
3064
|
-
tab.style.cssText = [
|
|
3065
|
-
"position:relative",
|
|
3066
|
-
"display:flex",
|
|
3067
|
-
"align-items:center",
|
|
3068
|
-
"min-width:90px",
|
|
3069
|
-
"max-width:160px",
|
|
3070
|
-
"height:28px",
|
|
3071
|
-
"padding:0 4px 0 8px",
|
|
3072
|
-
"border-radius:8px",
|
|
3073
|
-
"background:var(--app-shell-tab-background,transparent)",
|
|
3074
|
-
"flex:1 0 110px",
|
|
3075
|
-
].join(";");
|
|
3076
|
-
const tabButton = document.createElement("button");
|
|
3077
|
-
tabButton.type = "button";
|
|
3078
|
-
tabButton.setAttribute("role", "tab");
|
|
3079
|
-
tabButton.setAttribute("aria-selected", "false");
|
|
3080
|
-
tabButton.style.cssText = "display:flex;align-items:center;gap:7px;min-width:0;flex:1;height:100%;padding:0;background:transparent;border:0;color:var(--color-text-foreground);cursor:pointer";
|
|
3081
|
-
const icon = createMarkupIcon(detail.icon ?? feature.icon, "icon-xs", 16);
|
|
3082
|
-
if (icon) tabButton.append(icon);
|
|
3083
|
-
const label = document.createElement("span");
|
|
3084
|
-
label.textContent = detail.label;
|
|
3085
|
-
label.style.cssText = "min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
3086
|
-
tabButton.append(label);
|
|
3087
|
-
tabButton.addEventListener("click", () => activateTab(key));
|
|
3088
|
-
const close = document.createElement("button");
|
|
3089
|
-
close.type = "button";
|
|
3090
|
-
close.textContent = "×";
|
|
3091
|
-
close.setAttribute("data-app-shell-tab-close-button", "true");
|
|
3092
|
-
close.setAttribute(
|
|
3093
|
-
"aria-label",
|
|
3094
|
-
locale === "zh-CN" ? `关闭${detail.label}标签页` : `Close ${detail.label} tab`,
|
|
3095
|
-
);
|
|
3096
|
-
close.style.cssText = "width:20px;height:20px;border:0;border-radius:6px;padding:0;background:transparent;color:var(--color-text-foreground-tertiary);font-size:18px;line-height:18px;cursor:pointer";
|
|
3097
|
-
close.addEventListener("click", (event) => {
|
|
3098
|
-
event.stopPropagation();
|
|
3099
|
-
closeDetailTab(key);
|
|
3100
|
-
});
|
|
3101
|
-
tab.append(tabButton, close);
|
|
3102
|
-
|
|
3103
|
-
const panel = document.createElement("div");
|
|
3104
|
-
panel.setAttribute("role", "tabpanel");
|
|
3105
|
-
panel.setAttribute("aria-label", detail.label);
|
|
3106
|
-
panel.setAttribute("data-app-shell-tab-panel-controller", "right");
|
|
3107
|
-
panel.setAttribute("data-tab-id", stableId);
|
|
3108
|
-
panel.style.cssText = "position:absolute;inset:0;min-height:0;background:var(--color-token-main-surface-primary)";
|
|
3109
|
-
const frame = createFrame(feature.id, detail.label);
|
|
3110
|
-
panel.append(frame);
|
|
3111
|
-
strip.append(tab);
|
|
3112
|
-
panels.append(panel);
|
|
3113
|
-
const recordKey = surfaceKey(feature.id, "detail", detail.id);
|
|
3114
|
-
registerSurface(recordKey, feature, "detail", detail.surfaceUrl, panel, frame, detail.id);
|
|
3115
|
-
const record = { key, feature, detail, tab, tabButton, close, panel, frame, surfaceRecordKey: recordKey };
|
|
3116
|
-
openTabs.set(key, record);
|
|
3117
|
-
return record;
|
|
3118
|
-
}
|
|
3119
|
-
|
|
3120
|
-
function openFallbackDetailTab(feature, detail) {
|
|
3121
|
-
const key = `${feature.id}:${detail.id}`;
|
|
3122
|
-
const existing = openTabs.has(key);
|
|
3123
|
-
if (!existing) createDetailTab(feature, detail);
|
|
3124
|
-
else reloadSurfaceIfUnready(
|
|
3125
|
-
surfaceKey(feature.id, "detail", detail.id),
|
|
3126
|
-
detail.surfaceUrl,
|
|
3127
|
-
);
|
|
3128
|
-
activateTab(key);
|
|
3129
|
-
updateResponsiveSummaryPresentation();
|
|
3130
|
-
return {
|
|
3131
|
-
tabId: `${feature.id}-${detail.id}`,
|
|
3132
|
-
focusedExisting: existing,
|
|
3133
|
-
presentation: "fallback",
|
|
3134
|
-
};
|
|
3135
|
-
}
|
|
3136
|
-
|
|
3137
2994
|
async function openDetailTab(featureId, detailId) {
|
|
3138
2995
|
const feature = featureById.get(featureId);
|
|
3139
2996
|
const detail = feature?.detailTabs?.find((candidate) => candidate.id === detailId);
|
|
3140
2997
|
if (!feature || !detail) throw new Error("The requested detail Tab is not registered");
|
|
3141
|
-
|
|
3142
|
-
|
|
2998
|
+
const result = await openNativeDetailTab(feature, detail);
|
|
2999
|
+
if (!result) throw nativeTabCapabilityError
|
|
3000
|
+
?? new Error("Codex native right-panel tabs are unavailable");
|
|
3001
|
+
return result;
|
|
3143
3002
|
}
|
|
3144
3003
|
|
|
3145
3004
|
function openThread(threadId) {
|
|
@@ -3295,7 +3154,6 @@ export function createInjectionSource(features, {
|
|
|
3295
3154
|
checkThreadChange();
|
|
3296
3155
|
updateSidebarSelectedState();
|
|
3297
3156
|
updatePageSurfacePositions();
|
|
3298
|
-
updateTabHostGeometry();
|
|
3299
3157
|
ensureMainContentObserver();
|
|
3300
3158
|
updateResponsiveSummaryPresentation();
|
|
3301
3159
|
const nativeToggle = nativeSummaryButton();
|
|
@@ -3436,8 +3294,7 @@ export function createInjectionSource(features, {
|
|
|
3436
3294
|
const ownEntry = event.target.closest?.(`[${entryMarker}="${activePinnedFeatureId}"]`);
|
|
3437
3295
|
const rightWorkspaceInteraction = event.target.closest?.(
|
|
3438
3296
|
'[data-app-shell-tab-strip-controller="right"],'
|
|
3439
|
-
|
|
3440
|
-
+ '[data-codex-personal-tab-host="right"]',
|
|
3297
|
+
+ '[data-app-shell-tab-panel-controller="right"]',
|
|
3441
3298
|
);
|
|
3442
3299
|
const promptPreviewInteraction = event.target.closest?.(`[${promptPreviewMarker}]`);
|
|
3443
3300
|
if (
|
|
@@ -3525,7 +3382,6 @@ export function createInjectionSource(features, {
|
|
|
3525
3382
|
window.addEventListener("resize", () => {
|
|
3526
3383
|
closePromptPreview({ immediate: true });
|
|
3527
3384
|
updatePageSurfacePositions();
|
|
3528
|
-
updateTabHostGeometry();
|
|
3529
3385
|
updateResponsiveSummaryPresentation();
|
|
3530
3386
|
}, { signal: lifetime.signal });
|
|
3531
3387
|
const ensureObserver = new MutationObserver(queueEnsure);
|
|
@@ -3581,9 +3437,7 @@ export function createInjectionSource(features, {
|
|
|
3581
3437
|
closeModalSurface();
|
|
3582
3438
|
closeNativeDetailTabs();
|
|
3583
3439
|
restoreModelSelectorEnhancements();
|
|
3584
|
-
tabHost?.remove();
|
|
3585
3440
|
surfaceRecords.clear();
|
|
3586
|
-
openTabs.clear();
|
|
3587
3441
|
if (window.__codexPersonalRuntime === runtimeApi) delete window.__codexPersonalRuntime;
|
|
3588
3442
|
},
|
|
3589
3443
|
};
|