zozul-cli 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.
- package/.env.example +44 -0
- package/.github/workflows/publish.yml +26 -0
- package/DEVELOPMENT.md +288 -0
- package/LICENSE +201 -0
- package/README.md +178 -0
- package/dist/cli/commands.d.ts +3 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +307 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/format.d.ts +5 -0
- package/dist/cli/format.d.ts.map +1 -0
- package/dist/cli/format.js +115 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +37 -0
- package/dist/context/index.js.map +1 -0
- package/dist/dashboard/html.d.ts +17 -0
- package/dist/dashboard/html.d.ts.map +1 -0
- package/dist/dashboard/html.js +79 -0
- package/dist/dashboard/html.js.map +1 -0
- package/dist/dashboard/index.html +1245 -0
- package/dist/hooks/config.d.ts +19 -0
- package/dist/hooks/config.d.ts.map +1 -0
- package/dist/hooks/config.js +106 -0
- package/dist/hooks/config.js.map +1 -0
- package/dist/hooks/git.d.ts +6 -0
- package/dist/hooks/git.d.ts.map +1 -0
- package/dist/hooks/git.js +73 -0
- package/dist/hooks/git.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/server.d.ts +16 -0
- package/dist/hooks/server.d.ts.map +1 -0
- package/dist/hooks/server.js +349 -0
- package/dist/hooks/server.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/otel/config.d.ts +36 -0
- package/dist/otel/config.d.ts.map +1 -0
- package/dist/otel/config.js +109 -0
- package/dist/otel/config.js.map +1 -0
- package/dist/otel/index.d.ts +4 -0
- package/dist/otel/index.d.ts.map +1 -0
- package/dist/otel/index.js +3 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/otel/receiver.d.ts +10 -0
- package/dist/otel/receiver.d.ts.map +1 -0
- package/dist/otel/receiver.js +155 -0
- package/dist/otel/receiver.js.map +1 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/ingest.d.ts +20 -0
- package/dist/parser/ingest.d.ts.map +1 -0
- package/dist/parser/ingest.js +98 -0
- package/dist/parser/ingest.js.map +1 -0
- package/dist/parser/jsonl.d.ts +14 -0
- package/dist/parser/jsonl.d.ts.map +1 -0
- package/dist/parser/jsonl.js +202 -0
- package/dist/parser/jsonl.js.map +1 -0
- package/dist/parser/types.d.ts +81 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +9 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/parser/watcher.d.ts +16 -0
- package/dist/parser/watcher.d.ts.map +1 -0
- package/dist/parser/watcher.js +103 -0
- package/dist/parser/watcher.js.map +1 -0
- package/dist/pricing/index.d.ts +2 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/service/index.d.ts +31 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +252 -0
- package/dist/service/index.js.map +1 -0
- package/dist/storage/db.d.ts +75 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/db.js +117 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/repo.d.ts +162 -0
- package/dist/storage/repo.d.ts.map +1 -0
- package/dist/storage/repo.js +472 -0
- package/dist/storage/repo.js.map +1 -0
- package/dist/sync/client.d.ts +24 -0
- package/dist/sync/client.d.ts.map +1 -0
- package/dist/sync/client.js +41 -0
- package/dist/sync/client.js.map +1 -0
- package/dist/sync/index.d.ts +18 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +135 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/sync.test.d.ts +2 -0
- package/dist/sync/sync.test.d.ts.map +1 -0
- package/dist/sync/sync.test.js +412 -0
- package/dist/sync/sync.test.js.map +1 -0
- package/dist/sync/transform.d.ts +80 -0
- package/dist/sync/transform.d.ts.map +1 -0
- package/dist/sync/transform.js +90 -0
- package/dist/sync/transform.js.map +1 -0
- package/package.json +50 -0
- package/src/cli/commands.ts +332 -0
- package/src/cli/format.ts +133 -0
- package/src/context/index.ts +42 -0
- package/src/dashboard/html.ts +97 -0
- package/src/dashboard/index.html +1245 -0
- package/src/hooks/config.ts +119 -0
- package/src/hooks/git.ts +77 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/server.ts +397 -0
- package/src/index.ts +6 -0
- package/src/otel/config.ts +141 -0
- package/src/otel/index.ts +8 -0
- package/src/otel/receiver.ts +183 -0
- package/src/parser/index.ts +3 -0
- package/src/parser/ingest.ts +119 -0
- package/src/parser/jsonl.ts +241 -0
- package/src/parser/types.ts +89 -0
- package/src/parser/watcher.ts +116 -0
- package/src/pricing/index.ts +51 -0
- package/src/service/index.ts +272 -0
- package/src/storage/db.ts +198 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/repo.ts +601 -0
- package/src/sync/client.ts +63 -0
- package/src/sync/index.ts +207 -0
- package/src/sync/sync.test.ts +447 -0
- package/src/sync/transform.ts +184 -0
- package/tsconfig.json +19 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;AAC3B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface OtelConfig {
|
|
2
|
+
/** OTLP endpoint, e.g. http://localhost:4317 */
|
|
3
|
+
endpoint: string;
|
|
4
|
+
/** Protocol: grpc, http/json, or http/protobuf */
|
|
5
|
+
protocol: "grpc" | "http/json" | "http/protobuf";
|
|
6
|
+
/** Whether to log user prompt content */
|
|
7
|
+
logUserPrompts: boolean;
|
|
8
|
+
/** Whether to log MCP/tool detail names */
|
|
9
|
+
logToolDetails: boolean;
|
|
10
|
+
/** Metrics export interval in ms */
|
|
11
|
+
metricsInterval: number;
|
|
12
|
+
/** Logs export interval in ms */
|
|
13
|
+
logsInterval: number;
|
|
14
|
+
/** Optional auth header */
|
|
15
|
+
authHeader?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate the set of environment variables needed to enable
|
|
19
|
+
* Claude Code's built-in OpenTelemetry export.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateOtelEnvVars(config?: Partial<OtelConfig>): Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Generate a shell script that exports all required OTEL env vars.
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateOtelShellExports(config?: Partial<OtelConfig>): string;
|
|
26
|
+
/**
|
|
27
|
+
* Write the OTEL env vars into Claude Code's settings.json under the "env" key.
|
|
28
|
+
*/
|
|
29
|
+
export declare function installOtelToSettings(config?: Partial<OtelConfig>): {
|
|
30
|
+
path: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Remove zozul OTEL env vars from Claude Code's settings.json.
|
|
34
|
+
*/
|
|
35
|
+
export declare function uninstallOtelFromSettings(): boolean;
|
|
36
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/otel/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,CAAC;IACjD,yCAAyC;IACzC,cAAc,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;IACxB,oCAAoC;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwB5F;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG,MAAM,CAMjF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAoBxF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAyCnD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
endpoint: "http://localhost:7890",
|
|
6
|
+
protocol: "http/json",
|
|
7
|
+
logUserPrompts: true,
|
|
8
|
+
logToolDetails: true,
|
|
9
|
+
metricsInterval: 60000,
|
|
10
|
+
logsInterval: 5000,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Generate the set of environment variables needed to enable
|
|
14
|
+
* Claude Code's built-in OpenTelemetry export.
|
|
15
|
+
*/
|
|
16
|
+
export function generateOtelEnvVars(config = {}) {
|
|
17
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
18
|
+
const env = {
|
|
19
|
+
CLAUDE_CODE_ENABLE_TELEMETRY: "1",
|
|
20
|
+
OTEL_METRICS_EXPORTER: "otlp",
|
|
21
|
+
OTEL_LOGS_EXPORTER: "otlp",
|
|
22
|
+
OTEL_EXPORTER_OTLP_PROTOCOL: cfg.protocol,
|
|
23
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: cfg.endpoint,
|
|
24
|
+
OTEL_METRIC_EXPORT_INTERVAL: String(cfg.metricsInterval),
|
|
25
|
+
OTEL_LOGS_EXPORT_INTERVAL: String(cfg.logsInterval),
|
|
26
|
+
};
|
|
27
|
+
if (cfg.logUserPrompts) {
|
|
28
|
+
env.OTEL_LOG_USER_PROMPTS = "1";
|
|
29
|
+
}
|
|
30
|
+
if (cfg.logToolDetails) {
|
|
31
|
+
env.OTEL_LOG_TOOL_DETAILS = "1";
|
|
32
|
+
}
|
|
33
|
+
if (cfg.authHeader) {
|
|
34
|
+
env.OTEL_EXPORTER_OTLP_HEADERS = cfg.authHeader;
|
|
35
|
+
}
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generate a shell script that exports all required OTEL env vars.
|
|
40
|
+
*/
|
|
41
|
+
export function generateOtelShellExports(config = {}) {
|
|
42
|
+
const env = generateOtelEnvVars(config);
|
|
43
|
+
const lines = Object.entries(env).map(([key, value]) => `export ${key}="${value}"`);
|
|
44
|
+
return lines.join("\n") + "\n";
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Write the OTEL env vars into Claude Code's settings.json under the "env" key.
|
|
48
|
+
*/
|
|
49
|
+
export function installOtelToSettings(config = {}) {
|
|
50
|
+
const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
51
|
+
let existing = {};
|
|
52
|
+
if (fs.existsSync(settingsPath)) {
|
|
53
|
+
try {
|
|
54
|
+
existing = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
existing = {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const envVars = generateOtelEnvVars(config);
|
|
61
|
+
const existingEnv = (existing.env ?? {});
|
|
62
|
+
existing.env = { ...existingEnv, ...envVars };
|
|
63
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
64
|
+
fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
|
|
65
|
+
return { path: settingsPath };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove zozul OTEL env vars from Claude Code's settings.json.
|
|
69
|
+
*/
|
|
70
|
+
export function uninstallOtelFromSettings() {
|
|
71
|
+
const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
72
|
+
if (!fs.existsSync(settingsPath))
|
|
73
|
+
return false;
|
|
74
|
+
let existing;
|
|
75
|
+
try {
|
|
76
|
+
existing = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const env = existing.env;
|
|
82
|
+
if (!env)
|
|
83
|
+
return false;
|
|
84
|
+
const otelKeys = [
|
|
85
|
+
"CLAUDE_CODE_ENABLE_TELEMETRY",
|
|
86
|
+
"OTEL_METRICS_EXPORTER",
|
|
87
|
+
"OTEL_LOGS_EXPORTER",
|
|
88
|
+
"OTEL_EXPORTER_OTLP_PROTOCOL",
|
|
89
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
90
|
+
"OTEL_METRIC_EXPORT_INTERVAL",
|
|
91
|
+
"OTEL_LOGS_EXPORT_INTERVAL",
|
|
92
|
+
"OTEL_LOG_USER_PROMPTS",
|
|
93
|
+
"OTEL_LOG_TOOL_DETAILS",
|
|
94
|
+
"OTEL_EXPORTER_OTLP_HEADERS",
|
|
95
|
+
];
|
|
96
|
+
let removed = false;
|
|
97
|
+
for (const key of otelKeys) {
|
|
98
|
+
if (key in env) {
|
|
99
|
+
delete env[key];
|
|
100
|
+
removed = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (Object.keys(env).length === 0) {
|
|
104
|
+
delete existing.env;
|
|
105
|
+
}
|
|
106
|
+
fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
|
|
107
|
+
return removed;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/otel/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { generateOtelEnvVars, generateOtelShellExports, installOtelToSettings, uninstallOtelFromSettings, } from "./config.js";
|
|
2
|
+
export type { OtelConfig } from "./config.js";
|
|
3
|
+
export { handleOtlpMetrics, handleOtlpLogs } from "./receiver.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/otel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/otel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SessionRepo } from "../storage/repo.js";
|
|
2
|
+
export declare function handleOtlpMetrics(body: string, repo: SessionRepo, verbose?: boolean): number;
|
|
3
|
+
/**
|
|
4
|
+
* Parse OTLP JSON logs/events export and store in SQLite.
|
|
5
|
+
*
|
|
6
|
+
* Claude Code sends events in the standard OTLP JSON logs format:
|
|
7
|
+
* { resourceLogs: [{ scopeLogs: [{ logRecords: [...] }] }] }
|
|
8
|
+
*/
|
|
9
|
+
export declare function handleOtlpLogs(body: string, repo: SessionRepo, verbose?: boolean): number;
|
|
10
|
+
//# sourceMappingURL=receiver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/otel/receiver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqBtD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAyE5F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAqCzF"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
export function handleOtlpMetrics(body, repo, verbose) {
|
|
2
|
+
const payload = JSON.parse(body);
|
|
3
|
+
const resourceMetrics = payload.resourceMetrics ?? [];
|
|
4
|
+
const batch = [];
|
|
5
|
+
const sessionDeltas = new Map();
|
|
6
|
+
for (const rm of resourceMetrics) {
|
|
7
|
+
const resourceAttrs = flattenAttributes(rm.resource?.attributes);
|
|
8
|
+
for (const sm of rm.scopeMetrics ?? []) {
|
|
9
|
+
for (const metric of sm.metrics ?? []) {
|
|
10
|
+
const metricName = metric.name ?? "unknown";
|
|
11
|
+
const dataPoints = extractDataPoints(metric);
|
|
12
|
+
for (const dp of dataPoints) {
|
|
13
|
+
const attrs = flattenAttributes(dp.attributes);
|
|
14
|
+
const merged = { ...resourceAttrs, ...attrs };
|
|
15
|
+
const rawValue = dp.asDouble ?? dp.asInt ?? dp.value ?? 0;
|
|
16
|
+
const value = typeof rawValue === "string" ? parseFloat(rawValue) : Number(rawValue);
|
|
17
|
+
const ts = nanoToIso(dp.timeUnixNano ?? dp.startTimeUnixNano);
|
|
18
|
+
batch.push({
|
|
19
|
+
name: metricName,
|
|
20
|
+
value,
|
|
21
|
+
attributes: JSON.stringify(merged),
|
|
22
|
+
session_id: merged["session.id"] ?? null,
|
|
23
|
+
model: merged["model"] ?? null,
|
|
24
|
+
timestamp: ts,
|
|
25
|
+
});
|
|
26
|
+
// Accumulate per-session deltas to keep sessions table current
|
|
27
|
+
const sid = merged["session.id"];
|
|
28
|
+
if (sid) {
|
|
29
|
+
if (!sessionDeltas.has(sid)) {
|
|
30
|
+
sessionDeltas.set(sid, {
|
|
31
|
+
costDelta: 0, inputDelta: 0, outputDelta: 0,
|
|
32
|
+
cacheReadDelta: 0, cacheCreationDelta: 0, durationMsDelta: 0,
|
|
33
|
+
latestTimestamp: ts, model: merged["model"] ?? null,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const d = sessionDeltas.get(sid);
|
|
37
|
+
if (ts > d.latestTimestamp)
|
|
38
|
+
d.latestTimestamp = ts;
|
|
39
|
+
if (merged["model"])
|
|
40
|
+
d.model = merged["model"];
|
|
41
|
+
if (metricName === "claude_code.cost.usage") {
|
|
42
|
+
d.costDelta += value;
|
|
43
|
+
}
|
|
44
|
+
else if (metricName === "claude_code.token.usage") {
|
|
45
|
+
const type = merged["type"];
|
|
46
|
+
if (type === "input")
|
|
47
|
+
d.inputDelta += value;
|
|
48
|
+
else if (type === "output")
|
|
49
|
+
d.outputDelta += value;
|
|
50
|
+
else if (type === "cacheRead")
|
|
51
|
+
d.cacheReadDelta += value;
|
|
52
|
+
else if (type === "cacheCreation")
|
|
53
|
+
d.cacheCreationDelta += value;
|
|
54
|
+
}
|
|
55
|
+
else if (metricName === "claude_code.active_time.total") {
|
|
56
|
+
d.durationMsDelta += value * 1000; // seconds → ms
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (batch.length > 0) {
|
|
64
|
+
repo.insertOtelMetricBatch(batch);
|
|
65
|
+
for (const [sessionId, deltas] of sessionDeltas) {
|
|
66
|
+
repo.updateSessionFromOtel(sessionId, deltas);
|
|
67
|
+
}
|
|
68
|
+
if (verbose) {
|
|
69
|
+
process.stderr.write(` otel: stored ${batch.length} metric data points across ${sessionDeltas.size} session(s)\n`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return batch.length;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse OTLP JSON logs/events export and store in SQLite.
|
|
76
|
+
*
|
|
77
|
+
* Claude Code sends events in the standard OTLP JSON logs format:
|
|
78
|
+
* { resourceLogs: [{ scopeLogs: [{ logRecords: [...] }] }] }
|
|
79
|
+
*/
|
|
80
|
+
export function handleOtlpLogs(body, repo, verbose) {
|
|
81
|
+
const payload = JSON.parse(body);
|
|
82
|
+
const resourceLogs = payload.resourceLogs ?? [];
|
|
83
|
+
const batch = [];
|
|
84
|
+
for (const rl of resourceLogs) {
|
|
85
|
+
const resourceAttrs = flattenAttributes(rl.resource?.attributes);
|
|
86
|
+
for (const sl of rl.scopeLogs ?? []) {
|
|
87
|
+
for (const record of sl.logRecords ?? []) {
|
|
88
|
+
const attrs = flattenAttributes(record.attributes);
|
|
89
|
+
const merged = { ...resourceAttrs, ...attrs };
|
|
90
|
+
const eventName = merged["event.name"]
|
|
91
|
+
?? record.body?.stringValue
|
|
92
|
+
?? "unknown";
|
|
93
|
+
const ts = nanoToIso(record.timeUnixNano ?? record.observedTimeUnixNano);
|
|
94
|
+
batch.push({
|
|
95
|
+
event_name: eventName,
|
|
96
|
+
attributes: JSON.stringify(merged),
|
|
97
|
+
session_id: merged["session.id"] ?? null,
|
|
98
|
+
prompt_id: merged["prompt.id"] ?? null,
|
|
99
|
+
timestamp: ts,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (batch.length > 0) {
|
|
105
|
+
repo.insertOtelEventBatch(batch);
|
|
106
|
+
if (verbose) {
|
|
107
|
+
process.stderr.write(` otel: stored ${batch.length} log events\n`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return batch.length;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* OTLP metrics contain data inside different structures depending on type.
|
|
114
|
+
* Extract the data points array from whichever wrapper is present.
|
|
115
|
+
*/
|
|
116
|
+
function extractDataPoints(metric) {
|
|
117
|
+
if (metric.sum)
|
|
118
|
+
return metric.sum.dataPoints ?? [];
|
|
119
|
+
if (metric.gauge)
|
|
120
|
+
return metric.gauge.dataPoints ?? [];
|
|
121
|
+
if (metric.histogram)
|
|
122
|
+
return metric.histogram.dataPoints ?? [];
|
|
123
|
+
if (metric.summary)
|
|
124
|
+
return metric.summary.dataPoints ?? [];
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* OTLP attributes are arrays of { key, value: { stringValue|intValue|... } }.
|
|
129
|
+
* Flatten them into a plain { key: value } object.
|
|
130
|
+
*/
|
|
131
|
+
function flattenAttributes(attrs) {
|
|
132
|
+
const result = {};
|
|
133
|
+
if (!Array.isArray(attrs))
|
|
134
|
+
return result;
|
|
135
|
+
for (const attr of attrs) {
|
|
136
|
+
const a = attr;
|
|
137
|
+
if (!a.key || !a.value)
|
|
138
|
+
continue;
|
|
139
|
+
const v = a.value.stringValue
|
|
140
|
+
?? a.value.intValue
|
|
141
|
+
?? a.value.doubleValue
|
|
142
|
+
?? a.value.boolValue;
|
|
143
|
+
if (v !== undefined && v !== null) {
|
|
144
|
+
result[a.key] = String(v);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
function nanoToIso(nanos) {
|
|
150
|
+
if (!nanos)
|
|
151
|
+
return new Date().toISOString();
|
|
152
|
+
const ms = typeof nanos === "string" ? parseInt(nanos, 10) / 1_000_000 : nanos / 1_000_000;
|
|
153
|
+
return new Date(ms).toISOString();
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=receiver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiver.js","sourceRoot":"","sources":["../../src/otel/receiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SessionRepo } from "../storage/repo.js";
|
|
2
|
+
import type { ParsedSession } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ingest all discovered session JSONL files into the database.
|
|
5
|
+
* Skips sessions that already exist unless force=true.
|
|
6
|
+
*/
|
|
7
|
+
export declare function ingestAllSessions(repo: SessionRepo, opts?: {
|
|
8
|
+
force?: boolean;
|
|
9
|
+
noTag?: boolean;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
ingested: number;
|
|
12
|
+
skipped: number;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Ingest a single session file by path.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ingestSessionFile(repo: SessionRepo, filePath: string, projectPath?: string, opts?: {
|
|
18
|
+
noTag?: boolean;
|
|
19
|
+
}): Promise<ParsedSession>;
|
|
20
|
+
//# sourceMappingURL=ingest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/parser/ingest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9C,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBhD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,aAAa,CAAC,CAIxB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { discoverSessionFiles, parseSessionFile } from "./jsonl.js";
|
|
2
|
+
import { getActiveContext } from "../context/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ingest all discovered session JSONL files into the database.
|
|
5
|
+
* Skips sessions that already exist unless force=true.
|
|
6
|
+
*/
|
|
7
|
+
export async function ingestAllSessions(repo, opts = {}) {
|
|
8
|
+
const files = discoverSessionFiles();
|
|
9
|
+
let ingested = 0;
|
|
10
|
+
let skipped = 0;
|
|
11
|
+
for (const { filePath, projectPath } of files) {
|
|
12
|
+
const parsed = await parseSessionFile(filePath, projectPath);
|
|
13
|
+
if (!opts.force) {
|
|
14
|
+
const existing = repo.getSession(parsed.sessionId);
|
|
15
|
+
if (existing) {
|
|
16
|
+
skipped++;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
persistSession(repo, parsed, { noTag: opts.noTag });
|
|
21
|
+
ingested++;
|
|
22
|
+
}
|
|
23
|
+
return { ingested, skipped };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Ingest a single session file by path.
|
|
27
|
+
*/
|
|
28
|
+
export async function ingestSessionFile(repo, filePath, projectPath, opts = {}) {
|
|
29
|
+
const parsed = await parseSessionFile(filePath, projectPath);
|
|
30
|
+
persistSession(repo, parsed, opts);
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
function persistSession(repo, parsed, opts = {}) {
|
|
34
|
+
repo.upsertSession({
|
|
35
|
+
id: parsed.sessionId,
|
|
36
|
+
project_path: parsed.projectPath,
|
|
37
|
+
started_at: parsed.startedAt,
|
|
38
|
+
ended_at: parsed.endedAt,
|
|
39
|
+
total_input_tokens: parsed.totalInputTokens,
|
|
40
|
+
total_output_tokens: parsed.totalOutputTokens,
|
|
41
|
+
total_cache_read_tokens: parsed.totalCacheReadTokens,
|
|
42
|
+
total_cache_creation_tokens: parsed.totalCacheCreationTokens,
|
|
43
|
+
total_cost_usd: parsed.totalCostUsd,
|
|
44
|
+
total_turns: parsed.turns.length,
|
|
45
|
+
total_duration_ms: parsed.totalDurationMs,
|
|
46
|
+
model: parsed.model,
|
|
47
|
+
});
|
|
48
|
+
const turnIds = [];
|
|
49
|
+
for (const turn of parsed.turns) {
|
|
50
|
+
const turnId = repo.insertTurn({
|
|
51
|
+
session_id: parsed.sessionId,
|
|
52
|
+
turn_index: turn.turnIndex,
|
|
53
|
+
role: turn.role,
|
|
54
|
+
timestamp: turn.timestamp,
|
|
55
|
+
input_tokens: turn.inputTokens,
|
|
56
|
+
output_tokens: turn.outputTokens,
|
|
57
|
+
cache_read_tokens: turn.cacheReadTokens,
|
|
58
|
+
cache_creation_tokens: turn.cacheCreationTokens,
|
|
59
|
+
cost_usd: turn.costUsd,
|
|
60
|
+
duration_ms: turn.durationMs,
|
|
61
|
+
model: turn.model,
|
|
62
|
+
content_text: turn.contentText,
|
|
63
|
+
tool_calls: turn.toolCalls.length > 0 ? JSON.stringify(turn.toolCalls) : null,
|
|
64
|
+
is_real_user: turn.isRealUser ? 1 : 0,
|
|
65
|
+
});
|
|
66
|
+
turnIds.push(turnId);
|
|
67
|
+
if (turn.toolCalls.length > 0) {
|
|
68
|
+
// Replace tool uses for this turn atomically to avoid duplicates on re-ingest
|
|
69
|
+
repo.replaceToolUsesForTurn(turnId, turn.toolCalls.map(tc => ({
|
|
70
|
+
session_id: parsed.sessionId,
|
|
71
|
+
turn_id: turnId,
|
|
72
|
+
tool_name: tc.toolName,
|
|
73
|
+
tool_input: JSON.stringify(tc.toolInput),
|
|
74
|
+
tool_result: tc.toolResult ?? null,
|
|
75
|
+
success: null,
|
|
76
|
+
duration_ms: 0,
|
|
77
|
+
timestamp: turn.timestamp,
|
|
78
|
+
})));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!opts.noTag) {
|
|
82
|
+
const context = getActiveContext();
|
|
83
|
+
if (context?.active && context.active.length > 0 && turnIds.length > 0) {
|
|
84
|
+
// Only tag turns that occurred after the context was set
|
|
85
|
+
const contextTime = context.set_at ? new Date(context.set_at).getTime() : 0;
|
|
86
|
+
const eligibleIds = turnIds.filter((_, i) => {
|
|
87
|
+
const turnTime = new Date(parsed.turns[i].timestamp).getTime();
|
|
88
|
+
return turnTime >= contextTime;
|
|
89
|
+
});
|
|
90
|
+
if (eligibleIds.length > 0) {
|
|
91
|
+
for (const tag of context.active) {
|
|
92
|
+
repo.tagTurnsBatch(eligibleIds, tag);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/parser/ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParsedSession } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discover all session JSONL files across all projects.
|
|
4
|
+
* Files are stored directly in each project directory (not in a sessions/ subdir).
|
|
5
|
+
*/
|
|
6
|
+
export declare function discoverSessionFiles(): {
|
|
7
|
+
filePath: string;
|
|
8
|
+
projectPath: string;
|
|
9
|
+
}[];
|
|
10
|
+
/**
|
|
11
|
+
* Parse a single session JSONL file into a structured ParsedSession.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseSessionFile(filePath: string, projectPath?: string): Promise<ParsedSession>;
|
|
14
|
+
//# sourceMappingURL=jsonl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/parser/jsonl.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,aAAa,EAId,MAAM,YAAY,CAAC;AAWpB;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAAE,CA0BlF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAuHxB"}
|