tracelight 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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/dist/apiTypes.d.ts +139 -0
  4. package/dist/apiTypes.d.ts.map +1 -0
  5. package/dist/apiTypes.js +11 -0
  6. package/dist/apiTypes.js.map +1 -0
  7. package/dist/cli.d.ts +13 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +73 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/model.d.ts +133 -0
  12. package/dist/model.d.ts.map +1 -0
  13. package/dist/model.js +20 -0
  14. package/dist/model.js.map +1 -0
  15. package/dist/parser/index.d.ts +27 -0
  16. package/dist/parser/index.d.ts.map +1 -0
  17. package/dist/parser/index.js +434 -0
  18. package/dist/parser/index.js.map +1 -0
  19. package/dist/parser/rawTypes.d.ts +149 -0
  20. package/dist/parser/rawTypes.d.ts.map +1 -0
  21. package/dist/parser/rawTypes.js +11 -0
  22. package/dist/parser/rawTypes.js.map +1 -0
  23. package/dist/pricing.d.ts +35 -0
  24. package/dist/pricing.d.ts.map +1 -0
  25. package/dist/pricing.js +73 -0
  26. package/dist/pricing.js.map +1 -0
  27. package/dist/projectLoader.d.ts +31 -0
  28. package/dist/projectLoader.d.ts.map +1 -0
  29. package/dist/projectLoader.js +335 -0
  30. package/dist/projectLoader.js.map +1 -0
  31. package/dist/scripts/summarize.d.ts +7 -0
  32. package/dist/scripts/summarize.d.ts.map +1 -0
  33. package/dist/scripts/summarize.js +153 -0
  34. package/dist/scripts/summarize.js.map +1 -0
  35. package/dist/server/index.d.ts +18 -0
  36. package/dist/server/index.d.ts.map +1 -0
  37. package/dist/server/index.js +100 -0
  38. package/dist/server/index.js.map +1 -0
  39. package/package.json +70 -0
  40. package/ui/dist/assets/index-Bnr6kWU4.js +62 -0
  41. package/ui/dist/assets/index-HoOM9YCS.css +1 -0
  42. package/ui/dist/index.html +13 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Hand-maintained cost table for Claude model families.
