Skip to content

feat(adapter-cline): add Cline usage adapter with cross-platform discovery - #1642

Closed
Wraient wants to merge 1 commit into
ccusage:mainfrom
Wraient:feat/cline-adapter
Closed

Wraient wants to merge 1 commit into
ccusage:mainfrom
Wraient:feat/cline-adapter

Conversation

@Wraient

@Wraient Wraient commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds a ccusage cline usage adapter that reads Cline *.messages.json transcripts, with cross-platform data discovery on Linux, macOS, and Windows.

Data discovery

Cline writes the same per-message transcript format in two places, and both are scanned:

  1. Cline CLI / JetBrains plugin — ~/.cline (%USERPROFILE%\.cline on Windows), including historical sessions under data/sessions and any newer layout elsewhere under the root.
  2. VS Code extension globalStorage — User/globalStorage/saoudrizwan.claude-dev under each stock VS Code user-data root:
OS VS Code roots scanned
Linux ~/.config/Code, ~/.config/Code - Insiders, ~/.config/VSCodium
macOS ~/Library/Application Support/{Code, Code - Insiders, VSCodium}
Windows %APPDATA%\{Code, Code - Insiders, VSCodium}

CLINE_HOME overrides discovery with a comma-separated list of directories and takes precedence over all default roots; a blank value falls back to the defaults. Results are canonicalized, sorted, and deduplicated deterministically.

Cost handling

Each assistant message carries its own modelInfo.id and metrics. Cost uses the transcript's metrics.cost when present and non-zero; otherwise it is computed from token usage via the embedded LiteLLM pricing tables.

Validation

cd rust
CCUSAGE_PRICING_JSON_PATH=<pricing snapshot> cargo test -p ccusage-adapter-cline -p ccusage-cli-parser -p ccusage -p ccusage-adapter-all --quiet
CCUSAGE_PRICING_JSON_PATH=<pricing snapshot> cargo check --workspace

All green on Linux; no warnings. OS-specific discovery branches are gated with #[cfg(target_os)] following the existing adapter pattern.


Summary by cubic

Adds ccusage cline with cross‑platform discovery of Cline *.messages.json transcripts. Previously Cline usage was not detected; now it appears in unified and per‑agent reports with correct token and cost accounting.

  • Discovers transcripts under ~/.cline (or %USERPROFILE%\.cline) and VS Code User/globalStorage/saoudrizwan.claude-dev roots on Linux, macOS, and Windows; CLINE_HOME accepts a comma‑separated override list and takes precedence.
  • Dedupes messages across overlapping locations by (session_id, timestamp, model) and sorts results deterministically.
  • Uses metrics.cost when present; otherwise computes from token usage via the existing PricingMap (LiteLLM pricing) so mixed‑model sessions are costed correctly per message.
  • Wires the new adapter into ccusage and ccusage-adapter-all; adds CLI namespace and help, updates docs, and extends tests to cover env overrides and default discovery.

Usage and rollout

  • New commands: ccusage cline daily|monthly|session. Unified ccusage daily|monthly|session now includes Cline automatically.
  • Optional: set CLINE_HOME=/path1,/path2 to point at nonstandard or archive directories; unset or blank falls back to defaults.
  • No breaking changes or migrations required.

Written for commit 01ce54d. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added Cline as a supported coding-agent data source.
    • Added ccusage cline commands for daily, monthly, and session usage reports.
    • Cline transcripts are automatically discovered, parsed, deduplicated, and summarized.
    • Added support for filtering reports with --last and including Cline in unified reports.
  • Documentation

    • Updated guides and adapter documentation to describe Cline support and transcript discovery.

…overy

Reads Cline *.messages.json transcripts from ~/.cline (CLI and JetBrains
plugin) and from the VS Code extension globalStorage
(saoudrizwan.claude-dev) under the per-OS VS Code user-data roots on Linux,
macOS, and Windows. CLINE_HOME accepts a comma-separated list of override
roots and takes precedence; a blank value falls back to the defaults.
@github-actions

