pi-forge 1.2.0 → 1.2.1

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.
@@ -0,0 +1,490 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { config } from "./config.js";
5
+ import { ripgrepAvailable } from "./file-searcher.js";
6
+ import { readProjects } from "./project-manager.js";
7
+ const SNIPPET_CONTEXT = 60;
8
+ export async function searchSessions(opts) {
9
+ const projects = await readProjects();
10
+ const projectById = new Map(projects.map((p) => [p.id, p]));
11
+ const lineHits = (await ripgrepAvailable())
12
+ ? await collectWithRipgrep(opts)
13
+ : await collectInProcess(opts);
14
+ const grouped = new Map();
15
+ // Walk hits in `(file, lineNumber)` order so we can compute messageIndex
16
+ // (count of `type === "message"` lines preceding this one) without
17
+ // re-reading entire files. `collectWithRipgrep` and `collectInProcess`
18
+ // both honor that ordering.
19
+ for (const hit of lineHits) {
20
+ const projectId = projectIdFromPath(hit.filePath);
21
+ if (projectId === undefined)
22
+ continue; // Hit outside the per-project layout
23
+ if (!projectById.has(projectId))
24
+ continue; // Orphaned dir from a deleted project
25
+ // Lazy-initialize the per-file group on first hit; its `messageCounter`
26
+ // tracks the running message-line index within that file so
27
+ // subsequent hits in the same file don't have to rescan.
28
+ let group = grouped.get(hit.filePath);
29
+ if (group === undefined) {
30
+ const sessionId = await readSessionIdFromHeader(hit.filePath);
31
+ if (sessionId === undefined)
32
+ continue; // Corrupt / missing header
33
+ group = {
34
+ sessionId,
35
+ projectId,
36
+ filePath: hit.filePath,
37
+ matches: [],
38
+ messageCounter: 0,
39
+ };
40
+ grouped.set(hit.filePath, group);
41
+ }
42
+ if (group.matches.length >= opts.matchesPerSession)
43
+ continue;
44
+ const parsed = safeParseLine(hit.line);
45
+ if (parsed === undefined)
46
+ continue;
47
+ const extracted = extractSnippet(parsed, opts.query);
48
+ if (extracted === undefined)
49
+ continue;
50
+ // messageIndex tracking: count `type === "message"` lines from the
51
+ // start of the file up to AND INCLUDING this hit. We need to scan
52
+ // the file's intervening lines if we skipped any since the previous
53
+ // hit. The cheap path is "no skipped lines" (consecutive hits) —
54
+ // most queries only hit a handful of distinct lines per file.
55
+ const messageIndex = await advanceMessageIndex(group, hit.lineNumber);
56
+ if (messageIndex === undefined)
57
+ continue;
58
+ group.matches.push({
59
+ messageIndex,
60
+ messageEnvelopeId: typeof parsed.id === "string" ? parsed.id : undefined,
61
+ kind: extracted.kind,
62
+ snippet: extracted.snippet,
63
+ matchOffset: extracted.matchOffset,
64
+ matchLength: extracted.matchLength,
65
+ });
66
+ }
67
+ const results = [];
68
+ let truncated = false;
69
+ // Sort by file mtime (newest first) so recent matches land at the top.
70
+ const fileStats = await Promise.all(Array.from(grouped.values()).map(async (g) => ({
71
+ group: g,
72
+ modifiedAt: await fileMtime(g.filePath),
73
+ sessionName: await readSessionNameFromFile(g.filePath),
74
+ })));
75
+ fileStats.sort((a, b) => (a.modifiedAt < b.modifiedAt ? 1 : -1));
76
+ for (const entry of fileStats) {
77
+ if (results.length >= opts.sessionLimit) {
78
+ truncated = true;
79
+ break;
80
+ }
81
+ const project = projectById.get(entry.group.projectId);
82
+ if (project === undefined)
83
+ continue;
84
+ results.push({
85
+ sessionId: entry.group.sessionId,
86
+ projectId: entry.group.projectId,
87
+ projectName: project.name,
88
+ sessionName: entry.sessionName,
89
+ modifiedAt: entry.modifiedAt,
90
+ matches: entry.group.matches,
91
+ });
92
+ }
93
+ return {
94
+ engine: (await ripgrepAvailable()) ? "ripgrep" : "node",
95
+ results,
96
+ truncated,
97
+ };
98
+ }
99
+ async function collectWithRipgrep(opts) {
100
+ // Hits are bounded by the global session limit × per-session matches —
101
+ // a generous ceiling that prevents runaway output without truncating
102
+ // legitimate workloads. The session-grouping pass downstream applies
103
+ // the actual per-session caps.
104
+ const maxLines = opts.sessionLimit * opts.matchesPerSession * 4;
105
+ const args = [
106
+ "--json",
107
+ "--no-heading",
108
+ "--max-filesize",
109
+ "100M", // session JSONLs can be sizeable
110
+ "--max-count",
111
+ String(maxLines),
112
+ "-i", // case-insensitive — matches the dropdown's "type to find" UX
113
+ "--fixed-strings",
114
+ "--glob",
115
+ "*.jsonl",
116
+ "--",
117
+ opts.query,
118
+ config.sessionDir,
119
+ ];
120
+ return new Promise((resolveFn) => {
121
+ const hits = [];
122
+ const child = spawn("rg", args);
123
+ const timer = setTimeout(() => child.kill("SIGTERM"), opts.timeoutMs);
124
+ let buf = "";
125
+ let currentFile;
126
+ const finish = () => {
127
+ clearTimeout(timer);
128
+ resolveFn(hits);
129
+ };
130
+ child.stdout.setEncoding("utf8");
131
+ child.stdout.on("data", (chunk) => {
132
+ buf += chunk;
133
+ let nl = buf.indexOf("\n");
134
+ while (nl !== -1) {
135
+ const line = buf.slice(0, nl);
136
+ buf = buf.slice(nl + 1);
137
+ if (line.length > 0)
138
+ handleEvent(line);
139
+ nl = buf.indexOf("\n");
140
+ }
141
+ });
142
+ child.on("error", () => finish());
143
+ child.on("close", () => finish());
144
+ const handleEvent = (jsonLine) => {
145
+ let event;
146
+ try {
147
+ event = JSON.parse(jsonLine);
148
+ }
149
+ catch {
150
+ return;
151
+ }
152
+ if (event.type === "begin") {
153
+ const data = event.data;
154
+ currentFile = data?.path?.text;
155
+ }
156
+ else if (event.type === "match" && currentFile !== undefined) {
157
+ if (hits.length >= maxLines) {
158
+ child.kill("SIGTERM");
159
+ return;
160
+ }
161
+ const data = event.data;
162
+ if (data === undefined)
163
+ return;
164
+ const lineText = data.lines?.text ?? "";
165
+ const lineNumber = data.line_number ?? 0;
166
+ if (lineNumber === 0)
167
+ return;
168
+ hits.push({
169
+ filePath: currentFile,
170
+ lineNumber,
171
+ line: stripTrailingNewline(lineText),
172
+ });
173
+ }
174
+ };
175
+ });
176
+ }
177
+ /* ----------------------------- in-process path ----------------------------- */
178
+ async function collectInProcess(opts) {
179
+ const hits = [];
180
+ const deadline = Date.now() + opts.timeoutMs;
181
+ const needle = opts.query.toLowerCase();
182
+ const maxLines = opts.sessionLimit * opts.matchesPerSession * 4;
183
+ let projectDirs;
184
+ try {
185
+ projectDirs = await readdir(config.sessionDir);
186
+ }
187
+ catch {
188
+ return hits; // Session dir doesn't exist yet — empty result is fine.
189
+ }
190
+ for (const projectDir of projectDirs) {
191
+ if (Date.now() >= deadline || hits.length >= maxLines)
192
+ break;
193
+ const fullDir = join(config.sessionDir, projectDir);
194
+ let entries;
195
+ try {
196
+ entries = await readdir(fullDir, { withFileTypes: true });
197
+ }
198
+ catch {
199
+ continue;
200
+ }
201
+ for (const ent of entries) {
202
+ if (Date.now() >= deadline || hits.length >= maxLines)
203
+ break;
204
+ if (!ent.isFile() || !ent.name.endsWith(".jsonl"))
205
+ continue;
206
+ const filePath = join(fullDir, ent.name);
207
+ let content;
208
+ try {
209
+ content = await readFile(filePath, "utf8");
210
+ }
211
+ catch {
212
+ continue;
213
+ }
214
+ const lines = content.split("\n");
215
+ for (let i = 0; i < lines.length; i++) {
216
+ if (Date.now() >= deadline || hits.length >= maxLines)
217
+ break;
218
+ const line = lines[i] ?? "";
219
+ if (line.length === 0)
220
+ continue;
221
+ if (line.toLowerCase().includes(needle)) {
222
+ hits.push({ filePath, lineNumber: i + 1, line });
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return hits;
228
+ }
229
+ function safeParseLine(line) {
230
+ try {
231
+ return JSON.parse(line);
232
+ }
233
+ catch {
234
+ return undefined;
235
+ }
236
+ }
237
+ function extractSnippet(parsed, query) {
238
+ if (parsed.type !== "message")
239
+ return undefined;
240
+ const msg = parsed.message;
241
+ if (msg === undefined || msg === null || typeof msg !== "object")
242
+ return undefined;
243
+ const role = msg.role;
244
+ if (role !== "user" && role !== "assistant")
245
+ return undefined;
246
+ const content = msg.content;
247
+ // String content is the simple "user typed text" shape some SDK
248
+ // versions still emit. Treat as a single text block.
249
+ if (typeof content === "string") {
250
+ const hit = findMatch(content, query);
251
+ if (hit === undefined)
252
+ return undefined;
253
+ return {
254
+ kind: role === "user" ? "user" : "assistant",
255
+ snippet: clipSnippet(content, hit.offset, query.length),
256
+ matchOffset: clippedMatchOffset(content, hit.offset),
257
+ matchLength: query.length,
258
+ };
259
+ }
260
+ if (!Array.isArray(content))
261
+ return undefined;
262
+ // Walk content blocks. Prefer text-block matches (most readable).
263
+ // If no text block matches but a toolCall does, surface the rendered
264
+ // tool form as the snippet.
265
+ for (const block of content) {
266
+ if (block === undefined || block === null || typeof block !== "object")
267
+ continue;
268
+ const b = block;
269
+ if (b.type === "text" && typeof b.text === "string") {
270
+ const hit = findMatch(b.text, query);
271
+ if (hit !== undefined) {
272
+ return {
273
+ kind: role === "user" ? "user" : "assistant",
274
+ snippet: clipSnippet(b.text, hit.offset, query.length),
275
+ matchOffset: clippedMatchOffset(b.text, hit.offset),
276
+ matchLength: query.length,
277
+ };
278
+ }
279
+ }
280
+ }
281
+ // Tool-call fallback: only assistants emit toolCall blocks.
282
+ if (role === "assistant") {
283
+ for (const block of content) {
284
+ if (block === undefined || block === null || typeof block !== "object")
285
+ continue;
286
+ const b = block;
287
+ if (b.type !== "toolCall")
288
+ continue;
289
+ const rendered = renderToolCall(b);
290
+ const hit = findMatch(rendered, query);
291
+ if (hit === undefined)
292
+ continue;
293
+ return {
294
+ kind: "tool_call",
295
+ snippet: clipSnippet(rendered, hit.offset, query.length),
296
+ matchOffset: clippedMatchOffset(rendered, hit.offset),
297
+ matchLength: query.length,
298
+ };
299
+ }
300
+ }
301
+ return undefined;
302
+ }
303
+ function renderToolCall(block) {
304
+ const name = typeof block.name === "string" ? block.name : "tool";
305
+ const args = (block.arguments ?? block.input);
306
+ if (args === undefined || args === null || typeof args !== "object")
307
+ return name + "()";
308
+ const parts = [];
309
+ for (const [k, v] of Object.entries(args)) {
310
+ if (v === undefined || v === null)
311
+ continue;
312
+ let s;
313
+ if (typeof v === "string")
314
+ s = v;
315
+ else if (typeof v === "number" || typeof v === "boolean")
316
+ s = String(v);
317
+ else
318
+ s = JSON.stringify(v);
319
+ if (s.length > 200)
320
+ s = s.slice(0, 200) + "…";
321
+ parts.push(`${k}=${s}`);
322
+ }
323
+ return `${name}(${parts.join(", ")})`;
324
+ }
325
+ function findMatch(haystack, query) {
326
+ const i = haystack.toLowerCase().indexOf(query.toLowerCase());
327
+ if (i === -1)
328
+ return undefined;
329
+ return { offset: i };
330
+ }
331
+ function clipSnippet(source, matchOffset, matchLength) {
332
+ const start = Math.max(0, matchOffset - SNIPPET_CONTEXT);
333
+ const end = Math.min(source.length, matchOffset + matchLength + SNIPPET_CONTEXT);
334
+ let snippet = source.slice(start, end).replace(/\s+/g, " ").trim();
335
+ if (start > 0)
336
+ snippet = "…" + snippet;
337
+ if (end < source.length)
338
+ snippet = snippet + "…";
339
+ return snippet;
340
+ }
341
+ function clippedMatchOffset(source, matchOffset) {
342
+ // The clipped snippet always centers the match (with possible "…"
343
+ // prefix). Compute the new offset relative to the snippet so the
344
+ // client can highlight the exact substring.
345
+ const start = Math.max(0, matchOffset - SNIPPET_CONTEXT);
346
+ const prefixEllipsis = start > 0 ? 1 : 0;
347
+ const original = source.slice(start, matchOffset);
348
+ const collapsed = original.replace(/\s+/g, " ").replace(/^\s+/, "");
349
+ return prefixEllipsis + collapsed.length;
350
+ }
351
+ /* ----------------------------- file walking ----------------------------- */
352
+ const headerCache = new Map();
353
+ const nameCache = new Map();
354
+ const messageIndexCache = new Map();
355
+ async function readSessionIdFromHeader(filePath) {
356
+ if (headerCache.has(filePath))
357
+ return headerCache.get(filePath);
358
+ let content;
359
+ try {
360
+ content = await readFile(filePath, "utf8");
361
+ }
362
+ catch {
363
+ headerCache.set(filePath, undefined);
364
+ return undefined;
365
+ }
366
+ const firstNl = content.indexOf("\n");
367
+ const firstLine = firstNl === -1 ? content : content.slice(0, firstNl);
368
+ let header;
369
+ try {
370
+ header = JSON.parse(firstLine);
371
+ }
372
+ catch {
373
+ headerCache.set(filePath, undefined);
374
+ return undefined;
375
+ }
376
+ if (header.type !== "session" || typeof header.id !== "string") {
377
+ headerCache.set(filePath, undefined);
378
+ return undefined;
379
+ }
380
+ headerCache.set(filePath, header.id);
381
+ return header.id;
382
+ }
383
+ async function readSessionNameFromFile(filePath) {
384
+ if (nameCache.has(filePath))
385
+ return nameCache.get(filePath);
386
+ let content;
387
+ try {
388
+ content = await readFile(filePath, "utf8");
389
+ }
390
+ catch {
391
+ nameCache.set(filePath, undefined);
392
+ return undefined;
393
+ }
394
+ const lines = content.split("\n");
395
+ for (const line of lines) {
396
+ if (line.length === 0)
397
+ continue;
398
+ let parsed;
399
+ try {
400
+ parsed = JSON.parse(line);
401
+ }
402
+ catch {
403
+ continue;
404
+ }
405
+ if (parsed.type === "session_info" && typeof parsed.name === "string") {
406
+ nameCache.set(filePath, parsed.name);
407
+ return parsed.name;
408
+ }
409
+ }
410
+ nameCache.set(filePath, undefined);
411
+ return undefined;
412
+ }
413
+ async function fileMtime(filePath) {
414
+ try {
415
+ const { stat } = await import("node:fs/promises");
416
+ const s = await stat(filePath);
417
+ return s.mtime.toISOString();
418
+ }
419
+ catch {
420
+ return new Date(0).toISOString();
421
+ }
422
+ }
423
+ function projectIdFromPath(filePath) {
424
+ // ${SESSION_DIR}/<projectId>/<file>.jsonl — projectId is the
425
+ // immediate parent dir. Subagent child JSONLs live one level deeper
426
+ // and we ignore them here (their parent's main session is what we
427
+ // surface in search results).
428
+ const sessionDir = config.sessionDir;
429
+ if (!filePath.startsWith(sessionDir))
430
+ return undefined;
431
+ const rel = filePath.slice(sessionDir.length).replace(/^[/\\]+/, "");
432
+ const parts = rel.split(/[/\\]/);
433
+ if (parts.length < 2)
434
+ return undefined;
435
+ if (parts.length > 2)
436
+ return undefined; // Subagent child — skip
437
+ return parts[0];
438
+ }
439
+ /**
440
+ * Scan from the file's last-known message-line cursor up to the line
441
+ * containing this hit, counting `type === "message"` lines. Returns the
442
+ * 0-based index of the message at `lineNumber` (or undefined if that
443
+ * line isn't a message line).
444
+ */
445
+ async function advanceMessageIndex(group, lineNumber) {
446
+ const cached = messageIndexCache.get(group.filePath);
447
+ if (cached !== undefined) {
448
+ // Cached layout: array of all message-line numbers (1-based) in
449
+ // the file. Binary-search to find the index for this line.
450
+ const idx = cached.indexOf(lineNumber);
451
+ return idx === -1 ? undefined : idx;
452
+ }
453
+ let content;
454
+ try {
455
+ content = await readFile(group.filePath, "utf8");
456
+ }
457
+ catch {
458
+ return undefined;
459
+ }
460
+ const messageLines = [];
461
+ const lines = content.split("\n");
462
+ for (let i = 0; i < lines.length; i++) {
463
+ const line = lines[i] ?? "";
464
+ if (line.length === 0)
465
+ continue;
466
+ // Cheap pre-check before JSON.parse: every message line starts
467
+ // with `{"type":"message"`. Skipping the parse for non-message
468
+ // lines is a 10× speedup on long sessions.
469
+ if (!line.startsWith('{"type":"message"'))
470
+ continue;
471
+ messageLines.push(i + 1); // 1-based to match ripgrep
472
+ }
473
+ messageIndexCache.set(group.filePath, messageLines);
474
+ const idx = messageLines.indexOf(lineNumber);
475
+ return idx === -1 ? undefined : idx;
476
+ }
477
+ function stripTrailingNewline(s) {
478
+ if (s.endsWith("\r\n"))
479
+ return s.slice(0, -2);
480
+ if (s.endsWith("\n"))
481
+ return s.slice(0, -1);
482
+ return s;
483
+ }
484
+ /** Test-only: drop all per-file caches between assertions. */
485
+ export function _resetSessionSearcherCaches() {
486
+ headerCache.clear();
487
+ nameCache.clear();
488
+ messageIndexCache.clear();
489
+ }
490
+ //# sourceMappingURL=session-searcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-searcher.js","sourceRoot":"","sources":["../src/session-searcher.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-forge",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Browser UI for the pi coding agent — embedded HTTP server with a React workbench (chat, file browser, terminal, git, MCP).",
5
5
  "keywords": [
6
6
  "pi",