@fml-inc/panopticon 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 (124) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +5 -0
  3. package/README.md +363 -0
  4. package/bin/hook-handler +3 -0
  5. package/bin/mcp-server +3 -0
  6. package/bin/panopticon +3 -0
  7. package/bin/proxy +3 -0
  8. package/bin/server +3 -0
  9. package/dist/api/client.d.ts +67 -0
  10. package/dist/api/client.js +48 -0
  11. package/dist/api/client.js.map +1 -0
  12. package/dist/chunk-3BUJ7URA.js +387 -0
  13. package/dist/chunk-3BUJ7URA.js.map +1 -0
  14. package/dist/chunk-3TZAKV3M.js +158 -0
  15. package/dist/chunk-3TZAKV3M.js.map +1 -0
  16. package/dist/chunk-4SM2H22C.js +169 -0
  17. package/dist/chunk-4SM2H22C.js.map +1 -0
  18. package/dist/chunk-7Q3BJMLG.js +62 -0
  19. package/dist/chunk-7Q3BJMLG.js.map +1 -0
  20. package/dist/chunk-BVOE7A2Z.js +412 -0
  21. package/dist/chunk-BVOE7A2Z.js.map +1 -0
  22. package/dist/chunk-CF4GPWLI.js +170 -0
  23. package/dist/chunk-CF4GPWLI.js.map +1 -0
  24. package/dist/chunk-DZ5HJFB4.js +467 -0
  25. package/dist/chunk-DZ5HJFB4.js.map +1 -0
  26. package/dist/chunk-HQCY722C.js +428 -0
  27. package/dist/chunk-HQCY722C.js.map +1 -0
  28. package/dist/chunk-HRCEIYKU.js +134 -0
  29. package/dist/chunk-HRCEIYKU.js.map +1 -0
  30. package/dist/chunk-K7YUPLES.js +76 -0
  31. package/dist/chunk-K7YUPLES.js.map +1 -0
  32. package/dist/chunk-L7G27XWF.js +130 -0
  33. package/dist/chunk-L7G27XWF.js.map +1 -0
  34. package/dist/chunk-LWXF7YRG.js +626 -0
  35. package/dist/chunk-LWXF7YRG.js.map +1 -0
  36. package/dist/chunk-NXH7AONS.js +1120 -0
  37. package/dist/chunk-NXH7AONS.js.map +1 -0
  38. package/dist/chunk-QK5442ZP.js +55 -0
  39. package/dist/chunk-QK5442ZP.js.map +1 -0
  40. package/dist/chunk-QVK6VGCV.js +1703 -0
  41. package/dist/chunk-QVK6VGCV.js.map +1 -0
  42. package/dist/chunk-RX2RXHBH.js +1699 -0
  43. package/dist/chunk-RX2RXHBH.js.map +1 -0
  44. package/dist/chunk-SEXU2WYG.js +788 -0
  45. package/dist/chunk-SEXU2WYG.js.map +1 -0
  46. package/dist/chunk-SUGSQ4YI.js +264 -0
  47. package/dist/chunk-SUGSQ4YI.js.map +1 -0
  48. package/dist/chunk-TGXFVAID.js +138 -0
  49. package/dist/chunk-TGXFVAID.js.map +1 -0
  50. package/dist/chunk-WLBNFVIG.js +447 -0
  51. package/dist/chunk-WLBNFVIG.js.map +1 -0
  52. package/dist/chunk-XLTCUH5A.js +1072 -0
  53. package/dist/chunk-XLTCUH5A.js.map +1 -0
  54. package/dist/chunk-YVRWVDIA.js +146 -0
  55. package/dist/chunk-YVRWVDIA.js.map +1 -0
  56. package/dist/chunk-ZEC4LRKS.js +176 -0
  57. package/dist/chunk-ZEC4LRKS.js.map +1 -0
  58. package/dist/cli.d.ts +1 -0
  59. package/dist/cli.js +1084 -0
  60. package/dist/cli.js.map +1 -0
  61. package/dist/config-NwoZC-GM.d.ts +20 -0
  62. package/dist/db.d.ts +46 -0
  63. package/dist/db.js +15 -0
  64. package/dist/db.js.map +1 -0
  65. package/dist/doctor.d.ts +37 -0
  66. package/dist/doctor.js +14 -0
  67. package/dist/doctor.js.map +1 -0
  68. package/dist/hooks/handler.d.ts +23 -0
  69. package/dist/hooks/handler.js +295 -0
  70. package/dist/hooks/handler.js.map +1 -0
  71. package/dist/index.d.ts +57 -0
  72. package/dist/index.js +101 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/mcp/server.d.ts +1 -0
  75. package/dist/mcp/server.js +243 -0
  76. package/dist/mcp/server.js.map +1 -0
  77. package/dist/otlp/server.d.ts +7 -0
  78. package/dist/otlp/server.js +17 -0
  79. package/dist/otlp/server.js.map +1 -0
  80. package/dist/permissions.d.ts +33 -0
  81. package/dist/permissions.js +14 -0
  82. package/dist/permissions.js.map +1 -0
  83. package/dist/pricing.d.ts +29 -0
  84. package/dist/pricing.js +13 -0
  85. package/dist/pricing.js.map +1 -0
  86. package/dist/proxy/server.d.ts +10 -0
  87. package/dist/proxy/server.js +20 -0
  88. package/dist/proxy/server.js.map +1 -0
  89. package/dist/prune.d.ts +18 -0
  90. package/dist/prune.js +13 -0
  91. package/dist/prune.js.map +1 -0
  92. package/dist/query.d.ts +56 -0
  93. package/dist/query.js +27 -0
  94. package/dist/query.js.map +1 -0
  95. package/dist/reparse-636YZCE3.js +14 -0
  96. package/dist/reparse-636YZCE3.js.map +1 -0
  97. package/dist/repo.d.ts +17 -0
  98. package/dist/repo.js +9 -0
  99. package/dist/repo.js.map +1 -0
  100. package/dist/scanner.d.ts +73 -0
  101. package/dist/scanner.js +15 -0
  102. package/dist/scanner.js.map +1 -0
  103. package/dist/sdk.d.ts +82 -0
  104. package/dist/sdk.js +208 -0
  105. package/dist/sdk.js.map +1 -0
  106. package/dist/server.d.ts +5 -0
  107. package/dist/server.js +25 -0
  108. package/dist/server.js.map +1 -0
  109. package/dist/setup.d.ts +35 -0
  110. package/dist/setup.js +19 -0
  111. package/dist/setup.js.map +1 -0
  112. package/dist/sync/index.d.ts +29 -0
  113. package/dist/sync/index.js +32 -0
  114. package/dist/sync/index.js.map +1 -0
  115. package/dist/targets.d.ts +279 -0
  116. package/dist/targets.js +20 -0
  117. package/dist/targets.js.map +1 -0
  118. package/dist/types-D-MYCBol.d.ts +128 -0
  119. package/dist/types.d.ts +164 -0
  120. package/dist/types.js +1 -0
  121. package/dist/types.js.map +1 -0
  122. package/hooks/hooks.json +274 -0
  123. package/package.json +124 -0
  124. package/skills/panopticon-optimize/SKILL.md +222 -0
