claude-bridge-cli 2.0.19 → 2.0.21

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 +44 -2
  2. package/package.json +1 -1
package/lib/bridge.js CHANGED
@@ -787,6 +787,7 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
787
787
  // anything INTO the Files drawer it's now told about.
788
788
  "--add-dir", path.join(dataDir(), "images")];
789
789
  let resumeCwd = null;
790
+ let divergedFrom = null; // set if the CLI answers under a different session
790
791
  if (session_id) {
791
792
  const existing = scanSessionFiles().find(s => s.id === session_id);
792
793
  if (existing) {
@@ -841,9 +842,35 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
841
842
  }
842
843
  } catch {}
843
844
 
844
- const bin = isCmdShim ? process.env.COMSPEC || "cmd.exe" : config.claudeBin;
845
- const fullArgs = isCmdShim ? ["/c", config.claudeBin, ...args] : args;
845
+ // A newline in ANY argument truncates the command line there — cmd.exe's
846
+ // second parse ends the command at the line break, so every argument that
847
+ // FOLLOWS is silently discarded. The prompt was routed through @file for
848
+ // exactly this reason (see the note above), but the lesson was applied to
849
+ // one argument instead of to the rule. 2.0.18 added the first multi-line
850
+ // --append-system-prompt and re-opened the hole one argument over: the
851
+ // trailing --add-dir / --resume / --model were dropped, so on Windows
852
+ // every "resume" silently began a NEW session, on the default model, with
853
+ // no error to explain it. Newlines are not meaningful in any value we
854
+ // pass, so flatten them for cmd-shim spawns and close the whole class.
855
+ const flattenForCmd = (a) =>
856
+ typeof a === "string" ? a.replace(/\r\n|\r|\n/g, " ") : a;
857
+ const shellSafeArgs = isCmdShim ? args.map(flattenForCmd) : args;
858
+ if (isCmdShim && process.env.CLAUDE_BRIDGE_DEBUG) {
859
+ const n = args.filter((a, i) => a !== shellSafeArgs[i]).length;
860
+ if (n) console.error("[bridge] flattened newlines in %d arg(s) for cmd.exe", n);
861
+ }
846
862
 
863
+ const bin = isCmdShim ? process.env.COMSPEC || "cmd.exe" : config.claudeBin;
864
+ const fullArgs = isCmdShim ? ["/c", config.claudeBin, ...shellSafeArgs] : args;
865
+
866
+ // Opt-in spawn tracing (CLAUDE_BRIDGE_DEBUG=1). Nothing recorded WHAT the
867
+ // bridge actually ran, so when a turn misbehaved there was no evidence to
868
+ // separate "we built the wrong command" from "the CLI ignored it" — a
869
+ // resume regression took hours to narrow with no way to see the argv.
870
+ if (process.env.CLAUDE_BRIDGE_DEBUG) {
871
+ console.error("[bridge] spawn bin=%s cwd=%s args=%s",
872
+ bin, effCwd, JSON.stringify(fullArgs));
873
+ }
847
874
  const proc = spawn(bin, fullArgs, {
848
875
  cwd: effCwd,
849
876
  timeout: config.timeout,
@@ -871,6 +898,17 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
871
898
  const finalText = result.result || result.assistantMessage || "";
872
899
  writeCompletionMarker(sid, finalText);
873
900
  if (session_id && session_id !== sid) writeCompletionMarker(session_id, finalText);
901
+ // The CLI answered under a DIFFERENT session than we asked to resume:
902
+ // the turn's history is not where the user is looking, and the session
903
+ // they see can never update again. This was handled silently, so the
904
+ // symptom reaching the user was "Claude keeps repeating its last reply"
905
+ // with nothing anywhere to explain it. Never swallow it again — log it,
906
+ // and hand it to the client so the UI can say so.
907
+ if (session_id && session_id !== sid) {
908
+ console.error("[bridge] WARNING resume diverged: asked=%s answered=%s "
909
+ + "(the turn was written to a different session)", session_id, sid);
910
+ divergedFrom = session_id;
911
+ }
874
912
  if (images && images.length && session_id === "pending" && sid !== "pending") {
875
913
  const oldDir = path.join(dataDir(), "images", "pending");
876
914
  const newDir = path.join(dataDir(), "images", sid);
@@ -892,6 +930,10 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
892
930
  duration_ms: result.duration_ms || null,
893
931
  context: result.context || null,
894
932
  permission_denials,
933
+ // Non-null when the CLI answered under a different session than the
934
+ // one we asked to resume. The client shows the conversation it is
935
+ // displaying will not receive this turn, and where the turn went.
936
+ resume_diverged_from: divergedFrom,
895
937
  });
896
938
  } catch {
897
939
  if (stdout.trim()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-bridge-cli",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
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": {