@askalf/dario 3.29.0 → 3.30.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.
package/README.md CHANGED
@@ -11,10 +11,6 @@
11
11
  <a href="https://www.npmjs.com/package/@askalf/dario"><img src="https://img.shields.io/npm/dm/@askalf/dario" alt="Downloads"></a>
12
12
  </p>
13
13
 
14
- <p align="center">
15
- <sub><strong>v4 is not a version bump.</strong> The router was the prerequisite. What comes next uses it as a substrate. — <a href="https://github.com/askalf/dario/discussions/categories/announcements">watch this space</a></sub>
16
- </p>
17
-
18
14
  ```bash
19
15
  npm install -g @askalf/dario && dario proxy
20
16
  ```
@@ -26,7 +22,7 @@ One command, one local URL, every provider behind it. Point `ANTHROPIC_BASE_URL`
26
22
  - `llama-3.3-70b`, `deepseek-v3`, anything else → **Groq**, **OpenRouter**, **local LiteLLM**, **vLLM**, **Ollama**, whichever OpenAI-compat backend you wired up
27
23
  - Force a backend explicitly with a prefix: `openai:gpt-4o`, `groq:llama-3.3-70b`, `local:qwen-coder`, `claude:opus`
28
24
 
29
- Switching providers is a **model-name change** in your tool. Not a reconfigure. Not new base URLs. Not new API keys. Not a new SDK import. **Zero runtime dependencies. ~11,300 lines of TypeScript across ~25 files. ~1,250 assertions across 32 test suites. [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) on every release. Nothing phones home, ever.**
25
+ Switching providers is a **model-name change** in your tool. Not a reconfigure. Not new base URLs. Not new API keys. Not a new SDK import. **Zero runtime dependencies. ~10,750 lines of TypeScript across ~24 files. ~1,185 assertions across 32 test suites. [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) on every release. Nothing phones home, ever.**
30
26
 
31
27
  ---
32
28
 
@@ -98,11 +94,9 @@ Something broken? `dario doctor` prints a single aggregated health report — da
98
94
 
