claude-bridge-cli 2.0.21 → 2.0.23
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/lib/bridge.js +80 -9
- package/package.json +1 -1
package/lib/bridge.js
CHANGED
|
@@ -427,21 +427,92 @@ function searchSessions(query, limit = 30) {
|
|
|
427
427
|
} catch { return 0; }
|
|
428
428
|
});
|
|
429
429
|
|
|
430
|
+
// Scan far more than the old 200 newest — on a busy machine that cut off
|
|
431
|
+
// sessions only a few days old, so a term you KNEW was there returned
|
|
432
|
+
// nothing. The loop already stops once `limit` results are collected, and
|
|
433
|
+
// the whole-file prefilter below makes a non-matching session cheap.
|
|
430
434
|
const results = [];
|
|
431
|
-
for (const { id, project, filePath } of files.slice(0,
|
|
435
|
+
for (const { id, project, filePath } of files.slice(0, 2000)) {
|
|
436
|
+
if (results.length >= limit) break;
|
|
432
437
|
let stat;
|
|
433
438
|
try { stat = fs.statSync(filePath); } catch { continue; }
|
|
434
439
|
let content;
|
|
435
440
|
try { content = fs.readFileSync(filePath, "utf8"); } catch { continue; }
|
|
436
441
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
// Cheap prefilter: if the raw file can't contain it, skip the parse.
|
|
443
|
+
if (!content.toLowerCase().includes(q)) continue;
|
|
444
|
+
|
|
445
|
+
// Match against CONVERSATION CONTENT, not the raw JSONL. Grepping the file
|
|
446
|
+
// as one string matched JSON keys, uuids, base64 and other machinery, and
|
|
447
|
+
// produced snippets that were a slice of raw JSON — which is why results
|
|
448
|
+
// here looked far worse than the Python bridge's. Parse each record and
|
|
449
|
+
// search: user text, assistant text, tool_use inputs, and tool_result
|
|
450
|
+
// output (an id from an email often exists ONLY in a command or its
|
|
451
|
+
// output, so tool activity must be searched — just not the plumbing).
|
|
452
|
+
let matchCount = 0, snippet = "";
|
|
453
|
+
for (const line of content.split("\n")) {
|
|
454
|
+
if (!line) continue;
|
|
455
|
+
let rec;
|
|
456
|
+
try { rec = JSON.parse(line); } catch { continue; }
|
|
457
|
+
const t = rec.type;
|
|
458
|
+
const texts = [];
|
|
459
|
+
// Text also lives OUTSIDE message.content: a queued message you typed,
|
|
460
|
+
// the recorded last prompt, compaction summaries, system notes. Parsing
|
|
461
|
+
// only user/assistant records made those unfindable — the old whole-file
|
|
462
|
+
// grep did match them, so skipping them was a regression.
|
|
463
|
+
if (t !== "user" && t !== "assistant") {
|
|
464
|
+
for (const k of ["summary", "lastPrompt", "content", "text"]) {
|
|
465
|
+
if (typeof rec[k] === "string" && rec[k]) texts.push(rec[k]);
|
|
466
|
+
}
|
|
467
|
+
for (const text of texts) {
|
|
468
|
+
const tl = text.toLowerCase();
|
|
469
|
+
let from = tl.indexOf(q);
|
|
470
|
+
if (from < 0) continue;
|
|
471
|
+
while (from >= 0) { matchCount++; from = tl.indexOf(q, from + q.length); }
|
|
472
|
+
if (!snippet) {
|
|
473
|
+
const i = tl.indexOf(q);
|
|
474
|
+
const s = Math.max(0, i - 40), e = Math.min(text.length, i + q.length + 80);
|
|
475
|
+
snippet = (s > 0 ? "…" : "") + text.slice(s, e).replace(/\s+/g, " ").trim()
|
|
476
|
+
+ (e < text.length ? "…" : "");
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const msg = rec.message || {};
|
|
482
|
+
const c = msg.content;
|
|
483
|
+
if (typeof c === "string") texts.push(c);
|
|
484
|
+
else if (Array.isArray(c)) {
|
|
485
|
+
for (const b of c) {
|
|
486
|
+
if (!b || typeof b !== "object") continue;
|
|
487
|
+
if (b.type === "text" && typeof b.text === "string") texts.push(b.text);
|
|
488
|
+
else if (b.type === "tool_use" && b.input) {
|
|
489
|
+
try { texts.push(JSON.stringify(b.input)); } catch {}
|
|
490
|
+
} else if (b.type === "tool_result") {
|
|
491
|
+
const rc = b.content;
|
|
492
|
+
if (typeof rc === "string") texts.push(rc);
|
|
493
|
+
else if (Array.isArray(rc)) {
|
|
494
|
+
for (const rb of rc) {
|
|
495
|
+
if (rb && rb.type === "text" && typeof rb.text === "string") texts.push(rb.text);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
for (const text of texts) {
|
|
502
|
+
if (!text) continue;
|
|
503
|
+
const tl = text.toLowerCase();
|
|
504
|
+
let from = tl.indexOf(q);
|
|
505
|
+
if (from < 0) continue;
|
|
506
|
+
while (from >= 0) { matchCount++; from = tl.indexOf(q, from + q.length); }
|
|
507
|
+
if (!snippet) {
|
|
508
|
+
const i = tl.indexOf(q);
|
|
509
|
+
const s = Math.max(0, i - 40), e = Math.min(text.length, i + q.length + 80);
|
|
510
|
+
snippet = (s > 0 ? "…" : "") + text.slice(s, e).replace(/\s+/g, " ").trim()
|
|
511
|
+
+ (e < text.length ? "…" : "");
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (!matchCount) continue; // matched only machinery — not a real hit
|
|
445
516
|
|
|
446
517
|
let aiTitle = "", customTitle = "", msgCount = 0, realCwd = "";
|
|
447
518
|
try {
|
package/package.json
CHANGED