@askalf/dario 4.8.98 → 4.8.99

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
@@ -12,7 +12,7 @@
12
12
  <a href="https://x.com/ask_alf"><img src="https://img.shields.io/badge/follow-@ask_alf-1da1f2?style=flat-square" alt="Follow on X"></a>
13
13
  </p>
14
14
 
15
- <p align="center"><em>Zero runtime dependencies · <a href="https://www.npmjs.com/package/@askalf/dario">SLSA-attested</a> every release · nothing phones home · ~19.2k lines you can read in a weekend · independent, unofficial, third-party (<a href="DISCLAIMER.md">DISCLAIMER.md</a>)</em></p>
15
+ <p align="center"><em>Zero runtime dependencies · <a href="https://www.npmjs.com/package/@askalf/dario">SLSA-attested</a> every release · nothing phones home · ~20.5k lines you can read in a weekend · independent, unofficial, third-party (<a href="DISCLAIMER.md">DISCLAIMER.md</a>)</em></p>
16
16
 
17
17
  ---
18
18
 
@@ -228,6 +228,7 @@ Tune via `~/.dario/config.json` → `overageGuard`, or CLI flags: `--overage-beh
228
228
  - **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)
229
229
  - **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)
230
230
  - **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.
231
+ - **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`).
231
232
  - **Reachable from inside CC / any MCP client.** `dario subagent install` registers a CC sub-agent for in-session diagnostics; `dario mcp` exposes dario as a read-only MCP server. → [`docs/sub-agent.md`](./docs/sub-agent.md) · [`docs/mcp-server.md`](./docs/mcp-server.md)
232
233
  - **Shim mode** *(deprecated v4.2, removal scheduled v5.x)*. The original "no HTTP hop" path empirically matched only 3 of the 8 classifier axes and fell back to passthrough for the 1-block system prompts `claude -p` and the Agent SDK both send. Use **proxy mode** for any non-CC client — it's the only mode that rebuilds every request to CC's full canonical shape.
233
234
 
@@ -237,11 +238,11 @@ Tune via `~/.dario/config.json` → `overageGuard`, or CLI flags: `--overage-beh
237
238
 
238
239
  | Signal | Status |
239
240
  |---|---|
240
- | Source | **~19.2k** lines of TypeScript across **44** files — auditable in a weekend |
241
+ | Source | **~20.5k** lines of TypeScript across **47** files — auditable in a weekend |
241
242
  | Dependencies | **0 runtime.** Verify: `npm ls --production` |
242
243
  | Provenance | Every release [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions + Sigstore |
243
244
  | Scanning | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) on every push and weekly |
244
- | Tests | **92 test files**, **86 in the default `npm test` suite** (`test/all.test.mjs`) — green on every release |
245
+ | Tests | **99 test files**, **92 in the default `npm test` suite** (`test/all.test.mjs`) — green on every release |
245
246
  | Drift response | hourly [`cc-drift-watch.yml`](./.github/workflows/cc-drift-watch.yml) + auto-publish on merge — median CC-release → dario-release under one hour |
246
247
  | Credentials | Never logged, redacted from errors, `0600` on disk in `0700` dirs; MCP server redacts at the tool boundary |
247
248
  | Network | Binds `127.0.0.1` by default; upstream only to configured backends over HTTPS; hardcoded SSRF allowlist |
@@ -328,7 +329,7 @@ PRs welcome. Small TypeScript codebase, zero runtime deps. Architecture + file-b
328
329
  git clone https://github.com/askalf/dario && cd dario
329
330
  npm install
330
331
  npm run dev # tsx, no build step
331
- npm test # 86 test files via test/all.test.mjs, green on every release
332
+ npm test # 92 test files via test/all.test.mjs, green on every release
332
333
  npm run e2e # live proxy + OAuth (needs a working Claude backend)
333
334
  ```
334
335
 