99
95
  **You want dario itself addressable from inside Claude Code or any MCP client.** `dario subagent install` registers a first-party sub-agent under `~/.claude/agents/dario.md` so CC can delegate diagnostics and template-refresh in-session ([Claude Code sub-agent hook](#claude-code-sub-agent-hook-v326)). `dario mcp` turns dario itself into a read-only MCP server — Claude Desktop, Cursor, Zed, any MCP-aware editor can introspect dario's state (auth, pool, backends, template, fingerprint, runtime) without leaving the editor ([dario as MCP server](#dario-as-mcp-server-v327)).
100
96
 
101
- **You want to share capacity with a trusted group without surveilling each other.** The **sealed-sender overflow protocol** uses RSA blind signatures (Chaum 1983, implemented from scratch over Node's `crypto`) so members of a trust group can lend unused Claude capacity to each other with cryptographic unlinkability. Dario ships the primitive; [mux](https://github.com/askalf/mux) is the dedicated product around it. See [Sealed-sender overflow](#sealed-sender-overflow-protocol).
102
-
103
97
  **You want certainty that the proxy isn't trivially fingerprintable.** The "get ahead of Anthropic" release track (v3.22 – v3.28) closed six observable divergence axes between dario and real Claude Code: body field order (v3.22), TLS ClientHello (v3.23), inter-request timing (v3.24), stream-consumption shape (v3.25), sub-agent/MCP reach (v3.26/v3.27), and session-id lifecycle (v3.28). See [Fingerprint axes](#fingerprint-axes).
104
98
 
105
- **You want to actually audit the thing.** ~11,300 lines of TypeScript across ~25 files. Zero runtime dependencies (`npm ls --production` confirms). Credentials at `~/.dario/` with `0600` permissions. `127.0.0.1`-only by default. Every release [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions. Nothing phones home. Small enough to read in a weekend.
99
+ **You want to actually audit the thing.** ~10,750 lines of TypeScript across ~24 files. Zero runtime dependencies (`npm ls --production` confirms). Credentials at `~/.dario/` with `0600` permissions. `127.0.0.1`-only by default. Every release [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions. Nothing phones home. Small enough to read in a weekend.
106
100
 
107
101
  ---
108
102
 
@@ -246,26 +240,6 @@ Every request carries a `billingBucket` field (`subscription` / `subscription_fa
246
240
 
247
241
  ---
248
242
 
249
- ## Sealed-sender overflow protocol
250
-
251
- Trust-group members can lend each other Claude capacity with **cryptographic unlinkability**: a lender can verify the borrower is a valid group member without learning *which* member, so no one in the pool can surveil another through borrow telemetry.
252
-
253
- **The primitive.** RSA blind signatures (Chaum 1983), implemented from scratch on top of Node's `crypto` module using `RSA_NO_PADDING` for raw `m^e mod n` / `c^d mod n` primitives. Full-Domain Hash via MGF1-SHA256 (with counter retry) prevents multiplicative forgery. The flow: the group admin signs *blinded* tokens in a batch without seeing their real values; the member unblinds locally to obtain valid RSA-FDH signatures on random tokens the admin has never seen. When a member spends a token with a lender, the lender verifies the signature with the group public key — it proves "some member got this signed" without identifying who.
254
-
255
- **What this is, and what it isn't.** This is **privacy between group members**, not anonymity from Anthropic. When a lender accepts a borrow, the actual upstream request still lands under the lender's attributable Claude account identity — Anthropic sees the lender as the originator, exactly as they would for any other request on that account. The cryptographic unlinkability protects group members from each other.
256
-
257
- **What's in the release:**
258
-
259
- - `src/sealed-pool.ts` — ~550 lines. `GroupAdmin` / `GroupMember` / `GroupLender` classes with quota/expiry enforcement, SHA-256-hashed double-spend set, JSON wire envelope (`{v:1, groupId, token, sig, request}`), and key export/import for distributing group credentials.
260
- - `POST /v1/pool/borrow` endpoint on the proxy, gated on `~/.dario/group.json`. Positioned before `checkAuth` — the group signature *is* the authentication, so doubling it with a local API key would add nothing. Verified borrows delegate to `pool.select()` and forward upstream under the lender's account.
261
- - 85 test assertions in `test/sealed-pool.mjs` covering raw RSA roundtrip, unlinkability, wrong-key / tampered-sig / wrong-group / double-spend rejection, key export/import, admin membership / quota / expiry enforcement, concurrent-borrow double-spend prevention, and end-to-end two-member unlinkability.
262
-
263
- Full feature-parity with `/v1/messages` (streaming, inside-request 429 failover, reverse tool mapping) for borrowed requests is intentionally a follow-up — the current release ships the cryptographic primitive and a working minimal endpoint; full integration layers on top.
264
-
265
- **Dedicated product.** The sealed-sender protocol has a dedicated product around it: [mux](https://github.com/askalf/mux). mux carries the group admin tooling (key generation, member roster, batch signing), the member workflow (prepare / finalize / status), the borrower CLI, and the lender daemon as a coherent surface. It uses dario as its backend — a mux lender runs a dario pool and fronts it with `/v1/pool/borrow`. Dario keeps the primitive here for anyone who wants to embed it without running the full mux flow; for peer-to-peer capacity sharing as a product, use mux.
266
-
267
- ---
268
-
269
243
  ## Shim mode
270
244
 
271
245
  *Experimental, opt-in. The proxy is still the default — shim mode is a second transport, not a replacement.*
@@ -405,6 +379,12 @@ A version marker (`<!-- dario-sub-agent-version: X -->`) embedded in the markdow
405
379
  | `DARIO_NO_BUN` | Disable automatic Bun relaunch | unset |
406
380
  | `DARIO_MIN_INTERVAL_MS` | Legacy name for `DARIO_PACE_MIN_MS`. Still honored; new name wins when both are set. | — |
407
381
  | `DARIO_CC_PATH` | Override path to the Claude Code binary for OAuth detection | auto-detect |
382
+ | `DARIO_OAUTH_CLIENT_ID` | Override the detected Claude OAuth client id as an emergency escape hatch | unset |
383
+ | `DARIO_OAUTH_AUTHORIZE_URL` | Override the detected Claude OAuth authorize URL | unset |
384
+ | `DARIO_OAUTH_TOKEN_URL` | Override the detected Claude OAuth token URL | unset |
385
+ | `DARIO_OAUTH_SCOPES` | Override the detected Claude OAuth scopes | unset |
386
+ | `DARIO_OAUTH_OVERRIDE_PATH` | Override file path for JSON OAuth overrides | `~/.dario/oauth-config.override.json` |
387
+ | `DARIO_OAUTH_DISABLE_OVERRIDE=1` | Ignore env/file OAuth overrides entirely | unset |
408
388
 
409
389
  ---
410
390
 
@@ -576,7 +556,6 @@ curl http://localhost:3456/health
576
556
  |---|---|
577
557
  | `POST /v1/messages` | Anthropic Messages API (Claude backend) |
578
558
  | `POST /v1/chat/completions` | OpenAI-compatible Chat API (routes by model name) |
579
- | `POST /v1/pool/borrow` | Sealed-sender borrow endpoint. Accepts group-signed tokens and forwards the request through the lender's pool. |
580
559
  | `GET /v1/models` | Model list (Claude models — OpenAI models come from the OpenAI backend directly) |
581
560
  | `GET /health` | Proxy health + OAuth status + request count |
582
561
  | `GET /status` | Detailed Claude OAuth token status |
@@ -591,11 +570,11 @@ Dario handles your OAuth tokens and API keys locally. Here's why you can trust i
591
570
 
592
571
  | Signal | Status |
593
572
  |---|---|
594
- | **Source code** | ~11,300 lines of TypeScript across ~25 files — small enough to audit in a weekend |
573
+ | **Source code** | ~10,750 lines of TypeScript across ~24 files — small enough to audit in a weekend |
595
574
  | **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
596
575
  | **npm provenance** | Every release is [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions with sigstore provenance attached to the transparency log |
597
576
  | **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
598
- | **Test footprint** | ~1,250 assertions across 32 test suites. Full `npm test` green on every release |
577
+ | **Test footprint** | ~1,185 assertions across 32 test suites. Full `npm test` green on every release |
599
578
  | **Credential handling** | Tokens and API keys never logged, redacted from errors, stored with `0600` permissions. MCP server (v3.27) redacts keys at the tool boundary too — not even a `sk-…` prefix leaks. |
600
579
  | **OAuth flow** | PKCE (Proof Key for Code Exchange), no client secret. `--manual` flow for headless setups (v3.20). |
601
580
  | **Network scope** | Binds to `127.0.0.1` by default. `--host` allows LAN/mesh with `DARIO_API_KEY` gating. Upstream traffic goes only to the configured backend target URLs over HTTPS |
@@ -644,6 +623,19 @@ Yes — anything that speaks the OpenAI Chat Completions API. Groq, OpenRouter,
644
623
  **What happens when Anthropic rotates the OAuth config?**
645
624
  Dario auto-detects OAuth config from the installed Claude Code binary. When CC ships a new version with rotated values, dario picks them up on the next run. Cache at `~/.dario/cc-oauth-cache-v4.json`, keyed by the CC binary fingerprint. (Path bumped from v3 → v4 in v3.19.4 to invalidate stale caches across the scope-list change that broke the authorize flow between CC v2.1.104 and v2.1.107.)
646
625
 
626
+ If Anthropic rotates the values before the detector is updated, you can temporarily override any field with env vars (`DARIO_OAUTH_CLIENT_ID`, `DARIO_OAUTH_AUTHORIZE_URL`, `DARIO_OAUTH_TOKEN_URL`, `DARIO_OAUTH_SCOPES`) or by writing `~/.dario/oauth-config.override.json`:
627
+
628
+ ```json
629
+ {
630
+ "clientId": "...",
631
+ "authorizeUrl": "https://claude.com/cai/oauth/authorize",
632
+ "tokenUrl": "https://platform.claude.com/v1/oauth/token",
633
+ "scopes": "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload"
634
+ }
635
+ ```
636
+
637
+ Env vars win over the file. Set `DARIO_OAUTH_DISABLE_OVERRIDE=1` to force pure auto-detection.
638
+
647
639
  **What happens when Anthropic changes the CC request template?**
648
640
  Dario extracts the live request template from your installed Claude Code binary on startup — the system prompt, tool schemas, user-agent, beta flags, header insertion order, static header values, and top-level request-body key order — and uses those to replay requests instead of a version pinned into dario itself. When CC ships a new version with a tweaked template, the next `dario proxy` run picks it up automatically. Drift detection forces a refresh when the installed CC version changes under dario, and the nightly `cc-drift-watch` workflow catches upstream rotations (client_id, URLs, tool set, version) the day they ship on npm.
649
641
 
@@ -699,7 +691,7 @@ The CHANGELOG documents every v3.22 – v3.28 "get ahead of Anthropic" release w
699
691
 
700
692
  ## Contributing
701
693
 
702
- PRs welcome. The codebase is small TypeScript — ~11,300 lines across ~25 files:
694
+ PRs welcome. The codebase is small TypeScript — ~10,750 lines across ~24 files:
703
695
 
704
696
  | File | Purpose |
705
697
  |---|---|
@@ -721,7 +713,6 @@ PRs welcome. The codebase is small TypeScript — ~11,300 lines across ~25 files
721
713
  | `src/oauth.ts` | Single-account token storage, PKCE flow, auto-refresh, manual/headless flow (v3.20) |
722
714
  | `src/accounts.ts` | Multi-account credential storage, independent OAuth lifecycle, refresh single-flight |
723
715
  | `src/pool.ts` | Account pool, headroom-aware routing, session stickiness, failover target selection |
724
- | `src/sealed-pool.ts` | Sealed-sender overflow protocol — RSA blind signatures for unlinkable group pooling |
725
716
  | `src/analytics.ts` | Rolling request history, per-account / per-model stats, burn-rate, billing bucket classification |
726
717
  | `src/openai-backend.ts` | OpenAI-compat backend credential storage and request forwarder |
727
718
  | `src/shim/runtime.cjs` | Hand-written CJS payload loaded into child processes via `NODE_OPTIONS=--require`; patches `globalThis.fetch` for Anthropic messages requests only |
@@ -734,7 +725,7 @@ git clone https://github.com/askalf/dario
734
725
  cd dario
735
726
  npm install
736
727
  npm run dev # runs with tsx, no build step
737
- npm test # ~1,250 assertions across 32 suites
728
+ npm test # ~1,185 assertions across 32 suites
738
729
  npm run e2e # live proxy + OAuth (requires a working Claude backend)
739
730
  ```
740
731
 
@@ -32,13 +32,17 @@
32
32
  * startup only re-scans when the user upgrades Claude Code. The cache suffix
33
33
  * is bumped each time scope handling or the fallback config changes, so
34
34
  * upgrading dario picks up the new values without a manual cache clear.
35
+ *
36
+ * Escape hatch: if Anthropic rotates OAuth metadata before the detector is
37
+ * updated, operators can temporarily override any detected value via env vars
38
+ * or ~/.dario/oauth-config.override.json.
35
39
  */
36
40
  export interface DetectedOAuthConfig {
37
41
  clientId: string;
38
42
  authorizeUrl: string;
39
43
  tokenUrl: string;
40
44
  scopes: string;
41
- source: 'detected' | 'cached' | 'fallback';
45
+ source: 'detected' | 'cached' | 'fallback' | 'override';
42
46
  ccPath?: string;
43
47
  ccHash?: string;
44
48
  }
@@ -32,6 +32,10 @@
32
32
  * startup only re-scans when the user upgrades Claude Code. The cache suffix
33
33
  * is bumped each time scope handling or the fallback config changes, so
34
34
  * upgrading dario picks up the new values without a manual cache clear.
35
+ *
36
+ * Escape hatch: if Anthropic rotates OAuth metadata before the detector is
37
+ * updated, operators can temporarily override any detected value via env vars
38
+ * or ~/.dario/oauth-config.override.json.
35
39
  */
36
40
  import { readFile, writeFile, mkdir, stat, open as openFile } from 'node:fs/promises';
37
41
  import { existsSync } from 'node:fs';
@@ -68,6 +72,7 @@ export const FALLBACK_FOR_DRIFT_CHECK = FALLBACK;
68
72
  // Anthropic now rejects (dario #42). On upgrade, users regenerate the cache
69
73
  // with the new FALLBACK scopes automatically — no manual clear required.
70
74
  const CACHE_PATH = join(homedir(), '.dario', 'cc-oauth-cache-v4.json');
75
+ const DEFAULT_OVERRIDE_PATH = join(homedir(), '.dario', 'oauth-config.override.json');
71
76
  function candidatePaths() {
72
77
  const home = homedir();
73
78
  if (platform() === 'win32') {
@@ -100,6 +105,69 @@ function findCCBinary() {
100
105
  }
101
106
  return null;
102
107
  }
108
+ function isOverrideDisabled() {
109
+ return process.env['DARIO_OAUTH_DISABLE_OVERRIDE'] === '1';
110
+ }
111
+ function getOverridePath() {
112
+ return process.env['DARIO_OAUTH_OVERRIDE_PATH']?.trim() || DEFAULT_OVERRIDE_PATH;
113
+ }
114
+ function cleanOverrideValue(value) {
115
+ const trimmed = value?.trim();
116
+ return trimmed ? trimmed : undefined;
117
+ }
118
+ function normalizeOverride(parsed) {
119
+ const override = {};
120
+ const clientId = typeof parsed.clientId === 'string' ? cleanOverrideValue(parsed.clientId) : undefined;
121
+ const authorizeUrl = typeof parsed.authorizeUrl === 'string' ? cleanOverrideValue(parsed.authorizeUrl) : undefined;
122
+ const tokenUrl = typeof parsed.tokenUrl === 'string' ? cleanOverrideValue(parsed.tokenUrl) : undefined;
123
+ const scopes = typeof parsed.scopes === 'string' ? cleanOverrideValue(parsed.scopes) : undefined;
124
+ if (clientId)
125
+ override.clientId = clientId;
126
+ if (authorizeUrl)
127
+ override.authorizeUrl = authorizeUrl;
128
+ if (tokenUrl)
129
+ override.tokenUrl = tokenUrl;
130
+ if (scopes)
131
+ override.scopes = scopes;
132
+ return Object.keys(override).length > 0 ? override : null;
133
+ }
134
+ async function loadManualOverride() {
135
+ if (isOverrideDisabled())
136
+ return null;
137
+ const envOverride = normalizeOverride({
138
+ clientId: process.env['DARIO_OAUTH_CLIENT_ID'],
139
+ authorizeUrl: process.env['DARIO_OAUTH_AUTHORIZE_URL'],
140
+ tokenUrl: process.env['DARIO_OAUTH_TOKEN_URL'],
141
+ scopes: process.env['DARIO_OAUTH_SCOPES'],
142
+ });
143
+ if (envOverride)
144
+ return envOverride;
145
+ try {
146
+ const raw = await readFile(getOverridePath(), 'utf-8');
147
+ const parsed = JSON.parse(raw);
148
+ return normalizeOverride(parsed);
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ function warnOnNonHttpsOverride(name, value) {
155
+ if (!value || /^https:\/\//i.test(value))
156
+ return;
157
+ console.warn(`[dario] OAuth override ${name} is non-HTTPS (${value}). ` +
158
+ 'Allowed as an emergency escape hatch, but double-check the source before using it.');
159
+ }
160
+ function applyManualOverride(config, override) {
161
+ if (!override)
162
+ return config;
163
+ warnOnNonHttpsOverride('authorizeUrl', override.authorizeUrl);
164
+ warnOnNonHttpsOverride('tokenUrl', override.tokenUrl);
165
+ return {
166
+ ...config,
167
+ ...override,
168
+ source: 'override',
169
+ };
170
+ }
103
171
  /**
104
172
  * Fast fingerprint of a binary for caching. We hash the first 64KB plus
105
173
  * size+mtime — this discriminates CC versions without reading GBs off disk.
@@ -135,9 +203,9 @@ export function scanBinaryForOAuthConfig(buf) {
135
203
  const anchorIdx = buf.indexOf(anchor);
136
204
  if (anchorIdx === -1)
137
205
  return null;
206
+ const windowStart = anchorIdx;
138
207
  // The prod config object is laid out roughly as one line of minified JS.
139
208
  // Take a generous window to be safe across minifier differences.
140
- const windowStart = anchorIdx;
141
209
  const windowEnd = Math.min(buf.length, anchorIdx + 2048);
142
210
  const prodBlock = buf.slice(windowStart, windowEnd).toString('latin1');
143
211
  const cidMatch = /CLIENT_ID\s*:\s*"([0-9a-f-]{36})"/i.exec(prodBlock);
@@ -146,7 +214,9 @@ export function scanBinaryForOAuthConfig(buf) {
146
214
  const clientId = cidMatch[1];
147
215
  // Defensive: if we somehow matched the dev client_id, reject — the
148
216
  // anchor should have put us in the prod block, but this guards against
149
- // the block being laid out in an unexpected order across builds.
217
+ // the block being laid out in an unexpected order across builds. Failing
218
+ // the scan and falling back is safer than authenticating against the
219
+ // wrong Anthropic OAuth client.
150
220
  if (clientId === '22422756-60c9-4084-8eb7-27705fd5cf9a')
151
221
  return null;
152
222
  let authorizeUrl = FALLBACK.authorizeUrl;
@@ -203,23 +273,22 @@ export async function detectCCOAuthConfig() {
203
273
  if (memoized)
204
274
  return memoized;
205
275
  try {
276
+ const manualOverride = await loadManualOverride();
206
277
  const ccPath = findCCBinary();
207
278
  if (!ccPath) {
208
- memoized = FALLBACK;
279
+ memoized = applyManualOverride(FALLBACK, manualOverride);
209
280
  return memoized;
210
281
  }
211
282
  const hash = await fingerprintBinary(ccPath);
212
- // Check cache
213
283
  const cached = await loadCache();
214
284
  if (cached && cached.hash === hash) {
215
- memoized = { ...cached.config, source: 'cached', ccPath, ccHash: hash };
285
+ memoized = applyManualOverride({ ...cached.config, source: 'cached', ccPath, ccHash: hash }, manualOverride);
216
286
  return memoized;
217
287
  }
218
- // Read binary and scan
219
288
  const buf = await readFile(ccPath);
220
289
  const scanned = scanBinaryForOAuthConfig(buf);
221
290
  if (!scanned) {
222
- memoized = { ...FALLBACK, ccPath, ccHash: hash };
291
+ memoized = applyManualOverride({ ...FALLBACK, ccPath, ccHash: hash }, manualOverride);
223
292
  return memoized;
224
293
  }
225
294
  const detected = {
@@ -229,11 +298,11 @@ export async function detectCCOAuthConfig() {
229
298
  ccHash: hash,
230
299
  };
231
300
  await saveCache(hash, detected);
232
- memoized = detected;
301
+ memoized = applyManualOverride(detected, manualOverride);
233
302
  return memoized;
234
303
  }
235
304
  catch {
236
- memoized = FALLBACK;
305
+ memoized = applyManualOverride(FALLBACK, await loadManualOverride());
237
306
  return memoized;
238
307
  }
239
308
  }
@@ -1,6 +1,6 @@
1
1
  {
2
- "_version": "2.1.112",
3
- "_captured": "2026-04-17T16:19:32.643Z",
2
+ "_version": "2.1.114",
3
+ "_captured": "2026-04-19T16:11:41.237Z",
4
4
  "_source": "bundled",
5
5
  "_schemaVersion": 3,
6
6
  "agent_identity": "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
@@ -170,7 +170,7 @@
170
170
  },
171
171
  {
172
172
  "name": "Bash",
173
- "description": "Executes a given bash command and returns its output.\n\nThe working directory persists between commands, but shell state does not. The shell environment is initialized from the user's profile (bash or zsh).\n\nIMPORTANT: Avoid using this tool to run `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user:\n\n - File search: Use Glob (NOT find or ls)\n - Content search: Use Grep (NOT grep or rg)\n - Read files: Use Read (NOT cat/head/tail)\n - Edit files: Use Edit (NOT sed/awk)\n - Write files: Use Write (NOT echo >/cat <<EOF)\n - Communication: Output text directly (NOT echo/printf)\nWhile the Bash tool can do similar things, it’s better to use the built-in tools as they provide a better user experience and make it easier to review tool calls and give permission.\n\n# Instructions\n - If your command will create new directories or files, first use this tool to run `ls` to verify the parent directory exists and is the correct location.\n - Always quote file paths that contain spaces with double quotes in your command (e.g., cd \"path with spaces/file.txt\")\n - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of `cd`. You may use `cd` if the User explicitly requests it.\n - You may specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). By default, your command will timeout after 120000ms (2 minutes).\n - You can use the `run_in_background` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.\n - When issuing multiple commands:\n - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. Example: if you need to run \"git status\" and \"git diff\", send a single message with two Bash tool calls in parallel.\n - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together.\n - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail.\n - DO NOT use newlines to separate commands (newlines are ok in quoted strings).\n - For git commands:\n - Prefer to create a new commit rather than amending an existing commit.\n - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.\n - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.\n - Avoid unnecessary `sleep` commands:\n - Do not sleep between commands that can run immediately — just run them.\n - Use the Monitor tool to stream events from a background process (each stdout line is a notification). For one-shot \"wait until done,\" use Bash with run_in_background instead.\n - If your command is long running and you would like to be notified when it finishes — use `run_in_background`. No sleep needed.\n - Do not retry failing commands in a sleep loop — diagnose the root cause.\n - If waiting for a background task you started with `run_in_background`, you will be notified when it completes — do not poll.\n - Long leading `sleep` commands are blocked. To poll until a condition is met, use Monitor with an until-loop (e.g. `until <check>; do sleep 2; done`) — you get a notification when the loop exits. Do not chain shorter sleeps to work around the block.\n\n\n# Committing changes with git\n\nOnly create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:\n\nYou can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. The numbered steps below indicate which commands should be batched in parallel.\n\nGit Safety Protocol:\n- NEVER update the git config\n- NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions. Taking unauthorized destructive actions is unhelpful and can result in lost work, so it's best to ONLY run these commands when given direct instructions \n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it\n- NEVER run force push to main/master, warn the user if they request it\n- CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit\n- When staging files, prefer adding specific files by name rather than using \"git add -A\" or \"git add .\", which can accidentally include sensitive files (.env, credentials) or large binaries\n- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive\n\n1. Run the following bash commands in parallel, each using the Bash tool:\n - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.\n - Run a git diff command to see both staged and unstaged changes that will be committed.\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \"add\" means a wholly new feature, \"update\" means an enhancement to an existing feature, \"fix\" means a bug fix, etc.).\n - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files\n - Draft a concise (1-2 sentences) commit message that focuses on the \"why\" rather than the \"what\"\n - Ensure it accurately reflects the changes and their purpose\n3. Run the following commands in parallel:\n - Add relevant untracked files to the staging area.\n - Create the commit with a message ending with:\n Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>\n - Run git status after the commit completes to verify success.\n Note: git status depends on the commit completing, so run it sequentially after the commit.\n4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit\n\nImportant notes:\n- NEVER run additional commands to read or explore code, besides git bash commands\n- NEVER use the TodoWrite or Agent tools\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\n- IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\n- In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:\n<example>\ngit commit -m \"$(cat <<'EOF'\n Commit message here.\n\n Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>\n EOF\n )\"\n</example>\n\n# Creating pull requests\nUse the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.\n\nIMPORTANT: When the user asks you to create a pull request, follow these steps carefully:\n\n1. Run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:\n - Run a git status command to see all untracked files (never use -uall flag)\n - Run a git diff command to see both staged and unstaged changes that will be committed\n - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote\n - Run a git log command and `git diff [base-branch]...HEAD` to understand the full commit history for the current branch (from the time it diverged from the base branch)\n2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request title and summary:\n - Keep the PR title short (under 70 characters)\n - Use the description/body for details, not the title\n3. Run the following commands in parallel:\n - Create new branch if needed\n - Push to remote with -u flag if needed\n - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.\n<example>\ngh pr create --title \"the pr title\" --body \"$(cat <<'EOF'\n## Summary\n<1-3 bullet points>\n\n## Test plan\n[Bulleted markdown checklist of TODOs for testing the pull request...]\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\nEOF\n)\"\n</example>\n\nImportant:\n- DO NOT use the TodoWrite or Agent tools\n- Return the PR URL when you're done, so the user can see it\n\n# Other common operations\n- View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments",
173
+ "description": "Executes a given bash command and returns its output.\n\nThe working directory persists between commands, but shell state does not. The shell environment is initialized from the user's profile (bash or zsh).\n\nIMPORTANT: Avoid using this tool to run `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user:\n\n - File search: Use Glob (NOT find or ls)\n - Content search: Use Grep (NOT grep or rg)\n - Read files: Use Read (NOT cat/head/tail)\n - Edit files: Use Edit (NOT sed/awk)\n - Write files: Use Write (NOT echo >/cat <<EOF)\n - Communication: Output text directly (NOT echo/printf)\nWhile the Bash tool can do similar things, it’s better to use the built-in tools as they provide a better user experience and make it easier to review tool calls and give permission.\n\n# Instructions\n - If your command will create new directories or files, first use this tool to run `ls` to verify the parent directory exists and is the correct location.\n - Always quote file paths that contain spaces with double quotes in your command (e.g., cd \"path with spaces/file.txt\")\n - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of `cd`. You may use `cd` if the User explicitly requests it. In particular, never prepend `cd <current-directory>` to a `git` command — `git` already operates on the current working tree, and the compound triggers a permission prompt.\n - You may specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). By default, your command will timeout after 120000ms (2 minutes).\n - You can use the `run_in_background` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.\n - When issuing multiple commands:\n - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. Example: if you need to run \"git status\" and \"git diff\", send a single message with two Bash tool calls in parallel.\n - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together.\n - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail.\n - DO NOT use newlines to separate commands (newlines are ok in quoted strings).\n - For git commands:\n - Prefer to create a new commit rather than amending an existing commit.\n - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.\n - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.\n - Avoid unnecessary `sleep` commands:\n - Do not sleep between commands that can run immediately — just run them.\n - Use the Monitor tool to stream events from a background process (each stdout line is a notification). For one-shot \"wait until done,\" use Bash with run_in_background instead.\n - If your command is long running and you would like to be notified when it finishes — use `run_in_background`. No sleep needed.\n - Do not retry failing commands in a sleep loop — diagnose the root cause.\n - If waiting for a background task you started with `run_in_background`, you will be notified when it completes — do not poll.\n - Long leading `sleep` commands are blocked. To poll until a condition is met, use Monitor with an until-loop (e.g. `until <check>; do sleep 2; done`) — you get a notification when the loop exits. Do not chain shorter sleeps to work around the block.\n\n\n# Committing changes with git\n\nOnly create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:\n\nYou can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. The numbered steps below indicate which commands should be batched in parallel.\n\nGit Safety Protocol:\n- NEVER update the git config\n- NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions. Taking unauthorized destructive actions is unhelpful and can result in lost work, so it's best to ONLY run these commands when given direct instructions \n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it\n- NEVER run force push to main/master, warn the user if they request it\n- CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit\n- When staging files, prefer adding specific files by name rather than using \"git add -A\" or \"git add .\", which can accidentally include sensitive files (.env, credentials) or large binaries\n- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive\n\n1. Run the following bash commands in parallel, each using the Bash tool:\n - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.\n - Run a git diff command to see both staged and unstaged changes that will be committed.\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \"add\" means a wholly new feature, \"update\" means an enhancement to an existing feature, \"fix\" means a bug fix, etc.).\n - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files\n - Draft a concise (1-2 sentences) commit message that focuses on the \"why\" rather than the \"what\"\n - Ensure it accurately reflects the changes and their purpose\n3. Run the following commands in parallel:\n - Add relevant untracked files to the staging area.\n - Create the commit with a message ending with:\n Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>\n - Run git status after the commit completes to verify success.\n Note: git status depends on the commit completing, so run it sequentially after the commit.\n4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit\n\nImportant notes:\n- NEVER run additional commands to read or explore code, besides git bash commands\n- NEVER use the TodoWrite or Agent tools\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\n- IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\n- In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:\n<example>\ngit commit -m \"$(cat <<'EOF'\n Commit message here.\n\n Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>\n EOF\n )\"\n</example>\n\n# Creating pull requests\nUse the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.\n\nIMPORTANT: When the user asks you to create a pull request, follow these steps carefully:\n\n1. Run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:\n - Run a git status command to see all untracked files (never use -uall flag)\n - Run a git diff command to see both staged and unstaged changes that will be committed\n - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote\n - Run a git log command and `git diff [base-branch]...HEAD` to understand the full commit history for the current branch (from the time it diverged from the base branch)\n2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request title and summary:\n - Keep the PR title short (under 70 characters)\n - Use the description/body for details, not the title\n3. Run the following commands in parallel:\n - Create new branch if needed\n - Push to remote with -u flag if needed\n - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.\n<example>\ngh pr create --title \"the pr title\" --body \"$(cat <<'EOF'\n## Summary\n<1-3 bullet points>\n\n## Test plan\n[Bulleted markdown checklist of TODOs for testing the pull request...]\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\nEOF\n)\"\n</example>\n\nImportant:\n- DO NOT use the TodoWrite or Agent tools\n- Return the PR URL when you're done, so the user can see it\n\n# Other common operations\n- View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments",
174
174
  "input_schema": {
175
175
  "$schema": "https://json-schema.org/draft/2020-12/schema",
176
176
  "type": "object",
@@ -913,47 +913,43 @@
913
913
  "Write"
914
914
  ],
915
915
  "header_order": [
916
- "host",
917
- "connection",
918
916
  "accept",
919
- "x-stainless-retry-count",
920
- "x-stainless-timeout",
917
+ "content-type",
918
+ "user-agent",
919
+ "x-claude-code-session-id",
920
+ "x-stainless-arch",
921
921
  "x-stainless-lang",
922
- "x-stainless-package-version",
923
922
  "x-stainless-os",
924
- "x-stainless-arch",
923
+ "x-stainless-package-version",
924
+ "x-stainless-retry-count",
925
925
  "x-stainless-runtime",
926
926
  "x-stainless-runtime-version",
927
+ "x-stainless-timeout",
928
+ "anthropic-beta",
927
929
  "anthropic-dangerous-direct-browser-access",
928
930
  "anthropic-version",
929
931
  "x-api-key",
930
932
  "x-app",
931
- "user-agent",
932
- "x-claude-code-session-id",
933
- "content-type",
934
- "anthropic-beta",
935
- "accept-language",
936
- "sec-fetch-mode",
933
+ "connection",
934
+ "host",
937
935
  "accept-encoding",
938
936
  "content-length"
939
937
  ],
940
- "anthropic_beta": "claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,effort-2025-11-24,afk-mode-2026-01-31",
938
+ "anthropic_beta": "claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01,effort-2025-11-24,afk-mode-2026-01-31",
941
939
  "header_values": {
942
940
  "accept": "application/json",
943
- "x-stainless-retry-count": "0",
944
- "x-stainless-timeout": "600",
941
+ "user-agent": "claude-cli/2.1.114 (external, sdk-cli)",
942
+ "x-stainless-arch": "x64",
945
943
  "x-stainless-lang": "js",
946
- "x-stainless-package-version": "0.81.0",
947
944
  "x-stainless-os": "Windows",
948
- "x-stainless-arch": "x64",
945
+ "x-stainless-package-version": "0.81.0",
946
+ "x-stainless-retry-count": "0",
949
947
  "x-stainless-runtime": "node",
950
- "x-stainless-runtime-version": "v22.21.1",
948
+ "x-stainless-runtime-version": "v24.3.0",
949
+ "x-stainless-timeout": "600",
951
950
  "anthropic-dangerous-direct-browser-access": "true",
952
951
  "anthropic-version": "2023-06-01",
953
- "x-app": "cli",
954
- "user-agent": "claude-cli/2.1.112 (external, sdk-cli)",
955
- "accept-language": "*",
956
- "sec-fetch-mode": "cors"
952
+ "x-app": "cli"
957
953
  },
958
954
  "body_field_order": [
959
955
  "model",
@@ -271,7 +271,7 @@ export declare function _resetInstalledVersionProbeForTest(): void;
271
271
  */
272
272
  export declare const SUPPORTED_CC_RANGE: {
273
273
  readonly min: "1.0.0";
274
- readonly maxTested: "2.1.112";
274
+ readonly maxTested: "2.1.114";
275
275
  };
276
276
  /**
277
277
  * Compare two dotted-numeric version strings. Returns negative if `a<b`,
@@ -711,7 +711,7 @@ export function _resetInstalledVersionProbeForTest() {
711
711
  */
712
712
  export const SUPPORTED_CC_RANGE = {
713
713
  min: '1.0.0',
714
- maxTested: '2.1.112',
714
+ maxTested: '2.1.114',
715
715
  };
716
716
  /**
717
717
  * Compare two dotted-numeric version strings. Returns negative if `a<b`,
package/dist/proxy.d.ts CHANGED
@@ -24,11 +24,9 @@ interface ProxyOptions {
24
24
  }
25
25
  export declare function sanitizeError(err: unknown): string;
26
26
  /**
27
- * Two-lane auth: DARIO_API_KEY (x-api-key / Authorization: Bearer) for
28
- * normal clients, and MUX_COORD_SECRET (X-Mux-Coord-Secret) for the mux
29
- * gateway forwarding a verified sealed borrow. If neither is configured
30
- * the request is allowed (loopback-only default). Exported for tests.
27
+ * API-key auth via DARIO_API_KEY (x-api-key or Authorization: Bearer).
28
+ * If unset, requests are allowed (loopback-only default). Exported for tests.
31
29
  */
32
- export declare function authenticateRequest(headers: IncomingMessage['headers'], apiKeyBuf: Buffer | null, mcsBuf: Buffer | null): boolean;
30
+ export declare function authenticateRequest(headers: IncomingMessage['headers'], apiKeyBuf: Buffer | null): boolean;
33
31
  export declare function startProxy(opts?: ProxyOptions): Promise<void>;
34
32
  export {};