@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,244 @@
1
+ import { SpanAttributes, EventNames } from './types.js';
2
+ /**
3
+ * Creates an empty token usage object
4
+ */
5
+ function emptyTokenUsage() {
6
+ return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, total: 0 };
7
+ }
8
+ /**
9
+ * Custom span processor for tracking Claude API usage
10
+ */
11
+ export class ClaudeUsageProcessor {
12
+ storage;
13
+ log;
14
+ verbose;
15
+ trackModels;
16
+ trackTools;
17
+ currentSession = null;
18
+ flushInterval = null;
19
+ pendingRequests = [];
20
+ prometheusMetrics = null;
21
+ constructor(storage, log, options = {}) {
22
+ this.storage = storage;
23
+ this.log = log;
24
+ this.verbose = options.verbose ?? false;
25
+ this.trackModels = options.trackModels ?? true;
26
+ this.trackTools = options.trackTools ?? true;
27
+ this.prometheusMetrics = options.prometheusMetrics ?? null;
28
+ // Set up periodic flush
29
+ const flushMs = options.flushIntervalMs ?? 30000;
30
+ this.flushInterval = setInterval(() => {
31
+ this.flush().catch(err => {
32
+ this.log('error', `Flush error: ${err}`);
33
+ });
34
+ }, flushMs);
35
+ }
36
+ onStart(_span, _parentContext) {
37
+ // We primarily care about completed spans
38
+ }
39
+ onEnd(span) {
40
+ const attrs = span.attributes;
41
+ const eventName = attrs[SpanAttributes.EVENT_NAME];
42
+ const sessionId = attrs[SpanAttributes.SESSION_ID];
43
+ // Initialize session if needed
44
+ if (sessionId && !this.currentSession) {
45
+ this.initSession(sessionId);
46
+ }
47
+ if (!this.currentSession) {
48
+ return;
49
+ }
50
+ // Process based on event type
51
+ if (eventName === EventNames.API_REQUEST || span.name.includes('api_request')) {
52
+ this.processApiRequest(span);
53
+ }
54
+ else if (eventName === EventNames.API_ERROR || span.name.includes('api_error')) {
55
+ this.processApiError(span);
56
+ }
57
+ else if (eventName === EventNames.TOOL_RESULT || span.name.includes('tool_result')) {
58
+ this.processToolResult(span);
59
+ }
60
+ // Also check for LLM-related spans by name
61
+ if (span.name.includes('llm') || span.name.includes('claude') || span.name.includes('anthropic')) {
62
+ this.processLlmSpan(span);
63
+ }
64
+ }
65
+ initSession(sessionId) {
66
+ this.currentSession = {
67
+ sessionId,
68
+ startTime: new Date().toISOString(),
69
+ tokens: emptyTokenUsage(),
70
+ totalCostUsd: 0,
71
+ apiRequests: 0,
72
+ toolCalls: new Map(),
73
+ models: new Map(),
74
+ };
75
+ // Record Prometheus metric
76
+ this.prometheusMetrics?.recordSession();
77
+ if (this.verbose) {
78
+ this.log('info', `Session started: ${sessionId}`);
79
+ }
80
+ }
81
+ processApiRequest(span) {
82
+ if (!this.currentSession)
83
+ return;
84
+ const attrs = span.attributes;
85
+ const inputTokens = Number(attrs[SpanAttributes.INPUT_TOKENS] ?? attrs['gen_ai.usage.input_tokens'] ?? 0);
86
+ const outputTokens = Number(attrs[SpanAttributes.OUTPUT_TOKENS] ?? attrs['gen_ai.usage.output_tokens'] ?? 0);
87
+ const cacheReadTokens = Number(attrs[SpanAttributes.CACHE_READ_TOKENS] ?? attrs['gen_ai.usage.cache_read_tokens'] ?? 0);
88
+ const cacheCreationTokens = Number(attrs[SpanAttributes.CACHE_CREATION_TOKENS] ?? attrs['gen_ai.usage.cache_creation_tokens'] ?? 0);
89
+ const tokens = {
90
+ input: inputTokens,
91
+ output: outputTokens,
92
+ cacheRead: cacheReadTokens,
93
+ cacheCreation: cacheCreationTokens,
94
+ total: inputTokens + outputTokens + cacheReadTokens + cacheCreationTokens,
95
+ };
96
+ const model = String(attrs[SpanAttributes.MODEL] ?? attrs['gen_ai.request.model'] ?? attrs['gen_ai.response.model'] ?? 'unknown');
97
+ const costUsd = Number(attrs[SpanAttributes.COST_USD] ?? 0);
98
+ const durationMs = Number(attrs[SpanAttributes.DURATION_MS] ?? span.duration[0] * 1000 + span.duration[1] / 1e6);
99
+ const request = {
100
+ timestamp: new Date().toISOString(),
101
+ model,
102
+ durationMs,
103
+ tokens,
104
+ costUsd,
105
+ success: true,
106
+ };
107
+ // Update session totals
108
+ this.currentSession.apiRequests++;
109
+ this.currentSession.tokens.input += tokens.input;
110
+ this.currentSession.tokens.output += tokens.output;
111
+ this.currentSession.tokens.cacheRead += tokens.cacheRead;
112
+ this.currentSession.tokens.cacheCreation += tokens.cacheCreation;
113
+ this.currentSession.tokens.total += tokens.total;
114
+ this.currentSession.totalCostUsd += costUsd;
115
+ // Track by model
116
+ if (this.trackModels) {
117
+ const modelStats = this.currentSession.models.get(model) ?? {
118
+ requests: 0,
119
+ tokens: emptyTokenUsage(),
120
+ costUsd: 0,
121
+ };
122
+ modelStats.requests++;
123
+ modelStats.tokens.input += tokens.input;
124
+ modelStats.tokens.output += tokens.output;
125
+ modelStats.tokens.cacheRead += tokens.cacheRead;
126
+ modelStats.tokens.cacheCreation += tokens.cacheCreation;
127
+ modelStats.tokens.total += tokens.total;
128
+ modelStats.costUsd += costUsd;
129
+ this.currentSession.models.set(model, modelStats);
130
+ }
131
+ this.pendingRequests.push(request);
132
+ // Record Prometheus metrics
133
+ if (this.prometheusMetrics) {
134
+ this.prometheusMetrics.recordTokens(tokens, model);
135
+ this.prometheusMetrics.recordCost(costUsd, model);
136
+ this.prometheusMetrics.recordApiRequest(model, durationMs, true);
137
+ this.prometheusMetrics.updateSessionGauges(this.currentSession.tokens, this.currentSession.totalCostUsd);
138
+ }
139
+ if (this.verbose) {
140
+ this.log('info', `API request: ${model} | ${tokens.total} tokens | $${costUsd.toFixed(4)}`);
141
+ }
142
+ }
143
+ processApiError(span) {
144
+ if (!this.currentSession)
145
+ return;
146
+ const attrs = span.attributes;
147
+ const model = String(attrs[SpanAttributes.MODEL] ?? 'unknown');
148
+ const error = String(attrs[SpanAttributes.ERROR] ?? attrs['error'] ?? 'Unknown error');
149
+ const durationMs = Number(attrs[SpanAttributes.DURATION_MS] ?? 0);
150
+ const request = {
151
+ timestamp: new Date().toISOString(),
152
+ model,
153
+ durationMs,
154
+ tokens: emptyTokenUsage(),
155
+ costUsd: 0,
156
+ success: false,
157
+ error,
158
+ };
159
+ this.currentSession.apiRequests++;
160
+ this.pendingRequests.push(request);
161
+ // Record Prometheus metrics
162
+ this.prometheusMetrics?.recordApiRequest(model, durationMs, false);
163
+ this.log('warn', `API error: ${model} | ${error}`);
164
+ }
165
+ processToolResult(span) {
166
+ if (!this.currentSession || !this.trackTools)
167
+ return;
168
+ const attrs = span.attributes;
169
+ const toolName = String(attrs[SpanAttributes.TOOL_NAME] ?? attrs['tool_name'] ?? 'unknown');
170
+ const success = attrs[SpanAttributes.SUCCESS] === 'true' || attrs[SpanAttributes.SUCCESS] === true;
171
+ const durationMs = Number(attrs[SpanAttributes.DURATION_MS] ?? 0);
172
+ const toolStats = this.currentSession.toolCalls.get(toolName) ?? {
173
+ name: toolName,
174
+ invocations: 0,
175
+ successCount: 0,
176
+ failureCount: 0,
177
+ totalDurationMs: 0,
178
+ avgDurationMs: 0,
179
+ };
180
+ toolStats.invocations++;
181
+ if (success) {
182
+ toolStats.successCount++;
183
+ }
184
+ else {
185
+ toolStats.failureCount++;
186
+ }
187
+ toolStats.totalDurationMs += durationMs;
188
+ toolStats.avgDurationMs = toolStats.totalDurationMs / toolStats.invocations;
189
+ this.currentSession.toolCalls.set(toolName, toolStats);
190
+ // Record Prometheus metrics
191
+ this.prometheusMetrics?.recordToolInvocation(toolName, durationMs, success);
192
+ if (this.verbose) {
193
+ this.log('info', `Tool: ${toolName} | ${success ? 'success' : 'failed'} | ${durationMs}ms`);
194
+ }
195
+ }
196
+ processLlmSpan(span) {
197
+ // Generic LLM span processing for compatibility with various OpenTelemetry instrumentations
198
+ const attrs = span.attributes;
199
+ // Check for semantic conventions attributes
200
+ const inputTokens = Number(attrs['gen_ai.usage.input_tokens'] ?? attrs['llm.usage.prompt_tokens'] ?? 0);
201
+ const outputTokens = Number(attrs['gen_ai.usage.output_tokens'] ?? attrs['llm.usage.completion_tokens'] ?? 0);
202
+ if (inputTokens > 0 || outputTokens > 0) {
203
+ // This looks like an LLM call, process it if we haven't already
204
+ const alreadyProcessed = this.pendingRequests.some(r => r.timestamp === new Date().toISOString());
205
+ if (!alreadyProcessed) {
206
+ this.processApiRequest(span);
207
+ }
208
+ }
209
+ }
210
+ async forceFlush() {
211
+ await this.flush();
212
+ }
213
+ async flush() {
214
+ if (!this.currentSession)
215
+ return;
216
+ try {
217
+ // Save all pending requests
218
+ for (const request of this.pendingRequests) {
219
+ await this.storage.saveApiRequest(this.currentSession.sessionId, request);
220
+ }
221
+ this.pendingRequests = [];
222
+ // Update session
223
+ this.currentSession.endTime = new Date().toISOString();
224
+ await this.storage.saveSession(this.currentSession);
225
+ if (this.verbose) {
226
+ this.log('info', `Flushed session: ${this.currentSession.sessionId}`);
227
+ }
228
+ }
229
+ catch (err) {
230
+ this.log('error', `Failed to flush: ${err}`);
231
+ }
232
+ }
233
+ async shutdown() {
234
+ if (this.flushInterval) {
235
+ clearInterval(this.flushInterval);
236
+ this.flushInterval = null;
237
+ }
238
+ await this.flush();
239
+ if (this.currentSession) {
240
+ this.log('info', `Session ended: ${this.currentSession.sessionId} | Total: ${this.currentSession.tokens.total} tokens | $${this.currentSession.totalCostUsd.toFixed(4)}`);
241
+ }
242
+ }
243
+ }
244
+ //# sourceMappingURL=processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.js","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import type { TokenUsage } from './types.js';
2
+ /**
3
+ * Prometheus metric types
4
+ */
5
+ type MetricType = 'counter' | 'gauge' | 'histogram';
6
+ interface MetricDefinition {
7
+ name: string;
8
+ help: string;
9
+ type: MetricType;
10
+ labelNames: string[];
11
+ }
12
+ /**
13
+ * Simple Prometheus metrics registry
14
+ */
15
+ export declare class PrometheusRegistry {
16
+ private metrics;
17
+ private histogramBuckets;
18
+ register(definition: MetricDefinition): void;
19
+ inc(name: string, labels: Record<string, string>, value?: number): void;
20
+ set(name: string, labels: Record<string, string>, value: number): void;
21
+ observe(name: string, labels: Record<string, string>, value: number): void;
22
+ private labelsMatch;
23
+ private formatLabels;
24
+ serialize(): string;
25
+ }
26
+ /**
27
+ * Claude usage metrics for Prometheus
28
+ */
29
+ export declare class ClaudeMetrics {
30
+ private registry;
31
+ constructor(registry: PrometheusRegistry);
32
+ private registerMetrics;
33
+ recordSession(): void;
34
+ recordTokens(tokens: TokenUsage, model: string): void;
35
+ recordCost(costUsd: number, model: string): void;
36
+ recordApiRequest(model: string, durationMs: number, success: boolean): void;
37
+ recordToolInvocation(tool: string, durationMs: number, success: boolean): void;
38
+ updateSessionGauges(tokens: TokenUsage, costUsd: number): void;
39
+ getMetrics(): string;
40
+ }
41
+ /**
42
+ * HTTP server for Prometheus scraping
43
+ */
44
+ export declare class PrometheusServer {
45
+ private server;
46
+ private registry;
47
+ private port;
48
+ constructor(registry: PrometheusRegistry, port?: number);
49
+ start(): Promise<void>;
50
+ stop(): Promise<void>;
51
+ getPort(): number;
52
+ }
53
+ /**
54
+ * Pushgateway client for pushing metrics
55
+ */
56
+ export declare class PushgatewayClient {
57
+ private baseUrl;
58
+ private job;
59
+ private registry;
60
+ constructor(registry: PrometheusRegistry, baseUrl: string, job?: string);
61
+ push(groupingLabels?: Record<string, string>): Promise<void>;
62
+ delete(groupingLabels?: Record<string, string>): Promise<void>;
63
+ }
64
+ export {};
65
+ //# sourceMappingURL=prometheus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prometheus.d.ts","sourceRoot":"","sources":["../src/prometheus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;AAEpD,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAOD;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAA8E;IAC7F,OAAO,CAAC,gBAAgB,CAA6D;IAErF,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAI5C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,SAAI,GAAG,IAAI;IAYlE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAYtE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAoB1E,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IAKpB,SAAS,IAAI,MAAM;CA4CpB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,QAAQ,EAAE,kBAAkB;IAKxC,OAAO,CAAC,eAAe;IAuFvB,aAAa,IAAI,IAAI;IAIrB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAOrD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAK3E,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAK9E,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ9D,UAAU,IAAI,MAAM;CAGrB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,IAAI,CAAS;gBAET,QAAQ,EAAE,kBAAkB,EAAE,IAAI,SAAO;IAKrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrB,OAAO,IAAI,MAAM;CAGlB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAmB;IAM3E,IAAI,CAAC,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBhE,MAAM,CAAC,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAazE"}
@@ -0,0 +1,304 @@
1
+ import * as http from 'node:http';
2
+ /**
3
+ * Simple Prometheus metrics registry
4
+ */
5
+ export class PrometheusRegistry {
6
+ metrics = new Map();
7
+ histogramBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
8
+ register(definition) {
9
+ this.metrics.set(definition.name, { definition, values: [] });
10
+ }
11
+ inc(name, labels, value = 1) {
12
+ const metric = this.metrics.get(name);
13
+ if (!metric)
14
+ return;
15
+ const existing = metric.values.find(v => this.labelsMatch(v.labels, labels));
16
+ if (existing) {
17
+ existing.value += value;
18
+ }
19
+ else {
20
+ metric.values.push({ labels, value });
21
+ }
22
+ }
23
+ set(name, labels, value) {
24
+ const metric = this.metrics.get(name);
25
+ if (!metric)
26
+ return;
27
+ const existing = metric.values.find(v => this.labelsMatch(v.labels, labels));
28
+ if (existing) {
29
+ existing.value = value;
30
+ }
31
+ else {
32
+ metric.values.push({ labels, value });
33
+ }
34
+ }
35
+ observe(name, labels, value) {
36
+ // For histograms, we track sum, count, and bucket counts
37
+ const sumName = `${name}_sum`;
38
+ const countName = `${name}_count`;
39
+ this.inc(sumName, labels, value);
40
+ this.inc(countName, labels, 1);
41
+ // Update bucket counts
42
+ for (const bucket of this.histogramBuckets) {
43
+ const bucketName = `${name}_bucket`;
44
+ const bucketLabels = { ...labels, le: bucket.toString() };
45
+ if (value <= bucket) {
46
+ this.inc(bucketName, bucketLabels, 1);
47
+ }
48
+ }
49
+ // +Inf bucket
50
+ this.inc(`${name}_bucket`, { ...labels, le: '+Inf' }, 1);
51
+ }
52
+ labelsMatch(a, b) {
53
+ const keysA = Object.keys(a);
54
+ const keysB = Object.keys(b);
55
+ if (keysA.length !== keysB.length)
56
+ return false;
57
+ return keysA.every(key => a[key] === b[key]);
58
+ }
59
+ formatLabels(labels) {
60
+ const parts = Object.entries(labels).map(([k, v]) => `${k}="${v}"`);
61
+ return parts.length > 0 ? `{${parts.join(',')}}` : '';
62
+ }
63
+ serialize() {
64
+ const lines = [];
65
+ for (const [name, { definition, values }] of this.metrics) {
66
+ // Skip internal histogram metrics in the main loop
67
+ if (name.endsWith('_sum') || name.endsWith('_count') || name.endsWith('_bucket')) {
68
+ continue;
69
+ }
70
+ lines.push(`# HELP ${name} ${definition.help}`);
71
+ lines.push(`# TYPE ${name} ${definition.type}`);
72
+ if (definition.type === 'histogram') {
73
+ // Output histogram format
74
+ const sumMetric = this.metrics.get(`${name}_sum`);
75
+ const countMetric = this.metrics.get(`${name}_count`);
76
+ const bucketMetric = this.metrics.get(`${name}_bucket`);
77
+ if (bucketMetric) {
78
+ for (const v of bucketMetric.values) {
79
+ lines.push(`${name}_bucket${this.formatLabels(v.labels)} ${v.value}`);
80
+ }
81
+ }
82
+ if (sumMetric) {
83
+ for (const v of sumMetric.values) {
84
+ lines.push(`${name}_sum${this.formatLabels(v.labels)} ${v.value}`);
85
+ }
86
+ }
87
+ if (countMetric) {
88
+ for (const v of countMetric.values) {
89
+ lines.push(`${name}_count${this.formatLabels(v.labels)} ${v.value}`);
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ for (const v of values) {
95
+ lines.push(`${name}${this.formatLabels(v.labels)} ${v.value}`);
96
+ }
97
+ }
98
+ lines.push('');
99
+ }
100
+ return lines.join('\n');
101
+ }
102
+ }
103
+ /**
104
+ * Claude usage metrics for Prometheus
105
+ */
106
+ export class ClaudeMetrics {
107
+ registry;
108
+ constructor(registry) {
109
+ this.registry = registry;
110
+ this.registerMetrics();
111
+ }
112
+ registerMetrics() {
113
+ // Counters
114
+ this.registry.register({
115
+ name: 'claude_tokens_total',
116
+ help: 'Total number of tokens used',
117
+ type: 'counter',
118
+ labelNames: ['type', 'model'],
119
+ });
120
+ this.registry.register({
121
+ name: 'claude_cost_usd_total',
122
+ help: 'Total cost in USD',
123
+ type: 'counter',
124
+ labelNames: ['model'],
125
+ });
126
+ this.registry.register({
127
+ name: 'claude_api_requests_total',
128
+ help: 'Total number of API requests',
129
+ type: 'counter',
130
+ labelNames: ['model', 'status'],
131
+ });
132
+ this.registry.register({
133
+ name: 'claude_sessions_total',
134
+ help: 'Total number of sessions',
135
+ type: 'counter',
136
+ labelNames: [],
137
+ });
138
+ this.registry.register({
139
+ name: 'claude_tool_invocations_total',
140
+ help: 'Total number of tool invocations',
141
+ type: 'counter',
142
+ labelNames: ['tool', 'status'],
143
+ });
144
+ // Histograms
145
+ this.registry.register({
146
+ name: 'claude_api_request_duration_seconds',
147
+ help: 'API request duration in seconds',
148
+ type: 'histogram',
149
+ labelNames: ['model'],
150
+ });
151
+ // Register internal histogram metrics
152
+ for (const suffix of ['_sum', '_count', '_bucket']) {
153
+ this.registry.register({
154
+ name: `claude_api_request_duration_seconds${suffix}`,
155
+ help: '',
156
+ type: 'counter',
157
+ labelNames: ['model', 'le'],
158
+ });
159
+ }
160
+ this.registry.register({
161
+ name: 'claude_tool_duration_seconds',
162
+ help: 'Tool execution duration in seconds',
163
+ type: 'histogram',
164
+ labelNames: ['tool'],
165
+ });
166
+ for (const suffix of ['_sum', '_count', '_bucket']) {
167
+ this.registry.register({
168
+ name: `claude_tool_duration_seconds${suffix}`,
169
+ help: '',
170
+ type: 'counter',
171
+ labelNames: ['tool', 'le'],
172
+ });
173
+ }
174
+ // Gauges
175
+ this.registry.register({
176
+ name: 'claude_session_tokens',
177
+ help: 'Tokens used in current session',
178
+ type: 'gauge',
179
+ labelNames: ['type'],
180
+ });
181
+ this.registry.register({
182
+ name: 'claude_session_cost_usd',
183
+ help: 'Cost in current session',
184
+ type: 'gauge',
185
+ labelNames: [],
186
+ });
187
+ }
188
+ recordSession() {
189
+ this.registry.inc('claude_sessions_total', {});
190
+ }
191
+ recordTokens(tokens, model) {
192
+ this.registry.inc('claude_tokens_total', { type: 'input', model }, tokens.input);
193
+ this.registry.inc('claude_tokens_total', { type: 'output', model }, tokens.output);
194
+ this.registry.inc('claude_tokens_total', { type: 'cache_read', model }, tokens.cacheRead);
195
+ this.registry.inc('claude_tokens_total', { type: 'cache_creation', model }, tokens.cacheCreation);
196
+ }
197
+ recordCost(costUsd, model) {
198
+ this.registry.inc('claude_cost_usd_total', { model }, costUsd);
199
+ }
200
+ recordApiRequest(model, durationMs, success) {
201
+ this.registry.inc('claude_api_requests_total', { model, status: success ? 'success' : 'error' });
202
+ this.registry.observe('claude_api_request_duration_seconds', { model }, durationMs / 1000);
203
+ }
204
+ recordToolInvocation(tool, durationMs, success) {
205
+ this.registry.inc('claude_tool_invocations_total', { tool, status: success ? 'success' : 'error' });
206
+ this.registry.observe('claude_tool_duration_seconds', { tool }, durationMs / 1000);
207
+ }
208
+ updateSessionGauges(tokens, costUsd) {
209
+ this.registry.set('claude_session_tokens', { type: 'input' }, tokens.input);
210
+ this.registry.set('claude_session_tokens', { type: 'output' }, tokens.output);
211
+ this.registry.set('claude_session_tokens', { type: 'cache_read' }, tokens.cacheRead);
212
+ this.registry.set('claude_session_tokens', { type: 'cache_creation' }, tokens.cacheCreation);
213
+ this.registry.set('claude_session_cost_usd', {}, costUsd);
214
+ }
215
+ getMetrics() {
216
+ return this.registry.serialize();
217
+ }
218
+ }
219
+ /**
220
+ * HTTP server for Prometheus scraping
221
+ */
222
+ export class PrometheusServer {
223
+ server = null;
224
+ registry;
225
+ port;
226
+ constructor(registry, port = 9090) {
227
+ this.registry = registry;
228
+ this.port = port;
229
+ }
230
+ start() {
231
+ return new Promise((resolve, reject) => {
232
+ this.server = http.createServer((req, res) => {
233
+ if (req.url === '/metrics') {
234
+ res.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4' });
235
+ res.end(this.registry.serialize());
236
+ }
237
+ else if (req.url === '/health') {
238
+ res.writeHead(200, { 'Content-Type': 'application/json' });
239
+ res.end(JSON.stringify({ status: 'ok' }));
240
+ }
241
+ else {
242
+ res.writeHead(404);
243
+ res.end('Not Found');
244
+ }
245
+ });
246
+ this.server.on('error', reject);
247
+ this.server.listen(this.port, () => {
248
+ resolve();
249
+ });
250
+ });
251
+ }
252
+ stop() {
253
+ return new Promise((resolve) => {
254
+ if (this.server) {
255
+ this.server.close(() => resolve());
256
+ }
257
+ else {
258
+ resolve();
259
+ }
260
+ });
261
+ }
262
+ getPort() {
263
+ return this.port;
264
+ }
265
+ }
266
+ /**
267
+ * Pushgateway client for pushing metrics
268
+ */
269
+ export class PushgatewayClient {
270
+ baseUrl;
271
+ job;
272
+ registry;
273
+ constructor(registry, baseUrl, job = 'claude_tracker') {
274
+ this.registry = registry;
275
+ this.baseUrl = baseUrl.replace(/\/$/, '');
276
+ this.job = job;
277
+ }
278
+ async push(groupingLabels = {}) {
279
+ const labelPath = Object.entries(groupingLabels)
280
+ .map(([k, v]) => `/${k}/${encodeURIComponent(v)}`)
281
+ .join('');
282
+ const url = `${this.baseUrl}/metrics/job/${this.job}${labelPath}`;
283
+ const body = this.registry.serialize();
284
+ const response = await fetch(url, {
285
+ method: 'POST',
286
+ headers: { 'Content-Type': 'text/plain' },
287
+ body,
288
+ });
289
+ if (!response.ok) {
290
+ throw new Error(`Pushgateway error: ${response.status} ${response.statusText}`);
291
+ }
292
+ }
293
+ async delete(groupingLabels = {}) {
294
+ const labelPath = Object.entries(groupingLabels)
295
+ .map(([k, v]) => `/${k}/${encodeURIComponent(v)}`)
296
+ .join('');
297
+ const url = `${this.baseUrl}/metrics/job/${this.job}${labelPath}`;
298
+ const response = await fetch(url, { method: 'DELETE' });
299
+ if (!response.ok) {
300
+ throw new Error(`Pushgateway error: ${response.status} ${response.statusText}`);
301
+ }
302
+ }
303
+ }
304
+ //# sourceMappingURL=prometheus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prometheus.js","sourceRoot":"","sources":["../src/prometheus.ts"],"names":[],"mappings":"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"}