minecodex 0.1.7 → 0.1.9

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "images",
4
- "version": "0.1.7",
4
+ "version": "0.1.9",
5
5
  "label": {
6
6
  "en": "Images",
7
7
  "zh-CN": "图片"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "model-slider",
4
- "version": "0.1.7",
4
+ "version": "0.1.9",
5
5
  "label": {
6
6
  "en": "Model Slider",
7
7
  "zh-CN": "模型滑条"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "notes",
4
- "version": "0.1.7",
4
+ "version": "0.1.9",
5
5
  "label": {
6
6
  "en": "Notes",
7
7
  "zh-CN": "笔记"
@@ -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: inset 0 0 0 2px var(--notes-focus);
838
+ box-shadow: none;
839
839
  }
840
840
 
841
841
  .modal-command:focus-visible {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,6 +11,7 @@ const CODEX_APP_ORIGIN = "app://-";
11
11
  const SURFACE_LOAD_ACTION = "load-surface";
12
12
  const SURFACE_FRAME_PREFIX = "minecodex-surface-";
13
13
  const LOOPBACK_SURFACE_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
14
+ const RIGHT_PANEL_ROUTE_KINDS = Object.freeze(["home", "local-thread"]);
14
15
 
15
16
  export const RESPONSIVE_SUMMARY_LAYOUT = Object.freeze({
16
17
  contentBaseWidth: 736,
@@ -112,6 +113,7 @@ export function createInjectionSource(features, {
112
113
  currentRuntime?.dispose?.();
113
114
 
114
115
  const lifetime = new AbortController();
116
+ const rightPanelRouteKinds = new Set(config.rightPanelRouteKinds);
115
117
 
116
118
  const entryMarker = "data-codex-personal-feature";
117
119
  const pageSurfaceMarker = "data-codex-personal-surface";
@@ -248,15 +250,12 @@ export function createInjectionSource(features, {
248
250
  const pageSurfaces = new Map();
249
251
  const pinnedSurfaces = new Map();
250
252
  const surfaceRecords = new Map();
251
- const openTabs = new Map();
252
253
  const nativeDetailComponents = new Map();
253
254
  const nativeDetailSurfaceKeys = new Map();
254
255
  const nativeOpenTabSessions = new Set();
255
256
  const summaryStates = new Map();
256
257
  let activePageFeatureId = null;
257
258
  let activePinnedFeatureId = null;
258
- let activeTabKey = null;
259
- let tabHost = null;
260
259
  let ensureQueued = false;
261
260
  let ensureFrame = null;
262
261
  let ensureTimer = null;
@@ -2704,7 +2703,7 @@ export function createInjectionSource(features, {
2704
2703
  return key ? element[key] : null;
2705
2704
  }
2706
2705
 
2707
- function currentTaskScope() {
2706
+ function currentRightPanelScope() {
2708
2707
  let anchor = document.querySelector('[data-app-shell-tabs="true"]');
2709
2708
  let anchorFiber = reactFiberFor(anchor);
2710
2709
  if (!anchorFiber) {
@@ -2721,12 +2720,12 @@ export function createInjectionSource(features, {
2721
2720
  let rootFiber = anchorFiber;
2722
2721
  while (rootFiber.return) rootFiber = rootFiber.return;
2723
2722
 
2724
- const isTaskScope = (value) => (
2723
+ const isRightPanelScope = (value) => (
2725
2724
  value
2726
2725
  && typeof value === "object"
2727
2726
  && typeof value.get === "function"
2728
2727
  && typeof value.set === "function"
2729
- && value.value?.routeKind === "local-thread"
2728
+ && rightPanelRouteKinds.has(value.value?.routeKind)
2730
2729
  && typeof value.query?.getOrFetch === "function"
2731
2730
  );
2732
2731
  const inspected = new Set();
@@ -2737,8 +2736,8 @@ export function createInjectionSource(features, {
2737
2736
  || inspected.has(value)
2738
2737
  ) return null;
2739
2738
  inspected.add(value);
2740
- if (isTaskScope(value)) return value;
2741
- if (isTaskScope(value.current)) return value.current;
2739
+ if (isRightPanelScope(value)) return value;
2740
+ if (isRightPanelScope(value.current)) return value.current;
2742
2741
  return null;
2743
2742
  };
2744
2743
 
@@ -2772,12 +2771,32 @@ export function createInjectionSource(features, {
2772
2771
  return null;
2773
2772
  }
2774
2773
 
2774
+ async function waitForCurrentRightPanelScope() {
2775
+ const deadline = performance.now() + 2_000;
2776
+ do {
2777
+ const scope = currentRightPanelScope();
2778
+ if (scope) return scope;
2779
+ await new Promise((resolve) => setTimeout(resolve, 50));
2780
+ } while (performance.now() < deadline);
2781
+ return null;
2782
+ }
2783
+
2784
+ async function waitForNativeTabModuleUrl() {
2785
+ const deadline = performance.now() + 2_000;
2786
+ do {
2787
+ const moduleUrl = nativeTabModuleUrl();
2788
+ if (moduleUrl) return moduleUrl;
2789
+ await new Promise((resolve) => setTimeout(resolve, 50));
2790
+ } while (performance.now() < deadline);
2791
+ return null;
2792
+ }
2793
+
2775
2794
  async function loadNativeTabCapability() {
2776
2795
  if (nativeTabCapability) return nativeTabCapability;
2777
2796
  if (nativeTabCapabilityPromise) return nativeTabCapabilityPromise;
2778
2797
  nativeTabCapabilityPromise = (async () => {
2779
2798
  try {
2780
- const moduleUrl = nativeTabModuleUrl();
2799
+ const moduleUrl = await waitForNativeTabModuleUrl();
2781
2800
  if (!moduleUrl) throw new Error("Codex app-initial modulepreload was not found");
2782
2801
  const appModule = await import(moduleUrl);
2783
2802
  if (typeof appModule.Gtt !== "function") {
@@ -2793,6 +2812,7 @@ export function createInjectionSource(features, {
2793
2812
  typeof controller?.openTab !== "function"
2794
2813
  || typeof controller?.activateTab !== "function"
2795
2814
  || typeof controller?.closeTab !== "function"
2815
+ || !controller?.tabById$
2796
2816
  || typeof jsx?.jsx !== "function"
2797
2817
  || typeof React?.useLayoutEffect !== "function"
2798
2818
  || typeof React?.useRef !== "function"
@@ -2810,7 +2830,9 @@ export function createInjectionSource(features, {
2810
2830
  return null;
2811
2831
  }
2812
2832
  })();
2813
- return nativeTabCapabilityPromise;
2833
+ const capability = await nativeTabCapabilityPromise;
2834
+ if (!capability) nativeTabCapabilityPromise = null;
2835
+ return capability;
2814
2836
  }
2815
2837
 
2816
2838
  function nativeDetailIcon(feature, detail, jsx) {
@@ -2904,17 +2926,31 @@ export function createInjectionSource(features, {
2904
2926
  return reloaded;
2905
2927
  }
2906
2928
 
2929
+ async function waitForNativeDetailTabMount(scope, controller, tabId, detailKey) {
2930
+ const deadline = performance.now() + 2_000;
2931
+ do {
2932
+ let registered = false;
2933
+ try {
2934
+ registered = scope.get(controller.tabById$, tabId) != null;
2935
+ } catch {}
2936
+ if (registered && nativeDetailSurfaceKeys.has(detailKey)) return true;
2937
+ await new Promise((resolve) => setTimeout(resolve, 25));
2938
+ } while (performance.now() < deadline);
2939
+ return false;
2940
+ }
2941
+
2907
2942
  async function openNativeDetailTab(feature, detail) {
2908
2943
  const capability = await loadNativeTabCapability();
2909
2944
  if (!capability) return null;
2910
- const scope = currentTaskScope();
2945
+ const scope = await waitForCurrentRightPanelScope();
2911
2946
  if (!scope) {
2912
- nativeTabCapabilityError = new Error("The current Codex Task scope was not found");
2947
+ nativeTabCapabilityError = new Error("The current Codex right-panel scope was not found");
2913
2948
  return null;
2914
2949
  }
2915
2950
 
2916
2951
  const { controller, jsx } = capability;
2917
2952
  const tabId = `${feature.id}-${detail.id}`;
2953
+ const detailKey = `${feature.id}:${detail.id}`;
2918
2954
  let session = Array.from(nativeOpenTabSessions).find((candidate) => (
2919
2955
  candidate.scope === scope && candidate.tabId === tabId
2920
2956
  ));
@@ -2947,16 +2983,25 @@ export function createInjectionSource(features, {
2947
2983
  return null;
2948
2984
  }
2949
2985
 
2986
+ if (!await waitForNativeDetailTabMount(scope, controller, tabId, detailKey)) {
2987
+ if (isNewSession) nativeOpenTabSessions.delete(session);
2988
+ if (!focusedExisting) {
2989
+ try {
2990
+ controller.closeTab(scope, tabId);
2991
+ } catch {}
2992
+ }
2993
+ nativeTabCapabilityError = new Error("Codex native right-panel Tab did not mount");
2994
+ return null;
2995
+ }
2996
+
2950
2997
  nativeTabCapabilityError = null;
2951
2998
  if (focusedExisting) reloadNativeDetailIfUnready(feature, detail);
2952
- const fallbackKey = `${feature.id}:${detail.id}`;
2953
- if (openTabs.has(fallbackKey)) closeDetailTab(fallbackKey);
2954
2999
  return { tabId, focusedExisting, presentation: "native" };
2955
3000
  }
2956
3001
 
2957
3002
  function detailTabCapability() {
2958
3003
  return {
2959
- presentation: nativeTabCapability ? "native" : "fallback",
3004
+ presentation: nativeTabCapability ? "native" : "unavailable",
2960
3005
  moduleAsset: nativeTabCapability?.moduleAsset ?? null,
2961
3006
  error: nativeTabCapabilityError?.message ?? null,
2962
3007
  openNativeTabs: nativeOpenTabSessions.size,
@@ -2974,185 +3019,14 @@ export function createInjectionSource(features, {
2974
3019
  nativeDetailSurfaceKeys.clear();
2975
3020
  }
2976
3021
 
2977
- function updateTabHostGeometry() {
2978
- if (!tabHost?.isConnected) return;
2979
- const width = Math.min(620, Math.max(360, innerWidth * 0.44));
2980
- tabHost.style.width = `${Math.min(width, Math.max(300, innerWidth - 72))}px`;
2981
- }
2982
-
2983
- function createTabHost() {
2984
- const host = document.createElement("aside");
2985
- host.setAttribute("data-codex-personal-tab-host", "right");
2986
- host.setAttribute("aria-label", locale === "zh-CN" ? "CodexNotes 工作区标签页" : "CodexNotes workspace tabs");
2987
- host.style.cssText = [
2988
- "position:fixed",
2989
- "top:46px",
2990
- "bottom:0",
2991
- "right:0",
2992
- "z-index:42",
2993
- "display:flex",
2994
- "flex-direction:column",
2995
- "min-width:300px",
2996
- "background:var(--color-token-main-surface-primary)",
2997
- "border-left:0.5px solid var(--color-border)",
2998
- "box-shadow:-8px 0 16px -12px rgba(0,0,0,.24)",
2999
- ].join(";");
3000
- const header = document.createElement("div");
3001
- header.style.cssText = [
3002
- "height:46px",
3003
- "display:flex",
3004
- "align-items:center",
3005
- "padding:0 8px",
3006
- "flex:0 0 auto",
3007
- "background:var(--color-token-main-surface-primary)",
3008
- ].join(";");
3009
- const strip = document.createElement("div");
3010
- strip.setAttribute("data-app-shell-tab-strip-controller", "right");
3011
- strip.setAttribute("data-codex-personal-tab-strip", "true");
3012
- strip.setAttribute("role", "tablist");
3013
- strip.style.cssText = "display:flex;align-items:center;gap:4px;min-width:0;flex:1;overflow-x:auto;height:100%";
3014
- header.append(strip);
3015
- const panels = document.createElement("div");
3016
- panels.setAttribute("data-codex-personal-tab-panels", "true");
3017
- panels.style.cssText = "position:relative;min-height:0;flex:1;background:var(--color-token-main-surface-primary)";
3018
- host.append(header, panels);
3019
- document.body.append(host);
3020
- tabHost = host;
3021
- updateTabHostGeometry();
3022
- return host;
3023
- }
3024
-
3025
- function activateTab(key) {
3026
- const record = openTabs.get(key);
3027
- if (!record) return;
3028
- activeTabKey = key;
3029
- for (const [candidateKey, candidate] of openTabs) {
3030
- const active = candidateKey === key;
3031
- candidate.tabButton.setAttribute("aria-selected", String(active));
3032
- candidate.tab.style.setProperty(
3033
- "--app-shell-tab-background",
3034
- active
3035
- ? "color-mix(in srgb, var(--color-text-foreground) 5%, var(--color-token-main-surface-primary))"
3036
- : "transparent",
3037
- );
3038
- candidate.panel.hidden = !active;
3039
- }
3040
- record.tabButton.focus({ preventScroll: true });
3041
- queueTheme();
3042
- }
3043
-
3044
- function closeDetailTab(key) {
3045
- const record = openTabs.get(key);
3046
- if (!record) return;
3047
- const keys = Array.from(openTabs.keys());
3048
- const index = keys.indexOf(key);
3049
- record.tab.remove();
3050
- record.panel.remove();
3051
- removeSurfaceRecord(record.surfaceRecordKey);
3052
- openTabs.delete(key);
3053
- if (openTabs.size === 0) {
3054
- tabHost?.remove();
3055
- tabHost = null;
3056
- activeTabKey = null;
3057
- updateResponsiveSummaryPresentation();
3058
- return;
3059
- }
3060
- if (activeTabKey === key) {
3061
- const remainingKeys = Array.from(openTabs.keys());
3062
- activateTab(remainingKeys[Math.min(index, remainingKeys.length - 1)]);
3063
- }
3064
- updateResponsiveSummaryPresentation();
3065
- }
3066
-
3067
- function createDetailTab(feature, detail) {
3068
- const host = tabHost?.isConnected ? tabHost : createTabHost();
3069
- const strip = host.querySelector("[data-codex-personal-tab-strip]");
3070
- const panels = host.querySelector("[data-codex-personal-tab-panels]");
3071
- const key = `${feature.id}:${detail.id}`;
3072
- const stableId = `${feature.id}-${detail.id}`;
3073
-
3074
- const tab = document.createElement("div");
3075
- tab.setAttribute("data-app-shell-tab-controller", "right");
3076
- tab.setAttribute("data-tab-id", stableId);
3077
- tab.style.cssText = [
3078
- "position:relative",
3079
- "display:flex",
3080
- "align-items:center",
3081
- "min-width:90px",
3082
- "max-width:160px",
3083
- "height:28px",
3084
- "padding:0 4px 0 8px",
3085
- "border-radius:8px",
3086
- "background:var(--app-shell-tab-background,transparent)",
3087
- "flex:1 0 110px",
3088
- ].join(";");
3089
- const tabButton = document.createElement("button");
3090
- tabButton.type = "button";
3091
- tabButton.setAttribute("role", "tab");
3092
- tabButton.setAttribute("aria-selected", "false");
3093
- 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";
3094
- const icon = createMarkupIcon(detail.icon ?? feature.icon, "icon-xs", 16);
3095
- if (icon) tabButton.append(icon);
3096
- const label = document.createElement("span");
3097
- label.textContent = detail.label;
3098
- label.style.cssText = "min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
3099
- tabButton.append(label);
3100
- tabButton.addEventListener("click", () => activateTab(key));
3101
- const close = document.createElement("button");
3102
- close.type = "button";
3103
- close.textContent = "×";
3104
- close.setAttribute("data-app-shell-tab-close-button", "true");
3105
- close.setAttribute(
3106
- "aria-label",
3107
- locale === "zh-CN" ? `关闭${detail.label}标签页` : `Close ${detail.label} tab`,
3108
- );
3109
- 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";
3110
- close.addEventListener("click", (event) => {
3111
- event.stopPropagation();
3112
- closeDetailTab(key);
3113
- });
3114
- tab.append(tabButton, close);
3115
-
3116
- const panel = document.createElement("div");
3117
- panel.setAttribute("role", "tabpanel");
3118
- panel.setAttribute("aria-label", detail.label);
3119
- panel.setAttribute("data-app-shell-tab-panel-controller", "right");
3120
- panel.setAttribute("data-tab-id", stableId);
3121
- panel.style.cssText = "position:absolute;inset:0;min-height:0;background:var(--color-token-main-surface-primary)";
3122
- const frame = createFrame(feature.id, detail.label);
3123
- panel.append(frame);
3124
- strip.append(tab);
3125
- panels.append(panel);
3126
- const recordKey = surfaceKey(feature.id, "detail", detail.id);
3127
- registerSurface(recordKey, feature, "detail", detail.surfaceUrl, panel, frame, detail.id);
3128
- const record = { key, feature, detail, tab, tabButton, close, panel, frame, surfaceRecordKey: recordKey };
3129
- openTabs.set(key, record);
3130
- return record;
3131
- }
3132
-
3133
- function openFallbackDetailTab(feature, detail) {
3134
- const key = `${feature.id}:${detail.id}`;
3135
- const existing = openTabs.has(key);
3136
- if (!existing) createDetailTab(feature, detail);
3137
- else reloadSurfaceIfUnready(
3138
- surfaceKey(feature.id, "detail", detail.id),
3139
- detail.surfaceUrl,
3140
- );
3141
- activateTab(key);
3142
- updateResponsiveSummaryPresentation();
3143
- return {
3144
- tabId: `${feature.id}-${detail.id}`,
3145
- focusedExisting: existing,
3146
- presentation: "fallback",
3147
- };
3148
- }
3149
-
3150
3022
  async function openDetailTab(featureId, detailId) {
3151
3023
  const feature = featureById.get(featureId);
3152
3024
  const detail = feature?.detailTabs?.find((candidate) => candidate.id === detailId);
3153
3025
  if (!feature || !detail) throw new Error("The requested detail Tab is not registered");
3154
- return await openNativeDetailTab(feature, detail)
3155
- ?? openFallbackDetailTab(feature, detail);
3026
+ const result = await openNativeDetailTab(feature, detail);
3027
+ if (!result) throw nativeTabCapabilityError
3028
+ ?? new Error("Codex native right-panel tabs are unavailable");
3029
+ return result;
3156
3030
  }
3157
3031
 
3158
3032
  function openThread(threadId) {
@@ -3308,7 +3182,6 @@ export function createInjectionSource(features, {
3308
3182
  checkThreadChange();
3309
3183
  updateSidebarSelectedState();
3310
3184
  updatePageSurfacePositions();
3311
- updateTabHostGeometry();
3312
3185
  ensureMainContentObserver();
3313
3186
  updateResponsiveSummaryPresentation();
3314
3187
  const nativeToggle = nativeSummaryButton();
@@ -3449,8 +3322,7 @@ export function createInjectionSource(features, {
3449
3322
  const ownEntry = event.target.closest?.(`[${entryMarker}="${activePinnedFeatureId}"]`);
3450
3323
  const rightWorkspaceInteraction = event.target.closest?.(
3451
3324
  '[data-app-shell-tab-strip-controller="right"],'
3452
- + '[data-app-shell-tab-panel-controller="right"],'
3453
- + '[data-codex-personal-tab-host="right"]',
3325
+ + '[data-app-shell-tab-panel-controller="right"]',
3454
3326
  );
3455
3327
  const promptPreviewInteraction = event.target.closest?.(`[${promptPreviewMarker}]`);
3456
3328
  if (
@@ -3538,7 +3410,6 @@ export function createInjectionSource(features, {
3538
3410
  window.addEventListener("resize", () => {
3539
3411
  closePromptPreview({ immediate: true });
3540
3412
  updatePageSurfacePositions();
3541
- updateTabHostGeometry();
3542
3413
  updateResponsiveSummaryPresentation();
3543
3414
  }, { signal: lifetime.signal });
3544
3415
  const ensureObserver = new MutationObserver(queueEnsure);
@@ -3594,9 +3465,7 @@ export function createInjectionSource(features, {
3594
3465
  closeModalSurface();
3595
3466
  closeNativeDetailTabs();
3596
3467
  restoreModelSelectorEnhancements();
3597
- tabHost?.remove();
3598
3468
  surfaceRecords.clear();
3599
- openTabs.clear();
3600
3469
  if (window.__codexPersonalRuntime === runtimeApi) delete window.__codexPersonalRuntime;
3601
3470
  },
3602
3471
  };
@@ -3625,6 +3494,7 @@ export function createInjectionSource(features, {
3625
3494
  bindingName,
3626
3495
  bindingToken,
3627
3496
  summaryLayout: RESPONSIVE_SUMMARY_LAYOUT,
3497
+ rightPanelRouteKinds: RIGHT_PANEL_ROUTE_KINDS,
3628
3498
  features: runtimeFeatures,
3629
3499
  })})`;
3630
3500
  }