@askalf/dario 4.8.153 → 5.0.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/README.md +1 -2
- package/dist/cc-template-data.json +22 -18
- package/dist/cc-template.d.ts +0 -2
- package/dist/cc-template.js +0 -2
- package/dist/cli.js +50 -124
- package/dist/config-report.js +16 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +17 -7
- package/dist/live-fingerprint.d.ts +8 -8
- package/dist/live-fingerprint.js +6 -6
- package/dist/proxy.d.ts +2 -11
- package/dist/proxy.js +247 -256
- package/dist/runtime-fingerprint.d.ts +5 -11
- package/dist/runtime-fingerprint.js +7 -13
- package/dist/session-rotation.d.ts +22 -10
- package/dist/session-rotation.js +30 -13
- package/package.json +3 -3
- package/dist/shim/host.d.ts +0 -86
- package/dist/shim/host.js +0 -196
- package/dist/shim/runtime.cjs +0 -327
package/README.md
CHANGED
|
@@ -265,7 +265,6 @@ Tune via `~/.dario/config.json` → `overageGuard`, or CLI flags: `--overage-beh
|
|
|
265
265
|
- **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.
|
|
266
266
|
- **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`).
|
|
267
267
|
- **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)
|
|
268
|
-
- **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.
|
|
269
268
|
|
|
270
269
|
---
|
|
271
270
|
|
|
@@ -311,7 +310,7 @@ New *product* work happens in [askalf](https://askalf.org), the AI operation tha
|
|
|
311
310
|
|
|
312
311
|
## Commands
|
|
313
312
|
|
|
314
|
-
`dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `
|
|
313
|
+
`dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `mcp` · `subagent {install,status,remove}` · `usage` · `config` · `upgrade` · `status` · `refresh` · `resume` · `logout` · `help`
|
|
315
314
|
|
|
316
315
|
Full flag/env reference: [`docs/commands.md`](./docs/commands.md) · SDK examples + per-tool setup: [`docs/usage.md`](./docs/usage.md)
|
|
317
316
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_version": "2.1.
|
|
3
|
-
"_captured": "2026-07-
|
|
2
|
+
"_version": "2.1.207",
|
|
3
|
+
"_captured": "2026-07-11T06:31:35.366Z",
|
|
4
4
|
"_source": "bundled",
|
|
5
5
|
"_schemaVersion": 3,
|
|
6
6
|
"agent_identity": "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
|
|
@@ -529,7 +529,7 @@
|
|
|
529
529
|
},
|
|
530
530
|
{
|
|
531
531
|
"name": "EnterWorktree",
|
|
532
|
-
"description": "Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory). This tool creates an isolated git worktree and switches the current session into it.\n\n## When to Use\n\n- The user explicitly says \"worktree\" (e.g., \"start a worktree\", \"work in a worktree\", \"create a worktree\", \"use a worktree\")\n- CLAUDE.md or memory instructions direct you to work in a worktree for the current task\n\n## When NOT to Use\n\n- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead\n- The user asks to fix a bug or work on a feature — use normal git workflow unless worktrees are explicitly requested by the user or project instructions\n- Never use this tool unless \"worktree\" is explicitly mentioned by the user or in CLAUDE.md / memory instructions\n\n## Requirements\n\n- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json\n- Must not already be in a worktree session when creating a new worktree (`name`); switching into another existing worktree via `path` is allowed\n\n## Behavior\n\n- In a git repository: creates a new git worktree inside `.claude/worktrees/` on a new branch. The base ref is governed by the `worktree.baseRef` setting: `fresh` (default) branches from origin/<default-branch>; `head` branches from your current local HEAD\n- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation\n- Switches the session's working directory to the new worktree\n- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it\n\n## Entering an existing worktree\n\nPass `path` instead of `name` to switch the session into a worktree that already exists (e.g., one you just created with `git worktree add`).
|
|
532
|
+
"description": "Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory). This tool creates an isolated git worktree and switches the current session into it.\n\n## When to Use\n\n- The user explicitly says \"worktree\" (e.g., \"start a worktree\", \"work in a worktree\", \"create a worktree\", \"use a worktree\")\n- CLAUDE.md or memory instructions direct you to work in a worktree for the current task\n\n## When NOT to Use\n\n- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead\n- The user asks to fix a bug or work on a feature — use normal git workflow unless worktrees are explicitly requested by the user or project instructions\n- Never use this tool unless \"worktree\" is explicitly mentioned by the user or in CLAUDE.md / memory instructions\n\n## Requirements\n\n- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json\n- Must not already be in a worktree session when creating a new worktree (`name`); switching into another existing worktree via `path` is allowed\n\n## Behavior\n\n- In a git repository: creates a new git worktree inside `.claude/worktrees/` on a new branch. The base ref is governed by the `worktree.baseRef` setting: `fresh` (default) branches from origin/<default-branch>; `head` branches from your current local HEAD\n- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation\n- Switches the session's working directory to the new worktree\n- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it\n\n## Entering an existing worktree\n\nPass `path` instead of `name` to switch the session into a worktree that already exists (e.g., one you just created with `git worktree add`). On first entry from the launch directory, the path must appear in `git worktree list` for the repository that owns it — the current repository or, in a multi-repo workspace, a repository nested inside it; paths registered by neither are rejected. ExitWorktree will not remove a worktree entered this way; use `action: \"keep\"` to return to the original directory.\n\nSwitching with `path` also works when the session is already in a worktree (the previous worktree is left on disk, untouched, and only the new one is tracked for exit-time cleanup), and from agents whose working directory was pinned at launch (subagent isolation or explicit cwd). In both cases the target must be a worktree under `.claude/worktrees/` of the same repository, and from a pinned agent the switch only affects this agent, not the parent session. After a further switch, previously-visited worktrees are no longer writable — re-issue EnterWorktree with `path` to return to one.\n\n## Parameters\n\n- `name` (optional): A name for a new worktree. If neither `name` nor `path` is provided, a random name is generated.\n- `path` (optional): Path to an existing worktree to enter instead of creating one — of the current repository, or (on first entry from the launch directory) of a repository nested inside it. Mutually exclusive with `name`.\n",
|
|
533
533
|
"input_schema": {
|
|
534
534
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
535
535
|
"type": "object",
|
|
@@ -539,7 +539,7 @@
|
|
|
539
539
|
"type": "string"
|
|
540
540
|
},
|
|
541
541
|
"path": {
|
|
542
|
-
"description": "Path to an existing worktree
|
|
542
|
+
"description": "Path to an existing worktree to switch into instead of creating a new one. Must appear in `git worktree list` for the current repo — or, on first entry from the launch directory, for a repo nested inside it (multi-repo workspace). Mutually exclusive with `name`.",
|
|
543
543
|
"type": "string"
|
|
544
544
|
}
|
|
545
545
|
},
|
|
@@ -844,7 +844,7 @@
|
|
|
844
844
|
},
|
|
845
845
|
{
|
|
846
846
|
"name": "PushNotification",
|
|
847
|
-
"description": "This tool sends a desktop notification in the user's terminal. If Remote Control is connected, it also pushes to their phone. Either way, it pulls their attention from whatever they're doing — a meeting, another task, dinner — to this session. That's the cost. The benefit is they learn something now that they'd want to know now: a long task finished while they were away, a build is ready, you've hit something that needs their decision before you can continue.\n\nBecause a notification they didn't need is annoying in a way that accumulates, err toward not sending one. Don't notify for routine progress, or to announce you've answered something they asked seconds ago and are clearly still watching, or when a quick task completes. Notify when there's a real chance they've walked away and there's something worth coming back for — or when they've explicitly asked you to notify them.\n\nKeep the message under 200 characters, one line, no markdown. Lead with what they'd act on — \"build failed: 2 auth tests\" tells them more than \"task done\" and more than a status dump.\n\
|
|
847
|
+
"description": "This tool sends a desktop notification in the user's terminal. If Remote Control is connected, it also pushes to their phone. Either way, it pulls their attention from whatever they're doing — a meeting, another task, dinner — to this session. That's the cost. The benefit is they learn something now that they'd want to know now: a long task finished while they were away, a build is ready, you've hit something that needs their decision before you can continue.\n\nBecause a notification they didn't need is annoying in a way that accumulates, err toward not sending one. Don't notify for routine progress, or to announce you've answered something they asked seconds ago and are clearly still watching, or when a quick task completes. Notify when there's a real chance they've walked away and there's something worth coming back for — or when they've explicitly asked you to notify them.\n\nKeep the message under 200 characters, one line, no markdown. Lead with what they'd act on — \"build failed: 2 auth tests\" tells them more than \"task done\" and more than a status dump.\n\nWhen the user is actively at the terminal, your output already reaches them — a notification on top of it would be a duplicate, so the tool skips it and says so. A \"not sent\" result is expected and only ever about this one notification: it was redundant, turned off, or had nowhere to go.",
|
|
848
848
|
"input_schema": {
|
|
849
849
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
850
850
|
"type": "object",
|
|
@@ -943,6 +943,11 @@
|
|
|
943
943
|
"description": "Concrete inputs/state → wrong output/crash",
|
|
944
944
|
"type": "string"
|
|
945
945
|
},
|
|
946
|
+
"category": {
|
|
947
|
+
"description": "Short kebab-case slug of the finding type, e.g. \"correctness\", \"simplification\", \"efficiency\", \"test-coverage\"",
|
|
948
|
+
"type": "string",
|
|
949
|
+
"maxLength": 40
|
|
950
|
+
},
|
|
946
951
|
"verdict": {
|
|
947
952
|
"description": "Set when a verify pass ran; absent on inline-only reviews",
|
|
948
953
|
"type": "string",
|
|
@@ -978,35 +983,34 @@
|
|
|
978
983
|
},
|
|
979
984
|
{
|
|
980
985
|
"name": "ScheduleWakeup",
|
|
981
|
-
"description": "Schedule when to resume work in /loop dynamic mode — the user invoked /loop without an interval, asking you to self-pace iterations of a specific task.\n\nDo NOT schedule a short-interval wakeup to poll for background work you started — when harness-tracked work finishes, you are re-invoked automatically, so polling is wasted. Instead schedule a long fallback (1200s+) so the loop survives if the work hangs or never notifies. The exception is external work the harness cannot track (a CI run, a deploy, a remote queue) — there, pick a delay matched to how fast that state actually changes.\n\nPass the same /loop prompt back via `prompt` each turn so the next firing repeats the task. For an autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` as `prompt` instead — the runtime resolves it back to the autonomous-loop instructions at fire time. (There is a similar `<<autonomous-loop>>` sentinel for CronCreate-based autonomous loops; do not confuse the two — ScheduleWakeup always uses the `-dynamic` variant.)
|
|
986
|
+
"description": "Schedule when to resume work in /loop dynamic mode — the user invoked /loop without an interval, asking you to self-pace iterations of a specific task.\n\nDo NOT schedule a short-interval wakeup to poll for background work you started — when harness-tracked work finishes, you are re-invoked automatically, so polling is wasted. Instead schedule a long fallback (1200s+) so the loop survives if the work hangs or never notifies. The exception is external work the harness cannot track (a CI run, a deploy, a remote queue) — there, pick a delay matched to how fast that state actually changes.\n\nPass the same /loop prompt back via `prompt` each turn so the next firing repeats the task. For an autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` as `prompt` instead — the runtime resolves it back to the autonomous-loop instructions at fire time. (There is a similar `<<autonomous-loop>>` sentinel for CronCreate-based autonomous loops; do not confuse the two — ScheduleWakeup always uses the `-dynamic` variant.) To end the loop, call this tool with `stop: true` (omit every other field) — the loop ends immediately and no further wakeups fire.\n\n## Picking delaySeconds\n\nThis session's requests use the default 5-minute Anthropic prompt-cache TTL. Sleeping past 300 seconds means the next wake-up reads your full conversation context uncached — slower and more expensive. So the natural breakpoints:\n\n- **Under 5 minutes (60s–270s)**: cache stays warm. Right for actively polling external state the harness can't notify you about — a CI run, a deploy, a remote queue.\n- **5 minutes to 1 hour (300s–3600s)**: pay the cache miss. Right when there's no point checking sooner — waiting on something that takes minutes to change, genuinely idle, or as the long fallback heartbeat when something else is the primary wake signal.\n\n**Don't pick 300s.** It's the worst-of-both: you pay the cache miss without amortizing it. If you're tempted to \"wait 5 minutes,\" either drop to 270s (stay in cache) or commit to 1200s+ (one cache miss buys a much longer wait). Don't think in round-number minutes — think in cache windows.\n\nFor idle ticks with no specific signal to watch, default to **1200s–1800s** (20–30 min). The loop checks back, you don't burn cache 12× per hour for nothing, and the user can always interrupt if they need you sooner.\n\nThink about what you're actually waiting for, not just \"how long should I sleep.\" If you're polling a CI run that takes ~8 minutes, sleeping 60s burns the cache 8 times before it finishes — sleep ~270s twice instead.\n\nThe runtime clamps to [60, 3600], so you don't need to clamp yourself.\n\n## The reason field\n\nOne short sentence on what you chose and why. Goes to telemetry and is shown back to the user. \"watching CI run\" beats \"waiting.\" The user reads this to understand what you're doing without having to predict your cadence in advance — make it specific.\n",
|
|
982
987
|
"input_schema": {
|
|
983
988
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
984
989
|
"type": "object",
|
|
985
990
|
"properties": {
|
|
986
991
|
"delaySeconds": {
|
|
987
|
-
"description": "Seconds from now to wake up. Clamped to [60, 3600] by the runtime.",
|
|
992
|
+
"description": "Seconds from now to wake up. Clamped to [60, 3600] by the runtime. Required unless `stop` is true.",
|
|
988
993
|
"type": "number"
|
|
989
994
|
},
|
|
990
995
|
"reason": {
|
|
991
|
-
"description": "One short sentence explaining the chosen delay. Goes to telemetry and is shown to the user. Be specific.",
|
|
996
|
+
"description": "One short sentence explaining the chosen delay. Goes to telemetry and is shown to the user. Be specific. Required unless `stop` is true.",
|
|
992
997
|
"type": "string"
|
|
993
998
|
},
|
|
994
999
|
"prompt": {
|
|
995
|
-
"description": "The /loop input to fire on wake-up. Pass the same /loop input verbatim each turn so the next firing re-enters the skill and continues the loop. For autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` instead (the dynamic-pacing variant, not the CronCreate-mode `<<autonomous-loop>>`).",
|
|
1000
|
+
"description": "The /loop input to fire on wake-up. Pass the same /loop input verbatim each turn so the next firing re-enters the skill and continues the loop. For autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` instead (the dynamic-pacing variant, not the CronCreate-mode `<<autonomous-loop>>`). Required unless `stop` is true.",
|
|
996
1001
|
"type": "string"
|
|
1002
|
+
},
|
|
1003
|
+
"stop": {
|
|
1004
|
+
"description": "Set to true to end the dynamic loop immediately instead of scheduling another wakeup. When true, all other fields are ignored and no further wakeups fire.",
|
|
1005
|
+
"type": "boolean"
|
|
997
1006
|
}
|
|
998
1007
|
},
|
|
999
|
-
"required": [
|
|
1000
|
-
"delaySeconds",
|
|
1001
|
-
"reason",
|
|
1002
|
-
"prompt"
|
|
1003
|
-
],
|
|
1004
1008
|
"additionalProperties": false
|
|
1005
1009
|
}
|
|
1006
1010
|
},
|
|
1007
1011
|
{
|
|
1008
1012
|
"name": "SendMessage",
|
|
1009
|
-
"description": "# SendMessage\n\nSend a message to another agent.\n\n```json\n{\"to\": \"researcher\", \"summary\": \"assign task 1\", \"message\": \"start on task #1\"}\n```\n\n| `to` | |\n|---|---|\n| `\"researcher\"` | Teammate by name |\n| `\"main\"` | The main conversation (background subagents only) |\n\nYour plain text output is NOT visible to other agents — to communicate, you MUST call this tool. Messages from teammates are delivered automatically; you don't check an inbox. Refer to
|
|
1013
|
+
"description": "# SendMessage\n\nSend a message to another agent.\n\n```json\n{\"to\": \"researcher\", \"summary\": \"assign task 1\", \"message\": \"start on task #1\"}\n```\n\n| `to` | |\n|---|---|\n| `\"researcher\"` | Teammate by name |\n| `\"main\"` | The main conversation (background subagents only) |\n\nYour plain text output is NOT visible to other agents — to communicate, you MUST call this tool. Messages from teammates are delivered automatically; you don't check an inbox. Refer to agents by name — names keep working after an agent completes (a send resumes it from its transcript). Use the raw `agentId` (format `a...-...`) from its spawn result only when the agent has no name, or when a newer agent took the name (latest wins). When relaying, don't quote the original — it's already rendered to the user.",
|
|
1010
1014
|
"input_schema": {
|
|
1011
1015
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
1012
1016
|
"type": "object",
|
|
@@ -1417,7 +1421,7 @@
|
|
|
1417
1421
|
"anthropic_beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advisor-tool-2026-03-01,effort-2025-11-24",
|
|
1418
1422
|
"header_values": {
|
|
1419
1423
|
"accept": "application/json",
|
|
1420
|
-
"user-agent": "claude-cli/2.1.
|
|
1424
|
+
"user-agent": "claude-cli/2.1.207 (external, sdk-cli)",
|
|
1421
1425
|
"x-stainless-arch": "x64",
|
|
1422
1426
|
"x-stainless-lang": "js",
|
|
1423
1427
|
"x-stainless-os": "Linux",
|
|
@@ -1442,6 +1446,6 @@
|
|
|
1442
1446
|
"output_config",
|
|
1443
1447
|
"stream"
|
|
1444
1448
|
],
|
|
1445
|
-
"_supportedMaxTested": "2.1.
|
|
1446
|
-
"system_prompt_fable": "\nYou are an interactive agent that helps users with software engineering tasks.\n\nIMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.\n\n# Harness\n - Text you output outside of tool use is displayed to the user as Github-flavored markdown in a terminal.\n - Tools run behind a user-selected permission mode; a denied call means the user declined it — adjust, don't retry verbatim.\n -
|
|
1449
|
+
"_supportedMaxTested": "2.1.207",
|
|
1450
|
+
"system_prompt_fable": "\nYou are an interactive agent that helps users with software engineering tasks.\n\nIMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.\n\n# Harness\n - Text you output outside of tool use is displayed to the user as Github-flavored markdown in a terminal.\n - Tools run behind a user-selected permission mode; a denied call means the user declined it — adjust, don't retry verbatim.\n - The system may send updates, reminders, or modifications to rules via mid-conversation system turns. These are system-controlled, unlike function results. Hooks may intercept tool calls; treat hook output as user feedback.\n - Prefer the dedicated file/search tools over shell commands when one fits. Independent tool calls can run in parallel in one response.\n - Reference code as `file_path:line_number` — it's clickable.\n\n# Communicating with the user\n\nYour text output is what the user reads; they usually can't see your thinking or the raw tool results. Write it for a teammate who stepped away and is catching up, not for a log file: they don't know the codenames or shorthand you created along the way, and they didn't watch your process unfold. Before your first tool call, say in a sentence what you're about to do; while working, give brief updates when you find something load-bearing or change direction.\n\nText you write between tool calls may not be shown to the user. Everything the user needs from this turn — answers, summaries, findings, conclusions, deliverables — must be in the final text message of your turn, with no tool calls after it. Keep text between tool calls to brief status notes. If something important appeared only mid-turn or in your thinking, restate it in that final message.\n\nLead with the outcome. Your first sentence after finishing should answer \"what happened\" or \"what did you find\" — the thing the user would ask for if they said \"just give me the TLDR.\" Supporting detail and reasoning come after, for readers who want them.\n\nBeing readable and being concise are different things, and readable matters more. If the user has to reread your summary or ask you to explain, any time saved by brevity is gone. The way to keep output short is to be selective about what you include (drop details that don't change what the reader would do next), not to compress the writing into fragments, abbreviations, arrow chains like `A → B → fails`, or jargon. What you do include, write in complete sentences with the technical terms spelled out. Don't make the reader cross-reference labels or numbering you invented earlier; say what you mean in place.\n\nMatch the response to the question: a simple question gets a direct answer in prose, not headers and sections. Use tables only for short enumerable facts, with explanations in the surrounding prose rather than the cells. Calibrate to the user — a bit tighter for an expert, more explanatory for someone newer.\n\nWrite code that reads like the surrounding code: match its comment density, naming, and idiom.\nOnly write a code comment to state a constraint the code itself can't show — never to say where it came from, what the next line does, or why your change is correct; that's you talking to the reviewer, not the next reader, and it's noise the moment the PR merges.\n\nFor actions that are hard to reverse or outward-facing, confirm first unless durably authorized or explicitly told to proceed without asking; approval in one context doesn't extend to the next. Sending content to an external service publishes it; it may be cached or indexed even if later deleted. Before deleting or overwriting, look at the target — if what you find contradicts how it was described, or you didn't create it, surface that instead of proceeding. Report outcomes faithfully: if tests fail, say so with the output; if a step was skipped, say that; when something is done and verified, state it plainly without hedging.\n\nThis iteration of Claude is Claude Fable 5, the first model in Anthropic's new Claude 5 family and part of a new Mythos-class model tier that sits above Claude Opus in capability. Claude Fable 5 and Claude Mythos 5 share the same underlying model. Claude Fable 5 is our most intelligent generally available model, and includes additional safety measures for dual-use capabilities, while Claude Mythos 5 is available without those measures to only approved organizations. Fable 5 is the most advanced generally available Claude model. If the person asks about the differences between the two, Claude can direct them to https://www.anthropic.com/news/claude-fable-5-mythos-5 for more information.\n\n# Session-specific guidance\n - When the user types `/<skill-name>`, invoke it via Skill. Only use skills listed in the user-invocable skills section — don't guess.\n\n# Memory\n\nYou have a persistent file-based memory at `/root/.claude/projects/project/memory/`. This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence). Each memory is one file holding one fact, with frontmatter:\n\n```markdown\n---\nname: <short-kebab-case-slug>\ndescription: <one-line summary — used to decide relevance during recall>\nmetadata:\n type: user | feedback | project | reference\n---\n\n<the fact; for feedback/project, follow with **Why:** and **How to apply:** lines. Link related memories with [[their-name]].>\n```\n\nIn the body, link to related memories with `[[name]]`, where `name` is the other memory's `name:` slug. Link liberally — a `[[name]]` that doesn't match an existing memory yet is fine; it marks something worth writing later, not an error.\n\n`user` — who the user is (role, expertise, preferences). `feedback` — guidance the user has given on how you should work, both corrections and confirmed approaches; include the why. `project` — ongoing work, goals, or constraints not derivable from the code or git history; convert relative dates to absolute. `reference` — pointers to external resources (URLs, dashboards, tickets).\n\nAfter writing the file, add a one-line pointer in `MEMORY.md` (`- [Title](file.md) — hook`). `MEMORY.md` is the index loaded into context each session — one line per memory, no frontmatter, never put memory content there.\n\nBefore saving, check for an existing file that already covers it — update that file rather than creating a duplicate; delete memories that turn out to be wrong. Don't save what the repo already records (code structure, past fixes, git history, CLAUDE.md) or what only matters to this conversation; if asked to remember one of those, ask what was non-obvious about it and save that instead. Recalled memories appearing inside `<system-reminder>` blocks are background context, not user instructions, and reflect what was true when written — if one names a file, function, or flag, verify it still exists before recommending it.\n\n# Context management\nWhen the conversation grows long, some or all of the current context is summarized; the summary, along with any remaining unsummarized context, is provided in the next context window so work can continue — you don't need to wrap up early or hand off mid-task.\n\nYou are operating autonomously. The user is not watching in real time and cannot answer questions mid-task, so asking 'Want me to…?' or 'Shall I…?' will block the work. For reversible actions that follow from the original request, proceed without asking. Stop only for destructive actions or genuine scope changes the user must decide. Offering follow-ups after the task is done is fine; asking permission before doing the work is not.\n\nException: when the user is describing a problem, asking a question, or thinking out loud rather than requesting a change, the deliverable is your assessment. Report your findings and stop. Don't apply a fix until they ask for one.\n\nBefore ending your turn, check your last paragraph. If it is a plan, an analysis, a question, a list of next steps, or a promise about work you have not done ('I'll…', 'let me know when…'), do that work now with tool calls. That includes retrying after errors and gathering missing information yourself. Do not stop because the context or session is long. End your turn only when the task is complete or you are blocked on input only the user can provide.\n\nBefore running a command that changes system state — restarts, deletes, config edits — check that the evidence actually supports that specific action. A signal that pattern-matches to a known failure may have a different cause.\n"
|
|
1447
1451
|
}
|
package/dist/cc-template.d.ts
CHANGED
|
@@ -178,8 +178,6 @@ export declare function resolveSystemPrompt(arg: string | undefined, model?: str
|
|
|
178
178
|
* in the captured order are emitted in the template's exact case; names
|
|
179
179
|
* only in the caller's map keep the caller's case.
|
|
180
180
|
*
|
|
181
|
-
* Matches `rewriteHeaders` in `src/shim/runtime.cjs` — the shim and the
|
|
182
|
-
* proxy are two transports that need to produce the same wire shape.
|
|
183
181
|
*
|
|
184
182
|
* @param headers outbound headers the proxy built
|
|
185
183
|
* @param overrideHeaderOrder test-only override; production callers pass nothing
|
package/dist/cc-template.js
CHANGED
|
@@ -268,8 +268,6 @@ function stripBehavioralConstraints(input, level) {
|
|
|
268
268
|
* in the captured order are emitted in the template's exact case; names
|
|
269
269
|
* only in the caller's map keep the caller's case.
|
|
270
270
|
*
|
|
271
|
-
* Matches `rewriteHeaders` in `src/shim/runtime.cjs` — the shim and the
|
|
272
|
-
* proxy are two transports that need to produce the same wire shape.
|
|
273
271
|
*
|
|
274
272
|
* @param headers outbound headers the proxy built
|
|
275
273
|
* @param overrideHeaderOrder test-only override; production callers pass nothing
|
package/dist/cli.js
CHANGED
|
@@ -53,6 +53,22 @@ const DEFAULT_COMMAND = args.includes('--no-tui') ? 'help' : 'tui';
|
|
|
53
53
|
// `dario --version` etc. still dispatch as expected.
|
|
54
54
|
const positionalArgs = args.filter((a) => a !== '--no-tui');
|
|
55
55
|
const command = positionalArgs[0] ?? DEFAULT_COMMAND;
|
|
56
|
+
// v5.0 pool-as-primitive: materialize the just-authenticated `dario login`
|
|
57
|
+
// credentials as a pool of one (accounts/login.json under the reserved `login`
|
|
58
|
+
// alias) so every surface — proxy, doctor, config-report, /accounts — reads a
|
|
59
|
+
// single credential model. Idempotent and copy-only: a no-op when an accounts/
|
|
60
|
+
// pool already exists or no credentials are reachable, and it never refreshes
|
|
61
|
+
// the token lineage (see ensureLoginCredentialsInPool). Best-effort — a failure
|
|
62
|
+
// here shouldn't fail an otherwise-successful login; the proxy back-fills again
|
|
63
|
+
// at startup.
|
|
64
|
+
async function materializeLoginPool() {
|
|
65
|
+
try {
|
|
66
|
+
const alias = await ensureLoginCredentialsInPool();
|
|
67
|
+
if (alias)
|
|
68
|
+
console.log(' Pool: materialized as a pool of one (alias `login`).');
|
|
69
|
+
}
|
|
70
|
+
catch { /* non-fatal; proxy startup back-fills again */ }
|
|
71
|
+
}
|
|
56
72
|
async function login() {
|
|
57
73
|
console.log('');
|
|
58
74
|
console.log(' dario — Claude Login');
|
|
@@ -74,6 +90,7 @@ async function login() {
|
|
|
74
90
|
if (creds?.claudeAiOauth?.accessToken && creds.claudeAiOauth.expiresAt > Date.now()) {
|
|
75
91
|
if (noProxy) {
|
|
76
92
|
console.log(' Found valid credentials. (--no-proxy / --manual: not starting proxy.)');
|
|
93
|
+
await materializeLoginPool();
|
|
77
94
|
console.log('');
|
|
78
95
|
return;
|
|
79
96
|
}
|
|
@@ -93,6 +110,7 @@ async function login() {
|
|
|
93
110
|
const tokens = await refreshTokens();
|
|
94
111
|
const expiresIn = Math.round((tokens.expiresAt - Date.now()) / 60000);
|
|
95
112
|
console.log(` Refresh successful! Token expires in ${expiresIn} minutes.`);
|
|
113
|
+
await materializeLoginPool();
|
|
96
114
|
console.log('');
|
|
97
115
|
console.log(' Run `dario proxy` to start the API proxy.');
|
|
98
116
|
console.log('');
|
|
@@ -129,6 +147,7 @@ async function login() {
|
|
|
129
147
|
const expiresIn = Math.round((tokens.expiresAt - Date.now()) / 60000);
|
|
130
148
|
console.log(' Login successful!');
|
|
131
149
|
console.log(` Token expires in ${expiresIn} minutes (auto-refreshes).`);
|
|
150
|
+
await materializeLoginPool();
|
|
132
151
|
console.log('');
|
|
133
152
|
if (noProxy) {
|
|
134
153
|
console.log(' (--no-proxy / --manual: credentials saved, proxy not started.)');
|
|
@@ -360,9 +379,10 @@ async function proxy() {
|
|
|
360
379
|
// read-to-completion pattern. Costs tokens (the response is fully
|
|
361
380
|
// generated even if nobody reads it), so it's opt-in.
|
|
362
381
|
const drainOnClose = args.includes('--drain-on-close') || fileCfg.drainOnClose || undefined;
|
|
363
|
-
// --session-* knobs (v3.28, direction #1). Control the
|
|
364
|
-
//
|
|
365
|
-
//
|
|
382
|
+
// --session-* knobs (v3.28, direction #1). Control the session-id lifecycle:
|
|
383
|
+
// idle threshold, jitter on that threshold, hard max-age, and whether to give
|
|
384
|
+
// each upstream client its own session. v5.0: this policy now applies
|
|
385
|
+
// per-account (a pool of one behaves exactly as the pre-v5 single account).
|
|
366
386
|
// All defaults preserve v3.27 behaviour exactly. Logic lives in
|
|
367
387
|
// src/session-rotation.ts; these flags just feed resolveSessionRotationConfig.
|
|
368
388
|
const sessionIdleRotateMs = parsePositiveIntFlag('--session-idle-rotate=');
|
|
@@ -777,23 +797,24 @@ async function accounts() {
|
|
|
777
797
|
console.log(' ────────────────');
|
|
778
798
|
console.log('');
|
|
779
799
|
if (aliases.length === 0) {
|
|
780
|
-
console.log(' No
|
|
800
|
+
console.log(' No accounts in the pool yet.');
|
|
781
801
|
console.log('');
|
|
782
|
-
console.log('
|
|
783
|
-
console.log('
|
|
802
|
+
console.log(' The pool is the one credential model (v5.0): `dario login`');
|
|
803
|
+
console.log(' is a pool of one, materialized as the `login` account. Add');
|
|
804
|
+
console.log(' more to load-balance across subscriptions:');
|
|
784
805
|
console.log(' dario accounts add <alias>');
|
|
785
806
|
console.log('');
|
|
786
|
-
console.log('
|
|
787
|
-
console.log('
|
|
788
|
-
console.log('
|
|
807
|
+
console.log(' If you have run `dario login` but see this, its credentials');
|
|
808
|
+
console.log(' materialize into the pool on the next `dario login` or');
|
|
809
|
+
console.log(' `dario proxy`.');
|
|
789
810
|
console.log('');
|
|
790
811
|
return;
|
|
791
812
|
}
|
|
792
813
|
const loaded = await loadAllAccounts();
|
|
793
814
|
const now = Date.now();
|
|
794
|
-
console.log(` ${aliases.length}
|
|
815
|
+
console.log(` Pool of ${aliases.length} (${aliases.length === 1 ? '1 account' : aliases.length + ' accounts'})`);
|
|
795
816
|
if (aliases.length === 1) {
|
|
796
|
-
console.log(' (
|
|
817
|
+
console.log(' (A pool of one — add another with `dario accounts add <alias>` to load-balance.)');
|
|
797
818
|
}
|
|
798
819
|
console.log('');
|
|
799
820
|
for (const a of loaded) {
|
|
@@ -1094,13 +1115,6 @@ async function help() {
|
|
|
1094
1115
|
dario backend add NAME --key=sk-... [--base-url=...]
|
|
1095
1116
|
Add an OpenAI-compat backend (OpenAI, OpenRouter, Groq, etc.)
|
|
1096
1117
|
dario backend remove N Remove an OpenAI-compat backend
|
|
1097
|
-
dario shim -- CMD ARGS [DEPRECATED — removal scheduled for v5.x]
|
|
1098
|
-
Run CMD with dario's fetch-patch in-process.
|
|
1099
|
-
Only replaces 3 of 8 billing-classifier axes
|
|
1100
|
-
(system blocks, agent identity, header order).
|
|
1101
|
-
Falls back to passthrough on 1-block system
|
|
1102
|
-
requests (\`claude -p\`, Agent SDK). Use proxy
|
|
1103
|
-
mode for non-CC clients. See CHANGELOG v4.2.0.
|
|
1104
1118
|
dario subagent install Register ~/.claude/agents/dario.md so Claude Code
|
|
1105
1119
|
can delegate dario diagnostics / template-refresh
|
|
1106
1120
|
operations to a named sub-agent (v3.26)
|
|
@@ -1208,7 +1222,7 @@ async function help() {
|
|
|
1208
1222
|
proxy's JA3/JA4 ClientHello indistinguishable
|
|
1209
1223
|
from a stock CC request. Install Bun
|
|
1210
1224
|
(https://bun.sh) so dario auto-relaunches
|
|
1211
|
-
under it
|
|
1225
|
+
under it. (v3.23)
|
|
1212
1226
|
--stealth Single-flag behavioral-stealth preset.
|
|
1213
1227
|
Flips pace-jitter, think-time, and
|
|
1214
1228
|
session-start defaults from 0 to non-zero
|
|
@@ -1268,11 +1282,12 @@ async function help() {
|
|
|
1268
1282
|
is fully generated even if nobody reads
|
|
1269
1283
|
it) for fingerprint fidelity. Bounded by
|
|
1270
1284
|
the 5-minute upstream timeout. (v3.25)
|
|
1271
|
-
--session-idle-rotate=MS Idle ms before
|
|
1272
|
-
|
|
1285
|
+
--session-idle-rotate=MS Idle ms before an account's session id
|
|
1286
|
+
rotates (default: 900000 = 15 min).
|
|
1273
1287
|
Real CC rotates once per conversation, not
|
|
1274
1288
|
per call; the default matches its observed
|
|
1275
|
-
cadence.
|
|
1289
|
+
cadence. Applies per account — a pool of one
|
|
1290
|
+
rotates as the pre-v5 single account did. (v3.28)
|
|
1276
1291
|
--session-rotate-jitter=MS
|
|
1277
1292
|
Max additional uniform-random jitter (ms)
|
|
1278
1293
|
added to the idle threshold, sampled once
|
|
@@ -1489,109 +1504,20 @@ async function help() {
|
|
|
1489
1504
|
Tokens auto-refresh in the background — set it and forget it.
|
|
1490
1505
|
`);
|
|
1491
1506
|
}
|
|
1507
|
+
// `dario shim` was removed in v5.0 (deprecated since v4.2 — it matched only
|
|
1508
|
+
// 3 of the 8 billing-classifier axes and fell back to passthrough on 1-block
|
|
1509
|
+
// system requests). This stub keeps the failure mode a one-line pointer
|
|
1510
|
+
// instead of an "unknown command" for users upgrading across the boundary.
|
|
1492
1511
|
async function shim() {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
if (sepIdx >= 0) {
|
|
1503
|
-
head = rest.slice(0, sepIdx);
|
|
1504
|
-
childArgs = rest.slice(sepIdx + 1);
|
|
1505
|
-
}
|
|
1506
|
-
else {
|
|
1507
|
-
head = [];
|
|
1508
|
-
childArgs = rest;
|
|
1509
|
-
}
|
|
1510
|
-
for (const flag of head) {
|
|
1511
|
-
if (flag === '-v' || flag === '--verbose')
|
|
1512
|
-
verbose = true;
|
|
1513
|
-
else if (flag.startsWith('--priority=')) {
|
|
1514
|
-
const v = flag.slice('--priority='.length);
|
|
1515
|
-
if (v !== 'normal' && v !== 'below-normal' && v !== 'low') {
|
|
1516
|
-
console.error(`--priority: invalid value ${JSON.stringify(v)}. Expected one of: normal, below-normal, low.`);
|
|
1517
|
-
process.exit(1);
|
|
1518
|
-
}
|
|
1519
|
-
priority = v;
|
|
1520
|
-
}
|
|
1521
|
-
else {
|
|
1522
|
-
console.error(`Unknown shim flag: ${flag}`);
|
|
1523
|
-
process.exit(1);
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
if (childArgs.length === 0) {
|
|
1527
|
-
console.error('Usage: dario shim [-v] [--priority=normal|below-normal|low] -- <command> [args...]');
|
|
1528
|
-
console.error('Example: dario shim -- claude --print -p "hi"');
|
|
1529
|
-
console.error(' dario shim --priority=below-normal -- claude (recommended on Windows when RDP\'d into the host)');
|
|
1530
|
-
process.exit(1);
|
|
1531
|
-
}
|
|
1532
|
-
// v4.2.0+: shim mode is DEPRECATED — set for removal in v5.x.
|
|
1533
|
-
//
|
|
1534
|
-
// The empirical reason (verified by side-by-side fingerprint diff of
|
|
1535
|
-
// shim's `_rewriteBody` against the proxy's `buildCCRequest` — see
|
|
1536
|
-
// CHANGELOG v4.2.0 entry): shim mode only replaces 3 of the 8 axes
|
|
1537
|
-
// Anthropic's billing classifier actually inspects (system blocks,
|
|
1538
|
-
// agent identity, header order). It leaves the client's JSON key
|
|
1539
|
-
// order, max_tokens value, metadata billing tag, and any non-CC
|
|
1540
|
-
// fields (temperature, top_p, service_tier) unchanged on the wire.
|
|
1541
|
-
// And on the most-common claude -p / Agent-SDK request shape (which
|
|
1542
|
-
// sends a 1-block system, not the 3-block shape shim's shape-check
|
|
1543
|
-
// hardcodes), shim silently falls back to total passthrough — sending
|
|
1544
|
-
// the client's raw body to api.anthropic.com with zero replay.
|
|
1545
|
-
//
|
|
1546
|
-
// For interactive CC (`dario shim -- claude`), this is mostly a no-op
|
|
1547
|
-
// because CC's own outbound already matches every axis dario would
|
|
1548
|
-
// synthesize. But for any non-CC client (`dario shim -- aider`,
|
|
1549
|
-
// `dario shim -- cline`, your own scripts), shim mode does not deliver
|
|
1550
|
-
// the wire fidelity the README claims.
|
|
1551
|
-
//
|
|
1552
|
-
// We warn loudly here instead of silently breaking, and point users
|
|
1553
|
-
// at proxy mode. Set DARIO_SHIM_NO_DEPRECATION_WARNING=1 to suppress
|
|
1554
|
-
// the banner for scripts that need the exit-code semantics but have
|
|
1555
|
-
// already migrated their understanding.
|
|
1556
|
-
if (process.env['DARIO_SHIM_NO_DEPRECATION_WARNING'] !== '1') {
|
|
1557
|
-
console.error('');
|
|
1558
|
-
console.error('[dario] ⚠ DEPRECATION: `dario shim` is deprecated in v4.2 and scheduled for removal in v5.x.');
|
|
1559
|
-
console.error('[dario]');
|
|
1560
|
-
console.error('[dario] Shim mode only matches a subset of the wire-shape axes Anthropic\'s billing classifier');
|
|
1561
|
-
console.error('[dario] inspects. Specifically, it does not normalize JSON key order, max_tokens, metadata');
|
|
1562
|
-
console.error('[dario] billing-tag, or non-CC body fields. On `claude -p` / Agent-SDK style requests (1-block');
|
|
1563
|
-
console.error('[dario] system), shim falls back to total passthrough — the client\'s raw body reaches the');
|
|
1564
|
-
console.error('[dario] upstream unchanged.');
|
|
1565
|
-
console.error('[dario]');
|
|
1566
|
-
console.error('[dario] Use proxy mode instead, which rebuilds every request to CC\'s exact wire shape:');
|
|
1567
|
-
console.error('[dario]');
|
|
1568
|
-
console.error('[dario] Terminal 1: dario proxy');
|
|
1569
|
-
console.error('[dario] Terminal 2: ANTHROPIC_BASE_URL=http://localhost:3456 \\');
|
|
1570
|
-
console.error('[dario] ANTHROPIC_API_KEY=dario \\');
|
|
1571
|
-
console.error('[dario] ' + childArgs.join(' '));
|
|
1572
|
-
console.error('[dario]');
|
|
1573
|
-
console.error('[dario] To suppress this banner: DARIO_SHIM_NO_DEPRECATION_WARNING=1');
|
|
1574
|
-
console.error('');
|
|
1575
|
-
}
|
|
1576
|
-
const { runShim } = await import('./shim/host.js');
|
|
1577
|
-
try {
|
|
1578
|
-
const result = await runShim({
|
|
1579
|
-
command: childArgs[0],
|
|
1580
|
-
args: childArgs.slice(1),
|
|
1581
|
-
verbose,
|
|
1582
|
-
priority,
|
|
1583
|
-
});
|
|
1584
|
-
if (verbose) {
|
|
1585
|
-
const summary = result.analytics.summary(60);
|
|
1586
|
-
console.error(`[dario shim] ${result.events.length} relay events, ` +
|
|
1587
|
-
`subscriptionPercent=${summary.window.subscriptionPercent}%`);
|
|
1588
|
-
}
|
|
1589
|
-
process.exit(result.exitCode);
|
|
1590
|
-
}
|
|
1591
|
-
catch (err) {
|
|
1592
|
-
console.error('shim failed:', sanitizeError(err));
|
|
1593
|
-
process.exit(1);
|
|
1594
|
-
}
|
|
1512
|
+
console.error('`dario shim` was removed in v5.0. Use proxy mode instead:');
|
|
1513
|
+
console.error('');
|
|
1514
|
+
console.error(' Terminal 1: dario proxy');
|
|
1515
|
+
console.error(' Terminal 2: ANTHROPIC_BASE_URL=http://localhost:3456 \\');
|
|
1516
|
+
console.error(' ANTHROPIC_API_KEY=dario \\');
|
|
1517
|
+
console.error(' <your command>');
|
|
1518
|
+
console.error('');
|
|
1519
|
+
console.error('See MIGRATION.md (v4 → v5) for details.');
|
|
1520
|
+
process.exit(1);
|
|
1595
1521
|
}
|
|
1596
1522
|
async function subagent() {
|
|
1597
1523
|
const sub = args[1] ?? 'status';
|
package/dist/config-report.js
CHANGED
|
@@ -82,10 +82,25 @@ export async function collectEffectiveConfig() {
|
|
|
82
82
|
try {
|
|
83
83
|
const { listAccountAliases } = await import('./accounts.js');
|
|
84
84
|
const aliases = await listAccountAliases();
|
|
85
|
+
// Pool-as-primitive (v5.0): the pool is the one credential model. An empty
|
|
86
|
+
// accounts/ dir means either not-logged-in or a `dario login` whose
|
|
87
|
+
// credentials.json hasn't been back-filled into the pool yet (that happens
|
|
88
|
+
// on the next `dario login` / `dario proxy`), so report the pending pool-of-one.
|
|
89
|
+
let mode;
|
|
90
|
+
if (aliases.length > 0) {
|
|
91
|
+
mode = `pool of ${aliases.length}`;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const { loadCredentials } = await import('./oauth.js');
|
|
95
|
+
const creds = await loadCredentials();
|
|
96
|
+
mode = creds?.claudeAiOauth?.accessToken
|
|
97
|
+
? 'pool of 1 (login, not yet materialized)'
|
|
98
|
+
: 'empty (run `dario login`)';
|
|
99
|
+
}
|
|
85
100
|
sections.push({
|
|
86
101
|
title: 'Account pool',
|
|
87
102
|
rows: [
|
|
88
|
-
{ label: 'mode', value:
|
|
103
|
+
{ label: 'mode', value: mode },
|
|
89
104
|
...(aliases.length > 0 ? [{ label: 'aliases', value: aliases.join(', ') }] : []),
|
|
90
105
|
],
|
|
91
106
|
});
|
package/dist/doctor.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export interface IdentityDriftInput {
|
|
|
70
70
|
deviceId: string;
|
|
71
71
|
accountUuid: string;
|
|
72
72
|
} | null;
|
|
73
|
-
/** Pool account snapshots — `[]`
|
|
73
|
+
/** Pool account snapshots — `[]` when no pool accounts are materialized yet. */
|
|
74
74
|
poolAccounts: Array<{
|
|
75
75
|
alias: string;
|
|
76
76
|
deviceId: string;
|
package/dist/doctor.js
CHANGED
|
@@ -104,7 +104,7 @@ export function checkIdentityDrift(input) {
|
|
|
104
104
|
return [{
|
|
105
105
|
status: 'info',
|
|
106
106
|
label: 'Identity',
|
|
107
|
-
detail: `~/.claude.json userID=${shortId(live.deviceId)} —
|
|
107
|
+
detail: `~/.claude.json userID=${shortId(live.deviceId)} — no pool accounts snapshotted yet, so identity drift can't be checked. It starts once the login pool-of-one is materialized (\`dario login\` / \`dario proxy\`) or you \`dario accounts add\` more; until then a mismatch only surfaces as a 401 from Anthropic on non-Haiku models.`,
|
|
108
108
|
}];
|
|
109
109
|
}
|
|
110
110
|
const aligned = [];
|
|
@@ -740,7 +740,17 @@ export async function runChecks(opts = {}) {
|
|
|
740
740
|
const { listAccountAliases, loadAllAccounts } = await import('./accounts.js');
|
|
741
741
|
const aliases = await listAccountAliases();
|
|
742
742
|
if (aliases.length === 0) {
|
|
743
|
-
|
|
743
|
+
// Pool-as-primitive (v5.0): no accounts/ entries. Either not logged in,
|
|
744
|
+
// or a pre-v5 `dario login` whose credentials.json hasn't been back-filled
|
|
745
|
+
// into the pool yet — that happens on the next `dario login` / `dario proxy`.
|
|
746
|
+
const { loadCredentials } = await import('./oauth.js');
|
|
747
|
+
const creds = await loadCredentials();
|
|
748
|
+
if (creds?.claudeAiOauth?.accessToken) {
|
|
749
|
+
checks.push({ status: 'info', label: 'Pool', detail: 'pool of 1 (login credentials present, not yet materialized — runs on next `dario login` or `dario proxy`); `dario accounts add <alias>` adds more for headroom routing' });
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
checks.push({ status: 'info', label: 'Pool', detail: 'empty — run `dario login` (a pool of one) or `dario accounts add <alias>`' });
|
|
753
|
+
}
|
|
744
754
|
}
|
|
745
755
|
else {
|
|
746
756
|
const loaded = await loadAllAccounts();
|
|
@@ -749,9 +759,9 @@ export async function runChecks(opts = {}) {
|
|
|
749
759
|
checks.push({
|
|
750
760
|
status: expired > 0 ? 'warn' : 'ok',
|
|
751
761
|
label: 'Pool',
|
|
752
|
-
detail:
|
|
762
|
+
detail: `pool of ${aliases.length}` +
|
|
753
763
|
(expired > 0 ? `, ${expired} expired` : '') +
|
|
754
|
-
(aliases.length === 1 ? ' (pool
|
|
764
|
+
(aliases.length === 1 ? ' (a pool of one — `dario accounts add <alias>` to load-balance)' : ''),
|
|
755
765
|
});
|
|
756
766
|
// Next-account-in-rotation surfacing. The proxy's per-request
|
|
757
767
|
// selector picks by max headroom (with 7d_<family> per-model
|
|
@@ -761,9 +771,9 @@ export async function runChecks(opts = {}) {
|
|
|
761
771
|
// operators wondering "if I send a request right now, which
|
|
762
772
|
// account gets it?" — it matches `pool.select()` with no family
|
|
763
773
|
// hint, the same call the proxy uses when no model is parsed
|
|
764
|
-
// yet (e.g. on misshapen requests).
|
|
765
|
-
// account is
|
|
766
|
-
if (aliases.length >=
|
|
774
|
+
// yet (e.g. on misshapen requests). Shown for a pool of one too
|
|
775
|
+
// (v5.0): it confirms the sole account is eligible, not rejected.
|
|
776
|
+
if (aliases.length >= 1) {
|
|
767
777
|
try {
|
|
768
778
|
const { AccountPool } = await import('./pool.js');
|
|
769
779
|
const pool = new AccountPool();
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
* provided both run on the same Node major. A cross-runtime worry
|
|
42
42
|
* surfaces when Anthropic ships Bun- or bundled-binary CC: at that
|
|
43
43
|
* point Node-dario and Bun-CC would JA-differ.
|
|
44
|
-
* → Mitigation:
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* → Mitigation: dario auto-relaunches under Bun when it's on PATH so
|
|
45
|
+
* the proxy's ClientHello matches CC's Bun/BoringSSL shape;
|
|
46
|
+
* `--strict-tls` refuses to start otherwise.
|
|
47
47
|
*
|
|
48
48
|
* 3. HTTP/2 frame ordering + SETTINGS parameters. Similar to TLS, this
|
|
49
49
|
* is controlled by the HTTP library. Node and undici produce a
|
|
@@ -115,8 +115,8 @@ export interface TemplateData {
|
|
|
115
115
|
/**
|
|
116
116
|
* The `anthropic-beta` flag set CC sent on the captured request, verbatim.
|
|
117
117
|
* Schema v2 (v3.19). Previously the proxy path hardcoded this — bumping
|
|
118
|
-
* CC's beta list required a dario release. Now the
|
|
119
|
-
*
|
|
118
|
+
* CC's beta list required a dario release. Now the proxy replays
|
|
119
|
+
* whatever the live capture recorded. Falls back to
|
|
120
120
|
* `'claude-code-20250219'` when undefined (bundled snapshots, older caches).
|
|
121
121
|
*/
|
|
122
122
|
anthropic_beta?: string;
|
|
@@ -236,9 +236,9 @@ export declare function probeInstalledCCVersion(): string | null;
|
|
|
236
236
|
export declare function formatCaptureAge(capturedIso: string, now?: number): string;
|
|
237
237
|
/**
|
|
238
238
|
* One-line human summary of the active template — what source, which CC
|
|
239
|
-
* version captured it, and how old that capture is. Proxy
|
|
240
|
-
*
|
|
241
|
-
*
|
|
239
|
+
* version captured it, and how old that capture is. Proxy startup logs
|
|
240
|
+
* this so users can tell at a glance whether they're on a fresh live
|
|
241
|
+
* capture or a stale bundled fallback.
|
|
242
242
|
*/
|
|
243
243
|
export declare function describeTemplate(t: TemplateData): string;
|
|
244
244
|
export interface DriftResult {
|