@askalf/dario 3.1.1 → 3.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/dist/cli.js +23 -0
- package/dist/proxy.js +20 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,29 @@
|
|
|
9
9
|
* dario refresh — Force token refresh
|
|
10
10
|
* dario logout — Remove saved credentials
|
|
11
11
|
*/
|
|
12
|
+
// ── Bun auto-relaunch ──
|
|
13
|
+
// Bun's TLS fingerprint matches Claude Code's runtime (both use Bun/BoringSSL).
|
|
14
|
+
// If Bun is installed and we're running on Node, relaunch under Bun for
|
|
15
|
+
// network-level fingerprint fidelity.
|
|
16
|
+
if (!('Bun' in globalThis) && !process.env.DARIO_NO_BUN) {
|
|
17
|
+
try {
|
|
18
|
+
const { execFileSync } = await import('node:child_process');
|
|
19
|
+
// Check if bun exists
|
|
20
|
+
execFileSync('bun', ['--version'], { stdio: 'ignore', timeout: 3000 });
|
|
21
|
+
// Relaunch under bun
|
|
22
|
+
const { spawn } = await import('node:child_process');
|
|
23
|
+
const child = spawn('bun', ['run', ...process.argv.slice(1)], {
|
|
24
|
+
stdio: 'inherit',
|
|
25
|
+
env: { ...process.env, DARIO_NO_BUN: '1' },
|
|
26
|
+
});
|
|
27
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
28
|
+
// Prevent this process from continuing
|
|
29
|
+
await new Promise(() => { });
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Bun not available, continue with Node
|
|
33
|
+
}
|
|
34
|
+
}
|
|
12
35
|
import { unlink } from 'node:fs/promises';
|
|
13
36
|
import { join } from 'node:path';
|
|
14
37
|
import { homedir } from 'node:os';
|
package/dist/proxy.js
CHANGED
|
@@ -143,7 +143,9 @@ function sendCliResponse(res, cliResult, clientWantsStream, isOpenAI, corsOrigin
|
|
|
143
143
|
res.writeHead(cliResult.status, { 'Content-Type': cliResult.contentType, ...headers });
|
|
144
144
|
res.end(cliResult.body);
|
|
145
145
|
}
|
|
146
|
-
|
|
146
|
+
// Session ID rotates per request — each CC --print invocation creates a new session.
|
|
147
|
+
// A persistent session ID across many requests is a detection signal.
|
|
148
|
+
let SESSION_ID = randomUUID();
|
|
147
149
|
const OS_NAME = platform === 'win32' ? 'Windows' : platform === 'darwin' ? 'MacOS' : 'Linux';
|
|
148
150
|
// Claude Code device identity — required for Max plan billing classification.
|
|
149
151
|
// Without metadata.user_id, Anthropic classifies requests as third-party and
|
|
@@ -520,7 +522,6 @@ export async function startProxy(opts = {}) {
|
|
|
520
522
|
'anthropic-dangerous-direct-browser-access': 'true',
|
|
521
523
|
'user-agent': `claude-cli/${cliVersion} (external, cli)`,
|
|
522
524
|
'x-app': 'cli',
|
|
523
|
-
'x-claude-code-session-id': SESSION_ID,
|
|
524
525
|
'x-stainless-arch': arch,
|
|
525
526
|
'x-stainless-lang': 'js',
|
|
526
527
|
'x-stainless-os': OS_NAME,
|
|
@@ -533,6 +534,11 @@ export async function startProxy(opts = {}) {
|
|
|
533
534
|
const useCli = opts.cliBackend ?? false;
|
|
534
535
|
let requestCount = 0;
|
|
535
536
|
const semaphore = new Semaphore(MAX_CONCURRENT);
|
|
537
|
+
// Rate governor: CC --print takes ~2-3s per invocation.
|
|
538
|
+
// Rapid-fire requests from one "session" is an inhuman pattern.
|
|
539
|
+
// Minimum 500ms between requests — fast enough for agents, slow enough to not flag.
|
|
540
|
+
let lastRequestTime = 0;
|
|
541
|
+
const MIN_REQUEST_INTERVAL_MS = parseInt(process.env.DARIO_MIN_INTERVAL_MS || '500', 10);
|
|
536
542
|
// Optional proxy authentication — pre-encode key buffer for performance
|
|
537
543
|
const apiKey = process.env.DARIO_API_KEY;
|
|
538
544
|
const apiKeyBuf = apiKey ? Buffer.from(apiKey) : null;
|
|
@@ -739,15 +745,24 @@ export async function startProxy(opts = {}) {
|
|
|
739
745
|
beta += ',' + filtered;
|
|
740
746
|
}
|
|
741
747
|
}
|
|
748
|
+
// Rate governor — prevent inhuman request cadence
|
|
749
|
+
const now = Date.now();
|
|
750
|
+
const elapsed = now - lastRequestTime;
|
|
751
|
+
if (elapsed < MIN_REQUEST_INTERVAL_MS && lastRequestTime > 0) {
|
|
752
|
+
await new Promise(r => setTimeout(r, MIN_REQUEST_INTERVAL_MS - elapsed));
|
|
753
|
+
}
|
|
754
|
+
lastRequestTime = Date.now();
|
|
755
|
+
// Rotate session ID per request — CC --print creates a new session each invocation
|
|
756
|
+
SESSION_ID = randomUUID();
|
|
742
757
|
const headers = {
|
|
743
758
|
...staticHeaders,
|
|
744
759
|
'Authorization': `Bearer ${accessToken}`,
|
|
760
|
+
'x-claude-code-session-id': SESSION_ID,
|
|
745
761
|
'anthropic-version': passthrough ? (req.headers['anthropic-version'] || '2023-06-01') : '2023-06-01',
|
|
746
762
|
'anthropic-beta': beta,
|
|
747
|
-
// Real Claude Code adds x-client-request-id for firstParty + api.anthropic.com
|
|
748
763
|
'x-client-request-id': randomUUID(),
|
|
749
|
-
//
|
|
750
|
-
'x-stainless-timeout':
|
|
764
|
+
// CC sends 600 on first request per session. With rotation, every request is "first"
|
|
765
|
+
'x-stainless-timeout': '600',
|
|
751
766
|
};
|
|
752
767
|
const upstream = await fetch(targetBase, {
|
|
753
768
|
method: req.method ?? 'POST',
|