minecodex 0.1.13 → 0.1.15

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.
@@ -18,6 +18,7 @@
18
18
  "favoriteStorageKey": "codex-model-slider:favorites:v1",
19
19
  "providerAliases": {
20
20
  "opencode-go": "OpenCode Go",
21
+ "packyapi": "PackyAPI",
21
22
  "xai": "xAI",
22
23
  "zhipu": "Zhipu AI",
23
24
  "google": "Google",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -852,7 +852,20 @@ export function createInjectionSource(features, {
852
852
  const aliases = (selector.models ?? []).filter((model) => (
853
853
  comparableModelLabel(model.slug) === target || comparableModelLabel(model.displayName) === target
854
854
  ));
855
- return aliases.length === 1 ? aliases[0] : null;
855
+ return resolveModelAlias(aliases, identity);
856
+ }
857
+
858
+ function resolveModelAlias(aliases, identity) {
859
+ if (aliases.length === 1) return aliases[0];
860
+ if (aliases.length < 2 || identity.provider) return null;
861
+ const native = aliases.find((model) => !model.slug.includes("/"));
862
+ const thirdParty = aliases.find((model) => model.slug.includes("/"));
863
+ if (!native || !thirdParty) return null;
864
+ if (!modelIdentity(native.slug).backend.toLowerCase().startsWith("gpt")) return null;
865
+ const nativeLabel = formatIdentifier(
866
+ modelIdentity(String(native.displayName ?? native.slug)).backend,
867
+ ).toLowerCase();
868
+ return formatIdentifier(identity.backend).toLowerCase() === nativeLabel ? native : thirdParty;
856
869
  }
857
870
 
858
871
  function loadModelFavorites(selector) {
@@ -1128,6 +1141,29 @@ export function createInjectionSource(features, {
1128
1141
  }, 260);
1129
1142
  }
1130
1143
 
1144
+ function nativeGptSortRank(rawValue) {
1145
+ const known = new Map([
1146
+ ["gpt-5.6-sol", 1], ["gpt-5.6-terra", 2], ["gpt-5.6-luna", 3],
1147
+ ["gpt-5.5", 4], ["gpt-5.4", 5], ["gpt-5.4-mini", 6], ["gpt-5.3-codex-spark", 7],
1148
+ ]);
1149
+ const raw = String(rawValue ?? "").trim();
1150
+ const knownRank = known.get(raw);
1151
+ if (knownRank != null) return { official: true, rank: knownRank };
1152
+ const identity = modelIdentity(raw);
1153
+ return identity.provider ? null : { official: true, rank: 100 };
1154
+ }
1155
+
1156
+ function compareEnhancedModelItems(a, b, favorites) {
1157
+ const favA = Number(favorites.has(a.dataset.codexModelSliderRaw));
1158
+ const favB = Number(favorites.has(b.dataset.codexModelSliderRaw));
1159
+ if (favA !== favB) return favB - favA;
1160
+ const rankA = nativeGptSortRank(a.dataset.codexModelSliderRaw);
1161
+ const rankB = nativeGptSortRank(b.dataset.codexModelSliderRaw);
1162
+ if (Boolean(rankA) !== Boolean(rankB)) return rankA ? -1 : 1;
1163
+ if (rankA && rankB) return rankA.rank - rankB.rank;
1164
+ return 0;
1165
+ }
1166
+
1131
1167
  function renderEnhancedModelMenu(menu, selector) {
1132
1168
  const items = modelMenuItems(menu).filter((item) => item.dataset.codexModelSliderRaw);
1133
1169
  if (!items.length) return;
@@ -1135,7 +1171,7 @@ export function createInjectionSource(features, {
1135
1171
  items.forEach((item) => { item.style.display = ""; });
1136
1172
  const starred = items.filter((item) => favorites.has(item.dataset.codexModelSliderRaw));
1137
1173
  const ordinary = items.filter((item) => !favorites.has(item.dataset.codexModelSliderRaw));
1138
- const desired = [...starred, ...ordinary];
1174
+ const desired = items.slice().sort((a, b) => compareEnhancedModelItems(a, b, favorites));
1139
1175
  const parent = items[0].parentElement;
1140
1176
  if (!parent || !desired.every((item) => item.parentElement === parent)) return;
1141
1177
  const current = Array.from(parent.children).filter((child) => child.hasAttribute?.("data-codex-model-slider-item"));
@@ -1148,7 +1184,10 @@ export function createInjectionSource(features, {
1148
1184
  divider.setAttribute("data-codex-model-slider-divider", "");
1149
1185
  divider.setAttribute("role", "separator");
1150
1186
  }
1151
- if (divider.nextElementSibling !== ordinary[0]) parent.insertBefore(divider, ordinary[0]);
1187
+ const firstOrdinary = desired.find((item) => !favorites.has(item.dataset.codexModelSliderRaw));
1188
+ if (firstOrdinary && divider.nextElementSibling !== firstOrdinary) {
1189
+ parent.insertBefore(divider, firstOrdinary);
1190
+ }
1152
1191
  } else {
1153
1192
  divider?.remove();
1154
1193
  }
@@ -1204,6 +1243,7 @@ export function createInjectionSource(features, {
1204
1243
  }
1205
1244
 
1206
1245
  function enhanceModelItem(item, menu, selector, index) {
1246
+ if (item.querySelector("[data-codex-model-slider-row]")) return;
1207
1247
  const observedRaw = modelItemRawValue(item);
1208
1248
  if (!observedRaw) return;
1209
1249
  if (!modelSelectorOriginalItems.has(item)) modelSelectorOriginalItems.set(item, item.innerHTML);
@@ -1215,7 +1255,6 @@ export function createInjectionSource(features, {
1215
1255
  item.dataset.codexModelSliderItem = "";
1216
1256
  item.dataset.codexModelSliderOrder = String(index);
1217
1257
  item.dataset.codexModelSliderIdentitySource = catalogModel ? "catalog" : nativeDescriptor ? "native" : "visible";
1218
- if (item.querySelector("[data-codex-model-slider-row]")) return;
1219
1258
 
1220
1259
  const identity = modelIdentity(raw);
1221
1260
  const display = modelDisplayLabel(identity, selector);
@@ -3307,12 +3346,13 @@ export function createInjectionSource(features, {
3307
3346
  const anchorButton = temporaryChatButton ?? summaryButton ?? bottomPanelButton ?? sidePanelButton;
3308
3347
  if (!anchorButton) return;
3309
3348
  const anchorRoot = toolbarControlRoot(anchorButton);
3310
- // The side-panel toggle sits in a narrow fixed container that travels
3311
- // with the native panel. Entries anchored to it must live in the
3312
- // fallback toolbar group, otherwise the Notes entry would be dragged
3313
- // into the side panel and hidden. The Notes entry is only grouped with
3314
- // the native summary button when that button is the anchor.
3315
- const useFallbackAnchor = anchorButton === sidePanelButton;
3349
+ // The bottom/side-panel toggles sit in narrow fixed containers that
3350
+ // travel with the native panels. Entries anchored to them must live in
3351
+ // the fallback toolbar group, otherwise the Notes entry would be
3352
+ // dragged into the panel or push the native toggle out of the header.
3353
+ // The Notes entry is only grouped with the native summary button when
3354
+ // that button is the anchor.
3355
+ const useFallbackAnchor = anchorButton === sidePanelButton || anchorButton === bottomPanelButton;
3316
3356
  const summaryGroup = useFallbackAnchor ? null : nativeSummaryToolbarGroup(anchorButton);
3317
3357
  let targetGroup = summaryGroup ?? ensureFallbackSummaryToolbarGroup(anchorButton);
3318
3358
  if (!targetGroup) return;