scoutline 0.10.2 → 0.12.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 (151) hide show
  1. package/README.md +99 -44
  2. package/dist/capabilities/diagnostics.d.ts +75 -0
  3. package/dist/capabilities/diagnostics.d.ts.map +1 -1
  4. package/dist/capabilities/diagnostics.js.map +1 -1
  5. package/dist/capabilities/quota.d.ts +64 -1
  6. package/dist/capabilities/quota.d.ts.map +1 -1
  7. package/dist/capabilities/quota.js.map +1 -1
  8. package/dist/capabilities/vision.d.ts +4 -3
  9. package/dist/capabilities/vision.d.ts.map +1 -1
  10. package/dist/capabilities/vision.js +7 -5
  11. package/dist/capabilities/vision.js.map +1 -1
  12. package/dist/commands/code.d.ts +9 -1
  13. package/dist/commands/code.d.ts.map +1 -1
  14. package/dist/commands/code.js +4 -4
  15. package/dist/commands/code.js.map +1 -1
  16. package/dist/commands/crawl.d.ts.map +1 -1
  17. package/dist/commands/crawl.js +14 -3
  18. package/dist/commands/crawl.js.map +1 -1
  19. package/dist/commands/doctor.d.ts +71 -1
  20. package/dist/commands/doctor.d.ts.map +1 -1
  21. package/dist/commands/doctor.js +96 -15
  22. package/dist/commands/doctor.js.map +1 -1
  23. package/dist/commands/init.d.ts +186 -0
  24. package/dist/commands/init.d.ts.map +1 -0
  25. package/dist/commands/init.js +1221 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/map.d.ts.map +1 -1
  28. package/dist/commands/map.js +16 -3
  29. package/dist/commands/map.js.map +1 -1
  30. package/dist/commands/quota.d.ts +32 -0
  31. package/dist/commands/quota.d.ts.map +1 -1
  32. package/dist/commands/quota.js +165 -24
  33. package/dist/commands/quota.js.map +1 -1
  34. package/dist/commands/read.d.ts.map +1 -1
  35. package/dist/commands/read.js +9 -3
  36. package/dist/commands/read.js.map +1 -1
  37. package/dist/commands/repo.d.ts.map +1 -1
  38. package/dist/commands/repo.js +5 -3
  39. package/dist/commands/repo.js.map +1 -1
  40. package/dist/commands/research.d.ts +35 -7
  41. package/dist/commands/research.d.ts.map +1 -1
  42. package/dist/commands/research.js +93 -15
  43. package/dist/commands/research.js.map +1 -1
  44. package/dist/commands/tools.d.ts +8 -0
  45. package/dist/commands/tools.d.ts.map +1 -1
  46. package/dist/commands/tools.js +4 -4
  47. package/dist/commands/tools.js.map +1 -1
  48. package/dist/commands/vision.d.ts +10 -0
  49. package/dist/commands/vision.d.ts.map +1 -1
  50. package/dist/commands/vision.js +25 -2
  51. package/dist/commands/vision.js.map +1 -1
  52. package/dist/index.d.ts +136 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +894 -298
  55. package/dist/index.js.map +1 -1
  56. package/dist/lib/api-client.d.ts +1 -1
  57. package/dist/lib/api-client.d.ts.map +1 -1
  58. package/dist/lib/api-client.js +6 -2
  59. package/dist/lib/api-client.js.map +1 -1
  60. package/dist/lib/cache.d.ts +9 -2
  61. package/dist/lib/cache.d.ts.map +1 -1
  62. package/dist/lib/cache.js +9 -2
  63. package/dist/lib/cache.js.map +1 -1
  64. package/dist/lib/code-mode.d.ts +8 -0
  65. package/dist/lib/code-mode.d.ts.map +1 -1
  66. package/dist/lib/code-mode.js +3 -1
  67. package/dist/lib/code-mode.js.map +1 -1
  68. package/dist/lib/config-store.d.ts +165 -0
  69. package/dist/lib/config-store.d.ts.map +1 -0
  70. package/dist/lib/config-store.js +332 -0
  71. package/dist/lib/config-store.js.map +1 -0
  72. package/dist/lib/config.d.ts +2 -2
  73. package/dist/lib/config.d.ts.map +1 -1
  74. package/dist/lib/config.js +19 -11
  75. package/dist/lib/config.js.map +1 -1
  76. package/dist/lib/consumption.d.ts +144 -0
  77. package/dist/lib/consumption.d.ts.map +1 -0
  78. package/dist/lib/consumption.js +161 -0
  79. package/dist/lib/consumption.js.map +1 -0
  80. package/dist/lib/errors.d.ts +11 -0
  81. package/dist/lib/errors.d.ts.map +1 -1
  82. package/dist/lib/errors.js +14 -0
  83. package/dist/lib/errors.js.map +1 -1
  84. package/dist/lib/execution.d.ts +32 -4
  85. package/dist/lib/execution.d.ts.map +1 -1
  86. package/dist/lib/execution.js +156 -13
  87. package/dist/lib/execution.js.map +1 -1
  88. package/dist/lib/mcp-client.d.ts +12 -0
  89. package/dist/lib/mcp-client.d.ts.map +1 -1
  90. package/dist/lib/mcp-client.js +16 -7
  91. package/dist/lib/mcp-client.js.map +1 -1
  92. package/dist/lib/mcp-config.d.ts +10 -0
  93. package/dist/lib/mcp-config.d.ts.map +1 -1
  94. package/dist/lib/mcp-config.js +13 -7
  95. package/dist/lib/mcp-config.js.map +1 -1
  96. package/dist/lib/monitor-client.d.ts +19 -3
  97. package/dist/lib/monitor-client.d.ts.map +1 -1
  98. package/dist/lib/monitor-client.js +21 -5
  99. package/dist/lib/monitor-client.js.map +1 -1
  100. package/dist/lib/provider-fallback.d.ts +150 -0
  101. package/dist/lib/provider-fallback.d.ts.map +1 -0
  102. package/dist/lib/provider-fallback.js +510 -0
  103. package/dist/lib/provider-fallback.js.map +1 -0
  104. package/dist/lib/quota-mapping.d.ts +402 -0
  105. package/dist/lib/quota-mapping.d.ts.map +1 -0
  106. package/dist/lib/quota-mapping.js +539 -0
  107. package/dist/lib/quota-mapping.js.map +1 -0
  108. package/dist/lib/quota-store.d.ts +271 -0
  109. package/dist/lib/quota-store.d.ts.map +1 -0
  110. package/dist/lib/quota-store.js +540 -0
  111. package/dist/lib/quota-store.js.map +1 -0
  112. package/dist/lib/trigger-detection.d.ts +149 -0
  113. package/dist/lib/trigger-detection.d.ts.map +1 -0
  114. package/dist/lib/trigger-detection.js +149 -0
  115. package/dist/lib/trigger-detection.js.map +1 -0
  116. package/dist/lib/tty.d.ts +8 -1
  117. package/dist/lib/tty.d.ts.map +1 -1
  118. package/dist/lib/tty.js +53 -1
  119. package/dist/lib/tty.js.map +1 -1
  120. package/dist/providers/brave/adapter.d.ts +26 -0
  121. package/dist/providers/brave/adapter.d.ts.map +1 -1
  122. package/dist/providers/brave/adapter.js +66 -4
  123. package/dist/providers/brave/adapter.js.map +1 -1
  124. package/dist/providers/brave/client.d.ts +46 -2
  125. package/dist/providers/brave/client.d.ts.map +1 -1
  126. package/dist/providers/brave/client.js +55 -3
  127. package/dist/providers/brave/client.js.map +1 -1
  128. package/dist/providers/exa/adapter.d.ts.map +1 -1
  129. package/dist/providers/exa/adapter.js +10 -1
  130. package/dist/providers/exa/adapter.js.map +1 -1
  131. package/dist/providers/firecrawl/adapter.d.ts.map +1 -1
  132. package/dist/providers/firecrawl/adapter.js +13 -3
  133. package/dist/providers/firecrawl/adapter.js.map +1 -1
  134. package/dist/providers/minimax/adapter.d.ts.map +1 -1
  135. package/dist/providers/minimax/adapter.js +4 -0
  136. package/dist/providers/minimax/adapter.js.map +1 -1
  137. package/dist/providers/selection.d.ts +114 -1
  138. package/dist/providers/selection.d.ts.map +1 -1
  139. package/dist/providers/selection.js +99 -3
  140. package/dist/providers/selection.js.map +1 -1
  141. package/dist/providers/tavily/adapter.d.ts.map +1 -1
  142. package/dist/providers/tavily/adapter.js +2 -0
  143. package/dist/providers/tavily/adapter.js.map +1 -1
  144. package/dist/providers/types.d.ts +33 -1
  145. package/dist/providers/types.d.ts.map +1 -1
  146. package/dist/providers/types.js +8 -0
  147. package/dist/providers/types.js.map +1 -1
  148. package/dist/providers/zai/adapter.d.ts.map +1 -1
  149. package/dist/providers/zai/adapter.js +18 -5
  150. package/dist/providers/zai/adapter.js.map +1 -1
  151. package/package.json +2 -1
