feat: Add Gemini + Copilot Sources#42
Conversation
Adds Gemini and Copilot as tracked usage sources (ccusage v20 gemini/copilot subcommands), with registry entries, sources grammar (gemini/gem, copilot/cop), and completions across all three shells. Also fixes a latent ccfx-era bug: codex/oc labelKey was "period" instead of "date" — verified against the vendored binary and upstream v20.0.14 source, where all per-agent subcommands emit "date". pickCurrentEntry's default now matches. The cross-tool pivot display now uses variable-width columns to accommodate the added sources while keeping output within terminal width at 80 cols. Note: per Constitution Output Stability, the release shipping this needs a MINOR bump (new table columns/output keys) — left to the release process.
There was a problem hiding this comment.
Pull request overview
This PR expands tu’s tracked sources by wiring ccusage’s gemini and copilot subcommands into the existing fetch/CLI/display pipeline, while also correcting the ccfx-era labelKey mismatch (Codex/OpenCode) and tightening the 5-tool pivot rendering to fit 80-column terminals (including watch-mode delta indicators).
Changes:
- Add
geminiandcopilotto theTOOLSregistry and CLI grammar (plus shell completions), and fix Codex/OpenCodelabelKeyto"date"(withpickCurrentEntrydefault aligned to"date"). - Update the cross-tool history pivot (
renderTotalHistory) to use per-tool column widths and a space-less watch delta indicator, with bar-width budgeting adjusted for the indicator. - Extend/adjust tests and documentation/specs to reflect the new sources and updated formatting/width contract.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/node/tui/formatter.ts | Variable-width pivot columns; watch-mode delta indicator spacing and bar-width budgeting updates. |
| src/node/tui/tests/formatter.test.ts | New/updated assertions for 5-tool pivot width behavior and watch-mode wrapping constraints. |
| src/node/core/fetcher.ts | Adds gemini/copilot tools; corrects labelKey usage and pickCurrentEntry default behavior. |
| src/node/core/completions.ts | Adds gemini/copilot tokens (and aliases) to bash/zsh/fish completions. |
| src/node/core/cli.ts | Adds new sources + aliases to parsing and help text. |
| src/node/core/tests/help-dump.test.ts | Updates help text fixture sources line used by contract builder tests. |
| src/node/core/tests/fetcher.test.ts | Expands registry tests for 5 tools; updates label-key behavior fixtures and regression guards. |
| src/node/core/tests/completions.test.ts | Ensures completions coverage includes new source tokens. |
| src/node/core/tests/cli-parser.test.ts | Adds parsing tests for gemini/gem and copilot/cop. |
| README.md | Updates sources list and screenshot alt text to include Gemini and Copilot. |
| fab/changes/260703-gmcp-add-gemini-copilot-sources/plan.md | Captures the change plan/acceptance criteria for the feature and bundled fixes. |
| fab/changes/260703-gmcp-add-gemini-copilot-sources/intake.md | Records intake verification and rationale for the implementation choices. |
| fab/changes/260703-gmcp-add-gemini-copilot-sources/.status.yaml | Tracks fab pipeline status/metadata for the change. |
| fab/changes/260703-gmcp-add-gemini-copilot-sources/.history.jsonl | Audit/history log for the fab pipeline stages. |
| docs/specs/usage.md | Updates supported sources and notes about labelKey/registry shape. |
| docs/specs/layouts.md | Updates pivot layout examples and the pivot width contract to 5-tool behavior. |
| docs/site/workflows.md | Updates workflow docs to list the expanded set of sources. |
| docs/memory/display/formatting.md | Updates formatting “memory” with the pivot column sizing + watch indicator rules. |
| docs/memory/cli/data-pipeline.md | Updates CLI/data-pipeline “memory” to include new tools and corrected label-key behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - **Columns:** Date (10 left-aligned — ISO daily labels are 10 chars, monthly 7), one per tool sized to `max(toolName.length, 8)` right-aligned (variable per-tool width — e.g. `Claude Code` → 11, all shorter names floor to 8), row Cost (8 right-aligned) | ||
| - Variable-width columns keep the **full 5-tool data row — Date + tool columns + the 3-char gutter + the 8-wide Cost cell = 79 chars** — within 80 cols: `10 + (11+8+8+8+8) + 5×3 + 3 + 8 = 79`. The old fixed-14 layout was ~108 and overflowed; a prior `max(name, 9)` + Date-12 attempt fit the 74-char body but still rendered an 85-char full row that wrapped every line. At 80 cols the inline bar is suppressed (its area is negative) so no line exceeds 79 | ||
| - **Watch mode** appends a delta indicator (`↑`/`↓`) after the Cost cell when `prevCosts` is set. In this pivot only, the indicator is rendered **without its leading space** (`$8.97↑` — 1 visible char), so the watch-mode row is 79 + 1 = **80 chars** and still fits an 80-col terminal without wrapping (the spaced ` ↑` form would be 81 and wrap, corrupting the watch compositor's line-counting). Other renderers keep the spaced form (they have width headroom) |
There was a problem hiding this comment.
Fixed — reworded to state the remaining bar area is 0 (below the MIN_BAR_AREA threshold) at 80 cols, matching the width math, rather than "negative". (39a468c)
| @@ -12,7 +12,7 @@ import { runHelpDump, FULL_HELP } from "../cli.js"; | |||
| // builder treats this text byte-for-byte and derives the contract fields. | |||
There was a problem hiding this comment.
Fixed — corrected the comment to clarify HELP_TEXT is a shortened representative excerpt (not the full FULL_HELP; it omits the Combined/Examples/Setup/Help sections and most flags), and noted that FULL_HELP itself is exercised by the runHelpDump suite below. (39a468c)
| ### Design Decisions | ||
|
|
||
| 1. **`pickCurrentEntry` default `labelKey` kept at `"period"`**: keeps the period-keyed legacy test call sites (`pickCurrentEntry(entries, period, now)`) valid — *Why*: all production callers (`fetchTotals`) pass `tool.labelKey` explicitly, so the default only affects test-call-site ergonomics; churning existing green tests adds risk without benefit — *Rejected*: flipping the default to `"date"` (would require rewriting all period-keyed `pickCurrentEntry` fixtures for no production gain). | ||
| 2. **Column width `max(toolName.length, 9)`**: 9 ≈ widest typical cost cell (`$1,234.56`) — *Why*: keeps the 5-tool table ≈75 chars, fitting 80-col terminals, while never truncating a tool name — *Rejected*: fixed 14 (overflows 80 at 5 tools), hiding zero-data columns (machine-dependent output violates Output Stability). |
There was a problem hiding this comment.
Fixed — updated the Design Decisions section to match what was implemented: decision 1 now records the pickCurrentEntry default flipped to "date" (T016/A-019), and decision 2 records the min tool width of 8 with a Date column of 10 (T006). (39a468c)
Meta
gmcpexcludes
fab/,docs/· generated by fab-kit v2.13.3Pipeline: intake ✓ → apply ✓ → review ✓ → hydrate ✓ → ship → review-pr
Summary
tu tracked Claude Code, Codex, and OpenCode only, even though the vendored ccusage v20.0.14 binary already parses Gemini CLI and GitHub Copilot CLI usage via first-class
gemini/copilotsubcommands with the standarddaily --jsonsurface. With the[ccfx]source-mapping blocker merged, adding these sources no longer worsens double-counting, so this change wires them into theTOOLSregistry, CLI grammar, completions, and display.Bundled in (user-approved at intake): intake verification against the vendored binary and upstream v20.0.14 source found that codex/oc
labelKeywas incorrectly set to"period"— all per-agent subcommands actually emit"date". This is a latent ccfx-era bug (no live impact on this fleet, no codex/opencode transcripts present) fixed at the same registry lines this change already touches.Changes
TOOLSregistry — addgeminiandcopilotentries; fix codex/oclabelKeyfrom"period"to"date"(src/node/core/fetcher.ts)gemini/gemandcopilot/copaliases (src/node/core/cli.ts)src/node/core/completions.ts)src/node/tui/formatter.ts)