@askalf/dario 4.8.108 โ†’ 4.8.110

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
@@ -18,7 +18,7 @@
18
18
 
19
19
  > ๐Ÿ—“๏ธ **2026-06-15 โ€” Anthropic splits Claude billing.** Agent-SDK and `claude -p` (headless) traffic stops counting against your subscription pool and moves to a small separate monthly credit ($20 / $100 / $200 by plan), then metered per-token API rates. Most proxies forward your requests in exactly the shape that gets reclassified into that bucket. dario rewrites every request into interactive Claude Code wire-shape before it leaves your machine, so your traffic stays in the subscription pool you already pay for โ€” same install, no config change for the cliff. **[What changes, and how to verify it on your own machine โ†’](#the-deadline-2026-06-15)**
20
20
 
21
- > โ›” **Claude Fable 5 / Mythos 5 โ€” temporarily suspended for all Anthropic customers.** On 2026-06-12 a US-government legal directive disabled Fable 5 and Mythos 5 for **every** Anthropic plan and tier โ€” `api.anthropic.com` now returns `not_found` for them, and no account or proxy can route around it ([details](https://www.anthropic.com/news/fable-mythos-access)). As of **v4.8.71**, dario filters both families out of `/v1/models` and rejects any spelling (`fable`, `fable1m`, `claude-fable-5`, `claude-fable-5[1m]`, `claude:fable`) up front with a clean `404` pointing at `claude-opus-4-8` / `claude-sonnet-4-6` โ€” instead of forwarding into a confusing upstream error. Reversible without a code change once access is restored: set `DARIO_SUSPENDED_MODELS=` (empty) on the instance. `npm install -g @askalf/dario@latest`
21
+ > โ›” **Claude Fable 5 / Mythos 5 โ€” temporarily suspended for all Anthropic customers.** On 2026-06-12 a US-government legal directive disabled Fable 5 and Mythos 5 for **every** Anthropic plan and tier โ€” `api.anthropic.com` now returns `not_found` for them, and no account or proxy can route around it ([details](https://www.anthropic.com/news/fable-mythos-access)). As of **v4.8.71**, dario filters both families out of `/v1/models` and rejects any spelling (`fable`, `fable1m`, `claude-fable-5`, `claude-fable-5[1m]`, `claude:fable`) up front with a clean `404` pointing at `claude-opus-4-8` / `claude-sonnet-5` โ€” instead of forwarding into a confusing upstream error. Reversible without a code change once access is restored: set `DARIO_SUSPENDED_MODELS=` (empty) on the instance. `npm install -g @askalf/dario@latest`
22
22
  >
23
23
  > โš ๏ธ Still on a version **before 4.8.39**? Upgrade now โ€” those could silently corrupt code/structured content routed through the proxy (the identifier scrub stripped tokens like the JS `continue` keyword). **[Details โ†’](https://github.com/askalf/dario/issues/457)**
24
24
 
@@ -76,7 +76,7 @@ Type `dario` with no args (in another terminal) to open a full-screen control pa
76
76
  โ”‚ โ”‚
77
77
  โ”‚ Per-model: โ”‚
78
78
  โ”‚ opus-4-8 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 60% (148 req) โ”‚
79
- โ”‚ sonnet-4-6 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 26% ( 64 req) โ”‚
79
+ โ”‚ sonnet-5 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 26% ( 64 req) โ”‚
80
80
  โ”‚ haiku-4-5 โ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 14% ( 35 req) โ”‚
81
81
  โ”‚ โ”‚
82
82
  โ”‚ Rate-limit: โ”‚
@@ -194,7 +194,7 @@ You point every tool at one URL. dario reads each request, decides which backend
194
194
 
195
195
  The tool doesn't know. The backend doesn't know. dario is the seam.
196
196
 
197
- **The full Claude lineup, autodetected.** Opus 4.8, Sonnet 4.6, and Haiku 4.5 โ€” plus `[1m]` long-context variants, generated by one rule for every family โ€” by full id (`claude-opus-4-8`) or shortcut (`opus` / `sonnet` / `haiku`, append `1m` for the long-context form). `GET /v1/models` asks Anthropic's live catalog (TTL-cached, baked fallback when offline), and the family shortcuts track it โ€” a new model shows up and resolves the day it lands, no dario release needed; the model-specific wire shape (effort level, beta set, thinking config) is applied automatically. **Globally-suspended families are filtered out** of both the live catalog and the baked fallback, so `/v1/models` never advertises a model that 404s upstream and suspended ids are rejected locally with an actionable error โ€” currently Claude Fable 5 and Mythos 5 (US-government directive, 2026-06-12); governed by `DARIO_SUSPENDED_MODELS` (default `fable`), set it empty to re-enable when access is restored.
197
+ **The full Claude lineup, autodetected.** Opus 4.8, Sonnet 5, and Haiku 4.5 โ€” plus `[1m]` long-context variants, generated by one rule for every family โ€” by full id (`claude-opus-4-8`) or shortcut (`opus` / `sonnet` / `haiku`, append `1m` for the long-context form). `GET /v1/models` asks Anthropic's live catalog (TTL-cached, baked fallback when offline), and the family shortcuts track it โ€” a new model shows up and resolves the day it lands, no dario release needed; the model-specific wire shape (effort level, beta set, thinking config) is applied automatically. **Globally-suspended families are filtered out** of both the live catalog and the baked fallback, so `/v1/models` never advertises a model that 404s upstream and suspended ids are rejected locally with an actionable error โ€” currently Claude Fable 5 and Mythos 5 (US-government directive, 2026-06-12); governed by `DARIO_SUSPENDED_MODELS` (default `fable`), set it empty to re-enable when access is restored.
198
198
 
199
199
  ---
200
200
 
@@ -303,7 +303,7 @@ No. `five_hour` and `seven_day` are both subscription billing โ€” different acco
303
303
  No, and it's caught automatically โ€” see [The deadline](#the-deadline-2026-06-15) and [How it stays working](#how-it-works-and-how-it-stays-working). dario rewrites every request to interactive-CC shape before it reaches `api.anthropic.com`, and the three-class drift watcher picks up new changes (npm-release hourly, remote-config every 30 min, classifier-rule daily). v3.38.5 + v3.38.6 โ€” 13 minutes apart, same day as v2.1.142's silent drops โ€” are the prior art.
304
304
 
305
305
  **I'm getting `404 not_found` for `claude-fable-5` / `fable`. Did dario break?**
306
- No โ€” Claude Fable 5 and Mythos 5 were disabled for **all** Anthropic customers by a US-government legal directive on 2026-06-12 (every plan and tier; [details](https://www.anthropic.com/news/fable-mythos-access)). `api.anthropic.com` returns `not_found` for them, so no subscription or proxy can route them. Since v4.8.71 dario drops both families from `/v1/models` and rejects them locally with a clear 404 pointing at `claude-opus-4-8` / `claude-sonnet-4-6`, instead of forwarding into a confusing upstream error. When access is restored, set `DARIO_SUSPENDED_MODELS=` (empty) on the instance to re-enable โ€” no upgrade needed.
306
+ No โ€” Claude Fable 5 and Mythos 5 were disabled for **all** Anthropic customers by a US-government legal directive on 2026-06-12 (every plan and tier; [details](https://www.anthropic.com/news/fable-mythos-access)). `api.anthropic.com` returns `not_found` for them, so no subscription or proxy can route them. Since v4.8.71 dario drops both families from `/v1/models` and rejects them locally with a clear 404 pointing at `claude-opus-4-8` / `claude-sonnet-5`, instead of forwarding into a confusing upstream error. When access is restored, set `DARIO_SUSPENDED_MODELS=` (empty) on the instance to re-enable โ€” no upgrade needed.
307
307
 
308
308
  Full FAQ: [`docs/faq.md`](./docs/faq.md)
309
309
 
@@ -7,16 +7,17 @@
7
7
  * `DARIO_API_KEY` as a fallback โ€” even on loopback, since they add/remove
8
8
  * OAuth credentials):
9
9
  *
10
- * POST /admin/login/start { alias } -> { login_id, authorize_url, expires_at }
11
- * POST /admin/login/complete { login_id, code } -> { alias, status, expires_at }
12
- * GET /admin/accounts -> { accounts: [...], count }
13
- * DELETE /admin/accounts/<alias> -> { alias, removed }
10
+ * POST /admin/login/start { alias } -> { authorize_url, expires_at }
11
+ * POST /admin/login/complete { alias, code } -> { alias, status, expires_at }
12
+ * GET /admin/accounts -> { accounts: [...], count }
13
+ * DELETE /admin/accounts/<alias> -> { alias, removed }
14
14
  *
15
15
  * The login flow mirrors `dario accounts add --manual` (PKCE + manual paste):
16
16
  * `/start` returns the authorize URL the operator opens in a browser; they POST
17
17
  * the code Anthropic displays back to `/complete`. The PKCE verifier + state
18
- * live in an in-memory map keyed by `login_id` with a short TTL โ€” never on
19
- * disk, never returned to the client, single-use.
18
+ * live in an in-memory map keyed by the account `alias` with a short TTL โ€” never
19
+ * on disk, never returned to the client, single-use. One pending login per
20
+ * alias; a second `/start` for the same alias just replaces it (#599).
20
21
  *
21
22
  * Account changes take effect on the next proxy restart (the pool is built at
22
23
  * startup, src/proxy.ts). Hot-reload of a running pool is a deliberate
package/dist/admin-api.js CHANGED
@@ -1,9 +1,10 @@
1
- import { randomUUID, timingSafeEqual } from 'node:crypto';
1
+ import { timingSafeEqual } from 'node:crypto';
2
2
  import { startAddAccount, completeAddAccount, removeAccount, listAccountAliases, loadAccount, } from './accounts.js';
3
3
  import { parseManualPaste } from './oauth.js';
4
4
  const PENDING_TTL_MS = 10 * 60_000;
5
- const MAX_PENDING = 64; // backstop against unbounded growth from repeated /start
5
+ const MAX_PENDING = 64; // backstop against unbounded growth (distinct aliases)
6
6
  const ACCOUNTS_PREFIX = '/admin/accounts/';
7
+ // Keyed by account alias โ€” one pending login per alias (#599).
7
8
  const pendingLogins = new Map();
8
9
  function prunePending(now) {
9
10
  for (const [id, p] of pendingLogins) {
@@ -102,39 +103,38 @@ export async function handleAdminRequest(req, res, urlPath, deps) {
102
103
  send(res, 400, { error: 'missing "alias"' });
103
104
  return true;
104
105
  }
105
- if (pendingLogins.size >= MAX_PENDING) {
106
+ // Only a brand-new alias grows the map; a repeat /start replaces in place.
107
+ if (!pendingLogins.has(alias) && pendingLogins.size >= MAX_PENDING) {
106
108
  send(res, 429, { error: 'too many pending logins; complete or wait for one to expire' });
107
109
  return true;
108
110
  }
109
111
  const { authorizeUrl, codeVerifier, state } = await startAddAccount(alias); // throws on invalid alias
110
- const loginId = randomUUID();
111
112
  const expiresAt = now + PENDING_TTL_MS;
112
- pendingLogins.set(loginId, { alias, codeVerifier, state, expiresAt });
113
+ pendingLogins.set(alias, { codeVerifier, state, expiresAt });
113
114
  send(res, 200, {
114
- login_id: loginId,
115
115
  authorize_url: authorizeUrl,
116
116
  expires_at: new Date(expiresAt).toISOString(),
117
- instructions: 'Open authorize_url, approve, then POST the displayed code to /admin/login/complete with this login_id.',
117
+ instructions: `Open authorize_url, approve, then POST { "alias": "${alias}", "code": "<displayed code>" } to /admin/login/complete.`,
118
118
  });
119
119
  return true;
120
120
  }
121
- // POST /admin/login/complete { login_id, code }
121
+ // POST /admin/login/complete { alias, code }
122
122
  if (urlPath === '/admin/login/complete') {
123
123
  if (method !== 'POST') {
124
124
  send(res, 405, { error: 'Method not allowed (use POST)' });
125
125
  return true;
126
126
  }
127
127
  const body = await readJsonBody(req);
128
- const loginId = typeof body.login_id === 'string' ? body.login_id : '';
128
+ const alias = typeof body.alias === 'string' ? body.alias.trim() : '';
129
129
  const rawCode = typeof body.code === 'string' ? body.code : '';
130
- if (!loginId || !rawCode) {
131
- send(res, 400, { error: 'missing "login_id" or "code"' });
130
+ if (!alias || !rawCode) {
131
+ send(res, 400, { error: 'missing "alias" or "code"' });
132
132
  return true;
133
133
  }
134
- const p = pendingLogins.get(loginId);
134
+ const p = pendingLogins.get(alias);
135
135
  if (!p || p.expiresAt <= now) {
136
- pendingLogins.delete(loginId);
137
- send(res, 410, { error: 'login_id unknown or expired โ€” start a new login' });
136
+ pendingLogins.delete(alias);
137
+ send(res, 410, { error: 'no pending login for that alias (unknown or expired) โ€” start a new login' });
138
138
  return true;
139
139
  }
140
140
  // Accept "code#state" or a bare code; verify the embedded state if present.
@@ -147,8 +147,8 @@ export async function handleAdminRequest(req, res, urlPath, deps) {
147
147
  send(res, 400, { error: 'state mismatch โ€” code is from a different login attempt' });
148
148
  return true;
149
149
  }
150
- pendingLogins.delete(loginId); // single-use, regardless of exchange outcome
151
- const creds = await completeAddAccount(p.alias, code, p.codeVerifier, p.state);
150
+ pendingLogins.delete(alias); // single-use, regardless of exchange outcome
151
+ const creds = await completeAddAccount(alias, code, p.codeVerifier, p.state);
152
152
  deps.onAccountsChanged?.();
153
153
  send(res, 200, { alias: creds.alias, status: 'added', expires_at: new Date(creds.expiresAt).toISOString() });
154
154
  return true;
@@ -1,5 +1,5 @@
1
1
  {
2
- "_version": "2.1.196",
2
+ "_version": "2.1.197",
3
3
  "_captured": "2026-06-30T06:36:26.548Z",
4
4
  "_source": "bundled",
5
5
  "_schemaVersion": 3,
@@ -1417,7 +1417,7 @@
1417
1417
  "anthropic_beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advisor-tool-2026-03-01,effort-2025-11-24",
1418
1418
  "header_values": {
1419
1419
  "accept": "application/json",
1420
- "user-agent": "claude-cli/2.1.196 (external, sdk-cli)",
1420
+ "user-agent": "claude-cli/2.1.197 (external, sdk-cli)",
1421
1421
  "x-stainless-arch": "x64",
1422
1422
  "x-stainless-lang": "js",
1423
1423
  "x-stainless-os": "Linux",
@@ -1442,5 +1442,5 @@
1442
1442
  "output_config",
1443
1443
  "stream"
1444
1444
  ],
1445
- "_supportedMaxTested": "2.1.196"
1445
+ "_supportedMaxTested": "2.1.197"
1446
1446
  }
package/dist/proxy.js CHANGED
@@ -928,8 +928,17 @@ export async function startProxy(opts = {}) {
928
928
  // Single-account mode โ€” existing auth check
929
929
  status = await getStatus();
930
930
  if (!status.authenticated) {
931
- console.error('[dario] Not authenticated. Run `dario login` first.');
932
- process.exit(1);
931
+ if (process.env.DARIO_ADMIN === '1') {
932
+ // Admin API on (#599): start anyway so POST /admin/login/start can
933
+ // bootstrap the first account headlessly โ€” the whole point of the API
934
+ // is "no console access". LLM routes return 503 until an account
935
+ // exists. Scoped to DARIO_ADMIN=1; default dario still exits here.
936
+ console.warn('[dario] No credentials yet โ€” starting in admin-only mode (DARIO_ADMIN=1). Add an account via POST /admin/login/start (or run `dario login`); LLM requests return 503 until then.');
937
+ }
938
+ else {
939
+ console.error('[dario] Not authenticated. Run `dario login` first.');
940
+ process.exit(1);
941
+ }
933
942
  }
934
943
  }
935
944
  const cliVersion = detectCliVersion();
@@ -11,7 +11,7 @@
11
11
  * โ”Œโ”€ Hits โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€[ โ†‘โ†“ select ยท r refresh ]
12
12
  * โ”‚ HH:MM:SS METHOD MODEL IN OUT LAT ST
13
13
  * โ”‚ 18:42:01 POST fable-5 842 216 1.2s 200 โ†
14
- * โ”‚ 18:42:03 POST sonnet-4-6 1.2k 480 0.8s 200
14
+ * โ”‚ 18:42:03 POST sonnet-5 1.2k 480 0.8s 200
15
15
  * โ”‚ โ€ฆ
16
16
  * โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
17
  * โ”‚ selected: 18:42:01 req_011โ€ฆNvMn
@@ -11,7 +11,7 @@
11
11
  * โ”Œโ”€ Hits โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€[ โ†‘โ†“ select ยท r refresh ]
12
12
  * โ”‚ HH:MM:SS METHOD MODEL IN OUT LAT ST
13
13
  * โ”‚ 18:42:01 POST fable-5 842 216 1.2s 200 โ†
14
- * โ”‚ 18:42:03 POST sonnet-4-6 1.2k 480 0.8s 200
14
+ * โ”‚ 18:42:03 POST sonnet-5 1.2k 480 0.8s 200
15
15
  * โ”‚ โ€ฆ
16
16
  * โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
17
  * โ”‚ selected: 18:42:01 req_011โ€ฆNvMn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "4.8.108",
3
+ "version": "4.8.110",
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": {