@askalf/dario 5.4.19 → 5.4.21

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.
@@ -286,6 +286,8 @@ export declare function findInstalledCC(): {
286
286
  path: string | null;
287
287
  version: string | null;
288
288
  };
289
+ /** Test-only: drop the resolved-binary memo. */
290
+ export declare function _resetClaudeBinCacheForTest(): void;
289
291
  export declare function enumerateClaudeCandidates(): string[];
290
292
  /**
291
293
  * Given a captured /v1/messages request body, pull out the fields that
@@ -587,11 +587,32 @@ export function findInstalledCC() {
587
587
  const version = path ? probeInstalledCCVersion() : null;
588
588
  return { path, version };
589
589
  }
590
+ // Resolving the binary means enumerating candidates and, when there is more
591
+ // than one, SPAWNING each to compare versions. That is a subprocess per
592
+ // candidate per call, and there are four call sites (refresh, capture,
593
+ // findInstalledCC, drift). Profiling a proxy start showed ~720ms of blocking
594
+ // spawnSync, over half of a ~1270ms startup, from repeating this and the
595
+ // version probe. The installed binary cannot change mid-process, so resolve
596
+ // once. Keyed on the override so a test flipping DARIO_CLAUDE_BIN is not served
597
+ // a stale answer.
598
+ let _claudeBinCache = null;
599
+ /** Test-only: drop the resolved-binary memo. */
600
+ export function _resetClaudeBinCacheForTest() {
601
+ _claudeBinCache = null;
602
+ }
590
603
  function findClaudeBinary() {
591
604
  // Honor an explicit override first — useful for tests and for users on
592
605
  // non-standard installs.
593
- if (process.env.DARIO_CLAUDE_BIN)
594
- return process.env.DARIO_CLAUDE_BIN;
606
+ const override = process.env.DARIO_CLAUDE_BIN;
607
+ if (override)
608
+ return override;
609
+ if (_claudeBinCache && _claudeBinCache.key === '')
610
+ return _claudeBinCache.value;
611
+ const resolved = resolveClaudeBinaryUncached();
612
+ _claudeBinCache = { key: '', value: resolved };
613
+ return resolved;
614
+ }
615
+ function resolveClaudeBinaryUncached() {
595
616
  const candidates = enumerateClaudeCandidates();
596
617
  if (candidates.length === 0)
597
618
  return null;
package/dist/proxy.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { randomUUID, randomBytes, timingSafeEqual, createHash } from 'node:crypto';
3
- import { execSync } from 'node:child_process';
4
3
  import { readFileSync, readdirSync, createWriteStream } from 'node:fs';
5
4
  import { join } from 'node:path';
6
5
  import { homedir } from 'node:os';
@@ -11,7 +10,7 @@ import { buildHealthResponse, derivePoolStatus, shouldDiscloseHealthInternals }
11
10
  import { darioVersion } from './version.js';
12
11
  import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, overlayTemplateHeaderValues, forwardClientCCIdentityHeaders, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
13
12
  import { stampCch, hasCchSeed } from './cch.js';
14
- import { describeTemplate, detectDrift, checkCCCompat } from './live-fingerprint.js';
13
+ import { describeTemplate, detectDrift, checkCCCompat, probeInstalledCCVersion } from './live-fingerprint.js';
15
14
  import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs, reconcilePoolAccounts, resolvePoolStrategy } from './pool.js';
16
15
  import { Analytics, billingBucketFromClaim, formatUsageLogLine, SUBSCRIPTION_CLAIMS } from './analytics.js';
17
16
  import { OverageGuard, buildHaltErrorBody } from './overage-guard.js';
@@ -118,8 +117,15 @@ export function buildBillingTag(cliVersion, cch) {
118
117
  function detectCliVersion() {
119
118
  const templateVersion = CC_TEMPLATE._version || '2.1.100';
120
119
  try {
121
- const out = execSync('claude --version', { timeout: 5000, stdio: 'pipe' }).toString().trim();
122
- return out.match(/^([\d]+\.[\d]+\.[\d]+)/)?.[1] ?? templateVersion;
120
+ // Was its own execSync('claude --version'), which made this the THIRD
121
+ // synchronous spawn of a 259 MB binary during startup for one version
122
+ // string — findClaudeBinary probes candidates, probeInstalledCCVersion
123
+ // probes the winner, and this probed again. probeInstalledCCVersion is
124
+ // memoised per process and resolves the binary properly (honours
125
+ // DARIO_CLAUDE_BIN, picks the newest candidate) rather than trusting
126
+ // whatever bare `claude` the shell finds, so reusing it is both cheaper and
127
+ // more correct.
128
+ return probeInstalledCCVersion() ?? templateVersion;
123
129
  }
124
130
  catch {
125
131
  return templateVersion;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "5.4.19",
3
+ "version": "5.4.21",
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": {