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.
Files changed (139) hide show
  1. package/.env.example +44 -0
  2. package/.github/workflows/publish.yml +26 -0
  3. package/DEVELOPMENT.md +288 -0
  4. package/LICENSE +201 -0
  5. package/README.md +178 -0
  6. package/dist/cli/commands.d.ts +3 -0
  7. package/dist/cli/commands.d.ts.map +1 -0
  8. package/dist/cli/commands.js +307 -0
  9. package/dist/cli/commands.js.map +1 -0
  10. package/dist/cli/format.d.ts +5 -0
  11. package/dist/cli/format.d.ts.map +1 -0
  12. package/dist/cli/format.js +115 -0
  13. package/dist/cli/format.js.map +1 -0
  14. package/dist/context/index.d.ts +8 -0
  15. package/dist/context/index.d.ts.map +1 -0
  16. package/dist/context/index.js +37 -0
  17. package/dist/context/index.js.map +1 -0
  18. package/dist/dashboard/html.d.ts +17 -0
  19. package/dist/dashboard/html.d.ts.map +1 -0
  20. package/dist/dashboard/html.js +79 -0
  21. package/dist/dashboard/html.js.map +1 -0
  22. package/dist/dashboard/index.html +1245 -0
  23. package/dist/hooks/config.d.ts +19 -0
  24. package/dist/hooks/config.d.ts.map +1 -0
  25. package/dist/hooks/config.js +106 -0
  26. package/dist/hooks/config.js.map +1 -0
  27. package/dist/hooks/git.d.ts +6 -0
  28. package/dist/hooks/git.d.ts.map +1 -0
  29. package/dist/hooks/git.js +73 -0
  30. package/dist/hooks/git.js.map +1 -0
  31. package/dist/hooks/index.d.ts +4 -0
  32. package/dist/hooks/index.d.ts.map +1 -0
  33. package/dist/hooks/index.js +3 -0
  34. package/dist/hooks/index.js.map +1 -0
  35. package/dist/hooks/server.d.ts +16 -0
  36. package/dist/hooks/server.d.ts.map +1 -0
  37. package/dist/hooks/server.js +349 -0
  38. package/dist/hooks/server.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +6 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/otel/config.d.ts +36 -0
  44. package/dist/otel/config.d.ts.map +1 -0
  45. package/dist/otel/config.js +109 -0
  46. package/dist/otel/config.js.map +1 -0
  47. package/dist/otel/index.d.ts +4 -0
  48. package/dist/otel/index.d.ts.map +1 -0
  49. package/dist/otel/index.js +3 -0
  50. package/dist/otel/index.js.map +1 -0
  51. package/dist/otel/receiver.d.ts +10 -0
  52. package/dist/otel/receiver.d.ts.map +1 -0
  53. package/dist/otel/receiver.js +155 -0
  54. package/dist/otel/receiver.js.map +1 -0
  55. package/dist/parser/index.d.ts +4 -0
  56. package/dist/parser/index.d.ts.map +1 -0
  57. package/dist/parser/index.js +3 -0
  58. package/dist/parser/index.js.map +1 -0
  59. package/dist/parser/ingest.d.ts +20 -0
  60. package/dist/parser/ingest.d.ts.map +1 -0
  61. package/dist/parser/ingest.js +98 -0
  62. package/dist/parser/ingest.js.map +1 -0
  63. package/dist/parser/jsonl.d.ts +14 -0
  64. package/dist/parser/jsonl.d.ts.map +1 -0
  65. package/dist/parser/jsonl.js +202 -0
  66. package/dist/parser/jsonl.js.map +1 -0
  67. package/dist/parser/types.d.ts +81 -0
  68. package/dist/parser/types.d.ts.map +1 -0
  69. package/dist/parser/types.js +9 -0
  70. package/dist/parser/types.js.map +1 -0
  71. package/dist/parser/watcher.d.ts +16 -0
  72. package/dist/parser/watcher.d.ts.map +1 -0
  73. package/dist/parser/watcher.js +103 -0
  74. package/dist/parser/watcher.js.map +1 -0
  75. package/dist/pricing/index.d.ts +2 -0
  76. package/dist/pricing/index.d.ts.map +1 -0
  77. package/dist/pricing/index.js +37 -0
  78. package/dist/pricing/index.js.map +1 -0
  79. package/dist/service/index.d.ts +31 -0
  80. package/dist/service/index.d.ts.map +1 -0
  81. package/dist/service/index.js +252 -0
  82. package/dist/service/index.js.map +1 -0
  83. package/dist/storage/db.d.ts +75 -0
  84. package/dist/storage/db.d.ts.map +1 -0
  85. package/dist/storage/db.js +117 -0
  86. package/dist/storage/db.js.map +1 -0
  87. package/dist/storage/index.d.ts +4 -0
  88. package/dist/storage/index.d.ts.map +1 -0
  89. package/dist/storage/index.js +3 -0
  90. package/dist/storage/index.js.map +1 -0
  91. package/dist/storage/repo.d.ts +162 -0
  92. package/dist/storage/repo.d.ts.map +1 -0
  93. package/dist/storage/repo.js +472 -0
  94. package/dist/storage/repo.js.map +1 -0
  95. package/dist/sync/client.d.ts +24 -0
  96. package/dist/sync/client.d.ts.map +1 -0
  97. package/dist/sync/client.js +41 -0
  98. package/dist/sync/client.js.map +1 -0
  99. package/dist/sync/index.d.ts +18 -0
  100. package/dist/sync/index.d.ts.map +1 -0
  101. package/dist/sync/index.js +135 -0
  102. package/dist/sync/index.js.map +1 -0
  103. package/dist/sync/sync.test.d.ts +2 -0
  104. package/dist/sync/sync.test.d.ts.map +1 -0
  105. package/dist/sync/sync.test.js +412 -0
  106. package/dist/sync/sync.test.js.map +1 -0
  107. package/dist/sync/transform.d.ts +80 -0
  108. package/dist/sync/transform.d.ts.map +1 -0
  109. package/dist/sync/transform.js +90 -0
  110. package/dist/sync/transform.js.map +1 -0
  111. package/package.json +50 -0
  112. package/src/cli/commands.ts +332 -0
  113. package/src/cli/format.ts +133 -0
  114. package/src/context/index.ts +42 -0
  115. package/src/dashboard/html.ts +97 -0
  116. package/src/dashboard/index.html +1245 -0
  117. package/src/hooks/config.ts +119 -0
  118. package/src/hooks/git.ts +77 -0
  119. package/src/hooks/index.ts +7 -0
  120. package/src/hooks/server.ts +397 -0
  121. package/src/index.ts +6 -0
  122. package/src/otel/config.ts +141 -0
  123. package/src/otel/index.ts +8 -0
  124. package/src/otel/receiver.ts +183 -0
  125. package/src/parser/index.ts +3 -0
  126. package/src/parser/ingest.ts +119 -0
  127. package/src/parser/jsonl.ts +241 -0
  128. package/src/parser/types.ts +89 -0
  129. package/src/parser/watcher.ts +116 -0
  130. package/src/pricing/index.ts +51 -0
  131. package/src/service/index.ts +272 -0
  132. package/src/storage/db.ts +198 -0
  133. package/src/storage/index.ts +3 -0
  134. package/src/storage/repo.ts +601 -0
  135. package/src/sync/client.ts +63 -0
  136. package/src/sync/index.ts +207 -0
  137. package/src/sync/sync.test.ts +447 -0
  138. package/src/sync/transform.ts +184 -0
  139. package/tsconfig.json +19 -0