Copy link
Copy Markdown
Contributor

This PR was auto-closed. Only contributors approved with lgtm can open PRs. Open an issue first.

Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.

If a maintainer replies lgtmi, your future issues will stay open. If a maintainer replies lgtm, your future issues and PRs will stay open.

See CONTRIBUTING.md.

@github-actions github-actions Bot closed this Aug 24, 2026
@coderabbitai

coderabbitai Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 13018caa-93ce-4076-a67b-7cbef5cf73d8

📥 Commits

Reviewing files that changed from the base of the PR and between 130a518 and 01ce54d.

⛔ Files ignored due to path filters (2)
  • rust/Cargo.lock is excluded by !**/*.lock
  • rust/crates/ccusage-cli-parser/src/snapshots/ccusage_cli_parser__tests__root_help.snap is excluded by !**/*.snap
📒 Files selected for processing (24)
  • apps/ccusage/README.md
  • docs/guide/all-reports.md
  • docs/guide/index.md
  • rust/Cargo.toml
  • rust/adapters/cline/Cargo.toml
  • rust/adapters/cline/README.md
  • rust/adapters/cline/src/lib.rs
  • rust/adapters/cline/src/loader.rs
  • rust/adapters/cline/src/parser.rs
  • rust/adapters/cline/src/paths.rs
  • rust/adapters/cline/src/report.rs
  • rust/crates/ccusage-adapter-all/Cargo.toml
  • rust/crates/ccusage-adapter-all/src/lib.rs
  • rust/crates/ccusage-adapter-all/src/loader.rs
  • rust/crates/ccusage-adapter-all/src/tests.rs
  • rust/crates/ccusage-cli-parser/src/cli-commands.json
  • rust/crates/ccusage-cli-parser/src/parser.rs
  • rust/crates/ccusage-cli-parser/src/tests.rs
  • rust/crates/ccusage-cli/src/types.rs
  • rust/crates/ccusage-core/src/lib.rs
  • rust/crates/ccusage/Cargo.toml
  • rust/crates/ccusage/src/adapter/mod.rs
  • rust/crates/ccusage/src/cli/last_window.rs
  • rust/crates/ccusage/src/main.rs

📝 Walkthrough

Walkthrough

Adds a Cline adapter that discovers and parses transcript files, calculates usage, and generates reports. Registers Cline in standalone and unified CLI flows, adds command help and validation, updates tests, and documents Cline as a supported source.

Changes

Cline support

Layer / File(s) Summary
Cline transcript adapter
rust/adapters/cline/..., rust/Cargo.toml
Adds transcript discovery, parsing, deduplication, token and cost conversion, report summarization, output handling, tests, and crate documentation.
Cline CLI command surface
rust/crates/ccusage-cli-parser/..., rust/crates/ccusage-cli/src/types.rs, rust/crates/ccusage/src/..., rust/crates/ccusage-core/src/lib.rs
Adds the cline command, daily/monthly/session pages, parser recognition, --last handling, dispatch, and the built-in agent name.
Unified reports and documentation
rust/crates/ccusage-adapter-all/..., rust/crates/ccusage/Cargo.toml, apps/ccusage/README.md, docs/guide/...
Registers Cline in unified loading, isolates CLINE_HOME in tests, verifies production wiring, and updates supported-source documentation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant ClineAdapter
  participant UnifiedLoader
  User->>CLI: run ccusage cline daily
  CLI->>ClineAdapter: dispatch AgentCommandArgs
  ClineAdapter->>ClineAdapter: discover, parse, and summarize transcripts
  ClineAdapter-->>CLI: render usage report
  User->>CLI: run unified report
  CLI->>UnifiedLoader: load rows
  UnifiedLoader->>ClineAdapter: load and summarize Cline entries
  ClineAdapter-->>UnifiedLoader: return Cline usage rows
Loading

Suggested reviewers: ryoppippi

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Some tools did not complete. Review the errors below.

🔧 Clippy (1.97.1)

Clippy execution failed


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

This PR has correctness and discovery gaps that should be addressed before merging.