3
+ *
4
+ * IMPORTANT: These prices are hand-maintained and must be verified against
5
+ * https://www.anthropic.com/pricing before using for billing or reporting.
6
+ * Last verified: 2026-06-13.
7
+ */
8
+ /** Date this pricing table was last verified against Anthropic's public list prices. */
9
+ export const PRICING_AS_OF_DATE = "2026-06-13";
10
+ /**
11
+ * Known model-family prefixes mapped to their public list prices (USD per 1M tokens).
12
+ *
13
+ * Real model ids look like "claude-sonnet-4-6-20250930"; we match by prefix so
14
+ * versioned ids resolve correctly. Add new families here as they are released.
15
+ */
16
+ export const MODEL_PRICING = {
17
+ // Opus 4.6 / 4.7 / 4.8 list prices. (Older opus 4.0/4.1 were higher; rare in transcripts.)
18
+ "claude-opus": {
19
+ inputPer1M: 5,
20
+ outputPer1M: 25,
21
+ cacheWritePer1M: 6.25,
22
+ cacheReadPer1M: 0.5,
23
+ },
24
+ "claude-sonnet": {
25
+ inputPer1M: 3,
26
+ outputPer1M: 15,
27
+ cacheWritePer1M: 3.75,
28
+ cacheReadPer1M: 0.3,
29
+ },
30
+ "claude-haiku": {
31
+ inputPer1M: 1,
32
+ outputPer1M: 5,
33
+ cacheWritePer1M: 1.25,
34
+ cacheReadPer1M: 0.1,
35
+ },
36
+ // Fable 5 (Mythos-tier) sits above Opus on price.
37
+ "claude-fable": {
38
+ inputPer1M: 10,
39
+ outputPer1M: 50,
40
+ cacheWritePer1M: 12.5,
41
+ cacheReadPer1M: 1.0,
42
+ },
43
+ };
44
+ /**
45
+ * Finds the ModelPricing entry for a given model id by checking which known
46
+ * prefix the id starts with. Returns undefined for unknown models (e.g. "<synthetic>").
47
+ */
48
+ function findPricingForModel(modelId) {
49
+ for (const prefix of Object.keys(MODEL_PRICING)) {
50
+ if (modelId.startsWith(prefix)) {
51
+ return MODEL_PRICING[prefix];
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ /**
57
+ * Estimates the cost in USD for a given model and token usage.
58
+ *
59
+ * Returns undefined for model ids that don't match any known prefix (e.g. "<synthetic>"),
60
+ * so the UI can display "cost unavailable" rather than a misleading zero.
61
+ */
62
+ export function estimateCostUsd(modelId, usage) {
63
+ const pricing = findPricingForModel(modelId);
64
+ if (pricing === undefined) {
65
+ return undefined;
66
+ }
67
+ const tokensPerMillion = 1_000_000;
68
+ return ((usage.inputTokens * pricing.inputPer1M) / tokensPerMillion +
69
+ (usage.outputTokens * pricing.outputPer1M) / tokensPerMillion +
70
+ (usage.cacheCreationInputTokens * pricing.cacheWritePer1M) / tokensPerMillion +
71
+ (usage.cacheReadInputTokens * pricing.cacheReadPer1M) / tokensPerMillion);
72
+ }
73
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,wFAAwF;AACxF,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,2FAA2F;IAC3F,aAAa,EAAE;QACb,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,EAAE;QACf,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,GAAG;KACpB;IACD,eAAe,EAAE;QACf,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,EAAE;QACf,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,GAAG;KACpB;IACD,cAAc,EAAE;QACd,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,GAAG;KACpB;IACD,kDAAkD;IAClD,cAAc,EAAE;QACd,UAAU,EAAE,EAAE;QACd,WAAW,EAAE,EAAE;QACf,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,GAAG;KACpB;CACF,CAAC;AAEF;;;GAGG;AACH,SAAS,mBAAmB,CAAC,OAAe;IAC1C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAiB;IAChE,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,gBAAgB,GAAG,SAAS,CAAC;IAEnC,OAAO,CACL,CAAC,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,gBAAgB;QAC3D,CAAC,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,gBAAgB;QAC7D,CAAC,KAAK,CAAC,wBAAwB,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,gBAAgB;QAC7E,CAAC,KAAK,CAAC,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,gBAAgB,CACzE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Project loader: discovers Claude Code projects from ~/.claude/projects/ and
3
+ * parses their .jsonl session files into the internal model.
4
+ *
5
+ * This module is the only place that knows about the ~/.claude/projects/
6
+ * directory layout. The server and UI import only the types from apiTypes.ts
7
+ * and model.ts — never the raw parser shapes.
8
+ */
9
+ import type { SessionSummary } from "./model.js";
10
+ import type { ProjectListing, SessionListItem, SessionDetail } from "./apiTypes.js";
11
+ /**
12
+ * Reads a single .jsonl file and returns its SessionSummary, including populated subagents.
13
+ * Returns null on any read or parse failure (defensive).
14
+ */
15
+ export declare function loadSession(filePath: string): SessionSummary | null;
16
+ /**
17
+ * Converts a SessionSummary to the lightweight SessionListItem shape for the API.
18
+ */
19
+ export declare function toSessionListItem(sessionSummary: SessionSummary, filePath: string): SessionListItem;
20
+ /**
21
+ * Converts a SessionSummary to the full SessionDetail shape for the /api/sessions/:id endpoint.
22
+ * All turns are included in parser order; the UI decides which to render.
23
+ */
24
+ export declare function toSessionDetail(sessionSummary: SessionSummary, filePath: string): SessionDetail;
25
+ /**
26
+ * Loads all projects from ~/.claude/projects/, parsing each .jsonl session file.
27
+ * Returns projects sorted by most-recent session first.
28
+ * Projects or sessions that fail to load are silently skipped.
29
+ */
30
+ export declare function loadAllProjects(): ProjectListing[];
31
+ //# sourceMappingURL=projectLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectLoader.d.ts","sourceRoot":"","sources":["../src/projectLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAA2D,MAAM,YAAY,CAAC;AAE1G,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EAQd,MAAM,eAAe,CAAC;AAIvB;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CASnE;AAkED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,GACf,eAAe,CAmBjB;AAgHD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,GACf,aAAa,CAiBf;AA2CD;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,cAAc,EAAE,CA6ElD"}
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Project loader: discovers Claude Code projects from ~/.claude/projects/ and
3
+ * parses their .jsonl session files into the internal model.
4
+ *
5
+ * This module is the only place that knows about the ~/.claude/projects/
6
+ * directory layout. The server and UI import only the types from apiTypes.ts
7
+ * and model.ts — never the raw parser shapes.
8
+ */
9
+ import { readdirSync, readFileSync, statSync, existsSync } from "fs";
10
+ import { join, dirname, basename } from "path";
11
+ import { homedir } from "os";
12
+ import { parseSessionJsonl, parseSubagentTurns } from "./parser/index.js";
13
+ import { MODEL_PRICING, PRICING_AS_OF_DATE } from "./pricing.js";
14
+ const CLAUDE_PROJECTS_DIR = join(homedir(), ".claude", "projects");
15
+ /**
16
+ * Reads a single .jsonl file and returns its SessionSummary, including populated subagents.
17
+ * Returns null on any read or parse failure (defensive).
18
+ */
19
+ export function loadSession(filePath) {
20
+ try {
21
+ const jsonlText = readFileSync(filePath, "utf-8");
22
+ const baseSummary = parseSessionJsonl(jsonlText);
23
+ const subagents = loadSubagentsForSession(filePath);
24
+ return { ...baseSummary, subagents };
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * Derives the subagents sidecar directory from the session file path,
32
+ * then reads each agent-*.jsonl + agent-*.meta.json pair into a SubagentTrace.
33
+ *
34
+ * Layout: <dirOfFile>/<basenameWithout.jsonl>/subagents/
35
+ *
36
+ * Missing directory, missing/corrupt meta, or unreadable agent file all result
37
+ * in that subagent being silently skipped — never throws.
38
+ */
39
+ function loadSubagentsForSession(sessionFilePath) {
40
+ const sessionFileBasename = basename(sessionFilePath);
41
+ const sessionId = sessionFileBasename.endsWith(".jsonl")
42
+ ? sessionFileBasename.slice(0, -".jsonl".length)
43
+ : sessionFileBasename;
44
+ const subagentDir = join(dirname(sessionFilePath), sessionId, "subagents");
45
+ if (!existsSync(subagentDir)) {
46
+ return [];
47
+ }
48
+ let dirEntries;
49
+ try {
50
+ dirEntries = readdirSync(subagentDir);
51
+ }
52
+ catch {
53
+ return [];
54
+ }
55
+ const agentJsonlFiles = dirEntries.filter((name) => name.startsWith("agent-") && name.endsWith(".jsonl"));
56
+ const subagentTraces = [];
57
+ for (const agentJsonlFilename of agentJsonlFiles) {
58
+ const agentId = agentJsonlFilename
59
+ .replace(/^agent-/, "")
60
+ .replace(/\.jsonl$/, "");
61
+ const agentJsonlPath = join(subagentDir, agentJsonlFilename);
62
+ const agentMetaPath = join(subagentDir, `agent-${agentId}.meta.json`);
63
+ try {
64
+ const agentJsonlText = readFileSync(agentJsonlPath, "utf-8");
65
+ const agentMetaText = readFileSync(agentMetaPath, "utf-8");
66
+ const meta = JSON.parse(agentMetaText);
67
+ const agentType = typeof meta["agentType"] === "string" ? meta["agentType"] : "unknown";
68
+ const description = typeof meta["description"] === "string" ? meta["description"] : "";
69
+ const parentToolUseId = typeof meta["toolUseId"] === "string" ? meta["toolUseId"] : "";
70
+ const turns = parseSubagentTurns(agentJsonlText);
71
+ subagentTraces.push({ agentId, agentType, description, parentToolUseId, turns });
72
+ }
73
+ catch {
74
+ // Skip this subagent — missing or corrupt file
75
+ continue;
76
+ }
77
+ }
78
+ return subagentTraces;
79
+ }
80
+ /**
81
+ * Converts a SessionSummary to the lightweight SessionListItem shape for the API.
82
+ */
83
+ export function toSessionListItem(sessionSummary, filePath) {
84
+ const nonMetaTurnCount = sessionSummary.turns.filter((t) => !t.isMeta).length;
85
+ return {
86
+ sessionId: sessionSummary.sessionId,
87
+ filePath,
88
+ aiTitle: sessionSummary.aiTitle,
89
+ startedAt: sessionSummary.startedAt,
90
+ endedAt: sessionSummary.endedAt,
91
+ durationMs: sessionSummary.durationMs,
92
+ turnCount: nonMetaTurnCount,
93
+ totalUsage: {
94
+ inputTokens: sessionSummary.totalUsage.inputTokens,
95
+ outputTokens: sessionSummary.totalUsage.outputTokens,
96
+ cacheCreationInputTokens: sessionSummary.totalUsage.cacheCreationInputTokens,
97
+ cacheReadInputTokens: sessionSummary.totalUsage.cacheReadInputTokens,
98
+ },
99
+ modelsUsed: Array.from(sessionSummary.modelsUsed),
100
+ unknownEventCount: sessionSummary.unknownEvents.length,
101
+ };
102
+ }
103
+ /**
104
+ * Converts a TokenUsage to the over-the-wire TokenUsageSummary shape.
105
+ */
106
+ function toTokenUsageSummary(usage) {
107
+ return {
108
+ inputTokens: usage.inputTokens,
109
+ outputTokens: usage.outputTokens,
110
+ cacheCreationInputTokens: usage.cacheCreationInputTokens,
111
+ cacheReadInputTokens: usage.cacheReadInputTokens,
112
+ };
113
+ }
114
+ /**
115
+ * Converts a ContentBlock (model) to a ContentBlockJson (API wire type).
116
+ * ThinkingBlock's opaque `signature` field is intentionally dropped.
117
+ */
118
+ function toContentBlockJson(block) {
119
+ switch (block.type) {
120
+ case "text":
121
+ return { type: "text", text: block.text };
122
+ case "thinking":
123
+ return { type: "thinking", thinking: block.thinking };
124
+ case "tool_use":
125
+ return { type: "tool_use", id: block.id, name: block.name, input: block.input };
126
+ case "tool_result": {
127
+ const content = typeof block.content === "string"
128
+ ? block.content
129
+ : Array.from(block.content).map((textBlock) => ({ type: "text", text: textBlock.text }));
130
+ const resultBlock = {
131
+ type: "tool_result",
132
+ tool_use_id: block.tool_use_id,
133
+ content,
134
+ };
135
+ if (block.is_error !== undefined) {
136
+ return { ...resultBlock, is_error: block.is_error };
137
+ }
138
+ return resultBlock;
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Converts a ToolCall (model) to ToolCallJson (API wire type).
144
+ */
145
+ function toToolCallJson(toolCall) {
146
+ return {
147
+ id: toolCall.id,
148
+ name: toolCall.name,
149
+ input: toolCall.input,
150
+ result: toolCall.result,
151
+ isError: toolCall.isError,
152
+ subagentId: toolCall.subagentId,
153
+ };
154
+ }
155
+ /**
156
+ * Converts a Turn (model) to TurnJson (API wire type).
157
+ * The userMessageUuid field is not sent to the UI.
158
+ */
159
+ function toTurnJson(turn) {
160
+ return {
161
+ turnIndex: turn.turnIndex,
162
+ promptId: turn.promptId,
163
+ timestamp: turn.timestamp,
164
+ userText: turn.userText,
165
+ isMeta: turn.isMeta,
166
+ assistantBlocks: Array.from(turn.assistantBlocks).map(toContentBlockJson),
167
+ toolCalls: Array.from(turn.toolCalls).map(toToolCallJson),
168
+ usage: turn.usage !== undefined ? toTokenUsageSummary(turn.usage) : undefined,
169
+ model: turn.model,
170
+ durationMs: turn.durationMs,
171
+ isSidechain: turn.isSidechain,
172
+ };
173
+ }
174
+ /**
175
+ * Converts a SubagentTrace (model) to SubagentTraceJson (API wire type).
176
+ * Reuses toTurnJson for each subagent turn to keep the mapping consistent.
177
+ */
178
+ function toSubagentTraceJson(subagent) {
179
+ return {
180
+ agentId: subagent.agentId,
181
+ agentType: subagent.agentType,
182
+ description: subagent.description,
183
+ parentToolUseId: subagent.parentToolUseId,
184
+ turns: Array.from(subagent.turns).map(toTurnJson),
185
+ };
186
+ }
187
+ /**
188
+ * Builds the pricing table payload from the hand-maintained MODEL_PRICING table.
189
+ * MODEL_PRICING values are structurally identical to ModelPricingJson so they
190
+ * can be spread directly; the readonly modifier on the source fields is erased at runtime.
191
+ */
192
+ function buildPricingTableJson() {
193
+ const models = {};
194
+ for (const [prefix, pricing] of Object.entries(MODEL_PRICING)) {
195
+ models[prefix] = {
196
+ inputPer1M: pricing.inputPer1M,
197
+ outputPer1M: pricing.outputPer1M,
198
+ cacheWritePer1M: pricing.cacheWritePer1M,
199
+ cacheReadPer1M: pricing.cacheReadPer1M,
200
+ };
201
+ }
202
+ return { asOfDate: PRICING_AS_OF_DATE, models };
203
+ }
204
+ /**
205
+ * Converts a SessionSummary to the full SessionDetail shape for the /api/sessions/:id endpoint.
206
+ * All turns are included in parser order; the UI decides which to render.
207
+ */
208
+ export function toSessionDetail(sessionSummary, filePath) {
209
+ const nonMetaTurnCount = sessionSummary.turns.filter((t) => !t.isMeta).length;
210
+ return {
211
+ sessionId: sessionSummary.sessionId,
212
+ filePath,
213
+ aiTitle: sessionSummary.aiTitle,
214
+ startedAt: sessionSummary.startedAt,
215
+ endedAt: sessionSummary.endedAt,
216
+ durationMs: sessionSummary.durationMs,
217
+ turnCount: nonMetaTurnCount,
218
+ totalUsage: toTokenUsageSummary(sessionSummary.totalUsage),
219
+ modelsUsed: Array.from(sessionSummary.modelsUsed),
220
+ unknownEventCount: sessionSummary.unknownEvents.length,
221
+ turns: Array.from(sessionSummary.turns).map(toTurnJson),
222
+ subagents: Array.from(sessionSummary.subagents).map(toSubagentTraceJson),
223
+ pricing: buildPricingTableJson(),
224
+ };
225
+ }
226
+ /**
227
+ * Derives a human-readable display name from the slug.
228
+ * The slug is a cwd path with slashes replaced by hyphens, e.g.:
229
+ * "-Users-alice-Documents-independent-stuff-leetcode" → "Documents/independent-stuff/leetcode"
230
+ * "-home-bob-project" → "project"
231
+ * "-Users-alice" → "Users/alice" (no home-dir prefix match, show as-is)
232
+ *
233
+ * Strips leading "-Users-<username>-" or "-home-<username>-" (the home-dir prefix),
234
+ * then shows the last 2 path segments joined by "/" for readability.
235
+ * If slug doesn't match home patterns or is malformed, falls back to the last segment alone.
236
+ */
237
+ function slugToDisplayName(slug) {
238
+ // Normalize: remove leading hyphen
239
+ const normalized = slug.startsWith("-") ? slug.slice(1) : slug;
240
+ const parts = normalized.split("-").filter((s) => s.length > 0);
241
+ if (parts.length === 0) {
242
+ return slug;
243
+ }
244
+ // Try to detect and strip home-dir prefix: "-Users-<username>-" or "-home-<username>-"
245
+ let remainingParts = parts;
246
+ if (parts.length >= 2) {
247
+ const firstPart = parts[0];
248
+ if (firstPart === "Users" || firstPart === "home") {
249
+ // Skip the next part (username) and keep the rest
250
+ remainingParts = parts.slice(2);
251
+ }
252
+ }
253
+ // If we stripped everything, fall back to original last segment
254
+ if (remainingParts.length === 0) {
255
+ return parts[parts.length - 1];
256
+ }
257
+ // Show the last 2 path segments, joined by "/"
258
+ const numToShow = Math.min(2, remainingParts.length);
259
+ const displayParts = remainingParts.slice(-numToShow);
260
+ return displayParts.join("/");
261
+ }
262
+ /**
263
+ * Loads all projects from ~/.claude/projects/, parsing each .jsonl session file.
264
+ * Returns projects sorted by most-recent session first.
265
+ * Projects or sessions that fail to load are silently skipped.
266
+ */
267
+ export function loadAllProjects() {
268
+ let projectDirEntries;
269
+ try {
270
+ projectDirEntries = readdirSync(CLAUDE_PROJECTS_DIR);
271
+ }
272
+ catch {
273
+ return [];
274
+ }
275
+ const projects = [];
276
+ for (const entry of projectDirEntries) {
277
+ const entryPath = join(CLAUDE_PROJECTS_DIR, entry);
278
+ let entryIsDirectory;
279
+ try {
280
+ entryIsDirectory = statSync(entryPath).isDirectory();
281
+ }
282
+ catch {
283
+ continue;
284
+ }
285
+ if (!entryIsDirectory)
286
+ continue;
287
+ // Each project dir contains .jsonl files (sessions) and possibly subdirectories
288
+ // (subagent files, memory). We only parse the root-level .jsonl files.
289
+ let projectEntries;
290
+ try {
291
+ projectEntries = readdirSync(entryPath);
292
+ }
293
+ catch {
294
+ continue;
295
+ }
296
+ const jsonlFiles = projectEntries.filter((name) => name.endsWith(".jsonl") && !name.includes("/"));
297
+ if (jsonlFiles.length === 0)
298
+ continue;
299
+ const sessions = [];
300
+ for (const jsonlFile of jsonlFiles) {
301
+ const filePath = join(entryPath, jsonlFile);
302
+ const summary = loadSession(filePath);
303
+ if (summary === null)
304
+ continue;
305
+ sessions.push(toSessionListItem(summary, filePath));
306
+ }
307
+ if (sessions.length === 0)
308
+ continue;
309
+ // Sort sessions by startedAt descending (most recent first)
310
+ sessions.sort((sessionA, sessionB) => {
311
+ const timeA = sessionA.startedAt ? new Date(sessionA.startedAt).getTime() : 0;
312
+ const timeB = sessionB.startedAt ? new Date(sessionB.startedAt).getTime() : 0;
313
+ return timeB - timeA;
314
+ });
315
+ const mostRecentSessionAt = sessions[0].startedAt;
316
+ projects.push({
317
+ slug: entry,
318
+ displayName: slugToDisplayName(entry),
319
+ sessions,
320
+ mostRecentSessionAt,
321
+ });
322
+ }
323
+ // Sort projects by most-recent session first
324
+ projects.sort((projectA, projectB) => {
325
+ const timeA = projectA.mostRecentSessionAt
326
+ ? new Date(projectA.mostRecentSessionAt).getTime()
327
+ : 0;
328
+ const timeB = projectB.mostRecentSessionAt
329
+ ? new Date(projectB.mostRecentSessionAt).getTime()
330
+ : 0;
331
+ return timeB - timeA;
332
+ });
333
+ return projects;
334
+ }
335
+ //# sourceMappingURL=projectLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectLoader.js","sourceRoot":"","sources":["../src/projectLoader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * CLI script: print a turn-by-turn text summary of a Claude Code session JSONL file.
3
+ *
4
+ * Usage: npm run summarize -- <path-to-jsonl>
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=summarize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../../src/scripts/summarize.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * CLI script: print a turn-by-turn text summary of a Claude Code session JSONL file.
3
+ *
4
+ * Usage: npm run summarize -- <path-to-jsonl>
5
+ */
6
+ import { readFileSync } from "fs";
7
+ import { resolve } from "path";
8
+ import { parseSessionJsonl } from "../parser/index.js";
9
+ const args = process.argv.slice(2);
10
+ if (args.length === 0) {
11
+ console.error("Usage: npm run summarize -- <path-to-jsonl>");
12
+ process.exit(1);
13
+ }
14
+ const filePath = resolve(args[0]);
15
+ let jsonlText;
16
+ try {
17
+ jsonlText = readFileSync(filePath, "utf-8");
18
+ }
19
+ catch (err) {
20
+ console.error(`Error reading file: ${filePath}`);
21
+ console.error(err);
22
+ process.exit(1);
23
+ }
24
+ const summary = parseSessionJsonl(jsonlText);
25
+ // ---------------------------------------------------------------------------
26
+ // Print header
27
+ // ---------------------------------------------------------------------------
28
+ console.log("=".repeat(72));
29
+ console.log(`SESSION: ${summary.sessionId}`);
30
+ if (summary.aiTitle) {
31
+ console.log(`TITLE: ${summary.aiTitle}`);
32
+ }
33
+ if (summary.startedAt) {
34
+ const startDate = new Date(summary.startedAt).toLocaleString();
35
+ const durationSec = summary.durationMs
36
+ ? ` (${(summary.durationMs / 1000).toFixed(0)}s)`
37
+ : "";
38
+ console.log(`STARTED: ${startDate}${durationSec}`);
39
+ }
40
+ const { totalUsage } = summary;
41
+ console.log(`TOKENS: input=${totalUsage.inputTokens} output=${totalUsage.outputTokens} ` +
42
+ `cache_read=${totalUsage.cacheReadInputTokens} cache_create=${totalUsage.cacheCreationInputTokens}`);
43
+ if (summary.modelsUsed.length > 0) {
44
+ console.log(`MODELS: ${summary.modelsUsed.join(", ")}`);
45
+ }
46
+ console.log(`TURNS: ${summary.turns.length} total`);
47
+ if (summary.unknownEvents.length > 0) {
48
+ console.log(`UNKNOWN EVENTS: ${summary.unknownEvents.length} (unrecognized line types)`);
49
+ }
50
+ console.log("=".repeat(72));
51
+ console.log();
52
+ // ---------------------------------------------------------------------------
53
+ // Filter to non-meta turns for the summary
54
+ // ---------------------------------------------------------------------------
55
+ const nonMetaTurns = summary.turns.filter((t) => !t.isMeta);
56
+ const metaCount = summary.turns.length - nonMetaTurns.length;
57
+ if (metaCount > 0) {
58
+ console.log(`(${metaCount} meta/system turns omitted)\n`);
59
+ }
60
+ if (nonMetaTurns.length === 0) {
61
+ console.log("No conversation turns found.");
62
+ process.exit(0);
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Print each turn
66
+ // ---------------------------------------------------------------------------
67
+ for (const turn of nonMetaTurns) {
68
+ const turnLabel = `TURN ${turn.turnIndex + 1}`;
69
+ const timeLabel = turn.timestamp
70
+ ? ` [${new Date(turn.timestamp).toLocaleTimeString()}]`
71
+ : "";
72
+ const durationLabel = turn.durationMs
73
+ ? ` (${(turn.durationMs / 1000).toFixed(1)}s)`
74
+ : "";
75
+ const sidechainLabel = turn.isSidechain ? " [SIDECHAIN]" : "";
76
+ console.log("-".repeat(72));
77
+ console.log(`${turnLabel}${timeLabel}${durationLabel}${sidechainLabel} model=${turn.model ?? "?"}`);
78
+ // User message
79
+ if (turn.userText) {
80
+ const truncated = turn.userText.length > 200
81
+ ? turn.userText.slice(0, 200) + "…"
82
+ : turn.userText;
83
+ console.log(` USER: ${truncated}`);
84
+ }
85
+ // Token usage
86
+ if (turn.usage) {
87
+ const u = turn.usage;
88
+ console.log(` USAGE: in=${u.inputTokens} out=${u.outputTokens} ` +
89
+ `cache_read=${u.cacheReadInputTokens} cache_create=${u.cacheCreationInputTokens}`);
90
+ }
91
+ // Assistant content blocks
92
+ const thinkingBlocks = turn.assistantBlocks.filter((b) => b.type === "thinking");
93
+ const textBlocks = turn.assistantBlocks.filter((b) => b.type === "text");
94
+ const toolUseBlocks = turn.assistantBlocks.filter((b) => b.type === "tool_use");
95
+ if (thinkingBlocks.length > 0) {
96
+ console.log(` THINKING: [${thinkingBlocks.length} block(s) — collapsed]`);
97
+ }
98
+ for (const block of textBlocks) {
99
+ if (block.type !== "text")
100
+ continue;
101
+ const truncated = block.text.length > 300 ? block.text.slice(0, 300) + "…" : block.text;
102
+ console.log(` ASSISTANT: ${truncated}`);
103
+ }
104
+ // Tool calls
105
+ for (const toolCall of turn.toolCalls) {
106
+ const inputSummary = formatToolInput(toolCall.input);
107
+ const resultSummary = toolCall.result
108
+ ? `→ ${toolCall.result.slice(0, 100).replace(/\n/g, " ")}${toolCall.result.length > 100 ? "…" : ""}`
109
+ : toolCall.subagentId
110
+ ? `→ [subagent: ${toolCall.subagentId}]`
111
+ : "→ [no result]";
112
+ const errorMark = toolCall.isError ? " [ERROR]" : "";
113
+ console.log(` TOOL ${toolCall.name}(${inputSummary})${errorMark}`);
114
+ console.log(` ${resultSummary}`);
115
+ }
116
+ console.log();
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Unknown events summary
120
+ // ---------------------------------------------------------------------------
121
+ if (summary.unknownEvents.length > 0) {
122
+ console.log("=".repeat(72));
123
+ console.log(`UNKNOWN LINE TYPES:`);
124
+ const typeCounts = new Map();
125
+ for (const ev of summary.unknownEvents) {
126
+ typeCounts.set(ev.rawType, (typeCounts.get(ev.rawType) ?? 0) + 1);
127
+ }
128
+ for (const [rawType, count] of typeCounts) {
129
+ console.log(` ${rawType}: ${count} line(s)`);
130
+ }
131
+ console.log();
132
+ }
133
+ // ---------------------------------------------------------------------------
134
+ // Helpers
135
+ // ---------------------------------------------------------------------------
136
+ function formatToolInput(input) {
137
+ const keys = Object.keys(input);
138
+ if (keys.length === 0)
139
+ return "";
140
+ if (keys.length === 1) {
141
+ const value = String(input[keys[0]] ?? "");
142
+ const truncated = value.length > 60 ? value.slice(0, 60) + "…" : value;
143
+ return `${keys[0]}=${JSON.stringify(truncated)}`;
144
+ }
145
+ return keys
146
+ .slice(0, 3)
147
+ .map((k) => {
148
+ const value = String(input[k] ?? "");
149
+ return `${k}=${JSON.stringify(value.length > 30 ? value.slice(0, 30) + "…" : value)}`;
150
+ })
151
+ .join(", ");
152
+ }
153
+ //# sourceMappingURL=summarize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.js","sourceRoot":"","sources":["../../src/scripts/summarize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Fastify HTTP server for tracelight.
3
+ *
4
+ * Serves:
5
+ * - GET /api/projects — list of all projects with session summaries
6
+ * - GET /api/sessions/:id — full session detail by sessionId
7
+ * - Static files from the Vite build output (ui/dist/)
8
+ *
9
+ * The server imports only from model.ts and apiTypes.ts — never from parser/.
10
+ */
11
+ export interface ServerOptions {
12
+ port: number;
13
+ }
14
+ export declare function createServer(options: ServerOptions): Promise<{
15
+ start: () => Promise<string>;
16
+ stop: () => Promise<void>;
17
+ }>;
18
+ //# sourceMappingURL=index.d.ts.map