Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
**/node_modules/
/.pnp
.pnp.*
.yarn/*
Expand All @@ -23,6 +23,7 @@
# misc
.DS_Store
*.pem
.vscode/

# debug
npm-debug.log*
Expand All @@ -36,6 +37,13 @@ yarn-error.log*
# vercel
.vercel

# token-tracker local blob mock
/.token-tracker-local/

# typescript
*.tsbuildinfo
next-env.d.ts

# compiled output for standalone packages
/cli/dist
/mcp/dist
64 changes: 64 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# silver-token-tracker

Reads local logs from Claude Code, Codex CLI, and Gemini CLI and prints a terminal table showing token usage and estimated cost per model.

No account, no server, no network calls — everything runs locally.

## Install

This package will be published to npm by the silver-dev-org maintainers. Install instructions will be added once the official package is live.

For now, you can run the CLI directly from this repo:

```sh
git clone https://github.com/silver-dev-org/open-silver.git
cd open-silver/cli
bun install && bun run build
node dist/index.js run
```

## Usage

```sh
silver-token-tracker run # show the visual table (default when run with no args)
silver-token-tracker run --json # output raw JSON (useful for piping into other tools)
silver-token-tracker --help # show help and supported sources
```

## What it looks like

```
Claude Code
────────────────────────────────────────────────────────────────────────
┌───────────────────────────┬───────┬────────┬────────────┬─────────────┬────────────┐
│ Model │ Input │ Output │ Cache Read │ Cache Write │ Cost (USD) │
├───────────────────────────┼───────┼────────┼────────────┼─────────────┼────────────┤
│ claude-sonnet-4-6 │ 8.7K │ 1.0M │ 52.2M │ 3.5M │ $44.57 │
│ claude-haiku-4-5-20251001 │ 4.4K │ 67.6K │ 5.2M │ 571.3K │ $1.26 │
└───────────────────────────┴───────┴────────┴────────────┴─────────────┴────────────┘

────────────────────────────────────────────────────────────────────────
TOTAL 1 source · 62.6M tokens · $45.83
────────────────────────────────────────────────────────────────────────
```

Source headers and the cost column are color-highlighted in the terminal.

## Supported sources

| Source | Log location |
|--------|-------------|
| Claude Code | `~/.claude/projects/**/*.jsonl` |
| Codex CLI | `~/.codex/history/*.json` |
| Gemini CLI | `~/.gemini/logs/*.json` |

**Cursor is not supported.** The usage schema changed in Cursor v3.1+ and the new format does not expose per-model token counts in a stable way.

## Notes

- Token counts are aggregated across all sessions found on disk (all-time, not filtered by date).
- Costs are estimated using public API pricing — they may differ from what you are actually billed if you are on a subscription plan.

---

**Reference implementation:** A working build is published on npm under `@ftaboadac/silver-token-tracker` for early testing purposes. This is not the canonical install path — the official package will be published by the silver-dev-org maintainers once the repo is transferred.
122 changes: 122 additions & 0 deletions cli/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@ftaboadac/silver-token-tracker",
"version": "0.2.0",
"description": "Read local Claude Code, Codex CLI, and Gemini CLI logs and print token usage + cost in the terminal",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/ftaboadac/open-silver.git",
"directory": "cli"
},
"type": "module",
"bin": {
"silver-token-tracker": "dist/index.js"
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=18.17.0"
},
"dependencies": {
"cli-table3": "^0.6.5",
"picocolors": "^1.1.1"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^22",
"typescript": "^5.4.0"
},
"optionalDependencies": {
"better-sqlite3": "^12.9.0"
}
}
34 changes: 34 additions & 0 deletions cli/src/collector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { parseClaudeCodeUsage } from "./parsers/claude-code.js";
import { parseCodexUsage } from "./parsers/codex.js";
import { parseGeminiUsage } from "./parsers/gemini.js";
import type { ModelUsage, SourceReport, UsageSource } from "./types.js";

const PARSERS: Array<{ source: UsageSource; parse: () => Promise<ModelUsage[]> }> = [
{ source: "claude-code", parse: parseClaudeCodeUsage },
{ source: "codex", parse: parseCodexUsage },
{ source: "gemini-cli", parse: parseGeminiUsage },
];

export async function collectUsage(): Promise<SourceReport[]> {
const now = new Date().toISOString();
const results = await Promise.allSettled(PARSERS.map(({ parse }) => parse()));
const sources: SourceReport[] = [];

for (let i = 0; i < PARSERS.length; i++) {
const { source } = PARSERS[i];
const result = results[i];

if (result.status === "rejected") {
const message = result.reason instanceof Error ? result.reason.message : String(result.reason);
console.error(`Warning (${source}): ${message}`);
continue;
}

const models = result.value;
if (models.length === 0) continue;

sources.push({ source, models, lastSyncedAt: now });
}

return sources;
}
Loading