@@ -0,0 +1,788 @@
1
+ import {
2
+ getDb
3
+ } from "./chunk-DZ5HJFB4.js";
4
+
5
+ // src/sync/reader.ts
6
+ function parseJson(raw) {
7
+ if (!raw) return null;
8
+ try {
9
+ const parsed = JSON.parse(raw);
10
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ var HOOK_EVENTS_SQL = `
16
+ SELECT h.id, h.session_id, h.sync_id, h.event_type, h.timestamp_ms, h.cwd, h.repository,
17
+ h.tool_name, decompress(h.payload) as payload,
18
+ h.user_prompt, h.file_path, h.command, h.tool_result,
19
+ s.target
20
+ FROM hook_events h
21
+ LEFT JOIN sessions s ON s.session_id = h.session_id
22
+ WHERE h.id > ?
23
+ ORDER BY h.id
24
+ LIMIT ?
25
+ `;
26
+ function readHookEvents(afterId, limit) {
27
+ const db = getDb();
28
+ const rawRows = db.prepare(HOOK_EVENTS_SQL).all(afterId, limit);
29
+ const rows = rawRows.map((r) => ({
30
+ hookId: r.id,
31
+ sessionId: r.session_id,
32
+ syncId: r.sync_id,
33
+ eventType: r.event_type,
34
+ timestampMs: r.timestamp_ms,
35
+ cwd: r.cwd,
36
+ repository: r.repository,
37
+ toolName: r.tool_name,
38
+ payload: parseJson(r.payload),
39
+ userPrompt: r.user_prompt,
40
+ filePath: r.file_path,
41
+ command: r.command,
42
+ toolResult: r.tool_result,
43
+ target: r.target
44
+ }));
45
+ const maxId = rows.length > 0 ? rows[rows.length - 1].hookId : afterId;
46
+ return { rows, maxId };
47
+ }
48
+ var HOOK_COVERED_BODIES = [
49
+ // Claude Code
50
+ "claude_code.user_prompt",
51
+ "claude_code.tool_decision",
52
+ "claude_code.tool_result",
53
+ // Gemini CLI
54
+ "gemini_cli.user_prompt",
55
+ "gemini_cli.tool_call",
56
+ "gemini_cli.hook_call"
57
+ ];
58
+ var ALL_LOGS_SQL = `
59
+ SELECT id, sync_id, timestamp_ns, body, attributes, resource_attributes,
60
+ severity_text, session_id, prompt_id, trace_id, span_id
61
+ FROM otel_logs
62
+ WHERE id > ?
63
+ ORDER BY id
64
+ LIMIT ?
65
+ `;
66
+ function mapOtelRows(rawRows) {
67
+ return rawRows.map((r) => ({
68
+ id: r.id,
69
+ syncId: r.sync_id,
70
+ timestampNs: r.timestamp_ns,
71
+ body: r.body,
72
+ attributes: parseJson(r.attributes),
73
+ resourceAttributes: parseJson(r.resource_attributes),
74
+ severityText: r.severity_text,
75
+ sessionId: r.session_id,
76
+ promptId: r.prompt_id,
77
+ traceId: r.trace_id,
78
+ spanId: r.span_id
79
+ }));
80
+ }
81
+ function readOtelLogs(afterId, limit, hooksInstalled) {
82
+ const db = getDb();
83
+ if (!hooksInstalled) {
84
+ const rawRows2 = db.prepare(ALL_LOGS_SQL).all(afterId, limit);
85
+ const rows2 = mapOtelRows(rawRows2);
86
+ const maxId = rows2.length > 0 ? rows2[rows2.length - 1].id : afterId;
87
+ return { rows: rows2, maxId };
88
+ }
89
+ const scanMaxId = db.prepare(
90
+ "SELECT MAX(id) as m FROM (SELECT id FROM otel_logs WHERE id > ? ORDER BY id LIMIT ?)"
91
+ ).get(afterId, limit).m;
92
+ if (scanMaxId == null) return { rows: [], maxId: afterId };
93
+ const rawRows = db.prepare(
94
+ `SELECT id, sync_id, timestamp_ns, body, attributes, resource_attributes,
95
+ severity_text, session_id, prompt_id, trace_id, span_id
96
+ FROM otel_logs
97
+ WHERE id > ? AND id <= ?
98
+ AND body NOT IN (${HOOK_COVERED_BODIES.map(() => "?").join(", ")})
99
+ ORDER BY id`
100
+ ).all(afterId, scanMaxId, ...HOOK_COVERED_BODIES);
101
+ const rows = mapOtelRows(rawRows);
102
+ return { rows, maxId: scanMaxId };
103
+ }
104
+ var METRICS_SQL = `
105
+ SELECT id, sync_id, timestamp_ns, name, value, metric_type, unit,
106
+ attributes, resource_attributes, session_id
107
+ FROM otel_metrics
108
+ WHERE id > ?
109
+ ORDER BY id
110
+ LIMIT ?
111
+ `;
112
+ function readMetrics(afterId, limit) {
113
+ const db = getDb();
114
+ const rawRows = db.prepare(METRICS_SQL).all(afterId, limit);
115
+ const rows = rawRows.map((r) => ({
116
+ id: r.id,
117
+ syncId: r.sync_id,
118
+ timestampNs: r.timestamp_ns,
119
+ name: r.name,
120
+ value: r.value,
121
+ metricType: r.metric_type,
122
+ unit: r.unit,
123
+ attributes: parseJson(r.attributes),
124
+ resourceAttributes: parseJson(r.resource_attributes),
125
+ sessionId: r.session_id
126
+ }));
127
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
128
+ return { rows, maxId };
129
+ }
130
+ var SCANNER_TURNS_SQL = `
131
+ SELECT t.id, t.session_id, t.sync_id, t.source, t.turn_index, t.timestamp_ms,
132
+ t.model, t.role, t.content_preview,
133
+ t.input_tokens, t.output_tokens, t.cache_read_tokens,
134
+ t.cache_creation_tokens, t.reasoning_tokens,
135
+ s.cli_version
136
+ FROM scanner_turns t
137
+ LEFT JOIN sessions s ON s.session_id = t.session_id
138
+ WHERE t.id > ?
139
+ ORDER BY t.id
140
+ LIMIT ?
141
+ `;
142
+ function readScannerTurns(afterId, limit) {
143
+ const db = getDb();
144
+ const rawRows = db.prepare(SCANNER_TURNS_SQL).all(afterId, limit);
145
+ const rows = rawRows.map((r) => ({
146
+ id: r.id,
147
+ sessionId: r.session_id,
148
+ syncId: r.sync_id,
149
+ source: r.source,
150
+ turnIndex: r.turn_index,
151
+ timestampMs: r.timestamp_ms,
152
+ model: r.model,
153
+ role: r.role,
154
+ contentPreview: r.content_preview,
155
+ inputTokens: r.input_tokens,
156
+ outputTokens: r.output_tokens,
157
+ cacheReadTokens: r.cache_read_tokens,
158
+ cacheCreationTokens: r.cache_creation_tokens,
159
+ reasoningTokens: r.reasoning_tokens,
160
+ cliVersion: r.cli_version
161
+ }));
162
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
163
+ return { rows, maxId };
164
+ }
165
+ var SCANNER_EVENTS_SQL = `
166
+ SELECT id, session_id, sync_id, source, event_type, timestamp_ms,
167
+ tool_name, tool_input, tool_output, content, metadata
168
+ FROM scanner_events
169
+ WHERE id > ?
170
+ ORDER BY id
171
+ LIMIT ?
172
+ `;
173
+ function readScannerEvents(afterId, limit) {
174
+ const db = getDb();
175
+ const rawRows = db.prepare(SCANNER_EVENTS_SQL).all(afterId, limit);
176
+ const rows = rawRows.map((r) => ({
177
+ id: r.id,
178
+ sessionId: r.session_id,
179
+ syncId: r.sync_id,
180
+ source: r.source,
181
+ eventType: r.event_type,
182
+ timestampMs: r.timestamp_ms,
183
+ toolName: r.tool_name,
184
+ toolInput: r.tool_input,
185
+ toolOutput: r.tool_output,
186
+ content: r.content,
187
+ metadata: parseJson(r.metadata)
188
+ }));
189
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
190
+ return { rows, maxId };
191
+ }
192
+ var SPANS_SQL = `
193
+ SELECT id, trace_id, span_id, parent_span_id, name, kind,
194
+ start_time_ns, end_time_ns, status_code, status_message,
195
+ attributes, resource_attributes, session_id
196
+ FROM otel_spans
197
+ WHERE id > ?
198
+ ORDER BY id
199
+ LIMIT ?
200
+ `;
201
+ function readOtelSpans(afterId, limit) {
202
+ const db = getDb();
203
+ const rawRows = db.prepare(SPANS_SQL).all(afterId, limit);
204
+ const rows = rawRows.map((r) => ({
205
+ id: r.id,
206
+ traceId: r.trace_id,
207
+ spanId: r.span_id,
208
+ parentSpanId: r.parent_span_id,
209
+ name: r.name,
210
+ kind: r.kind,
211
+ startTimeNs: r.start_time_ns,
212
+ endTimeNs: r.end_time_ns,
213
+ statusCode: r.status_code,
214
+ statusMessage: r.status_message,
215
+ attributes: parseJson(r.attributes),
216
+ resourceAttributes: parseJson(r.resource_attributes),
217
+ sessionId: r.session_id
218
+ }));
219
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
220
+ return { rows, maxId };
221
+ }
222
+ function parseJsonArray(raw) {
223
+ if (!raw) return [];
224
+ try {
225
+ const parsed = JSON.parse(raw);
226
+ return Array.isArray(parsed) ? parsed : [];
227
+ } catch {
228
+ return [];
229
+ }
230
+ }
231
+ function parseJsonObject(raw) {
232
+ if (!raw) return {};
233
+ try {
234
+ const parsed = JSON.parse(raw);
235
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
236
+ } catch {
237
+ return {};
238
+ }
239
+ }
240
+ var USER_CONFIG_SQL = `
241
+ SELECT id, device_name, snapshot_at_ms, content_hash,
242
+ permissions, enabled_plugins, hooks, commands, rules, skills
243
+ FROM user_config_snapshots
244
+ WHERE id > ?
245
+ ORDER BY id
246
+ LIMIT ?
247
+ `;
248
+ function readUserConfigSnapshots(afterId, limit) {
249
+ const db = getDb();
250
+ const rawRows = db.prepare(USER_CONFIG_SQL).all(afterId, limit);
251
+ const rows = rawRows.map((r) => ({
252
+ id: r.id,
253
+ deviceName: r.device_name,
254
+ snapshotAtMs: r.snapshot_at_ms,
255
+ contentHash: r.content_hash,
256
+ permissions: parseJsonObject(r.permissions),
257
+ enabledPlugins: parseJsonArray(r.enabled_plugins),
258
+ hooks: parseJsonArray(r.hooks),
259
+ commands: parseJsonArray(r.commands),
260
+ rules: parseJsonArray(r.rules),
261
+ skills: parseJsonArray(r.skills)
262
+ }));
263
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
264
+ return { rows, maxId };
265
+ }
266
+ var REPO_CONFIG_SQL = `
267
+ SELECT id, repository, cwd, session_id, snapshot_at_ms, content_hash,
268
+ hooks, mcp_servers, commands, agents, rules,
269
+ local_hooks, local_mcp_servers, local_permissions,
270
+ local_is_gitignored, instructions
271
+ FROM repo_config_snapshots
272
+ WHERE id > ?
273
+ ORDER BY id
274
+ LIMIT ?
275
+ `;
276
+ function readRepoConfigSnapshots(afterId, limit) {
277
+ const db = getDb();
278
+ const rawRows = db.prepare(REPO_CONFIG_SQL).all(afterId, limit);
279
+ const rows = rawRows.map((r) => ({
280
+ id: r.id,
281
+ repository: r.repository,
282
+ cwd: r.cwd,
283
+ sessionId: r.session_id,
284
+ snapshotAtMs: r.snapshot_at_ms,
285
+ contentHash: r.content_hash,
286
+ hooks: parseJsonArray(r.hooks),
287
+ mcpServers: parseJsonArray(r.mcp_servers),
288
+ commands: parseJsonArray(r.commands),
289
+ agents: parseJsonArray(r.agents),
290
+ rules: parseJsonArray(r.rules),
291
+ localHooks: parseJsonArray(r.local_hooks),
292
+ localMcpServers: parseJsonArray(r.local_mcp_servers),
293
+ localPermissions: parseJsonObject(r.local_permissions),
294
+ localIsGitignored: r.local_is_gitignored === 1,
295
+ instructions: parseJsonArray(r.instructions)
296
+ }));
297
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
298
+ return { rows, maxId };
299
+ }
300
+ var MESSAGES_SQL = `
301
+ SELECT id, session_id, ordinal, role, content, timestamp_ms,
302
+ has_thinking, has_tool_use, content_length, is_system,
303
+ model, token_usage, context_tokens, output_tokens,
304
+ has_context_tokens, has_output_tokens
305
+ FROM messages
306
+ WHERE id > ?
307
+ ORDER BY id
308
+ LIMIT ?
309
+ `;
310
+ function readMessages(afterId, limit) {
311
+ const db = getDb();
312
+ const rawRows = db.prepare(MESSAGES_SQL).all(afterId, limit);
313
+ const rows = rawRows.map((r) => ({
314
+ id: r.id,
315
+ sessionId: r.session_id,
316
+ ordinal: r.ordinal,
317
+ role: r.role,
318
+ content: r.content,
319
+ timestampMs: r.timestamp_ms,
320
+ hasThinking: r.has_thinking === 1,
321
+ hasToolUse: r.has_tool_use === 1,
322
+ contentLength: r.content_length,
323
+ isSystem: r.is_system === 1,
324
+ model: r.model,
325
+ tokenUsage: r.token_usage,
326
+ contextTokens: r.context_tokens,
327
+ outputTokens: r.output_tokens,
328
+ hasContextTokens: r.has_context_tokens === 1,
329
+ hasOutputTokens: r.has_output_tokens === 1
330
+ }));
331
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
332
+ return { rows, maxId };
333
+ }
334
+ var TOOL_CALLS_SQL = `
335
+ SELECT id, message_id, session_id, sync_id, tool_name, category, tool_use_id,
336
+ input_json, skill_name, result_content_length, result_content,
337
+ subagent_session_id
338
+ FROM tool_calls
339
+ WHERE id > ?
340
+ ORDER BY id
341
+ LIMIT ?
342
+ `;
343
+ function readToolCalls(afterId, limit) {
344
+ const db = getDb();
345
+ const rawRows = db.prepare(TOOL_CALLS_SQL).all(afterId, limit);
346
+ const rows = rawRows.map((r) => ({
347
+ id: r.id,
348
+ messageId: r.message_id,
349
+ sessionId: r.session_id,
350
+ syncId: r.sync_id,
351
+ toolName: r.tool_name,
352
+ category: r.category,
353
+ toolUseId: r.tool_use_id,
354
+ inputJson: r.input_json,
355
+ skillName: r.skill_name,
356
+ resultContentLength: r.result_content_length,
357
+ resultContent: r.result_content,
358
+ subagentSessionId: r.subagent_session_id
359
+ }));
360
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
361
+ return { rows, maxId };
362
+ }
363
+ var SESSIONS_SQL = `
364
+ SELECT session_id, target, started_at_ms, ended_at_ms, cwd, first_prompt,
365
+ permission_mode, agent_version,
366
+ total_input_tokens, total_output_tokens, total_cache_read_tokens,
367
+ total_cache_creation_tokens, total_reasoning_tokens, turn_count,
368
+ models, summary, tool_counts, hook_tool_counts, event_type_counts, hook_event_type_counts, sync_seq,
369
+ project, machine, message_count, user_message_count,
370
+ parent_session_id, relationship_type, is_automated, created_at
371
+ FROM sessions
372
+ WHERE sync_seq > ?
373
+ ORDER BY sync_seq
374
+ LIMIT ?
375
+ `;
376
+ function readSessions(afterSeq, limit) {
377
+ const db = getDb();
378
+ const rawRows = db.prepare(SESSIONS_SQL).all(afterSeq, limit);
379
+ if (rawRows.length === 0) return { rows: [], maxId: afterSeq };
380
+ const sessionIds = rawRows.map((r) => r.session_id);
381
+ const placeholders = sessionIds.map(() => "?").join(", ");
382
+ const repoRows = db.prepare(
383
+ `SELECT session_id, repository, first_seen_ms, git_user_name, git_user_email, branch
384
+ FROM session_repositories
385
+ WHERE session_id IN (${placeholders})`
386
+ ).all(...sessionIds);
387
+ const cwdRows = db.prepare(
388
+ `SELECT session_id, cwd, first_seen_ms
389
+ FROM session_cwds
390
+ WHERE session_id IN (${placeholders})`
391
+ ).all(...sessionIds);
392
+ const reposBySession = /* @__PURE__ */ new Map();
393
+ for (const r of repoRows) {
394
+ const list = reposBySession.get(r.session_id) ?? [];
395
+ list.push({
396
+ repository: r.repository,
397
+ firstSeenMs: r.first_seen_ms,
398
+ gitUserName: r.git_user_name,
399
+ gitUserEmail: r.git_user_email,
400
+ branch: r.branch
401
+ });
402
+ reposBySession.set(r.session_id, list);
403
+ }
404
+ const cwdsBySession = /* @__PURE__ */ new Map();
405
+ for (const r of cwdRows) {
406
+ const list = cwdsBySession.get(r.session_id) ?? [];
407
+ list.push({ cwd: r.cwd, firstSeenMs: r.first_seen_ms });
408
+ cwdsBySession.set(r.session_id, list);
409
+ }
410
+ const rows = rawRows.map((r) => ({
411
+ sessionId: r.session_id,
412
+ target: r.target,
413
+ startedAtMs: r.started_at_ms,
414
+ endedAtMs: r.ended_at_ms,
415
+ cwd: r.cwd,
416
+ firstPrompt: r.first_prompt,
417
+ permissionMode: r.permission_mode,
418
+ agentVersion: r.agent_version,
419
+ totalInputTokens: r.total_input_tokens,
420
+ totalOutputTokens: r.total_output_tokens,
421
+ totalCacheReadTokens: r.total_cache_read_tokens,
422
+ totalCacheCreationTokens: r.total_cache_creation_tokens,
423
+ totalReasoningTokens: r.total_reasoning_tokens,
424
+ turnCount: r.turn_count,
425
+ models: r.models,
426
+ summary: r.summary,
427
+ toolCounts: parseJsonObject(r.tool_counts),
428
+ hookToolCounts: parseJsonObject(r.hook_tool_counts),
429
+ eventTypeCounts: parseJsonObject(r.event_type_counts),
430
+ hookEventTypeCounts: parseJsonObject(r.hook_event_type_counts),
431
+ project: r.project,
432
+ machine: r.machine,
433
+ messageCount: r.message_count,
434
+ userMessageCount: r.user_message_count,
435
+ parentSessionId: r.parent_session_id,
436
+ relationshipType: r.relationship_type,
437
+ isAutomated: r.is_automated === 1,
438
+ createdAt: r.created_at,
439
+ repositories: reposBySession.get(r.session_id) ?? [],
440
+ cwds: cwdsBySession.get(r.session_id) ?? []
441
+ }));
442
+ const maxId = rawRows[rawRows.length - 1].sync_seq;
443
+ return { rows, maxId };
444
+ }
445
+ function readSessionMessages(sessionId, afterId, limit) {
446
+ const db = getDb();
447
+ const rawRows = db.prepare(
448
+ `SELECT id, session_id, ordinal, role, content, timestamp_ms,
449
+ has_thinking, has_tool_use, content_length, is_system,
450
+ model, token_usage, context_tokens, output_tokens,
451
+ has_context_tokens, has_output_tokens
452
+ FROM messages
453
+ WHERE session_id = ? AND id > ?
454
+ ORDER BY id
455
+ LIMIT ?`
456
+ ).all(sessionId, afterId, limit);
457
+ const rows = rawRows.map((r) => ({
458
+ id: r.id,
459
+ sessionId: r.session_id,
460
+ ordinal: r.ordinal,
461
+ role: r.role,
462
+ content: r.content,
463
+ timestampMs: r.timestamp_ms,
464
+ hasThinking: r.has_thinking === 1,
465
+ hasToolUse: r.has_tool_use === 1,
466
+ contentLength: r.content_length,
467
+ isSystem: r.is_system === 1,
468
+ model: r.model,
469
+ tokenUsage: r.token_usage,
470
+ contextTokens: r.context_tokens,
471
+ outputTokens: r.output_tokens,
472
+ hasContextTokens: r.has_context_tokens === 1,
473
+ hasOutputTokens: r.has_output_tokens === 1
474
+ }));
475
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
476
+ return { rows, maxId };
477
+ }
478
+ function readSessionToolCalls(sessionId, afterId, limit) {
479
+ const db = getDb();
480
+ const rawRows = db.prepare(
481
+ `SELECT id, message_id, session_id, sync_id, tool_name, category, tool_use_id,
482
+ input_json, skill_name, result_content_length, result_content,
483
+ subagent_session_id
484
+ FROM tool_calls
485
+ WHERE session_id = ? AND id > ?
486
+ ORDER BY id
487
+ LIMIT ?`
488
+ ).all(sessionId, afterId, limit);
489
+ const rows = rawRows.map((r) => ({
490
+ id: r.id,
491
+ messageId: r.message_id,
492
+ sessionId: r.session_id,
493
+ syncId: r.sync_id,
494
+ toolName: r.tool_name,
495
+ category: r.category,
496
+ toolUseId: r.tool_use_id,
497
+ inputJson: r.input_json,
498
+ skillName: r.skill_name,
499
+ resultContentLength: r.result_content_length,
500
+ resultContent: r.result_content,
501
+ subagentSessionId: r.subagent_session_id
502
+ }));
503
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
504
+ return { rows, maxId };
505
+ }
506
+ function readSessionScannerTurns(sessionId, afterId, limit) {
507
+ const db = getDb();
508
+ const rawRows = db.prepare(
509
+ `SELECT t.id, t.session_id, t.sync_id, t.source, t.turn_index, t.timestamp_ms,
510
+ t.model, t.role, t.content_preview,
511
+ t.input_tokens, t.output_tokens, t.cache_read_tokens,
512
+ t.cache_creation_tokens, t.reasoning_tokens,
513
+ s.cli_version
514
+ FROM scanner_turns t
515
+ LEFT JOIN sessions s ON s.session_id = t.session_id
516
+ WHERE t.session_id = ? AND t.id > ?
517
+ ORDER BY t.id
518
+ LIMIT ?`
519
+ ).all(sessionId, afterId, limit);
520
+ const rows = rawRows.map((r) => ({
521
+ id: r.id,
522
+ sessionId: r.session_id,
523
+ syncId: r.sync_id,
524
+ source: r.source,
525
+ turnIndex: r.turn_index,
526
+ timestampMs: r.timestamp_ms,
527
+ model: r.model,
528
+ role: r.role,
529
+ contentPreview: r.content_preview,
530
+ inputTokens: r.input_tokens,
531
+ outputTokens: r.output_tokens,
532
+ cacheReadTokens: r.cache_read_tokens,
533
+ cacheCreationTokens: r.cache_creation_tokens,
534
+ reasoningTokens: r.reasoning_tokens,
535
+ cliVersion: r.cli_version
536
+ }));
537
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
538
+ return { rows, maxId };
539
+ }
540
+ function readSessionScannerEvents(sessionId, afterId, limit) {
541
+ const db = getDb();
542
+ const rawRows = db.prepare(
543
+ `SELECT id, session_id, sync_id, source, event_type, timestamp_ms,
544
+ tool_name, tool_input, tool_output, content, metadata
545
+ FROM scanner_events
546
+ WHERE session_id = ? AND id > ?
547
+ ORDER BY id
548
+ LIMIT ?`
549
+ ).all(sessionId, afterId, limit);
550
+ const rows = rawRows.map((r) => ({
551
+ id: r.id,
552
+ sessionId: r.session_id,
553
+ syncId: r.sync_id,
554
+ source: r.source,
555
+ eventType: r.event_type,
556
+ timestampMs: r.timestamp_ms,
557
+ toolName: r.tool_name,
558
+ toolInput: r.tool_input,
559
+ toolOutput: r.tool_output,
560
+ content: r.content,
561
+ metadata: parseJson(r.metadata)
562
+ }));
563
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
564
+ return { rows, maxId };
565
+ }
566
+ function readSessionHookEvents(sessionId, afterId, limit) {
567
+ const db = getDb();
568
+ const rawRows = db.prepare(
569
+ `SELECT h.id, h.session_id, h.sync_id, h.event_type, h.timestamp_ms, h.cwd, h.repository,
570
+ h.tool_name, decompress(h.payload) as payload,
571
+ h.user_prompt, h.file_path, h.command, h.tool_result,
572
+ s.target
573
+ FROM hook_events h
574
+ LEFT JOIN sessions s ON s.session_id = h.session_id
575
+ WHERE h.session_id = ? AND h.id > ?
576
+ ORDER BY h.id
577
+ LIMIT ?`
578
+ ).all(sessionId, afterId, limit);
579
+ const rows = rawRows.map((r) => ({
580
+ hookId: r.id,
581
+ sessionId: r.session_id,
582
+ syncId: r.sync_id,
583
+ eventType: r.event_type,
584
+ timestampMs: r.timestamp_ms,
585
+ cwd: r.cwd,
586
+ repository: r.repository,
587
+ toolName: r.tool_name,
588
+ payload: parseJson(r.payload),
589
+ userPrompt: r.user_prompt,
590
+ filePath: r.file_path,
591
+ command: r.command,
592
+ toolResult: r.tool_result,
593
+ target: r.target
594
+ }));
595
+ const maxId = rows.length > 0 ? rows[rows.length - 1].hookId : afterId;
596
+ return { rows, maxId };
597
+ }
598
+ function readSessionOtelLogs(sessionId, afterId, limit) {
599
+ const db = getDb();
600
+ const rawRows = db.prepare(
601
+ `SELECT id, sync_id, timestamp_ns, body, attributes, resource_attributes,
602
+ severity_text, session_id, prompt_id, trace_id, span_id
603
+ FROM otel_logs
604
+ WHERE session_id = ? AND id > ?
605
+ ORDER BY id
606
+ LIMIT ?`
607
+ ).all(sessionId, afterId, limit);
608
+ const rows = mapOtelRows(rawRows);
609
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
610
+ return { rows, maxId };
611
+ }
612
+ function readSessionOtelMetrics(sessionId, afterId, limit) {
613
+ const db = getDb();
614
+ const rawRows = db.prepare(
615
+ `SELECT id, sync_id, timestamp_ns, name, value, metric_type, unit,
616
+ attributes, resource_attributes, session_id
617
+ FROM otel_metrics
618
+ WHERE session_id = ? AND id > ?
619
+ ORDER BY id
620
+ LIMIT ?`
621
+ ).all(sessionId, afterId, limit);
622
+ const rows = rawRows.map((r) => ({
623
+ id: r.id,
624
+ syncId: r.sync_id,
625
+ timestampNs: r.timestamp_ns,
626
+ name: r.name,
627
+ value: r.value,
628
+ metricType: r.metric_type,
629
+ unit: r.unit,
630
+ attributes: parseJson(r.attributes),
631
+ resourceAttributes: parseJson(r.resource_attributes),
632
+ sessionId: r.session_id
633
+ }));
634
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
635
+ return { rows, maxId };
636
+ }
637
+ function readSessionOtelSpans(sessionId, afterId, limit) {
638
+ const db = getDb();
639
+ const rawRows = db.prepare(
640
+ `SELECT id, trace_id, span_id, parent_span_id, name, kind,
641
+ start_time_ns, end_time_ns, status_code, status_message,
642
+ attributes, resource_attributes, session_id
643
+ FROM otel_spans
644
+ WHERE session_id = ? AND id > ?
645
+ ORDER BY id
646
+ LIMIT ?`
647
+ ).all(sessionId, afterId, limit);
648
+ const rows = rawRows.map((r) => ({
649
+ id: r.id,
650
+ traceId: r.trace_id,
651
+ spanId: r.span_id,
652
+ parentSpanId: r.parent_span_id,
653
+ name: r.name,
654
+ kind: r.kind,
655
+ startTimeNs: r.start_time_ns,
656
+ endTimeNs: r.end_time_ns,
657
+ statusCode: r.status_code,
658
+ statusMessage: r.status_message,
659
+ attributes: parseJson(r.attributes),
660
+ resourceAttributes: parseJson(r.resource_attributes),
661
+ sessionId: r.session_id
662
+ }));
663
+ const maxId = rows.length > 0 ? rows[rows.length - 1].id : afterId;
664
+ return { rows, maxId };
665
+ }
666
+ var SESSION_READERS = {
667
+ messages: readSessionMessages,
668
+ tool_calls: readSessionToolCalls,
669
+ scanner_turns: readSessionScannerTurns,
670
+ scanner_events: readSessionScannerEvents,
671
+ hook_events: readSessionHookEvents,
672
+ otel_logs: readSessionOtelLogs,
673
+ otel_metrics: readSessionOtelMetrics,
674
+ otel_spans: readSessionOtelSpans
675
+ };
676
+
677
+ // src/sync/registry.ts
678
+ var TABLE_SYNC_REGISTRY = [
679
+ // ── Session-linked tables (filtered by repo attribution) ─────────────────
680
+ {
681
+ table: "sessions",
682
+ logNoun: "sessions",
683
+ read: (afterId, limit) => readSessions(afterId, limit),
684
+ sessionLinked: true
685
+ },
686
+ {
687
+ table: "messages",
688
+ logNoun: "messages",
689
+ read: (afterId, limit) => readMessages(afterId, limit),
690
+ sessionLinked: true
691
+ },
692
+ {
693
+ table: "tool_calls",
694
+ logNoun: "tool calls",
695
+ read: (afterId, limit) => readToolCalls(afterId, limit),
696
+ sessionLinked: true
697
+ },
698
+ {
699
+ table: "scanner_turns",
700
+ logNoun: "turns",
701
+ read: (afterId, limit) => readScannerTurns(afterId, limit),
702
+ sessionLinked: true
703
+ },
704
+ {
705
+ table: "scanner_events",
706
+ logNoun: "events",
707
+ read: (afterId, limit) => readScannerEvents(afterId, limit),
708
+ sessionLinked: true
709
+ },
710
+ {
711
+ table: "hook_events",
712
+ logNoun: "events",
713
+ read: (afterId, limit) => readHookEvents(afterId, limit),
714
+ sessionLinked: true
715
+ },
716
+ {
717
+ table: "otel_logs",
718
+ logNoun: "logs",
719
+ read: (afterId, limit) => readOtelLogs(afterId, limit, false),
720
+ sessionLinked: true
721
+ },
722
+ {
723
+ table: "otel_metrics",
724
+ logNoun: "metrics",
725
+ read: (afterId, limit) => readMetrics(afterId, limit),
726
+ sessionLinked: true
727
+ },
728
+ {
729
+ table: "otel_spans",
730
+ logNoun: "spans",
731
+ read: (afterId, limit) => readOtelSpans(afterId, limit),
732
+ sessionLinked: true
733
+ },
734
+ // ── Non-session tables (always synced) ────────────────────────────────────
735
+ {
736
+ table: "user_config_snapshots",
737
+ logNoun: "snapshots",
738
+ read: (afterId, limit) => readUserConfigSnapshots(afterId, limit),
739
+ sessionLinked: false
740
+ },
741
+ {
742
+ table: "repo_config_snapshots",
743
+ logNoun: "snapshots",
744
+ read: (afterId, limit) => readRepoConfigSnapshots(afterId, limit),
745
+ sessionLinked: false
746
+ }
747
+ ];
748
+
749
+ // src/sync/watermark.ts
750
+ function watermarkKey(table, targetName) {
751
+ return `${table}:${targetName}`;
752
+ }
753
+ function readWatermark(key) {
754
+ const db = getDb();
755
+ const row = db.prepare("SELECT value FROM watermarks WHERE key = ?").get(key);
756
+ return row?.value ?? 0;
757
+ }
758
+ function writeWatermark(key, value) {
759
+ const db = getDb();
760
+ db.prepare(
761
+ "INSERT INTO watermarks (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
762
+ ).run(key, value);
763
+ }
764
+ function resetWatermarks(targetName) {
765
+ const db = getDb();
766
+ if (targetName) {
767
+ const stmt = db.prepare("DELETE FROM watermarks WHERE key = ?");
768
+ for (const desc of TABLE_SYNC_REGISTRY) {
769
+ stmt.run(watermarkKey(desc.table, targetName));
770
+ }
771
+ db.prepare("DELETE FROM target_session_sync WHERE target = ?").run(
772
+ targetName
773
+ );
774
+ } else {
775
+ db.prepare("DELETE FROM watermarks").run();
776
+ db.prepare("DELETE FROM target_session_sync").run();
777
+ }
778
+ }
779
+
780
+ export {
781
+ SESSION_READERS,
782
+ TABLE_SYNC_REGISTRY,
783
+ watermarkKey,
784
+ readWatermark,
785
+ writeWatermark,
786
+ resetWatermarks
787
+ };
788
+ //# sourceMappingURL=chunk-SEXU2WYG.js.map