diff --git a/src-node/claude-code-agent.js b/src-node/claude-code-agent.js index 40eb387683..82a11d3f9f 100644 --- a/src-node/claude-code-agent.js +++ b/src-node/claude-code-agent.js @@ -270,8 +270,8 @@ exports.cancelQuery = async function () { if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; - // Clear session so next query starts fresh instead of resuming a killed session - currentSessionId = null; + // Keep currentSessionId so the next prompt resumes the same SDK session. + // Aborts leave an interrupt marker in the session log, not a corrupted state. // Clear any pending question or plan _questionResolve = null; _planResolve = null; @@ -522,7 +522,13 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, content = fs.readFileSync(input.tool_input.file_path, "utf8"); } if (input.tool_input.old_string && input.tool_input.new_string) { - content = content.replace(input.tool_input.old_string, input.tool_input.new_string); + if (input.tool_input.replace_all === true) { + content = content.split(input.tool_input.old_string) + .join(input.tool_input.new_string); + } else { + content = content.replace(input.tool_input.old_string, + input.tool_input.new_string); + } } const dir = path.dirname(input.tool_input.file_path); if (!fs.existsSync(dir)) { @@ -550,7 +556,8 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, const edit = { file: input.tool_input.file_path, oldText: input.tool_input.old_string, - newText: input.tool_input.new_string + newText: input.tool_input.new_string, + replaceAll: input.tool_input.replace_all === true }; editCount++; let editResult; @@ -1249,13 +1256,11 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, return; } _log("Cancelled"); - // Send sessionId so browser side can save partial history for later resume - const cancelledSessionId = currentSessionId; - // Clear session so next query starts fresh - currentSessionId = null; + // Keep currentSessionId so the next prompt can resume the same SDK + // session — the abort just leaves an interrupt marker in the log. nodeConnector.triggerPeer("aiComplete", { requestId: requestId, - sessionId: cancelledSessionId + sessionId: currentSessionId }); return; } @@ -1281,8 +1286,9 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, } } - // Clear session after error to prevent cascading failures from resuming a broken session - currentSessionId = null; + // Keep currentSessionId so the user can retry — errors are often + // transient (network, rate limit), and if the session really is broken + // the next attempt will surface a fresh error of its own. nodeConnector.triggerPeer("aiError", { requestId: requestId, @@ -1292,7 +1298,7 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, // Always send aiComplete after aiError so the UI exits streaming state nodeConnector.triggerPeer("aiComplete", { requestId: requestId, - sessionId: null + sessionId: currentSessionId }); } } diff --git a/tracking-repos.json b/tracking-repos.json index 44d0dd5a11..b883c1d8bc 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "871b8fdaf238c0bedd9dc1e24cbc75ee67987453" + "commitID": "4749d2e7bbdbe93f5f4c270212b30b02061c0d7b" } }