claude-bridge-cli 2.0.20 → 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.
- package/lib/bridge.js +72 -9
- 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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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 {
|
|
@@ -842,8 +887,26 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
|
|
|
842
887
|
}
|
|
843
888
|
} catch {}
|
|
844
889
|
|
|
890
|
+
// A newline in ANY argument truncates the command line there — cmd.exe's
|
|
891
|
+
// second parse ends the command at the line break, so every argument that
|
|
892
|
+
// FOLLOWS is silently discarded. The prompt was routed through @file for
|
|
893
|
+
// exactly this reason (see the note above), but the lesson was applied to
|
|
894
|
+
// one argument instead of to the rule. 2.0.18 added the first multi-line
|
|
895
|
+
// --append-system-prompt and re-opened the hole one argument over: the
|
|
896
|
+
// trailing --add-dir / --resume / --model were dropped, so on Windows
|
|
897
|
+
// every "resume" silently began a NEW session, on the default model, with
|
|
898
|
+
// no error to explain it. Newlines are not meaningful in any value we
|
|
899
|
+
// pass, so flatten them for cmd-shim spawns and close the whole class.
|
|
900
|
+
const flattenForCmd = (a) =>
|
|
901
|
+
typeof a === "string" ? a.replace(/\r\n|\r|\n/g, " ") : a;
|
|
902
|
+
const shellSafeArgs = isCmdShim ? args.map(flattenForCmd) : args;
|
|
903
|
+
if (isCmdShim && process.env.CLAUDE_BRIDGE_DEBUG) {
|
|
904
|
+
const n = args.filter((a, i) => a !== shellSafeArgs[i]).length;
|
|
905
|
+
if (n) console.error("[bridge] flattened newlines in %d arg(s) for cmd.exe", n);
|
|
906
|
+
}
|
|
907
|
+
|
|
845
908
|
const bin = isCmdShim ? process.env.COMSPEC || "cmd.exe" : config.claudeBin;
|
|
846
|
-
const fullArgs = isCmdShim ? ["/c", config.claudeBin, ...
|
|
909
|
+
const fullArgs = isCmdShim ? ["/c", config.claudeBin, ...shellSafeArgs] : args;
|
|
847
910
|
|
|
848
911
|
// Opt-in spawn tracing (CLAUDE_BRIDGE_DEBUG=1). Nothing recorded WHAT the
|
|
849
912
|
// bridge actually ran, so when a turn misbehaved there was no evidence to
|
package/package.json
CHANGED