@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,593 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { p as LRUCache } from "./src-BhinCSpi.mjs";
4
+ import { f as parseRevisionPrefix, h as isRecord, l as formatRevision, s as taxonomy, t as globMatch } from "./cascade-BWjRTD1q.mjs";
5
+ import "./utils-DrDwmNtu.mjs";
6
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/taxonomy.ts
7
+ /**
8
+ * Runtime model-identity taxonomy: classifies wire model ids into
9
+ * `(class, family, revision)` ranks, applies reviewed identity overrides, and
10
+ * exposes the collapse/discovery vocabularies.
11
+ *
12
+ * Faithful port of the o2 reference (`taxonomy.rs` / `classify.rs`):
13
+ * matchers rank `exact(4) > bounded(3) > namespace(2) > prefix(1) > glob(0)`
14
+ * with token byte length as tiebreak; equal cross-class or cross-family ranks
15
+ * throw unless classification is `lenient` (discovery normalization).
16
+ */
17
+ /** Two classes, families, or reviewed override patterns tie for one model id. */
18
+ var AmbiguousIdentityError = class extends Error {
19
+ model;
20
+ first;
21
+ second;
22
+ constructor(model, first, second, kind) {
23
+ super(`ambiguous ${kind} for \`${model}\`: \`${first}\` and \`${second}\` tie`);
24
+ this.model = model;
25
+ this.first = first;
26
+ this.second = second;
27
+ this.name = "AmbiguousIdentityError";
28
+ }
29
+ };
30
+ const MATCHER_RANK = {
31
+ exact: 4,
32
+ bounded: 3,
33
+ namespace: 2,
34
+ prefix: 1,
35
+ glob: 0
36
+ };
37
+ function bareOf(id) {
38
+ const slash = id.lastIndexOf("/");
39
+ return slash === -1 ? id : id.slice(slash + 1);
40
+ }
41
+ function boundedMatch(value, token) {
42
+ if (value === token) return true;
43
+ if (!value.startsWith(token)) return false;
44
+ const next = value.charCodeAt(token.length);
45
+ return next === 45 || next === 95 || next === 46 || next === 58 || next >= 48 && next <= 57;
46
+ }
47
+ function matcherMatches(matcher, lower, bare) {
48
+ switch (matcher.kind) {
49
+ case "exact": return bare === matcher.token;
50
+ case "bounded": return boundedMatch(bare, matcher.token);
51
+ case "namespace": {
52
+ const parts = matcher.bounded ? lower.split(/[/.:]/) : lower.split("/");
53
+ for (const part of parts) {
54
+ if (!part) continue;
55
+ if (matcher.bounded ? boundedMatch(part, matcher.token) : part === matcher.token) return true;
56
+ }
57
+ return false;
58
+ }
59
+ case "prefix": return bare.startsWith(matcher.token);
60
+ case "glob": return globMatch(matcher.token, bare);
61
+ }
62
+ }
63
+ function nonWildcardBytes(glob) {
64
+ let count = 0;
65
+ for (let i = 0; i < glob.length; i++) if (glob[i] !== "*") count++;
66
+ return count;
67
+ }
68
+ function rankFamilies(cls, subject) {
69
+ let winner;
70
+ let tied;
71
+ for (const family of cls.families) {
72
+ if (!globMatch(family.glob, subject)) continue;
73
+ const rank = [family.priority, nonWildcardBytes(family.glob)];
74
+ if (winner && winner.rank[0] === rank[0] && winner.rank[1] === rank[1] && winner.id !== family.id) tied = [winner.id, family.id];
75
+ else if (!winner || winner.rank[0] < rank[0] || winner.rank[0] === rank[0] && winner.rank[1] < rank[1]) {
76
+ winner = {
77
+ rank,
78
+ id: family.id
79
+ };
80
+ tied = void 0;
81
+ }
82
+ }
83
+ return {
84
+ winner,
85
+ tied
86
+ };
87
+ }
88
+ function stripClassNamespace(cls, bare) {
89
+ const separator = bare.search(/[.:]/);
90
+ if (separator <= 0 || separator === bare.length - 1) return void 0;
91
+ const namespace = bare.slice(0, separator);
92
+ if (!cls.matchers.some((matcher) => matcher.token === namespace)) return void 0;
93
+ return bare.slice(separator + 1);
94
+ }
95
+ function classifyFamily(cls, bare, model, lenient) {
96
+ const initial = rankFamilies(cls, bare);
97
+ const tied = initial.tied;
98
+ if (!tied) return initial.winner?.id;
99
+ const scoped = stripClassNamespace(cls, bare);
100
+ if (scoped !== void 0) {
101
+ const rescored = rankFamilies(cls, scoped);
102
+ if (rescored.winner && !rescored.tied) return rescored.winner.id;
103
+ }
104
+ if (lenient) return void 0;
105
+ throw new AmbiguousIdentityError(model, tied[0], tied[1], "family");
106
+ }
107
+ function extractRevision(cls, bare) {
108
+ if (cls.skipBare.includes(bare)) return void 0;
109
+ for (const rule of cls.revisionPrefixes) {
110
+ let tail;
111
+ if (rule.anywhere) {
112
+ const start = bare.indexOf(rule.prefix);
113
+ if (start !== -1) tail = bare.slice(start + rule.prefix.length);
114
+ } else if (bare.startsWith(rule.prefix)) tail = bare.slice(rule.prefix.length);
115
+ if (tail === void 0) continue;
116
+ const digit = tail.search(/[0-9]/);
117
+ if (digit === -1) return void 0;
118
+ const revision = parseRevisionPrefix(tail.slice(digit));
119
+ return revision ? formatRevision(revision) : void 0;
120
+ }
121
+ }
122
+ function classifyRanks(model, lenient) {
123
+ const lower = model.trim().toLowerCase();
124
+ const bare = bareOf(lower);
125
+ let winner;
126
+ let tied;
127
+ for (const cls of taxonomy.classes) for (const matcher of cls.matchers) {
128
+ if (!matcherMatches(matcher, lower, bare)) continue;
129
+ const rank = [MATCHER_RANK[matcher.kind], matcher.token.length];
130
+ if (winner && winner.rank[0] === rank[0] && winner.rank[1] === rank[1] && winner.cls.id !== cls.id) tied = [winner.cls.id, cls.id];
131
+ else if (!winner || winner.rank[0] < rank[0] || winner.rank[0] === rank[0] && winner.rank[1] < rank[1]) {
132
+ winner = {
133
+ rank,
134
+ cls
135
+ };
136
+ tied = void 0;
137
+ }
138
+ }
139
+ if (tied) {
140
+ if (lenient) return { class: "unknown" };
141
+ throw new AmbiguousIdentityError(lower, tied[0], tied[1], "class");
142
+ }
143
+ if (!winner) return { class: "unknown" };
144
+ const ranks = { class: winner.cls.id };
145
+ const family = classifyFamily(winner.cls, bare, lower, lenient);
146
+ if (family !== void 0) ranks.family = family;
147
+ const revision = extractRevision(winner.cls, bare);
148
+ if (revision !== void 0) ranks.revision = revision;
149
+ return ranks;
150
+ }
151
+ function ranksInClass(classId, model, lenient) {
152
+ const cls = taxonomy.classes.find((candidate) => candidate.id === classId);
153
+ if (!cls) return {};
154
+ const lower = model.trim().toLowerCase();
155
+ const bare = bareOf(lower);
156
+ const out = {};
157
+ const family = classifyFamily(cls, bare, lower, lenient);
158
+ if (family !== void 0) out.family = family;
159
+ const revision = extractRevision(cls, bare);
160
+ if (revision !== void 0) out.revision = revision;
161
+ return out;
162
+ }
163
+ let overrideIndexes;
164
+ function getOverrideIndexes() {
165
+ if (overrideIndexes !== void 0) return overrideIndexes;
166
+ const exact = /* @__PURE__ */ new Map();
167
+ const patterns = [];
168
+ const classes = taxonomy.classes;
169
+ for (const cls of classes) for (const override of cls.overrides) {
170
+ if (override.model === void 0) {
171
+ if (override.glob !== void 0) patterns.push({
172
+ override,
173
+ glob: override.glob,
174
+ provider: override.provider?.toLowerCase(),
175
+ specificity: nonWildcardBytes(override.glob)
176
+ });
177
+ continue;
178
+ }
179
+ const key = override.model.toLowerCase();
180
+ let bucket = exact.get(key);
181
+ if (bucket === void 0) {
182
+ bucket = {
183
+ byProvider: /* @__PURE__ */ new Map(),
184
+ agnostic: void 0
185
+ };
186
+ exact.set(key, bucket);
187
+ }
188
+ if (override.provider !== void 0) {
189
+ const providerKey = override.provider.toLowerCase();
190
+ if (!bucket.byProvider.has(providerKey)) bucket.byProvider.set(providerKey, override);
191
+ } else bucket.agnostic ??= override;
192
+ }
193
+ overrideIndexes = {
194
+ exact,
195
+ patterns
196
+ };
197
+ return overrideIndexes;
198
+ }
199
+ function overrideIsActive(override, observedAtMs) {
200
+ return override.expiresAtMs === void 0 || observedAtMs === void 0 || observedAtMs < override.expiresAtMs;
201
+ }
202
+ function rankPatternOverrides(patterns, provider, bareModel, observedAtMs) {
203
+ let winner;
204
+ let tied;
205
+ for (const pattern of patterns) {
206
+ const { override, specificity } = pattern;
207
+ if (pattern.provider !== provider || !overrideIsActive(override, observedAtMs)) continue;
208
+ if (!globMatch(pattern.glob, bareModel)) continue;
209
+ if (winner?.specificity === specificity) tied = [winner.override, override];
210
+ else if (winner === void 0 || winner.specificity < specificity) {
211
+ winner = {
212
+ specificity,
213
+ override
214
+ };
215
+ tied = void 0;
216
+ }
217
+ }
218
+ return {
219
+ winner,
220
+ tied
221
+ };
222
+ }
223
+ function findIdentityOverride(provider, bareModel, observedAtMs, lenient) {
224
+ const lowerProvider = provider.toLowerCase();
225
+ const lowerBareModel = bareModel.toLowerCase();
226
+ const indexes = getOverrideIndexes();
227
+ const bucket = indexes.exact.get(lowerBareModel);
228
+ if (bucket !== void 0) {
229
+ const scoped = bucket.byProvider.get(lowerProvider);
230
+ if (scoped !== void 0 && overrideIsActive(scoped, observedAtMs)) return scoped;
231
+ const agnostic = bucket.agnostic;
232
+ if (agnostic !== void 0 && overrideIsActive(agnostic, observedAtMs)) return agnostic;
233
+ }
234
+ const scoped = rankPatternOverrides(indexes.patterns, lowerProvider, lowerBareModel, observedAtMs);
235
+ const ranked = scoped.winner === void 0 && scoped.tied === void 0 ? rankPatternOverrides(indexes.patterns, void 0, lowerBareModel, observedAtMs) : scoped;
236
+ if (ranked.tied !== void 0) {
237
+ if (lenient) return void 0;
238
+ throw new AmbiguousIdentityError(lowerBareModel, ranked.tied[0].id, ranked.tied[1].id, "override");
239
+ }
240
+ return ranked.winner?.override;
241
+ }
242
+ /**
243
+ * Collapses a declared thinking or effort suffix from a model identifier.
244
+ * Exact `effort-family` aliases collapse to the family's logical model
245
+ * without assigning an effort; provider-scoped effort lanes additionally
246
+ * collapse an effort suffix wedged before the lane token.
247
+ */
248
+ function collapseVariantId(provider, model) {
249
+ const { collapse } = taxonomy;
250
+ const lower = model.toLowerCase();
251
+ for (const family of collapse.effortFamilies) if (family.provider === provider.toLowerCase() && family.aliases.includes(lower)) return {
252
+ logicalId: family.logical,
253
+ thinkingVariant: false
254
+ };
255
+ const bare = bareOf(lower);
256
+ let winner;
257
+ for (const rule of collapse.suffixes) {
258
+ if (!lower.endsWith(rule.suffix)) continue;
259
+ if (rule.exceptBarePrefix !== void 0 && bare.startsWith(rule.exceptBarePrefix)) continue;
260
+ if (!winner || rule.suffix.length > winner.suffix.length) winner = rule;
261
+ }
262
+ if (winner) {
263
+ const collapsed = {
264
+ logicalId: model.slice(0, model.length - winner.suffix.length),
265
+ thinkingVariant: winner.thinking === true
266
+ };
267
+ if (winner.effort !== void 0) collapsed.effort = winner.effort;
268
+ return collapsed;
269
+ }
270
+ for (const lane of collapse.lanes) {
271
+ if (!lane.providers.some((candidate) => candidate === provider.toLowerCase()) || !lower.endsWith(lane.suffix)) continue;
272
+ const trimmed = lower.slice(0, lower.length - lane.suffix.length);
273
+ const trimmedBare = bareOf(trimmed);
274
+ if (lane.barePrefix !== void 0 && !trimmedBare.startsWith(lane.barePrefix)) continue;
275
+ let effortRule;
276
+ for (const rule of collapse.suffixes) {
277
+ if (rule.effort === void 0 || !trimmed.endsWith(rule.suffix)) continue;
278
+ if (rule.exceptBarePrefix !== void 0 && trimmedBare.startsWith(rule.exceptBarePrefix)) continue;
279
+ if (!effortRule || rule.suffix.length > effortRule.suffix.length) effortRule = rule;
280
+ }
281
+ if (!effortRule) continue;
282
+ const base = model.slice(0, trimmed.length - effortRule.suffix.length);
283
+ if (!base || base.endsWith("/")) continue;
284
+ return {
285
+ logicalId: `${base}${model.slice(trimmed.length)}`,
286
+ effort: effortRule.effort,
287
+ thinkingVariant: false
288
+ };
289
+ }
290
+ return {
291
+ logicalId: model,
292
+ thinkingVariant: false
293
+ };
294
+ }
295
+ /**
296
+ * Removes the first declared thinking-variant suffix token from a model id.
297
+ *
298
+ * Unlike {@link collapseVariantId}, this vocabulary-only helper also handles an
299
+ * infix token used to pair live discovery siblings. Negated forms such as
300
+ * `non-thinking` and `no-thinking` are not variants.
301
+ */
302
+ function stripThinkingVariantSuffix(model) {
303
+ const lower = model.toLowerCase();
304
+ for (const token of taxonomy.collapse.pairTokens) {
305
+ const needle = `-${token}`;
306
+ let searchFrom = 0;
307
+ while (searchFrom < lower.length) {
308
+ const index = lower.indexOf(needle, searchFrom);
309
+ if (index === -1) break;
310
+ const end = index + needle.length;
311
+ const next = lower.charCodeAt(end);
312
+ const followedByTokenCharacter = next >= 48 && next <= 57 || next >= 97 && next <= 122;
313
+ let wordStart = index;
314
+ while (wordStart > 0) {
315
+ const code = lower.charCodeAt(wordStart - 1);
316
+ if (!(code >= 48 && code <= 57 || code >= 97 && code <= 122)) break;
317
+ wordStart--;
318
+ }
319
+ const preceding = lower.slice(wordStart, index);
320
+ if (!followedByTokenCharacter && preceding !== "non" && preceding !== "no") {
321
+ const stripped = model.slice(0, index) + model.slice(end);
322
+ return stripped.length > 0 ? stripped : void 0;
323
+ }
324
+ searchFrom = index + 1;
325
+ }
326
+ }
327
+ }
328
+ /**
329
+ * Classifies a model into its structured identity: reviewed override first,
330
+ * then suffix collapse, then class/family/revision ranks over the logical id.
331
+ *
332
+ * Results are memoized per (provider, model, lenient) — the rule tree is
333
+ * static per process. Cached identities are frozen and each caller receives
334
+ * a shallow copy, so a consumer that mutates its copy (e.g. `buildModel`
335
+ * storing `policy.identity` on the model) cannot poison the cache or any
336
+ * other model classified under the same key. Calls with an explicit
337
+ * observedAtMs skip the memo so override expiry stays exact.
338
+ *
339
+ * @throws AmbiguousIdentityError on equal-rank cross-class, cross-family, or
340
+ * reviewed-pattern matches unless `opts.lenient`.
341
+ */
342
+ const classifyMemo = new LRUCache({ max: 16384 });
343
+ function classifyMemoKey(provider, modelId, lenient) {
344
+ return `${provider.length}:${provider}${modelId.length}:${modelId}${lenient ? 1 : 0}`;
345
+ }
346
+ function classifyModel(provider, modelId, opts) {
347
+ if (opts?.observedAtMs === void 0) {
348
+ const key = classifyMemoKey(provider, modelId, opts?.lenient === true);
349
+ const cached = classifyMemo.get(key);
350
+ if (cached !== void 0) return { ...cached };
351
+ const identity = classifyModelUncached(provider, modelId, opts);
352
+ classifyMemo.set(key, Object.freeze(identity));
353
+ return { ...identity };
354
+ }
355
+ return classifyModelUncached(provider, modelId, opts);
356
+ }
357
+ function classifyModelUncached(provider, modelId, opts) {
358
+ const lenient = opts?.lenient === true;
359
+ const trimmed = modelId.trim();
360
+ const override = findIdentityOverride(provider, bareOf(trimmed), opts?.observedAtMs, lenient);
361
+ if (override) {
362
+ const logical = override.logical ?? trimmed;
363
+ const cls = override.class ?? classifyRanks(logical, lenient).class;
364
+ const inferred = ranksInClass(cls, logical, lenient);
365
+ const identity = { class: cls };
366
+ const family = override.family ?? inferred.family;
367
+ if (family !== void 0) identity.family = family;
368
+ const revision = override.revision ?? inferred.revision;
369
+ if (revision !== void 0) identity.revision = revision;
370
+ if (override.effort !== void 0) identity.effort = override.effort;
371
+ if (override.thinkingVariant) identity.thinkingVariant = true;
372
+ if (logical !== trimmed) identity.logicalId = logical;
373
+ return identity;
374
+ }
375
+ const collapsed = trimmed.length === modelId.length ? collapseVariantId(provider, trimmed) : {
376
+ logicalId: trimmed,
377
+ thinkingVariant: false
378
+ };
379
+ const ranks = classifyRanks(collapsed.logicalId, lenient);
380
+ const identity = { class: ranks.class };
381
+ if (ranks.family !== void 0) identity.family = ranks.family;
382
+ if (ranks.revision !== void 0) identity.revision = ranks.revision;
383
+ if (collapsed.effort !== void 0) identity.effort = collapsed.effort;
384
+ if (collapsed.thinkingVariant) identity.thinkingVariant = true;
385
+ if (collapsed.logicalId !== trimmed) identity.logicalId = collapsed.logicalId;
386
+ return identity;
387
+ }
388
+ /**
389
+ * Strips a declared billing-variant suffix (`-free`, `-contributor`) from a
390
+ * wire identifier, returning the base id it shares a transport with.
391
+ */
392
+ function billingVariantPlain(wireModel) {
393
+ for (const suffix of taxonomy.discovery.billingVariantSuffixes) {
394
+ const split = wireModel.length - suffix.length;
395
+ if (split <= 0) continue;
396
+ if (wireModel.slice(split).toLowerCase() === suffix) return wireModel.slice(0, split);
397
+ }
398
+ }
399
+ /** The declared collapse suffix vocabulary (read-only view for collapse logic). */
400
+ function collapseVocabulary() {
401
+ return taxonomy.collapse;
402
+ }
403
+ /** The declared discovery vocabulary (read-only view). */
404
+ function discoveryVocabulary() {
405
+ return taxonomy.discovery;
406
+ }
407
+ //#endregion
408
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/pricing.ts
409
+ function nonnegative(value) {
410
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
411
+ }
412
+ function isRates(value) {
413
+ return isRecord(value) && nonnegative(value.input) && nonnegative(value.output) && nonnegative(value.cacheRead) && nonnegative(value.cacheWrite);
414
+ }
415
+ function isLongContext(value) {
416
+ return isRecord(value) && isRates(value) && typeof value.inputThreshold === "number" && Number.isFinite(value.inputThreshold) && value.inputThreshold > 0 && (value.inputThresholdInclusive === void 0 || typeof value.inputThresholdInclusive === "boolean");
417
+ }
418
+ function isPeakWindow(value) {
419
+ return isRecord(value) && Array.isArray(value.weekdays) && value.weekdays.length > 0 && value.weekdays.every((day) => Number.isInteger(day) && day >= 0 && day <= 6) && new Set(value.weekdays).size === value.weekdays.length && typeof value.startMinute === "number" && Number.isInteger(value.startMinute) && typeof value.endMinute === "number" && Number.isInteger(value.endMinute) && value.startMinute >= 0 && value.endMinute <= 1440 && value.startMinute < value.endMinute;
420
+ }
421
+ function isEffectiveRate(value) {
422
+ return isRecord(value) && isRates(value) && typeof value.effectiveFrom === "number" && Number.isSafeInteger(value.effectiveFrom) && Math.abs(value.effectiveFrom) <= 864e13 && (value.longContext === void 0 || isLongContext(value.longContext));
423
+ }
424
+ /** Validate serialized schedules before admitting cached model rows. */
425
+ function isTimeBasedCost(value) {
426
+ if (!isRecord(value) || !nonnegative(value.offPeakMultiplier) || !Array.isArray(value.peakWindows) || !value.peakWindows.every(isPeakWindow)) return false;
427
+ if (value.effectiveRates === void 0) return true;
428
+ if (!Array.isArray(value.effectiveRates) || !value.effectiveRates.every(isEffectiveRate)) return false;
429
+ const dates = /* @__PURE__ */ new Set();
430
+ for (const rate of value.effectiveRates) {
431
+ if (dates.has(rate.effectiveFrom)) return false;
432
+ dates.add(rate.effectiveFrom);
433
+ }
434
+ return true;
435
+ }
436
+ function payload(value, keys, field) {
437
+ if (!isRecord(value) || Object.keys(value).some((key) => !keys.includes(key))) throw new Error(`Invalid time-based-cost ${field}`);
438
+ return value;
439
+ }
440
+ function namedEntries(value, field) {
441
+ if (!isRecord(value)) throw new Error(`Invalid time-based-cost ${field}: expected named objects`);
442
+ return Object.values(value);
443
+ }
444
+ /** Parse a KDL ISO UTC instant (`YYYY-MM-DDTHH:mm:ssZ`, optional milliseconds) to Unix ms. */
445
+ function parseUtcInstant(date, axis) {
446
+ if (typeof date !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(date)) throw new Error(`Invalid ${axis} effective-from: expected an ISO UTC timestamp`);
447
+ const instant = Date.parse(date);
448
+ if (!Number.isFinite(instant) || new Date(instant).toISOString() !== (date.includes(".") ? date : date.replace("Z", ".000Z"))) throw new Error(`Invalid ${axis} effective-from: invalid UTC date`);
449
+ return instant;
450
+ }
451
+ /** KDL object children are named records; normalize them once while constructing the model. */
452
+ function materializeTimeBasedCost(value) {
453
+ const source = payload(value, [
454
+ "offPeakMultiplier",
455
+ "peakWindows",
456
+ "effectiveRates"
457
+ ], "schedule");
458
+ const peakWindows = namedEntries(source.peakWindows, "peak-windows").map((entry) => {
459
+ const window = payload(entry, [
460
+ "weekdays",
461
+ "startMinute",
462
+ "endMinute"
463
+ ], "peak-window");
464
+ if (typeof window.weekdays !== "string" || !/^[0-6](,[0-6])*$/.test(window.weekdays)) throw new Error("Invalid time-based-cost weekdays: expected comma-separated UTC weekday numbers");
465
+ return {
466
+ ...window,
467
+ weekdays: window.weekdays.split(",").map(Number)
468
+ };
469
+ });
470
+ const effectiveRates = source.effectiveRates === void 0 ? void 0 : namedEntries(source.effectiveRates, "effective-rates").map((entry) => {
471
+ const rate = payload(entry, [
472
+ "effectiveFrom",
473
+ "input",
474
+ "output",
475
+ "cacheRead",
476
+ "cacheWrite",
477
+ "longContext"
478
+ ], "effective-rate");
479
+ const effectiveFrom = parseUtcInstant(rate.effectiveFrom, "time-based-cost");
480
+ if (rate.longContext !== void 0) payload(rate.longContext, [
481
+ "inputThreshold",
482
+ "inputThresholdInclusive",
483
+ "input",
484
+ "output",
485
+ "cacheRead",
486
+ "cacheWrite"
487
+ ], "long-context");
488
+ return {
489
+ ...rate,
490
+ effectiveFrom
491
+ };
492
+ });
493
+ const schedule = {
494
+ offPeakMultiplier: source.offPeakMultiplier,
495
+ peakWindows,
496
+ ...effectiveRates && { effectiveRates }
497
+ };
498
+ if (!isTimeBasedCost(schedule)) throw new Error("Invalid time-based-cost schedule: invalid windows, rates, or multiplier");
499
+ return schedule;
500
+ }
501
+ /**
502
+ * The latest `effectiveRates` card of a materialized schedule due at
503
+ * `timestamp`, or undefined before the first one (or without a schedule).
504
+ */
505
+ function dueEffectiveRate(schedule, timestamp) {
506
+ let due;
507
+ for (const candidate of schedule?.effectiveRates ?? []) if (candidate.effectiveFrom <= timestamp && (due === void 0 || candidate.effectiveFrom > due.effectiveFrom)) due = candidate;
508
+ return due;
509
+ }
510
+ const TOKEN_COST_LEGS = [
511
+ "input",
512
+ "output",
513
+ "cacheRead",
514
+ "cacheWrite"
515
+ ];
516
+ const DATED_CARD_KEYS = ["effectiveFrom", ...TOKEN_COST_LEGS];
517
+ /**
518
+ * Parse the compiled `effective-rates` block of a `cost-patch` or
519
+ * `cost-fallback` payload into dated cards, ascending by date. Throws on a
520
+ * malformed card, so a typo in a rule fails the build instead of silently
521
+ * leaving the old price in force.
522
+ */
523
+ function parseDatedCostCards(costAxis, axis) {
524
+ const effectiveRates = isRecord(costAxis) ? costAxis.effectiveRates : void 0;
525
+ if (effectiveRates === void 0) return [];
526
+ if (!isRecord(effectiveRates)) throw new Error(`Invalid ${axis} effective-rates: expected named objects`);
527
+ const cards = Object.values(effectiveRates).map((entry) => {
528
+ if (!isRecord(entry) || Object.keys(entry).some((key) => !DATED_CARD_KEYS.includes(key))) throw new Error(`Invalid ${axis} effective-rate: unknown or malformed fields`);
529
+ const card = { effectiveFrom: parseUtcInstant(entry.effectiveFrom, axis) };
530
+ for (const leg of TOKEN_COST_LEGS) {
531
+ const value = entry[leg];
532
+ if (value === void 0) continue;
533
+ if (!nonnegative(value)) throw new Error(`Invalid ${axis} effective-rate ${leg}: expected a nonnegative number`);
534
+ card[leg] = value;
535
+ }
536
+ return card;
537
+ });
538
+ cards.sort((a, b) => a.effectiveFrom - b.effectiveFrom);
539
+ for (let index = 1; index < cards.length; index++) if (cards[index].effectiveFrom === cards[index - 1].effectiveFrom) throw new Error(`Invalid ${axis} effective-rates: duplicate effective-from`);
540
+ return cards;
541
+ }
542
+ /**
543
+ * Earliest instant a rate card can name (the `Date` range minimum). A leading
544
+ * card from here holds the price in force before the first dated change.
545
+ */
546
+ const EARLIEST_EFFECTIVE_FROM = -864e13;
547
+ /** A schedule of dated rate cards alone: no peak windows, no off-peak discount. */
548
+ const NO_RECURRING_TARIFF = {
549
+ offPeakMultiplier: 1,
550
+ peakWindows: []
551
+ };
552
+ /**
553
+ * A flat card plus its dated overrides as a request-time `ModelCost`: the
554
+ * card due at `now` in the scalar legs, and every period (a leading card for
555
+ * the base price, then each dated card over the previous one) in a
556
+ * `timeBased` schedule without a recurring tariff. The plain card when no
557
+ * dated card exists.
558
+ */
559
+ function datedCost(base, cards, now = Date.now()) {
560
+ if (cards.length === 0) return base;
561
+ const effectiveRates = [{
562
+ effectiveFrom: EARLIEST_EFFECTIVE_FROM,
563
+ ...base
564
+ }];
565
+ for (const card of cards) effectiveRates.push({
566
+ ...effectiveRates.at(-1),
567
+ ...card
568
+ });
569
+ const timeBased = {
570
+ ...NO_RECURRING_TARIFF,
571
+ effectiveRates
572
+ };
573
+ const { effectiveFrom: _effectiveFrom, ...due } = dueEffectiveRate(timeBased, now);
574
+ return {
575
+ ...due,
576
+ timeBased
577
+ };
578
+ }
579
+ /**
580
+ * Overwrite `cost` legs with the latest dated card due at `now`. Leaves
581
+ * `cost` unchanged before the first card.
582
+ */
583
+ function applyDueDatedCostCard(cost, cards, now = Date.now()) {
584
+ let due;
585
+ for (const card of cards) if (card.effectiveFrom <= now) due = card;
586
+ if (due === void 0) return;
587
+ for (const leg of TOKEN_COST_LEGS) {
588
+ const value = due[leg];
589
+ if (value !== void 0) cost[leg] = value;
590
+ }
591
+ }
592
+ //#endregion
593
+ export { dueEffectiveRate as a, billingVariantPlain as c, collapseVocabulary as d, discoveryVocabulary as f, datedCost as i, classifyModel as l, NO_RECURRING_TARIFF as n, materializeTimeBasedCost as o, stripThinkingVariantSuffix as p, applyDueDatedCostCard as r, parseDatedCostCards as s, EARLIEST_EFFECTIVE_FROM as t, collapseVariantId as u };