@@ -0,0 +1,402 @@
1
+ /**
2
+ * Quota normalization — capability/category mapping + authority-aware
3
+ * scoring (Plan B — PB-T3).
4
+ *
5
+ * Derives a remaining score per `(provider, capability)` from the **raw
6
+ * category snapshot** persisted by PB-T1, so PB-T4 can rank providers
7
+ * without learning any Provider's category schema. Pure derivation only:
8
+ * takes a {@link QuotaState} as input, returns scored/ranked results,
9
+ * never touches disk or transport.
10
+ *
11
+ * Two review fixes shape the contract:
12
+ *
13
+ * 1. **Map raw categories, not a pre-derived remaining.** Each Provider
14
+ * normalizes its native quota payload into named {@link QuotaCategory}
15
+ * entries (PB-T1). This module declares which category name governs
16
+ * which `(provider, capability)` pair, then reads that category's
17
+ * `current.remainingPercent` as the score. The score is already
18
+ * normalized 0..100 by `buildQuotaWindow`; this module does NOT
19
+ * re-derive or re-clamp.
20
+ *
21
+ * 2. **Separate authority from score.** The "neutral 50 yet never
22
+ * fullest" contradiction is resolved by representing unknown
23
+ * authority explicitly rather than encoding it as a numeric score.
24
+ * Providers with a real credit/token signal form a **known tier**,
25
+ * ranked by score; providers without a signal (Brave rate-limit,
26
+ * Exa none) form an **unknown tier**, ranked after every known
27
+ * provider. The unknown tier never wins over a known provider, even
28
+ * a low-scored one.
29
+ *
30
+ * Boundary rules:
31
+ * - Imports the quota contract types from `capabilities/quota.js`,
32
+ * provider identity/capability types from `providers/types.js`, and
33
+ * PB-T1's `QuotaState` from `lib/quota-store.js`. No provider
34
+ * transport, no command presentation, no `MainDependencies`.
35
+ * - **Pure module.** No disk I/O, no transport, no
36
+ * `process.stderr.write`. Warning output is returned to the caller
37
+ * through an `onWarning` callback; the scoring result itself never
38
+ * observes the outside world.
39
+ * - **Fail-open on drift.** If a mapped category name is absent from
40
+ * the live snapshot (provider renamed it), degrade to the
41
+ * provider-level fallback, then to **unknown** — never hard-fail.
42
+ * Each degradation emits a structured warning so drift is visible.
43
+ *
44
+ * Relation to other Plan B tickets:
45
+ * - PB-T1: this module reads `QuotaState` (the persisted snapshot);
46
+ * it does not write.
47
+ * - PB-T2: consumption events advance `locallyUpdatedAt` and adjust
48
+ * category estimates. This module reads the resulting category
49
+ * `current` window; the locally-decremented value is the score.
50
+ * - PB-T4: consumes `rankProvidersForCapability` and applies the
51
+ * selection algorithm. This module never selects.
52
+ */
53
+ import type { ProviderCapability, ProviderId } from "../providers/types.js";
54
+ import type { QuotaState } from "./quota-store.js";
55
+ /**
56
+ * The authority-aware score for a single `(provider, capability)` pair.
57
+ *
58
+ * - `authority: "known"` — the provider exposes a real credit/token
59
+ * signal and the mapped category was found in the snapshot. `score`
60
+ * is the category's `current.remainingPercent` (already normalized
61
+ * 0..100 by PB-T1). `category` is the matched category name (after
62
+ * alias resolution / fallback), so PB-T4 can surface which pool was
63
+ * ranked.
64
+ * - `authority: "unknown"` — no authoritative signal is available
65
+ * (provider has no spend quota; snapshot missing; mapped category
66
+ * absent and no fallback matched; percent corrupt). `reason` is a
67
+ * stable, machine-readable reason code, NOT a user-facing message.
68
+ * Unknown entries are eligible as fallback but never win over a
69
+ * known-scored provider (PB-T4 contract).
70
+ *
71
+ * `unknown` is NEVER encoded as a numeric score (no neutral `50`, no
72
+ * `Infinity`, no `0`). This is the explicit fix for the "neutral 50 yet
73
+ * never fullest" contradiction flagged in review item 12: authority is
74
+ * a separate axis from score, and PB-T4 sorts the two tiers
75
+ * independently.
76
+ */
77
+ export type CapabilityScore = {
78
+ readonly authority: "known";
79
+ readonly score: number;
80
+ readonly category: string;
81
+ } | {
82
+ readonly authority: "unknown";
83
+ readonly reason: UnknownScoreReason;
84
+ };
85
+ /**
86
+ * Machine-readable reason for an unknown score. Stable across releases
87
+ * so callers (PB-T4, dashboards) can branch without parsing prose. The
88
+ * matching human-readable text lives in the warning metadata.
89
+ */
90
+ export type UnknownScoreReason =
91
+ /**
92
+ * The provider is in the always-unknown authority tier by policy
93
+ * (Brave rate-limit, Exa no quota capability). No category lookup
94
+ * is attempted.
95
+ */
96
+ "PROVIDER_NON_AUTHORITATIVE"
97
+ /**
98
+ * No mapping entry exists for `(provider, capability)`. Either the
99
+ * capability is observational (`quota`/`diagnostics`) or the
100
+ * mapping table has a gap (ticket: add a row + warn).
101
+ */
102
+ | "MAPPING_MISSING"
103
+ /**
104
+ * The provider has no snapshot in {@link QuotaState} (never
105
+ * harvested, or the entry was cleared).
106
+ */
107
+ | "SNAPSHOT_MISSING"
108
+ /**
109
+ * The snapshot exists but its `categories` array is empty.
110
+ */
111
+ | "SNAPSHOT_EMPTY"
112
+ /**
113
+ * None of the mapped aliases matched a category, and no
114
+ * provider-level fallback matched either. Likely provider-side
115
+ * rename (drift).
116
+ */
117
+ | "CATEGORY_NOT_FOUND"
118
+ /**
119
+ * The matched category's `remainingPercent` is not a finite number
120
+ * in 0..100. PB-T1's `buildQuotaWindow` is supposed to guarantee
121
+ * this, but a hand-edited `state.json` could violate it; the scorer
122
+ * treats corrupt input as unknown rather than synthesizing a score.
123
+ */
124
+ | "PERCENT_CORRUPT";
125
+ /**
126
+ * One row of the static mapping table: for `(provider, capability)`,
127
+ * which raw `QuotaCategory.name` governs the score.
128
+ *
129
+ * `categoryAliases` is an **ordered** list of acceptable category names.
130
+ * The first alias that matches a category in the live snapshot wins.
131
+ * This is the fail-open seam: when a provider renames a category, the
132
+ * lookup silently misses and the scorer degrades to the
133
+ * `providerFallbackCategory` (if any), then to unknown. Drift is
134
+ * surfaced through a structured warning.
135
+ *
136
+ * Case-sensitivity follows the existing normalizers: Tavily emits
137
+ * lowercase endpoint names (`search`, `crawl`, ...), Z.AI emits
138
+ * `requests`/`tokens`, Firecrawl emits a case-sensitive `Credits`. The
139
+ * alias list must match the normalizer's exact emission; do not
140
+ * case-fold here or the mapping will hide drift.
141
+ */
142
+ export interface CapabilityMappingEntry {
143
+ readonly provider: ProviderId;
144
+ readonly capability: ProviderCapability;
145
+ readonly categoryAliases: readonly string[];
146
+ /**
147
+ * Optional provider-level category used when no alias matches.
148
+ * For Tavily, this is the aggregate `requests` category — every
149
+ * endpoint shares one credit pool, so a missing endpoint category
150
+ * degrades to the pool-level remaining. For providers with one
151
+ * category per capability (Z.AI, Firecrawl), this is intentionally
152
+ * absent: a missing category means real drift, not a graceful
153
+ * fallback target.
154
+ */
155
+ readonly providerFallbackCategory?: string;
156
+ }
157
+ /**
158
+ * Default MiniMax model-name aliases per capability. MiniMax's
159
+ * `/remains` normalizer emits one category per live `model_name`
160
+ * string, and `model_name` values are arbitrary (the live schema does
161
+ * NOT emit a stable `general` label — see ticket
162
+ * `tests/quota-conformance.test.js:310-370` and fixtures including
163
+ * `zorla-x` and `abab6.5s-chat`). This table is the documented
164
+ * mapping policy: the first alias that matches a live category wins.
165
+ *
166
+ * Tests and PB-T4 callers can override this table via
167
+ * {@link ScoreOptions.minimaxModelAliases} when a deployment uses
168
+ * a different model name. Fail-open applies: an empty match degrades
169
+ * to unknown + warn, never a throw.
170
+ */
171
+ export declare const DEFAULT_MINIMAX_MODEL_ALIASES: Readonly<Record<"search" | "vision.interpret-image", readonly string[]>>;
172
+ /**
173
+ * The full Vision capability set advertised by Z.AI, plus the
174
+ * specialized operations MiniMax may attest. They all share the same
175
+ * category mapping within their provider (Z.AI → `tokens`, MiniMax →
176
+ * the VLM model alias), so the table is generated from one constant
177
+ * list per provider to keep the rows in sync.
178
+ */
179
+ export declare const ZAI_VISION_CAPABILITIES: readonly ProviderCapability[];
180
+ /**
181
+ * Specialized MiniMax Vision operations (mirror of the descriptor's
182
+ * attested set). They all share the VLM model alias.
183
+ */
184
+ export declare const MINIMAX_VISION_CAPABILITIES: readonly ProviderCapability[];
185
+ /**
186
+ * Z.AI capabilities that share the rolling `requests` category.
187
+ * `quota` and `diagnostics` are intentionally absent — they are
188
+ * observational, not selection candidates.
189
+ */
190
+ export declare const ZAI_REQUEST_CAPABILITIES: readonly ProviderCapability[];
191
+ /**
192
+ * Tavily endpoint-mapped capabilities. Each maps to a same-named
193
+ * endpoint category with a fallback to the aggregate `requests`
194
+ * pool (every Tavily endpoint bills against one credit pool).
195
+ */
196
+ export declare const TAVILY_ENDPOINT_CAPABILITIES: readonly ProviderCapability[];
197
+ /**
198
+ * Tavily `(capability → endpoint category name)` resolution. `reader`
199
+ * is mapped to the `extract` endpoint (the Tavily `/extract` endpoint
200
+ * serves reader calls). Other capabilities map to the same-named
201
+ * endpoint category.
202
+ */
203
+ export declare const TAVILY_CAPABILITY_TO_ENDPOINT: Readonly<Record<ProviderCapability, string | undefined>>;
204
+ /**
205
+ * Firecrawl capabilities. All four consume the shared `Credits` pool.
206
+ */
207
+ export declare const FIRECRAWL_CREDIT_CAPABILITIES: readonly ProviderCapability[];
208
+ /**
209
+ * The static capability→category mapping table. Built once at module
210
+ * load from the per-provider capability lists so a future capability
211
+ * addition only edits one constant, not 8 rows.
212
+ *
213
+ * Excluded by design:
214
+ * - Brave: always-unknown authority (rate-limit, not spend).
215
+ * - Exa: always-unknown authority (no quota capability).
216
+ * - `quota`/`diagnostics` on every provider: observational, not
217
+ * selection candidates.
218
+ *
219
+ * The table is `readonly` and exported so PB-T5/dashboards/Doctor can
220
+ * render the same source of truth the scorer uses.
221
+ */
222
+ export declare const CAPABILITY_MAPPINGS: readonly CapabilityMappingEntry[];
223
+ /**
224
+ * Per-provider authority policy.
225
+ *
226
+ * - `"mapped"` — the provider exposes real credit/token signals; its
227
+ * categories map to capabilities via {@link CAPABILITY_MAPPINGS} and
228
+ * the score is the matched category's `remainingPercent`.
229
+ * - `"always-unknown"` — the provider has no authoritative spend
230
+ * signal. {@link CapabilityScore} always returns `authority:"unknown"`
231
+ * with the documented reason, regardless of whether a snapshot
232
+ * exists. The provider remains **eligible** for PB-T4 fallback, but
233
+ * it never wins over a known-scored provider.
234
+ *
235
+ * `reason` is surfaced unchanged through the warning channel when a
236
+ * score is requested for an always-unknown provider; it documents the
237
+ * policy for dashboards and Doctor.
238
+ */
239
+ export interface ProviderAuthorityPolicy {
240
+ readonly provider: ProviderId;
241
+ readonly kind: "mapped" | "always-unknown";
242
+ readonly reason: string;
243
+ }
244
+ /**
245
+ * The static authority-policy table. Two providers are explicitly
246
+ * non-authoritative:
247
+ *
248
+ * - **Brave**: reports a rate-limit window via `X-RateLimit-*` headers,
249
+ * not spend or credits consumed. Brave uses metered billing, so the
250
+ * `remainingPercent` is a rate-limit signal, not a budget signal
251
+ * (see `BRAVE_QUOTA_CAVEAT` in `providers/brave/quota.ts`). The
252
+ * numeric window is retained for PB-T5 dashboard display; the
253
+ * authority axis deliberately ignores it.
254
+ * - **Exa**: advertises no `quota` capability at all. There is nothing
255
+ * to map or synthesize.
256
+ *
257
+ * Both providers stay **eligible** for PB-T4 fallback (their
258
+ * `authority:"unknown"` score sorts after every known provider), so
259
+ * they can still be picked when no known provider remains.
260
+ */
261
+ export declare const PROVIDER_AUTHORITY_POLICIES: readonly ProviderAuthorityPolicy[];
262
+ /**
263
+ * A structured warning emitted by the scorer. The pure module never
264
+ * writes to stderr; it returns warnings through the
265
+ * {@link ScoreOptions.onWarning} callback so the caller (PB-T4 / main)
266
+ * owns the rendering surface.
267
+ *
268
+ * `code` is stable across releases so dashboards can de-duplicate.
269
+ * `message` is a single-line human-readable string suitable for stderr.
270
+ */
271
+ export interface QuotaMappingWarning {
272
+ readonly code: "PROVIDER_NON_AUTHORITATIVE" | "MAPPING_MISSING" | "SNAPSHOT_MISSING" | "SNAPSHOT_EMPTY" | "CATEGORY_NOT_FOUND" | "PROVIDER_FALLBACK_USED" | "PERCENT_CORRUPT";
273
+ readonly provider: ProviderId;
274
+ readonly capability: ProviderCapability;
275
+ readonly message: string;
276
+ }
277
+ /**
278
+ * Look up the authority policy for a provider. Returns `undefined`
279
+ * only if the registry learns a new provider ID without a corresponding
280
+ * policy row; the scorer treats undefined as `"always-unknown"` so an
281
+ * unmapped provider never accidentally wins.
282
+ */
283
+ export declare function getProviderAuthorityPolicy(provider: ProviderId): ProviderAuthorityPolicy | undefined;
284
+ /**
285
+ * Look up the static mapping entry for `(provider, capability)`.
286
+ * Returns `undefined` when no row exists (observational capability,
287
+ * unknown capability, or a mapping-table gap).
288
+ *
289
+ * For MiniMax, the returned entry has an empty `categoryAliases`
290
+ * sentinel; the scorer expands it via
291
+ * {@link resolveMiniMaxAliasesForCapability}.
292
+ */
293
+ export declare function getCapabilityMapping(provider: ProviderId, capability: ProviderCapability): CapabilityMappingEntry | undefined;
294
+ /**
295
+ * Resolve the MiniMax alias list for a capability. Search returns the
296
+ * `search` aliases; every MiniMax vision capability returns the
297
+ * `vision.interpret-image` aliases (they all share the VLM transport).
298
+ * Unknown capabilities return an empty list.
299
+ */
300
+ export declare function resolveMiniMaxAliasesForCapability(capability: ProviderCapability, aliases?: Readonly<Record<"search" | "vision.interpret-image", readonly string[]>>): readonly string[];
301
+ /**
302
+ * Options for {@link scoreCapability} and {@link rankProvidersForCapability}.
303
+ */
304
+ export interface ScoreOptions {
305
+ /**
306
+ * Override the MiniMax model-name alias table. Production uses
307
+ * {@link DEFAULT_MINIMAX_MODEL_ALIASES}; tests pass a tailored table
308
+ * to assert specific match paths.
309
+ */
310
+ readonly minimaxModelAliases?: Readonly<Record<"search" | "vision.interpret-image", readonly string[]>>;
311
+ /**
312
+ * Best-effort warning sink. The scorer never calls
313
+ * `process.stderr.write`; every degradation routes through this
314
+ * callback. Caller owns the rendering surface. Production wires a
315
+ * stderr writer; tests inject a recorder.
316
+ */
317
+ readonly onWarning?: (warning: QuotaMappingWarning) => void;
318
+ }
319
+ /**
320
+ * Derive the authority-aware score for a single `(provider, capability)`
321
+ * pair from the persisted {@link QuotaState}.
322
+ *
323
+ * Resolution order:
324
+ * 1. **Authority policy.** An `always-unknown` provider returns
325
+ * `{ authority: "unknown", reason: "PROVIDER_NON_AUTHORITATIVE" }`
326
+ * without consulting the snapshot. This is the Brave/Exa contract.
327
+ * 2. **Mapping presence.** A `(provider, capability)` with no row in
328
+ * {@link CAPABILITY_MAPPINGS} returns `reason: "MAPPING_MISSING"`.
329
+ * Observational capabilities (`quota`/`diagnostics`) hit this path
330
+ * by design.
331
+ * 3. **Snapshot presence.** Missing snapshot → `SNAPSHOT_MISSING`;
332
+ * empty `categories` array → `SNAPSHOT_EMPTY`.
333
+ * 4. **Alias match.** Walk the entry's effective alias list (static
334
+ * for most providers; MiniMax resolves through the alias table).
335
+ * The first category whose name matches wins.
336
+ * 5. **Provider-level fallback.** When no alias matches and the entry
337
+ * declares a `providerFallbackCategory`, look it up. A match
338
+ * emits a `PROVIDER_FALLBACK_USED` warning so drift is visible.
339
+ * 6. **Unknown + warn.** No match at all → `CATEGORY_NOT_FOUND`.
340
+ * 7. **Percent validation.** A matched category whose
341
+ * `remainingPercent` is non-finite or outside 0..100 returns
342
+ * `PERCENT_CORRUPT`. PB-T1's `buildQuotaWindow` is supposed to
343
+ * guarantee this, but a hand-edited `state.json` could violate
344
+ * it; the scorer treats corrupt input as unknown rather than
345
+ * synthesizing a score.
346
+ *
347
+ * This function is total: it never throws. Every failure path returns
348
+ * a typed unknown score; the warning channel explains why.
349
+ */
350
+ export declare function scoreCapability(state: QuotaState, provider: ProviderId, capability: ProviderCapability, options?: ScoreOptions): CapabilityScore;
351
+ /**
352
+ * A ranked provider entry. The order in the returned array is the
353
+ * selection order PB-T4 walks.
354
+ *
355
+ * - Known-tier entries appear first, sorted by `score` descending.
356
+ * Ties break by registry order (`PROVIDER_IDS` by default, or the
357
+ * `registryOrder` option).
358
+ * - Unknown-tier entries appear after every known entry, in registry
359
+ * order. They remain eligible as fallback.
360
+ *
361
+ * Optional fields are present only when meaningful: `score`/`category`
362
+ * for known entries; `reason` for unknown entries.
363
+ */
364
+ export interface RankedProvider {
365
+ readonly provider: ProviderId;
366
+ readonly authority: "known" | "unknown";
367
+ readonly score?: number;
368
+ readonly category?: string;
369
+ readonly reason?: UnknownScoreReason;
370
+ }
371
+ /**
372
+ * Rank candidate providers for a capability.
373
+ *
374
+ * Returns a new array (caller owns it). The ranking is deterministic
375
+ * for identical inputs: same `state` + same `candidates` + same
376
+ * `registryOrder` → byte-identical output order.
377
+ *
378
+ * Algorithm:
379
+ * 1. Score each candidate via {@link scoreCapability}.
380
+ * 2. Partition into known and unknown tiers.
381
+ * 3. Sort known tier by score desc; break ties by registry order.
382
+ * 4. Sort unknown tier by registry order only.
383
+ * 5. Concatenate: known first, then unknown.
384
+ *
385
+ * The "5% known beats unknown" contract falls out of steps 3–5: every
386
+ * known entry precedes every unknown entry regardless of score. A
387
+ * known provider at 5% remaining still ranks above a non-authoritative
388
+ * Brave/Exa provider, because Brave/Exa are in the unknown tier.
389
+ *
390
+ * Duplicate candidates are de-duplicated in first-occurrence order
391
+ * before scoring (defensive — PB-T4 builds candidate lists, and a
392
+ * duplicate would otherwise double-emit warnings).
393
+ */
394
+ export declare function rankProvidersForCapability(state: QuotaState, capability: ProviderCapability, candidates: readonly ProviderId[], options?: ScoreOptions & {
395
+ /**
396
+ * Stable registry order for tie-breaking. Defaults to
397
+ * {@link PROVIDER_IDS} (the canonical production order
398
+ * `[zai, minimax, tavily, exa, brave, firecrawl]`).
399
+ */
400
+ readonly registryOrder?: readonly ProviderId[];
401
+ }): readonly RankedProvider[];
402
+ //# sourceMappingURL=quota-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-mapping.d.ts","sourceRoot":"","sources":["../../src/lib/quota-mapping.ts"],"names":[],"mappings":"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"}