@@ -427,6 +427,7 @@ export declare function buildCCRequest(clientBody: Record<string, unknown>, bill
427
427
  systemPrompt?: string;
428
428
  skipFields?: ReadonlySet<string>;
429
429
  honorClientThinking?: boolean;
430
+ preserveOutputFormat?: boolean;
430
431
  }): {
431
432
  body: Record<string, unknown>;
432
433
  toolMap: Map<string, ToolMapping>;
@@ -1614,6 +1614,22 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
1614
1614
  ccRequest.output_config = { effort: resolveEffort(opts.effort, clientBody, model) };
1615
1615
  }
1616
1616
  }
1617
+ // --preserve-output-format: carry the client's `output_config.format`
1618
+ // (Anthropic's native structured-output JSON schema) through to upstream.
1619
+ // dario rebuilds output_config from the CC template (effort only), so a
1620
+ // structured-output client's schema is otherwise dropped and the model
1621
+ // free-runs into prose its strict parser rejects. Unlike the injected
1622
+ // thinking/effort above (gated on !isHaiku because haiku rejects them),
1623
+ // this is the caller's OWN directive — it rides on whatever model the
1624
+ // caller chose, and is independent of skipFields, which opts out dario's
1625
+ // injected fields, not the caller's schema constraint.
1626
+ if (opts.preserveOutputFormat) {
1627
+ const clientOutputConfig = clientBody.output_config;
1628
+ if (clientOutputConfig?.format !== undefined) {
1629
+ const existing = ccRequest.output_config ?? {};
1630
+ ccRequest.output_config = { ...existing, format: clientOutputConfig.format };
1631
+ }
1632
+ }
1617
1633
  ccRequest.stream = stream;
1618
1634
  // Replay the captured top-level key order. The hardcoded build order above
1619
1635
  // matches CC v2.1.104 and is kept as a deterministic fallback; when a live
package/dist/cli.js CHANGED
@@ -523,6 +523,11 @@ async function proxy() {
523
523
  // ProxyOptions.honorClientThinking for rationale.
524
524
  const honorClientThinking = args.includes('--honor-client-thinking')
525
525
  || ['1', 'true', 'yes', 'on'].includes((process.env['DARIO_HONOR_CLIENT_THINKING'] ?? '').toLowerCase());
526
+ // --preserve-output-format — carry the client body's `output_config.format`
527
+ // (structured-output JSON schema) through to upstream instead of dropping it
528
+ // during the CC rebuild. See ProxyOptions.preserveOutputFormat for rationale.
529
+ const preserveOutputFormat = args.includes('--preserve-output-format')
530
+ || ['1', 'true', 'yes', 'on'].includes((process.env['DARIO_PRESERVE_OUTPUT_FORMAT'] ?? '').toLowerCase());
526
531
  // Non-loopback bind without DARIO_API_KEY turns dario into an open
527
532
  // OAuth-subscription relay for anyone on the reachable network. Refuse
528
533
  // to start rather than rely on the operator to read the startup banner.
@@ -542,7 +547,7 @@ async function proxy() {
542
547
  console.error(`[dario] Override (not recommended): pass --unsafe-no-auth if you have out-of-band network controls and accept the risk.`);
543
548
  process.exit(1);
544
549
  }
545
- await startProxy({ port, host, verbose, verboseBodies, model, passthrough, preserveTools, hybridTools, mergeTools, noAutoDetect, strictTls, pacingMinMs, pacingJitterMs, thinkTimeBaseMs, thinkTimePerTokenMs, thinkTimeJitterMs, thinkTimeMaxMs, sessionStartMinMs, sessionStartJitterMs, stealth, drainOnClose, sessionIdleRotateMs, sessionRotateJitterMs, sessionMaxAgeMs, sessionPerClient, preserveOrchestrationTags, noLiveCapture, strictTemplate, maxConcurrent, maxQueued, queueTimeoutMs, effort, maxTokens, logFile, passthroughBetas, skipFields, systemPrompt, overageGuardEnabled, overageGuardBehavior, overageGuardCooldownMs, overageGuardNotifyOs, honorClientThinking });
550
+ await startProxy({ port, host, verbose, verboseBodies, model, passthrough, preserveTools, hybridTools, mergeTools, noAutoDetect, strictTls, pacingMinMs, pacingJitterMs, thinkTimeBaseMs, thinkTimePerTokenMs, thinkTimeJitterMs, thinkTimeMaxMs, sessionStartMinMs, sessionStartJitterMs, stealth, drainOnClose, sessionIdleRotateMs, sessionRotateJitterMs, sessionMaxAgeMs, sessionPerClient, preserveOrchestrationTags, noLiveCapture, strictTemplate, maxConcurrent, maxQueued, queueTimeoutMs, effort, maxTokens, logFile, passthroughBetas, skipFields, systemPrompt, overageGuardEnabled, overageGuardBehavior, overageGuardCooldownMs, overageGuardNotifyOs, honorClientThinking, preserveOutputFormat });
546
551
  }