@@ -0,0 +1,252 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { execSync } from "node:child_process";
5
+ const LABEL = "com.zozul.serve";
6
+ const PLIST_PATH = path.join(os.homedir(), "Library", "LaunchAgents", `${LABEL}.plist`);
7
+ const SYSTEMD_DIR = path.join(os.homedir(), ".config", "systemd", "user");
8
+ const SYSTEMD_PATH = path.join(SYSTEMD_DIR, "zozul.service");
9
+ const LOG_PATH = path.join(os.homedir(), ".zozul", "zozul.log");
10
+ /**
11
+ * Install and immediately start zozul as a background service.
12
+ * Uses launchd on macOS, systemd --user on Linux.
13
+ */
14
+ export function installService(opts) {
15
+ const platform = detectPlatform();
16
+ if (platform === "unsupported") {
17
+ throw new Error(`Service install is not supported on ${process.platform}. Run 'zozul serve' manually.`);
18
+ }
19
+ // Build env vars to bake into the service so it doesn't depend on .env
20
+ const env = {
21
+ ZOZUL_PORT: String(opts.port),
22
+ };
23
+ if (opts.dbPath)
24
+ env.ZOZUL_DB_PATH = opts.dbPath;
25
+ if (process.env.ZOZUL_API_URL)
26
+ env.ZOZUL_API_URL = process.env.ZOZUL_API_URL;
27
+ if (process.env.ZOZUL_API_KEY)
28
+ env.ZOZUL_API_KEY = process.env.ZOZUL_API_KEY;
29
+ if (process.env.ZOZUL_VERBOSE)
30
+ env.ZOZUL_VERBOSE = process.env.ZOZUL_VERBOSE;
31
+ if (platform === "macos") {
32
+ return installLaunchd(env);
33
+ }
34
+ else {
35
+ return installSystemd(env);
36
+ }
37
+ }
38
+ /**
39
+ * Stop and remove the zozul background service.
40
+ */
41
+ export function uninstallService() {
42
+ const platform = detectPlatform();
43
+ if (platform === "macos") {
44
+ let removed = false;
45
+ if (fs.existsSync(PLIST_PATH)) {
46
+ try {
47
+ const uid = os.userInfo().uid;
48
+ execSync(`launchctl bootout gui/${uid}/${LABEL}`, { stdio: "ignore" });
49
+ }
50
+ catch {
51
+ // Not loaded — that's fine
52
+ }
53
+ fs.unlinkSync(PLIST_PATH);
54
+ removed = true;
55
+ }
56
+ return { removed, platform };
57
+ }
58
+ if (platform === "linux") {
59
+ let removed = false;
60
+ if (fs.existsSync(SYSTEMD_PATH)) {
61
+ try {
62
+ execSync("systemctl --user disable --now zozul", { stdio: "ignore" });
63
+ }
64
+ catch {
65
+ // Not enabled — that's fine
66
+ }
67
+ fs.unlinkSync(SYSTEMD_PATH);
68
+ try {
69
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
70
+ }
71
+ catch { /* ignore */ }
72
+ removed = true;
73
+ }
74
+ return { removed, platform };
75
+ }
76
+ return { removed: false, platform: "unsupported" };
77
+ }
78
+ /**
79
+ * Restart the running service in-place (kills and relaunches the current process).
80
+ * Throws if the service is not installed.
81
+ */
82
+ export function restartService() {
83
+ const platform = detectPlatform();
84
+ if (platform === "macos") {
85
+ if (!fs.existsSync(PLIST_PATH))
86
+ throw new Error("Service is not installed. Run 'zozul install --service' first.");
87
+ const uid = os.userInfo().uid;
88
+ execSync(`launchctl kickstart -k gui/${uid}/${LABEL}`, { stdio: "ignore" });
89
+ return;
90
+ }
91
+ if (platform === "linux") {
92
+ if (!fs.existsSync(SYSTEMD_PATH))
93
+ throw new Error("Service is not installed. Run 'zozul install --service' first.");
94
+ execSync("systemctl --user restart zozul", { stdio: "ignore" });
95
+ return;
96
+ }
97
+ throw new Error("Service restart is not supported on this platform.");
98
+ }
99
+ /**
100
+ * Returns a human-readable status string for the running service.
101
+ */
102
+ export function serviceStatus() {
103
+ const platform = detectPlatform();
104
+ if (platform === "macos") {
105
+ if (!fs.existsSync(PLIST_PATH))
106
+ return "not installed";
107
+ try {
108
+ const uid = os.userInfo().uid;
109
+ const out = execSync(`launchctl print gui/${uid}/${LABEL} 2>&1`, { encoding: "utf-8" });
110
+ const stateMatch = out.match(/state = (.+)/);
111
+ const state = stateMatch?.[1]?.trim() ?? "unknown";
112
+ const pidMatch = out.match(/pid = (\d+)/);
113
+ if (pidMatch)
114
+ return `running (pid ${pidMatch[1]})`;
115
+ if (state === "running")
116
+ return "running";
117
+ if (state === "spawn scheduled")
118
+ return "installed (starting…)";
119
+ return `installed (${state})`;
120
+ }
121
+ catch {
122
+ return "installed (not running)";
123
+ }
124
+ }
125
+ if (platform === "linux") {
126
+ if (!fs.existsSync(SYSTEMD_PATH))
127
+ return "not installed";
128
+ try {
129
+ execSync("systemctl --user is-active zozul", { stdio: "ignore" });
130
+ return "running";
131
+ }
132
+ catch {
133
+ return "installed (not running)";
134
+ }
135
+ }
136
+ return "unsupported platform";
137
+ }
138
+ // ── macOS launchd ──
139
+ function installLaunchd(env) {
140
+ const nodeBin = process.execPath;
141
+ const scriptPath = path.resolve(process.argv[1]);
142
+ fs.mkdirSync(path.dirname(PLIST_PATH), { recursive: true });
143
+ fs.mkdirSync(path.dirname(LOG_PATH), { recursive: true });
144
+ const envEntries = Object.entries(env)
145
+ .map(([k, v]) => `\t\t<key>${k}</key>\n\t\t<string>${v}</string>`)
146
+ .join("\n");
147
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
148
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
149
+ <plist version="1.0">
150
+ <dict>
151
+ \t<key>Label</key>
152
+ \t<string>${LABEL}</string>
153
+ \t<key>ProgramArguments</key>
154
+ \t<array>
155
+ \t\t<string>${nodeBin}</string>
156
+ \t\t<string>${scriptPath}</string>
157
+ \t\t<string>serve</string>
158
+ \t</array>
159
+ \t<key>EnvironmentVariables</key>
160
+ \t<dict>
161
+ ${envEntries}
162
+ \t</dict>
163
+ \t<key>RunAtLoad</key>
164
+ \t<true/>
165
+ \t<key>KeepAlive</key>
166
+ \t<dict>
167
+ \t\t<key>SuccessfulExit</key>
168
+ \t\t<false/>
169
+ \t</dict>
170
+ \t<key>StandardOutPath</key>
171
+ \t<string>${LOG_PATH}</string>
172
+ \t<key>StandardErrorPath</key>
173
+ \t<string>${LOG_PATH}</string>
174
+ \t<key>WorkingDirectory</key>
175
+ \t<string>${path.dirname(LOG_PATH)}</string>
176
+ </dict>
177
+ </plist>
178
+ `;
179
+ fs.writeFileSync(PLIST_PATH, plist, "utf-8");
180
+ // Unload any previous version first, then bootstrap
181
+ let alreadyRunning = false;
182
+ const uid = os.userInfo().uid;
183
+ try {
184
+ execSync(`launchctl bootout gui/${uid}/${LABEL}`, { stdio: "ignore" });
185
+ }
186
+ catch {
187
+ // Wasn't loaded — fine
188
+ }
189
+ try {
190
+ execSync(`launchctl bootstrap gui/${uid} "${PLIST_PATH}"`, { stdio: "pipe" });
191
+ }
192
+ catch (err) {
193
+ const msg = err instanceof Error ? err.message : String(err);
194
+ if (msg.includes("already")) {
195
+ alreadyRunning = true;
196
+ }
197
+ else {
198
+ throw new Error(`launchctl bootstrap failed: ${msg}`);
199
+ }
200
+ }
201
+ return { platform: "macos", servicePath: PLIST_PATH, alreadyRunning };
202
+ }
203
+ // ── Linux systemd ──
204
+ function installSystemd(env) {
205
+ const nodeBin = process.execPath;
206
+ const scriptPath = path.resolve(process.argv[1]);
207
+ fs.mkdirSync(SYSTEMD_DIR, { recursive: true });
208
+ fs.mkdirSync(path.dirname(LOG_PATH), { recursive: true });
209
+ const envLines = Object.entries(env)
210
+ .map(([k, v]) => `Environment="${k}=${v}"`)
211
+ .join("\n");
212
+ const unit = `[Unit]
213
+ Description=zozul — Agent Observability
214
+ After=network.target
215
+
216
+ [Service]
217
+ ExecStart=${nodeBin} ${scriptPath} serve
218
+ ${envLines}
219
+ WorkingDirectory=${path.dirname(LOG_PATH)}
220
+ Restart=on-failure
221
+ RestartSec=5
222
+ StandardOutput=append:${LOG_PATH}
223
+ StandardError=append:${LOG_PATH}
224
+
225
+ [Install]
226
+ WantedBy=default.target
227
+ `;
228
+ fs.writeFileSync(SYSTEMD_PATH, unit, "utf-8");
229
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
230
+ let alreadyRunning = false;
231
+ try {
232
+ execSync("systemctl --user enable --now zozul", { stdio: "pipe" });
233
+ }
234
+ catch (err) {
235
+ const msg = err instanceof Error ? err.message : String(err);
236
+ if (msg.includes("already")) {
237
+ alreadyRunning = true;
238
+ }
239
+ else {
240
+ throw new Error(`systemctl enable failed: ${msg}`);
241
+ }
242
+ }
243
+ return { platform: "linux", servicePath: SYSTEMD_PATH, alreadyRunning };
244
+ }
245
+ function detectPlatform() {
246
+ if (process.platform === "darwin")
247
+ return "macos";
248
+ if (process.platform === "linux")
249
+ return "linux";
250
+ return "unsupported";
251
+ }
252
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import Database from "better-sqlite3";
2
+ export declare function getDb(dbPath?: string): Database.Database;
3
+ export type SessionRow = {
4
+ id: string;
5
+ project_path: string | null;
6
+ started_at: string;
7
+ ended_at: string | null;
8
+ total_input_tokens: number;
9
+ total_output_tokens: number;
10
+ total_cache_read_tokens: number;
11
+ total_cache_creation_tokens: number;
12
+ total_cost_usd: number;
13
+ total_turns: number;
14
+ total_duration_ms: number;
15
+ model: string | null;
16
+ };
17
+ export type TurnRow = {
18
+ id: number;
19
+ session_id: string;
20
+ turn_index: number;
21
+ role: string;
22
+ timestamp: string;
23
+ input_tokens: number;
24
+ output_tokens: number;
25
+ cache_read_tokens: number;
26
+ cache_creation_tokens: number;
27
+ cost_usd: number;
28
+ duration_ms: number;
29
+ model: string | null;
30
+ content_text: string | null;
31
+ tool_calls: string | null;
32
+ is_real_user: number;
33
+ };
34
+ export type ToolUseRow = {
35
+ id: number;
36
+ session_id: string;
37
+ turn_id: number | null;
38
+ tool_name: string;
39
+ tool_input: string | null;
40
+ tool_result: string | null;
41
+ success: number | null;
42
+ duration_ms: number;
43
+ timestamp: string;
44
+ };
45
+ export type HookEventRow = {
46
+ id: number;
47
+ session_id: string | null;
48
+ event_name: string;
49
+ timestamp: string;
50
+ payload: string;
51
+ };
52
+ export type OtelMetricRow = {
53
+ id: number;
54
+ name: string;
55
+ value: number;
56
+ attributes: string | null;
57
+ session_id: string | null;
58
+ model: string | null;
59
+ timestamp: string;
60
+ };
61
+ export type OtelEventRow = {
62
+ id: number;
63
+ event_name: string;
64
+ attributes: string | null;
65
+ session_id: string | null;
66
+ prompt_id: string | null;
67
+ timestamp: string;
68
+ };
69
+ export type TaskTagRow = {
70
+ id: number;
71
+ turn_id: number;
72
+ task: string;
73
+ tagged_at: string;
74
+ };
75
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/storage/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import Database from "better-sqlite3";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import fs from "node:fs";
5
+ const DEFAULT_DB_DIR = path.join(os.homedir(), ".zozul");
6
+ const DEFAULT_DB_PATH = path.join(DEFAULT_DB_DIR, "zozul.db");
7
+ export function getDb(dbPath = DEFAULT_DB_PATH) {
8
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
9
+ const db = new Database(dbPath);
10
+ db.pragma("journal_mode = WAL");
11
+ db.pragma("foreign_keys = ON");
12
+ migrate(db);
13
+ return db;
14
+ }
15
+ function migrate(db) {
16
+ db.exec(`
17
+ CREATE TABLE IF NOT EXISTS sessions (
18
+ id TEXT PRIMARY KEY,
19
+ project_path TEXT,
20
+ started_at TEXT NOT NULL,
21
+ ended_at TEXT,
22
+ total_input_tokens INTEGER DEFAULT 0,
23
+ total_output_tokens INTEGER DEFAULT 0,
24
+ total_cache_read_tokens INTEGER DEFAULT 0,
25
+ total_cache_creation_tokens INTEGER DEFAULT 0,
26
+ total_cost_usd REAL DEFAULT 0,
27
+ total_turns INTEGER DEFAULT 0,
28
+ total_duration_ms INTEGER DEFAULT 0,
29
+ model TEXT
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS turns (
33
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
34
+ session_id TEXT NOT NULL REFERENCES sessions(id),
35
+ turn_index INTEGER NOT NULL,
36
+ role TEXT NOT NULL,
37
+ timestamp TEXT NOT NULL,
38
+ input_tokens INTEGER DEFAULT 0,
39
+ output_tokens INTEGER DEFAULT 0,
40
+ cache_read_tokens INTEGER DEFAULT 0,
41
+ cache_creation_tokens INTEGER DEFAULT 0,
42
+ cost_usd REAL DEFAULT 0,
43
+ duration_ms INTEGER DEFAULT 0,
44
+ model TEXT,
45
+ content_text TEXT,
46
+ tool_calls TEXT,
47
+ is_real_user INTEGER DEFAULT 0,
48
+ UNIQUE(session_id, turn_index)
49
+ );
50
+
51
+ CREATE TABLE IF NOT EXISTS tool_uses (
52
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
53
+ session_id TEXT NOT NULL REFERENCES sessions(id),
54
+ turn_id INTEGER REFERENCES turns(id),
55
+ tool_name TEXT NOT NULL,
56
+ tool_input TEXT,
57
+ tool_result TEXT,
58
+ success INTEGER,
59
+ duration_ms INTEGER DEFAULT 0,
60
+ timestamp TEXT NOT NULL
61
+ );
62
+
63
+ CREATE TABLE IF NOT EXISTS hook_events (
64
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
65
+ session_id TEXT,
66
+ event_name TEXT NOT NULL,
67
+ timestamp TEXT NOT NULL,
68
+ payload TEXT NOT NULL
69
+ );
70
+
71
+ CREATE TABLE IF NOT EXISTS otel_metrics (
72
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
73
+ name TEXT NOT NULL,
74
+ value REAL NOT NULL,
75
+ attributes TEXT,
76
+ session_id TEXT,
77
+ model TEXT,
78
+ timestamp TEXT NOT NULL
79
+ );
80
+
81
+ CREATE TABLE IF NOT EXISTS otel_events (
82
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
83
+ event_name TEXT NOT NULL,
84
+ attributes TEXT,
85
+ session_id TEXT,
86
+ prompt_id TEXT,
87
+ timestamp TEXT NOT NULL
88
+ );
89
+
90
+ CREATE INDEX IF NOT EXISTS idx_turns_session ON turns(session_id);
91
+ CREATE INDEX IF NOT EXISTS idx_tool_uses_session ON tool_uses(session_id);
92
+ CREATE INDEX IF NOT EXISTS idx_hook_events_session ON hook_events(session_id);
93
+ CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at);
94
+ CREATE INDEX IF NOT EXISTS idx_otel_metrics_name ON otel_metrics(name, timestamp);
95
+ CREATE INDEX IF NOT EXISTS idx_otel_metrics_session ON otel_metrics(session_id);
96
+ CREATE INDEX IF NOT EXISTS idx_otel_events_name ON otel_events(event_name, timestamp);
97
+ CREATE INDEX IF NOT EXISTS idx_otel_events_session ON otel_events(session_id);
98
+
99
+ CREATE TABLE IF NOT EXISTS task_tags (
100
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
101
+ turn_id INTEGER NOT NULL REFERENCES turns(id),
102
+ task TEXT NOT NULL,
103
+ tagged_at TEXT NOT NULL,
104
+ UNIQUE(turn_id, task)
105
+ );
106
+
107
+ CREATE INDEX IF NOT EXISTS idx_task_tags_task ON task_tags(task);
108
+ CREATE INDEX IF NOT EXISTS idx_task_tags_turn ON task_tags(turn_id);
109
+
110
+ CREATE TABLE IF NOT EXISTS sync_watermarks (
111
+ table_name TEXT PRIMARY KEY,
112
+ last_synced_id INTEGER NOT NULL DEFAULT 0,
113
+ last_synced_at TEXT
114
+ );
115
+ `);
116
+ }
117
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/storage/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;AAE9D,MAAM,UAAU,KAAK,CAAC,SAAiB,eAAe;IACpD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,OAAO,CAAC,EAAqB;IACpC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGP,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getDb } from "./db.js";
2
+ export { SessionRepo } from "./repo.js";
3
+ export type { SessionRow, TurnRow } from "./db.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { getDb } from "./db.js";
2
+ export { SessionRepo } from "./repo.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,162 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { SessionRow, TurnRow, ToolUseRow, HookEventRow, OtelMetricRow, OtelEventRow, TaskTagRow } from "./db.js";
3
+ export declare class SessionRepo {
4
+ private db;
5
+ constructor(db: Database.Database);
6
+ upsertSession(session: Omit<SessionRow, "ended_at"> & {
7
+ ended_at?: string | null;
8
+ }): void;
9
+ /**
10
+ * Accumulate metric deltas from a single OTEL export batch into the sessions row.
11
+ * Creates a stub session row if none exists yet (OTEL may arrive before JSONL ingest).
12
+ * All numeric fields are additive deltas — never a full replacement.
13
+ */
14
+ updateSessionFromOtel(sessionId: string, deltas: {
15
+ costDelta: number;
16
+ inputDelta: number;
17
+ outputDelta: number;
18
+ cacheReadDelta: number;
19
+ cacheCreationDelta: number;
20
+ durationMsDelta: number;
21
+ latestTimestamp: string;
22
+ model: string | null;
23
+ }): void;
24
+ insertTurn(turn: Omit<TurnRow, "id">): number;
25
+ insertToolUse(toolUse: {
26
+ session_id: string;
27
+ turn_id: number | null;
28
+ tool_name: string;
29
+ tool_input: string | null;
30
+ tool_result: string | null;
31
+ success: number | null;
32
+ duration_ms: number;
33
+ timestamp: string;
34
+ }): void;
35
+ /**
36
+ * Replace all tool uses for a given turn in a single transaction.
37
+ * Deletes existing rows first to prevent duplication on re-ingest.
38
+ */
39
+ replaceToolUsesForTurn(turnId: number, toolUses: {
40
+ session_id: string;
41
+ turn_id: number | null;
42
+ tool_name: string;
43
+ tool_input: string | null;
44
+ tool_result: string | null;
45
+ success: number | null;
46
+ duration_ms: number;
47
+ timestamp: string;
48
+ }[]): void;
49
+ insertHookEvent(event: {
50
+ session_id: string | null;
51
+ event_name: string;
52
+ timestamp: string;
53
+ payload: string;
54
+ }): void;
55
+ listSessions(limit?: number, offset?: number): SessionRow[];
56
+ countSessions(): number;
57
+ getSession(id: string): SessionRow | undefined;
58
+ getSessionTurns(sessionId: string): TurnRow[];
59
+ getSessionToolUses(sessionId: string): unknown[];
60
+ getSessionHookEvents(sessionId: string): unknown[];
61
+ getAggregateStats(): unknown;
62
+ insertOtelMetric(metric: {
63
+ name: string;
64
+ value: number;
65
+ attributes: string | null;
66
+ session_id: string | null;
67
+ model: string | null;
68
+ timestamp: string;
69
+ }): void;
70
+ insertOtelMetricBatch(metrics: {
71
+ name: string;
72
+ value: number;
73
+ attributes: string | null;
74
+ session_id: string | null;
75
+ model: string | null;
76
+ timestamp: string;
77
+ }[]): void;
78
+ insertOtelEvent(event: {
79
+ event_name: string;
80
+ attributes: string | null;
81
+ session_id: string | null;
82
+ prompt_id: string | null;
83
+ timestamp: string;
84
+ }): void;
85
+ insertOtelEventBatch(events: {
86
+ event_name: string;
87
+ attributes: string | null;
88
+ session_id: string | null;
89
+ prompt_id: string | null;
90
+ timestamp: string;
91
+ }[]): void;
92
+ getTokenTimeSeries(from: string, to: string, stepSeconds: number): {
93
+ timestamp: string;
94
+ input: number;
95
+ output: number;
96
+ cache_read: number;
97
+ }[];
98
+ getCostTimeSeries(from: string, to: string, stepSeconds: number): {
99
+ timestamp: string;
100
+ cost: number;
101
+ }[];
102
+ getToolUsageBreakdown(): {
103
+ tool_name: string;
104
+ count: number;
105
+ }[];
106
+ getModelBreakdown(): {
107
+ model: string;
108
+ cost: number;
109
+ tokens: number;
110
+ }[];
111
+ getRecentOtelEvents(limit?: number): {
112
+ event_name: string;
113
+ attributes: string | null;
114
+ session_id: string | null;
115
+ prompt_id: string | null;
116
+ timestamp: string;
117
+ }[];
118
+ tagTurn(turnId: number, task: string): void;
119
+ tagTurnsBatch(turnIds: number[], task: string): void;
120
+ getTasksForTurn(turnId: number): string[];
121
+ getTaskTagsForTurn(turnId: number): TaskTagRow[];
122
+ getTurnsByTask(task: string, limit?: number, offset?: number): TurnRow[];
123
+ getTaggedTurns(opts?: {
124
+ tags?: string[];
125
+ mode?: "all" | "any";
126
+ from?: string;
127
+ to?: string;
128
+ limit?: number;
129
+ offset?: number;
130
+ }): (TurnRow & {
131
+ tags: string;
132
+ block_input_tokens: number;
133
+ block_output_tokens: number;
134
+ block_cost_usd: number;
135
+ })[];
136
+ getTurnBlock(turnId: number): TurnRow[];
137
+ getStatsByTask(task: string, from?: string, to?: string): unknown;
138
+ getStatsByTasks(tasks: string[], mode?: "all" | "any", from?: string, to?: string): unknown;
139
+ listTasks(): {
140
+ task: string;
141
+ turn_count: number;
142
+ first_tagged: string;
143
+ last_tagged: string;
144
+ }[];
145
+ getSyncWatermark(tableName: string): number;
146
+ setSyncWatermark(tableName: string, lastSyncedId: number): void;
147
+ getUnsyncedSessions(minRowid: number): (SessionRow & {
148
+ _rowid: number;
149
+ })[];
150
+ getSessionsByIds(ids: string[]): SessionRow[];
151
+ getTurnsAfter(minId: number, limit: number): TurnRow[];
152
+ getToolUsesAfter(minId: number, limit: number): ToolUseRow[];
153
+ getHookEventsAfter(minId: number, limit: number): HookEventRow[];
154
+ getOtelMetricsAfter(minId: number, limit: number): OtelMetricRow[];
155
+ getOtelEventsAfter(minId: number, limit: number): OtelEventRow[];
156
+ getTaskTagsAfter(minId: number, limit: number): TaskTagRow[];
157
+ getTurnLookup(): Map<number, {
158
+ session_id: string;
159
+ turn_index: number;
160
+ }>;
161
+ }
162
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/storage/repo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEtH,qBAAa,WAAW;IACV,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAEzC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IA2BzF;;;;OAIG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE;QAC/C,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,GAAG,IAAI;IA4BR,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,MAAM;IAoB7C,aAAa,CAAC,OAAO,EAAE;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;IAOR;;;OAGG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC/C,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,EAAE,GAAG,IAAI;IAYV,eAAe,CAAC,KAAK,EAAE;QACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI;IAOR,YAAY,CAAC,KAAK,SAAK,EAAE,MAAM,SAAI,GAAG,UAAU,EAAE;IAMlD,aAAa,IAAI,MAAM;IAKvB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI9C,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE;IAM7C,kBAAkB,CAAC,SAAS,EAAE,MAAM;IAMpC,oBAAoB,CAAC,SAAS,EAAE,MAAM;IAMtC,iBAAiB;IAiBjB,gBAAgB,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;IAOR,qBAAqB,CAAC,OAAO,EAAE;QAC7B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,EAAE,GAAG,IAAI;IAWV,eAAe,CAAC,KAAK,EAAE;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;IAOR,oBAAoB,CAAC,MAAM,EAAE;QAC3B,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;KACnB,EAAE,GAAG,IAAI;IAaV,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE;IAe7I,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;IAavG,qBAAqB,IAAI;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;IAU/D,iBAAiB,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE;IAatE,mBAAmB,CAAC,KAAK,SAAK,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE;IAW5J,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAO3C,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAWpD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAOzC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE;IAMhD,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,EAAE,MAAM,SAAI,GAAG,OAAO,EAAE;IAU/D,cAAc,CAAC,IAAI,GAAE;QACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ,GAAG,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE;IA6DxH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE;IAoBvC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;IAmBvD,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,KAAK,GAAG,KAAa,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;IAyCxF,SAAS,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IAY9F,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAO3C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAY/D,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,UAAU,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE;IAM1E,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAQ7C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;IAMtD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAM5D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;IAMhE,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE;IAMlE,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;IAMhE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAM5D,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAMzE"}