Reviewed changes This review covers the complete single-commit addition of the Cline adapter, its transcript parser and discovery logic, CLI and unified-report wiring, tests, and documentation updates.

  • Transcript adapter Adds parsing, token mapping, cost handling, deduplication, and daily/monthly/session report generation for Cline *.messages.json files.
  • Cross-platform discovery Scans the Cline home tree and selected VS Code extension global-storage roots, with comma-separated CLINE_HOME overrides.
  • CLI integration Registers cline focused commands, unified loading, progress reporting, --last handling, and root help output.
  • Documentation Updates the npm README and broad unified-report guides to mention Cline.

⚠️ Published docs omit Cline setup details

The PR adds a supported source and documents it in the adapter README and broad report pages, but the published guide has no Cline data-source page or sidebar entry, and its environment-variable and getting-started tables omit the discovery variables. Users therefore cannot discover the focused setup or how to configure non-default Cline data locations.

Technical details
# Document the new data source consistently

## Affected sites
- `docs/.vitepress/config.ts:69-87` — the Data Sources sidebar has no Cline entry.
- `docs/guide/environment-variables.md:9-26` — the agent directory table has no Cline variable.
- `docs/guide/getting-started.md:163-179` — the troubleshooting data-directory list has no Cline entry.

## Required outcome
- Add a Cline guide with focused commands, default roots, supported override variables, and links to the shared report and JSON guides.
- Add the guide to VitePress navigation and keep the environment-variable and getting-started tables consistent with the implementation and Cline's actual variables.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

