@zhihaohong52/sonata 0.4.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +437 -0
  3. package/dist/adapters/claude.js +83 -0
  4. package/dist/adapters/claude.js.map +1 -0
  5. package/dist/adapters/codex.js +382 -0
  6. package/dist/adapters/codex.js.map +1 -0
  7. package/dist/adapters/index.js +21 -0
  8. package/dist/adapters/index.js.map +1 -0
  9. package/dist/adapters/opencode.js +104 -0
  10. package/dist/adapters/opencode.js.map +1 -0
  11. package/dist/adapters/pi.js +152 -0
  12. package/dist/adapters/pi.js.map +1 -0
  13. package/dist/adapters/reasonix.js +358 -0
  14. package/dist/adapters/reasonix.js.map +1 -0
  15. package/dist/adapters/types.js +2 -0
  16. package/dist/adapters/types.js.map +1 -0
  17. package/dist/agent-markers.js +3 -0
  18. package/dist/agent-markers.js.map +1 -0
  19. package/dist/aipricing.js +109 -0
  20. package/dist/aipricing.js.map +1 -0
  21. package/dist/catalog.js +274 -0
  22. package/dist/catalog.js.map +1 -0
  23. package/dist/cli.js +766 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/commands/approve.js +23 -0
  26. package/dist/commands/approve.js.map +1 -0
  27. package/dist/commands/auth.js +41 -0
  28. package/dist/commands/auth.js.map +1 -0
  29. package/dist/commands/catalog.js +172 -0
  30. package/dist/commands/catalog.js.map +1 -0
  31. package/dist/commands/code.js +113 -0
  32. package/dist/commands/code.js.map +1 -0
  33. package/dist/commands/dispatch.js +148 -0
  34. package/dist/commands/dispatch.js.map +1 -0
  35. package/dist/commands/doctor.js +545 -0
  36. package/dist/commands/doctor.js.map +1 -0
  37. package/dist/commands/gc.js +25 -0
  38. package/dist/commands/gc.js.map +1 -0
  39. package/dist/commands/init-log.js +83 -0
  40. package/dist/commands/init-log.js.map +1 -0
  41. package/dist/commands/init.js +157 -0
  42. package/dist/commands/init.js.map +1 -0
  43. package/dist/commands/log.js +24 -0
  44. package/dist/commands/log.js.map +1 -0
  45. package/dist/commands/route.js +660 -0
  46. package/dist/commands/route.js.map +1 -0
  47. package/dist/commands/run.js +199 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/runs.js +37 -0
  50. package/dist/commands/runs.js.map +1 -0
  51. package/dist/commands/serve.js +818 -0
  52. package/dist/commands/serve.js.map +1 -0
  53. package/dist/commands/status.js +14 -0
  54. package/dist/commands/status.js.map +1 -0
  55. package/dist/commands/sync.js +258 -0
  56. package/dist/commands/sync.js.map +1 -0
  57. package/dist/commands/tail.js +229 -0
  58. package/dist/commands/tail.js.map +1 -0
  59. package/dist/commands/usage.js +85 -0
  60. package/dist/commands/usage.js.map +1 -0
  61. package/dist/commands/verify.js +69 -0
  62. package/dist/commands/verify.js.map +1 -0
  63. package/dist/commands/wait.js +38 -0
  64. package/dist/commands/wait.js.map +1 -0
  65. package/dist/config.js +588 -0
  66. package/dist/config.js.map +1 -0
  67. package/dist/detect.js +445 -0
  68. package/dist/detect.js.map +1 -0
  69. package/dist/filelock.js +83 -0
  70. package/dist/filelock.js.map +1 -0
  71. package/dist/init/apply.js +96 -0
  72. package/dist/init/apply.js.map +1 -0
  73. package/dist/init/candidates.js +115 -0
  74. package/dist/init/candidates.js.map +1 -0
  75. package/dist/init/discover.js +216 -0
  76. package/dist/init/discover.js.map +1 -0
  77. package/dist/init/helpers.js +429 -0
  78. package/dist/init/helpers.js.map +1 -0
  79. package/dist/init/interactive-state.js +128 -0
  80. package/dist/init/interactive-state.js.map +1 -0
  81. package/dist/init/plan.js +225 -0
  82. package/dist/init/plan.js.map +1 -0
  83. package/dist/init/scripted-state.js +130 -0
  84. package/dist/init/scripted-state.js.map +1 -0
  85. package/dist/init/toml.js +83 -0
  86. package/dist/init/toml.js.map +1 -0
  87. package/dist/init/validate.js +149 -0
  88. package/dist/init/validate.js.map +1 -0
  89. package/dist/ledger.js +123 -0
  90. package/dist/ledger.js.map +1 -0
  91. package/dist/mcp/protocol.js +64 -0
  92. package/dist/mcp/protocol.js.map +1 -0
  93. package/dist/mcp/server.js +96 -0
  94. package/dist/mcp/server.js.map +1 -0
  95. package/dist/mcp/tools.js +210 -0
  96. package/dist/mcp/tools.js.map +1 -0
  97. package/dist/mode.js +64 -0
  98. package/dist/mode.js.map +1 -0
  99. package/dist/native/claude-shim.js +228 -0
  100. package/dist/native/claude-shim.js.map +1 -0
  101. package/dist/native/codex-auth.js +177 -0
  102. package/dist/native/codex-auth.js.map +1 -0
  103. package/dist/native/copilot-auth.js +105 -0
  104. package/dist/native/copilot-auth.js.map +1 -0
  105. package/dist/native/credentials.js +83 -0
  106. package/dist/native/credentials.js.map +1 -0
  107. package/dist/native/hosts.js +60 -0
  108. package/dist/native/hosts.js.map +1 -0
  109. package/dist/native/litellm.js +103 -0
  110. package/dist/native/litellm.js.map +1 -0
  111. package/dist/native/models.js +96 -0
  112. package/dist/native/models.js.map +1 -0
  113. package/dist/native/oauth-login.js +112 -0
  114. package/dist/native/oauth-login.js.map +1 -0
  115. package/dist/native/router.js +469 -0
  116. package/dist/native/router.js.map +1 -0
  117. package/dist/native/tls.js +73 -0
  118. package/dist/native/tls.js.map +1 -0
  119. package/dist/native/usage.js +119 -0
  120. package/dist/native/usage.js.map +1 -0
  121. package/dist/normalize.js +98 -0
  122. package/dist/normalize.js.map +1 -0
  123. package/dist/pricing.js +86 -0
  124. package/dist/pricing.js.map +1 -0
  125. package/dist/roles.js +49 -0
  126. package/dist/roles.js.map +1 -0
  127. package/dist/sessions.js +62 -0
  128. package/dist/sessions.js.map +1 -0
  129. package/dist/settings.js +131 -0
  130. package/dist/settings.js.map +1 -0
  131. package/dist/store.js +70 -0
  132. package/dist/store.js.map +1 -0
  133. package/dist/tmux.js +89 -0
  134. package/dist/tmux.js.map +1 -0
  135. package/dist/tui-ink/app-state.js +340 -0
  136. package/dist/tui-ink/app-state.js.map +1 -0
  137. package/dist/tui-ink/app.js +156 -0
  138. package/dist/tui-ink/app.js.map +1 -0
  139. package/dist/tui-ink/components/byok-step.js +102 -0
  140. package/dist/tui-ink/components/byok-step.js.map +1 -0
  141. package/dist/tui-ink/components/login-screen.js +80 -0
  142. package/dist/tui-ink/components/login-screen.js.map +1 -0
  143. package/dist/tui-ink/components/models-step.js +92 -0
  144. package/dist/tui-ink/components/models-step.js.map +1 -0
  145. package/dist/tui-ink/components/multi-select-state.js +56 -0
  146. package/dist/tui-ink/components/multi-select-state.js.map +1 -0
  147. package/dist/tui-ink/components/multi-select.js +69 -0
  148. package/dist/tui-ink/components/multi-select.js.map +1 -0
  149. package/dist/tui-ink/components/providers-step.js +285 -0
  150. package/dist/tui-ink/components/providers-step.js.map +1 -0
  151. package/dist/tui-ink/components/ranked-select-state.js +41 -0
  152. package/dist/tui-ink/components/ranked-select-state.js.map +1 -0
  153. package/dist/tui-ink/components/ranked-select.js +61 -0
  154. package/dist/tui-ink/components/ranked-select.js.map +1 -0
  155. package/dist/tui-ink/components/search-select.js +47 -0
  156. package/dist/tui-ink/components/search-select.js.map +1 -0
  157. package/dist/tui-ink/components/text-input-state.js +42 -0
  158. package/dist/tui-ink/components/text-input-state.js.map +1 -0
  159. package/dist/tui-ink/components/text-input.js +48 -0
  160. package/dist/tui-ink/components/text-input.js.map +1 -0
  161. package/dist/tui-ink/run.js +38 -0
  162. package/dist/tui-ink/run.js.map +1 -0
  163. package/dist/tui-ink/test-compile.js +4 -0
  164. package/dist/tui-ink/test-compile.js.map +1 -0
  165. package/dist/tui-ink/types.js +2 -0
  166. package/dist/tui-ink/types.js.map +1 -0
  167. package/dist/tui.js +330 -0
  168. package/dist/tui.js.map +1 -0
  169. package/dist/types.js +2 -0
  170. package/dist/types.js.map +1 -0
  171. package/dist/watchdog.js +85 -0
  172. package/dist/watchdog.js.map +1 -0
  173. package/hooks/capture-mode.mjs +56 -0
  174. package/hooks/ensure-serve.mjs +140 -0
  175. package/hooks/hooks.json +12 -0
  176. package/hooks/route-session.mjs +47 -0
  177. package/hooks/route-subagent.mjs +54 -0
  178. package/package.json +64 -0
  179. package/roles/code.md +13 -0
  180. package/roles/explore.md +9 -0
  181. package/roles/plan.md +10 -0
  182. package/roles/review.md +11 -0
  183. package/skills/loop/SKILL.md +43 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aipricing.js","sourceRoot":"","sources":["../src/aipricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Which models are worth which work.
