@semboja/opencode-claude 0.1.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.
@@ -0,0 +1,31 @@
1
+ import type { StorageBackend, SessionUsage, ApiRequestMetrics, UsageStats } from './types.js';
2
+ /**
3
+ * File-based storage backend for Claude usage tracking
4
+ */
5
+ export declare class FileStorage implements StorageBackend {
6
+ private basePath;
7
+ private sessionsDir;
8
+ private requestsDir;
9
+ constructor(storagePath?: string);
10
+ private ensureDirectories;
11
+ private sessionFilePath;
12
+ private requestFilePath;
13
+ saveSession(session: SessionUsage): Promise<void>;
14
+ saveApiRequest(sessionId: string, request: ApiRequestMetrics): Promise<void>;
15
+ getSession(sessionId: string): Promise<SessionUsage | null>;
16
+ getAllSessions(limit?: number): Promise<SessionUsage[]>;
17
+ getUsageStats(startDate?: string, endDate?: string): Promise<UsageStats>;
18
+ }
19
+ /**
20
+ * In-memory storage backend (useful for testing or ephemeral tracking)
21
+ */
22
+ export declare class MemoryStorage implements StorageBackend {
23
+ private sessions;
24
+ private requests;
25
+ saveSession(session: SessionUsage): Promise<void>;
26
+ saveApiRequest(sessionId: string, request: ApiRequestMetrics): Promise<void>;
27
+ getSession(sessionId: string): Promise<SessionUsage | null>;
28
+ getAllSessions(limit?: number): Promise<SessionUsage[]>;
29
+ getUsageStats(): Promise<UsageStats>;
30
+ }
31
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,UAAU,EAGX,MAAM,YAAY,CAAC;AAsBpB;;GAEG;AACH,qBAAa,WAAY,YAAW,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,CAAC,EAAE,MAAM;IAOhC,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAIjB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5E,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAa3D,cAAc,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBpD,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA+E/E;AAED;;GAEG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAA0C;IAEpD,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5E,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAI3D,cAAc,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIpD,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;CAY3C"}
@@ -0,0 +1,197 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as os from 'node:os';
4
+ /**
5
+ * Creates an empty token usage object
6
+ */
7
+ function emptyTokenUsage() {
8
+ return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, total: 0 };
9
+ }
10
+ /**
11
+ * Adds two token usage objects together
12
+ */
13
+ function addTokenUsage(a, b) {
14
+ return {
15
+ input: a.input + b.input,
16
+ output: a.output + b.output,
17
+ cacheRead: a.cacheRead + b.cacheRead,
18
+ cacheCreation: a.cacheCreation + b.cacheCreation,
19
+ total: a.total + b.total,
20
+ };
21
+ }
22
+ /**
23
+ * File-based storage backend for Claude usage tracking
24
+ */
25
+ export class FileStorage {
26
+ basePath;
27
+ sessionsDir;
28
+ requestsDir;
29
+ constructor(storagePath) {
30
+ this.basePath = storagePath ?? path.join(os.homedir(), '.opencode', 'claude-usage');
31
+ this.sessionsDir = path.join(this.basePath, 'sessions');
32
+ this.requestsDir = path.join(this.basePath, 'requests');
33
+ this.ensureDirectories();
34
+ }
35
+ ensureDirectories() {
36
+ fs.mkdirSync(this.sessionsDir, { recursive: true });
37
+ fs.mkdirSync(this.requestsDir, { recursive: true });
38
+ }
39
+ sessionFilePath(sessionId) {
40
+ return path.join(this.sessionsDir, `${sessionId}.json`);
41
+ }
42
+ requestFilePath(sessionId) {
43
+ return path.join(this.requestsDir, `${sessionId}.jsonl`);
44
+ }
45
+ async saveSession(session) {
46
+ const serializable = {
47
+ ...session,
48
+ toolCalls: Object.fromEntries(session.toolCalls),
49
+ models: Object.fromEntries(session.models),
50
+ };
51
+ fs.writeFileSync(this.sessionFilePath(session.sessionId), JSON.stringify(serializable, null, 2));
52
+ }
53
+ async saveApiRequest(sessionId, request) {
54
+ const line = JSON.stringify(request) + '\n';
55
+ fs.appendFileSync(this.requestFilePath(sessionId), line);
56
+ }
57
+ async getSession(sessionId) {
58
+ const filePath = this.sessionFilePath(sessionId);
59
+ if (!fs.existsSync(filePath)) {
60
+ return null;
61
+ }
62
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
63
+ return {
64
+ ...data,
65
+ toolCalls: new Map(Object.entries(data.toolCalls || {})),
66
+ models: new Map(Object.entries(data.models || {})),
67
+ };
68
+ }
69
+ async getAllSessions(limit = 100) {
70
+ if (!fs.existsSync(this.sessionsDir)) {
71
+ return [];
72
+ }
73
+ const files = fs.readdirSync(this.sessionsDir)
74
+ .filter(f => f.endsWith('.json'))
75
+ .sort((a, b) => {
76
+ const statA = fs.statSync(path.join(this.sessionsDir, a));
77
+ const statB = fs.statSync(path.join(this.sessionsDir, b));
78
+ return statB.mtime.getTime() - statA.mtime.getTime();
79
+ })
80
+ .slice(0, limit);
81
+ const sessions = [];
82
+ for (const file of files) {
83
+ const sessionId = file.replace('.json', '');
84
+ const session = await this.getSession(sessionId);
85
+ if (session) {
86
+ sessions.push(session);
87
+ }
88
+ }
89
+ return sessions;
90
+ }
91
+ async getUsageStats(startDate, endDate) {
92
+ const sessions = await this.getAllSessions(1000);
93
+ const stats = {
94
+ totalSessions: 0,
95
+ totalApiRequests: 0,
96
+ totalTokens: emptyTokenUsage(),
97
+ totalCostUsd: 0,
98
+ byModel: new Map(),
99
+ byDay: new Map(),
100
+ topTools: [],
101
+ };
102
+ const toolMap = new Map();
103
+ for (const session of sessions) {
104
+ // Filter by date if provided
105
+ if (startDate && session.startTime < startDate)
106
+ continue;
107
+ if (endDate && session.endTime && session.endTime > endDate)
108
+ continue;
109
+ stats.totalSessions++;
110
+ stats.totalApiRequests += session.apiRequests;
111
+ stats.totalTokens = addTokenUsage(stats.totalTokens, session.tokens);
112
+ stats.totalCostUsd += session.totalCostUsd;
113
+ // Aggregate by model
114
+ for (const [model, modelData] of session.models) {
115
+ const existing = stats.byModel.get(model) ?? {
116
+ requests: 0,
117
+ tokens: emptyTokenUsage(),
118
+ costUsd: 0,
119
+ };
120
+ existing.requests += modelData.requests;
121
+ existing.tokens = addTokenUsage(existing.tokens, modelData.tokens);
122
+ existing.costUsd += modelData.costUsd;
123
+ stats.byModel.set(model, existing);
124
+ }
125
+ // Aggregate by day
126
+ const day = session.startTime.split('T')[0];
127
+ const dayData = stats.byDay.get(day) ?? {
128
+ requests: 0,
129
+ tokens: emptyTokenUsage(),
130
+ costUsd: 0,
131
+ };
132
+ dayData.requests += session.apiRequests;
133
+ dayData.tokens = addTokenUsage(dayData.tokens, session.tokens);
134
+ dayData.costUsd += session.totalCostUsd;
135
+ stats.byDay.set(day, dayData);
136
+ // Aggregate tools
137
+ for (const [toolName, toolData] of session.toolCalls) {
138
+ const existing = toolMap.get(toolName) ?? {
139
+ name: toolName,
140
+ invocations: 0,
141
+ successCount: 0,
142
+ failureCount: 0,
143
+ totalDurationMs: 0,
144
+ avgDurationMs: 0,
145
+ };
146
+ existing.invocations += toolData.invocations;
147
+ existing.successCount += toolData.successCount;
148
+ existing.failureCount += toolData.failureCount;
149
+ existing.totalDurationMs += toolData.totalDurationMs;
150
+ toolMap.set(toolName, existing);
151
+ }
152
+ }
153
+ // Calculate averages and sort tools
154
+ stats.topTools = Array.from(toolMap.values())
155
+ .map(t => ({
156
+ ...t,
157
+ avgDurationMs: t.invocations > 0 ? t.totalDurationMs / t.invocations : 0,
158
+ }))
159
+ .sort((a, b) => b.invocations - a.invocations)
160
+ .slice(0, 10);
161
+ return stats;
162
+ }
163
+ }
164
+ /**
165
+ * In-memory storage backend (useful for testing or ephemeral tracking)
166
+ */
167
+ export class MemoryStorage {
168
+ sessions = new Map();
169
+ requests = new Map();
170
+ async saveSession(session) {
171
+ this.sessions.set(session.sessionId, session);
172
+ }
173
+ async saveApiRequest(sessionId, request) {
174
+ const existing = this.requests.get(sessionId) ?? [];
175
+ existing.push(request);
176
+ this.requests.set(sessionId, existing);
177
+ }
178
+ async getSession(sessionId) {
179
+ return this.sessions.get(sessionId) ?? null;
180
+ }
181
+ async getAllSessions(limit = 100) {
182
+ return Array.from(this.sessions.values()).slice(0, limit);
183
+ }
184
+ async getUsageStats() {
185
+ // Simplified implementation - same logic as FileStorage
186
+ return {
187
+ totalSessions: this.sessions.size,
188
+ totalApiRequests: 0,
189
+ totalTokens: emptyTokenUsage(),
190
+ totalCostUsd: 0,
191
+ byModel: new Map(),
192
+ byDay: new Map(),
193
+ topTools: [],
194
+ };
195
+ }
196
+ }
197
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Token usage breakdown by type
3
+ */
4
+ export interface TokenUsage {
5
+ input: number;
6
+ output: number;
7
+ cacheRead: number;
8
+ cacheCreation: number;
9
+ total: number;
10
+ }
11
+ /**
12
+ * API request metrics
13
+ */
14
+ export interface ApiRequestMetrics {
15
+ timestamp: string;
16
+ model: string;
17
+ durationMs: number;
18
+ tokens: TokenUsage;
19
+ costUsd: number;
20
+ success: boolean;
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Tool usage metrics
25
+ */
26
+ export interface ToolMetrics {
27
+ name: string;
28
+ invocations: number;
29
+ successCount: number;
30
+ failureCount: number;
31
+ totalDurationMs: number;
32
+ avgDurationMs: number;
33
+ }
34
+ /**
35
+ * Session-level usage summary
36
+ */
37
+ export interface SessionUsage {
38
+ sessionId: string;
39
+ startTime: string;
40
+ endTime?: string;
41
+ tokens: TokenUsage;
42
+ totalCostUsd: number;
43
+ apiRequests: number;
44
+ toolCalls: Map<string, ToolMetrics>;
45
+ models: Map<string, {
46
+ requests: number;
47
+ tokens: TokenUsage;
48
+ costUsd: number;
49
+ }>;
50
+ }
51
+ /**
52
+ * Aggregated usage statistics
53
+ */
54
+ export interface UsageStats {
55
+ totalSessions: number;
56
+ totalApiRequests: number;
57
+ totalTokens: TokenUsage;
58
+ totalCostUsd: number;
59
+ byModel: Map<string, {
60
+ requests: number;
61
+ tokens: TokenUsage;
62
+ costUsd: number;
63
+ }>;
64
+ byDay: Map<string, {
65
+ requests: number;
66
+ tokens: TokenUsage;
67
+ costUsd: number;
68
+ }>;
69
+ topTools: ToolMetrics[];
70
+ }
71
+ /**
72
+ * Storage backend interface
73
+ */
74
+ export interface StorageBackend {
75
+ saveSession(session: SessionUsage): Promise<void>;
76
+ saveApiRequest(sessionId: string, request: ApiRequestMetrics): Promise<void>;
77
+ getSession(sessionId: string): Promise<SessionUsage | null>;
78
+ getAllSessions(limit?: number): Promise<SessionUsage[]>;
79
+ getUsageStats(startDate?: string, endDate?: string): Promise<UsageStats>;
80
+ }
81
+ /**
82
+ * Plugin configuration options
83
+ */
84
+ export interface ClaudeTrackerConfig {
85
+ /** Storage backend type: 'file' | 'sqlite' | 'custom' */
86
+ storage: 'file' | 'sqlite' | 'custom';
87
+ /** Path for file/sqlite storage (default: ~/.opencode/claude-usage) */
88
+ storagePath?: string;
89
+ /** Custom storage backend implementation */
90
+ customStorage?: StorageBackend;
91
+ /** Enable detailed logging */
92
+ verbose?: boolean;
93
+ /** Flush interval in ms (default: 30000) */
94
+ flushIntervalMs?: number;
95
+ /** Include model names in tracking */
96
+ trackModels?: boolean;
97
+ /** Include tool usage in tracking */
98
+ trackTools?: boolean;
99
+ }
100
+ /**
101
+ * Span attribute names used by Claude/OpenCode
102
+ */
103
+ export declare const SpanAttributes: {
104
+ readonly MODEL: "model";
105
+ readonly COST_USD: "cost_usd";
106
+ readonly DURATION_MS: "duration_ms";
107
+ readonly INPUT_TOKENS: "input_tokens";
108
+ readonly OUTPUT_TOKENS: "output_tokens";
109
+ readonly CACHE_READ_TOKENS: "cache_read_tokens";
110
+ readonly CACHE_CREATION_TOKENS: "cache_creation_tokens";
111
+ readonly TOOL_NAME: "tool_name";
112
+ readonly SUCCESS: "success";
113
+ readonly ERROR: "error";
114
+ readonly SESSION_ID: "session.id";
115
+ readonly EVENT_NAME: "event.name";
116
+ };
117
+ /**
118
+ * Event names emitted by Claude Code
119
+ */
120
+ export declare const EventNames: {
121
+ readonly API_REQUEST: "claude_code.api_request";
122
+ readonly API_ERROR: "claude_code.api_error";
123
+ readonly TOOL_RESULT: "claude_code.tool_result";
124
+ readonly TOOL_DECISION: "claude_code.tool_decision";
125
+ readonly USER_PROMPT: "claude_code.user_prompt";
126
+ };
127
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Span attribute names used by Claude/OpenCode
3
+ */
4
+ export const SpanAttributes = {
5
+ MODEL: 'model',
6
+ COST_USD: 'cost_usd',
7
+ DURATION_MS: 'duration_ms',
8
+ INPUT_TOKENS: 'input_tokens',
9
+ OUTPUT_TOKENS: 'output_tokens',
10
+ CACHE_READ_TOKENS: 'cache_read_tokens',
11
+ CACHE_CREATION_TOKENS: 'cache_creation_tokens',
12
+ TOOL_NAME: 'tool_name',
13
+ SUCCESS: 'success',
14
+ ERROR: 'error',
15
+ SESSION_ID: 'session.id',
16
+ EVENT_NAME: 'event.name',
17
+ };
18
+ /**
19
+ * Event names emitted by Claude Code
20
+ */
21
+ export const EventNames = {
22
+ API_REQUEST: 'claude_code.api_request',
23
+ API_ERROR: 'claude_code.api_error',
24
+ TOOL_RESULT: 'claude_code.tool_result',
25
+ TOOL_DECISION: 'claude_code.tool_decision',
26
+ USER_PROMPT: 'claude_code.user_prompt',
27
+ };
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8FA;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,iBAAiB,EAAE,mBAAmB;IACtC,qBAAqB,EAAE,uBAAuB;IAC9C,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;CAChB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,WAAW,EAAE,yBAAyB;IACtC,SAAS,EAAE,uBAAuB;IAClC,WAAW,EAAE,yBAAyB;IACtC,aAAa,EAAE,2BAA2B;IAC1C,WAAW,EAAE,yBAAyB;CAC9B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@semboja/opencode-claude",
3
+ "version": "0.1.0",
4
+ "description": "Claude usage tracking plugin for OpenCode - monitor tokens, costs, sessions, and API performance",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "claude-tracker": "dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "clean": "rm -rf dist",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "opencode",
30
+ "plugin",
31
+ "claude",
32
+ "anthropic",
33
+ "llm",
34
+ "monitoring",
35
+ "usage",
36
+ "tokens",
37
+ "cost",
38
+ "observability",
39
+ "opentelemetry"
40
+ ],
41
+ "author": "",
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@opencode-ai/plugin": "^1.1.14",
45
+ "@opentelemetry/api": "^1.9.0",
46
+ "@opentelemetry/sdk-node": "^0.203.0",
47
+ "@opentelemetry/sdk-trace-base": "^2.0.1"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.0.0",
51
+ "typescript": "^5.9.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "url": ""
59
+ }
60
+ }