tz: Option<&JiffTimeZone>,
pricing: &PricingMap,
) -> LoadedEntry {
let cost = calculate_cline_cost(&entry, pricing);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_loaded_entry never receives SharedArgs.mode, and calculate_cline_cost always prefers the recorded cost before calculating with CostMode::Calculate. As a result, ccusage cline ... --mode calculate does not recalculate, while --mode display can estimate unrecorded costs and emit pricing warnings instead of displaying stored values only.


let metrics = message.get("metrics");
let usage = metrics.map(parse_metrics).unwrap_or_default();
let cost_usd = metrics

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A numeric metrics.cost of 0 is discarded here, so a legitimate zero-cost Cline turn is treated as missing. Cline supports free models, and the fallback then reports a positive table estimate for those turns in default auto mode, overstating the user's actual cost.

for entry in file_entries {
// Dedupe by (session_id, timestamp, model) so a re-read of the
// same transcript doesn't double-count messages.
let key = (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loader deduplicates on (session_id, timestamp, model) even though Cline messages carry a unique id; two distinct assistant messages in one session can share a millisecond timestamp and model and one will be silently dropped. Preserve the source message ID in ClineEntry and use it for cross-root deduplication.

/// source-specific path variable, so a current profile and an archive can be
/// reported together. A blank value falls back to the default roots.
fn discovery_roots() -> Result<Vec<PathBuf>> {
if let Ok(env_roots) = env::var(CLINE_HOME_ENV) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cline's supported CLI relocation is exposed as CLINE_DATA_DIR and --data-dir (with session-specific overrides also supported), not CLINE_HOME. A user running Cline with a relocated data directory writes transcripts outside ~/.cline, so this adapter silently reports no usage unless the user sets the adapter-specific variable separately.

#[cfg(target_os = "linux")]
{
let config = home.join(".config");
for name in ["Code", "Code - Insiders", "VSCodium"] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cline's IDE extension is also supported in Cursor and Windsurf, but this per-OS list scans only Code, Code Insiders, and VSCodium. Sessions created through those supported hosts are therefore silently absent from reports; add their corresponding globalStorage roots and fixture coverage.

@ryoppippi

Copy link
Copy Markdown
Member

Historical audit: this pull request was auto-closed by the legacy contributor gate. That closure did not assess technical importance.

Audit result: excluded from the current maintenance scope. This change depends on an unsupported external source, unavailable schema or fixture, platform or release infrastructure the project cannot reliably maintain, an operational service, or an unsafe or underspecified design. It is not a candidate for automatic revival or implementation.

@ryoppippi ryoppippi added the triage:excluded Excluded from the current maintenance scope. label Aug 31, 2026
ryoppippi added a commit that referenced this pull request Nov 10, 2026
* feat(cline): add extension and CLI usage adapter

Read Cline editor tasks, CLI session transcripts, and legacy CLI tasks
through a dedicated Rust adapter. Preserve reported costs and request
model history, normalize CLI cache-inclusive input, and expose focused
and unified reports with configuration, documentation, and fixtures.

Builds on the investigation and prior implementation in #1642.

Co-authored-by: Rushikesh Gaikwad <[email protected]>

* fix(cline): require complete per-request usage records

Count only requests with explicit integer counters, a recorded model ID,
and a valid request timestamp. Remove task metadata model inference and
exclude deleted-request and subagent rollups instead of assigning them
request timing or model information.

Reject incomplete, partial, unknown-model, all-zero, and inconsistent or
overflowing usage records. Document the exclusions and cover them with
fixtures plus focused and unified report assertions and snapshots.

* fix(cline): report session activity bounds and project path

Cline session reports grouped rows with summarize_by_key, which only
tracks token and cost totals, and report_from_rows always passed
include_session_metadata=false. Session JSON therefore never carried
firstActivity, lastActivity, or projectPath, unlike the other session
adapters, and the unified report got no lastActivity metadata for Cline
sessions.

Build session rows with SessionAccumulator, as zcode, qwen, and pi do,
and emit session metadata for session reports. A unit test covers a
session whose entries arrive out of order, and the session snapshots now
include the new fields.

* refactor(cli): share one report list for agents with weekly reports

STANDARD_WEEKLY_AGENT_REPORTS was an exact copy of
OPENCODE_AGENT_REPORTS. The copy existed because the original was named
after one agent rather than the report set it describes, so a second
agent with the same reports could not reuse it by name.

Rename OPENCODE_AGENT_REPORTS to ALL_AGENT_REPORTS, since it lists every
AgentReportKind, and use it for both OpenCode and Cline. The matching
arms in agent_report_supported are merged too, and the ccusage-cli
public-surface list is updated to the new name.

* docs(rust): stop hard-coding adapter counts in crate READMEs

ccusage-adapter-all said it depends on "all 18 adapters" and ccusage-cli
said "all 17 adapters". Cargo.toml now lists 19 source adapters, so both
numbers were stale, and a fixed number goes stale again whenever an
adapter is added. Say "every source adapter" / "every adapter" instead.

The ccusage-adapter-all "Depends on" list was also missing
ccusage-adapter-antigravity, which the crate depends on and loads.

* docs(cline): explain session ID prefixes and default root discovery

Session reports show IDs such as task:<id> and cli:<id>, but the guide
never explained the prefixes. Document that task: marks extension and
legacy CLI tasks and cli: marks CLI session transcripts, so a task and a
CLI session that share an ID stay separate rows.

The adapter README and the guide's storage table read as if each
platform searched only its own config directory. default_roots() checks
every candidate on every platform and skips missing ones. Say so, and
mention the %USERPROFILE%\AppData\Roaming fallback in the README.

* test(all): clear APPDATA in unified loader test isolation

The isolation helpers pin HOME and USERPROFILE to the fixture and clear
CLINE_DATA_DIR, but the Cline adapter reads APPDATA before falling back
to USERPROFILE for its Windows extension roots. On a Windows machine
these tests could pick up real Cline data from %APPDATA%.

Clear APPDATA in both helpers so Cline discovery falls back to the
fixture's USERPROFILE.

* test(cline): assert recorded costs render in table reports

The shared Cline fixture totals $0.0012, so every cost cell in the table
snapshots renders as $0.00 and a broken table cost path would not change
them. Add a fixture with $1.25 and $2.50 recorded costs and assert that
the Total row of each report kind renders $3.75.

---------

Co-authored-by: Rushikesh Gaikwad <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage:excluded Excluded from the current maintenance scope.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants