Skip to content

Commit 397ca8e

Browse files
feat(opencode): add OpenCode CLI package (#758)
Co-authored-by: ryoppippi <[email protected]>
1 parent 7f73cd6 commit 397ca8e

File tree

22 files changed

+1764
-0
lines changed

22 files changed

+1764
-0
lines changed

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
77
This is a monorepo containing multiple packages. For package-specific guidance, refer to the individual CLAUDE.md files:
88

99
- **Main CLI Package**: @apps/ccusage/CLAUDE.md - Core ccusage CLI tool and library
10+
- **Codex CLI Package**: @apps/codex/CLAUDE.md - OpenAI Codex usage tracking CLI
11+
- **OpenCode CLI Package**: @apps/opencode/CLAUDE.md - OpenCode usage tracking CLI
1012
- **MCP Server Package**: @apps/mcp/CLAUDE.md - MCP server implementation for ccusage data
1113
- **Documentation**: @docs/CLAUDE.md - VitePress-based documentation website
1214

apps/ccusage/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ The main CLI tool for analyzing Claude Code usage from local JSONL files. Track
2929

3030
Companion tool for analyzing OpenAI Codex usage. Same powerful features as ccusage but tailored for Codex users, including GPT-5 support and 1M token context windows.
3131

32+
### 🚀 [@ccusage/opencode](https://www.npmjs.com/package/@ccusage/opencode) - OpenCode Usage Analyzer
33+
34+
Companion tool for analyzing OpenCode (Claude Code fork) usage. Track token usage and costs from OpenCode sessions with the same reporting capabilities as ccusage.
35+
3236
### 🔌 [@ccusage/mcp](https://www.npmjs.com/package/@ccusage/mcp) - MCP Server Integration
3337

3438
Model Context Protocol server that exposes ccusage data to Claude Desktop and other MCP-compatible tools. Enable real-time usage tracking directly in your AI workflows.

apps/opencode/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CLAUDE.md

apps/opencode/CLAUDE.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# OpenCode CLI Notes
2+
3+
## Log Sources
4+
5+
- OpenCode session usage is recorded under `${OPENCODE_DATA_DIR:-~/.local/share/opencode}/storage/message/` (the CLI resolves `OPENCODE_DATA_DIR` and falls back to `~/.local/share/opencode`).
6+
- Each message is stored as an individual JSON file (not JSONL like Claude or Codex).
7+
- Message structure includes `tokens.input`, `tokens.output`, `tokens.cache.read`, and `tokens.cache.write`.
8+
9+
## Token Fields
10+
11+
- `input`: total input tokens sent to the model.
12+
- `output`: output tokens (completion text).
13+
- `cache.read`: cached portion of the input (prompt-caching).
14+
- `cache.write`: cache creation tokens.
15+
- Pre-calculated `cost` field may be present in OpenCode messages.
16+
17+
## Cost Calculation
18+
19+
- OpenCode messages may include pre-calculated `cost` field in USD.
20+
- When `cost` is not present, costs should be calculated using model pricing data.
21+
- Token mapping:
22+
- `inputTokens``tokens.input`
23+
- `outputTokens``tokens.output`
24+
- `cacheReadInputTokens``tokens.cache.read`
25+
- `cacheCreationInputTokens``tokens.cache.write`
26+
27+
## CLI Usage
28+
29+
- Treat OpenCode as a sibling to `apps/ccusage` and `apps/codex`.
30+
- Reuse shared packages (`@ccusage/terminal`, `@ccusage/internal`) wherever possible.
31+
- OpenCode is packaged as a bundled CLI. Keep every runtime dependency in `devDependencies`.
32+
- Entry point uses Gunshi framework.
33+
- Data discovery relies on `OPENCODE_DATA_DIR` environment variable.
34+
- Default path: `~/.local/share/opencode`.
35+
36+
## Testing Notes
37+
38+
- Tests rely on `fs-fixture` with `using` to ensure cleanup.
39+
- All vitest blocks live alongside implementation files via `if (import.meta.vitest != null)`.
40+
- Vitest globals are enabled - use `describe`, `it`, `expect` directly without imports.

apps/opencode/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<div align="center">
2+
<img src="https://cdn.jsdelivr.net/gh/ryoppippi/ccusage@main/docs/public/logo.svg" alt="ccusage logo" width="256" height="256">
3+
<h1>@ccusage/opencode</h1>
4+
</div>
5+
6+
<p align="center">
7+
<a href="https://socket.dev/api/npm/package/@ccusage/opencode"><img src="https://socket.dev/api/badge/npm/package/@ccusage/opencode" alt="Socket Badge" /></a>
8+
<a href="https://npmjs.com/package/@ccusage/opencode"><img src="https://img.shields.io/npm/v/@ccusage/opencode?color=yellow" alt="npm version" /></a>
9+
<a href="https://tanstack.com/stats/npm?packageGroups=%5B%7B%22packages%22:%5B%7B%22name%22:%22@ccusage/opencode%22%7D%5D%7D%5D&range=30-days&transform=none&binType=daily&showDataMode=all&height=400"><img src="https://img.shields.io/npm/dt/@ccusage/opencode" alt="NPM Downloads" /></a>
10+
<a href="https://packagephobia.com/result?p=@ccusage/opencode"><img src="https://packagephobia.com/badge?p=@ccusage/opencode" alt="install size" /></a>
11+
<a href="https://deepwiki.com/ryoppippi/ccusage"><img src="https://img.shields.io/badge/DeepWiki-ryoppippi%2Fccusage-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==" alt="DeepWiki"></a>
12+
</p>
13+
14+
> Analyze [OpenCode](https://github.com/AnishDe12020/opencode) (Claude Code fork) usage logs with the same reporting experience as <code>ccusage</code>.
15+
16+
## Quick Start
17+
18+
```bash
19+
# Recommended - always include @latest
20+
npx @ccusage/opencode@latest --help
21+
bunx @ccusage/opencode@latest --help
22+
23+
# Alternative package runners
24+
pnpm dlx @ccusage/opencode
25+
pnpx @ccusage/opencode
26+
27+
# Using deno (with security flags)
28+
deno run -E -R=$HOME/.local/share/opencode/ -S=homedir -N='raw.githubusercontent.com:443' npm:@ccusage/opencode@latest --help
29+
```
30+
31+
### Recommended: Shell Alias
32+
33+
Since `npx @ccusage/opencode@latest` is quite long to type repeatedly, we strongly recommend setting up a shell alias:
34+
35+
```bash
36+
# bash/zsh: alias ccusage-opencode='bunx @ccusage/opencode@latest'
37+
# fish: alias ccusage-opencode 'bunx @ccusage/opencode@latest'
38+
39+
# Then simply run:
40+
ccusage-opencode daily
41+
ccusage-opencode monthly --json
42+
```
43+
44+
> 💡 The CLI looks for OpenCode usage data under `OPENCODE_DATA_DIR` (defaults to `~/.local/share/opencode`).
45+
46+
## Common Commands
47+
48+
```bash
49+
# Daily usage grouped by date (default command)
50+
npx @ccusage/opencode@latest daily
51+
52+
# Weekly usage grouped by ISO week
53+
npx @ccusage/opencode@latest weekly
54+
55+
# Monthly usage grouped by month
56+
npx @ccusage/opencode@latest monthly
57+
58+
# Session-level detailed report
59+
npx @ccusage/opencode@latest session
60+
61+
# JSON output for scripting
62+
npx @ccusage/opencode@latest daily --json
63+
64+
# Compact mode for screenshots/sharing
65+
npx @ccusage/opencode@latest daily --compact
66+
```
67+
68+
Useful environment variables:
69+
70+
- `OPENCODE_DATA_DIR` – override the OpenCode data directory (defaults to `~/.local/share/opencode`)
71+
- `LOG_LEVEL` – control consola log verbosity (0 silent … 5 trace)
72+
73+
## Features
74+
75+
- 📊 **Daily Reports**: View token usage and costs aggregated by date
76+
- 📅 **Weekly Reports**: View usage grouped by ISO week (YYYY-Www)
77+
- 🗓️ **Monthly Reports**: View usage aggregated by month (YYYY-MM)
78+
- 💬 **Session Reports**: View usage grouped by conversation sessions
79+
- 📈 **Responsive Tables**: Automatic layout adjustment for terminal width
80+
- 🤖 **Model Tracking**: See which Claude models you're using (Opus, Sonnet, Haiku, etc.)
81+
- 💵 **Accurate Cost Calculation**: Uses LiteLLM pricing database to calculate costs from token data
82+
- 🔄 **Cache Token Support**: Tracks and displays cache creation and cache read tokens separately
83+
- 📄 **JSON Output**: Export data in structured JSON format with `--json`
84+
- 📱 **Compact Mode**: Use `--compact` flag for narrow terminals, perfect for screenshots
85+
86+
## Cost Calculation
87+
88+
OpenCode stores `cost: 0` in message files, so this CLI calculates accurate costs from token usage data using the LiteLLM pricing database. All models supported by LiteLLM will have accurate pricing.
89+
90+
## Data Location
91+
92+
OpenCode stores usage data in:
93+
94+
- **Messages**: `~/.local/share/opencode/storage/message/{sessionID}/msg_{messageID}.json`
95+
- **Sessions**: `~/.local/share/opencode/storage/session/{projectHash}/{sessionID}.json`
96+
97+
Each message file contains token counts (`input`, `output`, `cache.read`, `cache.write`) and model information.
98+
99+
## Documentation
100+
101+
For detailed guides and examples, visit **[ccusage.com](https://ccusage.com/)**.
102+
103+
## Sponsors
104+
105+
### Featured Sponsor
106+
107+
Check out [ccusage: The Claude Code cost scorecard that went viral](https://www.youtube.com/watch?v=Ak6qpQ5qdgk)
108+
109+
<p align="center">
110+
<a href="https://www.youtube.com/watch?v=Ak6qpQ5qdgk">
111+
<img src="https://cdn.jsdelivr.net/gh/ryoppippi/ccusage@main/docs/public/ccusage_thumbnail.png" alt="ccusage: The Claude Code cost scorecard that went viral" width="600">
112+
</a>
113+
</p>
114+
115+
<p align="center">
116+
<a href="https://github.com/sponsors/ryoppippi">
117+
<img src="https://cdn.jsdelivr.net/gh/ryoppippi/sponsors@main/sponsors.svg">
118+
</a>
119+
</p>
120+
121+
## License
122+
123+
MIT © [@ryoppippi](https://github.com/ryoppippi)

apps/opencode/eslint.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ryoppippi } from '@ryoppippi/eslint-config';
2+
3+
/** @type {import('eslint').Linter.FlatConfig[]} */
4+
const config = ryoppippi({
5+
type: 'app',
6+
}, {
7+
rules: {
8+
'test/no-importing-vitest-globals': 'error',
9+
},
10+
});
11+
12+
export default config;

apps/opencode/package.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"name": "@ccusage/opencode",
3+
"type": "module",
4+
"version": "0.1.0",
5+
"description": "Usage analysis tool for OpenCode sessions",
6+
"author": "ryoppippi",
7+
"license": "MIT",
8+
"funding": "https://github.com/ryoppippi/ccusage?sponsor=1",
9+
"homepage": "https://github.com/ryoppippi/ccusage#readme",
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/ryoppippi/ccusage.git"
13+
},
14+
"bugs": {
15+
"url": "https://github.com/ryoppippi/ccusage/issues"
16+
},
17+
"main": "./dist/index.js",
18+
"module": "./dist/index.js",
19+
"bin": {
20+
"ccusage-opencode": "./src/index.ts"
21+
},
22+
"files": [
23+
"dist"
24+
],
25+
"engines": {
26+
"node": ">=20.19.4"
27+
},
28+
"scripts": {
29+
"build": "tsdown",
30+
"format": "pnpm run lint --fix",
31+
"lint": "eslint --cache .",
32+
"prepack": "pnpm run build && clean-pkg-json",
33+
"prerelease": "pnpm run lint && pnpm run typecheck && pnpm run build",
34+
"start": "bun ./src/index.ts",
35+
"test": "TZ=UTC vitest",
36+
"typecheck": "tsgo --noEmit"
37+
},
38+
"devDependencies": {
39+
"@ccusage/internal": "workspace:*",
40+
"@ccusage/terminal": "workspace:*",
41+
"@praha/byethrow": "catalog:runtime",
42+
"@ryoppippi/eslint-config": "catalog:lint",
43+
"@typescript/native-preview": "catalog:types",
44+
"clean-pkg-json": "catalog:release",
45+
"es-toolkit": "catalog:runtime",
46+
"eslint": "catalog:lint",
47+
"fast-sort": "catalog:runtime",
48+
"fs-fixture": "catalog:testing",
49+
"gunshi": "catalog:runtime",
50+
"path-type": "catalog:runtime",
51+
"picocolors": "catalog:runtime",
52+
"sort-package-json": "catalog:release",
53+
"tinyglobby": "catalog:runtime",
54+
"tsdown": "catalog:build",
55+
"unplugin-macros": "catalog:build",
56+
"unplugin-unused": "catalog:build",
57+
"valibot": "catalog:runtime",
58+
"vitest": "catalog:testing"
59+
},
60+
"publishConfig": {
61+
"bin": {
62+
"ccusage-opencode": "./dist/index.js"
63+
}
64+
},
65+
"devEngines": {
66+
"runtime": [
67+
{
68+
"name": "node",
69+
"version": "^24.11.0",
70+
"onFail": "download"
71+
},
72+
{
73+
"name": "bun",
74+
"version": "^1.3.2",
75+
"onFail": "download"
76+
}
77+
]
78+
}
79+
}

0 commit comments

Comments
 (0)