zozul-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +44 -0
- package/.github/workflows/publish.yml +26 -0
- package/DEVELOPMENT.md +288 -0
- package/LICENSE +201 -0
- package/README.md +178 -0
- package/dist/cli/commands.d.ts +3 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +307 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/format.d.ts +5 -0
- package/dist/cli/format.d.ts.map +1 -0
- package/dist/cli/format.js +115 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +37 -0
- package/dist/context/index.js.map +1 -0
- package/dist/dashboard/html.d.ts +17 -0
- package/dist/dashboard/html.d.ts.map +1 -0
- package/dist/dashboard/html.js +79 -0
- package/dist/dashboard/html.js.map +1 -0
- package/dist/dashboard/index.html +1245 -0
- package/dist/hooks/config.d.ts +19 -0
- package/dist/hooks/config.d.ts.map +1 -0
- package/dist/hooks/config.js +106 -0
- package/dist/hooks/config.js.map +1 -0
- package/dist/hooks/git.d.ts +6 -0
- package/dist/hooks/git.d.ts.map +1 -0
- package/dist/hooks/git.js +73 -0
- package/dist/hooks/git.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/server.d.ts +16 -0
- package/dist/hooks/server.d.ts.map +1 -0
- package/dist/hooks/server.js +349 -0
- package/dist/hooks/server.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/otel/config.d.ts +36 -0
- package/dist/otel/config.d.ts.map +1 -0
- package/dist/otel/config.js +109 -0
- package/dist/otel/config.js.map +1 -0
- package/dist/otel/index.d.ts +4 -0
- package/dist/otel/index.d.ts.map +1 -0
- package/dist/otel/index.js +3 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/otel/receiver.d.ts +10 -0
- package/dist/otel/receiver.d.ts.map +1 -0
- package/dist/otel/receiver.js +155 -0
- package/dist/otel/receiver.js.map +1 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/ingest.d.ts +20 -0
- package/dist/parser/ingest.d.ts.map +1 -0
- package/dist/parser/ingest.js +98 -0
- package/dist/parser/ingest.js.map +1 -0
- package/dist/parser/jsonl.d.ts +14 -0
- package/dist/parser/jsonl.d.ts.map +1 -0
- package/dist/parser/jsonl.js +202 -0
- package/dist/parser/jsonl.js.map +1 -0
- package/dist/parser/types.d.ts +81 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +9 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/parser/watcher.d.ts +16 -0
- package/dist/parser/watcher.d.ts.map +1 -0
- package/dist/parser/watcher.js +103 -0
- package/dist/parser/watcher.js.map +1 -0
- package/dist/pricing/index.d.ts +2 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/service/index.d.ts +31 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +252 -0
- package/dist/service/index.js.map +1 -0
- package/dist/storage/db.d.ts +75 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/db.js +117 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/repo.d.ts +162 -0
- package/dist/storage/repo.d.ts.map +1 -0
- package/dist/storage/repo.js +472 -0
- package/dist/storage/repo.js.map +1 -0
- package/dist/sync/client.d.ts +24 -0
- package/dist/sync/client.d.ts.map +1 -0
- package/dist/sync/client.js +41 -0
- package/dist/sync/client.js.map +1 -0
- package/dist/sync/index.d.ts +18 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +135 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/sync.test.d.ts +2 -0
- package/dist/sync/sync.test.d.ts.map +1 -0
- package/dist/sync/sync.test.js +412 -0
- package/dist/sync/sync.test.js.map +1 -0
- package/dist/sync/transform.d.ts +80 -0
- package/dist/sync/transform.d.ts.map +1 -0
- package/dist/sync/transform.js +90 -0
- package/dist/sync/transform.js.map +1 -0
- package/package.json +50 -0
- package/src/cli/commands.ts +332 -0
- package/src/cli/format.ts +133 -0
- package/src/context/index.ts +42 -0
- package/src/dashboard/html.ts +97 -0
- package/src/dashboard/index.html +1245 -0
- package/src/hooks/config.ts +119 -0
- package/src/hooks/git.ts +77 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/server.ts +397 -0
- package/src/index.ts +6 -0
- package/src/otel/config.ts +141 -0
- package/src/otel/index.ts +8 -0
- package/src/otel/receiver.ts +183 -0
- package/src/parser/index.ts +3 -0
- package/src/parser/ingest.ts +119 -0
- package/src/parser/jsonl.ts +241 -0
- package/src/parser/types.ts +89 -0
- package/src/parser/watcher.ts +116 -0
- package/src/pricing/index.ts +51 -0
- package/src/service/index.ts +272 -0
- package/src/storage/db.ts +198 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/repo.ts +601 -0
- package/src/sync/client.ts +63 -0
- package/src/sync/index.ts +207 -0
- package/src/sync/sync.test.ts +447 -0
- package/src/sync/transform.ts +184 -0
- package/tsconfig.json +19 -0
|
@@ -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 @@
|
|
|
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
|