claude-bridge-cli 1.2.8 → 1.3.0
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 +50 -6
- package/package.json +1 -1
package/lib/bridge.js
CHANGED
|
@@ -139,13 +139,13 @@ function parseSessionFile(filePath) {
|
|
|
139
139
|
if (!preview && !looksLikeInternal(text)) preview = text.slice(0, 200);
|
|
140
140
|
}
|
|
141
141
|
if (obj.type === "result" && obj.result?.metadata?.title?.value) aiTitle = aiTitle || obj.result.metadata.title.value;
|
|
142
|
-
if (obj.type === "ai-title"
|
|
142
|
+
if (obj.type === "ai-title") aiTitle = obj.aiTitle || obj.title || aiTitle;
|
|
143
|
+
if (obj.type === "custom-title") customTitle = obj.customTitle || obj.title || customTitle;
|
|
143
144
|
} catch {}
|
|
144
145
|
}
|
|
145
146
|
if (stat.size > CHUNK) {
|
|
146
147
|
const tailBuf = Buffer.alloc(CHUNK);
|
|
147
148
|
fs.readSync(fd, tailBuf, 0, CHUNK, stat.size - CHUNK);
|
|
148
|
-
// Skip first (possibly partial) line
|
|
149
149
|
const tail = tailBuf.toString("utf8");
|
|
150
150
|
const tailLines = tail.split("\n");
|
|
151
151
|
if (tailLines.length > 1) tailLines.shift();
|
|
@@ -157,8 +157,8 @@ function parseSessionFile(filePath) {
|
|
|
157
157
|
const text = typeof obj.message.content === "string" ? obj.message.content : JSON.stringify(obj.message.content);
|
|
158
158
|
if (!looksLikeInternal(text)) lastPrompt = text.slice(0, 200);
|
|
159
159
|
}
|
|
160
|
-
if (obj.type === "
|
|
161
|
-
if (obj.type === "
|
|
160
|
+
if (obj.type === "ai-title") aiTitle = obj.aiTitle || obj.title || aiTitle;
|
|
161
|
+
if (obj.type === "custom-title") customTitle = obj.customTitle || obj.title || customTitle;
|
|
162
162
|
} catch {}
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -281,6 +281,39 @@ function searchSessions(query, limit = 30) {
|
|
|
281
281
|
|
|
282
282
|
// ── Session messages ──
|
|
283
283
|
|
|
284
|
+
const INTERNAL_USER_PATTERNS = [
|
|
285
|
+
"<system-reminder>", "<command-name>", "<command-message>",
|
|
286
|
+
"<local-command-stdout>", "<command-stderr>", "<local-command-stderr>",
|
|
287
|
+
"Caveat: The messages below were generated by",
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
function extractUserText(content) {
|
|
291
|
+
// Only extract type:"text" parts. tool_result records don't have a text
|
|
292
|
+
// part so they return empty string and get filtered out.
|
|
293
|
+
if (typeof content === "string") return content;
|
|
294
|
+
if (Array.isArray(content)) {
|
|
295
|
+
for (const part of content) {
|
|
296
|
+
if (part && typeof part === "object" && part.type === "text") {
|
|
297
|
+
return part.text || "";
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return "";
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function shouldSkipUserText(text) {
|
|
305
|
+
if (!text) return true;
|
|
306
|
+
const t = text.replace(/^\s+/, "");
|
|
307
|
+
// Skip internal command-stub patterns
|
|
308
|
+
if (INTERNAL_USER_PATTERNS.some(p => t.startsWith(p))) return true;
|
|
309
|
+
// Skip @file references — the bridge writes prompts to temp files,
|
|
310
|
+
// claude logs the literal @path string in the JSONL even though it
|
|
311
|
+
// reads file contents internally.
|
|
312
|
+
if (/^@[A-Z]:[\\\/]/.test(t) && /\.txt\s*$/.test(t)) return true;
|
|
313
|
+
if (/^@\/.*\.txt\s*$/.test(t)) return true;
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
284
317
|
function getSessionMessages(sessionId) {
|
|
285
318
|
const base = projectsDir();
|
|
286
319
|
let dirs;
|
|
@@ -292,8 +325,12 @@ function getSessionMessages(sessionId) {
|
|
|
292
325
|
for (const line of fs.readFileSync(filePath, "utf8").split("\n").filter(Boolean)) {
|
|
293
326
|
try {
|
|
294
327
|
const obj = JSON.parse(line);
|
|
328
|
+
// Skip transcript-only and meta records (replays, recaps)
|
|
329
|
+
if (obj.isMeta === true) continue;
|
|
330
|
+
if (obj.isVisibleInTranscriptOnly === true) continue;
|
|
295
331
|
if (obj.type === "user" && obj.message?.content) {
|
|
296
|
-
|
|
332
|
+
const text = extractUserText(obj.message.content);
|
|
333
|
+
if (shouldSkipUserText(text)) continue;
|
|
297
334
|
const split = splitUserTextAndImages(text);
|
|
298
335
|
messages.push({
|
|
299
336
|
role: "user",
|
|
@@ -304,7 +341,14 @@ function getSessionMessages(sessionId) {
|
|
|
304
341
|
} else if (obj.type === "assistant" && obj.message?.content) {
|
|
305
342
|
const parts = Array.isArray(obj.message.content) ? obj.message.content : [obj.message.content];
|
|
306
343
|
const text = parts.map(p => typeof p === "string" ? p : p.text || "").join("");
|
|
307
|
-
if (text)
|
|
344
|
+
if (!text) continue;
|
|
345
|
+
// Merge consecutive assistant turns into one (tool_use cycles)
|
|
346
|
+
if (messages.length && messages[messages.length - 1].role === "assistant") {
|
|
347
|
+
messages[messages.length - 1].text = (messages[messages.length - 1].text + "\n" + text).trim();
|
|
348
|
+
messages[messages.length - 1].timestamp = obj.timestamp || messages[messages.length - 1].timestamp;
|
|
349
|
+
} else {
|
|
350
|
+
messages.push({ role: "assistant", text, timestamp: obj.timestamp });
|
|
351
|
+
}
|
|
308
352
|
} else if (obj.type === "result" && obj.result?.assistantMessage) {
|
|
309
353
|
const text = typeof obj.result.assistantMessage === "string" ? obj.result.assistantMessage : "";
|
|
310
354
|
if (text) messages.push({ role: "assistant", text, timestamp: obj.timestamp });
|
package/package.json
CHANGED