@askalf/dario 5.4.24 → 5.4.26
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/dist/config-report.js +7 -0
- package/dist/live-fingerprint.d.ts +1 -1
- package/dist/live-fingerprint.js +1 -1
- package/dist/oauth.d.ts +33 -0
- package/dist/oauth.js +50 -4
- package/dist/proxy.js +3 -1
- package/package.json +1 -1
package/dist/config-report.js
CHANGED
|
@@ -18,6 +18,7 @@ import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
|
18
18
|
import { join, dirname } from 'node:path';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
20
|
import { homedir } from 'node:os';
|
|
21
|
+
import { ignoreCcCredentials } from './oauth.js';
|
|
21
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
23
|
/**
|
|
23
24
|
* Collect the effective dario configuration the proxy would run with.
|
|
@@ -76,6 +77,12 @@ export async function collectEffectiveConfig() {
|
|
|
76
77
|
rows: [
|
|
77
78
|
{ label: 'credentials', value: credsInfo },
|
|
78
79
|
{ label: 'path', value: credsPath },
|
|
80
|
+
{
|
|
81
|
+
label: 'DARIO_IGNORE_CC_CREDENTIALS',
|
|
82
|
+
value: ignoreCcCredentials()
|
|
83
|
+
? "on — using ONLY dario's own credentials.json; Claude Code session token + keychain ignored (won't rotate a live `claude` session)"
|
|
84
|
+
: 'off — also reads ~/.claude/.credentials.json + OS keychain, picks freshest (can rotate a live `claude` session on the same machine)',
|
|
85
|
+
},
|
|
79
86
|
],
|
|
80
87
|
});
|
|
81
88
|
// ── Pool
|
|
@@ -354,7 +354,7 @@ export declare function detectDrift(t: TemplateData, installedOverride?: string
|
|
|
354
354
|
*/
|
|
355
355
|
export declare const SUPPORTED_CC_RANGE: {
|
|
356
356
|
readonly min: "1.0.0";
|
|
357
|
-
readonly maxTested: "2.1.
|
|
357
|
+
readonly maxTested: "2.1.221";
|
|
358
358
|
};
|
|
359
359
|
/**
|
|
360
360
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -969,7 +969,7 @@ export function detectDrift(t, installedOverride) {
|
|
|
969
969
|
*/
|
|
970
970
|
export const SUPPORTED_CC_RANGE = {
|
|
971
971
|
min: '1.0.0',
|
|
972
|
-
maxTested: '2.1.
|
|
972
|
+
maxTested: '2.1.221',
|
|
973
973
|
};
|
|
974
974
|
/**
|
|
975
975
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/oauth.d.ts
CHANGED
|
@@ -22,6 +22,39 @@ export interface OAuthTokens {
|
|
|
22
22
|
export interface CredentialsFile {
|
|
23
23
|
claudeAiOauth: OAuthTokens;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Whether to ignore the interactive Claude Code session's credentials entirely
|
|
27
|
+
* — set via `DARIO_IGNORE_CC_CREDENTIALS` (1/true/yes/on). Exported for tests.
|
|
28
|
+
*
|
|
29
|
+
* Default (unset) keeps the historical behaviour: loadCredentials reads dario's
|
|
30
|
+
* own file, CC's `~/.claude/.credentials.json`, AND the OS keychain (where
|
|
31
|
+
* modern CC stores its token), then uses the FRESHEST. That auto-detection is
|
|
32
|
+
* convenient for a machine dedicated to dario, but it is exactly what breaks a
|
|
33
|
+
* live `claude` session running on the SAME machine/account: the moment CC's
|
|
34
|
+
* token is fresher (e.g. right after you log into CC), dario grabs that same
|
|
35
|
+
* token and refreshes it, Anthropic rotates it, and the interactive session
|
|
36
|
+
* still holding the old copy starts 401ing.
|
|
37
|
+
*
|
|
38
|
+
* With the flag set, dario uses ONLY its own `~/.dario/credentials.json` (from a
|
|
39
|
+
* prior `dario login`) and never touches the CC file or keychain — so it stays
|
|
40
|
+
* on the Max subscription ($0) while never rotating the interactive session's
|
|
41
|
+
* token. The API-key path (`ANTHROPIC_UPSTREAM_API_KEY`) also isolates, but
|
|
42
|
+
* bypasses OAuth/Max onto retail billing, defeating the point of dario.
|
|
43
|
+
*/
|
|
44
|
+
export declare function ignoreCcCredentials(env?: NodeJS.ProcessEnv): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Which credential sources loadCredentials() consults, given whether the
|
|
47
|
+
* interactive Claude Code session's credentials should be ignored. Exported so
|
|
48
|
+
* the isolation guarantee is testable without real credentials on disk.
|
|
49
|
+
*
|
|
50
|
+
* `readKeychain` gates the OS keychain the same way as the CC file: the modern
|
|
51
|
+
* CC binary stores its OAuth token in the keychain, not on disk, so isolating
|
|
52
|
+
* from the interactive session means skipping BOTH.
|
|
53
|
+
*/
|
|
54
|
+
export declare function credentialSourcePlan(ignoreCc: boolean): {
|
|
55
|
+
filePaths: string[];
|
|
56
|
+
readKeychain: boolean;
|
|
57
|
+
};
|
|
25
58
|
/**
|
|
26
59
|
* Information about a keychain entry surfaced for operator disambiguation
|
|
27
60
|
* during `dario accounts add --from-keychain`.
|
package/dist/oauth.js
CHANGED
|
@@ -75,6 +75,43 @@ function generatePKCE() {
|
|
|
75
75
|
function getDarioCredentialsPath() {
|
|
76
76
|
return join(homedir(), '.dario', 'credentials.json');
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Whether to ignore the interactive Claude Code session's credentials entirely
|
|
80
|
+
* — set via `DARIO_IGNORE_CC_CREDENTIALS` (1/true/yes/on). Exported for tests.
|
|
81
|
+
*
|
|
82
|
+
* Default (unset) keeps the historical behaviour: loadCredentials reads dario's
|
|
83
|
+
* own file, CC's `~/.claude/.credentials.json`, AND the OS keychain (where
|
|
84
|
+
* modern CC stores its token), then uses the FRESHEST. That auto-detection is
|
|
85
|
+
* convenient for a machine dedicated to dario, but it is exactly what breaks a
|
|
86
|
+
* live `claude` session running on the SAME machine/account: the moment CC's
|
|
87
|
+
* token is fresher (e.g. right after you log into CC), dario grabs that same
|
|
88
|
+
* token and refreshes it, Anthropic rotates it, and the interactive session
|
|
89
|
+
* still holding the old copy starts 401ing.
|
|
90
|
+
*
|
|
91
|
+
* With the flag set, dario uses ONLY its own `~/.dario/credentials.json` (from a
|
|
92
|
+
* prior `dario login`) and never touches the CC file or keychain — so it stays
|
|
93
|
+
* on the Max subscription ($0) while never rotating the interactive session's
|
|
94
|
+
* token. The API-key path (`ANTHROPIC_UPSTREAM_API_KEY`) also isolates, but
|
|
95
|
+
* bypasses OAuth/Max onto retail billing, defeating the point of dario.
|
|
96
|
+
*/
|
|
97
|
+
export function ignoreCcCredentials(env = process.env) {
|
|
98
|
+
const v = (env['DARIO_IGNORE_CC_CREDENTIALS'] ?? '').trim().toLowerCase();
|
|
99
|
+
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Which credential sources loadCredentials() consults, given whether the
|
|
103
|
+
* interactive Claude Code session's credentials should be ignored. Exported so
|
|
104
|
+
* the isolation guarantee is testable without real credentials on disk.
|
|
105
|
+
*
|
|
106
|
+
* `readKeychain` gates the OS keychain the same way as the CC file: the modern
|
|
107
|
+
* CC binary stores its OAuth token in the keychain, not on disk, so isolating
|
|
108
|
+
* from the interactive session means skipping BOTH.
|
|
109
|
+
*/
|
|
110
|
+
export function credentialSourcePlan(ignoreCc) {
|
|
111
|
+
return ignoreCc
|
|
112
|
+
? { filePaths: [getDarioCredentialsPath()], readKeychain: false }
|
|
113
|
+
: { filePaths: [getDarioCredentialsPath(), getClaudeCodeCredentialsPath()], readKeychain: true };
|
|
114
|
+
}
|
|
78
115
|
function getClaudeCodeCredentialsPath() {
|
|
79
116
|
return join(homedir(), '.claude', '.credentials.json');
|
|
80
117
|
}
|
|
@@ -362,8 +399,15 @@ export async function loadCredentials() {
|
|
|
362
399
|
// work the way it did before any `dario login` had ever run, while
|
|
363
400
|
// still preferring dario's own file when both sources are equivalent
|
|
364
401
|
// (dario file wins ties on expiresAt by being checked first).
|
|
402
|
+
//
|
|
403
|
+
// DARIO_IGNORE_CC_CREDENTIALS narrows the source set to dario's OWN file
|
|
404
|
+
// only — never the interactive CC session's token (its file OR the keychain).
|
|
405
|
+
// See ignoreCcCredentials() / credentialSourcePlan() for why: on a machine
|
|
406
|
+
// shared with a live `claude` session, grabbing + refreshing CC's token here
|
|
407
|
+
// rotates it out from under that session.
|
|
408
|
+
const plan = credentialSourcePlan(ignoreCcCredentials());
|
|
365
409
|
const candidates = [];
|
|
366
|
-
for (const path of
|
|
410
|
+
for (const path of plan.filePaths) {
|
|
367
411
|
try {
|
|
368
412
|
const raw = await readFile(path, 'utf-8');
|
|
369
413
|
const parsed = JSON.parse(raw);
|
|
@@ -374,9 +418,11 @@ export async function loadCredentials() {
|
|
|
374
418
|
catch { /* try next */ }
|
|
375
419
|
}
|
|
376
420
|
// OS keychain (modern CC stores credentials here, not on disk).
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
421
|
+
if (plan.readKeychain) {
|
|
422
|
+
const keychainCreds = await loadKeychainCredentials();
|
|
423
|
+
if (keychainCreds?.claudeAiOauth?.accessToken && keychainCreds?.claudeAiOauth?.refreshToken) {
|
|
424
|
+
candidates.push(keychainCreds);
|
|
425
|
+
}
|
|
380
426
|
}
|
|
381
427
|
const best = pickFreshestCredentials(candidates);
|
|
382
428
|
if (!best)
|
package/dist/proxy.js
CHANGED
|
@@ -5,7 +5,7 @@ import { join } from 'node:path';
|
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import { setDefaultResultOrder } from 'node:dns';
|
|
7
7
|
import { arch, platform } from 'node:process';
|
|
8
|
-
import { getAccessToken, getStatus } from './oauth.js';
|
|
8
|
+
import { getAccessToken, getStatus, ignoreCcCredentials } from './oauth.js';
|
|
9
9
|
import { buildHealthResponse, derivePoolStatus, shouldDiscloseHealthInternals } from './health-response.js';
|
|
10
10
|
import { darioVersion } from './version.js';
|
|
11
11
|
import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, overlayTemplateHeaderValues, forwardClientCCIdentityHeaders, isMcpToolName, CC_TEMPLATE, effectiveCacheControl, withForced1hBeta } from './cc-template.js';
|
|
@@ -962,6 +962,8 @@ export async function startProxy(opts = {}) {
|
|
|
962
962
|
const upstreamApiKey = (opts.upstreamApiKey ?? process.env.ANTHROPIC_UPSTREAM_API_KEY ?? '').trim();
|
|
963
963
|
if (upstreamApiKey)
|
|
964
964
|
console.error('[dario] upstream auth: per-token API key (x-api-key) — OAuth/Max + account pool bypassed');
|
|
965
|
+
else if (ignoreCcCredentials())
|
|
966
|
+
console.error("[dario] DARIO_IGNORE_CC_CREDENTIALS: using ONLY dario's own credentials.json — Claude Code session token + keychain ignored (won't rotate a live `claude` session; run `dario login` if not authed)");
|
|
965
967
|
// DNS result order — prefer IPv4 for the Anthropic upstream by default.
|
|
966
968
|
// api.anthropic.com publishes both A and AAAA records. In a container with
|
|
967
969
|
// no IPv6 egress (e.g. a default Docker bridge network), Node's `verbatim`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.26",
|
|
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": {
|