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,135 @@
1
+ import { transformSession, transformTurn, transformToolUse, transformHookEvent, transformTaskTag, transformOtelMetric, transformOtelEvent, } from "./transform.js";
2
+ const BATCH_SIZE = 500;
3
+ function zeroCounts() {
4
+ return { synced: 0, failed: 0 };
5
+ }
6
+ /**
7
+ * Build the sync payload for a single session — gathers all child entities
8
+ * (turns, tool_uses, hook_events, task_tags) and transforms them.
9
+ */
10
+ function buildSessionPayload(repo, session) {
11
+ const turns = repo.getSessionTurns(session.id);
12
+ const toolUses = repo.getSessionToolUses(session.id);
13
+ const hookEvents = repo.getSessionHookEvents(session.id);
14
+ // Build turn_id → turn_index lookup for this session
15
+ const turnLookup = new Map(turns.map(t => [t.id, t.turn_index]));
16
+ // Get task tags for all turns in this session
17
+ const taskTags = [];
18
+ for (const turn of turns) {
19
+ const tags = repo.getTaskTagsForTurn(turn.id);
20
+ taskTags.push(...tags);
21
+ }
22
+ return {
23
+ session: transformSession(session),
24
+ turns: turns.map(transformTurn),
25
+ tool_uses: toolUses.map(row => transformToolUse(row, turnLookup)),
26
+ task_tags: taskTags.map(row => transformTaskTag(row, turnLookup)),
27
+ hook_events: hookEvents.map(transformHookEvent),
28
+ };
29
+ }
30
+ export async function runSync(repo, client, opts = {}) {
31
+ const result = {
32
+ sessions: zeroCounts(),
33
+ otel_metrics: zeroCounts(),
34
+ otel_events: zeroCounts(),
35
+ };
36
+ // ── Phase 1: Determine sessions to sync ──
37
+ const sessionsWatermark = repo.getSyncWatermark("sessions");
38
+ const turnsWatermark = repo.getSyncWatermark("turns");
39
+ // New sessions (by rowid)
40
+ const newSessions = repo.getUnsyncedSessions(sessionsWatermark);
41
+ const sessionIdsToSync = new Set(newSessions.map(s => s.id));
42
+ // Sessions with new turns
43
+ const peekTurns = repo.getTurnsAfter(turnsWatermark, BATCH_SIZE);
44
+ for (const t of peekTurns)
45
+ sessionIdsToSync.add(t.session_id);
46
+ // ── Phase 2: Sync sessions (one request per session, includes all child data) ──
47
+ if (sessionIdsToSync.size > 0) {
48
+ const idsFromTurns = [...sessionIdsToSync].filter(id => !newSessions.some(s => s.id === id));
49
+ const extraSessions = repo.getSessionsByIds(idsFromTurns);
50
+ const allSessions = [...newSessions, ...extraSessions];
51
+ let maxSyncedRowid = sessionsWatermark;
52
+ let maxSyncedTurnId = turnsWatermark;
53
+ for (const session of allSessions) {
54
+ if (opts.dryRun) {
55
+ result.sessions.synced++;
56
+ continue;
57
+ }
58
+ const payload = buildSessionPayload(repo, session);
59
+ try {
60
+ const resp = await client.syncSession(session.id, payload);
61
+ result.sessions.synced++;
62
+ // Track watermarks
63
+ const rowid = session._rowid;
64
+ if (rowid != null && rowid > maxSyncedRowid)
65
+ maxSyncedRowid = rowid;
66
+ // Track max turn id for this session's turns
67
+ const sessionTurns = repo.getSessionTurns(session.id);
68
+ for (const t of sessionTurns) {
69
+ if (t.id > maxSyncedTurnId)
70
+ maxSyncedTurnId = t.id;
71
+ }
72
+ if (opts.verbose) {
73
+ console.log(` ${session.id}: ${resp.turns_synced} turns, ` +
74
+ `${resp.tool_uses_synced} tool_uses, ${resp.task_tags_synced} tags, ` +
75
+ `${resp.hook_events_synced} hook_events`);
76
+ }
77
+ }
78
+ catch (err) {
79
+ result.sessions.failed++;
80
+ if (opts.verbose) {
81
+ console.error(` ${session.id}: failed — ${err instanceof Error ? err.message : err}`);
82
+ }
83
+ }
84
+ }
85
+ if (!opts.dryRun) {
86
+ if (maxSyncedRowid > sessionsWatermark) {
87
+ repo.setSyncWatermark("sessions", maxSyncedRowid);
88
+ }
89
+ if (maxSyncedTurnId > turnsWatermark) {
90
+ repo.setSyncWatermark("turns", maxSyncedTurnId);
91
+ }
92
+ }
93
+ }
94
+ // ── Phase 3: Sync OTel data (not session-scoped, uses separate bulk endpoints) ──
95
+ result.otel_metrics = await syncBulkTable("otel_metrics", repo, (minId, limit) => repo.getOtelMetricsAfter(minId, limit), transformOtelMetric, (items) => client.postOtelMetricsBulk(items), opts);
96
+ result.otel_events = await syncBulkTable("otel_events", repo, (minId, limit) => repo.getOtelEventsAfter(minId, limit), transformOtelEvent, (items) => client.postOtelEventsBulk(items), opts);
97
+ return result;
98
+ }
99
+ /**
100
+ * Generic helper for append-only bulk tables (otel_metrics, otel_events).
101
+ */
102
+ async function syncBulkTable(tableName, repo, readAfter, transform, postBulk, opts) {
103
+ const counts = zeroCounts();
104
+ let watermark = repo.getSyncWatermark(tableName);
105
+ for (;;) {
106
+ const rows = readAfter(watermark, BATCH_SIZE);
107
+ if (rows.length === 0)
108
+ break;
109
+ if (opts.dryRun) {
110
+ counts.synced += rows.length;
111
+ watermark = rows[rows.length - 1].id;
112
+ continue;
113
+ }
114
+ const payload = rows.map(transform);
115
+ try {
116
+ await postBulk(payload);
117
+ const newWatermark = rows[rows.length - 1].id;
118
+ repo.setSyncWatermark(tableName, newWatermark);
119
+ watermark = newWatermark;
120
+ counts.synced += rows.length;
121
+ if (opts.verbose) {
122
+ console.log(` ${tableName}: synced ${rows.length} rows (watermark → ${newWatermark})`);
123
+ }
124
+ }
125
+ catch (err) {
126
+ counts.failed += rows.length;
127
+ if (opts.verbose) {
128
+ console.error(` ${tableName}: batch failed — ${err instanceof Error ? err.message : err}`);
129
+ }
130
+ break;
131
+ }
132
+ }
133
+ return counts;
134
+ }
135
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.test.d.ts","sourceRoot":"","sources":["../../src/sync/sync.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,412 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import http from "node:http";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { getDb } from "../storage/db.js";
7
+ import { SessionRepo } from "../storage/repo.js";
8
+ import { ZozulApiClient } from "./client.js";
9
+ import { runSync } from "./index.js";
10
+ // ── Mock server that collects POSTed payloads ──
11
+ function createMockServer() {
12
+ const received = {};
13
+ const server = http.createServer(async (req, res) => {
14
+ if (req.method !== "POST") {
15
+ res.writeHead(405).end();
16
+ return;
17
+ }
18
+ const chunks = [];
19
+ for await (const chunk of req)
20
+ chunks.push(chunk);
21
+ const body = JSON.parse(Buffer.concat(chunks).toString());
22
+ const route = req.url;
23
+ if (!received[route])
24
+ received[route] = [];
25
+ if (Array.isArray(body)) {
26
+ received[route].push(...body);
27
+ }
28
+ else {
29
+ received[route].push(body);
30
+ }
31
+ // Return a sync-style response for session sync endpoints
32
+ if (route.includes("/sync")) {
33
+ const payload = body;
34
+ res.writeHead(200, { "Content-Type": "application/json" });
35
+ res.end(JSON.stringify({
36
+ session_id: route.split("/")[4], // /api/v1/sessions/{id}/sync
37
+ turns_synced: payload.turns?.length ?? 0,
38
+ tool_uses_synced: payload.tool_uses?.length ?? 0,
39
+ task_tags_synced: payload.task_tags?.length ?? 0,
40
+ hook_events_synced: payload.hook_events?.length ?? 0,
41
+ }));
42
+ return;
43
+ }
44
+ res.writeHead(200, { "Content-Type": "application/json" });
45
+ res.end(JSON.stringify({ ok: true }));
46
+ });
47
+ return { server, received };
48
+ }
49
+ function listen(server) {
50
+ return new Promise((resolve) => {
51
+ server.listen(0, "127.0.0.1", () => {
52
+ const addr = server.address();
53
+ resolve(addr.port);
54
+ });
55
+ });
56
+ }
57
+ function close(server) {
58
+ return new Promise((resolve) => server.close(() => resolve()));
59
+ }
60
+ // ── Test suite ──
61
+ describe("zozul sync e2e", () => {
62
+ let dbPath;
63
+ let repo;
64
+ let db;
65
+ let server;
66
+ let received;
67
+ let client;
68
+ beforeEach(async () => {
69
+ dbPath = path.join(os.tmpdir(), `zozul-test-${Date.now()}.db`);
70
+ db = getDb(dbPath);
71
+ repo = new SessionRepo(db);
72
+ const mock = createMockServer();
73
+ server = mock.server;
74
+ received = mock.received;
75
+ const port = await listen(server);
76
+ client = new ZozulApiClient({
77
+ apiUrl: `http://127.0.0.1:${port}`,
78
+ apiKey: "test-key",
79
+ });
80
+ });
81
+ afterEach(async () => {
82
+ db.close();
83
+ await close(server);
84
+ try {
85
+ fs.unlinkSync(dbPath);
86
+ }
87
+ catch { }
88
+ try {
89
+ fs.unlinkSync(dbPath + "-wal");
90
+ }
91
+ catch { }
92
+ try {
93
+ fs.unlinkSync(dbPath + "-shm");
94
+ }
95
+ catch { }
96
+ });
97
+ it("syncs a session with all child data in one request", async () => {
98
+ // Seed session
99
+ repo.upsertSession({
100
+ id: "sess-001",
101
+ project_path: "/projects/test",
102
+ started_at: "2026-03-28T10:00:00Z",
103
+ total_input_tokens: 100,
104
+ total_output_tokens: 50,
105
+ total_cache_read_tokens: 20,
106
+ total_cache_creation_tokens: 5,
107
+ total_cost_usd: 0.01,
108
+ total_turns: 2,
109
+ total_duration_ms: 5000,
110
+ model: "claude-sonnet-4-6",
111
+ });
112
+ // Seed turns
113
+ const turnId = repo.insertTurn({
114
+ session_id: "sess-001",
115
+ turn_index: 0,
116
+ role: "human",
117
+ timestamp: "2026-03-28T10:00:01Z",
118
+ input_tokens: 50,
119
+ output_tokens: 0,
120
+ cache_read_tokens: 10,
121
+ cache_creation_tokens: 0,
122
+ cost_usd: 0.005,
123
+ duration_ms: 1000,
124
+ model: "claude-sonnet-4-6",
125
+ content_text: "Hello",
126
+ tool_calls: null,
127
+ is_real_user: 1,
128
+ });
129
+ repo.insertTurn({
130
+ session_id: "sess-001",
131
+ turn_index: 1,
132
+ role: "assistant",
133
+ timestamp: "2026-03-28T10:00:02Z",
134
+ input_tokens: 50,
135
+ output_tokens: 50,
136
+ cache_read_tokens: 10,
137
+ cache_creation_tokens: 5,
138
+ cost_usd: 0.005,
139
+ duration_ms: 4000,
140
+ model: "claude-sonnet-4-6",
141
+ content_text: "Hi there!",
142
+ tool_calls: JSON.stringify([{ toolName: "Read", toolInput: { path: "/tmp" } }]),
143
+ is_real_user: 0,
144
+ });
145
+ // Seed tool use
146
+ repo.insertToolUse({
147
+ session_id: "sess-001",
148
+ turn_id: turnId,
149
+ tool_name: "Read",
150
+ tool_input: JSON.stringify({ path: "/tmp" }),
151
+ tool_result: "file contents",
152
+ success: 1,
153
+ duration_ms: 200,
154
+ timestamp: "2026-03-28T10:00:02Z",
155
+ });
156
+ // Seed hook event
157
+ repo.insertHookEvent({
158
+ session_id: "sess-001",
159
+ event_name: "UserPromptSubmit",
160
+ timestamp: "2026-03-28T10:00:01Z",
161
+ payload: JSON.stringify({ prompt: "Hello" }),
162
+ });
163
+ // Seed otel metric
164
+ repo.insertOtelMetric({
165
+ name: "claude_code.token.usage",
166
+ value: 100,
167
+ attributes: JSON.stringify({ type: "input" }),
168
+ session_id: "sess-001",
169
+ model: "claude-sonnet-4-6",
170
+ timestamp: "2026-03-28T10:00:02Z",
171
+ });
172
+ // Seed otel event
173
+ repo.insertOtelEvent({
174
+ event_name: "claude_code.conversation.turn",
175
+ attributes: JSON.stringify({ role: "human" }),
176
+ session_id: "sess-001",
177
+ prompt_id: "prompt-001",
178
+ timestamp: "2026-03-28T10:00:01Z",
179
+ });
180
+ // Seed task tag
181
+ repo.tagTurn(turnId, "FEAT-123");
182
+ // ── Run sync ──
183
+ const result = await runSync(repo, client, { verbose: false });
184
+ // ── Verify counts ──
185
+ expect(result.sessions.synced).toBe(1);
186
+ expect(result.sessions.failed).toBe(0);
187
+ expect(result.otel_metrics.synced).toBe(1);
188
+ expect(result.otel_events.synced).toBe(1);
189
+ // ── Verify session sync payload ──
190
+ const syncPayloads = received["/api/v1/sessions/sess-001/sync"];
191
+ expect(syncPayloads).toHaveLength(1);
192
+ const payload = syncPayloads[0];
193
+ // Session
194
+ expect(payload.session).toMatchObject({ id: "sess-001", model: "claude-sonnet-4-6" });
195
+ // Turns — uses turn_index, no session_id (session is implicit)
196
+ const turns = payload.turns;
197
+ expect(turns).toHaveLength(2);
198
+ expect(turns[0]).toMatchObject({ turn_index: 0, is_real_user: true });
199
+ expect(turns[1]).toMatchObject({ turn_index: 1, is_real_user: false });
200
+ expect(turns[1].tool_calls).toEqual([{ toolName: "Read", toolInput: { path: "/tmp" } }]);
201
+ // Tool uses — uses turn_index instead of turn_id
202
+ const toolUses = payload.tool_uses;
203
+ expect(toolUses).toHaveLength(1);
204
+ expect(toolUses[0]).toMatchObject({ tool_name: "Read", success: true, turn_index: 0 });
205
+ expect(toolUses[0].tool_input).toEqual({ path: "/tmp" });
206
+ expect(toolUses[0]).not.toHaveProperty("turn_id");
207
+ expect(toolUses[0]).not.toHaveProperty("session_id");
208
+ // Hook events
209
+ const hookEvents = payload.hook_events;
210
+ expect(hookEvents).toHaveLength(1);
211
+ expect(hookEvents[0]).toMatchObject({ event_name: "UserPromptSubmit" });
212
+ expect(hookEvents[0].payload).toEqual({ prompt: "Hello" });
213
+ // Task tags — uses turn_index
214
+ const taskTags = payload.task_tags;
215
+ expect(taskTags).toHaveLength(1);
216
+ expect(taskTags[0]).toMatchObject({ task: "FEAT-123", turn_index: 0 });
217
+ // OTel sent separately
218
+ const otelMetrics = received["/api/v1/otel/metrics/bulk"];
219
+ expect(otelMetrics).toHaveLength(1);
220
+ expect(otelMetrics[0]).toMatchObject({ name: "claude_code.token.usage", value: 100 });
221
+ const otelEvents = received["/api/v1/otel/events/bulk"];
222
+ expect(otelEvents).toHaveLength(1);
223
+ expect(otelEvents[0]).toMatchObject({ event_name: "claude_code.conversation.turn" });
224
+ });
225
+ it("is idempotent — second sync sends nothing", async () => {
226
+ repo.upsertSession({
227
+ id: "sess-002",
228
+ project_path: null,
229
+ started_at: "2026-03-28T11:00:00Z",
230
+ total_input_tokens: 10,
231
+ total_output_tokens: 10,
232
+ total_cache_read_tokens: 0,
233
+ total_cache_creation_tokens: 0,
234
+ total_cost_usd: 0.001,
235
+ total_turns: 1,
236
+ total_duration_ms: 500,
237
+ model: "claude-haiku-4-5",
238
+ });
239
+ repo.insertTurn({
240
+ session_id: "sess-002",
241
+ turn_index: 0,
242
+ role: "human",
243
+ timestamp: "2026-03-28T11:00:01Z",
244
+ input_tokens: 10,
245
+ output_tokens: 10,
246
+ cache_read_tokens: 0,
247
+ cache_creation_tokens: 0,
248
+ cost_usd: 0.001,
249
+ duration_ms: 500,
250
+ model: "claude-haiku-4-5",
251
+ content_text: "test",
252
+ tool_calls: null,
253
+ is_real_user: 1,
254
+ });
255
+ // First sync
256
+ const r1 = await runSync(repo, client, {});
257
+ expect(r1.sessions.synced).toBe(1);
258
+ // Clear received payloads
259
+ for (const key of Object.keys(received))
260
+ delete received[key];
261
+ // Second sync
262
+ const r2 = await runSync(repo, client, {});
263
+ expect(r2.sessions.synced).toBe(0);
264
+ expect(r2.otel_metrics.synced).toBe(0);
265
+ expect(r2.otel_events.synced).toBe(0);
266
+ expect(Object.keys(received)).toHaveLength(0);
267
+ });
268
+ it("incremental sync picks up only new sessions", async () => {
269
+ repo.upsertSession({
270
+ id: "sess-A",
271
+ project_path: null,
272
+ started_at: "2026-03-28T12:00:00Z",
273
+ total_input_tokens: 10,
274
+ total_output_tokens: 10,
275
+ total_cache_read_tokens: 0,
276
+ total_cache_creation_tokens: 0,
277
+ total_cost_usd: 0.001,
278
+ total_turns: 1,
279
+ total_duration_ms: 100,
280
+ model: null,
281
+ });
282
+ repo.insertTurn({
283
+ session_id: "sess-A",
284
+ turn_index: 0,
285
+ role: "human",
286
+ timestamp: "2026-03-28T12:00:01Z",
287
+ input_tokens: 10,
288
+ output_tokens: 10,
289
+ cache_read_tokens: 0,
290
+ cache_creation_tokens: 0,
291
+ cost_usd: 0.001,
292
+ duration_ms: 100,
293
+ model: null,
294
+ content_text: "first",
295
+ tool_calls: null,
296
+ is_real_user: 1,
297
+ });
298
+ await runSync(repo, client, {});
299
+ for (const key of Object.keys(received))
300
+ delete received[key];
301
+ // Add second session
302
+ repo.upsertSession({
303
+ id: "sess-B",
304
+ project_path: "/new",
305
+ started_at: "2026-03-28T13:00:00Z",
306
+ total_input_tokens: 20,
307
+ total_output_tokens: 20,
308
+ total_cache_read_tokens: 0,
309
+ total_cache_creation_tokens: 0,
310
+ total_cost_usd: 0.002,
311
+ total_turns: 1,
312
+ total_duration_ms: 200,
313
+ model: "claude-opus-4-6",
314
+ });
315
+ repo.insertTurn({
316
+ session_id: "sess-B",
317
+ turn_index: 0,
318
+ role: "human",
319
+ timestamp: "2026-03-28T13:00:01Z",
320
+ input_tokens: 20,
321
+ output_tokens: 20,
322
+ cache_read_tokens: 0,
323
+ cache_creation_tokens: 0,
324
+ cost_usd: 0.002,
325
+ duration_ms: 200,
326
+ model: "claude-opus-4-6",
327
+ content_text: "second",
328
+ tool_calls: null,
329
+ is_real_user: 1,
330
+ });
331
+ const r2 = await runSync(repo, client, {});
332
+ expect(r2.sessions.synced).toBe(1);
333
+ // Only sess-B should have been synced
334
+ expect(received["/api/v1/sessions/sess-B/sync"]).toHaveLength(1);
335
+ expect(received["/api/v1/sessions/sess-A/sync"]).toBeUndefined();
336
+ });
337
+ it("dry-run does not send data or update watermarks", async () => {
338
+ repo.upsertSession({
339
+ id: "sess-dry",
340
+ project_path: null,
341
+ started_at: "2026-03-28T14:00:00Z",
342
+ total_input_tokens: 5,
343
+ total_output_tokens: 5,
344
+ total_cache_read_tokens: 0,
345
+ total_cache_creation_tokens: 0,
346
+ total_cost_usd: 0.0005,
347
+ total_turns: 1,
348
+ total_duration_ms: 50,
349
+ model: null,
350
+ });
351
+ repo.insertTurn({
352
+ session_id: "sess-dry",
353
+ turn_index: 0,
354
+ role: "human",
355
+ timestamp: "2026-03-28T14:00:01Z",
356
+ input_tokens: 5,
357
+ output_tokens: 5,
358
+ cache_read_tokens: 0,
359
+ cache_creation_tokens: 0,
360
+ cost_usd: 0.0005,
361
+ duration_ms: 50,
362
+ model: null,
363
+ content_text: "dry",
364
+ tool_calls: null,
365
+ is_real_user: 1,
366
+ });
367
+ const result = await runSync(repo, client, { dryRun: true });
368
+ expect(result.sessions.synced).toBe(1);
369
+ expect(Object.keys(received)).toHaveLength(0);
370
+ expect(repo.getSyncWatermark("sessions")).toBe(0);
371
+ // Real sync after dry run should still work
372
+ const r2 = await runSync(repo, client, {});
373
+ expect(r2.sessions.synced).toBe(1);
374
+ expect(received["/api/v1/sessions/sess-dry/sync"]).toHaveLength(1);
375
+ });
376
+ it("handles server errors gracefully", async () => {
377
+ repo.upsertSession({
378
+ id: "sess-err",
379
+ project_path: null,
380
+ started_at: "2026-03-28T15:00:00Z",
381
+ total_input_tokens: 10,
382
+ total_output_tokens: 10,
383
+ total_cache_read_tokens: 0,
384
+ total_cache_creation_tokens: 0,
385
+ total_cost_usd: 0.001,
386
+ total_turns: 1,
387
+ total_duration_ms: 100,
388
+ model: null,
389
+ });
390
+ repo.insertTurn({
391
+ session_id: "sess-err",
392
+ turn_index: 0,
393
+ role: "human",
394
+ timestamp: "2026-03-28T15:00:01Z",
395
+ input_tokens: 10,
396
+ output_tokens: 10,
397
+ cache_read_tokens: 0,
398
+ cache_creation_tokens: 0,
399
+ cost_usd: 0.001,
400
+ duration_ms: 100,
401
+ model: null,
402
+ content_text: "error test",
403
+ tool_calls: null,
404
+ is_real_user: 1,
405
+ });
406
+ await close(server);
407
+ const result = await runSync(repo, client, {});
408
+ expect(result.sessions.failed).toBe(1);
409
+ expect(repo.getSyncWatermark("sessions")).toBe(0);
410
+ });
411
+ });
412
+ //# sourceMappingURL=sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.test.js","sourceRoot":"","sources":["../../src/sync/sync.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import type { SessionRow, TurnRow, ToolUseRow, HookEventRow, TaskTagRow } from "../storage/db.js";
2
+ export type ApiSession = {
3
+ id: string;
4
+ project_path: string | null;
5
+ started_at: string;
6
+ ended_at: string | null;
7
+ total_input_tokens: number;
8
+ total_output_tokens: number;
9
+ total_cache_read_tokens: number;
10
+ total_cache_creation_tokens: number;
11
+ total_cost_usd: number;
12
+ total_turns: number;
13
+ total_duration_ms: number;
14
+ model: string | null;
15
+ };
16
+ export type ApiTurn = {
17
+ turn_index: number;
18
+ role: string;
19
+ timestamp: string;
20
+ input_tokens: number;
21
+ output_tokens: number;
22
+ cache_read_tokens: number;
23
+ cache_creation_tokens: number;
24
+ cost_usd: number;
25
+ duration_ms: number;
26
+ model: string | null;
27
+ content_text: string | null;
28
+ tool_calls: unknown[] | null;
29
+ is_real_user: boolean;
30
+ };
31
+ export type ApiToolUse = {
32
+ turn_index: number | null;
33
+ tool_name: string;
34
+ tool_input: unknown | null;
35
+ tool_result: string | null;
36
+ success: boolean | null;
37
+ duration_ms: number;
38
+ timestamp: string;
39
+ };
40
+ export type ApiHookEvent = {
41
+ event_name: string;
42
+ timestamp: string;
43
+ payload: unknown;
44
+ };
45
+ export type ApiTaskTag = {
46
+ turn_index: number | null;
47
+ task: string;
48
+ tagged_at: string;
49
+ };
50
+ export type ApiOtelMetric = {
51
+ name: string;
52
+ value: number;
53
+ attributes: unknown | null;
54
+ session_id: string | null;
55
+ model: string | null;
56
+ timestamp: string;
57
+ };
58
+ export type ApiOtelEvent = {
59
+ event_name: string;
60
+ attributes: unknown | null;
61
+ session_id: string | null;
62
+ prompt_id: string | null;
63
+ timestamp: string;
64
+ };
65
+ export type SessionSyncPayload = {
66
+ session: ApiSession;
67
+ turns: ApiTurn[];
68
+ tool_uses: ApiToolUse[];
69
+ task_tags: ApiTaskTag[];
70
+ hook_events: ApiHookEvent[];
71
+ };
72
+ export type TurnLookup = Map<number, number>;
73
+ export declare function transformSession(row: SessionRow): ApiSession;
74
+ export declare function transformTurn(row: TurnRow): ApiTurn;
75
+ export declare function transformToolUse(row: ToolUseRow, turnLookup: TurnLookup): ApiToolUse;
76
+ export declare function transformHookEvent(row: HookEventRow): ApiHookEvent;
77
+ export declare function transformTaskTag(row: TaskTagRow, turnLookup: TurnLookup): ApiTaskTag;
78
+ export declare function transformOtelMetric(row: import("../storage/db.js").OtelMetricRow): ApiOtelMetric;
79
+ export declare function transformOtelEvent(row: import("../storage/db.js").OtelEventRow): ApiOtelEvent;
80
+ //# sourceMappingURL=transform.d.ts.map