@askalf/dario 4.1.0 → 4.2.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 +111 -6
- package/dist/cli.js +92 -4
- package/dist/tui/tabs/config.js +30 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ That's the whole setup. Every tool that honors those env vars now runs on your s
|
|
|
34
34
|
|
|
35
35
|
**New in v4:** type `dario` (no args) in another terminal to open the interactive TUI — live request stream, per-model burn-rate, rate-limit utilization, and a config editor that writes to `~/.dario/config.json`. Migrating from v3? See [MIGRATION.md](MIGRATION.md).
|
|
36
36
|
|
|
37
|
+
**New in v4.1 — overage-guard:** dario halts itself the moment a single response carries `representative-claim: overage` and returns 503 with a clean error body until you run `dario resume` or the cooldown clears. Subscribers should never see an overage hit during normal operation; one means something is wrong, and continuing to forward requests bleeds against per-token billing. Active protection by default; flip to warn-only with `--overage-behavior=warn` or off entirely with `--no-overage-guard`.
|
|
38
|
+
|
|
37
39
|
```
|
|
38
40
|
┌─ dario v4 ──────────────────────────[ q quit · Tab next · ? help ]──┐
|
|
39
41
|
│ Status Config ▎Analytics▎ Hits Accounts Backends │
|
|
@@ -154,6 +156,105 @@ Reclassification flips the request from `five_hour` (your subscription) to `over
|
|
|
154
156
|
|
|
155
157
|
---
|
|
156
158
|
|
|
159
|
+
## What dario does when overage lands (v4.1)
|
|
160
|
+
|
|
161
|
+
v4 made the billing bucket visible per-request in the TUI's Hits tab. v4.1 turns that visibility into active protection.
|
|
162
|
+
|
|
163
|
+
The moment any upstream response carries `representative-claim: overage`, dario **halts the proxy**. Every subsequent `/v1/messages`, `/v1/complete`, `/v1/chat/completions` request returns `503` with an Anthropic-shaped error body the client surfaces verbatim:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"type": "error",
|
|
168
|
+
"error": {
|
|
169
|
+
"type": "dario_overage_guard",
|
|
170
|
+
"message": "dario halted to prevent API-rate bleed. A request was classified as 'overage' (per-token billing) instead of your subscription pool. To resume: run `dario resume` in another terminal, or wait until <ISO ts> for the cooldown to auto-clear. Details: github.com/askalf/dario/issues/288"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The state surfaces in four TUI tabs simultaneously — each answers a different question a user has when their bill suddenly starts moving:
|
|
176
|
+
|
|
177
|
+
| Tab | Question it answers | What it renders |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| **Status** | What's happening RIGHT NOW? | `⚠ HALTED` banner with triggering request, cause, live countdown to auto-resume, manual-resume hint |
|
|
180
|
+
| **Hits** | Which specific request triggered it? | Pinned banner across the top + red `!` marker + red row on the triggering request in the live buffer + 503-status row for any blocked-while-halted requests |
|
|
181
|
+
| **Analytics** | How often is this happening across my traffic? | New "Overage" bar in the rate-limit cluster, alongside 5h/7d — red the moment count is non-zero |
|
|
182
|
+
| **Config** | How do I tune this? | Four in-place-editable fields: `overageGuard.enabled`, `.behavior` (enum-validated halt/warn), `.cooldownMs`, `.notifyOs` |
|
|
183
|
+
|
|
184
|
+
Status and Hits during an active halt:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
┌─ dario v4.1 ────────────────────────[ q quit · Tab next · ? help ]──┐
|
|
188
|
+
│ ▎Status▎ Config Analytics Hits Accounts Backends │
|
|
189
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
190
|
+
│ Overage-guard │
|
|
191
|
+
│ ⚠ HALTED overage detected 12s ago │
|
|
192
|
+
│ Request: claude-opus-4-7 account=work │
|
|
193
|
+
│ Cause: representative-claim = overage │
|
|
194
|
+
│ Auto-resume in 29m 48s │
|
|
195
|
+
│ Manual resume press R here, or `dario resume` from any shell │
|
|
196
|
+
│ │
|
|
197
|
+
│ Last refresh: just now. r refresh · R resume. │
|
|
198
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
┌─ dario v4.1 ────────────────────────[ q quit · Tab next · ? help ]──┐
|
|
203
|
+
│ Status Config Analytics ▎Hits▎ Accounts Backends │
|
|
204
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
205
|
+
│ Hits 248 buffered · live │
|
|
206
|
+
│ │
|
|
207
|
+
│ ⚠ HALTED overage detected at 15:54:28 on opus-4-7 acct=work │
|
|
208
|
+
│ → New /v1/messages return 503 until R here, or `dario resume` │
|
|
209
|
+
│ │
|
|
210
|
+
│ time model in out lat st │
|
|
211
|
+
│ ▎15:54:31 opus-4-7 2.1k — — 503 │
|
|
212
|
+
│ 15:54:29 haiku-4-5 120 24 0.3s 200 │
|
|
213
|
+
│ ! 15:54:28 opus-4-7 1.4k 216 1.2s 200 ◀ red row │
|
|
214
|
+
│ 15:54:25 sonnet-4-6 1.2k 480 0.8s 200 │
|
|
215
|
+
│ 15:54:20 opus-4-7 842 216 1.2s 200 │
|
|
216
|
+
│ ────────────────────────────────────────────────────────────── │
|
|
217
|
+
│ Selected: 15:54:31 req_011Cb52VKMBsB6z6w28NvMn │
|
|
218
|
+
│ Account: work │
|
|
219
|
+
│ Model: claude-opus-4-7 │
|
|
220
|
+
│ Billing bucket: (halted before upstream — no claim) │
|
|
221
|
+
│ Status: 503 dario_overage_guard │
|
|
222
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Analytics — the burn-rate view, with the new Overage bar at the bottom of the rate-limit cluster (here showing one overage hit out of 248 — which is enough to halt by default):
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
┌─ dario v4.1 ────────────────────────[ q quit · Tab next · ? help ]──┐
|
|
229
|
+
│ Status Config ▎Analytics▎ Hits Accounts Backends │
|
|
230
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
231
|
+
│ Analytics — last 60 min │
|
|
232
|
+
│ │
|
|
233
|
+
│ Requests: 248 (4.1/min) │
|
|
234
|
+
│ Tokens in: 142,830 │
|
|
235
|
+
│ Tokens out: 38,200 │
|
|
236
|
+
│ Subscription %: 99% │
|
|
237
|
+
│ │
|
|
238
|
+
│ Rate-limit │
|
|
239
|
+
│ 5h ████░░░░░░░░░░░░░░░░░░░░░░░░ 18% │
|
|
240
|
+
│ 7d ██░░░░░░░░░░░░░░░░░░░░░░░░░░ 8% │
|
|
241
|
+
│ Overage █░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1 req of 248 │
|
|
242
|
+
│ ⮤ red — the moment count is non-zero │
|
|
243
|
+
│ │
|
|
244
|
+
│ Billing │
|
|
245
|
+
│ subscription 247 req │
|
|
246
|
+
│ extra_usage 1 req │
|
|
247
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Why "halt at hit #1" is the right default: subscribers should never see a single overage response during normal operation. One means something is wrong — wire-shape drift, classifier change, account misconfig — and continuing to forward requests in the same shape bleeds real money for accounts with extra-usage enabled, or returns wall-of-rejections for accounts without it. The first hit is the signal; the second through hundredth are damage.
|
|
251
|
+
|
|
252
|
+
**Resume paths** — `dario resume` from any shell, `R` on the TUI Status tab, or the cooldown timer (default 30 min). **Configuration** — `~/.dario/config.json` → `overageGuard`, or CLI flags (`--overage-behavior=warn` for visibility-only, `--no-overage-guard` to disable, `--overage-cooldown=<ms>` to tune). **OS notification** — best-effort native toast (osascript / notify-send / BurntToast) plus terminal BEL as the unconditional floor. See [#288](https://github.com/askalf/dario/issues/288).
|
|
253
|
+
|
|
254
|
+
**Verified end-to-end live.** [`test/overage-guard-e2e-live.mjs`](./test/overage-guard-e2e-live.mjs) patches `globalThis.fetch` to mock the upstream, starts a real dario proxy in-process, and drives the five-stage halt cycle through real HTTP: subscription request flows → upstream returns overage → guard halts → next request returns 503 with the `dario_overage_guard` body → `POST /admin/resume` clears state → requests flow again. 20/20 assertions, 3 upstream calls intercepted (the halted request short-circuited at the request handler, never touched the upstream). Run with `node test/overage-guard-e2e-live.mjs`.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
157
258
|
## Does it actually work?
|
|
158
259
|
|
|
159
260
|
Four LLMs reviewed the codebase cold, same prompt ([`reviews/PROMPT.md`](./reviews/PROMPT.md)), each signed a verdict:
|
|
@@ -235,9 +336,10 @@ The tool doesn't know. The backend doesn't know. Dario is the seam.
|
|
|
235
336
|
- **Multi-account pool.** Drop 2+ Claude accounts in `~/.dario/accounts/` and pool mode auto-activates: every request routes to the account with the most headroom, multi-turn sessions pin to one account so the prompt cache survives, in-flight 429s fail over to a peer before your client sees an error. `dario accounts add work` / `dario accounts add personal`. → [`docs/multi-account-pool.md`](./docs/multi-account-pool.md)
|
|
236
337
|
- **Behavioral stealth (`--stealth`).** Static wire fidelity covers *what* the request looks like; `--stealth` adds *when* it arrives — response-length-correlated think time and 1.2–4.2s session-start latency, the inter-arrival pattern real interactive sessions have and agent loops don't. → [`docs/wire-fidelity.md`](./docs/wire-fidelity.md)
|
|
237
338
|
- **Runs any non-Claude-Code agent.** A 64-entry schema-verified `TOOL_MAP` pre-maps Cline, Roo, Kilo, Cursor, Windsurf, Continue, Copilot, OpenHands, OpenClaw, Hermes, [hands](https://github.com/askalf/hands) tool names to CC's native set. No flag, no validator errors. → [`docs/agent-compat.md`](./docs/agent-compat.md)
|
|
238
|
-
- **Shim mode
|
|
339
|
+
- **Shim mode** *(deprecated in v4.2; removal scheduled for v5.x)*. The original "no HTTP hop" path that patched `globalThis.fetch` inside a `dario shim -- <cmd>` child process. Empirically only matches 3 of the 8 wire-shape axes the billing classifier inspects (system blocks, agent identity, header order) and falls back to total passthrough when the client sends a 1-block system — which `claude -p` and Agent-SDK both do. Use **proxy mode** for any non-CC client; that's the only mode that rebuilds every request to CC's full canonical shape. Shim emits a deprecation banner on every invocation. See [CHANGELOG v4.2.0](./CHANGELOG.md) for the side-by-side fingerprint diff that drove this call.
|
|
239
340
|
- **Recover output capability.** `dario proxy --system-prompt=partial` strips CC's tone/verbosity/no-comments constraints for 1.2–2.8× more output on open-ended work — empirically without flipping billing (the classifier doesn't read that slot). [Discussion #183](https://github.com/askalf/dario/discussions/183) has the per-prompt receipts. → [`docs/system-prompt.md`](./docs/system-prompt.md)
|
|
240
341
|
- **Reachable from inside CC / any MCP client.** `dario subagent install` registers a CC sub-agent for in-session diagnostics; `dario mcp` exposes dario as a read-only MCP server. → [`docs/sub-agent.md`](./docs/sub-agent.md) · [`docs/mcp-server.md`](./docs/mcp-server.md)
|
|
342
|
+
- **Active overage protection (v4.1).** Halts the proxy on any `representative-claim: overage` response and returns 503 to subsequent requests until you run `dario resume` or the cooldown clears. Visibility-only mode (`--overage-behavior=warn`) for operators who want the signal without disrupting traffic. Halt state visible in TUI Status/Hits/Analytics tabs, surfaced as named SSE events, and as a best-effort native desktop notification. [#288](https://github.com/askalf/dario/issues/288).
|
|
241
343
|
|
|
242
344
|
---
|
|
243
345
|
|
|
@@ -245,11 +347,11 @@ The tool doesn't know. The backend doesn't know. Dario is the seam.
|
|
|
245
347
|
|
|
246
348
|
| Signal | Status |
|
|
247
349
|
|---|---|
|
|
248
|
-
| Source | **
|
|
350
|
+
| Source | **~18.5k** lines of TypeScript across **44** files — auditable in a weekend |
|
|
249
351
|
| Dependencies | **0 runtime.** Verify: `npm ls --production` |
|
|
250
|
-
| Provenance | Every release [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions + Sigstore
|
|
352
|
+
| Provenance | Every release [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions + Sigstore. v4.1.0 published 2026-05-16T15:13:24Z |
|
|
251
353
|
| Scanning | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) on every push and weekly |
|
|
252
|
-
| Tests | **
|
|
354
|
+
| Tests | **80 test files**, **74 in default `npm test` suite** — green on every release |
|
|
253
355
|
| Drift response | [`cc-drift-watch.yml`](./.github/workflows/cc-drift-watch.yml) hourly cron, [`cc-drift-auto-release.yml`](./.github/workflows/cc-drift-auto-release.yml) auto-publish on merge — median CC-release → dario-release under one hour |
|
|
254
356
|
| Credentials | Never logged, redacted from errors, `0600` on disk in `0700` dirs; MCP server redacts at the tool boundary |
|
|
255
357
|
| Network | Binds `127.0.0.1` by default; upstream only to configured backends over HTTPS; hardcoded SSRF allowlist |
|
|
@@ -273,7 +375,7 @@ cd $(npm root -g)/@askalf/dario && npm ls --production
|
|
|
273
375
|
|
|
274
376
|
## Commands
|
|
275
377
|
|
|
276
|
-
`dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `shim` · `mcp` · `subagent {install,status,remove}` · `usage` · `config` · `upgrade` · `status` · `refresh` · `logout` · `help`
|
|
378
|
+
`dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `shim` · `mcp` · `subagent {install,status,remove}` · `usage` · `config` · `upgrade` · `status` · `refresh` · `resume` · `logout` · `help`
|
|
277
379
|
|
|
278
380
|
Full flag/env reference: [`docs/commands.md`](./docs/commands.md) · SDK examples + per-tool setup: [`docs/usage.md`](./docs/usage.md)
|
|
279
381
|
|
|
@@ -285,7 +387,10 @@ Full flag/env reference: [`docs/commands.md`](./docs/commands.md) · SDK example
|
|
|
285
387
|
Mechanically, dario uses your existing Claude Code OAuth tokens — it authenticates you as you, with your subscription, through Anthropic's official endpoints. Whether any particular use complies with current terms is between you and Anthropic; consult their terms and your agreement. Independent, unofficial, third-party — see [DISCLAIMER.md](DISCLAIMER.md).
|
|
286
388
|
|
|
287
389
|
**What does the v4 TUI actually do?**
|
|
288
|
-
Open `dario` with no args. Six tabs: **Status** shows proxy health + OAuth expiry + config source; **Config** edits `~/.dario/config.json` in place (bool toggles inline, numbers/strings open a prompt, `s` saves); **Analytics** polls `/analytics` every 2s and renders per-model bars + rate-limit utilization +
|
|
390
|
+
Open `dario` with no args. Six tabs: **Status** shows proxy health + OAuth expiry + config source + overage-guard state (v4.1: halt banner with countdown + `R` to resume); **Config** edits `~/.dario/config.json` in place (bool toggles inline, numbers/strings open a prompt, `s` saves); **Analytics** polls `/analytics` every 2s and renders per-model bars + rate-limit utilization + an Overage bar that's red the moment count is non-zero (v4.1); **Hits** subscribes to `/analytics/stream` SSE for the live request feed with per-record detail drilldown and a pinned halt banner when overage is detected (v4.1); **Accounts** lists the pool; **Backends** lists OpenAI-compat backends. Pure ANSI, zero new runtime deps. Migration from v3: [MIGRATION.md](MIGRATION.md).
|
|
391
|
+
|
|
392
|
+
**What if a request lands in `overage` despite the wire-shape replay?**
|
|
393
|
+
v4.1+ halts the proxy on the first overage response and returns 503 to subsequent requests until you investigate. See [What dario does when overage lands](#what-dario-does-when-overage-lands-v41). The TUI Status tab shows the triggering request + countdown to auto-resume; `dario resume` from any shell clears the halt immediately; `--overage-behavior=warn` switches to visibility-only mode if you'd rather see the signal than block traffic.
|
|
289
394
|
|
|
290
395
|
**Do I need Claude Code installed?**
|
|
291
396
|
Recommended, not required. With CC, `dario login` picks up credentials automatically and the live template extractor reads your binary on every startup. Without it, dario runs its own OAuth flow and falls back to the bundled (scrubbed) template snapshot.
|
package/dist/cli.js
CHANGED
|
@@ -216,8 +216,11 @@ async function resume() {
|
|
|
216
216
|
catch (err) {
|
|
217
217
|
const msg = err.message;
|
|
218
218
|
// The proxy-not-running case is the common failure path; surface a
|
|
219
|
-
// friendly hint instead of a raw
|
|
220
|
-
|
|
219
|
+
// friendly hint instead of a raw fetch error. Match across runtimes:
|
|
220
|
+
// - Node: 'ECONNREFUSED', 'fetch failed', 'ENOTFOUND', 'ETIMEDOUT'
|
|
221
|
+
// - Bun: 'Unable to connect' (different fetch error wording)
|
|
222
|
+
// - Both: 'connect EHOSTUNREACH', 'getaddrinfo' (DNS path)
|
|
223
|
+
if (/ECONNREFUSED|ENOTFOUND|ETIMEDOUT|EHOSTUNREACH|fetch failed|unable to connect|getaddrinfo/i.test(msg)) {
|
|
221
224
|
console.error(`[dario] No proxy running on localhost:${port}. Start one with \`dario proxy\` (overage-guard state is per-process; there's nothing to resume on a stopped proxy).`);
|
|
222
225
|
process.exit(1);
|
|
223
226
|
}
|
|
@@ -1024,6 +1027,11 @@ async function help() {
|
|
|
1024
1027
|
dario proxy [options] Start the API proxy server
|
|
1025
1028
|
dario status Check authentication status
|
|
1026
1029
|
dario refresh Force token refresh
|
|
1030
|
+
dario resume Clear the overage-guard halt on a running proxy.
|
|
1031
|
+
v4.1.0+. Idempotent: returns "no-op" if the
|
|
1032
|
+
proxy isn't halted. Errors with a friendly hint
|
|
1033
|
+
if no proxy is running on localhost:3456.
|
|
1034
|
+
POSTs /admin/resume on the local proxy. (dario#288)
|
|
1027
1035
|
dario logout Remove saved credentials
|
|
1028
1036
|
dario accounts list List accounts in the multi-account pool
|
|
1029
1037
|
dario accounts add NAME [--manual] [--from-keychain[=<target>]]
|
|
@@ -1045,8 +1053,13 @@ async function help() {
|
|
|
1045
1053
|
dario backend add NAME --key=sk-... [--base-url=...]
|
|
1046
1054
|
Add an OpenAI-compat backend (OpenAI, OpenRouter, Groq, etc.)
|
|
1047
1055
|
dario backend remove N Remove an OpenAI-compat backend
|
|
1048
|
-
dario shim -- CMD ARGS
|
|
1049
|
-
|
|
1056
|
+
dario shim -- CMD ARGS [DEPRECATED — removal scheduled for v5.x]
|
|
1057
|
+
Run CMD with dario's fetch-patch in-process.
|
|
1058
|
+
Only replaces 3 of 8 billing-classifier axes
|
|
1059
|
+
(system blocks, agent identity, header order).
|
|
1060
|
+
Falls back to passthrough on 1-block system
|
|
1061
|
+
requests (\`claude -p\`, Agent SDK). Use proxy
|
|
1062
|
+
mode for non-CC clients. See CHANGELOG v4.2.0.
|
|
1050
1063
|
dario subagent install Register ~/.claude/agents/dario.md so Claude Code
|
|
1051
1064
|
can delegate dario diagnostics / template-refresh
|
|
1052
1065
|
operations to a named sub-agent (v3.26)
|
|
@@ -1281,6 +1294,37 @@ async function help() {
|
|
|
1281
1294
|
ceiling server-side, so too-high values
|
|
1282
1295
|
return a clean 400.
|
|
1283
1296
|
Env: DARIO_MAX_TOKENS. (dario#88)
|
|
1297
|
+
--no-overage-guard Disable the overage-guard (v4.1.0+). Default
|
|
1298
|
+
behavior halts the proxy on any response with
|
|
1299
|
+
representative-claim=overage and returns 503
|
|
1300
|
+
with an Anthropic-shaped error body until
|
|
1301
|
+
cooldown expires or \`dario resume\` clears
|
|
1302
|
+
the state. Subscribers should never see an
|
|
1303
|
+
overage hit during normal operation; one
|
|
1304
|
+
means something is wrong (wire drift,
|
|
1305
|
+
classifier change, account misconfig).
|
|
1306
|
+
Env: DARIO_OVERAGE_GUARD=off. (dario#288)
|
|
1307
|
+
--overage-behavior=<halt|warn>
|
|
1308
|
+
Behavior when overage is detected (v4.1.0+):
|
|
1309
|
+
halt — return 503 to new /v1/messages
|
|
1310
|
+
requests until resume / cooldown.
|
|
1311
|
+
Default. Strongest protection.
|
|
1312
|
+
warn — emit events + OS notification only,
|
|
1313
|
+
keep forwarding. Visibility mode for
|
|
1314
|
+
operators who want the signal without
|
|
1315
|
+
cutting off traffic.
|
|
1316
|
+
Env: DARIO_OVERAGE_BEHAVIOR.
|
|
1317
|
+
--overage-cooldown=MS Ms to wait before auto-clearing the halt
|
|
1318
|
+
state (v4.1.0+). Default: 1800000 (30 min).
|
|
1319
|
+
Manual \`dario resume\` clears immediately
|
|
1320
|
+
regardless of this value.
|
|
1321
|
+
Env: DARIO_OVERAGE_COOLDOWN.
|
|
1322
|
+
--no-overage-notify Suppress the native desktop notification on
|
|
1323
|
+
halt (v4.1.0+). Terminal BEL is the
|
|
1324
|
+
unconditional floor; TUI banner + SSE event
|
|
1325
|
+
still fire regardless. Use in headless / CI
|
|
1326
|
+
contexts where toast popups don't make sense.
|
|
1327
|
+
Env: DARIO_OVERAGE_NOTIFY=off.
|
|
1284
1328
|
--port=PORT Port to listen on (default: 3456)
|
|
1285
1329
|
--host=ADDRESS Address to bind to (default: 127.0.0.1)
|
|
1286
1330
|
Use 0.0.0.0 for LAN; see README for DARIO_API_KEY
|
|
@@ -1396,6 +1440,50 @@ async function shim() {
|
|
|
1396
1440
|
console.error(' dario shim --priority=below-normal -- claude (recommended on Windows when RDP\'d into the host)');
|
|
1397
1441
|
process.exit(1);
|
|
1398
1442
|
}
|
|
1443
|
+
// v4.2.0+: shim mode is DEPRECATED — set for removal in v5.x.
|
|
1444
|
+
//
|
|
1445
|
+
// The empirical reason (verified by side-by-side fingerprint diff of
|
|
1446
|
+
// shim's `_rewriteBody` against the proxy's `buildCCRequest` — see
|
|
1447
|
+
// CHANGELOG v4.2.0 entry): shim mode only replaces 3 of the 8 axes
|
|
1448
|
+
// Anthropic's billing classifier actually inspects (system blocks,
|
|
1449
|
+
// agent identity, header order). It leaves the client's JSON key
|
|
1450
|
+
// order, max_tokens value, metadata billing tag, and any non-CC
|
|
1451
|
+
// fields (temperature, top_p, service_tier) unchanged on the wire.
|
|
1452
|
+
// And on the most-common claude -p / Agent-SDK request shape (which
|
|
1453
|
+
// sends a 1-block system, not the 3-block shape shim's shape-check
|
|
1454
|
+
// hardcodes), shim silently falls back to total passthrough — sending
|
|
1455
|
+
// the client's raw body to api.anthropic.com with zero replay.
|
|
1456
|
+
//
|
|
1457
|
+
// For interactive CC (`dario shim -- claude`), this is mostly a no-op
|
|
1458
|
+
// because CC's own outbound already matches every axis dario would
|
|
1459
|
+
// synthesize. But for any non-CC client (`dario shim -- aider`,
|
|
1460
|
+
// `dario shim -- cline`, your own scripts), shim mode does not deliver
|
|
1461
|
+
// the wire fidelity the README claims.
|
|
1462
|
+
//
|
|
1463
|
+
// We warn loudly here instead of silently breaking, and point users
|
|
1464
|
+
// at proxy mode. Set DARIO_SHIM_NO_DEPRECATION_WARNING=1 to suppress
|
|
1465
|
+
// the banner for scripts that need the exit-code semantics but have
|
|
1466
|
+
// already migrated their understanding.
|
|
1467
|
+
if (process.env['DARIO_SHIM_NO_DEPRECATION_WARNING'] !== '1') {
|
|
1468
|
+
console.error('');
|
|
1469
|
+
console.error('[dario] ⚠ DEPRECATION: `dario shim` is deprecated in v4.2 and scheduled for removal in v5.x.');
|
|
1470
|
+
console.error('[dario]');
|
|
1471
|
+
console.error('[dario] Shim mode only matches a subset of the wire-shape axes Anthropic\'s billing classifier');
|
|
1472
|
+
console.error('[dario] inspects. Specifically, it does not normalize JSON key order, max_tokens, metadata');
|
|
1473
|
+
console.error('[dario] billing-tag, or non-CC body fields. On `claude -p` / Agent-SDK style requests (1-block');
|
|
1474
|
+
console.error('[dario] system), shim falls back to total passthrough — the client\'s raw body reaches the');
|
|
1475
|
+
console.error('[dario] upstream unchanged.');
|
|
1476
|
+
console.error('[dario]');
|
|
1477
|
+
console.error('[dario] Use proxy mode instead, which rebuilds every request to CC\'s exact wire shape:');
|
|
1478
|
+
console.error('[dario]');
|
|
1479
|
+
console.error('[dario] Terminal 1: dario proxy');
|
|
1480
|
+
console.error('[dario] Terminal 2: ANTHROPIC_BASE_URL=http://localhost:3456 \\');
|
|
1481
|
+
console.error('[dario] ANTHROPIC_API_KEY=dario \\');
|
|
1482
|
+
console.error('[dario] ' + childArgs.join(' '));
|
|
1483
|
+
console.error('[dario]');
|
|
1484
|
+
console.error('[dario] To suppress this banner: DARIO_SHIM_NO_DEPRECATION_WARNING=1');
|
|
1485
|
+
console.error('');
|
|
1486
|
+
}
|
|
1399
1487
|
const { runShim } = await import('./shim/host.js');
|
|
1400
1488
|
try {
|
|
1401
1489
|
const result = await runShim({
|
package/dist/tui/tabs/config.js
CHANGED
|
@@ -217,15 +217,45 @@ function commitEdit(state) {
|
|
|
217
217
|
if (!Number.isFinite(n)) {
|
|
218
218
|
return { ...state, editBuffer: null, statusMessage: `Not a number: "${state.editBuffer}"`, statusKind: 'error' };
|
|
219
219
|
}
|
|
220
|
+
// Path-specific guards. cooldownMs must be non-negative — silently
|
|
221
|
+
// dropping a bad value on next config-file load is correct but lets
|
|
222
|
+
// the user save an invalid file. Surface immediately. (v4.1.1)
|
|
223
|
+
if (f.path === 'overageGuard.cooldownMs' && n < 0) {
|
|
224
|
+
return { ...state, editBuffer: null, statusMessage: `overageGuard.cooldownMs must be >= 0 (got ${n})`, statusKind: 'error' };
|
|
225
|
+
}
|
|
220
226
|
parsed = n;
|
|
221
227
|
}
|
|
222
228
|
}
|
|
229
|
+
else if (f.type === 'string') {
|
|
230
|
+
// String enums: validate so we reject bad input at commit time rather
|
|
231
|
+
// than let the proxy's sanitize() silently drop it on next load. v4.1.1
|
|
232
|
+
// adds the overageGuard.behavior enum; future enums register here.
|
|
233
|
+
const enumValues = STRING_ENUMS[f.path];
|
|
234
|
+
if (enumValues && !enumValues.includes(state.editBuffer)) {
|
|
235
|
+
return {
|
|
236
|
+
...state,
|
|
237
|
+
editBuffer: null,
|
|
238
|
+
statusMessage: `${f.label} must be one of: ${enumValues.join(', ')} (got "${state.editBuffer}")`,
|
|
239
|
+
statusKind: 'error',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
parsed = state.editBuffer;
|
|
243
|
+
}
|
|
223
244
|
else {
|
|
224
245
|
parsed = state.editBuffer;
|
|
225
246
|
}
|
|
226
247
|
const next = setByPath(state.config, f.path, parsed);
|
|
227
248
|
return { ...state, config: next, editBuffer: null, statusMessage: `Updated ${f.label}.`, statusKind: 'success' };
|
|
228
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Allowed values for string-enum fields. Keyed by FIELDS path. Anything
|
|
252
|
+
* absent here is treated as free-text (no enum validation). v4.1.1+ —
|
|
253
|
+
* additive: registering a new entry forces enum validation on the next
|
|
254
|
+
* commit without touching the rest of the editor.
|
|
255
|
+
*/
|
|
256
|
+
const STRING_ENUMS = {
|
|
257
|
+
'overageGuard.behavior': ['halt', 'warn'],
|
|
258
|
+
};
|
|
229
259
|
function doSave(state) {
|
|
230
260
|
try {
|
|
231
261
|
saveConfig(undefined, { ...state.config, version: CONFIG_SCHEMA_VERSION });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
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": {
|