Skip to content

Commit 0307ac8

Browse files
fix: claude-plugin check if assistant has content
1 parent fb75aa1 commit 0307ac8

File tree

3 files changed

+43
-78
lines changed

3 files changed

+43
-78
lines changed

packages/hook-utils/src/transcript.ts

Lines changed: 13 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,71 +33,6 @@ function extractMessageContent(parsed: any): string {
3333
}
3434
}
3535

36-
/**
37-
* Extract last message of specified role from transcript JSONL file
38-
* @param transcriptPath Path to transcript file
39-
* @param role 'user' or 'assistant'
40-
* @param stripSystemReminders Whether to remove <system-reminder> tags (for assistant)
41-
*/
42-
export function extractLastMessage(
43-
transcriptPath: string,
44-
role: "user" | "assistant",
45-
stripSystemReminders: boolean = false
46-
): string {
47-
if (!transcriptPath || !existsSync(transcriptPath)) {
48-
throw new Error(`Transcript path missing or file does not exist: ${transcriptPath}`);
49-
}
50-
51-
const content = readFileSync(transcriptPath, "utf-8").trim();
52-
if (!content) {
53-
throw new Error(`Transcript file exists but is empty: ${transcriptPath}`);
54-
}
55-
56-
const lines = content.split("\n");
57-
let foundMatchingRole = false;
58-
59-
for (let i = lines.length - 1; i >= 0; i--) {
60-
const line = JSON.parse(lines[i]);
61-
if (line.type === role) {
62-
foundMatchingRole = true;
63-
64-
if (line.message?.content) {
65-
let text = "";
66-
const msgContent = line.message.content;
67-
68-
if (typeof msgContent === "string") {
69-
text = msgContent;
70-
} else if (Array.isArray(msgContent)) {
71-
text = msgContent
72-
.filter((c: any) => c.type === "text")
73-
.map((c: any) => c.text)
74-
.join("\n");
75-
} else {
76-
// Unknown content format - throw error
77-
throw new Error(
78-
`Unknown message content format in transcript. Type: ${typeof msgContent}`
79-
);
80-
}
81-
82-
if (stripSystemReminders) {
83-
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
84-
text = text.replace(/\n{3,}/g, "\n\n").trim();
85-
}
86-
87-
// Return text even if empty - caller decides if that's an error
88-
return text;
89-
}
90-
}
91-
}
92-
93-
// If we searched the whole transcript and didn't find any message of this role
94-
if (!foundMatchingRole) {
95-
throw new Error(`No message found for role '${role}' in transcript: ${transcriptPath}`);
96-
}
97-
98-
return "";
99-
}
100-
10136
const DEFAULTS = ["[Request interrupted by user for tool use]"];
10237

