@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.0

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.
Files changed (109) hide show
  1. package/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
  2. package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
  3. package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
  4. package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
  5. package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
  6. package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
  7. package/lib/behavior-BwvTUtag.mjs +111 -0
  8. package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
  9. package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
  10. package/lib/cascade-BWjRTD1q.mjs +30265 -0
  11. package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
  12. package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
  13. package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
  14. package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
  15. package/lib/collapse-_nkb2dn7.mjs +1945 -0
  16. package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
  17. package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
  18. package/lib/cursor-BgOuV7Qf.mjs +794 -0
  19. package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
  20. package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
  21. package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
  22. package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
  23. package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
  24. package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
  25. package/lib/factory-droid-ChhmsGWb.mjs +71 -0
  26. package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
  27. package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
  28. package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
  29. package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
  30. package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
  31. package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
  32. package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
  33. package/lib/google-validation-CdvRj4ec.mjs +126 -0
  34. package/lib/id-EJwVLDHE.mjs +2548 -0
  35. package/lib/index.mjs +248 -258
  36. package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
  37. package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
  38. package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
  39. package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
  40. package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
  41. package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
  42. package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
  43. package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
  44. package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
  45. package/lib/pricing-DusBEhwm.mjs +593 -0
  46. package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
  47. package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
  48. package/lib/slugify-ynYWBIA5.mjs +11 -0
  49. package/lib/snowflake-B_jap6lz.mjs +666 -0
  50. package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
  51. package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
  52. package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
  53. package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
  54. package/lib/types/tools/hashline/native/index.d.ts +2 -2
  55. package/lib/types/tools/hashline/native/policy.d.ts +19 -21
  56. package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
  57. package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
  58. package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
  59. package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
  60. package/lib/utils-D2tK38xq.mjs +34006 -0
  61. package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
  62. package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
  63. package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
  64. package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
  65. package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
  66. package/package.json +8 -8
  67. package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
  68. package/lib/anthropic-ClCw0PV_.mjs +0 -3624
  69. package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
  70. package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
  71. package/lib/bundled-references-DY3EJxZV.mjs +0 -56
  72. package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
  73. package/lib/collapse-CkMNRNr7.mjs +0 -2304
  74. package/lib/cursor-C6jaIJDg.mjs +0 -283
  75. package/lib/cursor-D-XZYDf_.mjs +0 -4544
  76. package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
  77. package/lib/devin-ExGIghmx.mjs +0 -69
  78. package/lib/devin-u0ljw5P6.mjs +0 -628
  79. package/lib/effort-BdtQMN-_.mjs +0 -23
  80. package/lib/event-stream-BKEtb45Y.mjs +0 -167
  81. package/lib/gemini-headers-Co9cVvex.mjs +0 -54
  82. package/lib/google-auth-qAN-6DMW.mjs +0 -232
  83. package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
  84. package/lib/google-lTxuq28n.mjs +0 -38
  85. package/lib/google-shared-Y01j9xOr.mjs +0 -856
  86. package/lib/google-validation-BEkNs-Bx.mjs +0 -18
  87. package/lib/google-vertex-DcM-FRC5.mjs +0 -99
  88. package/lib/hosts-00rjRzUD.mjs +0 -203
  89. package/lib/id-AL5obQzR.mjs +0 -71
  90. package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
  91. package/lib/ollama-6R0oXZks.mjs +0 -574
  92. package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
  93. package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
  94. package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
  95. package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
  96. package/lib/openai-responses-CjpafAEr.mjs +0 -861
  97. package/lib/protobuf-BMgDYu_U.mjs +0 -717
  98. package/lib/provider-response-SqKSkkUc.mjs +0 -22
  99. package/lib/proxy-DxvCQOCA.mjs +0 -230
  100. package/lib/request-debug-BwPOqN_j.mjs +0 -183
  101. package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
  102. package/lib/sse-debug-B-tkLCPW.mjs +0 -11
  103. package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
  104. package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
  105. package/lib/taxonomy-DSIM99rS.mjs +0 -15392
  106. package/lib/thinking-ngMwf_1Y.mjs +0 -336
  107. package/lib/type-guards-CttAANEx.mjs +0 -11
  108. package/lib/utils-CE3DSebh.mjs +0 -11763
  109. package/lib/vision-guard-BCpXWUj3.mjs +0 -77
