claude-bridge-cli 2.0.21 → 2.0.22

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 (2) hide show
  1. package/lib/bridge.js +53 -8
  2. package/package.json +1 -1
package/lib/bridge.js CHANGED
@@ -434,14 +434,59 @@ function searchSessions(query, limit = 30) {
434
434
  let content;
435
435
  try { content = fs.readFileSync(filePath, "utf8"); } catch { continue; }
436
436
 
437
- const lower = content.toLowerCase();
438
- const idx = lower.indexOf(q);
439
- if (idx < 0) continue;
440
-
441
- const matchCount = lower.split(q).length - 1;
442
- const snippetStart = Math.max(0, idx - 40);
443
- const snippetEnd = Math.min(content.length, idx + q.length + 80);
444
- const snippet = content.slice(snippetStart, snippetEnd).replace(/\n/g, " ").trim();
437
+ // Cheap prefilter: if the raw file can't contain it, skip the parse.
438
+ if (!content.toLowerCase().includes(q)) continue;
439
+
440
+ // Match against CONVERSATION CONTENT, not the raw JSONL. Grepping the file
441
+ // as one string matched JSON keys, uuids, base64 and other machinery, and
442
+ // produced snippets that were a slice of raw JSON — which is why results
443
+ // here looked far worse than the Python bridge's. Parse each record and
444
+ // search: user text, assistant text, tool_use inputs, and tool_result
445
+ // output (an id from an email often exists ONLY in a command or its
446
+ // output, so tool activity must be searched — just not the plumbing).
447
+ let matchCount = 0, snippet = "";
448
+ for (const line of content.split("\n")) {
449
+ if (!line) continue;
450
+ let rec;
451
+ try { rec = JSON.parse(line); } catch { continue; }
452
+ const t = rec.type;
453
+ if (t !== "user" && t !== "assistant") continue;
454
+ const msg = rec.message || {};
455
+ const texts = [];
456
+ const c = msg.content;
457
+ if (typeof c === "string") texts.push(c);
458
+ else if (Array.isArray(c)) {
459
+ for (const b of c) {
460
+ if (!b || typeof b !== "object") continue;
461
+ if (b.type === "text" && typeof b.text === "string") texts.push(b.text);
462
+ else if (b.type === "tool_use" && b.input) {
463
+ try { texts.push(JSON.stringify(b.input)); } catch {}
464
+ } else if (b.type === "tool_result") {
465
+ const rc = b.content;
466
+ if (typeof rc === "string") texts.push(rc);
467
+ else if (Array.isArray(rc)) {
468
+ for (const rb of rc) {
469
+ if (rb && rb.type === "text" && typeof rb.text === "string") texts.push(rb.text);
470
+ }
471
+ }
472
+ }
473
+ }
474
+ }
475
+ for (const text of texts) {
476
+ if (!text) continue;
477
+ const tl = text.toLowerCase();
478
+ let from = tl.indexOf(q);
479
+ if (from < 0) continue;
480
+ while (from >= 0) { matchCount++; from = tl.indexOf(q, from + q.length); }
481
+ if (!snippet) {
482
+ const i = tl.indexOf(q);
483
+ const s = Math.max(0, i - 40), e = Math.min(text.length, i + q.length + 80);
484
+ snippet = (s > 0 ? "…" : "") + text.slice(s, e).replace(/\s+/g, " ").trim()
485
+ + (e < text.length ? "…" : "");
486
+ }
487
+ }
488
+ }
489
+ if (!matchCount) continue; // matched only machinery — not a real hit
445
490
 
446
491
  let aiTitle = "", customTitle = "", msgCount = 0, realCwd = "";
447
492
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-bridge-cli",
3
- "version": "2.0.21",
3
+ "version": "2.0.22",
4
4
  "description": "Use Claude Code from your browser. Runs a local server that connects your browser tools to the Claude CLI.",
5
5
  "main": "lib/bridge.js",
6
6
  "bin": {