@askalf/dario 3.2.6 → 3.3.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.
@@ -33,6 +33,8 @@ export declare function buildCCRequest(clientBody: Record<string, unknown>, bill
33
33
  deviceId: string;
34
34
  accountUuid: string;
35
35
  sessionId: string;
36
+ }, opts?: {
37
+ preserveTools?: boolean;
36
38
  }): {
37
39
  body: Record<string, unknown>;
38
40
  toolMap: Map<string, ToolMapping>;
@@ -52,7 +52,7 @@ const TOOL_MAP = {
52
52
  * Replaces the entire request structure — tools, fields, ordering — with
53
53
  * what real CC sends. Only the conversation content is preserved.
54
54
  */
55
- export function buildCCRequest(clientBody, billingTag, cache1h, identity) {
55
+ export function buildCCRequest(clientBody, billingTag, cache1h, identity, opts = {}) {
56
56
  const model = clientBody.model || 'claude-sonnet-4-6';
57
57
  const isHaiku = model.toLowerCase().includes('haiku');
58
58
  const messages = clientBody.messages || [];
@@ -71,9 +71,14 @@ export function buildCCRequest(clientBody, billingTag, cache1h, identity) {
71
71
  }
72
72
  }
73
73
  // ── Build tool mapping ──
74
+ // In preserveTools mode, skip the tool name/arg rewriting entirely.
75
+ // Tool routing in real agents requires bidirectional schema fidelity that
76
+ // lossy forward-only translation can't provide. Users with custom tool
77
+ // schemas should use preserveTools to keep their tools as-is and accept
78
+ // the fingerprint risk on their own account.
74
79
  const activeToolMap = new Map();
75
80
  const unmappedTools = [];
76
- if (clientTools) {
81
+ if (clientTools && !opts.preserveTools) {
77
82
  for (const tool of clientTools) {
78
83
  const name = (tool.name || '').toLowerCase();
79
84
  const mapping = TOOL_MAP[name];
@@ -105,30 +110,27 @@ export function buildCCRequest(clientBody, billingTag, cache1h, identity) {
105
110
  }
106
111
  }
107
112
  // ── Remap tool_use and tool_result references in message history ──
108
- // Track tool_use_id CC tool name for consistent remapping
109
- const toolUseIdMap = new Map();
110
- for (const msg of messages) {
111
- if (Array.isArray(msg.content)) {
112
- for (const block of msg.content) {
113
- if (block.type === 'tool_use' && typeof block.name === 'string') {
114
- const mapping = activeToolMap.get(block.name);
115
- if (mapping) {
116
- block.name = mapping.ccTool;
117
- if (mapping.translateArgs && block.input) {
118
- block.input = mapping.translateArgs(block.input);
113
+ // Skip in preserveTools mode leave conversation history untouched.
114
+ if (!opts.preserveTools) {
115
+ for (const msg of messages) {
116
+ if (Array.isArray(msg.content)) {
117
+ for (const block of msg.content) {
118
+ if (block.type === 'tool_use' && typeof block.name === 'string') {
119
+ const mapping = activeToolMap.get(block.name);
120
+ if (mapping) {
121
+ block.name = mapping.ccTool;
122
+ if (mapping.translateArgs && block.input) {
123
+ block.input = mapping.translateArgs(block.input);
124
+ }
119
125
  }
120
126
  }
121
- // Track the ID so tool_results stay consistent
122
- if (typeof block.id === 'string') {
123
- toolUseIdMap.set(block.id, block.name);
124
- }
125
- }
126
- // Strip any client-specific fields from tool_result blocks that CC wouldn't send
127
- if (block.type === 'tool_result') {
128
- // Remove non-standard fields clients may add
129
- for (const key of Object.keys(block)) {
130
- if (!['type', 'tool_use_id', 'content', 'is_error'].includes(key)) {
131
- delete block[key];
127
+ // Strip any client-specific fields from tool_result blocks that CC wouldn't send
128
+ if (block.type === 'tool_result') {
129
+ // Remove non-standard fields clients may add
130
+ for (const key of Object.keys(block)) {
131
+ if (!['type', 'tool_use_id', 'content', 'is_error'].includes(key)) {
132
+ delete block[key];
133
+ }
132
134
  }
133
135
  }
134
136
  }
@@ -199,9 +201,11 @@ export function buildCCRequest(clientBody, billingTag, cache1h, identity) {
199
201
  { type: 'text', text: fullSystemPrompt, cache_control: cache1h },
200
202
  ],
201
203
  };
202
- // Tools come before metadata in CC's key order
204
+ // Tools come before metadata in CC's key order.
205
+ // preserveTools mode: pass client tools through unchanged (better for real
206
+ // agents with custom schemas, but loses the CC tool fingerprint).
203
207
  if (clientTools && clientTools.length > 0) {
204
- ccRequest.tools = CC_TOOL_DEFINITIONS;
208
+ ccRequest.tools = opts.preserveTools ? clientTools : CC_TOOL_DEFINITIONS;
205
209
  }
206
210
  // Metadata
207
211
  ccRequest.metadata = {
package/dist/cli.js CHANGED
@@ -128,9 +128,10 @@ async function proxy() {
128
128
  const verbose = args.includes('--verbose') || args.includes('-v');
129
129
  const cliBackend = args.includes('--cli');
130
130
  const passthrough = args.includes('--passthrough') || args.includes('--thin');
131
+ const preserveTools = args.includes('--preserve-tools') || args.includes('--keep-tools');
131
132
  const modelArg = args.find(a => a.startsWith('--model='));
132
133
  const model = modelArg ? modelArg.split('=')[1] : undefined;
133
- await startProxy({ port, verbose, model, cliBackend, passthrough });
134
+ await startProxy({ port, verbose, model, cliBackend, passthrough, preserveTools });
134
135
  }
135
136
  async function help() {
136
137
  console.log(`
@@ -150,6 +151,7 @@ async function help() {
150
151
  Default: passthrough (client decides)
151
152
  --cli Use Claude CLI as backend (bypasses rate limits)
152
153
  --passthrough Thin proxy — OAuth swap only, no injection
154
+ --preserve-tools Keep client tool schemas (for agents with custom tools)
153
155
  --port=PORT Port to listen on (default: 3456)
154
156
  --verbose, -v Log all requests
155
157
 
package/dist/oauth.js CHANGED
@@ -8,11 +8,13 @@ import { randomBytes, createHash } from 'node:crypto';
8
8
  import { readFile, writeFile, mkdir, rename } from 'node:fs/promises';
9
9
  import { dirname, join } from 'node:path';
10
10
  import { homedir } from 'node:os';
11
- // Claude Code's public OAuth client (PKCE, no secret needed)
12
- const OAUTH_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
13
- const OAUTH_AUTHORIZE_URL = 'https://platform.claude.com/oauth/authorize';
11
+ // Claude Code's public OAuth client (PKCE, no secret needed) — extracted from CC v2.1.104 binary
12
+ const OAUTH_CLIENT_ID = '22422756-60c9-4084-8eb7-27705fd5cf9a';
13
+ // Max Plan OAuth (for Claude Pro/Max subscriptions) — claude.com/cai/oauth/authorize
14
+ const OAUTH_AUTHORIZE_URL = 'https://claude.com/cai/oauth/authorize';
14
15
  const OAUTH_TOKEN_URL = 'https://platform.claude.com/v1/oauth/token';
15
- const OAUTH_SCOPES = 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload';
16
+ // Max plan scopes (excludes org:create_api_key which requires Console plan)
17
+ const OAUTH_SCOPES = 'user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload';
16
18
  // Refresh 30 min before expiry
17
19
  const REFRESH_BUFFER_MS = 30 * 60 * 1000;
18
20
  // After a failed refresh, don't retry for 60s to avoid spam
package/dist/proxy.d.ts CHANGED
@@ -4,6 +4,7 @@ interface ProxyOptions {
4
4
  model?: string;
5
5
  cliBackend?: boolean;
6
6
  passthrough?: boolean;
7
+ preserveTools?: boolean;
7
8
  }
8
9
  export declare function sanitizeError(err: unknown): string;
9
10
  export declare function startProxy(opts?: ProxyOptions): Promise<void>;
package/dist/proxy.js CHANGED
@@ -705,7 +705,7 @@ export async function startProxy(opts = {}) {
705
705
  const fullVersion = `${cliVersion}.${buildTag}`;
706
706
  const billingTag = `x-anthropic-billing-header: cc_version=${fullVersion}; cc_entrypoint=cli; cch=${cch};`;
707
707
  const CACHE_1H = { type: 'ephemeral', ttl: '1h' };
708
- const { body: ccBody, toolMap } = buildCCRequest(r, billingTag, CACHE_1H, { deviceId: identity.deviceId, accountUuid: identity.accountUuid, sessionId: SESSION_ID });
708
+ const { body: ccBody, toolMap } = buildCCRequest(r, billingTag, CACHE_1H, { deviceId: identity.deviceId, accountUuid: identity.accountUuid, sessionId: SESSION_ID }, { preserveTools: opts.preserveTools ?? false });
709
709
  // Store tool map for response reverse-mapping
710
710
  ccToolMap = toolMap;
711
711
  // Replace request body entirely with CC template
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "3.2.6",
3
+ "version": "3.3.0",
4
4
  "description": "Use your Claude subscription as an API. No API key needed. Local proxy for Claude Max/Pro subscriptions.",
5
5
  "type": "module",
6
6
  "bin": {