The Cline CLI (npm `cline`, 3.x) stores sessions as <sessions>/<id>/<id>.json + <id>.messages.json. The existing `cline` provider only discovers tasks/<id>/ui_messages.json, so every CLI session was silently reported as $0.00 — no warning, not even under --verbose. Adds `cline-cli` as its own provider rather than a third root on `cline`, leaving the shared Cline-family parser (Roo Code, KiloCode, IBM Bob) untouched. It mirrors the CLI's own root resolution (CLINE_SESSION_DATA_DIR -> CLINE_DATA_DIR -> CLINE_DIR -> ~/.cline), implements probeRoots() so `doctor` can tell "not installed" from "wrong override", emits one call per assistant message's `metrics` block, and falls back to the session rollup when a session carries none. The fallback reads `usage`, not `aggregateUsage`, which folds in spawned subagents that are themselves separate session directories. Two supporting changes, both required for CLI costs to report correctly: - parser.ts re-priced cline-cli calls from tokens because the provider was not on the reported-cost allowlist, inflating a real 12-session local sample from $1.11 to $3.92. - session-cache.ts gains the matching PROVIDER_ENV_VARS entry (so a changed override invalidates) and a `reported-cost-v1` parse version (so sessions cached before the allowlist fix re-parse once instead of being re-priced forever). Cost is treated as metered only when actually present and non-negative, so a metered $0 stays reported while a missing or negative cost falls back to token pricing — applied identically on the per-message and rollup paths. Timestamps promote a seconds-resolution value rather than silently landing in 1970, matching the guard kiro.ts uses. CLINE_DIR / CLINE_DATA_DIR / CLINE_SESSION_DATA_DIR are added to the test env-isolation list so a developer's real sessions cannot bleed into fixtures. The VS Code variant discovery bug reported alongside this in #874 is deliberately NOT fixed here — it shipped in #882. Verified against 18 real local sessions: 142 calls, 4,934,762 input / 224,561 output tokens, and a cost matching the CLI's own metered total to the cent. `codeburn doctor` reports "Cline CLI OK". Refs: #874
3.4 KiB
Cline CLI
The Cline command-line agent (npm cline, 3.x). Separate from the Cline provider, which reads the VS Code extension's task tree.
- Source:
src/providers/cline-cli.ts - Loading: eager (
src/providers/index.ts) - Test:
tests/providers/cline-cli.test.ts
Where it reads from
One root, resolved exactly as the CLI resolves it — each level independently overridable:
| Level | Env var | Default |
|---|---|---|
| sessions | CLINE_SESSION_DATA_DIR |
<data>/sessions |
| data | CLINE_DATA_DIR |
<root>/data |
| root | CLINE_DIR |
~/.cline |
A directory is a session only when it contains <sessionId>/<sessionId>.json. probeRoots() reports the resolved sessions dir, so codeburn doctor distinguishes "CLI not installed" from "override pointing somewhere else".
Storage format
sessions/<sessionId>/
<sessionId>.json metadata + rolled-up usage
<sessionId>.messages.json per-message metrics
<sessionId>.json carries session_id, provider, model, cwd, workspace_root, started_at / ended_at, messages_path, and a metadata.usage rollup (inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, totalCost).
<sessionId>.messages.json holds { version, updated_at, agent, sessionId, messages[], system_prompt }. Assistant messages carry Anthropic-style content blocks (thinking / text / tool_use) plus:
"modelInfo": { "id": "z-ai/glm-5.2", "provider": "cline-pass" },
"metrics": { "inputTokens": 6937, "outputTokens": 213,
"cacheReadTokens": 0, "cacheWriteTokens": 0, "cost": 0.002108502 }
One metrics block becomes one parsed call. Dedup key: cline-cli:<sessionId>:<messageId>.
Caching
None at the provider level; the metadata file is the cached source path and the normal parser/cache layers apply.
Quirks
providerin the session file is the upstream LLM route (e.g.cline-pass), not the tool. The codeburn provider name is alwayscline-cli.- Model strings are not normalized by the CLI. The same model appears as
z-ai/glm-5.2,cline-pass/glm-5.2, andGLM-5.2across sessions, so pricing lookups may need amodel-alias. - Cost is reported per message, so
costIsEstimatedis false on the normal path; it falls back tocalculateCostonly when a message omitscost. - Rollup fallback. A session whose messages carry no metrics (interrupted, or an older layout) emits a single call from
metadata.usage. This readsusage, deliberately notaggregateUsage/aggregatedAgentsCost, which fold in spawned subagents that are themselves separate session directories and would double count. messages_pathis absolute and goes stale when a session directory is copied between machines, so the co-located<sessionId>.messages.jsonis preferred andmessages_pathis only the fallback.- Tool names differ from the extension's.
run_commands,read_files,search_codebase,editor,apply_patch,fetch_web_content,skills,spawn_agent, and theteam_*family.run_commandscarries a JSON-encoded array of command lines in a single string field.
When fixing a bug here
- Reproduce with a minimal session directory:
<id>.jsonplus<id>.messages.json. - Run
tests/providers/cline-cli.test.ts. - This provider shares no code with
vscode-cline-parser.ts— changes here cannot affect Cline, Roo Code, KiloCode, or IBM Bob.