10338
/**
@@ -126,7 +61,7 @@ export function extractLastAssistantWithPrecedingUsers(
12661
// Find the last assistant message
12762
let lastAssistantIndex = -1;
12863
for (let i = parsedLines.length - 1; i >= 0; i--) {
129-
let assistantMessage = extractMessageContent(parsedLines[lastAssistantIndex]);
64+
let assistantMessage = extractMessageContent(parsedLines[i]);
13065

13166
if (parsedLines[i].type === "assistant" && assistantMessage) {
13267
lastAssistantIndex = i;
@@ -158,9 +93,19 @@ export function extractLastAssistantWithPrecedingUsers(
15893
if (parsed.type === "assistant" && parsed.message && gotAtleastOne && content) {
15994
// Stop when we hit another assistant message
16095
break;
161-
} else if (parsed.type === "user" && !DEFAULTS.includes(content) && content) {
96+
} else if (parsed.type === "user" && parsed.message && !DEFAULTS.includes(content) && content) {
16297
// Collect user message (we'll reverse later to maintain chronological order)
163-
userMessages.unshift(content);
98+
99+
let strippedcontent = content.replace(
100+
/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g,
101+
""
102+
);
103+
strippedcontent = content.replace(
104+
/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g,
105+
""
106+
);
107+
108+
userMessages.unshift(strippedcontent);
164109
gotAtleastOne = true;
165110
}
166111
}

plugin/scripts/cli.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function extractLastAssistantWithPrecedingUsers(transcriptPath, stripSystemRemin
6565
const parsedLines = lines.map((line) => JSON.parse(line));
6666
let lastAssistantIndex = -1;
6767
for (let i = parsedLines.length - 1; i >= 0; i--) {
68-
let assistantMessage2 = extractMessageContent(parsedLines[lastAssistantIndex]);
68+
let assistantMessage2 = extractMessageContent(parsedLines[i]);
6969
if (parsedLines[i].type === "assistant" && assistantMessage2) {
7070
lastAssistantIndex = i;
7171
break;
@@ -86,8 +86,10 @@ function extractLastAssistantWithPrecedingUsers(transcriptPath, stripSystemRemin
8686
const content2 = extractMessageContent(parsed);
8787
if (parsed.type === "assistant" && parsed.message && gotAtleastOne && content2) {
8888
break;
89-
} else if (parsed.type === "user" && !DEFAULTS.includes(content2) && content2) {
90-
userMessages.unshift(content2);
89+
} else if (parsed.type === "user" && parsed.message && !DEFAULTS.includes(content2) && content2) {
90+
let strippedcontent = content2.replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g, "");
91+
strippedcontent = content2.replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g, "");
92+
userMessages.unshift(strippedcontent);
9193
gotAtleastOne = true;
9294
}
9395
}

plugin/scripts/run-conversation-read.mjs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ function extractMessageContent(parsed) {
1919
throw new Error(`Unknown message content format. Type: ${typeof msgContent}`);
2020
}
2121
}
22+
23+
var DEFAULTS = ["[Request interrupted by user for tool use]"];
24+
2225
__name(extractMessageContent, "extractMessageContent");
23-
function extractLastAssistantWithPrecedingUsers(_transcriptPath, stripSystemReminders = false) {
26+
function extractLastAssistantWithPrecedingUsers(transcriptPath, stripSystemReminders = false) {
27+
// const transcriptPath =
28+
// "/Users/harshithmullapudi/.claude/projects/-Users-harshithmullapudi-Documents-core/48ab3b13-0743-40c7-8733-1c42049343ba.jsonl";
2429
if (!transcriptPath || !existsSync(transcriptPath)) {
2530
throw new Error(`Transcript path missing or file does not exist: ${transcriptPath}`);
2631
}
27-
2832
const content = readFileSync(transcriptPath, "utf-8").trim();
2933
if (!content) {
3034
throw new Error(`Transcript file exists but is empty: ${transcriptPath}`);
@@ -33,7 +37,8 @@ function extractLastAssistantWithPrecedingUsers(_transcriptPath, stripSystemRemi
3337
const parsedLines = lines.map((line) => JSON.parse(line));
3438
let lastAssistantIndex = -1;
3539
for (let i = parsedLines.length - 1; i >= 0; i--) {
36-
if (parsedLines[i].type === "assistant") {
40+
let assistantMessage2 = extractMessageContent(parsedLines[i]);
41+
if (parsedLines[i].type === "assistant" && assistantMessage2) {
3742
lastAssistantIndex = i;
3843
break;
3944
}
@@ -51,14 +56,27 @@ function extractLastAssistantWithPrecedingUsers(_transcriptPath, stripSystemRemi
5156
}
5257
const userMessages = [];
5358
let gotAtleastOne = false;
54-
5559
for (let i = lastAssistantIndex - 1; i >= 0; i--) {
5660
const parsed = parsedLines[i];
5761

58-
if (parsed.type === "assistant" && gotAtleastOne && extractMessageContent(parsed)) {
62+
const content2 = extractMessageContent(parsed);
63+
if (parsed.type === "assistant" && gotAtleastOne && content2) {
5964
break;
60-
} else if (parsed.type === "user" && extractMessageContent(parsed)) {
61-
userMessages.unshift(extractMessageContent(parsed));
65+
} else if (
66+
parsed.type === "user" &&
67+
parsed.message &&
68+
!DEFAULTS.includes(content2) &&
69+
content2
70+
) {
71+
let strippedcontent = content2.replace(
72+
/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g,
73+
""
74+
);
75+
strippedcontent = content2.replace(
76+
/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g,
77+
""
78+
);
79+
userMessages.unshift(strippedcontent);
6280
gotAtleastOne = true;
6381
}
6482
}

0 commit comments

Comments
 (0)