Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src-node/claude-code-agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,21 +269,33 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale)
newText: input.tool_input.new_string
};
editCount++;
let editResult;
try {
await nodeConnector.execPeer("applyEditToBuffer", edit);
editResult = await nodeConnector.execPeer("applyEditToBuffer", edit);
} catch (err) {
console.warn("[Phoenix AI] Failed to apply edit to buffer:", err.message);
editResult = { applied: false, error: err.message };
}
nodeConnector.triggerPeer("aiToolEdit", {
requestId: requestId,
toolId: myToolId,
edit: edit
});
let reason;
if (editResult && editResult.applied === false) {
reason = "Edit FAILED: " + (editResult.error || "unknown error");
} else {
reason = "Edit applied successfully via Phoenix editor.";
if (editResult && editResult.isLivePreviewRelated) {
reason += " The edited file is part of the active live preview." +
" Reload when ready with execJsInLivePreview: `location.reload()`";
}
}
return {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Edit applied successfully via Phoenix editor."
permissionDecisionReason: reason
}
};
}
Expand Down Expand Up @@ -342,21 +354,33 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale)
newText: input.tool_input.content
};
editCount++;
let writeResult;
try {
await nodeConnector.execPeer("applyEditToBuffer", edit);
writeResult = await nodeConnector.execPeer("applyEditToBuffer", edit);
} catch (err) {
console.warn("[Phoenix AI] Failed to apply write to buffer:", err.message);
writeResult = { applied: false, error: err.message };
}
nodeConnector.triggerPeer("aiToolEdit", {
requestId: requestId,
toolId: myToolId,
edit: edit
});
let reason;
if (writeResult && writeResult.applied === false) {
reason = "Write FAILED: " + (writeResult.error || "unknown error");
} else {
reason = "Write applied successfully via Phoenix editor.";
if (writeResult && writeResult.isLivePreviewRelated) {
reason += " The written file is part of the active live preview." +
" Reload when ready with execJsInLivePreview: `location.reload()`";
}
}
return {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Write applied successfully via Phoenix editor."
permissionDecisionReason: reason
}
};
}
Expand Down
28 changes: 11 additions & 17 deletions src/LiveDevelopment/BrowserScripts/RemoteFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ function RemoteFunctions(config = {}) {
if (this.trigger) {
_trigger(this.elements[i], "highlight", 0);
}
clearElementBackground(this.elements[i]);
clearElementHoverHighlight(this.elements[i]);
}

this.elements = [];
Expand Down Expand Up @@ -583,19 +583,12 @@ function RemoteFunctions(config = {}) {
return getHighlightMode() !== "click";
}

// helper function to clear element background highlighting
function clearElementBackground(element) {
if (element._originalBackgroundColor !== undefined) {
element.style.backgroundColor = element._originalBackgroundColor;
} else {
// only clear background if it's currently a highlight color, not if it's an original user style
const currentBg = element.style.backgroundColor;
if (currentBg === "rgba(0, 162, 255, 0.2)" || currentBg.includes("rgba(0, 162, 255")) {
element.style.backgroundColor = "";
}
// if it's some other color, we just leave it as is - it's likely a user-defined style
// helper function to clear element hover outline highlighting
function clearElementHoverHighlight(element) {
if (element._originalHoverOutline !== undefined) {
element.style.outline = element._originalHoverOutline;
}
delete element._originalBackgroundColor;
delete element._originalHoverOutline;
}

function onElementHover(event) {
Expand All @@ -622,9 +615,10 @@ function RemoteFunctions(config = {}) {
if (_hoverHighlight && shouldShowHighlightOnHover()) {
_hoverHighlight.clear();

// Store original background color to restore on hover out
element._originalBackgroundColor = element.style.backgroundColor;
element.style.backgroundColor = "rgba(0, 162, 255, 0.2)";
// Store original outline to restore on hover out, then apply a blue border
element._originalHoverOutline = element.style.outline;
const outlineColor = element.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR) ? "#4285F4" : "#3C3F41";
element.style.outline = `1px solid ${outlineColor}`;

_hoverHighlight.add(element, false);

Expand All @@ -646,7 +640,7 @@ function RemoteFunctions(config = {}) {
// this is to check the user's settings, if they want to show the elements highlights on hover or click
if (_hoverHighlight && shouldShowHighlightOnHover()) {
_hoverHighlight.clear();
clearElementBackground(element);
clearElementHoverHighlight(element);
// dismiss the info box
const infoBoxHandler = LivePreviewView.getToolHandler("InfoBox");
if (infoBoxHandler) {
Expand Down
18 changes: 17 additions & 1 deletion src/core-ai/aiPhoenixConnectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,30 @@ define(function (require, exports, module) {
* @param {Object} params - {file, oldText, newText}
* @return {Promise<{applied: boolean, error?: string}>}
*/
function _isFileInLivePreview(filePath) {
const liveDetails = LiveDevMain.getLivePreviewDetails();
if (!liveDetails || !liveDetails.liveDocument) {
return false;
}
const vfsPath = SnapshotStore.realToVfsPath(filePath);
const liveDocPath = liveDetails.liveDocument.doc.file.fullPath;
if (vfsPath === liveDocPath) {
return true;
}
return !!(liveDetails.liveDocument.isRelated && liveDetails.liveDocument.isRelated(vfsPath));
}

function applyEditToBuffer(params) {
const deferred = new $.Deferred();
_applySingleEdit(params)
.done(function (result) {
if (result && result.previousContent !== undefined) {
_previousContentMap[params.file] = result.previousContent;
}
deferred.resolve({ applied: true });
deferred.resolve({
applied: true,
isLivePreviewRelated: _isFileInLivePreview(params.file)
});
})
.fail(function (err) {
deferred.resolve({ applied: false, error: err.message || String(err) });
Expand Down
Loading