heyiam 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/app/dist/assets/index-BGQkmy7q.css +1 -0
- package/app/dist/assets/index-CbLHxerW.js +14 -0
- package/app/dist/favicon.svg +1 -0
- package/app/dist/icons.svg +24 -0
- package/app/dist/index.html +20 -0
- package/dist/analyzer.d.ts +96 -0
- package/dist/analyzer.js +249 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/auth.d.ts +34 -0
- package/dist/auth.js +99 -0
- package/dist/auth.js.map +1 -0
- package/dist/bridge.d.ts +32 -0
- package/dist/bridge.js +211 -0
- package/dist/bridge.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic-provider.d.ts +11 -0
- package/dist/llm/anthropic-provider.js +16 -0
- package/dist/llm/anthropic-provider.js.map +1 -0
- package/dist/llm/index.d.ts +16 -0
- package/dist/llm/index.js +25 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/project-enhance.d.ts +71 -0
- package/dist/llm/project-enhance.js +236 -0
- package/dist/llm/project-enhance.js.map +1 -0
- package/dist/llm/proxy-provider.d.ts +16 -0
- package/dist/llm/proxy-provider.js +60 -0
- package/dist/llm/proxy-provider.js.map +1 -0
- package/dist/llm/triage.d.ts +66 -0
- package/dist/llm/triage.js +283 -0
- package/dist/llm/triage.js.map +1 -0
- package/dist/llm/types.d.ts +19 -0
- package/dist/llm/types.js +2 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/machine-key.d.ts +10 -0
- package/dist/machine-key.js +51 -0
- package/dist/machine-key.js.map +1 -0
- package/dist/parsers/claude.d.ts +18 -0
- package/dist/parsers/claude.js +265 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/index.d.ts +28 -0
- package/dist/parsers/index.js +124 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/types.d.ts +81 -0
- package/dist/parsers/types.js +2 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +857 -0
- package/dist/server.js.map +1 -0
- package/dist/settings.d.ts +92 -0
- package/dist/settings.js +160 -0
- package/dist/settings.js.map +1 -0
- package/dist/summarize.d.ts +72 -0
- package/dist/summarize.js +312 -0
- package/dist/summarize.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a Claude Code .jsonl session file into structured analysis.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code sessions are newline-delimited JSON with entry types:
|
|
6
|
+
* - user: user messages (may contain tool_result content blocks)
|
|
7
|
+
* - assistant: model responses (text, thinking, tool_use blocks)
|
|
8
|
+
* - system: metadata (subtypes: turn_duration, api_error, compact_boundary, etc.)
|
|
9
|
+
* - progress: hook/streaming progress events
|
|
10
|
+
* - file-history-snapshot, agent-name, custom-title, last-prompt, queue-operation
|
|
11
|
+
*
|
|
12
|
+
* Tool calls appear as { type: "tool_use", id, name, input } content blocks
|
|
13
|
+
* inside assistant messages. Tool results appear as { type: "tool_result" }
|
|
14
|
+
* blocks inside subsequent user messages.
|
|
15
|
+
*/
|
|
16
|
+
function parseEntries(raw) {
|
|
17
|
+
const entries = [];
|
|
18
|
+
for (const line of raw.split("\n")) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (!trimmed)
|
|
21
|
+
continue;
|
|
22
|
+
try {
|
|
23
|
+
entries.push(JSON.parse(trimmed));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// skip malformed lines
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return entries;
|
|
30
|
+
}
|
|
31
|
+
function isToolUseBlock(block) {
|
|
32
|
+
return block.type === "tool_use";
|
|
33
|
+
}
|
|
34
|
+
function getContentBlocks(entry) {
|
|
35
|
+
const content = entry.message?.content;
|
|
36
|
+
if (!content || typeof content === "string")
|
|
37
|
+
return [];
|
|
38
|
+
return content;
|
|
39
|
+
}
|
|
40
|
+
function extractToolCalls(entries) {
|
|
41
|
+
const calls = [];
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry.type !== "assistant")
|
|
44
|
+
continue;
|
|
45
|
+
for (const block of getContentBlocks(entry)) {
|
|
46
|
+
if (isToolUseBlock(block)) {
|
|
47
|
+
calls.push({
|
|
48
|
+
id: block.id,
|
|
49
|
+
name: block.name,
|
|
50
|
+
input: block.input,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return calls;
|
|
56
|
+
}
|
|
57
|
+
function extractFilesTouched(toolCalls) {
|
|
58
|
+
const files = new Set();
|
|
59
|
+
for (const call of toolCalls) {
|
|
60
|
+
const input = call.input;
|
|
61
|
+
switch (call.name) {
|
|
62
|
+
case "Read":
|
|
63
|
+
case "Write":
|
|
64
|
+
if (typeof input.file_path === "string")
|
|
65
|
+
files.add(input.file_path);
|
|
66
|
+
break;
|
|
67
|
+
case "Edit":
|
|
68
|
+
if (typeof input.file_path === "string")
|
|
69
|
+
files.add(input.file_path);
|
|
70
|
+
break;
|
|
71
|
+
case "Glob":
|
|
72
|
+
case "Grep":
|
|
73
|
+
if (typeof input.path === "string")
|
|
74
|
+
files.add(input.path);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [...files].sort();
|
|
79
|
+
}
|
|
80
|
+
function countTurns(entries) {
|
|
81
|
+
let turns = 0;
|
|
82
|
+
let lastRole = null;
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
if (entry.type === "user" || entry.type === "assistant") {
|
|
85
|
+
const role = entry.type;
|
|
86
|
+
// A turn is a user→assistant exchange. Count each time we see
|
|
87
|
+
// an assistant message following a user message (directly or
|
|
88
|
+
// with intervening system/progress entries).
|
|
89
|
+
if (role === "assistant" && lastRole === "user") {
|
|
90
|
+
turns++;
|
|
91
|
+
}
|
|
92
|
+
lastRole = role;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return turns;
|
|
96
|
+
}
|
|
97
|
+
/** Max gap between consecutive entries before it's considered a break (5 min). */
|
|
98
|
+
const IDLE_THRESHOLD_MS = 5 * 60 * 1000;
|
|
99
|
+
function computeDuration(entries) {
|
|
100
|
+
const timestamps = [];
|
|
101
|
+
let startStr = null;
|
|
102
|
+
let endStr = null;
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
if (!entry.timestamp)
|
|
105
|
+
continue;
|
|
106
|
+
if (!startStr)
|
|
107
|
+
startStr = entry.timestamp;
|
|
108
|
+
endStr = entry.timestamp;
|
|
109
|
+
timestamps.push(new Date(entry.timestamp).getTime());
|
|
110
|
+
}
|
|
111
|
+
if (timestamps.length < 2 || !startStr || !endStr) {
|
|
112
|
+
return { duration_ms: 0, wall_clock_ms: 0, start_time: startStr, end_time: endStr };
|
|
113
|
+
}
|
|
114
|
+
const wallClock = timestamps[timestamps.length - 1] - timestamps[0];
|
|
115
|
+
// Sum only active segments (gaps under threshold)
|
|
116
|
+
let activeMs = 0;
|
|
117
|
+
for (let i = 1; i < timestamps.length; i++) {
|
|
118
|
+
const gap = timestamps[i] - timestamps[i - 1];
|
|
119
|
+
if (gap < IDLE_THRESHOLD_MS) {
|
|
120
|
+
activeMs += gap;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
duration_ms: Math.max(activeMs, 0),
|
|
125
|
+
wall_clock_ms: Math.max(wallClock, 0),
|
|
126
|
+
start_time: startStr,
|
|
127
|
+
end_time: endStr,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export function computeLocStats(entries) {
|
|
131
|
+
const toolCalls = extractToolCalls(entries);
|
|
132
|
+
let totalAdded = 0;
|
|
133
|
+
let totalRemoved = 0;
|
|
134
|
+
const filesChanged = new Set();
|
|
135
|
+
// Track last-write line counts per file for dedup
|
|
136
|
+
const writeLineCounts = new Map();
|
|
137
|
+
for (const call of toolCalls) {
|
|
138
|
+
if (call.name === "Write") {
|
|
139
|
+
const filePath = call.input.file_path;
|
|
140
|
+
const content = call.input.content;
|
|
141
|
+
if (typeof filePath !== "string" || typeof content !== "string")
|
|
142
|
+
continue;
|
|
143
|
+
const lines = content.split("\n").length;
|
|
144
|
+
const prevLines = writeLineCounts.get(filePath) ?? 0;
|
|
145
|
+
if (writeLineCounts.has(filePath)) {
|
|
146
|
+
// Overwrite: remove previous count, add new
|
|
147
|
+
totalAdded -= prevLines;
|
|
148
|
+
totalAdded += lines;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
totalAdded += lines;
|
|
152
|
+
}
|
|
153
|
+
writeLineCounts.set(filePath, lines);
|
|
154
|
+
filesChanged.add(filePath);
|
|
155
|
+
}
|
|
156
|
+
else if (call.name === "Edit") {
|
|
157
|
+
const filePath = call.input.file_path;
|
|
158
|
+
const oldStr = call.input.old_string;
|
|
159
|
+
const newStr = call.input.new_string;
|
|
160
|
+
if (typeof filePath !== "string")
|
|
161
|
+
continue;
|
|
162
|
+
const oldLines = typeof oldStr === "string" ? oldStr.split("\n").length : 0;
|
|
163
|
+
const newLines = typeof newStr === "string" ? newStr.split("\n").length : 0;
|
|
164
|
+
totalAdded += newLines;
|
|
165
|
+
totalRemoved += oldLines;
|
|
166
|
+
filesChanged.add(filePath);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
loc_added: totalAdded,
|
|
171
|
+
loc_removed: totalRemoved,
|
|
172
|
+
loc_net: totalAdded - totalRemoved,
|
|
173
|
+
files_changed: [...filesChanged].sort(),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async function detect(path) {
|
|
177
|
+
// Claude Code session files are .jsonl in ~/.claude/projects/
|
|
178
|
+
if (!path.endsWith(".jsonl"))
|
|
179
|
+
return false;
|
|
180
|
+
try {
|
|
181
|
+
const raw = await readFile(path, "utf-8");
|
|
182
|
+
const firstLine = raw.split("\n")[0];
|
|
183
|
+
if (!firstLine)
|
|
184
|
+
return false;
|
|
185
|
+
const entry = JSON.parse(firstLine);
|
|
186
|
+
// Claude sessions have sessionId, type, and typically version fields
|
|
187
|
+
return (typeof entry.sessionId === "string" &&
|
|
188
|
+
typeof entry.type === "string" &&
|
|
189
|
+
typeof entry.version === "string");
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Map subagent_type values from Agent tool calls to display roles.
|
|
197
|
+
* Teamrc agent names like "trc-frontend-dev" get the prefix stripped.
|
|
198
|
+
* Built-in types like "Explore" or "Plan" are lowercased.
|
|
199
|
+
*/
|
|
200
|
+
export function mapAgentRole(subagentType) {
|
|
201
|
+
if (subagentType.startsWith("trc-")) {
|
|
202
|
+
return subagentType.slice(4); // "trc-frontend-dev" → "frontend-dev"
|
|
203
|
+
}
|
|
204
|
+
return subagentType.toLowerCase(); // "Explore" → "explore"
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Extract agent roles from parent's Agent tool calls.
|
|
208
|
+
* Returns a map of tool_use id → agentRole for matching with child sessions.
|
|
209
|
+
*/
|
|
210
|
+
export function extractAgentRoles(entries) {
|
|
211
|
+
const roles = new Map();
|
|
212
|
+
for (const entry of entries) {
|
|
213
|
+
if (entry.type !== "assistant")
|
|
214
|
+
continue;
|
|
215
|
+
for (const block of getContentBlocks(entry)) {
|
|
216
|
+
if (isToolUseBlock(block) && block.name === "Agent") {
|
|
217
|
+
const subagentType = block.input.subagent_type;
|
|
218
|
+
if (typeof subagentType === "string") {
|
|
219
|
+
roles.set(block.id, mapAgentRole(subagentType));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return roles;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Extract the agentId from a child session's first entry (fallback role detection).
|
|
228
|
+
*/
|
|
229
|
+
export function extractAgentIdFromEntries(entries) {
|
|
230
|
+
for (const entry of entries) {
|
|
231
|
+
if (entry.agentId)
|
|
232
|
+
return entry.agentId;
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
async function parse(path) {
|
|
237
|
+
const raw = await readFile(path, "utf-8");
|
|
238
|
+
const entries = parseEntries(raw);
|
|
239
|
+
const toolCalls = extractToolCalls(entries);
|
|
240
|
+
const filesTouched = extractFilesTouched(toolCalls);
|
|
241
|
+
const turns = countTurns(entries);
|
|
242
|
+
const { duration_ms, wall_clock_ms, start_time, end_time } = computeDuration(entries);
|
|
243
|
+
const loc_stats = computeLocStats(entries);
|
|
244
|
+
// Extract cwd from the first entry that has it
|
|
245
|
+
const cwd = entries.find((e) => e.cwd)?.cwd;
|
|
246
|
+
return {
|
|
247
|
+
source: "claude",
|
|
248
|
+
turns,
|
|
249
|
+
tool_calls: toolCalls,
|
|
250
|
+
files_touched: filesTouched,
|
|
251
|
+
duration_ms,
|
|
252
|
+
wall_clock_ms,
|
|
253
|
+
loc_stats,
|
|
254
|
+
raw_entries: entries,
|
|
255
|
+
start_time,
|
|
256
|
+
end_time,
|
|
257
|
+
cwd,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
export const claudeParser = {
|
|
261
|
+
name: "claude",
|
|
262
|
+
detect,
|
|
263
|
+
parse,
|
|
264
|
+
};
|
|
265
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/parsers/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SessionAnalysis } from "./types.js";
|
|
2
|
+
export type { SessionAnalysis, SessionParser, SessionSource, ToolCall, LocStats, RawEntry } from "./types.js";
|
|
3
|
+
/** Detect which parser handles a given file and parse it */
|
|
4
|
+
export declare function parseSession(path: string): Promise<SessionAnalysis>;
|
|
5
|
+
export interface SessionMeta {
|
|
6
|
+
path: string;
|
|
7
|
+
source: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
/** The top-level project directory name (e.g., "-Users-ben-Dev-myapp") */
|
|
10
|
+
projectDir: string;
|
|
11
|
+
/** Whether this is a subagent session */
|
|
12
|
+
isSubagent: boolean;
|
|
13
|
+
parentSessionId?: string;
|
|
14
|
+
agentRole?: string;
|
|
15
|
+
children?: SessionMeta[];
|
|
16
|
+
}
|
|
17
|
+
/** Scan for all Claude Code session files under a base path.
|
|
18
|
+
*
|
|
19
|
+
* Claude Code stores sessions as:
|
|
20
|
+
* ~/.claude/projects/{encoded-path}/{uuid}.jsonl ← main sessions
|
|
21
|
+
* ~/.claude/projects/{encoded-path}/{uuid}/subagents/{id}.jsonl ← subagent sessions
|
|
22
|
+
*
|
|
23
|
+
* Children are linked to parents by matching the directory name ({uuid}/)
|
|
24
|
+
* to the parent's session file ({uuid}.jsonl). By default, only parent
|
|
25
|
+
* sessions are returned at the top level; children are nested in the
|
|
26
|
+
* parent's `children` array.
|
|
27
|
+
*/
|
|
28
|
+
export declare function listSessions(basePath?: string): Promise<SessionMeta[]>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { claudeParser, mapAgentRole } from "./claude.js";
|
|
5
|
+
const parsers = [claudeParser];
|
|
6
|
+
/** Detect which parser handles a given file and parse it */
|
|
7
|
+
export async function parseSession(path) {
|
|
8
|
+
for (const parser of parsers) {
|
|
9
|
+
if (await parser.detect(path)) {
|
|
10
|
+
return parser.parse(path);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`No parser detected for: ${path}`);
|
|
14
|
+
}
|
|
15
|
+
/** Scan for all Claude Code session files under a base path.
|
|
16
|
+
*
|
|
17
|
+
* Claude Code stores sessions as:
|
|
18
|
+
* ~/.claude/projects/{encoded-path}/{uuid}.jsonl ← main sessions
|
|
19
|
+
* ~/.claude/projects/{encoded-path}/{uuid}/subagents/{id}.jsonl ← subagent sessions
|
|
20
|
+
*
|
|
21
|
+
* Children are linked to parents by matching the directory name ({uuid}/)
|
|
22
|
+
* to the parent's session file ({uuid}.jsonl). By default, only parent
|
|
23
|
+
* sessions are returned at the top level; children are nested in the
|
|
24
|
+
* parent's `children` array.
|
|
25
|
+
*/
|
|
26
|
+
export async function listSessions(basePath) {
|
|
27
|
+
const base = basePath ?? join(homedir(), ".claude", "projects");
|
|
28
|
+
const parents = [];
|
|
29
|
+
const childrenByParentId = new Map();
|
|
30
|
+
let projectDirs;
|
|
31
|
+
try {
|
|
32
|
+
projectDirs = await readdir(base, { withFileTypes: true });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return parents;
|
|
36
|
+
}
|
|
37
|
+
for (const projectEntry of projectDirs) {
|
|
38
|
+
if (!projectEntry.isDirectory())
|
|
39
|
+
continue;
|
|
40
|
+
const projectPath = join(base, projectEntry.name);
|
|
41
|
+
const projectDir = projectEntry.name;
|
|
42
|
+
let files;
|
|
43
|
+
try {
|
|
44
|
+
files = await readdir(projectPath, { withFileTypes: true });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
if (file.name.endsWith(".jsonl") && !file.isDirectory()) {
|
|
51
|
+
// Main session file
|
|
52
|
+
const fullPath = join(projectPath, file.name);
|
|
53
|
+
const sessionId = file.name.replace(/\.jsonl$/, "");
|
|
54
|
+
await tryAddSession(fullPath, sessionId, projectDir, false, parents);
|
|
55
|
+
}
|
|
56
|
+
else if (file.isDirectory()) {
|
|
57
|
+
// Directory name is the parent session UUID
|
|
58
|
+
const parentSessionId = file.name;
|
|
59
|
+
const children = await collectSubagents(join(projectPath, file.name), projectDir, parentSessionId);
|
|
60
|
+
if (children.length > 0) {
|
|
61
|
+
const existing = childrenByParentId.get(parentSessionId) ?? [];
|
|
62
|
+
existing.push(...children);
|
|
63
|
+
childrenByParentId.set(parentSessionId, existing);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Link children to parents
|
|
69
|
+
for (const parent of parents) {
|
|
70
|
+
const children = childrenByParentId.get(parent.sessionId);
|
|
71
|
+
if (children && children.length > 0) {
|
|
72
|
+
parent.children = children;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return parents;
|
|
76
|
+
}
|
|
77
|
+
async function collectSubagents(sessionDataDir, projectDir, parentSessionId) {
|
|
78
|
+
const subagentsDir = join(sessionDataDir, "subagents");
|
|
79
|
+
const children = [];
|
|
80
|
+
let files;
|
|
81
|
+
try {
|
|
82
|
+
files = await readdir(subagentsDir, { withFileTypes: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return children; // No subagents directory
|
|
86
|
+
}
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
if (!file.name.endsWith(".jsonl") || file.isDirectory())
|
|
89
|
+
continue;
|
|
90
|
+
const fullPath = join(subagentsDir, file.name);
|
|
91
|
+
const sessionId = file.name.replace(/\.jsonl$/, "");
|
|
92
|
+
// Try to read .meta.json for agent type/role
|
|
93
|
+
const metaPath = join(subagentsDir, file.name.replace(/\.jsonl$/, ".meta.json"));
|
|
94
|
+
let agentRole;
|
|
95
|
+
try {
|
|
96
|
+
const metaRaw = await readFile(metaPath, "utf-8");
|
|
97
|
+
const meta = JSON.parse(metaRaw);
|
|
98
|
+
if (meta.agentType) {
|
|
99
|
+
agentRole = mapAgentRole(meta.agentType);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// No meta.json or malformed — role will be undefined
|
|
104
|
+
}
|
|
105
|
+
await tryAddSession(fullPath, sessionId, projectDir, true, children, parentSessionId, agentRole);
|
|
106
|
+
}
|
|
107
|
+
return children;
|
|
108
|
+
}
|
|
109
|
+
async function tryAddSession(fullPath, sessionId, projectDir, isSubagent, out, parentSessionId, agentRole) {
|
|
110
|
+
for (const parser of parsers) {
|
|
111
|
+
if (await parser.detect(fullPath)) {
|
|
112
|
+
const meta = { path: fullPath, source: parser.name, sessionId, projectDir, isSubagent };
|
|
113
|
+
if (parentSessionId) {
|
|
114
|
+
meta.parentSessionId = parentSessionId;
|
|
115
|
+
}
|
|
116
|
+
if (agentRole) {
|
|
117
|
+
meta.agentRole = agentRole;
|
|
118
|
+
}
|
|
119
|
+
out.push(meta);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAqB,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKzD,MAAM,OAAO,GAAoB,CAAC,YAAY,CAAC,CAAC;AAEhD,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;AACrD,CAAC;AAeD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAiB;IAClD,MAAM,IAAI,GAAG,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAChE,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE5D,IAAI,WAAW,CAAC;IAChB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,MAAM,YAAY,IAAI,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE;YAAE,SAAS;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC;QAErC,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxD,oBAAoB;gBACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;gBACpD,MAAM,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACvE,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC9B,4CAA4C;gBAC5C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC;gBAClC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;gBACnG,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;oBAC/D,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;oBAC3B,kBAAkB,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,cAAsB,EACtB,UAAkB,EAClB,eAAuB;IAEvB,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC,CAAC,yBAAyB;IAC5C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,SAAS;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAEpD,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;QACjF,IAAI,SAA6B,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA2B,CAAC;YAC3D,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;QAED,MAAM,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,QAAgB,EAChB,SAAiB,EACjB,UAAkB,EAClB,UAAmB,EACnB,GAAkB,EAClB,eAAwB,EACxB,SAAkB;IAElB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,GAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;YACrG,IAAI,eAAe,EAAE,CAAC;gBACpB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;YACzC,CAAC;YACD,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;YAC7B,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type SessionSource = "claude" | "cursor" | "codex" | "gemini" | "antigravity";
|
|
2
|
+
export interface ToolCall {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
input: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface LocStats {
|
|
8
|
+
loc_added: number;
|
|
9
|
+
loc_removed: number;
|
|
10
|
+
loc_net: number;
|
|
11
|
+
files_changed: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface SessionAnalysis {
|
|
14
|
+
source: SessionSource;
|
|
15
|
+
turns: number;
|
|
16
|
+
tool_calls: ToolCall[];
|
|
17
|
+
files_touched: string[];
|
|
18
|
+
/** Active time — excludes idle gaps > 5 min */
|
|
19
|
+
duration_ms: number;
|
|
20
|
+
/** Wall-clock time — first to last timestamp */
|
|
21
|
+
wall_clock_ms: number;
|
|
22
|
+
loc_stats: LocStats;
|
|
23
|
+
raw_entries: RawEntry[];
|
|
24
|
+
start_time: string | null;
|
|
25
|
+
end_time: string | null;
|
|
26
|
+
agent_role?: string;
|
|
27
|
+
parent_session_id?: string | null;
|
|
28
|
+
/** Working directory where the session was started */
|
|
29
|
+
cwd?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Minimal shape of a JSONL entry from Claude Code sessions */
|
|
32
|
+
export interface RawEntry {
|
|
33
|
+
type: string;
|
|
34
|
+
uuid: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
sessionId: string;
|
|
37
|
+
message?: {
|
|
38
|
+
role?: string;
|
|
39
|
+
content?: string | ContentBlock[];
|
|
40
|
+
model?: string;
|
|
41
|
+
id?: string;
|
|
42
|
+
usage?: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
subtype?: string;
|
|
45
|
+
durationMs?: number;
|
|
46
|
+
parentUuid?: string | null;
|
|
47
|
+
isSidechain?: boolean;
|
|
48
|
+
cwd?: string;
|
|
49
|
+
version?: string;
|
|
50
|
+
gitBranch?: string;
|
|
51
|
+
agentId?: string;
|
|
52
|
+
}
|
|
53
|
+
export type ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock | ImageBlock;
|
|
54
|
+
export interface TextBlock {
|
|
55
|
+
type: "text";
|
|
56
|
+
text: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ThinkingBlock {
|
|
59
|
+
type: "thinking";
|
|
60
|
+
thinking: string;
|
|
61
|
+
}
|
|
62
|
+
export interface ToolUseBlock {
|
|
63
|
+
type: "tool_use";
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
input: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
export interface ToolResultBlock {
|
|
69
|
+
type: "tool_result";
|
|
70
|
+
tool_use_id: string;
|
|
71
|
+
content?: unknown;
|
|
72
|
+
}
|
|
73
|
+
export interface ImageBlock {
|
|
74
|
+
type: "image";
|
|
75
|
+
source: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
export interface SessionParser {
|
|
78
|
+
name: string;
|
|
79
|
+
detect(path: string): Promise<boolean>;
|
|
80
|
+
parse(path: string): Promise<SessionAnalysis>;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/parsers/types.ts"],"names":[],"mappings":""}
|
package/dist/server.d.ts
ADDED