@@ -0,0 +1,1945 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import "./src-BhinCSpi.mjs";
4
+ import { c as compareRevision, d as parseRevisionConstraint, h as isRecord, p as revisionSatisfies, u as parseRevision } from "./cascade-BWjRTD1q.mjs";
5
+ import { L as THINKING_EFFORTS, h as MODEL_KINDS, s as resolveModelPolicy, t as bareModelId } from "./id-EJwVLDHE.mjs";
6
+ import { t as cleanModelName } from "./utils-DrDwmNtu.mjs";
7
+ import { a as dueEffectiveRate, d as collapseVocabulary, l as classifyModel, n as NO_RECURRING_TARIFF, o as materializeTimeBasedCost, p as stripThinkingVariantSuffix, r as applyDueDatedCostCard, s as parseDatedCostCards, t as EARLIEST_EFFECTIVE_FROM, u as collapseVariantId } from "./pricing-DusBEhwm.mjs";
8
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/model-tokenizer.ts
9
+ const MAX_TOKENIZER_CACHE_ENTRIES = 2048;
10
+ const modelTokenizerCache = /* @__PURE__ */ new Map();
11
+ function revisionAtLeast$1(revision, floor) {
12
+ if (revision === void 0) return false;
13
+ const parsedRevision = parseRevision(revision);
14
+ const parsedFloor = parseRevision(floor);
15
+ return parsedRevision !== void 0 && parsedFloor !== void 0 && compareRevision(parsedRevision, parsedFloor) >= 0;
16
+ }
17
+ function claudeTokenizer(identity) {
18
+ if (identity.class !== "anthropic") return void 0;
19
+ if (identity.family === "opus") {
20
+ if (revisionAtLeast$1(identity.revision, "5")) return "claude-v5";
21
+ if (revisionAtLeast$1(identity.revision, "4.7")) return "claude-v47";
22
+ return "claude-v3";
23
+ }
24
+ if (identity.family === "sonnet" || identity.family === "fable" || identity.family === "mythos") return revisionAtLeast$1(identity.revision, "5") ? "claude-v5-sonnet" : "claude-v3";
25
+ if (identity.family === "haiku" && revisionAtLeast$1(identity.revision, "5.5")) return "claude-v5-sonnet";
26
+ return "claude-v3";
27
+ }
28
+ function qwenTokenizer(identity) {
29
+ return identity.class === "qwen" && revisionAtLeast$1(identity.revision, "3.5") ? "qwen3" : void 0;
30
+ }
31
+ function deepSeekTokenizer(identity) {
32
+ return identity.class === "deepseek" ? "deepseek-v3" : void 0;
33
+ }
34
+ function kimiTokenizer(identity) {
35
+ return identity.class === "kimi" ? "kimi-k2" : void 0;
36
+ }
37
+ function glmTokenizer(identity) {
38
+ return identity.class === "glm" && revisionAtLeast$1(identity.revision, "5") ? "glm5" : void 0;
39
+ }
40
+ function openAITokenizer(identity) {
41
+ return identity.class === "openai" && revisionAtLeast$1(identity.revision, "5") ? "o200k" : void 0;
42
+ }
43
+ /**
44
+ * Resolve the exact locally embedded tokenizer for a canonical model id.
45
+ *
46
+ * This is catalog policy, not a runtime caller heuristic: [`buildModel`](./build.ts)
47
+ * materializes the result as `Model.tokenizer`; consumers read that property.
48
+ */
49
+ function resolveModelTokenizer(modelId, provider = "") {
50
+ const cacheKey = `${provider}\0${modelId}`;
51
+ const cached = modelTokenizerCache.get(cacheKey);
52
+ if (cached !== void 0) return cached ?? void 0;
53
+ const identity = classifyModel(provider, bareModelId(modelId), { lenient: true });
54
+ const tokenizer = claudeTokenizer(identity) ?? qwenTokenizer(identity) ?? deepSeekTokenizer(identity) ?? kimiTokenizer(identity) ?? glmTokenizer(identity) ?? openAITokenizer(identity);
55
+ if (modelTokenizerCache.size === MAX_TOKENIZER_CACHE_ENTRIES) modelTokenizerCache.clear();
56
+ modelTokenizerCache.set(cacheKey, tokenizer ?? null);
57
+ return tokenizer;
58
+ }
59
+ //#endregion
60
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/build.ts
61
+ /**
62
+ * The single Model constructor. Resolution runs through the compat engine
63
+ * (`compat/resolve`): identity classification, cascade-rule axes, host
64
+ * detection, and spec overrides materialize exactly once per spec.
65
+ *
66
+ * Request handlers read fields — they never detect, parse ids, or allocate
67
+ * compat per request.
68
+ */
69
+ function numberField(source, key) {
70
+ const value = Reflect.get(source, key);
71
+ return typeof value === "number" ? value : void 0;
72
+ }
73
+ /** Narrow an unknown compiled-axis payload to an object payload. */
74
+ function objectPayload(value) {
75
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
76
+ }
77
+ /** Narrow a compiled `input-modalities` axis value to the model input union. */
78
+ function isInputModalities(value) {
79
+ return Array.isArray(value) && value.every((entry) => entry === "text" || entry === "image");
80
+ }
81
+ /**
82
+ * Applies resolved catalog-data axes onto the model: reviewed metadata
83
+ * corrections (`cost-patch`, `limits-patch`, `long-context-cost`,
84
+ * `context-window-floor`) overwrite upstream values; selection metadata
85
+ * (`priority`, `apply-patch-tool-type`, `service-tier-cost`,
86
+ * `requires-cursor-tool-schema-projection`, `requires-tool-result-image-hoisting`,
87
+ * `supports-assistant-prefill`) is rule-owned; `context-promotion-target` fills
88
+ * only when the spec left it unset.
89
+ */
90
+ function applyCatalogAssignments(model, catalog) {
91
+ const kind = MODEL_KINDS.find((value) => value === catalog.kind);
92
+ if (kind !== void 0) model.kind = kind;
93
+ if (catalog.contextWindowAuthoritative === true) model.contextWindowAuthoritative = true;
94
+ else delete model.contextWindowAuthoritative;
95
+ if (catalog.longContextWindowUncapped === true) model.longContextWindowUncapped = true;
96
+ else delete model.longContextWindowUncapped;
97
+ const webSearch = catalog.webSearch;
98
+ if (webSearch === "gemini" || webSearch === "anthropic" || webSearch === "codex" || webSearch === "xai" || webSearch === "openrouter" || webSearch === "openai") model.webSearch = webSearch;
99
+ if (typeof catalog.webSearchModel === "string") model.webSearchModel = catalog.webSearchModel;
100
+ if (catalog.hostedImage === true) model.hostedImage = true;
101
+ else if (catalog.hostedImage === false) delete model.hostedImage;
102
+ if (typeof catalog.imageModel === "string") model.imageModel = catalog.imageModel;
103
+ else if (catalog.imageModel === false) delete model.imageModel;
104
+ const serviceTierCost = objectPayload(catalog.serviceTierCost);
105
+ if (serviceTierCost !== void 0) {
106
+ const flex = numberField(serviceTierCost, "flex");
107
+ const priorityTier = numberField(serviceTierCost, "priority");
108
+ const ultrafast = numberField(serviceTierCost, "ultrafast");
109
+ model.serviceTierCost = {
110
+ ...flex !== void 0 && { flex },
111
+ ...priorityTier !== void 0 && { priority: priorityTier },
112
+ ...ultrafast !== void 0 && { ultrafast }
113
+ };
114
+ }
115
+ const priority = catalog.priority;
116
+ if (typeof priority === "number") model.priority = priority;
117
+ const promptCache = objectPayload(catalog.promptCache);
118
+ if (promptCache !== void 0) {
119
+ const short = numberField(promptCache, "short");
120
+ const long = numberField(promptCache, "long");
121
+ model.promptCache = {
122
+ ...short !== void 0 && { short },
123
+ ...long !== void 0 && { long }
124
+ };
125
+ }
126
+ const applyPatchToolType = catalog.applyPatchToolType;
127
+ if (applyPatchToolType === "freeform" || applyPatchToolType === "function") model.applyPatchToolType = applyPatchToolType;
128
+ const editPromptVariant = catalog.editPromptVariant;
129
+ if (editPromptVariant === "full" || editPromptVariant === "compact") model.editPromptVariant = editPromptVariant;
130
+ const pricingStatus = catalog.pricingStatus;
131
+ if (pricingStatus === "free" || pricingStatus === "included" || pricingStatus === "variable" || pricingStatus === "unknown") model.pricingStatus = pricingStatus;
132
+ if (catalog.requiresCursorToolSchemaProjection === true) model.requiresCursorToolSchemaProjection = true;
133
+ else delete model.requiresCursorToolSchemaProjection;
134
+ if (catalog.toolSchemasInContext === false) model.toolSchemasInContext = false;
135
+ else delete model.toolSchemasInContext;
136
+ if (catalog.requiresToolResultImageHoisting === true) model.requiresToolResultImageHoisting = true;
137
+ else delete model.requiresToolResultImageHoisting;
138
+ if (catalog.supportsAssistantPrefill === true) model.supportsAssistantPrefill = true;
139
+ else delete model.supportsAssistantPrefill;
140
+ if (typeof catalog.omitMaxOutputTokens === "boolean" && model.omitMaxOutputTokens === void 0) model.omitMaxOutputTokens = catalog.omitMaxOutputTokens;
141
+ const contextPromotionTarget = catalog.contextPromotionTarget;
142
+ if (typeof contextPromotionTarget === "string" && model.contextPromotionTarget === void 0) model.contextPromotionTarget = contextPromotionTarget;
143
+ }
144
+ /**
145
+ * The row's corrected price card at `now`: `cost-patch`, then `cost-fallback`
146
+ * (each with its dated card due at `now`), then the long-context tier and
147
+ * cache-rate derivations, all from the upstream card.
148
+ */
149
+ function correctedCost(upstream, catalog, cards, now) {
150
+ let cost = { ...upstream };
151
+ const upstreamCard = upstream.timeBased?.effectiveRates?.[0]?.effectiveFrom === -864e13 ? dueEffectiveRate(upstream.timeBased, now) : void 0;
152
+ if (upstreamCard !== void 0) {
153
+ const { effectiveFrom: _effectiveFrom, ...card } = upstreamCard;
154
+ const { longContext: _longContext, ...base } = cost;
155
+ cost = {
156
+ ...base,
157
+ ...card
158
+ };
159
+ }
160
+ const patch = objectPayload(catalog.costPatch);
161
+ if (patch !== void 0) {
162
+ const input = numberField(patch, "input");
163
+ if (input !== void 0) cost.input = input;
164
+ const output = numberField(patch, "output");
165
+ if (output !== void 0) cost.output = output;
166
+ const cacheRead = numberField(patch, "cacheRead");
167
+ if (cacheRead !== void 0) cost.cacheRead = cacheRead;
168
+ const cacheWrite = numberField(patch, "cacheWrite");
169
+ if (cacheWrite !== void 0) cost.cacheWrite = cacheWrite;
170
+ applyDueDatedCostCard(cost, cards.patch, now);
171
+ }
172
+ const fallback = objectPayload(catalog.costFallback);
173
+ if (fallback !== void 0) {
174
+ if (!(cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0)) {
175
+ const input = numberField(fallback, "input");
176
+ if (input !== void 0) cost.input = input;
177
+ const output = numberField(fallback, "output");
178
+ if (output !== void 0) cost.output = output;
179
+ const cacheRead = numberField(fallback, "cacheRead");
180
+ if (cacheRead !== void 0) cost.cacheRead = cacheRead;
181
+ const cacheWrite = numberField(fallback, "cacheWrite");
182
+ if (cacheWrite !== void 0) cost.cacheWrite = cacheWrite;
183
+ applyDueDatedCostCard(cost, cards.fallback, now);
184
+ }
185
+ }
186
+ const longContext = objectPayload(catalog.longContext);
187
+ if (longContext !== void 0) {
188
+ const inputThreshold = numberField(longContext, "inputThreshold");
189
+ const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
190
+ const multiplier = numberField(longContext, "multiplier");
191
+ const input = numberField(longContext, "input");
192
+ const output = numberField(longContext, "output");
193
+ const cacheRead = numberField(longContext, "cacheRead");
194
+ const cacheWrite = numberField(longContext, "cacheWrite");
195
+ const hasTokenPrice = cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0;
196
+ if (inputThreshold !== void 0 && multiplier !== void 0 && hasTokenPrice) cost = {
197
+ ...cost,
198
+ longContext: {
199
+ inputThreshold,
200
+ ...inclusive && { inputThresholdInclusive: true },
201
+ input: cost.input * multiplier,
202
+ output: cost.output * (numberField(longContext, "outputMultiplier") ?? multiplier),
203
+ cacheRead: cost.cacheRead * multiplier,
204
+ cacheWrite: cost.cacheWrite * multiplier
205
+ }
206
+ };
207
+ else if (inputThreshold !== void 0 && input !== void 0 && output !== void 0 && cacheRead !== void 0 && cacheWrite !== void 0) cost = {
208
+ ...cost,
209
+ longContext: {
210
+ inputThreshold,
211
+ input,
212
+ output,
213
+ cacheRead,
214
+ cacheWrite
215
+ }
216
+ };
217
+ }
218
+ if (catalog.cacheReadAtInputRate === true) {
219
+ const { longContext } = cost;
220
+ cost = {
221
+ ...cost,
222
+ cacheRead: cost.input,
223
+ ...longContext && { longContext: {
224
+ ...longContext,
225
+ cacheRead: longContext.input
226
+ } }
227
+ };
228
+ }
229
+ const cacheWriteRate = catalog.cacheWriteRate;
230
+ if (typeof cacheWriteRate === "number") {
231
+ const { longContext } = cost;
232
+ cost = {
233
+ ...cost,
234
+ cacheWrite: cost.input * cacheWriteRate,
235
+ ...longContext && { longContext: {
236
+ ...longContext,
237
+ cacheWrite: longContext.input * cacheWriteRate
238
+ } }
239
+ };
240
+ }
241
+ return cost;
242
+ }
243
+ /**
244
+ * Every price period the dated `cost-patch`/`cost-fallback` cards define, for
245
+ * request-time selection (`calculateUsageCost`): a row built before a change
246
+ * still bills requests after it at the new price, and a leading card keeps
247
+ * earlier requests at the old one on rows built after it. Undefined when no
248
+ * card changes the price (no cards, or a fallback the upstream price outranks).
249
+ */
250
+ function scheduledRates(upstream, catalog, cards) {
251
+ const dates = [...cards.patch, ...cards.fallback].map((card) => card.effectiveFrom).sort((a, b) => a - b);
252
+ if (dates.length === 0) return void 0;
253
+ const periods = [];
254
+ let previousPrice;
255
+ for (const effectiveFrom of [EARLIEST_EFFECTIVE_FROM, ...dates]) {
256
+ const { input, output, cacheRead, cacheWrite, longContext } = correctedCost(upstream, catalog, cards, effectiveFrom);
257
+ const price = {
258
+ input,
259
+ output,
260
+ cacheRead,
261
+ cacheWrite,
262
+ ...longContext && { longContext }
263
+ };
264
+ const key = JSON.stringify(price);
265
+ if (key === previousPrice) continue;
266
+ previousPrice = key;
267
+ periods.push({
268
+ effectiveFrom,
269
+ ...price
270
+ });
271
+ }
272
+ return periods.length > 1 ? periods : void 0;
273
+ }
274
+ /**
275
+ * Applies reviewed catalog-data value corrections (`cost-patch`,
276
+ * `cache-read-at-input-rate`, `cache-write-rate`, `limits-patch`,
277
+ * `long-context-cost`, `context-window-floor`, `input-modalities`) onto an
278
+ * upstream-sourced spec. Applied by
279
+ * `buildModel` to every upstream-sourced spec; user-authored overrides are
280
+ * recomposed after building by the override applicators, so explicit user
281
+ * limits and pricing still win.
282
+ */
283
+ function applyCatalogCorrections(model, catalog) {
284
+ const upstream = model.cost;
285
+ const cards = {
286
+ patch: parseDatedCostCards(catalog.costPatch, "cost-patch"),
287
+ fallback: parseDatedCostCards(catalog.costFallback, "cost-fallback")
288
+ };
289
+ model.cost = correctedCost(upstream, catalog, cards, Date.now());
290
+ const recurring = catalog.timeBased === void 0 ? void 0 : materializeTimeBasedCost(catalog.timeBased);
291
+ const dated = scheduledRates(upstream, catalog, cards);
292
+ if (dated !== void 0) {
293
+ if (recurring?.effectiveRates !== void 0) throw new Error("Dated cost-patch/cost-fallback effective-rates cannot combine with time-based-cost effective-rates");
294
+ model.cost = {
295
+ ...model.cost,
296
+ timeBased: {
297
+ ...recurring ?? NO_RECURRING_TARIFF,
298
+ effectiveRates: dated
299
+ }
300
+ };
301
+ } else if (recurring !== void 0) model.cost = {
302
+ ...model.cost,
303
+ timeBased: recurring
304
+ };
305
+ const limitsPatch = objectPayload(catalog.limitsPatch);
306
+ if (limitsPatch !== void 0) {
307
+ const contextWindow = numberField(limitsPatch, "contextWindow");
308
+ if (contextWindow !== void 0) model.contextWindow = contextWindow;
309
+ const maxTokens = numberField(limitsPatch, "maxTokens");
310
+ if (maxTokens !== void 0) model.maxTokens = maxTokens;
311
+ }
312
+ const maxTokensFallback = catalog.maxTokensFallback;
313
+ if (typeof maxTokensFallback === "number" && model.maxTokens === null) model.maxTokens = maxTokensFallback;
314
+ const maxTokensCeiling = catalog.maxTokensCeiling;
315
+ if (typeof maxTokensCeiling === "number" && model.maxTokens !== null && model.maxTokens > maxTokensCeiling) model.maxTokens = maxTokensCeiling;
316
+ const contextWindowFloor = catalog.contextWindowFloor;
317
+ if (typeof contextWindowFloor === "number") model.contextWindow = Math.max(model.contextWindow ?? 0, contextWindowFloor);
318
+ const inputModalities = catalog.inputModalities;
319
+ if (isInputModalities(inputModalities)) model.input = inputModalities;
320
+ }
321
+ /**
322
+ * Direct first-party OpenAI Responses endpoints (api.openai.com, Azure OpenAI
323
+ * deployments). Gates GA computer-use detection; identity supplies the model
324
+ * generation.
325
+ */
326
+ function isDirectOpenAIResponsesEndpoint(spec) {
327
+ if (spec.api === "openai-responses") {
328
+ if (spec.provider !== "openai") return false;
329
+ if (!spec.baseUrl) return true;
330
+ try {
331
+ const url = new URL(spec.baseUrl);
332
+ return url.protocol === "https:" && url.hostname === "api.openai.com";
333
+ } catch {
334
+ return false;
335
+ }
336
+ }
337
+ if (spec.api !== "azure-openai-responses" || spec.provider !== "azure" && spec.provider !== "azure-openai") return false;
338
+ if (!spec.baseUrl) return true;
339
+ try {
340
+ const url = new URL(spec.baseUrl);
341
+ return url.protocol === "https:" && (url.hostname.endsWith(".openai.azure.com") || url.hostname === "models.inference.ai.azure.com");
342
+ } catch {
343
+ return false;
344
+ }
345
+ }
346
+ function explicitComputerUseConfig(spec) {
347
+ if (!("supportsComputerUseConfig" in spec)) return spec.supportsComputerUse;
348
+ const value = Reflect.get(spec, "supportsComputerUseConfig");
349
+ return typeof value === "boolean" ? value : void 0;
350
+ }
351
+ function revisionAtLeast(identity, major, minor) {
352
+ if (identity.revision === void 0) return false;
353
+ const [revMajor = 0, revMinor = 0] = identity.revision.split(".").map(Number);
354
+ return revMajor > major || revMajor === major && revMinor >= minor;
355
+ }
356
+ function supportsOpenAIGAComputerUse(spec, identity, explicitSupport) {
357
+ if (explicitSupport !== void 0) return explicitSupport;
358
+ if (!isDirectOpenAIResponsesEndpoint(spec)) return false;
359
+ const wireIdentity = spec.requestModelId === void 0 ? identity : resolveModelPolicy({
360
+ ...spec,
361
+ id: spec.requestModelId
362
+ }).identity;
363
+ return wireIdentity.class === "openai" && revisionAtLeast(wireIdentity, 5, 4);
364
+ }
365
+ /**
366
+ * Build one model from an authored spec. Bundled models.json rows are fully
367
+ * materialized by the generator and consumed directly (see `models.ts`), so
368
+ * this only runs for discovered/custom/override specs.
369
+ */
370
+ function buildModel(spec) {
371
+ const policy = resolveModelPolicy(spec);
372
+ const supportsComputerUseConfig = explicitComputerUseConfig(spec);
373
+ const model = {
374
+ ...spec,
375
+ reasoning: spec.reasoning || policy.thinking !== void 0,
376
+ name: cleanModelName(spec.name),
377
+ identity: policy.identity,
378
+ requiresGlyphTokenization: policy.identity.class === "anthropic",
379
+ tokenizer: spec.tokenizer ?? resolveModelTokenizer(spec.requestModelId ?? spec.id, spec.provider),
380
+ thinking: policy.thinking,
381
+ supportsComputerUse: supportsOpenAIGAComputerUse(spec, policy.identity, supportsComputerUseConfig),
382
+ supportsComputerUseConfig,
383
+ compat: policy.compat,
384
+ compatConfig: spec.compat
385
+ };
386
+ applyCatalogAssignments(model, policy.catalog);
387
+ applyCatalogCorrections(model, policy.catalog);
388
+ if (spec.kindConfig !== void 0) model.kind = spec.kindConfig;
389
+ if (spec.promptCacheConfig !== void 0) model.promptCache = { ...spec.promptCacheConfig };
390
+ return model;
391
+ }
392
+ //#endregion
393
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/discovery/protobuf.ts
394
+ const textEncoder = new TextEncoder();
395
+ const textDecoder = new TextDecoder("utf-8", { fatal: true });
396
+ /** Creates a high-performance, lazy protobuf message codec from an IR field descriptor list. */
397
+ function pb(typeName, fields = []) {
398
+ let compiled;
399
+ function getCodec() {
400
+ if (!compiled) compiled = compileCodec(typeName, fields);
401
+ return compiled;
402
+ }
403
+ const codec = ((arg) => {
404
+ if (arg instanceof Uint8Array) return getCodec().decode(arg);
405
+ return getCodec().encode(arg);
406
+ });
407
+ codec.create = (value) => getCodec().create(value);
408
+ codec.encode = (value) => getCodec().encode(value);
409
+ codec.decode = (value) => getCodec().decode(value);
410
+ codec.toJson = (value) => getCodec().toJson(value);
411
+ return codec;
412
+ }
413
+ /** Creates a message using its codec's protobuf defaults. */
414
+ function create(codec, value) {
415
+ return codec.create(value);
416
+ }
417
+ /** Encodes a message using its codec. */
418
+ function toBinary(codec, value) {
419
+ return codec.encode(value);
420
+ }
421
+ /** Decodes wire bytes using a message codec. */
422
+ function fromBinary(codec, value) {
423
+ return codec.decode(value);
424
+ }
425
+ /** Encodes a JSON value as `google.protobuf.Value`. */
426
+ function encodeJsonValue(value) {
427
+ const writer = new Writer();
428
+ writeJsonValue(writer, value);
429
+ return writer.finish();
430
+ }
431
+ /** Decodes `google.protobuf.Value` wire bytes into a JSON value. */
432
+ function decodeJsonValue(value) {
433
+ return readJsonValue(new Reader(value));
434
+ }
435
+ function compileCodec(typeName, fieldDescs) {
436
+ const compiledFields = [];
437
+ const byNumber = /* @__PURE__ */ new Map();
438
+ for (const desc of fieldDescs) if (desc.kind === "oneof") {
439
+ const oneofHandler = compileOneofField(desc);
440
+ compiledFields.push(oneofHandler);
441
+ for (const v of desc.variants) byNumber.set(v.no, oneofHandler);
442
+ } else if (desc.kind === "map") {
443
+ const mapHandler = compileMapField(desc);
444
+ compiledFields.push(mapHandler);
445
+ byNumber.set(desc.no, mapHandler);
446
+ } else if (desc.kind === "message") {
447
+ const msgHandler = desc.repeat ? compileRepeatedField(desc.name, desc.no, messageValue(desc.T)) : compileSingularField(desc.name, desc.no, messageValue(desc.T));
448
+ compiledFields.push(msgHandler);
449
+ byNumber.set(desc.no, msgHandler);
450
+ } else {
451
+ const valCodec = scalarValue(desc.kind);
452
+ const scalarHandler = desc.repeat ? compileRepeatedField(desc.name, desc.no, valCodec) : compileSingularField(desc.name, desc.no, valCodec, desc.optional);
453
+ compiledFields.push(scalarHandler);
454
+ byNumber.set(desc.no, scalarHandler);
455
+ }
456
+ const codec = ((arg) => {
457
+ if (arg instanceof Uint8Array) return codec.decode(arg);
458
+ return codec.encode(arg);
459
+ });
460
+ codec.create = (value) => {
461
+ const message = typeName ? { $typeName: typeName } : {};
462
+ for (const f of compiledFields) f.initDefault(message);
463
+ if (value) for (const key in value) {
464
+ const v = Reflect.get(value, key);
465
+ if (v !== void 0) Reflect.set(message, key, v);
466
+ }
467
+ return message;
468
+ };
469
+ codec.encode = (value) => {
470
+ const writer = new Writer();
471
+ for (const f of compiledFields) f.encode(value, writer);
472
+ writeUnknownFields(value, writer);
473
+ return writer.finish();
474
+ };
475
+ codec.decode = (value) => {
476
+ const reader = new Reader(value);
477
+ const message = typeName ? { $typeName: typeName } : {};
478
+ for (const f of compiledFields) f.initDefault(message);
479
+ while (reader.pos < reader.len) {
480
+ const tag = reader.uint32();
481
+ const fieldNumber = tag >>> 3;
482
+ const wireType = tag & 7;
483
+ if (!isWireType(wireType)) throw new Error(`Unsupported protobuf wire type ${wireType} at byte ${reader.pos}`);
484
+ const field = byNumber.get(fieldNumber);
485
+ if (field) field.decode(message, reader, wireType, fieldNumber);
486
+ else {
487
+ const start = reader.pos;
488
+ reader.skip(wireType);
489
+ appendUnknownField(message, {
490
+ no: fieldNumber,
491
+ wireType,
492
+ data: reader.slice(start, reader.pos)
493
+ });
494
+ }
495
+ }
496
+ return message;
497
+ };
498
+ codec.toJson = (value) => {
499
+ const output = {};
500
+ for (const f of compiledFields) f.toJson(value, output);
501
+ return output;
502
+ };
503
+ return codec;
504
+ }
505
+ function compileSingularField(name, number, value, optional = false) {
506
+ return {
507
+ number,
508
+ initDefault(message) {
509
+ if (!optional && value.defaultValue !== void 0) Reflect.set(message, name, value.defaultValue);
510
+ },
511
+ encode(message, writer) {
512
+ const input = Reflect.get(message, name);
513
+ if (input === void 0 || !optional && value.isDefault(input)) return;
514
+ writer.tag(number, value.wireType);
515
+ value.encode(input, writer);
516
+ },
517
+ decode(message, reader, wireType, _fieldNumber) {
518
+ assertWireType(wireType, value.wireType);
519
+ Reflect.set(message, name, value.decode(reader));
520
+ },
521
+ toJson(message, output) {
522
+ const input = Reflect.get(message, name);
523
+ if (input === void 0 || !optional && value.isDefault(input)) return;
524
+ output[name] = value.toJson(input);
525
+ }
526
+ };
527
+ }
528
+ function compileRepeatedField(name, number, value) {
529
+ return {
530
+ number,
531
+ initDefault(message) {
532
+ Reflect.set(message, name, []);
533
+ },
534
+ encode(message, writer) {
535
+ const items = Reflect.get(message, name);
536
+ if (!Array.isArray(items) || items.length === 0) return;
537
+ if (value.wireType !== 2 && isPackableScalar(value)) {
538
+ const packed = new Writer();
539
+ for (const item of items) value.encode(item, packed);
540
+ writer.tag(number, 2);
541
+ writer.lengthDelimited(packed.finish());
542
+ return;
543
+ }
544
+ for (const item of items) {
545
+ writer.tag(number, value.wireType);
546
+ value.encode(item, writer);
547
+ }
548
+ },
549
+ decode(message, reader, wireType, _fieldNumber) {
550
+ const target = arrayField(message, name);
551
+ if (wireType === 2 && value.wireType !== 2 && isPackableScalar(value)) {
552
+ const limit = reader.uint32();
553
+ const end = reader.pos + limit;
554
+ while (reader.pos < end) target.push(value.decode(reader));
555
+ return;
556
+ }
557
+ assertWireType(wireType, value.wireType);
558
+ target.push(value.decode(reader));
559
+ },
560
+ toJson(message, output) {
561
+ const items = Reflect.get(message, name);
562
+ if (!Array.isArray(items) || items.length === 0) return;
563
+ output[name] = items.map((item) => value.toJson(item));
564
+ }
565
+ };
566
+ }
567
+ function compileMapField(desc) {
568
+ const name = desc.name;
569
+ const number = desc.no;
570
+ const key = scalarValue("string");
571
+ const valCodec = typeof desc.V === "function" ? messageValue(desc.V) : scalarValue(desc.V);
572
+ return {
573
+ number,
574
+ initDefault(message) {
575
+ Reflect.set(message, name, Object.create(null));
576
+ },
577
+ encode(message, writer) {
578
+ const input = Reflect.get(message, name);
579
+ if (!isMessageObject(input)) return;
580
+ for (const entryKey in input) {
581
+ const entry = new Writer();
582
+ if (!key.isDefault(entryKey)) {
583
+ entry.tag(1, key.wireType);
584
+ key.encode(entryKey, entry);
585
+ }
586
+ const entryValue = input[entryKey];
587
+ if (!valCodec.isDefault(entryValue)) {
588
+ entry.tag(2, valCodec.wireType);
589
+ valCodec.encode(entryValue, entry);
590
+ }
591
+ writer.tag(number, 2);
592
+ writer.lengthDelimited(entry.finish());
593
+ }
594
+ },
595
+ decode(message, reader, wireType, _fieldNumber) {
596
+ assertWireType(wireType, 2);
597
+ const target = mapField(message, name);
598
+ const limit = reader.uint32();
599
+ const end = reader.pos + limit;
600
+ let entryKey = "";
601
+ let entryValue = valCodec.defaultValue;
602
+ while (reader.pos < end) {
603
+ const tag = reader.uint32();
604
+ const entryNumber = tag >>> 3;
605
+ const entryWireType = tag & 7;
606
+ if (!isWireType(entryWireType)) throw new Error(`Unsupported wire type ${entryWireType} in map entry`);
607
+ if (entryNumber === 1) {
608
+ assertWireType(entryWireType, key.wireType);
609
+ entryKey = requireString(key.decode(reader));
610
+ } else if (entryNumber === 2) {
611
+ assertWireType(entryWireType, valCodec.wireType);
612
+ entryValue = valCodec.decode(reader);
613
+ } else reader.skip(entryWireType);
614
+ }
615
+ target[entryKey] = entryValue;
616
+ },
617
+ toJson(message, output) {
618
+ const input = Reflect.get(message, name);
619
+ if (!isMessageObject(input)) return;
620
+ const mapOutput = Object.create(null);
621
+ for (const entryKey in input) mapOutput[entryKey] = valCodec.toJson(input[entryKey]);
622
+ output[name] = mapOutput;
623
+ }
624
+ };
625
+ }
626
+ function compileOneofField(desc) {
627
+ const name = desc.name;
628
+ const variantsByName = /* @__PURE__ */ new Map();
629
+ const variantsByNumber = /* @__PURE__ */ new Map();
630
+ for (const variant of desc.variants) {
631
+ const codec = variant.kind === "message" ? messageValue(variant.T) : scalarValue(variant.kind);
632
+ variantsByName.set(variant.name, {
633
+ no: variant.no,
634
+ codec
635
+ });
636
+ variantsByNumber.set(variant.no, {
637
+ name: variant.name,
638
+ codec
639
+ });
640
+ }
641
+ return {
642
+ number: 0,
643
+ initDefault(message) {
644
+ Reflect.set(message, name, { case: void 0 });
645
+ },
646
+ encode(message, writer) {
647
+ const oneof = Reflect.get(message, name);
648
+ if (!oneof || typeof oneof !== "object" || !("case" in oneof) || typeof oneof.case !== "string") return;
649
+ const variant = variantsByName.get(oneof.case);
650
+ if (!variant) return;
651
+ const value = Reflect.get(oneof, "value");
652
+ if (value === void 0) return;
653
+ writer.tag(variant.no, variant.codec.wireType);
654
+ variant.codec.encode(value, writer);
655
+ },
656
+ decode(message, reader, wireType, fieldNumber) {
657
+ const variant = variantsByNumber.get(fieldNumber);
658
+ if (!variant) throw new Error(`Unknown oneof field ${fieldNumber}`);
659
+ assertWireType(wireType, variant.codec.wireType);
660
+ Reflect.set(message, name, {
661
+ case: variant.name,
662
+ value: variant.codec.decode(reader)
663
+ });
664
+ },
665
+ toJson(message, output) {
666
+ const oneof = Reflect.get(message, name);
667
+ if (!oneof || typeof oneof !== "object" || !("case" in oneof) || typeof oneof.case !== "string") return;
668
+ const variant = variantsByName.get(oneof.case);
669
+ if (!variant) return;
670
+ const value = Reflect.get(oneof, "value");
671
+ if (value === void 0) return;
672
+ output[oneof.case] = variant.codec.toJson(value);
673
+ }
674
+ };
675
+ }
676
+ function isPackableScalar(value) {
677
+ return value.wireType === 0 || value.wireType === 1 || value.wireType === 5;
678
+ }
679
+ function scalarValue(kind) {
680
+ switch (kind) {
681
+ case "bool": return scalar(0, false, requireBoolean, (value, writer) => writer.bool(value), (reader) => reader.bool(), (value) => value);
682
+ case "bytes": return scalar(2, /* @__PURE__ */ new Uint8Array(0), requireBytes, (value, writer) => writer.bytes(value), (reader) => reader.bytes(), (value) => value.toBase64(), (value) => value.byteLength === 0);
683
+ case "double": return scalar(1, 0, requireNumber, (value, writer) => writer.double(value), (reader) => reader.double(), (value) => value);
684
+ case "enum": return scalar(0, 0, requireInt32, (value, writer) => writer.int32(value), (reader) => reader.int32(), (value) => value);
685
+ case "float": return scalar(5, 0, requireNumber, (value, writer) => writer.float(value), (reader) => reader.float(), (value) => value);
686
+ case "int32": return scalar(0, 0, requireInt32, (value, writer) => writer.int32(value), (reader) => reader.int32(), (value) => value);
687
+ case "int64": return scalar(0, 0n, requireBigInt, (value, writer) => writer.int64(value), (reader) => reader.int64(), (value) => value.toString());
688
+ case "string": return scalar(2, "", requireString, (value, writer) => writer.string(value), (reader) => reader.string(), (value) => value);
689
+ case "uint32": return scalar(0, 0, requireUint32, (value, writer) => writer.uint32(value), (reader) => reader.uint32(), (value) => value);
690
+ case "uint64": return scalar(0, 0n, requireUnsignedBigInt, (value, writer) => writer.uint64(value), (reader) => reader.uint64(), (value) => value.toString());
691
+ }
692
+ }
693
+ function scalar(wireType, defaultValue, validate, write, read, toJson, isDefault = (value) => value === defaultValue) {
694
+ return {
695
+ wireType,
696
+ defaultValue,
697
+ encode(value, writer) {
698
+ write(validate(value), writer);
699
+ },
700
+ decode(reader) {
701
+ return read(reader);
702
+ },
703
+ toJson(value) {
704
+ return toJson(validate(value));
705
+ },
706
+ isDefault(value) {
707
+ return isDefault(validate(value));
708
+ }
709
+ };
710
+ }
711
+ function messageValue(factory) {
712
+ let cached;
713
+ function getCodec() {
714
+ if (!cached) cached = factory();
715
+ return cached;
716
+ }
717
+ return {
718
+ wireType: 2,
719
+ defaultValue: void 0,
720
+ encode(value, writer) {
721
+ writer.lengthDelimited(getCodec().encode(value));
722
+ },
723
+ decode(reader) {
724
+ return getCodec().decode(reader.bytes());
725
+ },
726
+ toJson(value) {
727
+ return getCodec().toJson(value);
728
+ },
729
+ isDefault(value) {
730
+ return value === void 0;
731
+ }
732
+ };
733
+ }
734
+ function requireBoolean(value) {
735
+ if (typeof value === "boolean") return value;
736
+ throw new Error(`Expected boolean, got ${typeof value}`);
737
+ }
738
+ function requireBytes(value) {
739
+ if (value instanceof Uint8Array) return value;
740
+ throw new Error("Expected Uint8Array");
741
+ }
742
+ function requireNumber(value) {
743
+ if (typeof value === "number" && Number.isFinite(value)) return value;
744
+ throw new Error(`Expected number, got ${typeof value}`);
745
+ }
746
+ function requireInt32(value) {
747
+ if (typeof value === "number" && Number.isInteger(value)) return value | 0;
748
+ throw new Error(`Expected int32, got ${typeof value}`);
749
+ }
750
+ function requireString(value) {
751
+ if (typeof value === "string") return value;
752
+ throw new Error(`Expected string, got ${typeof value}`);
753
+ }
754
+ function requireBigInt(value) {
755
+ if (typeof value === "bigint") return value;
756
+ if (typeof value === "number" && Number.isInteger(value)) return BigInt(value);
757
+ if (typeof value === "string") return BigInt(value);
758
+ throw new Error(`Expected bigint, got ${typeof value}`);
759
+ }
760
+ function requireUint32(value) {
761
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0) return value >>> 0;
762
+ throw new Error(`Expected uint32, got ${typeof value}`);
763
+ }
764
+ function requireUnsignedBigInt(value) {
765
+ const b = requireBigInt(value);
766
+ if (b < 0n) throw new Error("Expected unsigned bigint");
767
+ return b;
768
+ }
769
+ function arrayField(message, name) {
770
+ let arr = Reflect.get(message, name);
771
+ if (!Array.isArray(arr)) {
772
+ arr = [];
773
+ Reflect.set(message, name, arr);
774
+ }
775
+ return arr;
776
+ }
777
+ function mapField(message, name) {
778
+ const value = Reflect.get(message, name);
779
+ if (isRecord(value)) return value;
780
+ const map = Object.create(null);
781
+ Reflect.set(message, name, map);
782
+ return map;
783
+ }
784
+ function appendUnknownField(message, field) {
785
+ const existing = Reflect.get(message, "$unknown");
786
+ if (isUnknownFields(existing)) {
787
+ existing.push(field);
788
+ return;
789
+ }
790
+ Reflect.set(message, "$unknown", [field]);
791
+ }
792
+ function isUnknownFields(value) {
793
+ return Array.isArray(value) && value.every(isUnknownField);
794
+ }
795
+ function writeUnknownFields(message, writer) {
796
+ const bag = Reflect.get(message, "$unknown");
797
+ if (!Array.isArray(bag)) return;
798
+ for (const field of bag) if (isUnknownField(field)) {
799
+ writer.tag(field.no, field.wireType);
800
+ writer.raw(field.data);
801
+ }
802
+ }
803
+ function isUnknownField(value) {
804
+ return isRecord(value) && typeof value.no === "number" && typeof value.wireType === "number" && isWireType(value.wireType) && value.data instanceof Uint8Array;
805
+ }
806
+ function isMessageObject(value) {
807
+ return isRecord(value) && !(value instanceof Uint8Array);
808
+ }
809
+ function isWireType(value) {
810
+ return value === 0 || value === 1 || value === 2 || value === 5;
811
+ }
812
+ function assertWireType(actual, expected) {
813
+ if (actual !== expected) throw new Error(`Unexpected protobuf wire type ${actual}; expected ${expected}`);
814
+ }
815
+ function isArrayBufferBacked(bytes) {
816
+ return bytes?.buffer instanceof ArrayBuffer;
817
+ }
818
+ var Writer = class {
819
+ #chunks = [];
820
+ #length = 0;
821
+ tag(number, wireType) {
822
+ this.uint32(number << 3 | wireType);
823
+ }
824
+ uint32(value) {
825
+ let v = value >>> 0;
826
+ const buffer = /* @__PURE__ */ new Uint8Array(5);
827
+ let pos = 0;
828
+ while (v > 127) {
829
+ buffer[pos++] = v & 127 | 128;
830
+ v >>>= 7;
831
+ }
832
+ buffer[pos++] = v;
833
+ this.raw(buffer.subarray(0, pos));
834
+ }
835
+ int32(value) {
836
+ if (value >= 0) {
837
+ this.uint32(value);
838
+ return;
839
+ }
840
+ this.int64(BigInt(value));
841
+ }
842
+ int64(value) {
843
+ let v = BigInt.asUintN(64, value);
844
+ const buffer = /* @__PURE__ */ new Uint8Array(10);
845
+ let pos = 0;
846
+ while (v > 127n) {
847
+ buffer[pos++] = Number(v & 127n) | 128;
848
+ v >>= 7n;
849
+ }
850
+ buffer[pos++] = Number(v);
851
+ this.raw(buffer.subarray(0, pos));
852
+ }
853
+ uint64(value) {
854
+ this.int64(value);
855
+ }
856
+ bool(value) {
857
+ this.raw(new Uint8Array([value ? 1 : 0]));
858
+ }
859
+ float(value) {
860
+ const buffer = /* @__PURE__ */ new Uint8Array(4);
861
+ new DataView(buffer.buffer).setFloat32(0, value, true);
862
+ this.raw(buffer);
863
+ }
864
+ double(value) {
865
+ const buffer = /* @__PURE__ */ new Uint8Array(8);
866
+ new DataView(buffer.buffer).setFloat64(0, value, true);
867
+ this.raw(buffer);
868
+ }
869
+ string(value) {
870
+ this.lengthDelimited(textEncoder.encode(value));
871
+ }
872
+ bytes(value) {
873
+ this.lengthDelimited(value);
874
+ }
875
+ lengthDelimited(value) {
876
+ this.uint32(value.byteLength);
877
+ this.raw(value);
878
+ }
879
+ raw(chunk) {
880
+ this.#chunks.push(chunk);
881
+ this.#length += chunk.byteLength;
882
+ }
883
+ /** Wire bytes on a plain `ArrayBuffer`, so they satisfy `fetch`'s `BodyInit` as-is. */
884
+ finish() {
885
+ const [only] = this.#chunks;
886
+ if (this.#chunks.length === 1 && isArrayBufferBacked(only)) return only;
887
+ const result = new Uint8Array(this.#length);
888
+ let offset = 0;
889
+ for (const chunk of this.#chunks) {
890
+ result.set(chunk, offset);
891
+ offset += chunk.byteLength;
892
+ }
893
+ return result;
894
+ }
895
+ };
896
+ var Reader = class {
897
+ buf;
898
+ len;
899
+ pos = 0;
900
+ constructor(buf) {
901
+ this.buf = buf;
902
+ this.len = buf.byteLength;
903
+ }
904
+ uint32() {
905
+ let result = 0;
906
+ let shift = 0;
907
+ while (this.pos < this.len) {
908
+ const byte = this.buf[this.pos++];
909
+ result |= (byte & 127) << shift;
910
+ if ((byte & 128) === 0) return result >>> 0;
911
+ shift += 7;
912
+ if (shift >= 32) throw new Error("Varint exceeds 32 bits");
913
+ }
914
+ throw new Error("Unexpected end of protobuf varint");
915
+ }
916
+ int32() {
917
+ return Number(BigInt.asIntN(32, this.uint64()));
918
+ }
919
+ int64() {
920
+ let result = 0n;
921
+ let shift = 0n;
922
+ while (this.pos < this.len) {
923
+ const byte = this.buf[this.pos++];
924
+ result |= BigInt(byte & 127) << shift;
925
+ if ((byte & 128) === 0) return BigInt.asIntN(64, result);
926
+ shift += 7n;
927
+ if (shift >= 64n) throw new Error("Varint exceeds 64 bits");
928
+ }
929
+ throw new Error("Unexpected end of protobuf 64-bit varint");
930
+ }
931
+ uint64() {
932
+ return BigInt.asUintN(64, this.int64());
933
+ }
934
+ bool() {
935
+ return this.uint32() !== 0;
936
+ }
937
+ float() {
938
+ if (this.pos + 4 > this.len) throw new Error("Unexpected EOF reading float");
939
+ const view = new DataView(this.buf.buffer, this.buf.byteOffset + this.pos, 4);
940
+ this.pos += 4;
941
+ return view.getFloat32(0, true);
942
+ }
943
+ double() {
944
+ if (this.pos + 8 > this.len) throw new Error("Unexpected EOF reading double");
945
+ const view = new DataView(this.buf.buffer, this.buf.byteOffset + this.pos, 8);
946
+ this.pos += 8;
947
+ return view.getFloat64(0, true);
948
+ }
949
+ string() {
950
+ return textDecoder.decode(this.bytes());
951
+ }
952
+ bytes() {
953
+ const length = this.uint32();
954
+ if (this.pos + length > this.len) throw new Error("Unexpected EOF reading bytes");
955
+ const result = this.buf.subarray(this.pos, this.pos + length);
956
+ this.pos += length;
957
+ return result;
958
+ }
959
+ slice(start, end) {
960
+ return this.buf.subarray(start, end);
961
+ }
962
+ skip(wireType) {
963
+ switch (wireType) {
964
+ case 0:
965
+ this.int64();
966
+ return;
967
+ case 1:
968
+ if (this.pos + 8 > this.len) throw new Error("Unexpected EOF skipping 64-bit");
969
+ this.pos += 8;
970
+ return;
971
+ case 2:
972
+ this.bytes();
973
+ return;
974
+ case 5:
975
+ if (this.pos + 4 > this.len) throw new Error("Unexpected EOF skipping 32-bit");
976
+ this.pos += 4;
977
+ return;
978
+ }
979
+ }
980
+ };
981
+ function writeJsonValue(writer, value) {
982
+ if (value === null) {
983
+ writer.tag(1, 0);
984
+ writer.uint32(0);
985
+ return;
986
+ }
987
+ if (typeof value === "number") {
988
+ writer.tag(2, 1);
989
+ writer.double(value);
990
+ return;
991
+ }
992
+ if (typeof value === "string") {
993
+ writer.tag(3, 2);
994
+ writer.string(value);
995
+ return;
996
+ }
997
+ if (typeof value === "boolean") {
998
+ writer.tag(4, 0);
999
+ writer.bool(value);
1000
+ return;
1001
+ }
1002
+ if (Array.isArray(value)) {
1003
+ const listWriter = new Writer();
1004
+ for (const item of value) {
1005
+ listWriter.tag(1, 2);
1006
+ const itemWriter = new Writer();
1007
+ writeJsonValue(itemWriter, item);
1008
+ listWriter.lengthDelimited(itemWriter.finish());
1009
+ }
1010
+ writer.tag(6, 2);
1011
+ writer.lengthDelimited(listWriter.finish());
1012
+ return;
1013
+ }
1014
+ if (isRecord(value)) {
1015
+ const structWriter = new Writer();
1016
+ for (const key in value) {
1017
+ const item = value[key];
1018
+ const entryWriter = new Writer();
1019
+ entryWriter.tag(1, 2);
1020
+ entryWriter.string(key);
1021
+ entryWriter.tag(2, 2);
1022
+ const valueWriter = new Writer();
1023
+ writeJsonValue(valueWriter, item);
1024
+ entryWriter.lengthDelimited(valueWriter.finish());
1025
+ structWriter.tag(1, 2);
1026
+ structWriter.lengthDelimited(entryWriter.finish());
1027
+ }
1028
+ writer.tag(5, 2);
1029
+ writer.lengthDelimited(structWriter.finish());
1030
+ }
1031
+ }
1032
+ function readJsonValue(reader) {
1033
+ let value = null;
1034
+ while (reader.pos < reader.len) {
1035
+ const tag = reader.uint32();
1036
+ const fieldNumber = tag >>> 3;
1037
+ const wireType = tag & 7;
1038
+ if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in google.protobuf.Value`);
1039
+ switch (fieldNumber) {
1040
+ case 1:
1041
+ assertWireType(wireType, 0);
1042
+ reader.uint32();
1043
+ value = null;
1044
+ break;
1045
+ case 2:
1046
+ assertWireType(wireType, 1);
1047
+ value = reader.double();
1048
+ break;
1049
+ case 3:
1050
+ assertWireType(wireType, 2);
1051
+ value = reader.string();
1052
+ break;
1053
+ case 4:
1054
+ assertWireType(wireType, 0);
1055
+ value = reader.bool();
1056
+ break;
1057
+ case 5:
1058
+ assertWireType(wireType, 2);
1059
+ value = readJsonStruct(new Reader(reader.bytes()));
1060
+ break;
1061
+ case 6:
1062
+ assertWireType(wireType, 2);
1063
+ value = readJsonList(new Reader(reader.bytes()));
1064
+ break;
1065
+ default: reader.skip(wireType);
1066
+ }
1067
+ }
1068
+ return value;
1069
+ }
1070
+ function readJsonStruct(reader) {
1071
+ const output = {};
1072
+ while (reader.pos < reader.len) {
1073
+ const tag = reader.uint32();
1074
+ const fieldNumber = tag >>> 3;
1075
+ const wireType = tag & 7;
1076
+ if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in Struct`);
1077
+ if (fieldNumber === 1) {
1078
+ assertWireType(wireType, 2);
1079
+ const entryReader = new Reader(reader.bytes());
1080
+ let entryKey = "";
1081
+ let entryVal = null;
1082
+ while (entryReader.pos < entryReader.len) {
1083
+ const entryTag = entryReader.uint32();
1084
+ const entryNo = entryTag >>> 3;
1085
+ const entryWire = entryTag & 7;
1086
+ if (entryNo === 1) entryKey = entryReader.string();
1087
+ else if (entryNo === 2) entryVal = readJsonValue(new Reader(entryReader.bytes()));
1088
+ else if (isWireType(entryWire)) entryReader.skip(entryWire);
1089
+ }
1090
+ output[entryKey] = entryVal;
1091
+ } else reader.skip(wireType);
1092
+ }
1093
+ return output;
1094
+ }
1095
+ function readJsonList(reader) {
1096
+ const list = [];
1097
+ while (reader.pos < reader.len) {
1098
+ const tag = reader.uint32();
1099
+ const fieldNumber = tag >>> 3;
1100
+ const wireType = tag & 7;
1101
+ if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in ListValue`);
1102
+ if (fieldNumber === 1) {
1103
+ assertWireType(wireType, 2);
1104
+ list.push(readJsonValue(new Reader(reader.bytes())));
1105
+ } else reader.skip(wireType);
1106
+ }
1107
+ return list;
1108
+ }
1109
+ //#endregion
1110
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/types.ts
1111
+ /**
1112
+ * Revision placeholder in a templated `variant-family` (`gemini-{rev}-flash`).
1113
+ * A family whose id carries it is instantiated once per live revision that
1114
+ * discovery advertises, so new generations of a lineage collapse without a
1115
+ * new reviewed entry.
1116
+ */
1117
+ const REVISION_PLACEHOLDER = "{rev}";
1118
+ //#endregion
1119
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/collapse.ts
1120
+ const VARIANT_ROUTING_KEYS = ["off", ...THINKING_EFFORTS];
1121
+ const DEFAULT_PAIR_EFFORTS = [
1122
+ "minimal",
1123
+ "low",
1124
+ "medium",
1125
+ "high"
1126
+ ];
1127
+ /**
1128
+ * Build one effort-tier family from a tier→wire-id map: routing keeps only the
1129
+ * listed efforts, `members` dedupes the targets in tier order, and thinking is
1130
+ * `mode: "effort"` (mandatory when the family has no `off` route). Shared by the
1131
+ * Devin and Cursor tables, whose per-effort siblings follow the same shape.
1132
+ */
1133
+ function tierFamily(id, name, routes, efforts, defaultMember) {
1134
+ const routing = {};
1135
+ if (routes.off) routing.off = routes.off;
1136
+ for (const effort of efforts) switch (effort) {
1137
+ case "minimal":
1138
+ if (routes.minimal) routing[effort] = routes.minimal;
1139
+ break;
1140
+ case "low":
1141
+ if (routes.low) routing[effort] = routes.low;
1142
+ break;
1143
+ case "medium":
1144
+ if (routes.medium) routing[effort] = routes.medium;
1145
+ break;
1146
+ case "high":
1147
+ if (routes.high) routing[effort] = routes.high;
1148
+ break;
1149
+ case "xhigh":
1150
+ if (routes.xhigh) routing[effort] = routes.xhigh;
1151
+ break;
1152
+ case "max": if (routes.max) routing[effort] = routes.max;
1153
+ }
1154
+ return {
1155
+ id,
1156
+ name,
1157
+ members: [
1158
+ routes.off,
1159
+ routes.minimal,
1160
+ routes.low,
1161
+ routes.medium,
1162
+ routes.high,
1163
+ routes.xhigh,
1164
+ routes.max
1165
+ ].filter((member, index, items) => typeof member === "string" && items.indexOf(member) === index),
1166
+ routing,
1167
+ thinking: {
1168
+ mode: "effort",
1169
+ efforts,
1170
+ ...routes.off ? void 0 : { requiresEffort: true }
1171
+ },
1172
+ ...defaultMember !== void 0 ? { defaultMember } : void 0
1173
+ };
1174
+ }
1175
+ /** One reviewed family from the compiled collapse vocabulary → runtime shape. */
1176
+ function compiledFamily(compiled) {
1177
+ const family = {
1178
+ id: compiled.id,
1179
+ name: compiled.name,
1180
+ members: compiled.members,
1181
+ routing: compiled.routing
1182
+ };
1183
+ if (compiled.defaultMember !== void 0) family.defaultMember = compiled.defaultMember;
1184
+ if (compiled.retiredMembers?.length) family.retiredMembers = compiled.retiredMembers;
1185
+ if (!compiled.noThinking && compiled.mode !== void 0) family.thinking = {
1186
+ mode: compiled.mode,
1187
+ efforts: compiled.efforts ?? [],
1188
+ ...compiled.effortBudgets !== void 0 && { effortBudgets: compiled.effortBudgets },
1189
+ ...compiled.defaultLevel !== void 0 && { defaultLevel: compiled.defaultLevel },
1190
+ ...compiled.requiresEffort === true && { requiresEffort: true }
1191
+ };
1192
+ if (compiled.suppressWhenOff) family.suppressWhenOff = true;
1193
+ if (compiled.preserveAbsentEffortRoutes) family.preserveAbsentEffortRoutes = true;
1194
+ if (compiled.extraAliases?.length) family.extraAliases = compiled.extraAliases;
1195
+ return family;
1196
+ }
1197
+ const REVISION_CAPTURE = String.raw`(\d+(?:\.\d+){0,2})`;
1198
+ /** One compiled `{rev}` family → runtime template with its id matcher. */
1199
+ function compiledTemplate(compiled) {
1200
+ const family = compiledFamily(compiled);
1201
+ const alternatives = [
1202
+ family.id,
1203
+ ...family.members,
1204
+ ...family.extraAliases ?? []
1205
+ ].map((id) => id.split(REVISION_PLACEHOLDER).map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(REVISION_CAPTURE));
1206
+ const template = {
1207
+ family,
1208
+ pattern: new RegExp(`^(?:${alternatives.join("|")})$`, "i")
1209
+ };
1210
+ if (compiled.revision !== void 0) {
1211
+ const terms = parseRevisionConstraint(compiled.revision);
1212
+ if (terms !== void 0) template.revision = terms;
1213
+ }
1214
+ return template;
1215
+ }
1216
+ /** Substitute the placeholder throughout one templated family. */
1217
+ function instantiateTemplate(template, rev) {
1218
+ if (template.revision !== void 0) {
1219
+ const parsed = parseRevision(rev);
1220
+ if (parsed === void 0 || !revisionSatisfies(parsed, template.revision)) return void 0;
1221
+ }
1222
+ const fill = (id) => id.replaceAll(REVISION_PLACEHOLDER, rev);
1223
+ const source = template.family;
1224
+ const routing = {};
1225
+ for (const effort of VARIANT_ROUTING_KEYS) {
1226
+ const target = source.routing[effort];
1227
+ if (target !== void 0) routing[effort] = fill(target);
1228
+ }
1229
+ const family = {
1230
+ ...source,
1231
+ id: fill(source.id),
1232
+ name: fill(source.name),
1233
+ members: source.members.map(fill),
1234
+ routing
1235
+ };
1236
+ if (source.defaultMember !== void 0) family.defaultMember = fill(source.defaultMember);
1237
+ if (source.retiredMembers !== void 0) family.retiredMembers = source.retiredMembers.map(fill);
1238
+ if (source.extraAliases !== void 0) family.extraAliases = source.extraAliases.map(fill);
1239
+ return family;
1240
+ }
1241
+ /**
1242
+ * The family a template yields for `id` (logical id, member, or alias), or
1243
+ * undefined when no template matches or the revision is out of range.
1244
+ */
1245
+ function templateFamilyFor(templates, id) {
1246
+ for (const template of templates) {
1247
+ const match = template.pattern.exec(id);
1248
+ if (match === null) continue;
1249
+ let rev;
1250
+ for (let group = 1; group < match.length && rev === void 0; group++) rev = match[group];
1251
+ if (rev === void 0) continue;
1252
+ const family = instantiateTemplate(template, rev);
1253
+ if (family !== void 0) return family;
1254
+ }
1255
+ }
1256
+ /**
1257
+ * Concrete families for every revision present in `ids`, one per
1258
+ * instantiated id, skipping ids a concrete family in `table` already owns.
1259
+ */
1260
+ function instantiateTemplates(table, ids) {
1261
+ const templates = table.templates;
1262
+ if (templates === void 0 || templates.length === 0) return [];
1263
+ const seen = /* @__PURE__ */ new Set();
1264
+ for (const family of table.families) seen.add(family.id);
1265
+ const out = [];
1266
+ for (const id of ids) {
1267
+ const family = templateFamilyFor(templates, id);
1268
+ if (family === void 0 || seen.has(family.id)) continue;
1269
+ seen.add(family.id);
1270
+ out.push(family);
1271
+ }
1272
+ return out;
1273
+ }
1274
+ /** Provider id → reviewed collapse table, built once from the compiled vocabulary. */
1275
+ function buildCompiledTables() {
1276
+ const { variantFamilies, providerAliases } = collapseVocabulary();
1277
+ const tables = {};
1278
+ for (const compiled of variantFamilies) {
1279
+ const table = tables[compiled.provider] ??= { families: [] };
1280
+ if (compiled.id.includes("{rev}")) (table.templates ??= []).push(compiledTemplate(compiled));
1281
+ else table.families.push(compiledFamily(compiled));
1282
+ }
1283
+ for (const [provider, aliases] of Object.entries(providerAliases)) {
1284
+ tables[provider] ??= { families: [] };
1285
+ tables[provider].providerAliases = aliases;
1286
+ }
1287
+ return tables;
1288
+ }
1289
+ const CURSOR_TIER_ID_PATTERN = /^(.+?)-(extra-high|none|minimal|low|medium|high|xhigh|max)(-fast)?$/;
1290
+ const CURSOR_TIER_BASE_PATTERN = /-(extra-high|none|minimal|low|medium|high|xhigh|max)$/;
1291
+ const CURSOR_THINKING_TOKEN_PATTERN = /(^|-)thinking($|-)/;
1292
+ const CURSOR_TIER_BY_TOKEN = {
1293
+ none: "none",
1294
+ minimal: "minimal",
1295
+ low: "low",
1296
+ medium: "medium",
1297
+ high: "high",
1298
+ "extra-high": "xhigh",
1299
+ xhigh: "xhigh",
1300
+ max: "max"
1301
+ };
1302
+ /** Whether an existing logical row already routes every live member in `members`. */
1303
+ function collapsedCursorLogicalMatches(spec, members) {
1304
+ const routing = spec.thinking?.effortRouting;
1305
+ if (!routing) return false;
1306
+ for (const member of members) {
1307
+ if (spec.requestModelId === member.spec.id) continue;
1308
+ let matched = false;
1309
+ for (const effort of VARIANT_ROUTING_KEYS) if (routing[effort] === member.spec.id) {
1310
+ matched = true;
1311
+ break;
1312
+ }
1313
+ if (!matched) return false;
1314
+ }
1315
+ return true;
1316
+ }
1317
+ /**
1318
+ * Derive safe Cursor per-effort families from live wire ids. A family is
1319
+ * intentionally left expanded when its base is an independent live SKU, any
1320
+ * member already has a thinking ladder, member metadata differs, or a tier
1321
+ * token is also part of a product name.
1322
+ */
1323
+ function deriveCursorEffortFamilies(specs) {
1324
+ const byId = /* @__PURE__ */ new Map();
1325
+ const groups = /* @__PURE__ */ new Map();
1326
+ const candidateBases = /* @__PURE__ */ new Set();
1327
+ for (const spec of specs) {
1328
+ if (!byId.has(spec.id)) byId.set(spec.id, spec);
1329
+ const match = CURSOR_TIER_ID_PATTERN.exec(spec.id);
1330
+ if (!match) continue;
1331
+ const baseId = match[1];
1332
+ const tier = CURSOR_TIER_BY_TOKEN[match[2] ?? ""];
1333
+ const fast = match[3] !== void 0;
1334
+ if (!baseId || !tier) continue;
1335
+ const member = {
1336
+ baseId,
1337
+ fast,
1338
+ spec,
1339
+ tier
1340
+ };
1341
+ const key = `${baseId}\0${fast ? "fast" : "standard"}`;
1342
+ const group = groups.get(key);
1343
+ if (group) group.push(member);
1344
+ else groups.set(key, [member]);
1345
+ candidateBases.add(baseId);
1346
+ }
1347
+ const unsafeBases = /* @__PURE__ */ new Set();
1348
+ for (const group of groups.values()) {
1349
+ const first = group[0];
1350
+ if (!first) continue;
1351
+ const { baseId } = first;
1352
+ const standardGroup = groups.get(`${baseId}\0standard`) ?? [];
1353
+ const standardBase = byId.get(baseId);
1354
+ const laneBase = byId.get(`${baseId}${first.fast ? "-fast" : ""}`);
1355
+ const independentStandardBase = standardBase !== void 0 && !collapsedCursorLogicalMatches(standardBase, standardGroup);
1356
+ const independentLaneBase = laneBase !== void 0 && !collapsedCursorLogicalMatches(laneBase, group);
1357
+ if (independentStandardBase || independentLaneBase || new Set(group.map((member) => member.tier)).size !== group.length || CURSOR_TIER_BASE_PATTERN.test(baseId) || CURSOR_THINKING_TOKEN_PATTERN.test(baseId) || candidateBases.has(`${baseId}-thinking`) || byId.has(`${baseId}-thinking`) || byId.has(`${baseId}-thinking-fast`) || byId.has(`${baseId}-fast-thinking`) || group.some((member) => member.spec.thinking !== void 0 || member.spec.requestModelId !== void 0) || group.some((member) => candidateBases.has(`${baseId}-${member.tier}`))) unsafeBases.add(baseId);
1358
+ }
1359
+ const families = [];
1360
+ for (const group of groups.values()) {
1361
+ const first = group[0];
1362
+ if (!first || group.length < 2 || unsafeBases.has(first.baseId)) continue;
1363
+ if (group.some((member) => member.spec.api !== first.spec.api || member.spec.baseUrl !== first.spec.baseUrl || member.spec.contextWindow !== first.spec.contextWindow || member.spec.maxTokens !== first.spec.maxTokens || member.spec.cursorMaxMode !== first.spec.cursorMaxMode || !Bun.deepEquals(member.spec.cost, first.spec.cost) || !Bun.deepEquals(member.spec.compat, first.spec.compat))) continue;
1364
+ const routes = {};
1365
+ for (const member of group) if (member.tier === "none") routes.off = member.spec.id;
1366
+ else routes[member.tier] = member.spec.id;
1367
+ const efforts = THINKING_EFFORTS.filter((effort) => routes[effort] !== void 0);
1368
+ if (efforts.length === 0) continue;
1369
+ const strippedName = first.spec.name.replace(/\s+(extra-high|none|minimal|low|medium|high|xhigh|max)(\s+fast)?$/i, "").trim();
1370
+ const baseName = strippedName === first.spec.id ? first.baseId : strippedName || first.baseId;
1371
+ const suffix = first.fast ? "-fast" : "";
1372
+ families.push(tierFamily(`${first.baseId}${suffix}`, `${baseName}${first.fast ? " Fast" : ""}`, routes, efforts));
1373
+ }
1374
+ return families;
1375
+ }
1376
+ /** Provider id → reviewed collapse table. The CCA providers diverge on thinking transport. */
1377
+ const REVIEWED_COLLAPSE_TABLES = buildCompiledTables();
1378
+ /**
1379
+ * Return the reviewed collapse table compiled for `provider`, when declared.
1380
+ * Discovery uses this accessor to preserve injectable table seams.
1381
+ */
1382
+ function reviewedCollapseTable(provider) {
1383
+ return REVIEWED_COLLAPSE_TABLES[provider] ?? REVIEWED_COLLAPSE_TABLES[provider.toLowerCase()];
1384
+ }
1385
+ /**
1386
+ * Logical id of the reviewed `provider` family claiming `memberId` as a member
1387
+ * or extra alias, or `undefined` when no reviewed family owns it. Cursor's rich
1388
+ * discovery names lanes with it so they keep the id the legacy-slug collapse
1389
+ * (and the bundled catalog) assigns.
1390
+ */
1391
+ function reviewedVariantFamilyId(provider, memberId) {
1392
+ const table = reviewedCollapseTable(provider);
1393
+ return table ? getAliasIndex(table).resolve(memberId.trim()) : void 0;
1394
+ }
1395
+ /**
1396
+ * The global automatic rule: derive an `X` + `X-thinking` family for every
1397
+ * pair where both ids are live in `specs` (trailing or infix token). Gates:
1398
+ * - both members share the same `api`,
1399
+ * - known pricing must match — all-zero cost rows count as unknown
1400
+ * (aggregators routinely ship them), but twins that BOTH carry real,
1401
+ * differing prices are distinct SKUs and never merge,
1402
+ * - ids claimed by the provider's reviewed table are skipped (curation wins).
1403
+ * The capability surface prefers the thinking member's metadata, then the
1404
+ * bare member's, then the canonical deriver (aggregators often ship
1405
+ * `reasoning: false` and no thinking config on the twin), then a budget
1406
+ * default. `off` routes to the bare id; every supported effort routes to the
1407
+ * thinking id.
1408
+ */
1409
+ function deriveThinkingPairFamilies(specs, table, provider) {
1410
+ const byId = /* @__PURE__ */ new Map();
1411
+ for (const spec of specs) if (!byId.has(spec.id)) byId.set(spec.id, spec);
1412
+ const claimed = table ? getAliasIndex(table) : void 0;
1413
+ const families = [];
1414
+ for (const spec of specs) {
1415
+ const collapsed = provider === void 0 ? void 0 : collapseVariantId(provider, spec.id);
1416
+ const baseId = collapsed?.thinkingVariant ? collapsed.logicalId : stripThinkingVariantSuffix(spec.id);
1417
+ if (baseId === void 0 || baseId === spec.id) continue;
1418
+ const base = byId.get(baseId);
1419
+ if (!base) continue;
1420
+ if (claimed && (claimed.resolve(spec.id) !== void 0 || claimed.resolve(baseId) !== void 0 || claimed.isFamily(spec.id) || claimed.isFamily(baseId))) continue;
1421
+ if (spec.api !== base.api) continue;
1422
+ const specPriced = spec.cost.input !== 0 || spec.cost.output !== 0;
1423
+ const basePriced = base.cost.input !== 0 || base.cost.output !== 0;
1424
+ if (specPriced && basePriced && (spec.cost.input !== base.cost.input || spec.cost.output !== base.cost.output || spec.cost.cacheRead !== base.cost.cacheRead || spec.cost.cacheWrite !== base.cost.cacheWrite)) continue;
1425
+ const surface = derivePairThinkingSurface(spec, base);
1426
+ const routing = { off: base.id };
1427
+ for (const effort of surface.efforts) routing[effort] = spec.id;
1428
+ families.push({
1429
+ id: base.id,
1430
+ name: base.name,
1431
+ members: [base.id, spec.id],
1432
+ routing,
1433
+ thinking: surface
1434
+ });
1435
+ }
1436
+ return families;
1437
+ }
1438
+ function derivePairThinkingSurface(thinkingSpec, baseSpec) {
1439
+ const baked = thinkingSpec.thinking ?? baseSpec.thinking;
1440
+ if (baked && baked.efforts.length > 0) {
1441
+ const { effortRouting: _routing, suppressWhenOff: _suppress, requiresEffort: _required, ...surface } = baked;
1442
+ return surface;
1443
+ }
1444
+ const { compat: _compat, ...policySpec } = thinkingSpec;
1445
+ const derived = resolveModelPolicy({
1446
+ ...policySpec,
1447
+ reasoning: true,
1448
+ thinking: void 0
1449
+ }).thinking;
1450
+ if (derived && derived.efforts.length > 0) {
1451
+ const { effortRouting: _dRouting, suppressWhenOff: _dSuppress, requiresEffort: _dRequired, ...surface } = derived;
1452
+ return surface;
1453
+ }
1454
+ return {
1455
+ mode: "budget",
1456
+ efforts: DEFAULT_PAIR_EFFORTS
1457
+ };
1458
+ }
1459
+ /**
1460
+ * Re-point a stale collapsed spec whose `requestModelId` or routing still
1461
+ * targets a retired wire id. Collapsed snapshots (bundled catalog, cache
1462
+ * rows, previous-generation fallbacks) pass through collapsing untouched, so
1463
+ * a reviewed-table routing fix would otherwise never reach them. Only retired
1464
+ * targets are rewritten — presence-filtered routing decisions from live
1465
+ * discovery stay authoritative for everything else. Per retired entry the
1466
+ * table's route for that effort wins, then the off/first-live-member wire id,
1467
+ * then the route is dropped (falls back to `requestModelId ?? id`). Returns
1468
+ * `spec` by reference when nothing targets a retired id.
1469
+ */
1470
+ function reconcileRetiredRouting(spec, family, retired) {
1471
+ const currentThinking = spec.thinking;
1472
+ const routing = currentThinking?.effortRouting;
1473
+ const requestRetired = spec.requestModelId !== void 0 && retired.has(spec.requestModelId);
1474
+ let routingRetired = false;
1475
+ if (routing !== void 0) for (const key of VARIANT_ROUTING_KEYS) {
1476
+ const target = routing[key];
1477
+ if (target !== void 0 && retired.has(target)) {
1478
+ routingRetired = true;
1479
+ break;
1480
+ }
1481
+ }
1482
+ if (!requestRetired && !routingRetired) return spec;
1483
+ const offTarget = family.routing.off;
1484
+ const fallbackWireId = offTarget !== void 0 && !retired.has(offTarget) ? offTarget : family.members.find((id) => !retired.has(id));
1485
+ const next = { ...spec };
1486
+ if (routingRetired && routing !== void 0 && currentThinking !== void 0) {
1487
+ const nextRouting = {};
1488
+ for (const effortKey of VARIANT_ROUTING_KEYS) {
1489
+ const target = routing[effortKey];
1490
+ if (target === void 0) continue;
1491
+ if (!retired.has(target)) {
1492
+ nextRouting[effortKey] = target;
1493
+ continue;
1494
+ }
1495
+ const tableTarget = family.routing[effortKey];
1496
+ if (tableTarget !== void 0 && !retired.has(tableTarget)) nextRouting[effortKey] = tableTarget;
1497
+ else if (fallbackWireId !== void 0) nextRouting[effortKey] = fallbackWireId;
1498
+ }
1499
+ next.thinking = {
1500
+ ...currentThinking,
1501
+ effortRouting: nextRouting
1502
+ };
1503
+ }
1504
+ if (requestRetired) {
1505
+ if (fallbackWireId !== void 0 && fallbackWireId !== spec.id) next.requestModelId = fallbackWireId;
1506
+ else delete next.requestModelId;
1507
+ }
1508
+ return next;
1509
+ }
1510
+ /**
1511
+ * Refresh a collapsed snapshot's thinking surface in place. Bundled catalog and
1512
+ * prev-generation snapshots freeze a family's transport, budgets, and routing;
1513
+ * discovery emits the canonical id but the exact-id merge never overwrites a
1514
+ * stale `family.id` row (e.g. `gemini-3.1-pro`) nor a recycled `extraAliases`
1515
+ * row (e.g. `gemini-3-flash`). This re-applies the reviewed-table family's thinking,
1516
+ * routing, and default wire id while keeping the spec id (load-bearing for exact
1517
+ * selectors and bundled lookups). Returns `spec` by reference when unchanged.
1518
+ */
1519
+ function refreshCollapsedThinking(spec, family, retired) {
1520
+ const familyThinking = family.thinking;
1521
+ if (!spec.reasoning || familyThinking?.effortBudgets === void 0) return spec;
1522
+ const routing = {};
1523
+ let hasRouting = false;
1524
+ for (const effortKey of VARIANT_ROUTING_KEYS) {
1525
+ const target = family.routing[effortKey];
1526
+ if (target !== void 0 && !retired?.has(target)) {
1527
+ routing[effortKey] = target;
1528
+ hasRouting = true;
1529
+ }
1530
+ }
1531
+ const thinking = { ...familyThinking };
1532
+ if (hasRouting) thinking.effortRouting = routing;
1533
+ if (family.suppressWhenOff) thinking.suppressWhenOff = true;
1534
+ const offTarget = family.routing.off;
1535
+ const requestModelId = offTarget !== void 0 && !retired?.has(offTarget) && offTarget !== spec.id ? offTarget : spec.requestModelId;
1536
+ if (Bun.deepEquals(thinking, spec.thinking) && requestModelId === spec.requestModelId) return spec;
1537
+ return {
1538
+ ...spec,
1539
+ thinking,
1540
+ ...requestModelId !== void 0 ? { requestModelId } : {}
1541
+ };
1542
+ }
1543
+ /**
1544
+ * Re-point a collapsed snapshot's default wire id to the family's declared
1545
+ * {@link EffortVariantFamily.defaultMember} when the snapshot still advertises a
1546
+ * different default. Bundled catalog and cache rows freeze `requestModelId` from
1547
+ * before a family gained a preferred default (Cursor Grok 4.5/4.6 → `-medium`),
1548
+ * and neither the existing-collapsed pass-through nor `refreshCollapsedThinking`
1549
+ * (scoped to `effortBudgets` families) would otherwise correct them — leaving an
1550
+ * effort-less request clamped to the refused `-low` tier (issue #9478). Only
1551
+ * re-points when the target is a live route in the snapshot's own
1552
+ * `effortRouting`. Returns `spec` by reference when unchanged.
1553
+ */
1554
+ function reconcileDefaultMember(spec, family, presentMembers) {
1555
+ const defaultMember = family.defaultMember;
1556
+ if (defaultMember === void 0 || defaultMember === spec.id) return spec;
1557
+ const target = presentMembers === void 0 || presentMembers.has(defaultMember) ? defaultMember : family.members.find((id) => presentMembers.has(id));
1558
+ if (target === void 0 || spec.requestModelId === target) return spec;
1559
+ const routing = spec.thinking?.effortRouting;
1560
+ if (routing === void 0) return spec;
1561
+ for (const key of VARIANT_ROUTING_KEYS) if (routing[key] === target) return {
1562
+ ...spec,
1563
+ requestModelId: target
1564
+ };
1565
+ return spec;
1566
+ }
1567
+ /**
1568
+ * Whether a Cursor wire id names an extended tier that upstream serves only in
1569
+ * max mode. The compiled taxonomy identifies `xhigh`/`extra-high`/`max`
1570
+ * efforts and their optional service lanes. This is an inference, not an
1571
+ * upstream marker: it is the only per-tier signal available for bundled rows
1572
+ * and for routes live discovery never advertised.
1573
+ */
1574
+ function isCursorMaxModeWireId(wireModelId) {
1575
+ const effort = collapseVariantId("cursor", wireModelId).effort;
1576
+ return effort === "xhigh" || effort === "max";
1577
+ }
1578
+ /**
1579
+ * Recover Cursor's max-mode marker for a bundled collapsed row. The bundled
1580
+ * snapshot may contain only the logical row, but its effort routing still
1581
+ * records the wire ids, so {@link isCursorMaxModeWireId} preserves the
1582
+ * transport invariant even when live discovery contributes no raw members.
1583
+ */
1584
+ function reconcileCursorMaxModeFromRouting(spec) {
1585
+ if (spec.provider !== "cursor" || spec.cursorMaxMode === true) return spec;
1586
+ const routing = spec.thinking?.effortRouting;
1587
+ if (routing === void 0) return spec;
1588
+ return Object.values(routing).some((target) => typeof target === "string" && isCursorMaxModeWireId(target)) ? {
1589
+ ...spec,
1590
+ cursorMaxMode: true
1591
+ } : spec;
1592
+ }
1593
+ /**
1594
+ * Index the discovered `max_mode` marker of every live Cursor member by its own
1595
+ * wire id. The collapsed row's `cursorMaxMode` is an OR across members, so it
1596
+ * says nothing per tier; the transport needs the marker addressable by the wire
1597
+ * id it actually sends, because upstream marks tiers the slug cannot identify
1598
+ * (the whole Opus `-fast` lane is max-mode, `-low-fast` included). Returns
1599
+ * `undefined` when no member carries a marker, so unmarked rosters add no field.
1600
+ */
1601
+ function cursorMaxModeRoutesOf(provider, memberSpecs) {
1602
+ if (provider !== "cursor") return void 0;
1603
+ let routes;
1604
+ for (const member of memberSpecs) {
1605
+ if (member.cursorMaxMode === void 0) continue;
1606
+ routes ??= {};
1607
+ routes[member.id] = member.cursorMaxMode;
1608
+ }
1609
+ return routes;
1610
+ }
1611
+ /**
1612
+ * Lift Cursor's max-mode markers from live member rows onto an already-collapsed
1613
+ * snapshot. Bundled catalog and cache rows froze the flag from `memberSpecs[0]`
1614
+ * — the `-none`/`-low` tier — so the committed `gpt-5.6-*` / `cursor-grok-*`
1615
+ * rows carry `cursorMaxMode: false`. The existing-collapsed pass-through keeps
1616
+ * the snapshot verbatim, so a live `GetUsableModels` roster that marks the
1617
+ * `-xhigh`/`-max` tiers would be discarded and max-tier requests would keep
1618
+ * sending `max_mode: false` on a max-mode-only wire id. The row-level flag
1619
+ * mirrors the fresh-collapse aggregation: only the positive case is lifted, so
1620
+ * a roster that marks nothing leaves the snapshot alone. The per-wire-id
1621
+ * markers are merged on top of the snapshot's own so live rows win per route.
1622
+ * Returns `spec` by reference when unchanged.
1623
+ */
1624
+ function reconcileCursorMaxMode(spec, memberSpecs) {
1625
+ const routes = cursorMaxModeRoutesOf(spec.provider, memberSpecs);
1626
+ const lifts = spec.cursorMaxMode !== true && memberSpecs.some((member) => member.cursorMaxMode === true);
1627
+ if (routes === void 0 && !lifts) return spec;
1628
+ return {
1629
+ ...spec,
1630
+ ...lifts ? { cursorMaxMode: true } : {},
1631
+ ...routes === void 0 ? {} : { cursorMaxModeRoutes: {
1632
+ ...spec.cursorMaxModeRoutes,
1633
+ ...routes
1634
+ } }
1635
+ };
1636
+ }
1637
+ /**
1638
+ * Collapse every family in `table` found in `specs`. Non-member specs pass
1639
+ * through verbatim (by reference), order preserved; the collapsed spec
1640
+ * replaces the first occurrence of its family.
1641
+ */
1642
+ function collapseWithTable(specs, table) {
1643
+ const byId = /* @__PURE__ */ new Map();
1644
+ for (const spec of specs) if (!byId.has(spec.id)) byId.set(spec.id, spec);
1645
+ /** family id → spec to emit at the family's first occurrence. */
1646
+ const replacement = /* @__PURE__ */ new Map();
1647
+ /** spec ids that belong to a touched family (members + logical id). */
1648
+ const familyIdBySpecId = /* @__PURE__ */ new Map();
1649
+ const instantiated = instantiateTemplates(table, byId.keys());
1650
+ const families = instantiated.length === 0 ? table.families : [...table.families, ...instantiated];
1651
+ for (const family of families) {
1652
+ const retired = family.retiredMembers !== void 0 && family.retiredMembers.length > 0 ? new Set(family.retiredMembers) : void 0;
1653
+ const existing = byId.get(family.id);
1654
+ const existingCollapsed = existing !== void 0 && (existing.requestModelId !== void 0 || existing.thinking?.effortRouting !== void 0);
1655
+ const reconciled = existing !== void 0 && existingCollapsed && retired !== void 0 ? reconcileRetiredRouting(existing, family, retired) : existing;
1656
+ const rawPresent = family.members.filter((id) => byId.has(id) && !(id === family.id && existingCollapsed));
1657
+ if (rawPresent.length === 0) {
1658
+ const refreshed = existing !== void 0 && existingCollapsed ? reconcileCursorMaxModeFromRouting(reconcileDefaultMember(refreshCollapsedThinking(reconciled ?? existing, family, retired), family)) : reconciled;
1659
+ if (refreshed !== void 0 && refreshed !== existing) {
1660
+ familyIdBySpecId.set(family.id, family.id);
1661
+ replacement.set(family.id, refreshed);
1662
+ }
1663
+ continue;
1664
+ }
1665
+ for (const id of rawPresent) familyIdBySpecId.set(id, family.id);
1666
+ if (existing) familyIdBySpecId.set(family.id, family.id);
1667
+ const memberSpecs = [];
1668
+ for (const id of rawPresent) {
1669
+ const member = byId.get(id);
1670
+ if (member !== void 0) memberSpecs.push(member);
1671
+ }
1672
+ if (existingCollapsed && reconciled !== void 0) {
1673
+ replacement.set(family.id, reconcileCursorMaxMode(reconcileDefaultMember(reconciled, family, new Set(rawPresent)), memberSpecs));
1674
+ continue;
1675
+ }
1676
+ const firstMember = memberSpecs[0];
1677
+ if (firstMember === void 0) continue;
1678
+ const presentSet = new Set(rawPresent);
1679
+ const routing = {};
1680
+ let hasRouting = false;
1681
+ let hasEffortRoute = false;
1682
+ let usedAbsentEffortRoute = false;
1683
+ for (const effort of VARIANT_ROUTING_KEYS) {
1684
+ const target = family.routing[effort];
1685
+ const targetPresent = target !== void 0 && presentSet.has(target);
1686
+ const preserveAbsentEffort = target !== void 0 && effort !== "off" && family.preserveAbsentEffortRoutes === true;
1687
+ if (target !== void 0 && (targetPresent || preserveAbsentEffort) && !retired?.has(target)) {
1688
+ routing[effort] = target;
1689
+ hasRouting = true;
1690
+ if (effort !== "off") hasEffortRoute = true;
1691
+ if (!targetPresent && effort !== "off") usedAbsentEffortRoute = true;
1692
+ }
1693
+ }
1694
+ const reasoning = memberSpecs.some((spec) => spec.reasoning) || hasEffortRoute;
1695
+ const familyThinking = family.thinking;
1696
+ const thinking = familyThinking ? { ...familyThinking } : void 0;
1697
+ if (thinking !== void 0) {
1698
+ if (hasRouting) thinking.effortRouting = routing;
1699
+ if (family.suppressWhenOff) thinking.suppressWhenOff = true;
1700
+ }
1701
+ const input = [];
1702
+ if (memberSpecs.some((spec) => spec.input.includes("text"))) input.push("text");
1703
+ if (memberSpecs.some((spec) => spec.input.includes("image"))) input.push("image");
1704
+ const cursorMaxMode = memberSpecs.some((spec) => spec.cursorMaxMode === true) ? true : void 0;
1705
+ const cursorMaxModeRoutes = cursorMaxModeRoutesOf(firstMember.provider, memberSpecs);
1706
+ const collapsed = {
1707
+ ...firstMember,
1708
+ id: family.id,
1709
+ name: family.name,
1710
+ reasoning,
1711
+ input,
1712
+ contextWindow: maxOrNull(memberSpecs.map((spec) => spec.contextWindow)),
1713
+ maxTokens: maxOrNull(memberSpecs.map((spec) => spec.maxTokens)),
1714
+ ...cursorMaxMode === void 0 ? {} : { cursorMaxMode },
1715
+ ...cursorMaxModeRoutes === void 0 ? {} : { cursorMaxModeRoutes }
1716
+ };
1717
+ if (memberSpecs.some((spec) => spec.isProviderDefault === true)) collapsed.isProviderDefault = true;
1718
+ const defaultWireId = (family.defaultMember !== void 0 && presentSet.has(family.defaultMember) && !retired?.has(family.defaultMember) ? family.defaultMember : void 0) ?? rawPresent.find((id) => !retired?.has(id)) ?? rawPresent[0];
1719
+ if (defaultWireId === void 0) continue;
1720
+ if (defaultWireId === family.id) {
1721
+ if (usedAbsentEffortRoute) collapsed.requestModelId = defaultWireId;
1722
+ else delete collapsed.requestModelId;
1723
+ } else collapsed.requestModelId = defaultWireId;
1724
+ if (reasoning && thinking !== void 0) collapsed.thinking = thinking;
1725
+ else delete collapsed.thinking;
1726
+ replacement.set(family.id, collapsed);
1727
+ }
1728
+ for (const family of table.families) {
1729
+ if (family.extraAliases === void 0) continue;
1730
+ const retired = family.retiredMembers !== void 0 && family.retiredMembers.length > 0 ? new Set(family.retiredMembers) : void 0;
1731
+ for (const alias of family.extraAliases) {
1732
+ if (alias === family.id || familyIdBySpecId.has(alias)) continue;
1733
+ const aliasSpec = byId.get(alias);
1734
+ if (aliasSpec === void 0) continue;
1735
+ const refreshed = refreshCollapsedThinking(aliasSpec, family, retired);
1736
+ if (refreshed !== aliasSpec) {
1737
+ familyIdBySpecId.set(alias, alias);
1738
+ replacement.set(alias, refreshed);
1739
+ }
1740
+ }
1741
+ }
1742
+ if (replacement.size === 0) return [...specs];
1743
+ const emitted = /* @__PURE__ */ new Set();
1744
+ const out = [];
1745
+ for (const spec of specs) {
1746
+ const familyId = familyIdBySpecId.get(spec.id);
1747
+ if (familyId === void 0) {
1748
+ out.push(spec);
1749
+ continue;
1750
+ }
1751
+ if (emitted.has(familyId)) continue;
1752
+ emitted.add(familyId);
1753
+ const familySpec = replacement.get(familyId);
1754
+ if (familySpec !== void 0) out.push(familySpec);
1755
+ }
1756
+ return out;
1757
+ }
1758
+ /**
1759
+ * Re-key model-to-model configuration after collapse removes a referenced
1760
+ * member id. Qualified targets keep their provider; bare targets remain bare.
1761
+ */
1762
+ function retargetCollapsedModelReferences(specs) {
1763
+ const liveIdsByProvider = /* @__PURE__ */ new Map();
1764
+ for (const spec of specs) {
1765
+ const provider = spec.provider.toLowerCase();
1766
+ let liveIds = liveIdsByProvider.get(provider);
1767
+ if (!liveIds) {
1768
+ liveIds = /* @__PURE__ */ new Set();
1769
+ liveIdsByProvider.set(provider, liveIds);
1770
+ }
1771
+ liveIds.add(spec.id.toLowerCase());
1772
+ }
1773
+ for (let index = 0; index < specs.length; index++) {
1774
+ const spec = specs[index];
1775
+ if (!spec) continue;
1776
+ const contextPromotionTarget = resolveCollapsedModelReference(spec.contextPromotionTarget, spec.provider, liveIdsByProvider);
1777
+ const compactionModel = resolveCollapsedModelReference(spec.compactionModel, spec.provider, liveIdsByProvider);
1778
+ const webSearchModel = resolveCollapsedModelReference(spec.webSearchModel, spec.provider, liveIdsByProvider);
1779
+ const imageModel = resolveCollapsedModelReference(spec.imageModel, spec.provider, liveIdsByProvider);
1780
+ if (contextPromotionTarget === spec.contextPromotionTarget && compactionModel === spec.compactionModel && webSearchModel === spec.webSearchModel && imageModel === spec.imageModel) continue;
1781
+ specs[index] = {
1782
+ ...spec,
1783
+ contextPromotionTarget,
1784
+ compactionModel,
1785
+ webSearchModel,
1786
+ imageModel
1787
+ };
1788
+ }
1789
+ }
1790
+ function resolveCollapsedModelReference(target, currentProvider, liveIdsByProvider) {
1791
+ if (target === void 0) return void 0;
1792
+ const separator = target.indexOf("/");
1793
+ const provider = separator >= 0 ? target.slice(0, separator) : currentProvider;
1794
+ const providerId = provider.toLowerCase();
1795
+ const normalizedModelId = (separator >= 0 ? target.slice(separator + 1) : target).trim().toLowerCase();
1796
+ const liveIds = liveIdsByProvider.get(providerId);
1797
+ if (liveIds?.has(normalizedModelId)) return target;
1798
+ const alias = resolveRegisteredVariantAlias(provider, normalizedModelId);
1799
+ if (alias === void 0 || !liveIds?.has(alias.toLowerCase())) return target;
1800
+ return separator >= 0 ? `${provider}/${alias}` : alias;
1801
+ }
1802
+ /**
1803
+ * Collapse a full mixed-provider list: per provider, the compiled reviewed table, Cursor's
1804
+ * conservative live effort-sibling rule, and the automatic `X`/`X-thinking`
1805
+ * pair rule. Used by the catalog generator; the runtime equivalent lives at
1806
+ * the model-manager merge point. Output is regrouped by provider — callers
1807
+ * re-sort.
1808
+ */
1809
+ function collapseVariants(specs, opts) {
1810
+ if (opts?.table !== void 0) return collapseWithTable(specs, opts.table);
1811
+ const byProvider = /* @__PURE__ */ new Map();
1812
+ for (const spec of specs) {
1813
+ const slice = byProvider.get(spec.provider);
1814
+ if (slice) slice.push(spec);
1815
+ else byProvider.set(spec.provider, [spec]);
1816
+ }
1817
+ const out = [];
1818
+ for (const [provider, slice] of byProvider) {
1819
+ const table = reviewedCollapseTable(provider);
1820
+ let result = table ? collapseWithTable(slice, table) : slice;
1821
+ if (provider === "cursor") {
1822
+ const cursorDerived = deriveCursorEffortFamilies(result);
1823
+ if (cursorDerived.length > 0) result = collapseWithTable(result, { families: cursorDerived });
1824
+ }
1825
+ const derived = deriveThinkingPairFamilies(result, table, provider);
1826
+ if (derived.length > 0) result = collapseWithTable(result, { families: derived });
1827
+ registerCollapsedVariantAliases(provider, result);
1828
+ out.push(...result);
1829
+ }
1830
+ retargetCollapsedModelReferences(out);
1831
+ return out;
1832
+ }
1833
+ /**
1834
+ * Alias index over a collapse table (or the live families observed at
1835
+ * runtime). Templated families are materialized on first lookup of any id
1836
+ * they match, so a revision discovery has never advertised still resolves.
1837
+ */
1838
+ var VariantAliasIndex = class {
1839
+ /** lowercased retired id → replacement model id. */
1840
+ #forward = /* @__PURE__ */ new Map();
1841
+ /**
1842
+ * lowercased provider-scoped alias → replacement model id. Kept apart from
1843
+ * `#forward` so bare-id and reverse lookups never see it.
1844
+ */
1845
+ providerScoped = /* @__PURE__ */ new Map();
1846
+ /** replacement model id → retired ids that resolve to it. */
1847
+ #reverse = /* @__PURE__ */ new Map();
1848
+ /** Collapsed logical ids declared by the table or observed at runtime. */
1849
+ #familyIds = /* @__PURE__ */ new Set();
1850
+ #templates;
1851
+ constructor(templates = []) {
1852
+ this.#templates = templates;
1853
+ }
1854
+ /** Register `from` → `to`; false when `from` is already claimed. */
1855
+ add(from, to) {
1856
+ if (from === to || this.#forward.has(from.toLowerCase())) return false;
1857
+ this.#forward.set(from.toLowerCase(), to);
1858
+ const sources = this.#reverse.get(to);
1859
+ if (sources) sources.push(from);
1860
+ else this.#reverse.set(to, [from]);
1861
+ return true;
1862
+ }
1863
+ /** Register a family: its logical id plus every member and extra alias. */
1864
+ addFamily(family) {
1865
+ this.#familyIds.add(family.id);
1866
+ for (const member of family.members) this.add(member, family.id);
1867
+ for (const alias of family.extraAliases ?? []) this.add(alias, family.id);
1868
+ }
1869
+ markFamily(id) {
1870
+ this.#familyIds.add(id);
1871
+ }
1872
+ /** Replacement model id for a retired/member id (case-insensitive). */
1873
+ resolve(id) {
1874
+ const lower = id.toLowerCase();
1875
+ this.#learn(lower);
1876
+ return this.#forward.get(lower);
1877
+ }
1878
+ /** Whether `id` is a collapsed logical id of this index. */
1879
+ isFamily(id) {
1880
+ this.#learn(id);
1881
+ return this.#familyIds.has(id);
1882
+ }
1883
+ /** Retired ids that resolve to logical `id`. */
1884
+ sourcesOf(id) {
1885
+ this.#learn(id);
1886
+ return this.#reverse.get(id);
1887
+ }
1888
+ /** Materialize the template family that owns `id`, once. */
1889
+ #learn(id) {
1890
+ if (this.#templates.length === 0) return;
1891
+ const family = templateFamilyFor(this.#templates, id);
1892
+ if (family === void 0 || this.#familyIds.has(family.id)) return;
1893
+ this.addFamily(family);
1894
+ }
1895
+ };
1896
+ const dynamicAliasIndexes = /* @__PURE__ */ new Map();
1897
+ const kAliasIndex = Symbol("compat-collapse.aliasIndex");
1898
+ /**
1899
+ * Persist aliases embedded in collapsed routing so generated catalog rows and
1900
+ * newly discovered families expose the same selector migrations as reviewed tables.
1901
+ */
1902
+ function registerCollapsedVariantAliases(provider, specs) {
1903
+ const providerId = provider.toLowerCase();
1904
+ let index = dynamicAliasIndexes.get(providerId);
1905
+ for (const spec of specs) {
1906
+ const routing = spec.thinking?.effortRouting;
1907
+ if (!routing) continue;
1908
+ let registered = false;
1909
+ for (const effort of VARIANT_ROUTING_KEYS) {
1910
+ const source = routing[effort];
1911
+ if (!source || source === spec.id) continue;
1912
+ index ??= new VariantAliasIndex();
1913
+ registered = index.add(source, spec.id) || registered;
1914
+ }
1915
+ if (spec.requestModelId && spec.requestModelId !== spec.id) {
1916
+ index ??= new VariantAliasIndex();
1917
+ registered = index.add(spec.requestModelId, spec.id) || registered;
1918
+ }
1919
+ if (registered) index?.markFamily(spec.id);
1920
+ }
1921
+ if (index) dynamicAliasIndexes.set(providerId, index);
1922
+ }
1923
+ function resolveRegisteredVariantAlias(provider, normalizedModelId) {
1924
+ const providerId = provider.toLowerCase();
1925
+ const table = reviewedCollapseTable(provider) ?? reviewedCollapseTable(providerId);
1926
+ return (table ? getAliasIndex(table).resolve(normalizedModelId) : void 0) ?? dynamicAliasIndexes.get(providerId)?.resolve(normalizedModelId);
1927
+ }
1928
+ function getAliasIndex(table) {
1929
+ const cached = Reflect.get(table, kAliasIndex);
1930
+ if (cached instanceof VariantAliasIndex) return cached;
1931
+ const index = new VariantAliasIndex(table.templates);
1932
+ for (const family of table.families) index.addFamily(family);
1933
+ for (const alias in table.providerAliases) {
1934
+ const target = table.providerAliases[alias];
1935
+ if (target !== void 0 && alias !== target) index.providerScoped.set(alias.toLowerCase(), target);
1936
+ }
1937
+ Reflect.set(table, kAliasIndex, index);
1938
+ return index;
1939
+ }
1940
+ function maxOrNull(values) {
1941
+ const known = values.filter((v) => v != null);
1942
+ return known.length ? Math.max(...known) : null;
1943
+ }
1944
+ //#endregion
1945
+ export { decodeJsonValue as a, pb as c, create as i, toBinary as l, isCursorMaxModeWireId as n, encodeJsonValue as o, reviewedVariantFamilyId as r, fromBinary as s, collapseVariants as t, buildModel as u };