@lemantorus/opencode-analytics 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -0
- package/bin/opencode-analytics.js +143 -0
- package/package.json +38 -0
- package/public/app.js +880 -0
- package/public/index.html +176 -0
- package/public/styles.css +826 -0
- package/server/db.js +541 -0
- package/server/index.js +491 -0
- package/server/pricing.json +122 -0
- package/server/user-prices.json +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# OpenCode Analytics
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Unofficial** - This is a community-built dashboard, not affiliated with or endorsed by [Anomaly](https://anoma.ly) (the creators of OpenCode).
|
|
4
|
+
|
|
5
|
+
A beautiful, real-time analytics dashboard for OpenCode that visualizes your AI coding usage, token consumption, costs, and model performance.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### 📊 Usage Overview
|
|
12
|
+
- Total messages count
|
|
13
|
+
- Input/Output token breakdown
|
|
14
|
+
- Cache read/write statistics
|
|
15
|
+
- Estimated cost calculation
|
|
16
|
+
|
|
17
|
+
### 📈 Daily Usage Trend
|
|
18
|
+
- Interactive line chart showing token usage over time
|
|
19
|
+
- Toggle between Tokens view and Cost view
|
|
20
|
+
- Supports custom date ranges
|
|
21
|
+
|
|
22
|
+
### 🤖 Model Breakdown
|
|
23
|
+
- Comprehensive table of all models used
|
|
24
|
+
- Per-model statistics: messages, input/output tokens, cache, cost
|
|
25
|
+
- Visual bar chart comparison
|
|
26
|
+
- Cost distribution doughnut chart
|
|
27
|
+
|
|
28
|
+
### ⚡ Models Usage (TPS)
|
|
29
|
+
- Real tokens-per-second calculation using actual response times
|
|
30
|
+
- Select which models to compare (multi-select dropdown)
|
|
31
|
+
- Shows average TPS per day over the last 30 days
|
|
32
|
+
- Tooltip shows tree format with TPS + input/output tokens:
|
|
33
|
+
```
|
|
34
|
+
Model Name
|
|
35
|
+
├─ TPS: 45.23 tok/s
|
|
36
|
+
└─ In: 12.5K | Out: 8.2K
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**How TPS is calculated:**
|
|
40
|
+
```
|
|
41
|
+
Output TPS = outputTokens / ((time.completed - time.created) / 1000)
|
|
42
|
+
```
|
|
43
|
+
This uses the actual response start and completion timestamps from each message, providing true generation speed metrics.
|
|
44
|
+
|
|
45
|
+
### 🕐 Hourly Activity
|
|
46
|
+
- See your most productive hours
|
|
47
|
+
- Toggle between Messages count and TPS view
|
|
48
|
+
- Visual indication of peak hours (business hours highlighted)
|
|
49
|
+
|
|
50
|
+
### 💰 Cost Management
|
|
51
|
+
- Automatic pricing from models.dev API
|
|
52
|
+
- Manual price overrides per model
|
|
53
|
+
- Total estimated cost tracking
|
|
54
|
+
|
|
55
|
+
### 🎨 Design
|
|
56
|
+
- Dark theme optimized for developers
|
|
57
|
+
- JetBrains Mono font
|
|
58
|
+
- Smooth animations
|
|
59
|
+
- Responsive layout
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
### From npm (recommended)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install -g @lemantorus/opencode-analytics
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### From source
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/lemantorus/opencode_analytics.git
|
|
73
|
+
cd opencode_analytics
|
|
74
|
+
npm install
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
### Quick Start
|
|
80
|
+
|
|
81
|
+
Simply run from anywhere:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
opencode-analytics
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This will:
|
|
88
|
+
1. Auto-detect your OpenCode database location based on your OS
|
|
89
|
+
2. Start the server on http://localhost:3456
|
|
90
|
+
3. Open the dashboard in your default browser
|
|
91
|
+
|
|
92
|
+
### Command Line Options
|
|
93
|
+
|
|
94
|
+
| Option | Alias | Description | Default |
|
|
95
|
+
|--------|-------|-------------|---------|
|
|
96
|
+
| `--port` | `-p` | Port to run server on | 3456 |
|
|
97
|
+
| `--db` | - | Path to OpenCode database | Auto-detected |
|
|
98
|
+
| `--no-open` | - | Don't open browser automatically | false |
|
|
99
|
+
| `--help` | `-h` | Show help message | - |
|
|
100
|
+
|
|
101
|
+
### Examples
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Run on custom port
|
|
105
|
+
opencode-analytics --port 4000
|
|
106
|
+
|
|
107
|
+
# Use custom database path
|
|
108
|
+
opencode-analytics --db /path/to/opencode.db
|
|
109
|
+
|
|
110
|
+
# Don't open browser
|
|
111
|
+
opencode-analytics --no-open
|
|
112
|
+
|
|
113
|
+
# Combine options
|
|
114
|
+
opencode-analytics -p 3000 --db ~/custom/opencode.db --no-open
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Override database path
|
|
121
|
+
OPENCODE_DB_PATH=/custom/path/opencode.db opencode-analytics
|
|
122
|
+
|
|
123
|
+
# Override port
|
|
124
|
+
PORT=4000 opencode-analytics
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Database Locations
|
|
128
|
+
|
|
129
|
+
OpenCode stores its SQLite database in platform-specific locations:
|
|
130
|
+
|
|
131
|
+
| OS | Path |
|
|
132
|
+
|----|------|
|
|
133
|
+
| Linux | `~/.local/share/opencode/opencode.db` |
|
|
134
|
+
| macOS | `~/.local/share/opencode/opencode.db` |
|
|
135
|
+
| Windows | `%USERPROFILE%\.local\share\opencode\opencode.db` |
|
|
136
|
+
|
|
137
|
+
The application automatically detects your OS and finds the database. You can override this with the `--db` flag or `OPENCODE_DB_PATH` environment variable.
|
|
138
|
+
|
|
139
|
+
## Custom Pricing
|
|
140
|
+
|
|
141
|
+
The dashboard fetches live pricing from [models.dev](https://models.dev), but you can override prices for any model:
|
|
142
|
+
|
|
143
|
+
1. Click "Edit Pricing" button
|
|
144
|
+
2. Modify prices per 1M tokens
|
|
145
|
+
3. Click "Save" for each model
|
|
146
|
+
|
|
147
|
+
Your custom prices are stored locally and will persist across sessions.
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
### Running from source
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Clone the repository
|
|
155
|
+
git clone https://github.com/lemantorus/opencode_analytics.git
|
|
156
|
+
cd opencode_analytics
|
|
157
|
+
|
|
158
|
+
# Install dependencies
|
|
159
|
+
npm install
|
|
160
|
+
|
|
161
|
+
# Start the server
|
|
162
|
+
npm start
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Project Structure
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
opencode-analytics/
|
|
169
|
+
├── bin/
|
|
170
|
+
│ └── opencode-analytics.js # CLI entry point
|
|
171
|
+
├── server/
|
|
172
|
+
│ ├── index.js # Express server
|
|
173
|
+
│ ├── db.js # Database queries
|
|
174
|
+
│ ├── pricing.json # Cached pricing data
|
|
175
|
+
│ └── user-prices.json # User overrides
|
|
176
|
+
├── public/
|
|
177
|
+
│ ├── index.html # Dashboard HTML
|
|
178
|
+
│ ├── app.js # Frontend JavaScript
|
|
179
|
+
│ └── styles.css # Dashboard styles
|
|
180
|
+
├── package.json
|
|
181
|
+
└── README.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Tech Stack
|
|
185
|
+
|
|
186
|
+
- **Backend**: Node.js, Express
|
|
187
|
+
- **Database**: SQLite (OpenCode's native DB)
|
|
188
|
+
- **Frontend**: Vanilla JavaScript, Chart.js
|
|
189
|
+
- **Build**: No build step required
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License - feel free to use, modify, and distribute.
|
|
194
|
+
|
|
195
|
+
## Author
|
|
196
|
+
|
|
197
|
+
Built by [Lemantorus](https://github.com/lemantorus) - Not affiliated with [Anomaly](https://anoma.ly) or the official OpenCode project.
|
|
198
|
+
|
|
199
|
+
## Credits
|
|
200
|
+
|
|
201
|
+
- [OpenCode](https://opencode.ai) - The amazing AI coding agent
|
|
202
|
+
- [models.dev](https://models.dev) - For real-time model pricing
|
|
203
|
+
- [Chart.js](https://www.chartjs.org) - Beautiful charts
|
|
204
|
+
|
|
205
|
+
## Support
|
|
206
|
+
|
|
207
|
+
If you encounter any issues or have suggestions:
|
|
208
|
+
|
|
209
|
+
1. Check the [issues](https://github.com/lemantorus/opencode_analytics/issues)
|
|
210
|
+
2. Open a new issue if needed
|
|
211
|
+
3. Contributions are welcome!
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const { parseArgs } = require('util');
|
|
7
|
+
|
|
8
|
+
const HELP_TEXT = `
|
|
9
|
+
OpenCode Analytics
|
|
10
|
+
===================
|
|
11
|
+
|
|
12
|
+
Usage: opencode-analytics [options]
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--port, -p <port> Port to run server on (default: 3456)
|
|
16
|
+
--db <path> Path to OpenCode database (auto-detected by OS)
|
|
17
|
+
--no-open Don't open browser automatically
|
|
18
|
+
--help, -h Show this help message
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
opencode-analytics
|
|
22
|
+
opencode-analytics --port 4000
|
|
23
|
+
opencode-analytics --db /custom/path/opencode.db
|
|
24
|
+
opencode-analytics --port 3000 --no-open
|
|
25
|
+
|
|
26
|
+
Database locations by OS:
|
|
27
|
+
Linux/macOS: ~/.local/share/opencode/opencode.db
|
|
28
|
+
Windows: %USERPROFILE%\\.local\\share\\opencode\\opencode.db
|
|
29
|
+
|
|
30
|
+
Override with: OPENCODE_DB_PATH environment variable
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
function detectDbPath() {
|
|
34
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
35
|
+
|
|
36
|
+
if (!home) {
|
|
37
|
+
console.error('Could not detect home directory');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const dataDir = path.join(home, '.local', 'share', 'opencode');
|
|
42
|
+
const dbPath = path.join(dataDir, 'opencode.db');
|
|
43
|
+
|
|
44
|
+
return dbPath;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function findDbPath() {
|
|
48
|
+
if (process.env.OPENCODE_DB_PATH) {
|
|
49
|
+
return process.env.OPENCODE_DB_PATH;
|
|
50
|
+
}
|
|
51
|
+
return detectDbPath();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function openBrowser(url) {
|
|
55
|
+
const open = (await import('open')).default;
|
|
56
|
+
open(url);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function main() {
|
|
60
|
+
const options = {
|
|
61
|
+
port: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
short: 'p',
|
|
64
|
+
default: '3456'
|
|
65
|
+
},
|
|
66
|
+
db: {
|
|
67
|
+
type: 'string'
|
|
68
|
+
},
|
|
69
|
+
'no-open': {
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
default: false
|
|
72
|
+
},
|
|
73
|
+
help: {
|
|
74
|
+
type: 'boolean',
|
|
75
|
+
short: 'h',
|
|
76
|
+
default: false
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
let args;
|
|
81
|
+
try {
|
|
82
|
+
args = parseArgs({ options, allowPositionals: false });
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error('Invalid arguments:', e.message);
|
|
85
|
+
console.log(HELP_TEXT);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (args.values.help) {
|
|
90
|
+
console.log(HELP_TEXT);
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const port = parseInt(args.values.port) || 3456;
|
|
95
|
+
const dbPath = args.values.db || findDbPath();
|
|
96
|
+
const shouldOpen = !args.values['no-open'];
|
|
97
|
+
|
|
98
|
+
console.log(`OpenCode Analytics v1.0.0`);
|
|
99
|
+
console.log(`Database: ${dbPath}`);
|
|
100
|
+
|
|
101
|
+
if (!fs.existsSync(dbPath)) {
|
|
102
|
+
console.error(`\nError: Database not found at: ${dbPath}`);
|
|
103
|
+
console.error(`\nPlease ensure OpenCode has been used at least once on this machine.`);
|
|
104
|
+
console.error(`Or specify a custom DB path with: --db /path/to/opencode.db`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const serverPath = path.join(__dirname, '..', 'server', 'index.js');
|
|
109
|
+
|
|
110
|
+
if (!fs.existsSync(serverPath)) {
|
|
111
|
+
console.error(`Error: Server not found at: ${serverPath}`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
process.env.OPENCODE_DB_PATH = dbPath;
|
|
116
|
+
process.env.PORT = port;
|
|
117
|
+
|
|
118
|
+
const serverProcess = spawn(process.execPath, [serverPath], {
|
|
119
|
+
env: { ...process.env, OPENCODE_DB_PATH: dbPath, PORT: port.toString() },
|
|
120
|
+
stdio: 'inherit'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
serverProcess.on('error', (err) => {
|
|
124
|
+
console.error('Server error:', err);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
serverProcess.on('close', (code) => {
|
|
129
|
+
process.exit(code);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
setTimeout(async () => {
|
|
133
|
+
const url = `http://localhost:${port}`;
|
|
134
|
+
console.log(`\nServer running at: ${url}`);
|
|
135
|
+
|
|
136
|
+
if (shouldOpen) {
|
|
137
|
+
console.log('Opening browser...');
|
|
138
|
+
await openBrowser(url);
|
|
139
|
+
}
|
|
140
|
+
}, 1000);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lemantorus/opencode-analytics",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Analytics dashboard for OpenCode - visualize your AI coding usage (unofficial)",
|
|
5
|
+
"main": "server/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"opencode-analytics": "./bin/opencode-analytics.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"server",
|
|
12
|
+
"public"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"start": "node bin/opencode-analytics.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"opencode",
|
|
19
|
+
"analytics",
|
|
20
|
+
"ai",
|
|
21
|
+
"llm",
|
|
22
|
+
"usage",
|
|
23
|
+
"dashboard"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "Lemantorus <andrew@example.com>",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/lemantorus/opencode_analytics"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"express": "^4.22.1",
|
|
36
|
+
"open": "^10.1.0"
|
|
37
|
+
}
|
|
38
|
+
}
|