Skip to content

Commit 241e4dd

Browse files
committed
feat: claude code integration continued
1 parent 52e291f commit 241e4dd

5 files changed

Lines changed: 390 additions & 43 deletions

File tree

src-node/claude-code-agent.js

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,36 +211,89 @@ async function _runQuery(requestId, prompt, projectPath, model, signal) {
211211
hooks: [
212212
async (input) => {
213213
console.log("[Phoenix AI] Intercepted Edit tool");
214-
collectedEdits.push({
214+
const edit = {
215215
file: input.tool_input.file_path,
216216
oldText: input.tool_input.old_string,
217217
newText: input.tool_input.new_string
218-
});
218+
};
219+
collectedEdits.push(edit);
220+
try {
221+
await nodeConnector.execPeer("applyEditToBuffer", edit);
222+
} catch (err) {
223+
console.warn("[Phoenix AI] Failed to apply edit to buffer:", err.message);
224+
}
219225
return {
220226
hookSpecificOutput: {
221227
hookEventName: "PreToolUse",
222228
permissionDecision: "deny",
223-
permissionDecisionReason: "Edit delegated to Phoenix editor"
229+
permissionDecisionReason: "Edit applied successfully via Phoenix editor."
224230
}
225231
};
226232
}
227233
]
228234
},
235+
{
236+
matcher: "Read",
237+
hooks: [
238+
async (input) => {
239+
const filePath = input.tool_input.file_path;
240+
if (!filePath) {
241+
return undefined;
242+
}
243+
try {
244+
const result = await nodeConnector.execPeer("getFileContent", { filePath });
245+
if (result && result.isDirty && result.content !== null) {
246+
const MAX_LINES = 2000;
247+
const MAX_LINE_LENGTH = 2000;
248+
const lines = result.content.split("\n");
249+
const offset = input.tool_input.offset || 0;
250+
const limit = input.tool_input.limit || MAX_LINES;
251+
const selected = lines.slice(offset, offset + limit);
252+
let formatted = selected.map((line, i) => {
253+
const truncated = line.length > MAX_LINE_LENGTH
254+
? line.slice(0, MAX_LINE_LENGTH) + "..."
255+
: line;
256+
return String(offset + i + 1).padStart(6) + "\t" + truncated;
257+
}).join("\n");
258+
formatted = filePath + " (unsaved editor content, " +
259+
lines.length + " lines total)\n\n" + formatted;
260+
console.log("[Phoenix AI] Serving dirty file content for:", filePath);
261+
return {
262+
hookSpecificOutput: {
263+
hookEventName: "PreToolUse",
264+
permissionDecision: "deny",
265+
permissionDecisionReason: formatted
266+
}
267+
};
268+
}
269+
} catch (err) {
270+
console.warn("[Phoenix AI] Failed to check dirty state:", filePath, err.message);
271+
}
272+
return undefined;
273+
}
274+
]
275+
},
229276
{
230277
matcher: "Write",
231278
hooks: [
232279
async (input) => {
233280
console.log("[Phoenix AI] Intercepted Write tool");
234-
collectedEdits.push({
281+
const edit = {
235282
file: input.tool_input.file_path,
236283
oldText: null,
237284
newText: input.tool_input.content
238-
});
285+
};
286+
collectedEdits.push(edit);
287+
try {
288+
await nodeConnector.execPeer("applyEditToBuffer", edit);
289+
} catch (err) {
290+
console.warn("[Phoenix AI] Failed to apply write to buffer:", err.message);
291+
}
239292
return {
240293
hookSpecificOutput: {
241294
hookEventName: "PreToolUse",
242295
permissionDecision: "deny",
243-
permissionDecisionReason: "Write delegated to Phoenix editor"
296+
permissionDecisionReason: "Write applied successfully via Phoenix editor."
244297
}
245298
};
246299
}
@@ -279,6 +332,7 @@ async function _runQuery(requestId, prompt, projectPath, model, signal) {
279332
let activeToolIndex = null;
280333
let activeToolInputJson = "";
281334
let toolCounter = 0;
335+
let lastToolStreamTime = 0;
282336

283337
for await (const message of result) {
284338
// Check abort
@@ -310,11 +364,21 @@ async function _runQuery(requestId, prompt, projectPath, model, signal) {
310364
});
311365
}
312366

313-
// Accumulate tool input JSON
367+
// Accumulate tool input JSON and stream preview
314368
if (event.type === "content_block_delta" &&
315369
event.delta?.type === "input_json_delta" &&
316370
event.index === activeToolIndex) {
317371
activeToolInputJson += event.delta.partial_json;
372+
const now = Date.now();
373+
if (now - lastToolStreamTime >= TEXT_STREAM_THROTTLE_MS) {
374+
lastToolStreamTime = now;
375+
nodeConnector.triggerPeer("aiToolStream", {
376+
requestId: requestId,
377+
toolId: toolCounter,
378+
toolName: activeToolName,
379+
partialJson: activeToolInputJson
380+
});
381+
}
318382
}
319383

320384
// Tool block complete — parse input and send details

0 commit comments

Comments
 (0)