@askalf/dario 4.8.134 → 4.8.136
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 +1 -1
- package/dist/cc-template.d.ts +33 -1
- package/dist/cc-template.js +73 -12
- package/dist/proxy.js +17 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,7 +224,7 @@ Tune via `~/.dario/config.json` → `overageGuard`, or CLI flags: `--overage-beh
|
|
|
224
224
|
- **Multi-account pool.** Drop Claude accounts in `~/.dario/accounts/` and pool mode auto-activates — one is enough to serve, so `dario accounts add` alone bootstraps a proxy with no `dario login` step. With more, 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. → [`docs/multi-account-pool.md`](./docs/multi-account-pool.md)
|
|
225
225
|
- **Headless admin API (`DARIO_ADMIN=1`).** Provision and manage pool accounts entirely over HTTP — start with zero accounts, `POST /admin/login/start`, paste the code back, and the account is routable the moment the `200` lands (live pool hot-reload, no restart). Token-gated even on loopback, audit-logged, rate-limited; `GET /admin/accounts` reports live per-account headroom. Built for Docker / k8s / Raspberry-Pi deployments where a console is the awkward part. → [`docs/admin-api.md`](./docs/admin-api.md)
|
|
226
226
|
- **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)
|
|
227
|
-
- **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/integrations/agent-compat.md`](./docs/integrations/agent-compat.md)
|
|
227
|
+
- **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. MCP tools (`mcp__server__tool`) forward verbatim — the shape real CC uses for session-attached servers (v4.8.135). → [`docs/integrations/agent-compat.md`](./docs/integrations/agent-compat.md)
|
|
228
228
|
- **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)
|
|
229
229
|
- **Honor client thinking (`--honor-client-thinking`).** By default dario rebuilds the outbound request with CC's interactive thinking shape regardless of what the client sent. Pass this flag (or `DARIO_HONOR_CLIENT_THINKING=1`) to pass a non-CC client's own `thinking` block through unchanged. Off by default; the rebuild-to-CC path is what keeps the subscription pool routing.
|
|
230
230
|
- **Preserve structured output (`--preserve-output-format`).** By default dario rebuilds `output_config` from CC's template (effort only), dropping a client's `output_config.format` JSON schema, so structured-output clients get unconstrained prose their strict parser rejects. Pass this flag (or `DARIO_PRESERVE_OUTPUT_FORMAT=1`) to carry the client's schema through unchanged — SDK clients like the Vercel AI SDK's `generateObject` then get schema-constrained output. Off by default; empirically without flipping billing (verified `five_hour` on `claude-sonnet-4-6`).
|
package/dist/cc-template.d.ts
CHANGED
|
@@ -56,13 +56,45 @@ export declare const CC_TOOL_DEFINITIONS: {
|
|
|
56
56
|
description: string;
|
|
57
57
|
input_schema: Record<string, unknown>;
|
|
58
58
|
}[];
|
|
59
|
+
/** The UNFILTERED bundled union — every tool the bake knows across platforms
|
|
60
|
+
* (PLATFORM_ONLY_TOOLS keeps the bundle a superset). The identity-mapping,
|
|
61
|
+
* detection, and advertise paths intersect with what the CLIENT declared,
|
|
62
|
+
* and the client's declaration already encodes its platform — a Linux CC
|
|
63
|
+
* never declares PowerShell. Filtering those paths by the PROXY HOST's
|
|
64
|
+
* process.platform (pre-v4.8.136) made a Linux-hosted dario treat a win32
|
|
65
|
+
* client's PowerShell/Glob/Grep as non-native: PowerShell fell to the
|
|
66
|
+
* unmapped round-robin, and all three were dropped from the advertised
|
|
67
|
+
* array (Glob/Grep translated via lowercase aliases but were never sent
|
|
68
|
+
* upstream). Host-filtered CC_TOOL_DEFINITIONS stays correct for the paths
|
|
69
|
+
* with no client declaration to mirror: the full-template fallback, the
|
|
70
|
+
* merge-mode base array, and Fable's no-tools shape. */
|
|
71
|
+
export declare const CC_TOOL_DEFINITIONS_UNION: {
|
|
72
|
+
name: string;
|
|
73
|
+
description: string;
|
|
74
|
+
input_schema: Record<string, unknown>;
|
|
75
|
+
}[];
|
|
76
|
+
export declare const CC_NATIVE_NAMES_UNION: Set<string>;
|
|
59
77
|
/** CC's own tool names, EXACT case ("Read", "Bash", "Agent", …). A CC client's
|
|
60
78
|
* tools identity-map to themselves and OVERRIDE TOOL_MAP — whose lowercase
|
|
61
79
|
* cross-client aliases ('read' → {path}/{filePath}) would otherwise mistranslate
|
|
62
80
|
* a CC tool (Read's file_path → path). Exact case is the discriminator: CC sends
|
|
63
81
|
* PascalCase, the {path}-style clients send lowercase/snake, so a non-CC `read`
|
|
64
|
-
* still routes through TOOL_MAP. Tracks the live bundle (refreshed each bake).
|
|
82
|
+
* still routes through TOOL_MAP. Tracks the live bundle (refreshed each bake).
|
|
83
|
+
* HOST-filtered — the routing, detection, and advertise paths use the
|
|
84
|
+
* _UNION variants below so a client on a different platform than the proxy
|
|
85
|
+
* host still identity-maps (v4.8.136). */
|
|
65
86
|
export declare const CC_NATIVE_NAMES: Set<string>;
|
|
87
|
+
/** MCP tools attached to a CC session are namespaced `mcp__<server>__<tool>`.
|
|
88
|
+
* Real CC advertises them VERBATIM after its built-ins — the schemas are
|
|
89
|
+
* operator-supplied, so there is no canonical template entry to substitute.
|
|
90
|
+
* Passing them through unchanged IS CC's wire shape; remapping them was the
|
|
91
|
+
* divergence. Before v4.8.135 they fell through to the unmapped-tool
|
|
92
|
+
* round-robin: dropped from the advertised array (the model never saw them)
|
|
93
|
+
* while history tool_use blocks were renamed onto Bash/Read/… with junk args
|
|
94
|
+
* — seen live as "tool substitution: 28/52 client tools not in TOOL_MAP" on
|
|
95
|
+
* a CC session with an MCP server attached. Like CC_NATIVE_NAMES, these
|
|
96
|
+
* identity-map and skip TOOL_MAP entirely. */
|
|
97
|
+
export declare function isMcpToolName(name: unknown): boolean;
|
|
66
98
|
/** CC's static system prompt (~25KB). The shared base — baked from a non-Fable
|
|
67
99
|
* model (Opus). CC ships some models a larger, model-specific prompt; see
|
|
68
100
|
* CC_SYSTEM_PROMPT_FABLE / systemPromptForModel. */
|
package/dist/cc-template.js
CHANGED
|
@@ -66,13 +66,43 @@ export const INTERACTIVE_ONLY_TOOLS = new Set([
|
|
|
66
66
|
]);
|
|
67
67
|
/** CC's exact tool definitions for the current platform — filtered from the bundled union. */
|
|
68
68
|
export const CC_TOOL_DEFINITIONS = filterToolsForPlatform(TEMPLATE.tools, process.platform);
|
|
69
|
+
/** The UNFILTERED bundled union — every tool the bake knows across platforms
|
|
70
|
+
* (PLATFORM_ONLY_TOOLS keeps the bundle a superset). The identity-mapping,
|
|
71
|
+
* detection, and advertise paths intersect with what the CLIENT declared,
|
|
72
|
+
* and the client's declaration already encodes its platform — a Linux CC
|
|
73
|
+
* never declares PowerShell. Filtering those paths by the PROXY HOST's
|
|
74
|
+
* process.platform (pre-v4.8.136) made a Linux-hosted dario treat a win32
|
|
75
|
+
* client's PowerShell/Glob/Grep as non-native: PowerShell fell to the
|
|
76
|
+
* unmapped round-robin, and all three were dropped from the advertised
|
|
77
|
+
* array (Glob/Grep translated via lowercase aliases but were never sent
|
|
78
|
+
* upstream). Host-filtered CC_TOOL_DEFINITIONS stays correct for the paths
|
|
79
|
+
* with no client declaration to mirror: the full-template fallback, the
|
|
80
|
+
* merge-mode base array, and Fable's no-tools shape. */
|
|
81
|
+
export const CC_TOOL_DEFINITIONS_UNION = TEMPLATE.tools;
|
|
82
|
+
export const CC_NATIVE_NAMES_UNION = new Set(TEMPLATE.tools.map((t) => String(t.name)));
|
|
69
83
|
/** CC's own tool names, EXACT case ("Read", "Bash", "Agent", …). A CC client's
|
|
70
84
|
* tools identity-map to themselves and OVERRIDE TOOL_MAP — whose lowercase
|
|
71
85
|
* cross-client aliases ('read' → {path}/{filePath}) would otherwise mistranslate
|
|
72
86
|
* a CC tool (Read's file_path → path). Exact case is the discriminator: CC sends
|
|
73
87
|
* PascalCase, the {path}-style clients send lowercase/snake, so a non-CC `read`
|
|
74
|
-
* still routes through TOOL_MAP. Tracks the live bundle (refreshed each bake).
|
|
88
|
+
* still routes through TOOL_MAP. Tracks the live bundle (refreshed each bake).
|
|
89
|
+
* HOST-filtered — the routing, detection, and advertise paths use the
|
|
90
|
+
* _UNION variants below so a client on a different platform than the proxy
|
|
91
|
+
* host still identity-maps (v4.8.136). */
|
|
75
92
|
export const CC_NATIVE_NAMES = new Set(CC_TOOL_DEFINITIONS.map((t) => String(t.name)));
|
|
93
|
+
/** MCP tools attached to a CC session are namespaced `mcp__<server>__<tool>`.
|
|
94
|
+
* Real CC advertises them VERBATIM after its built-ins — the schemas are
|
|
95
|
+
* operator-supplied, so there is no canonical template entry to substitute.
|
|
96
|
+
* Passing them through unchanged IS CC's wire shape; remapping them was the
|
|
97
|
+
* divergence. Before v4.8.135 they fell through to the unmapped-tool
|
|
98
|
+
* round-robin: dropped from the advertised array (the model never saw them)
|
|
99
|
+
* while history tool_use blocks were renamed onto Bash/Read/… with junk args
|
|
100
|
+
* — seen live as "tool substitution: 28/52 client tools not in TOOL_MAP" on
|
|
101
|
+
* a CC session with an MCP server attached. Like CC_NATIVE_NAMES, these
|
|
102
|
+
* identity-map and skip TOOL_MAP entirely. */
|
|
103
|
+
export function isMcpToolName(name) {
|
|
104
|
+
return typeof name === 'string' && name.startsWith('mcp__');
|
|
105
|
+
}
|
|
76
106
|
/** CC's static system prompt (~25KB). The shared base — baked from a non-Fable
|
|
77
107
|
* model (Opus). CC ships some models a larger, model-specific prompt; see
|
|
78
108
|
* CC_SYSTEM_PROMPT_FABLE / systemPromptForModel. */
|
|
@@ -526,14 +556,21 @@ export function detectNonCCByTools(clientTools) {
|
|
|
526
556
|
const rawName = tool.name || '';
|
|
527
557
|
// A tool is "foreign" only if dario can neither map it (TOOL_MAP, by
|
|
528
558
|
// lowercased cross-client alias) nor recognize it as CC's own (CC_NATIVE_NAMES,
|
|
529
|
-
// by exact PascalCase)
|
|
559
|
+
// by exact PascalCase) nor pass it through as an MCP tool (mcp__* — identity,
|
|
560
|
+
// like CC natives). CC-native tools identity-map to themselves in the remap
|
|
530
561
|
// path (see buildCCRequest), so counting them here inflates the ratio and
|
|
531
562
|
// mis-flags a modern, agentic-heavy CC client (Agent, Skill, Workflow, Task*,
|
|
532
563
|
// … — in the live bundle but absent from TOOL_MAP's alias table) as
|
|
533
564
|
// 'unknown-non-cc', flipping it to preserve and discarding the CC tool
|
|
534
|
-
// fingerprint dario exists to present.
|
|
535
|
-
//
|
|
536
|
-
|
|
565
|
+
// fingerprint dario exists to present. Same trap for MCP tools: two or three
|
|
566
|
+
// attached servers push a real CC session past the 80% line on their own
|
|
567
|
+
// (28/52 seen live). Mirror the routing's membership test so detection and
|
|
568
|
+
// routing agree. An ALL-mcp surface now scores ratio 0 and stays in default
|
|
569
|
+
// mode — safe, because the advertise path sends an mcp-only declaration
|
|
570
|
+
// verbatim rather than falling back to the full CC template.
|
|
571
|
+
// Union set, not the host-filtered one: a win32 client's PowerShell is
|
|
572
|
+
// native regardless of the platform dario itself runs on (v4.8.136).
|
|
573
|
+
if (!TOOL_MAP[rawName.toLowerCase()] && !CC_NATIVE_NAMES_UNION.has(rawName) && !isMcpToolName(rawName))
|
|
537
574
|
unmapped++;
|
|
538
575
|
}
|
|
539
576
|
const ratio = unmapped / clientTools.length;
|
|
@@ -1336,10 +1373,16 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
|
|
|
1336
1373
|
// 2. CC's newer built-ins (Agent, AskUserQuestion, Cron*, Task*, Workflow,
|
|
1337
1374
|
// NotebookEdit, Enter/ExitPlanMode, …) aren't in TOOL_MAP at all, so
|
|
1338
1375
|
// they were round-robined onto Read/Bash/etc. and collided.
|
|
1376
|
+
// 3. MCP tools (mcp__<server>__<tool>) carry operator-supplied schemas
|
|
1377
|
+
// that never have a TOOL_MAP or template entry. Real CC forwards them
|
|
1378
|
+
// verbatim, so they identity-map too and are advertised as-is below.
|
|
1339
1379
|
// Exact case is the discriminator (CC sends PascalCase; {path}-style clients
|
|
1340
1380
|
// send lowercase/snake) so a genuine non-CC `read` still routes via TOOL_MAP.
|
|
1341
1381
|
// Tracks the live bundle, so future CC tools are covered after the next bake.
|
|
1342
|
-
|
|
1382
|
+
// UNION set: identity must hold for a win32 client's PowerShell/Glob/Grep
|
|
1383
|
+
// even when dario itself runs on Linux (v4.8.136) — the exact-case check
|
|
1384
|
+
// still keeps a non-CC lowercase `glob`/`grep` on its TOOL_MAP alias.
|
|
1385
|
+
const mapping = CC_NATIVE_NAMES_UNION.has(tool.name) || isMcpToolName(tool.name)
|
|
1343
1386
|
? { ccTool: tool.name, translateArgs: (a) => a, translateBack: (a) => a }
|
|
1344
1387
|
: TOOL_MAP[name];
|
|
1345
1388
|
if (mapping) {
|
|
@@ -1377,8 +1420,8 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
|
|
|
1377
1420
|
const CC_FALLBACK_TOOLS = ['Bash', 'Read', 'Grep', 'Glob', 'WebSearch', 'WebFetch'];
|
|
1378
1421
|
for (const tool of clientTools) {
|
|
1379
1422
|
const name = (tool.name || '').toLowerCase();
|
|
1380
|
-
if (
|
|
1381
|
-
continue; // CC-native (identity in pass 1) or mapped
|
|
1423
|
+
if (CC_NATIVE_NAMES_UNION.has(tool.name) || isMcpToolName(tool.name) || TOOL_MAP[name])
|
|
1424
|
+
continue; // CC-native (union) / MCP (identity in pass 1) or mapped
|
|
1382
1425
|
unmappedTools.push(tool.name);
|
|
1383
1426
|
if (opts.hybridTools)
|
|
1384
1427
|
continue; // dropped — see comment above
|
|
@@ -1555,13 +1598,31 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
|
|
|
1555
1598
|
// dario-routed CC session). A real CC client with a reduced tool set sends
|
|
1556
1599
|
// exactly this reduced array (every --disallowedTools / MCP delta does
|
|
1557
1600
|
// this), so filtering tracks CC's wire shape rather than diverging from it.
|
|
1558
|
-
//
|
|
1559
|
-
//
|
|
1601
|
+
//
|
|
1602
|
+
// MCP tools (mcp__<server>__<tool>) are appended VERBATIM after the
|
|
1603
|
+
// canonical natives — that mirrors real CC, which sends operator-supplied
|
|
1604
|
+
// MCP schemas after its built-ins. There is no template entry to
|
|
1605
|
+
// substitute, and omitting them here (pre-v4.8.135) meant the model never
|
|
1606
|
+
// saw the session's MCP surface at all while history references were
|
|
1607
|
+
// round-robined onto fallback slots.
|
|
1608
|
+
//
|
|
1609
|
+
// If the client declared neither a CC-native nor an MCP tool it isn't
|
|
1610
|
+
// really CC; keep the full template as the safer fingerprint default in
|
|
1611
|
+
// that case. An mcp-only declaration goes out verbatim instead — falling
|
|
1612
|
+
// back to the full template there would advertise natives the client
|
|
1613
|
+
// can't execute (the AskUserQuestion failure mode above).
|
|
1560
1614
|
const clientToolNames = new Set(clientTools
|
|
1561
1615
|
.map((t) => t.name?.toLowerCase())
|
|
1562
1616
|
.filter((n) => Boolean(n)));
|
|
1563
|
-
|
|
1564
|
-
|
|
1617
|
+
// Intersect against the UNION, not the host-filtered set: the client's
|
|
1618
|
+
// declaration encodes the client's platform, so a win32 CC declaring
|
|
1619
|
+
// PowerShell/Glob/Grep gets their canonical defs even from a Linux-hosted
|
|
1620
|
+
// dario. The host filter only governs the no-declaration fallbacks.
|
|
1621
|
+
const availableCC = CC_TOOL_DEFINITIONS_UNION.filter((t) => clientToolNames.has(t.name.toLowerCase()));
|
|
1622
|
+
const mcpTools = clientTools.filter((t) => isMcpToolName(t.name));
|
|
1623
|
+
ccRequest.tools = availableCC.length > 0 || mcpTools.length > 0
|
|
1624
|
+
? [...availableCC, ...mcpTools]
|
|
1625
|
+
: CC_TOOL_DEFINITIONS;
|
|
1565
1626
|
}
|
|
1566
1627
|
}
|
|
1567
1628
|
else if (effectiveMergeTools) {
|
package/dist/proxy.js
CHANGED
|
@@ -9,7 +9,7 @@ import { arch, platform } from 'node:process';
|
|
|
9
9
|
import { getAccessToken, getStatus } from './oauth.js';
|
|
10
10
|
import { buildHealthResponse, derivePoolStatus, shouldDiscloseHealthInternals } from './health-response.js';
|
|
11
11
|
import { darioVersion } from './version.js';
|
|
12
|
-
import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, CC_TEMPLATE } from './cc-template.js';
|
|
12
|
+
import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, isMcpToolName, CC_TEMPLATE } from './cc-template.js';
|
|
13
13
|
import { stampCch, hasCchSeed } from './cch.js';
|
|
14
14
|
import { describeTemplate, detectDrift, checkCCCompat } from './live-fingerprint.js';
|
|
15
15
|
import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs, reconcilePoolAccounts } from './pool.js';
|
|
@@ -892,6 +892,8 @@ export async function startProxy(opts = {}) {
|
|
|
892
892
|
// tool-substitution warn line. Same de-dup contract as
|
|
893
893
|
// detectedClientsLogged so mixed-traffic proxies don't spam.
|
|
894
894
|
const toolSubLogged = new Set();
|
|
895
|
+
// Same de-dup contract for the verbose-only MCP-passthrough note.
|
|
896
|
+
const mcpPassthroughLogged = new Set();
|
|
895
897
|
// Body-dump mode: set via --verbose=2 / -vv or DARIO_LOG_BODIES=1.
|
|
896
898
|
// When on, every request emits a redacted JSON body to stderr so
|
|
897
899
|
// operators can see exactly what dario forwards upstream. Default
|
|
@@ -2146,6 +2148,20 @@ export async function startProxy(opts = {}) {
|
|
|
2146
2148
|
const more = unmappedTools.length > 5 ? `, +${unmappedTools.length - 5} more` : '';
|
|
2147
2149
|
console.log(`[dario] tool substitution: ${unmappedTools.length}/${totalTools} client tool${unmappedTools.length === 1 ? '' : 's'} not in TOOL_MAP — remapped onto CC fallback slots (${sample}${more}). Pass --preserve-tools to forward your schemas verbatim instead.`);
|
|
2148
2150
|
}
|
|
2151
|
+
// MCP tools (mcp__<server>__<tool>) forward verbatim in default
|
|
2152
|
+
// mode — real CC advertises session-attached MCP schemas as-is,
|
|
2153
|
+
// so this is passthrough, not substitution. Verbose-only note so
|
|
2154
|
+
// operators can confirm their MCP surface survived; same de-dupe
|
|
2155
|
+
// as the substitution warn.
|
|
2156
|
+
if (verbose && !preserveToolsEffective && !mcpPassthroughLogged.has(subKey)) {
|
|
2157
|
+
const mcpCount = Array.isArray(r.tools)
|
|
2158
|
+
? r.tools.filter((t) => isMcpToolName(t?.name)).length
|
|
2159
|
+
: 0;
|
|
2160
|
+
if (mcpCount > 0) {
|
|
2161
|
+
mcpPassthroughLogged.add(subKey);
|
|
2162
|
+
console.log(`[dario] ${mcpCount} MCP tool${mcpCount === 1 ? '' : 's'} (mcp__*) forwarded verbatim alongside CC's native set`);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2149
2165
|
// Store tool map for response reverse-mapping
|
|
2150
2166
|
ccToolMap = toolMap;
|
|
2151
2167
|
// Replace request body entirely with CC template
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.136",
|
|
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": {
|