claude-bridge-cli 1.2.5 → 1.2.7

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 +56 -20
  2. package/package.json +1 -1
package/lib/bridge.js CHANGED
@@ -118,23 +118,54 @@ function looksLikeInternal(text) {
118
118
  function parseSessionFile(filePath) {
119
119
  let preview = "", aiTitle = "", customTitle = "", msgCount = 0, lastPrompt = "";
120
120
  try {
121
- const lines = fs.readFileSync(filePath, "utf8").split("\n").filter(Boolean);
122
- msgCount = lines.length;
123
- for (const line of lines) {
124
- try {
125
- const obj = JSON.parse(line);
126
- if (obj.type === "summary" && obj.summary) preview = preview || obj.summary.slice(0, 200);
127
- if (obj.type === "user" && obj.message?.content) {
128
- const text = typeof obj.message.content === "string" ? obj.message.content : JSON.stringify(obj.message.content);
129
- if (!preview && !looksLikeInternal(text)) preview = text.slice(0, 200);
130
- if (!looksLikeInternal(text)) lastPrompt = text.slice(0, 200);
131
- }
132
- if (obj.type === "result" && obj.result) {
133
- aiTitle = aiTitle || (obj.result.metadata?.title?.value || "");
121
+ // For listing, read just the first 64KB and the last 64KB.
122
+ // First chunk: get preview + ai_title from early events.
123
+ // Last chunk: get last_prompt and custom-title overrides (latest wins).
124
+ // Message count is approximated from file size.
125
+ const stat = fs.statSync(filePath);
126
+ const CHUNK = 64 * 1024;
127
+ const fd = fs.openSync(filePath, "r");
128
+ try {
129
+ const headBuf = Buffer.alloc(Math.min(CHUNK, stat.size));
130
+ fs.readSync(fd, headBuf, 0, headBuf.length, 0);
131
+ const head = headBuf.toString("utf8");
132
+ for (const line of head.split("\n")) {
133
+ if (!line) continue;
134
+ try {
135
+ const obj = JSON.parse(line);
136
+ if (obj.type === "summary" && obj.summary) preview = preview || obj.summary.slice(0, 200);
137
+ if (obj.type === "user" && obj.message?.content) {
138
+ const text = typeof obj.message.content === "string" ? obj.message.content : JSON.stringify(obj.message.content);
139
+ if (!preview && !looksLikeInternal(text)) preview = text.slice(0, 200);
140
+ }
141
+ if (obj.type === "result" && obj.result?.metadata?.title?.value) aiTitle = aiTitle || obj.result.metadata.title.value;
142
+ if (obj.type === "ai-title" && obj.title) aiTitle = obj.title;
143
+ } catch {}
144
+ }
145
+ if (stat.size > CHUNK) {
146
+ const tailBuf = Buffer.alloc(CHUNK);
147
+ fs.readSync(fd, tailBuf, 0, CHUNK, stat.size - CHUNK);
148
+ // Skip first (possibly partial) line
149
+ const tail = tailBuf.toString("utf8");
150
+ const tailLines = tail.split("\n");
151
+ if (tailLines.length > 1) tailLines.shift();
152
+ for (const line of tailLines) {
153
+ if (!line) continue;
154
+ try {
155
+ const obj = JSON.parse(line);
156
+ if (obj.type === "user" && obj.message?.content) {
157
+ const text = typeof obj.message.content === "string" ? obj.message.content : JSON.stringify(obj.message.content);
158
+ if (!looksLikeInternal(text)) lastPrompt = text.slice(0, 200);
159
+ }
160
+ if (obj.type === "custom-title" && obj.title) customTitle = obj.title;
161
+ if (obj.type === "ai-title" && obj.title) aiTitle = obj.title;
162
+ } catch {}
134
163
  }
135
- if (obj.type === "ai-title" && obj.title) aiTitle = obj.title;
136
- if (obj.type === "custom-title" && obj.title) customTitle = obj.title;
137
- } catch {}
164
+ }
165
+ // Rough message count: assume ~500 bytes/line average for big files.
166
+ msgCount = Math.max(1, Math.floor(stat.size / 500));
167
+ } finally {
168
+ fs.closeSync(fd);
138
169
  }
139
170
  } catch {}
140
171
  return { preview, ai_title: customTitle || aiTitle, message_count: msgCount, last_prompt: lastPrompt };
@@ -362,11 +393,16 @@ function askClaude(config, { prompt, session_id, images, cwd, plan_mode, allow_t
362
393
  const existing = scanSessionFiles().find(s => s.id === session_id);
363
394
  if (existing) {
364
395
  args.push("--resume", session_id);
365
- // Read original cwd from the first line of the JSONL (Claude stores it there)
396
+ // Scan JSONL for the first event with a cwd field
366
397
  try {
367
- const firstLine = fs.readFileSync(existing.filePath, "utf8").split("\n")[0];
368
- const parsed = JSON.parse(firstLine);
369
- if (parsed.cwd) resumeCwd = parsed.cwd;
398
+ const lines = fs.readFileSync(existing.filePath, "utf8").split("\n");
399
+ for (const line of lines) {
400
+ if (!line) continue;
401
+ try {
402
+ const parsed = JSON.parse(line);
403
+ if (parsed.cwd) { resumeCwd = parsed.cwd; break; }
404
+ } catch {}
405
+ }
370
406
  } catch {}
371
407
  } else {
372
408
  args.push("--session-id", session_id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-bridge-cli",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
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": {