3
+ *
4
+ * Two data sources feed tier assignment: a small curated table (our own
5
+ * judgement, shipped with sonata) and an optional Artificial Analysis cache
6
+ * the *user* fetched with their own key (`sonata catalog update`). AA's free
7
+ * tier licenses internal use only — no redistribution — so nothing derived
8
+ * from AA data may ever be committed to this repository. The curated table is
9
+ * deliberately hand-written from experience, not from AA numbers.
10
+ */
11
+ import { existsSync, readFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ export const AA_ATTRIBUTION = 'Model rankings by Artificial Analysis — https://artificialanalysis.ai';
14
+ /** Coding Index at or above this ⇒ complex-eligible. Chosen so today's
15
+ * mid-tier coders (deepseek-v4-flash class) sit just above the line. */
16
+ export const AA_CAPABLE_CODING_INDEX = 40;
17
+ /** Blended $/1M tokens at or below this ⇒ cheap enough for the simple tier. */
18
+ export const AA_CHEAP_BLENDED_PRICE_USD = 1.0;
19
+ /**
20
+ * Capability, best available measure first.
21
+ *
22
+ * Every sonata role — code, review, plan, explore — runs as an agentic
23
+ * subagent driving tools in a loop, so the agentic index describes all four
24
+ * better than a coding or reasoning score does. The fallbacks exist for models
25
+ * AA has not scored agentically and for caches written before it was
26
+ * collected, not as a per-role choice.
27
+ */
28
+ export function capabilityOf(entry) {
29
+ return entry.agenticIndex ?? entry.codingIndex ?? entry.intelligenceIndex ?? 0;
30
+ }
31
+ /**
32
+ * What one unit of work costs, best available measure first.
33
+ *
34
+ * `costPerTask` prices the work; the blended per-1M rate only prices tokens
35
+ * and is a weaker proxy, kept for models AA has not costed.
36
+ */
37
+ export function costOfEntry(entry) {
38
+ return entry.costPerTask ?? entry.blendedPriceUsd;
39
+ }
40
+ /**
41
+ * A model must reach this fraction of the best score among the *selected*
42
+ * models to be eligible for a simple tier.
43
+ *
44
+ * Relative, not absolute: an absolute floor is wrong in both directions —
45
+ * it excludes everything when a user's whole selection is modest, and admits
46
+ * junk when their selection is strong. The simple tier optimises
47
+ * capability-per-dollar, and without a floor a very cheap, very weak model
48
+ * wins on ratio alone.
49
+ *
50
+ * Set where it is to keep the tier *deep* as well as good. A tier is a ranked
51
+ * fallback list, so a floor strict enough to admit one model leaves the router
52
+ * nothing to fall through to and sends the first failure straight to 529 and
53
+ * the dispatch lane. Measured on a real 17-model config, 0.85 admitted exactly
54
+ * one model where 0.75 admits four.
55
+ *
56
+ * The floor is not only a depth control: it also decides the *leader*, because
57
+ * a model it admits can outrank the others on value. On that same config,
58
+ * raising it to 0.85 excludes the cheapest model and promotes a stronger,
59
+ * dearer one. So it trades capability against both cost and resilience, and
60
+ * moving it changes what grunt work actually runs on — not merely what stands
61
+ * behind that choice.
62
+ */
63
+ export const SIMPLE_CAPABILITY_FLOOR = 0.75;
64
+ /**
65
+ * The key an AA score is stored and looked up under.
66
+ *
67
+ * AA writes versions with dashes (`glm-5-3`) where sonata, ai-pricing.fyi and
68
+ * every gateway write dots (`glm-5.3`), so a name that is otherwise identical
69
+ * never joins — measured on a real 17-model config, only 3 matched, and the
70
+ * other 14 fell back to a constant rank that made the sort a no-op. Going
71
+ * dots-to-dashes is the safe direction: dashes are load-bearing inside real
72
+ * names (`deepseek-v4-flash`), so the reverse would be ambiguous. Verified
73
+ * collision-free across both catalogs (0 of 258 ai-pricing, 0 of 233 AA).
74
+ */
75
+ export function aaMatchKey(name) {
76
+ return name.replace(/\./g, '-');
77
+ }
78
+ /**
79
+ * Collapses the many spellings of one model to a single name: harness and
80
+ * provider prefixes go (`opencode-acme-…`, `openai/…`), and a trailing MMDD
81
+ * date suffix goes (`-0731`). Idempotent, so a normalized name can be
82
+ * normalized again safely.
83
+ *
84
+ * `providers` names the gateways actually configured, and is how a provider
85
+ * sonata has never heard of gets stripped. The built-in list below can only
86
+ * cover providers someone thought to hardcode; every other user's gateway fell
87
+ * through to the `default` catalog entry (capable, not cheap), quietly keeping
88
+ * its models out of the simple tier. Pass the config's gateway names and that
89
+ * stops being a guess.
90
+ */
91
+ export function normalizeModelName(raw, providers = []) {
92
+ let name = raw.includes('/') ? raw.slice(raw.lastIndexOf('/') + 1) : raw;
93
+ // Sonata keys are exactly `<harness>-<provider>-<model>`, so only the first
94
+ // two segments are ours to remove. A `while` loop re-matches its own output
95
+ // and keeps eating past that structure, corrupting a model whose real name
96
+ // happens to begin with a reserved word (`openai-…`, `pi-…`). So stripping
97
+ // is two ordered passes — at most one harness prefix, then at most one
98
+ // provider prefix — never a loop that can run again.
99
+ const HARNESS_PREFIXES = ['opencode-', 'codex-', 'pi-', 'reasonix-', 'claude-harness-'];
100
+ // Configured gateways first and longest-first, so `openai-codex-x` loses the
101
+ // whole gateway name rather than the shorter `openai-` that also matches.
102
+ const PROVIDER_PREFIXES = [
103
+ ...providers.map((provider) => `${provider}-`),
104
+ 'openrouter-', 'openai-', 'google-', 'anthropic-',
105
+ ].sort((a, b) => b.length - a.length);
106
+ for (const prefix of HARNESS_PREFIXES) {
107
+ if (name.startsWith(prefix) && name.length > prefix.length) {
108
+ name = name.slice(prefix.length);
109
+ break;
110
+ }
111
+ }
112
+ for (const prefix of PROVIDER_PREFIXES) {
113
+ if (name.startsWith(prefix) && name.length > prefix.length) {
114
+ name = name.slice(prefix.length);
115
+ break;
116
+ }
117
+ }
118
+ return name.replace(/-\d{4}$/, '');
119
+ }
120
+ /** Our own judgement, not AA data. Kept deliberately small: the default for
121
+ * anything unlisted is capable-not-cheap, the direction that never silently
122
+ * hands hard work to a weak model. */
123
+ const CURATED = {
124
+ 'deepseek-v4-flash': { capable: true, cheap: true },
125
+ 'deepseek-v4-pro': { capable: true, cheap: false },
126
+ 'gpt-5.6-luna': { capable: true, cheap: true },
127
+ 'gpt-5.6-terra': { capable: true, cheap: false },
128
+ 'gpt-5.6-sol': { capable: true, cheap: false },
129
+ 'kimi-k3': { capable: true, cheap: true },
130
+ 'kimi-k3-free': { capable: false, cheap: true },
131
+ 'glm-5.3': { capable: true, cheap: true },
132
+ 'grok-4.6': { capable: true, cheap: false },
133
+ 'gemini-3.7-flash': { capable: true, cheap: true },
134
+ 'qwen3.8-max': { capable: true, cheap: false },
135
+ 'ox-alpha-free': { capable: false, cheap: true },
136
+ };
137
+ export function lookupModel(name, aa, providers = []) {
138
+ const normalized = normalizeModelName(name, providers);
139
+ const scored = aa?.models[normalized] ?? aa?.models[aaMatchKey(normalized)];
140
+ if (scored !== undefined) {
141
+ return {
142
+ capable: scored.codingIndex >= AA_CAPABLE_CODING_INDEX,
143
+ cheap: scored.blendedPriceUsd <= AA_CHEAP_BLENDED_PRICE_USD,
144
+ source: 'aa',
145
+ };
146
+ }
147
+ const curated = CURATED[normalized];
148
+ if (curated !== undefined)
149
+ return { ...curated, source: 'curated' };
150
+ return { capable: true, cheap: false, source: 'default' };
151
+ }
152
+ /** The AA row behind a model key, joined through the match key. */
153
+ function scoreFor(key, aa, providers = []) {
154
+ const normalized = normalizeModelName(key, providers);
155
+ return aa?.models[normalized] ?? aa?.models[aaMatchKey(normalized)];
156
+ }
157
+ /** Rank for ordering within a tier: the role's AA score when known, else a
158
+ * fixed mid score so curated/default models interleave stably. */
159
+ function rank(key, aa, providers = []) {
160
+ const scored = scoreFor(key, aa, providers);
161
+ return scored !== undefined
162
+ ? { index: capabilityOf(scored), price: costOfEntry(scored) }
163
+ : { index: AA_CAPABLE_CODING_INDEX, price: AA_CHEAP_BLENDED_PRICE_USD };
164
+ }
165
+ /**
166
+ * Capability per dollar — how a simple tier is ordered.
167
+ *
168
+ * A simple tier exists to do grunt work cheaply, so the model that returns the
169
+ * most capability per dollar wins, not the most capable model that happens to
170
+ * clear a price threshold (which is what this used to do, and is backwards for
171
+ * a tier whose whole purpose is cost). Price is floored before dividing so a
172
+ * free model sorts first rather than dividing by zero.
173
+ */
174
+ function valueOf(r) {
175
+ return r.index / Math.max(r.price, 0.01);
176
+ }
177
+ export function proposeTiers(modelKeys, aa, providers = [], avoided = new Set()) {
178
+ const rankOf = (k) => rank(k, aa, providers);
179
+ // An avoided model sorts after every non-avoided one, whatever it scores.
180
+ // Demotion, not exclusion: the tier keeps it as a fallback candidate, so
181
+ // avoiding a gateway costs preference rather than the depth a ranked list
182
+ // exists to provide.
183
+ const avoidance = (a, b) => Number(avoided.has(a)) - Number(avoided.has(b));
184
+ // Complex work wants the most capable model, cost only breaking ties.
185
+ const byCapability = (a, b) => {
186
+ const ra = rankOf(a);
187
+ const rb = rankOf(b);
188
+ return avoidance(a, b) || rb.index - ra.index || ra.price - rb.price;
189
+ };
190
+ // Simple work wants the most capability per dollar, capability breaking ties.
191
+ const byValue = (a, b) => {
192
+ const ra = rankOf(a);
193
+ const rb = rankOf(b);
194
+ return avoidance(a, b) || valueOf(rb) - valueOf(ra) || rb.index - ra.index;
195
+ };
196
+ const complex = modelKeys.filter((k) => lookupModel(k, aa, providers).capable).sort(byCapability);
197
+ // The floor is relative to the best model actually selected, so it adapts to
198
+ // the user's own set rather than to an absolute score that is wrong whenever
199
+ // their selection is uniformly strong or uniformly modest.
200
+ // Measured over the models that can actually lead the tier: including an
201
+ // avoided model here could raise the bar high enough to exclude everything
202
+ // preferred, inverting the setting's intent.
203
+ const preferred = modelKeys.filter((k) => !avoided.has(k));
204
+ const best = Math.max(0, ...(preferred.length > 0 ? preferred : modelKeys).map((k) => rankOf(k).index));
205
+ const simple = modelKeys
206
+ .filter((k) => {
207
+ const e = lookupModel(k, aa, providers);
208
+ return e.capable && e.cheap && rankOf(k).index >= best * SIMPLE_CAPABILITY_FLOOR;
209
+ })
210
+ .sort(byValue);
211
+ // A tier must always resolve to something: with no capable model, everything
212
+ // is complex-eligible; with no cheap-capable model, simple mirrors complex.
213
+ // The fallback is sorted too — raw input order would break the documented
214
+ // "index descending, price ascending" ordering on exactly the path where no
215
+ // model cleared the threshold.
216
+ const complexFinal = complex.length > 0 ? complex : [...modelKeys].sort(byCapability);
217
+ // Falls back to the complex set, but re-sorted by value: the reason to
218
+ // fall back is that nothing cleared the cheap bar, not that cost stopped
219
+ // mattering for grunt work.
220
+ const simpleFinal = simple.length > 0 ? simple : [...complexFinal].sort(byValue);
221
+ return { simple: simpleFinal, complex: complexFinal };
222
+ }
223
+ /**
224
+ * How long a ranking cache stays trustworthy.
225
+ *
226
+ * Not a correctness bound — a stale catalog still ranks — but model releases
227
+ * and price cuts land continuously, so an old one silently proposes tiers
228
+ * built on superseded scores. Thirty days is long enough not to nag and short
229
+ * enough that a whole model generation cannot pass unnoticed.
230
+ */
231
+ export const AA_CATALOG_MAX_AGE_DAYS = 30;
232
+ /** Whole days since a catalog was fetched, or undefined if the stamp is unreadable. */
233
+ export function aaCatalogAgeDays(fetchedAt, now) {
234
+ const at = Date.parse(fetchedAt);
235
+ if (!Number.isFinite(at))
236
+ return undefined;
237
+ // A stamp from the future is a clock disagreement, not freshness to report
238
+ // as negative age; treat it as current.
239
+ return Math.max(0, Math.floor((now.getTime() - at) / 86_400_000));
240
+ }
241
+ export function aaCatalogPath(home) {
242
+ return join(home, '.config', 'sonata', 'catalog.json');
243
+ }
244
+ export function loadAaCatalog(home) {
245
+ const path = aaCatalogPath(home);
246
+ if (!existsSync(path))
247
+ return undefined;
248
+ try {
249
+ const doc = JSON.parse(readFileSync(path, 'utf8'));
250
+ if (typeof doc.fetchedAt !== 'string' || typeof doc.models !== 'object' || doc.models === null)
251
+ return undefined;
252
+ // Validate each entry, not just the top level: a missing, null, string or
253
+ // non-finite score passes the shape check and then misclassifies the model
254
+ // (`undefined >= 40` is `false`, silently "not capable"). A partially-
255
+ // corrupt cache is still useful, so drop the bad entries and keep the good;
256
+ // degrade to no cache only when nothing survives.
257
+ const models = {};
258
+ for (const [name, entry] of Object.entries(doc.models)) {
259
+ if (entry !== null &&
260
+ typeof entry === 'object' &&
261
+ Number.isFinite(entry.codingIndex) &&
262
+ Number.isFinite(entry.blendedPriceUsd)) {
263
+ models[name] = entry;
264
+ }
265
+ }
266
+ if (Object.keys(models).length === 0)
267
+ return undefined;
268
+ return { fetchedAt: doc.fetchedAt, models };
269
+ }
270
+ catch {
271
+ return undefined;
272
+ }
273
+ }
274
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}