547
552
  /**
548
553
  * Parse `--system-prompt=<verbatim|partial|aggressive|filepath>` (or the
@@ -1413,6 +1418,17 @@ async function help() {
1413
1418
  \`thinking\`. Env:
1414
1419
  DARIO_HONOR_CLIENT_THINKING.
1415
1420
 
1421
+ --preserve-output-format
1422
+ Pass the client body's
1423
+ \`output_config.format\` (structured-output
1424
+ JSON schema) through to upstream instead of
1425
+ dropping it during the CC rebuild. Lets SDK
1426
+ clients (e.g. the Vercel AI SDK's
1427
+ \`generateObject\`) get schema-constrained
1428
+ output through dario. No effect when the
1429
+ client omits \`output_config.format\`. Env:
1430
+ DARIO_PRESERVE_OUTPUT_FORMAT.
1431
+
1416
1432
  --upstream-proxy=URL / --via=URL
1417
1433
  Route all of dario's outbound fetch
1418
1434
  calls (api.anthropic.com, OpenAI-compat
package/dist/proxy.d.ts CHANGED
@@ -317,6 +317,24 @@ interface ProxyOptions {
317
317
  * Env: DARIO_HONOR_CLIENT_THINKING=1.
318
318
  */
319
319
  honorClientThinking?: boolean;
320
+ /**
321
+ * When set, the client body's `output_config.format` (Anthropic's native
322
+ * structured-output JSON schema) is carried through to the upstream instead
323
+ * of being dropped during the CC rebuild. dario rebuilds `output_config`
324
+ * from the CC template (effort only), so structured-output clients — e.g.
325
+ * the Vercel AI SDK's `generateObject` — otherwise get unconstrained prose
326
+ * that fails their strict schema parse.
327
+ *
328
+ * Independent of skipFields: that opts out dario's INJECTED fields, while
329
+ * this preserves the caller's own schema constraint. The constraint is
330
+ * enforced upstream during decoding, so it holds regardless of the injected
331
+ * CC identity or thinking shape. Verified on claude-sonnet-4-6 that
332
+ * subscription (five_hour) routing is unchanged — headers, beta flags,
333
+ * metadata, and OAuth identity are untouched.
334
+ *
335
+ * Env: DARIO_PRESERVE_OUTPUT_FORMAT=1.
336
+ */
337
+ preserveOutputFormat?: boolean;
320
338
  /**
321
339
  * System-prompt mode for the Claude backend. Empirically validated as
322
340
  * unfingerprinted by the billing classifier in docs/research/system-prompt-classifier-study.md.
package/dist/proxy.js CHANGED
@@ -1726,6 +1726,7 @@ export async function startProxy(opts = {}) {
1726
1726
  systemPrompt: opts.systemPrompt,
1727
1727
  skipFields,
1728
1728
  honorClientThinking: opts.honorClientThinking ?? false,
1729
+ preserveOutputFormat: opts.preserveOutputFormat ?? false,
1729
1730
  });
1730
1731
  // Prompt-cache the tools + conversation prefix (the system prompt
1731
1732
  // is already cached in ccBody's system blocks). Mirrors CC's cache
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "4.8.98",
3
+ "version": "4.8.99",
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": {