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.
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/apiTypes.d.ts +139 -0
- package/dist/apiTypes.d.ts.map +1 -0
- package/dist/apiTypes.js +11 -0
- package/dist/apiTypes.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +73 -0
- package/dist/cli.js.map +1 -0
- package/dist/model.d.ts +133 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +20 -0
- package/dist/model.js.map +1 -0
- package/dist/parser/index.d.ts +27 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +434 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/rawTypes.d.ts +149 -0
- package/dist/parser/rawTypes.d.ts.map +1 -0
- package/dist/parser/rawTypes.js +11 -0
- package/dist/parser/rawTypes.js.map +1 -0
- package/dist/pricing.d.ts +35 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +73 -0
- package/dist/pricing.js.map +1 -0
- package/dist/projectLoader.d.ts +31 -0
- package/dist/projectLoader.d.ts.map +1 -0
- package/dist/projectLoader.js +335 -0
- package/dist/projectLoader.js.map +1 -0
- package/dist/scripts/summarize.d.ts +7 -0
- package/dist/scripts/summarize.d.ts.map +1 -0
- package/dist/scripts/summarize.js +153 -0
- package/dist/scripts/summarize.js.map +1 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +100 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +70 -0
- package/ui/dist/assets/index-Bnr6kWU4.js +62 -0
- package/ui/dist/assets/index-HoOM9YCS.css +1 -0
- package/ui/dist/index.html +13 -0
package/dist/pricing.js
ADDED
|
@@ -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 @@
|
|
|
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
|