@askalf/dario 5.4.0 → 5.4.1

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.
@@ -1430,9 +1430,7 @@
1430
1430
  "header_values": {
1431
1431
  "accept": "application/json",
1432
1432
  "user-agent": "claude-cli/2.1.220 (external, sdk-cli)",
1433
- "x-stainless-arch": "x64",
1434
1433
  "x-stainless-lang": "js",
1435
- "x-stainless-os": "Windows",
1436
1434
  "x-stainless-package-version": "0.94.0",
1437
1435
  "x-stainless-retry-count": "0",
1438
1436
  "x-stainless-runtime": "node",
@@ -170,6 +170,15 @@ export declare const CC_AGENT_IDENTITY: string;
170
170
  */
171
171
  export declare const CLIENT_SYSTEM_PREFACE: string;
172
172
  export declare function resolveSystemPrompt(arg: string | undefined, model?: string): string;
173
+ /**
174
+ * Overlay a captured template's `header_values` onto the outbound header record,
175
+ * skipping the keys that must never be replayed.
176
+ *
177
+ * Extracted as a pure function (like `orderHeadersForOutbound`) so the skip
178
+ * behaviour is unit-testable without spinning up the proxy. Mutates and returns
179
+ * `headers` for call-site convenience.
180
+ */
181
+ export declare function overlayTemplateHeaderValues(headers: Record<string, string>, headerValues: Record<string, string> | undefined): Record<string, string>;
173
182
  /**
174
183
  * Apply the live template's captured header_order to an outbound header
175
184
  * record. Returns a HeadersInit in one of two forms:
@@ -267,6 +267,45 @@ function stripBehavioralConstraints(input, level) {
267
267
  }
268
268
  return s;
269
269
  }
270
+ /**
271
+ * Header-value keys from a captured template that must NEVER be replayed onto an
272
+ * outbound request, even though they are stored in `header_values`.
273
+ *
274
+ * - `x-api-key` is a capture artifact: the fingerprint spawn sets
275
+ * ANTHROPIC_API_KEY=sk-dario-fingerprint-capture, and replaying that
276
+ * placeholder alongside a real OAuth Bearer 401s on some tiers (dario#42).
277
+ * - `x-stainless-os` / `x-stainless-arch` describe the machine that ran the
278
+ * CAPTURE, not CC's wire shape. The proxy already computes both correctly for
279
+ * the current process; overlaying the captured values made a Linux host
280
+ * announce `x-stainless-os: Windows` off a Windows-baked bundle (dario#854).
281
+ *
282
+ * `extractStaticHeaderValues` (live-fingerprint.ts) also refuses to STORE these,
283
+ * so new captures are clean. This skip list is what makes every ALREADY-baked
284
+ * template and warm cache self-heal without waiting for a re-bake.
285
+ */
286
+ const NEVER_REPLAY_HEADER_VALUES = new Set([
287
+ 'x-api-key',
288
+ 'x-stainless-os',
289
+ 'x-stainless-arch',
290
+ ]);
291
+ /**
292
+ * Overlay a captured template's `header_values` onto the outbound header record,
293
+ * skipping the keys that must never be replayed.
294
+ *
295
+ * Extracted as a pure function (like `orderHeadersForOutbound`) so the skip
296
+ * behaviour is unit-testable without spinning up the proxy. Mutates and returns
297
+ * `headers` for call-site convenience.
298
+ */
299
+ export function overlayTemplateHeaderValues(headers, headerValues) {
300
+ if (!headerValues)
301
+ return headers;
302
+ for (const [k, v] of Object.entries(headerValues)) {
303
+ if (NEVER_REPLAY_HEADER_VALUES.has(k.toLowerCase()))
304
+ continue;
305
+ headers[k] = v;
306
+ }
307
+ return headers;
308
+ }
270
309
  /**
271
310
  * Apply the live template's captured header_order to an outbound header
272
311
  * record. Returns a HeadersInit in one of two forms:
@@ -692,6 +692,23 @@ const STATIC_HEADER_EXCLUDE = new Set([
692
692
  'anthropic-beta',
693
693
  // Billing tag — rebuilt per request from cc_version
694
694
  'x-anthropic-billing-header',
695
+ // HOST-SPECIFIC (dario#854 fallout). These describe the machine that ran the
696
+ // capture, not CC's wire shape, so replaying them makes every consumer of a
697
+ // baked template announce the BAKE host's platform instead of its own. The
698
+ // proxy already computes both correctly per-process (OS_NAME / arch), and the
699
+ // overlay used to clobber those with the captured values.
700
+ //
701
+ // Found 2026-07-25: the bundled template had been baked on Windows for
702
+ // several releases (#820/#828/#840/#849/#851 -> x-stainless-os: Windows,
703
+ // 30 tools incl. PowerShell), while cc-drift-template-watch runs its live
704
+ // capture every 30 min on the Linux Hetzner runner. So the Linux box served
705
+ // `x-stainless-os: Windows`, and the watch saw permanent drift against a
706
+ // bundle it could never match -- auto-rebaking to Linux (#852), which the next
707
+ // Windows-side bake (#854) would flip straight back. Excluding these ends
708
+ // both the fidelity bug and the rebake ping-pong: the bake host stops
709
+ // mattering for these keys.
710
+ 'x-stainless-os',
711
+ 'x-stainless-arch',
695
712
  ]);
696
713
  function extractStaticHeaderValues(headers) {
697
714
  const out = {};
package/dist/proxy.js CHANGED
@@ -9,7 +9,7 @@ import { arch, platform } from 'node:process';
9
9
  import { getAccessToken, getStatus } from './oauth.js';
10
10
  import { buildHealthResponse, derivePoolStatus, shouldDiscloseHealthInternals } from './health-response.js';
11
11
  import { darioVersion } from './version.js';
12
- import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
12
+ import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, overlayTemplateHeaderValues, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
13
13
  import { stampCch, hasCchSeed } from './cch.js';
14
14
  import { describeTemplate, detectDrift, checkCCCompat } from './live-fingerprint.js';
15
15
  import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs, reconcilePoolAccounts, resolvePoolStrategy } from './pool.js';
@@ -1393,12 +1393,18 @@ export async function startProxy(opts = {}) {
1393
1393
  // "invalid x-api-key" 401 on some account tiers as of 2026-04-17 (dario#42).
1394
1394
  // The capture filter was updated in v3.19.2 to stop storing it, but the
1395
1395
  // per-request skip below lets existing caches self-heal without a refresh.
1396
- if (!passthrough && CC_TEMPLATE.header_values) {
1397
- for (const [k, v] of Object.entries(CC_TEMPLATE.header_values)) {
1398
- if (k.toLowerCase() === 'x-api-key')
1399
- continue;
1400
- staticHeaders[k] = v;
1401
- }
1396
+ // `x-stainless-os` / `x-stainless-arch` are skipped for the same
1397
+ // self-healing reason: they describe the machine that ran the CAPTURE, not
1398
+ // CC's wire shape. Overlaying them made a Linux box announce
1399
+ // `x-stainless-os: Windows` off a Windows-baked bundle (dario#854), so the
1400
+ // runtime values set above — OS_NAME and arch, correct for THIS process —
1401
+ // must win. The capture filter stops storing them going forward; this skip
1402
+ // keeps every already-baked template and warm cache honest immediately.
1403
+ //
1404
+ // The skip list lives with the overlay in cc-template.ts so it is unit-testable
1405
+ // without standing up the proxy (same reason orderHeadersForOutbound is pure).
1406
+ if (!passthrough) {
1407
+ overlayTemplateHeaderValues(staticHeaders, CC_TEMPLATE.header_values);
1402
1408
  }
1403
1409
  let requestCount = 0;
1404
1410
  const queue = new RequestQueue({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "5.4.0",
3
+ "version": "5.4.1",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {