@posthog/agent 2.1.131 → 2.1.137
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/dist/adapters/claude/conversion/tool-use-to-acp.d.ts +14 -28
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +116 -164
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/permissions/permission-options.js +33 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/tools.js +21 -11
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +1251 -606
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +2 -2
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +1300 -655
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +1278 -635
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +2 -2
- package/src/adapters/base-acp-agent.ts +6 -3
- package/src/adapters/claude/UPSTREAM.md +63 -0
- package/src/adapters/claude/claude-agent.ts +682 -421
- package/src/adapters/claude/conversion/sdk-to-acp.ts +249 -85
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +174 -149
- package/src/adapters/claude/hooks.ts +53 -1
- package/src/adapters/claude/permissions/permission-handlers.ts +39 -21
- package/src/adapters/claude/session/commands.ts +13 -9
- package/src/adapters/claude/session/mcp-config.ts +2 -5
- package/src/adapters/claude/session/options.ts +58 -6
- package/src/adapters/claude/session/settings.ts +326 -0
- package/src/adapters/claude/tools.ts +1 -0
- package/src/adapters/claude/types.ts +38 -0
- package/src/execution-mode.ts +26 -10
- package/src/server/agent-server.test.ts +41 -1
- package/src/utils/common.ts +1 -1
package/dist/server/bin.cjs
CHANGED
|
@@ -509,7 +509,7 @@ var require_has_flag = __commonJS({
|
|
|
509
509
|
var require_supports_color = __commonJS({
|
|
510
510
|
"../../node_modules/supports-color/index.js"(exports2, module2) {
|
|
511
511
|
"use strict";
|
|
512
|
-
var
|
|
512
|
+
var os5 = require("os");
|
|
513
513
|
var tty = require("tty");
|
|
514
514
|
var hasFlag = require_has_flag();
|
|
515
515
|
var { env } = process;
|
|
@@ -557,7 +557,7 @@ var require_supports_color = __commonJS({
|
|
|
557
557
|
return min;
|
|
558
558
|
}
|
|
559
559
|
if (process.platform === "win32") {
|
|
560
|
-
const osRelease =
|
|
560
|
+
const osRelease = os5.release().split(".");
|
|
561
561
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
562
562
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
563
563
|
}
|
|
@@ -805,10 +805,10 @@ var require_src2 = __commonJS({
|
|
|
805
805
|
var fs_1 = require("fs");
|
|
806
806
|
var debug_1 = __importDefault(require_src());
|
|
807
807
|
var log = debug_1.default("@kwsites/file-exists");
|
|
808
|
-
function check(
|
|
809
|
-
log(`checking %s`,
|
|
808
|
+
function check(path9, isFile, isDirectory) {
|
|
809
|
+
log(`checking %s`, path9);
|
|
810
810
|
try {
|
|
811
|
-
const stat = fs_1.statSync(
|
|
811
|
+
const stat = fs_1.statSync(path9);
|
|
812
812
|
if (stat.isFile() && isFile) {
|
|
813
813
|
log(`[OK] path represents a file`);
|
|
814
814
|
return true;
|
|
@@ -828,8 +828,8 @@ var require_src2 = __commonJS({
|
|
|
828
828
|
throw e;
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
|
-
function exists2(
|
|
832
|
-
return check(
|
|
831
|
+
function exists2(path9, type = exports2.READABLE) {
|
|
832
|
+
return check(path9, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
|
|
833
833
|
}
|
|
834
834
|
exports2.exists = exists2;
|
|
835
835
|
exports2.FILE = 1;
|
|
@@ -904,7 +904,7 @@ var import_hono = require("hono");
|
|
|
904
904
|
// package.json
|
|
905
905
|
var package_default = {
|
|
906
906
|
name: "@posthog/agent",
|
|
907
|
-
version: "2.1.
|
|
907
|
+
version: "2.1.137",
|
|
908
908
|
repository: "https://github.com/PostHog/twig",
|
|
909
909
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
910
910
|
exports: {
|
|
@@ -980,7 +980,6 @@ var package_default = {
|
|
|
980
980
|
"@twig/git": "workspace:*",
|
|
981
981
|
"@types/bun": "latest",
|
|
982
982
|
"@types/tar": "^6.1.13",
|
|
983
|
-
minimatch: "^10.0.3",
|
|
984
983
|
msw: "^2.12.7",
|
|
985
984
|
tsup: "^8.5.1",
|
|
986
985
|
tsx: "^4.20.6",
|
|
@@ -1001,6 +1000,7 @@ var package_default = {
|
|
|
1001
1000
|
commander: "^14.0.2",
|
|
1002
1001
|
hono: "^4.11.7",
|
|
1003
1002
|
jsonwebtoken: "^9.0.2",
|
|
1003
|
+
minimatch: "^10.0.3",
|
|
1004
1004
|
tar: "^7.5.0",
|
|
1005
1005
|
uuid: "13.0.0",
|
|
1006
1006
|
"yoga-wasm-web": "^0.3.3",
|
|
@@ -1281,9 +1281,10 @@ function nodeWritableToWebWritable(nodeStream) {
|
|
|
1281
1281
|
}
|
|
1282
1282
|
|
|
1283
1283
|
// src/adapters/claude/claude-agent.ts
|
|
1284
|
-
var
|
|
1285
|
-
var
|
|
1286
|
-
var
|
|
1284
|
+
var import_node_crypto = require("crypto");
|
|
1285
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
1286
|
+
var os4 = __toESM(require("os"), 1);
|
|
1287
|
+
var path4 = __toESM(require("path"), 1);
|
|
1287
1288
|
var import_sdk2 = require("@agentclientprotocol/sdk");
|
|
1288
1289
|
var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
|
|
1289
1290
|
var import_uuid = require("uuid");
|
|
@@ -1305,7 +1306,7 @@ function unreachable(value, logger) {
|
|
|
1305
1306
|
try {
|
|
1306
1307
|
valueAsString = JSON.stringify(value);
|
|
1307
1308
|
} catch {
|
|
1308
|
-
valueAsString = value;
|
|
1309
|
+
valueAsString = String(value);
|
|
1309
1310
|
}
|
|
1310
1311
|
logger.error(`Unexpected case: ${valueAsString}`);
|
|
1311
1312
|
}
|
|
@@ -1377,19 +1378,20 @@ var BaseAcpAgent = class {
|
|
|
1377
1378
|
}
|
|
1378
1379
|
async cancel(params) {
|
|
1379
1380
|
if (this.sessionId !== params.sessionId) {
|
|
1380
|
-
throw new Error("Session
|
|
1381
|
+
throw new Error("Session ID mismatch");
|
|
1381
1382
|
}
|
|
1382
1383
|
this.session.cancelled = true;
|
|
1383
1384
|
const meta = params._meta;
|
|
1384
1385
|
if (meta?.interruptReason) {
|
|
1385
1386
|
this.session.interruptReason = meta.interruptReason;
|
|
1386
1387
|
}
|
|
1387
|
-
await this.
|
|
1388
|
+
await this.interrupt();
|
|
1388
1389
|
}
|
|
1389
1390
|
async closeSession() {
|
|
1390
1391
|
try {
|
|
1391
1392
|
this.session.abortController.abort();
|
|
1392
1393
|
await this.cancel({ sessionId: this.sessionId });
|
|
1394
|
+
this.session.settingsManager.dispose();
|
|
1393
1395
|
this.logger.info("Closed session", { sessionId: this.sessionId });
|
|
1394
1396
|
} catch (err) {
|
|
1395
1397
|
this.logger.warn("Failed to close session", {
|
|
@@ -1564,8 +1566,8 @@ var ToolContentBuilder = class {
|
|
|
1564
1566
|
this.items.push({ type: "content", content: image(data, mimeType, uri) });
|
|
1565
1567
|
return this;
|
|
1566
1568
|
}
|
|
1567
|
-
diff(
|
|
1568
|
-
this.items.push({ type: "diff", path:
|
|
1569
|
+
diff(path9, oldText, newText) {
|
|
1570
|
+
this.items.push({ type: "diff", path: path9, oldText, newText });
|
|
1569
1571
|
return this;
|
|
1570
1572
|
}
|
|
1571
1573
|
build() {
|
|
@@ -1585,7 +1587,7 @@ var registerHookCallback = (toolUseID, {
|
|
|
1585
1587
|
onPostToolUseHook
|
|
1586
1588
|
};
|
|
1587
1589
|
};
|
|
1588
|
-
var createPostToolUseHook = ({ onModeChange }) => async (input, toolUseID) => {
|
|
1590
|
+
var createPostToolUseHook = ({ onModeChange, logger }) => async (input, toolUseID) => {
|
|
1589
1591
|
if (input.hook_event_name === "PostToolUse") {
|
|
1590
1592
|
const toolName = input.tool_name;
|
|
1591
1593
|
if (onModeChange && toolName === "EnterPlanMode") {
|
|
@@ -1600,11 +1602,54 @@ var createPostToolUseHook = ({ onModeChange }) => async (input, toolUseID) => {
|
|
|
1600
1602
|
input.tool_response
|
|
1601
1603
|
);
|
|
1602
1604
|
delete toolUseCallbacks[toolUseID];
|
|
1605
|
+
} else {
|
|
1606
|
+
logger?.error(
|
|
1607
|
+
`No onPostToolUseHook found for tool use ID: ${toolUseID}`
|
|
1608
|
+
);
|
|
1609
|
+
delete toolUseCallbacks[toolUseID];
|
|
1603
1610
|
}
|
|
1604
1611
|
}
|
|
1605
1612
|
}
|
|
1606
1613
|
return { continue: true };
|
|
1607
1614
|
};
|
|
1615
|
+
var createPreToolUseHook = (settingsManager, logger) => async (input, _toolUseID) => {
|
|
1616
|
+
if (input.hook_event_name !== "PreToolUse") {
|
|
1617
|
+
return { continue: true };
|
|
1618
|
+
}
|
|
1619
|
+
const toolName = input.tool_name;
|
|
1620
|
+
const toolInput = input.tool_input;
|
|
1621
|
+
const permissionCheck = settingsManager.checkPermission(
|
|
1622
|
+
toolName,
|
|
1623
|
+
toolInput
|
|
1624
|
+
);
|
|
1625
|
+
if (permissionCheck.decision !== "ask") {
|
|
1626
|
+
logger.info(
|
|
1627
|
+
`[PreToolUseHook] Tool: ${toolName}, Decision: ${permissionCheck.decision}, Rule: ${permissionCheck.rule}`
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1630
|
+
switch (permissionCheck.decision) {
|
|
1631
|
+
case "allow":
|
|
1632
|
+
return {
|
|
1633
|
+
continue: true,
|
|
1634
|
+
hookSpecificOutput: {
|
|
1635
|
+
hookEventName: "PreToolUse",
|
|
1636
|
+
permissionDecision: "allow",
|
|
1637
|
+
permissionDecisionReason: `Allowed by settings rule: ${permissionCheck.rule}`
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
case "deny":
|
|
1641
|
+
return {
|
|
1642
|
+
continue: true,
|
|
1643
|
+
hookSpecificOutput: {
|
|
1644
|
+
hookEventName: "PreToolUse",
|
|
1645
|
+
permissionDecision: "deny",
|
|
1646
|
+
permissionDecisionReason: `Denied by settings rule: ${permissionCheck.rule}`
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1649
|
+
default:
|
|
1650
|
+
return { continue: true };
|
|
1651
|
+
}
|
|
1652
|
+
};
|
|
1608
1653
|
|
|
1609
1654
|
// src/adapters/claude/mcp/tool-metadata.ts
|
|
1610
1655
|
var mcpToolMetadataCache = /* @__PURE__ */ new Map();
|
|
@@ -1681,79 +1726,7 @@ var SYSTEM_REMINDER = `
|
|
|
1681
1726
|
<system-reminder>
|
|
1682
1727
|
Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.
|
|
1683
1728
|
</system-reminder>`;
|
|
1684
|
-
function
|
|
1685
|
-
let currentContent = fileContent;
|
|
1686
|
-
const randomHex = Array.from(crypto.getRandomValues(new Uint8Array(5))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1687
|
-
const markerPrefix = `__REPLACE_MARKER_${randomHex}_`;
|
|
1688
|
-
let markerCounter = 0;
|
|
1689
|
-
const markers = [];
|
|
1690
|
-
for (const edit of edits) {
|
|
1691
|
-
if (edit.oldText === "") {
|
|
1692
|
-
throw new Error(
|
|
1693
|
-
`The provided \`old_string\` is empty.
|
|
1694
|
-
|
|
1695
|
-
No edits were applied.`
|
|
1696
|
-
);
|
|
1697
|
-
}
|
|
1698
|
-
if (edit.replaceAll) {
|
|
1699
|
-
const parts = [];
|
|
1700
|
-
let lastIndex = 0;
|
|
1701
|
-
let searchIndex = 0;
|
|
1702
|
-
while (true) {
|
|
1703
|
-
const index = currentContent.indexOf(edit.oldText, searchIndex);
|
|
1704
|
-
if (index === -1) {
|
|
1705
|
-
if (searchIndex === 0) {
|
|
1706
|
-
throw new Error(
|
|
1707
|
-
`The provided \`old_string\` does not appear in the file: "${edit.oldText}".
|
|
1708
|
-
|
|
1709
|
-
No edits were applied.`
|
|
1710
|
-
);
|
|
1711
|
-
}
|
|
1712
|
-
break;
|
|
1713
|
-
}
|
|
1714
|
-
parts.push(currentContent.substring(lastIndex, index));
|
|
1715
|
-
const marker = `${markerPrefix}${markerCounter++}__`;
|
|
1716
|
-
markers.push(marker);
|
|
1717
|
-
parts.push(marker + edit.newText);
|
|
1718
|
-
lastIndex = index + edit.oldText.length;
|
|
1719
|
-
searchIndex = lastIndex;
|
|
1720
|
-
}
|
|
1721
|
-
parts.push(currentContent.substring(lastIndex));
|
|
1722
|
-
currentContent = parts.join("");
|
|
1723
|
-
} else {
|
|
1724
|
-
const index = currentContent.indexOf(edit.oldText);
|
|
1725
|
-
if (index === -1) {
|
|
1726
|
-
throw new Error(
|
|
1727
|
-
`The provided \`old_string\` does not appear in the file: "${edit.oldText}".
|
|
1728
|
-
|
|
1729
|
-
No edits were applied.`
|
|
1730
|
-
);
|
|
1731
|
-
} else {
|
|
1732
|
-
const marker = `${markerPrefix}${markerCounter++}__`;
|
|
1733
|
-
markers.push(marker);
|
|
1734
|
-
currentContent = currentContent.substring(0, index) + marker + edit.newText + currentContent.substring(index + edit.oldText.length);
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
const lineNumbers = [];
|
|
1739
|
-
for (const marker of markers) {
|
|
1740
|
-
const index = currentContent.indexOf(marker);
|
|
1741
|
-
if (index !== -1) {
|
|
1742
|
-
const lineNumber = Math.max(
|
|
1743
|
-
0,
|
|
1744
|
-
currentContent.substring(0, index).split(/\r\n|\r|\n/).length - 1
|
|
1745
|
-
);
|
|
1746
|
-
lineNumbers.push(lineNumber);
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
let finalContent = currentContent;
|
|
1750
|
-
for (const marker of markers) {
|
|
1751
|
-
finalContent = finalContent.replace(marker, "");
|
|
1752
|
-
}
|
|
1753
|
-
const uniqueLineNumbers = [...new Set(lineNumbers)].sort();
|
|
1754
|
-
return { newContent: finalContent, lineNumbers: uniqueLineNumbers };
|
|
1755
|
-
}
|
|
1756
|
-
function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ debug: false, prefix: "[ClaudeTools]" })) {
|
|
1729
|
+
function toolInfoFromToolUse(toolUse, options) {
|
|
1757
1730
|
const name = toolUse.name;
|
|
1758
1731
|
const input = toolUse.input;
|
|
1759
1732
|
switch (name) {
|
|
@@ -1778,6 +1751,13 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1778
1751
|
locations: input?.notebook_path ? [{ path: String(input.notebook_path) }] : []
|
|
1779
1752
|
};
|
|
1780
1753
|
case "Bash":
|
|
1754
|
+
if (options?.supportsTerminalOutput && options?.toolUseId) {
|
|
1755
|
+
return {
|
|
1756
|
+
title: input?.description ? String(input.description) : "Execute command",
|
|
1757
|
+
kind: "execute",
|
|
1758
|
+
content: [{ type: "terminal", terminalId: options.toolUseId }]
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1781
1761
|
return {
|
|
1782
1762
|
title: input?.description ? String(input.description) : "Execute command",
|
|
1783
1763
|
kind: "execute",
|
|
@@ -1798,11 +1778,11 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1798
1778
|
case "Read": {
|
|
1799
1779
|
let limit = "";
|
|
1800
1780
|
const inputLimit = input?.limit;
|
|
1801
|
-
const inputOffset = input?.offset ??
|
|
1781
|
+
const inputOffset = input?.offset ?? 1;
|
|
1802
1782
|
if (inputLimit) {
|
|
1803
|
-
limit = ` (${inputOffset
|
|
1804
|
-
} else if (inputOffset) {
|
|
1805
|
-
limit = ` (from line ${inputOffset
|
|
1783
|
+
limit = ` (${inputOffset} - ${inputOffset + inputLimit - 1})`;
|
|
1784
|
+
} else if (inputOffset > 1) {
|
|
1785
|
+
limit = ` (from line ${inputOffset})`;
|
|
1806
1786
|
}
|
|
1807
1787
|
return {
|
|
1808
1788
|
title: `Read ${input?.file_path ? String(input.file_path) : "File"}${limit}`,
|
|
@@ -1824,39 +1804,21 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1824
1804
|
locations: []
|
|
1825
1805
|
};
|
|
1826
1806
|
case "Edit": {
|
|
1827
|
-
const
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
let affectedLines = [];
|
|
1831
|
-
if (path8 && oldText) {
|
|
1832
|
-
try {
|
|
1833
|
-
const oldContent = cachedFileContent[path8] || "";
|
|
1834
|
-
const newContent = replaceAndCalculateLocation(oldContent, [
|
|
1835
|
-
{
|
|
1836
|
-
oldText,
|
|
1837
|
-
newText,
|
|
1838
|
-
replaceAll: false
|
|
1839
|
-
}
|
|
1840
|
-
]);
|
|
1841
|
-
oldText = oldContent;
|
|
1842
|
-
newText = newContent.newContent;
|
|
1843
|
-
affectedLines = newContent.lineNumbers;
|
|
1844
|
-
} catch (e) {
|
|
1845
|
-
logger.error("Failed to edit file", e);
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1807
|
+
const path9 = input?.file_path ? String(input.file_path) : void 0;
|
|
1808
|
+
const oldText = input?.old_string ? String(input.old_string) : null;
|
|
1809
|
+
const newText = input?.new_string ? String(input.new_string) : "";
|
|
1848
1810
|
return {
|
|
1849
|
-
title:
|
|
1811
|
+
title: path9 ? `Edit \`${path9}\`` : "Edit",
|
|
1850
1812
|
kind: "edit",
|
|
1851
|
-
content: input &&
|
|
1813
|
+
content: input && path9 ? [
|
|
1852
1814
|
{
|
|
1853
1815
|
type: "diff",
|
|
1854
|
-
path:
|
|
1816
|
+
path: path9,
|
|
1855
1817
|
oldText,
|
|
1856
1818
|
newText
|
|
1857
1819
|
}
|
|
1858
1820
|
] : [],
|
|
1859
|
-
locations:
|
|
1821
|
+
locations: path9 ? [{ path: path9 }] : []
|
|
1860
1822
|
};
|
|
1861
1823
|
}
|
|
1862
1824
|
case "Write": {
|
|
@@ -1910,10 +1872,10 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1910
1872
|
}
|
|
1911
1873
|
if (input?.output_mode) {
|
|
1912
1874
|
switch (input.output_mode) {
|
|
1913
|
-
case "
|
|
1875
|
+
case "files_with_matches":
|
|
1914
1876
|
label += " -l";
|
|
1915
1877
|
break;
|
|
1916
|
-
case "
|
|
1878
|
+
case "count":
|
|
1917
1879
|
label += " -c";
|
|
1918
1880
|
break;
|
|
1919
1881
|
default:
|
|
@@ -1932,7 +1894,9 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1932
1894
|
if (input?.multiline) {
|
|
1933
1895
|
label += " -P";
|
|
1934
1896
|
}
|
|
1935
|
-
|
|
1897
|
+
if (input?.pattern) {
|
|
1898
|
+
label += ` "${String(input.pattern)}"`;
|
|
1899
|
+
}
|
|
1936
1900
|
if (input?.path) {
|
|
1937
1901
|
label += ` ${String(input.path)}`;
|
|
1938
1902
|
}
|
|
@@ -2026,7 +1990,49 @@ function mcpToolInfo(name, _input) {
|
|
|
2026
1990
|
content: []
|
|
2027
1991
|
};
|
|
2028
1992
|
}
|
|
2029
|
-
function
|
|
1993
|
+
function toolUpdateFromEditToolResponse(toolResponse) {
|
|
1994
|
+
if (!toolResponse || typeof toolResponse !== "object") return null;
|
|
1995
|
+
const response = toolResponse;
|
|
1996
|
+
const patches = response.structuredPatch;
|
|
1997
|
+
if (!Array.isArray(patches) || patches.length === 0) return null;
|
|
1998
|
+
const content = [];
|
|
1999
|
+
const locations = [];
|
|
2000
|
+
for (const patch of patches) {
|
|
2001
|
+
if (!patch.hunks || patch.hunks.length === 0) continue;
|
|
2002
|
+
const filePath = patch.newFileName || patch.oldFileName;
|
|
2003
|
+
const oldLines = [];
|
|
2004
|
+
const newLines = [];
|
|
2005
|
+
for (const hunk of patch.hunks) {
|
|
2006
|
+
for (const line of hunk.lines) {
|
|
2007
|
+
if (line.startsWith("-")) {
|
|
2008
|
+
oldLines.push(line.slice(1));
|
|
2009
|
+
} else if (line.startsWith("+")) {
|
|
2010
|
+
newLines.push(line.slice(1));
|
|
2011
|
+
} else if (line.startsWith(" ")) {
|
|
2012
|
+
oldLines.push(line.slice(1));
|
|
2013
|
+
newLines.push(line.slice(1));
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
content.push({
|
|
2018
|
+
type: "diff",
|
|
2019
|
+
path: filePath,
|
|
2020
|
+
oldText: oldLines.join("\n"),
|
|
2021
|
+
newText: newLines.join("\n")
|
|
2022
|
+
});
|
|
2023
|
+
const firstHunk = patch.hunks[0];
|
|
2024
|
+
locations.push({
|
|
2025
|
+
path: filePath,
|
|
2026
|
+
line: firstHunk.newStart
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
if (content.length === 0) return null;
|
|
2030
|
+
return { content, locations };
|
|
2031
|
+
}
|
|
2032
|
+
function toolUpdateFromToolResult(toolResult, toolUse, options) {
|
|
2033
|
+
if ("is_error" in toolResult && toolResult.is_error && toolResult.content && toolResult.content.length > 0) {
|
|
2034
|
+
return toAcpContentUpdate(toolResult.content, true);
|
|
2035
|
+
}
|
|
2030
2036
|
switch (toolUse?.name) {
|
|
2031
2037
|
case "Read":
|
|
2032
2038
|
if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {
|
|
@@ -2043,6 +2049,16 @@ function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
|
2043
2049
|
)
|
|
2044
2050
|
};
|
|
2045
2051
|
}
|
|
2052
|
+
if (itemObj.type === "image" && itemObj.source) {
|
|
2053
|
+
return {
|
|
2054
|
+
type: "content",
|
|
2055
|
+
content: {
|
|
2056
|
+
type: "image",
|
|
2057
|
+
data: itemObj.source.data ?? "",
|
|
2058
|
+
mimeType: itemObj.source.media_type ?? "image/png"
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2046
2062
|
return {
|
|
2047
2063
|
type: "content",
|
|
2048
2064
|
content: item
|
|
@@ -2058,18 +2074,51 @@ function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
|
2058
2074
|
}
|
|
2059
2075
|
return {};
|
|
2060
2076
|
case "Bash": {
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2077
|
+
const result = toolResult.content;
|
|
2078
|
+
const terminalId = "tool_use_id" in toolResult ? String(toolResult.tool_use_id) : "";
|
|
2079
|
+
const isError = "is_error" in toolResult && toolResult.is_error;
|
|
2080
|
+
let output = "";
|
|
2081
|
+
let exitCode = isError ? 1 : 0;
|
|
2082
|
+
if (result && typeof result === "object" && "type" in result && result.type === "bash_code_execution_result") {
|
|
2083
|
+
const bashResult = result;
|
|
2084
|
+
output = [bashResult.stdout, bashResult.stderr].filter(Boolean).join("\n");
|
|
2085
|
+
exitCode = bashResult.return_code;
|
|
2086
|
+
} else if (typeof result === "string") {
|
|
2087
|
+
output = result;
|
|
2088
|
+
} else if (Array.isArray(result) && result.length > 0 && "text" in result[0] && typeof result[0].text === "string") {
|
|
2089
|
+
output = result.map((c) => c.text ?? "").join("\n");
|
|
2090
|
+
}
|
|
2091
|
+
if (options?.supportsTerminalOutput) {
|
|
2092
|
+
return {
|
|
2093
|
+
content: [{ type: "terminal", terminalId }],
|
|
2094
|
+
_meta: {
|
|
2095
|
+
terminal_info: {
|
|
2096
|
+
terminal_id: terminalId
|
|
2097
|
+
},
|
|
2098
|
+
terminal_output: {
|
|
2099
|
+
terminal_id: terminalId,
|
|
2100
|
+
data: output
|
|
2101
|
+
},
|
|
2102
|
+
terminal_exit: {
|
|
2103
|
+
terminal_id: terminalId,
|
|
2104
|
+
exit_code: exitCode,
|
|
2105
|
+
signal: null
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2110
|
+
if (output.trim()) {
|
|
2111
|
+
return {
|
|
2112
|
+
content: toolContent().text(`\`\`\`console
|
|
2113
|
+
${output.trimEnd()}
|
|
2114
|
+
\`\`\``).build()
|
|
2115
|
+
};
|
|
2070
2116
|
}
|
|
2071
2117
|
return {};
|
|
2072
2118
|
}
|
|
2119
|
+
case "Edit":
|
|
2120
|
+
case "Write":
|
|
2121
|
+
return {};
|
|
2073
2122
|
case "ExitPlanMode": {
|
|
2074
2123
|
return { title: "Exited Plan Mode" };
|
|
2075
2124
|
}
|
|
@@ -2229,6 +2278,7 @@ function handleThinkingChunk(chunk, parentToolCallId) {
|
|
|
2229
2278
|
return update;
|
|
2230
2279
|
}
|
|
2231
2280
|
function handleToolUseChunk(chunk, ctx) {
|
|
2281
|
+
const alreadyCached = chunk.id in ctx.toolUseCache;
|
|
2232
2282
|
ctx.toolUseCache[chunk.id] = chunk;
|
|
2233
2283
|
if (chunk.name === "TodoWrite") {
|
|
2234
2284
|
const input = chunk.input;
|
|
@@ -2240,37 +2290,60 @@ function handleToolUseChunk(chunk, ctx) {
|
|
|
2240
2290
|
}
|
|
2241
2291
|
return null;
|
|
2242
2292
|
}
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2293
|
+
if (!alreadyCached && ctx.registerHooks !== false) {
|
|
2294
|
+
registerHookCallback(chunk.id, {
|
|
2295
|
+
onPostToolUseHook: async (toolUseId, _toolInput, toolResponse) => {
|
|
2296
|
+
const toolUse = ctx.toolUseCache[toolUseId];
|
|
2297
|
+
if (toolUse) {
|
|
2298
|
+
const editUpdate = toolUse.name === "Edit" ? toolUpdateFromEditToolResponse(toolResponse) : null;
|
|
2299
|
+
await ctx.client.sessionUpdate({
|
|
2300
|
+
sessionId: ctx.sessionId,
|
|
2301
|
+
update: {
|
|
2302
|
+
_meta: toolMeta(toolUse.name, toolResponse, ctx.parentToolCallId),
|
|
2303
|
+
toolCallId: toolUseId,
|
|
2304
|
+
sessionUpdate: "tool_call_update",
|
|
2305
|
+
...editUpdate ? editUpdate : {}
|
|
2306
|
+
}
|
|
2307
|
+
});
|
|
2308
|
+
} else {
|
|
2309
|
+
ctx.logger.error(
|
|
2310
|
+
`Got a tool response for tool use that wasn't tracked: ${toolUseId}`
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2259
2313
|
}
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2262
2316
|
let rawInput;
|
|
2263
2317
|
try {
|
|
2264
2318
|
rawInput = JSON.parse(JSON.stringify(chunk.input));
|
|
2265
2319
|
} catch {
|
|
2266
2320
|
}
|
|
2321
|
+
const toolInfo = toolInfoFromToolUse(chunk, {
|
|
2322
|
+
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
2323
|
+
toolUseId: chunk.id
|
|
2324
|
+
});
|
|
2325
|
+
const meta = {
|
|
2326
|
+
...toolMeta(chunk.name, void 0, ctx.parentToolCallId)
|
|
2327
|
+
};
|
|
2328
|
+
if (chunk.name === "Bash" && ctx.supportsTerminalOutput && !alreadyCached) {
|
|
2329
|
+
meta.terminal_info = { terminal_id: chunk.id };
|
|
2330
|
+
}
|
|
2331
|
+
if (alreadyCached) {
|
|
2332
|
+
return {
|
|
2333
|
+
_meta: meta,
|
|
2334
|
+
toolCallId: chunk.id,
|
|
2335
|
+
sessionUpdate: "tool_call_update",
|
|
2336
|
+
rawInput,
|
|
2337
|
+
...toolInfo
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2267
2340
|
return {
|
|
2268
|
-
_meta:
|
|
2341
|
+
_meta: meta,
|
|
2269
2342
|
toolCallId: chunk.id,
|
|
2270
2343
|
sessionUpdate: "tool_call",
|
|
2271
2344
|
rawInput,
|
|
2272
2345
|
status: "pending",
|
|
2273
|
-
...
|
|
2346
|
+
...toolInfo
|
|
2274
2347
|
};
|
|
2275
2348
|
}
|
|
2276
2349
|
function handleToolResultChunk(chunk, ctx) {
|
|
@@ -2279,36 +2352,71 @@ function handleToolResultChunk(chunk, ctx) {
|
|
|
2279
2352
|
ctx.logger.error(
|
|
2280
2353
|
`Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`
|
|
2281
2354
|
);
|
|
2282
|
-
return
|
|
2355
|
+
return [];
|
|
2283
2356
|
}
|
|
2284
2357
|
if (toolUse.name === "TodoWrite") {
|
|
2285
|
-
return
|
|
2358
|
+
return [];
|
|
2286
2359
|
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2360
|
+
const { _meta: resultMeta, ...toolUpdate } = toolUpdateFromToolResult(
|
|
2361
|
+
chunk,
|
|
2362
|
+
toolUse,
|
|
2363
|
+
{
|
|
2364
|
+
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
2365
|
+
toolUseId: chunk.tool_use_id
|
|
2366
|
+
}
|
|
2367
|
+
);
|
|
2368
|
+
const updates = [];
|
|
2369
|
+
if (resultMeta?.terminal_output) {
|
|
2370
|
+
const terminalOutputMeta = {
|
|
2371
|
+
terminal_output: resultMeta.terminal_output
|
|
2372
|
+
};
|
|
2373
|
+
if (ctx.parentToolCallId) {
|
|
2374
|
+
terminalOutputMeta.claudeCode = {
|
|
2375
|
+
parentToolCallId: ctx.parentToolCallId
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
updates.push({
|
|
2379
|
+
_meta: terminalOutputMeta,
|
|
2380
|
+
toolCallId: chunk.tool_use_id,
|
|
2381
|
+
sessionUpdate: "tool_call_update"
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2384
|
+
const meta = {
|
|
2385
|
+
...toolMeta(toolUse.name, void 0, ctx.parentToolCallId),
|
|
2386
|
+
...resultMeta?.terminal_exit ? { terminal_exit: resultMeta.terminal_exit } : {}
|
|
2387
|
+
};
|
|
2388
|
+
updates.push({
|
|
2389
|
+
_meta: meta,
|
|
2289
2390
|
toolCallId: chunk.tool_use_id,
|
|
2290
2391
|
sessionUpdate: "tool_call_update",
|
|
2291
2392
|
status: chunk.is_error ? "failed" : "completed",
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
};
|
|
2393
|
+
rawOutput: chunk.content,
|
|
2394
|
+
...toolUpdate
|
|
2395
|
+
});
|
|
2396
|
+
return updates;
|
|
2297
2397
|
}
|
|
2298
2398
|
function processContentChunk(chunk, role, ctx) {
|
|
2299
2399
|
switch (chunk.type) {
|
|
2300
2400
|
case "text":
|
|
2301
|
-
case "text_delta":
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2401
|
+
case "text_delta": {
|
|
2402
|
+
const update = handleTextChunk(chunk, role, ctx.parentToolCallId);
|
|
2403
|
+
return update ? [update] : [];
|
|
2404
|
+
}
|
|
2405
|
+
case "image": {
|
|
2406
|
+
const update = handleImageChunk(chunk, role);
|
|
2407
|
+
return update ? [update] : [];
|
|
2408
|
+
}
|
|
2305
2409
|
case "thinking":
|
|
2306
|
-
case "thinking_delta":
|
|
2307
|
-
|
|
2410
|
+
case "thinking_delta": {
|
|
2411
|
+
const update = handleThinkingChunk(chunk, ctx.parentToolCallId);
|
|
2412
|
+
return update ? [update] : [];
|
|
2413
|
+
}
|
|
2308
2414
|
case "tool_use":
|
|
2309
2415
|
case "server_tool_use":
|
|
2310
|
-
case "mcp_tool_use":
|
|
2311
|
-
|
|
2416
|
+
case "mcp_tool_use": {
|
|
2417
|
+
const update = handleToolUseChunk(chunk, ctx);
|
|
2418
|
+
return update ? [update] : [];
|
|
2419
|
+
}
|
|
2312
2420
|
case "tool_result":
|
|
2313
2421
|
case "tool_search_tool_result":
|
|
2314
2422
|
case "web_fetch_tool_result":
|
|
@@ -2330,13 +2438,13 @@ function processContentChunk(chunk, role, ctx) {
|
|
|
2330
2438
|
case "container_upload":
|
|
2331
2439
|
case "compaction":
|
|
2332
2440
|
case "compaction_delta":
|
|
2333
|
-
return
|
|
2441
|
+
return [];
|
|
2334
2442
|
default:
|
|
2335
2443
|
unreachable(chunk, ctx.logger);
|
|
2336
|
-
return
|
|
2444
|
+
return [];
|
|
2337
2445
|
}
|
|
2338
2446
|
}
|
|
2339
|
-
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId) {
|
|
2447
|
+
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput) {
|
|
2340
2448
|
if (typeof content === "string") {
|
|
2341
2449
|
const update = {
|
|
2342
2450
|
sessionUpdate: messageUpdateType(role),
|
|
@@ -2357,18 +2465,19 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentC
|
|
|
2357
2465
|
fileContentCache,
|
|
2358
2466
|
client,
|
|
2359
2467
|
logger,
|
|
2360
|
-
parentToolCallId
|
|
2468
|
+
parentToolCallId,
|
|
2469
|
+
registerHooks,
|
|
2470
|
+
supportsTerminalOutput
|
|
2361
2471
|
};
|
|
2362
2472
|
const output = [];
|
|
2363
2473
|
for (const chunk of content) {
|
|
2364
|
-
const update
|
|
2365
|
-
if (update) {
|
|
2474
|
+
for (const update of processContentChunk(chunk, role, ctx)) {
|
|
2366
2475
|
output.push({ sessionId, update });
|
|
2367
2476
|
}
|
|
2368
2477
|
}
|
|
2369
2478
|
return output;
|
|
2370
2479
|
}
|
|
2371
|
-
function streamEventToAcpNotifications(message, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId) {
|
|
2480
|
+
function streamEventToAcpNotifications(message, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput) {
|
|
2372
2481
|
const event = message.event;
|
|
2373
2482
|
switch (event.type) {
|
|
2374
2483
|
case "content_block_start":
|
|
@@ -2380,7 +2489,9 @@ function streamEventToAcpNotifications(message, sessionId, toolUseCache, fileCon
|
|
|
2380
2489
|
fileContentCache,
|
|
2381
2490
|
client,
|
|
2382
2491
|
logger,
|
|
2383
|
-
parentToolCallId
|
|
2492
|
+
parentToolCallId,
|
|
2493
|
+
registerHooks,
|
|
2494
|
+
supportsTerminalOutput
|
|
2384
2495
|
);
|
|
2385
2496
|
case "content_block_delta":
|
|
2386
2497
|
return toAcpNotifications(
|
|
@@ -2391,7 +2502,9 @@ function streamEventToAcpNotifications(message, sessionId, toolUseCache, fileCon
|
|
|
2391
2502
|
fileContentCache,
|
|
2392
2503
|
client,
|
|
2393
2504
|
logger,
|
|
2394
|
-
parentToolCallId
|
|
2505
|
+
parentToolCallId,
|
|
2506
|
+
registerHooks,
|
|
2507
|
+
supportsTerminalOutput
|
|
2395
2508
|
);
|
|
2396
2509
|
case "message_start":
|
|
2397
2510
|
case "message_delta":
|
|
@@ -2450,29 +2563,25 @@ async function handleSystemMessage(message, context) {
|
|
|
2450
2563
|
break;
|
|
2451
2564
|
}
|
|
2452
2565
|
}
|
|
2453
|
-
function handleResultMessage(message
|
|
2454
|
-
const
|
|
2455
|
-
if (session.cancelled) {
|
|
2456
|
-
return {
|
|
2457
|
-
shouldStop: true,
|
|
2458
|
-
stopReason: "cancelled"
|
|
2459
|
-
};
|
|
2460
|
-
}
|
|
2566
|
+
function handleResultMessage(message) {
|
|
2567
|
+
const usage = extractUsageFromResult(message);
|
|
2461
2568
|
switch (message.subtype) {
|
|
2462
2569
|
case "success": {
|
|
2463
2570
|
if (message.result.includes("Please run /login")) {
|
|
2464
2571
|
return {
|
|
2465
2572
|
shouldStop: true,
|
|
2466
|
-
error: import_sdk.RequestError.authRequired()
|
|
2573
|
+
error: import_sdk.RequestError.authRequired(),
|
|
2574
|
+
usage
|
|
2467
2575
|
};
|
|
2468
2576
|
}
|
|
2469
2577
|
if (message.is_error) {
|
|
2470
2578
|
return {
|
|
2471
2579
|
shouldStop: true,
|
|
2472
|
-
error: import_sdk.RequestError.internalError(void 0, message.result)
|
|
2580
|
+
error: import_sdk.RequestError.internalError(void 0, message.result),
|
|
2581
|
+
usage
|
|
2473
2582
|
};
|
|
2474
2583
|
}
|
|
2475
|
-
return { shouldStop: true, stopReason: "end_turn" };
|
|
2584
|
+
return { shouldStop: true, stopReason: "end_turn", usage };
|
|
2476
2585
|
}
|
|
2477
2586
|
case "error_during_execution":
|
|
2478
2587
|
if (message.is_error) {
|
|
@@ -2481,10 +2590,11 @@ function handleResultMessage(message, context) {
|
|
|
2481
2590
|
error: import_sdk.RequestError.internalError(
|
|
2482
2591
|
void 0,
|
|
2483
2592
|
message.errors.join(", ") || message.subtype
|
|
2484
|
-
)
|
|
2593
|
+
),
|
|
2594
|
+
usage
|
|
2485
2595
|
};
|
|
2486
2596
|
}
|
|
2487
|
-
return { shouldStop: true, stopReason: "end_turn" };
|
|
2597
|
+
return { shouldStop: true, stopReason: "end_turn", usage };
|
|
2488
2598
|
case "error_max_budget_usd":
|
|
2489
2599
|
case "error_max_turns":
|
|
2490
2600
|
case "error_max_structured_output_retries":
|
|
@@ -2494,13 +2604,37 @@ function handleResultMessage(message, context) {
|
|
|
2494
2604
|
error: import_sdk.RequestError.internalError(
|
|
2495
2605
|
void 0,
|
|
2496
2606
|
message.errors.join(", ") || message.subtype
|
|
2497
|
-
)
|
|
2607
|
+
),
|
|
2608
|
+
usage
|
|
2498
2609
|
};
|
|
2499
2610
|
}
|
|
2500
|
-
return { shouldStop: true, stopReason: "max_turn_requests" };
|
|
2611
|
+
return { shouldStop: true, stopReason: "max_turn_requests", usage };
|
|
2501
2612
|
default:
|
|
2502
|
-
return { shouldStop: false };
|
|
2613
|
+
return { shouldStop: false, usage };
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
function extractUsageFromResult(message) {
|
|
2617
|
+
const msg = message;
|
|
2618
|
+
const msgUsage = msg.usage;
|
|
2619
|
+
if (!msgUsage) return void 0;
|
|
2620
|
+
const modelUsage = msg.modelUsage;
|
|
2621
|
+
let contextWindowSize;
|
|
2622
|
+
if (modelUsage) {
|
|
2623
|
+
const contextWindows = Object.values(modelUsage).map(
|
|
2624
|
+
(m) => m.contextWindow
|
|
2625
|
+
);
|
|
2626
|
+
if (contextWindows.length > 0) {
|
|
2627
|
+
contextWindowSize = Math.min(...contextWindows);
|
|
2628
|
+
}
|
|
2503
2629
|
}
|
|
2630
|
+
return {
|
|
2631
|
+
inputTokens: msgUsage.input_tokens ?? 0,
|
|
2632
|
+
outputTokens: msgUsage.output_tokens ?? 0,
|
|
2633
|
+
cachedReadTokens: msgUsage.cache_read_input_tokens ?? 0,
|
|
2634
|
+
cachedWriteTokens: msgUsage.cache_creation_input_tokens ?? 0,
|
|
2635
|
+
costUsd: typeof msg.total_cost_usd === "number" ? msg.total_cost_usd : void 0,
|
|
2636
|
+
contextWindowSize
|
|
2637
|
+
};
|
|
2504
2638
|
}
|
|
2505
2639
|
async function handleStreamEvent(message, context) {
|
|
2506
2640
|
const { sessionId, client, toolUseCache, fileContentCache, logger } = context;
|
|
@@ -2512,7 +2646,9 @@ async function handleStreamEvent(message, context) {
|
|
|
2512
2646
|
fileContentCache,
|
|
2513
2647
|
client,
|
|
2514
2648
|
logger,
|
|
2515
|
-
parentToolCallId
|
|
2649
|
+
parentToolCallId,
|
|
2650
|
+
context.registerHooks,
|
|
2651
|
+
context.supportsTerminalOutput
|
|
2516
2652
|
)) {
|
|
2517
2653
|
await client.sessionUpdate(notification);
|
|
2518
2654
|
context.session.notificationHistory.push(notification);
|
|
@@ -2524,14 +2660,15 @@ function hasLocalCommandStdout(content) {
|
|
|
2524
2660
|
function hasLocalCommandStderr(content) {
|
|
2525
2661
|
return typeof content === "string" && content.includes("<local-command-stderr>");
|
|
2526
2662
|
}
|
|
2527
|
-
function isSimpleUserMessage(message) {
|
|
2528
|
-
return message.type === "user" && (typeof message.message.content === "string" || Array.isArray(message.message.content) && message.message.content.length === 1 && message.message.content[0].type === "text");
|
|
2529
|
-
}
|
|
2530
2663
|
function isLoginRequiredMessage(message) {
|
|
2531
2664
|
return message.type === "assistant" && message.message.model === "<synthetic>" && Array.isArray(message.message.content) && message.message.content.length === 1 && message.message.content[0].type === "text" && message.message.content[0].text?.includes("Please run /login") === true;
|
|
2532
2665
|
}
|
|
2666
|
+
function isPlainTextUserMessage(message) {
|
|
2667
|
+
const content = message.message.content;
|
|
2668
|
+
return message.type === "user" && (typeof content === "string" || Array.isArray(content) && content.length === 1 && content[0].type === "text");
|
|
2669
|
+
}
|
|
2533
2670
|
function shouldSkipUserAssistantMessage(message) {
|
|
2534
|
-
return hasLocalCommandStdout(message.message.content) || hasLocalCommandStderr(message.message.content) ||
|
|
2671
|
+
return hasLocalCommandStdout(message.message.content) || hasLocalCommandStderr(message.message.content) || isLoginRequiredMessage(message);
|
|
2535
2672
|
}
|
|
2536
2673
|
function logSpecialMessages(message, logger) {
|
|
2537
2674
|
const content = message.message.content;
|
|
@@ -2552,18 +2689,33 @@ function filterMessageContent(content) {
|
|
|
2552
2689
|
}
|
|
2553
2690
|
async function handleUserAssistantMessage(message, context) {
|
|
2554
2691
|
const { session, sessionId, client, toolUseCache, fileContentCache, logger } = context;
|
|
2555
|
-
if (session.cancelled) {
|
|
2556
|
-
return {};
|
|
2557
|
-
}
|
|
2558
2692
|
if (shouldSkipUserAssistantMessage(message)) {
|
|
2693
|
+
const content2 = message.message.content;
|
|
2694
|
+
if (typeof content2 === "string" && hasLocalCommandStdout(content2) && content2.includes("Context Usage")) {
|
|
2695
|
+
const stripped = content2.replace("<local-command-stdout>", "").replace("</local-command-stdout>", "");
|
|
2696
|
+
for (const notification of toAcpNotifications(
|
|
2697
|
+
stripped,
|
|
2698
|
+
"assistant",
|
|
2699
|
+
sessionId,
|
|
2700
|
+
toolUseCache,
|
|
2701
|
+
fileContentCache,
|
|
2702
|
+
client,
|
|
2703
|
+
logger
|
|
2704
|
+
)) {
|
|
2705
|
+
await client.sessionUpdate(notification);
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2559
2708
|
logSpecialMessages(message, logger);
|
|
2560
2709
|
if (isLoginRequiredMessage(message)) {
|
|
2561
2710
|
return { shouldStop: true, error: import_sdk.RequestError.authRequired() };
|
|
2562
2711
|
}
|
|
2563
2712
|
return {};
|
|
2564
2713
|
}
|
|
2714
|
+
if (isPlainTextUserMessage(message)) {
|
|
2715
|
+
return {};
|
|
2716
|
+
}
|
|
2565
2717
|
const content = message.message.content;
|
|
2566
|
-
const contentToProcess = filterMessageContent(content);
|
|
2718
|
+
const contentToProcess = message.type === "assistant" ? filterMessageContent(content) : content;
|
|
2567
2719
|
const parentToolCallId = "parent_tool_use_id" in message ? message.parent_tool_use_id ?? void 0 : void 0;
|
|
2568
2720
|
for (const notification of toAcpNotifications(
|
|
2569
2721
|
contentToProcess,
|
|
@@ -2573,7 +2725,9 @@ async function handleUserAssistantMessage(message, context) {
|
|
|
2573
2725
|
fileContentCache,
|
|
2574
2726
|
client,
|
|
2575
2727
|
logger,
|
|
2576
|
-
parentToolCallId
|
|
2728
|
+
parentToolCallId,
|
|
2729
|
+
context.registerHooks,
|
|
2730
|
+
context.supportsTerminalOutput
|
|
2577
2731
|
)) {
|
|
2578
2732
|
await client.sessionUpdate(notification);
|
|
2579
2733
|
session.notificationHistory.push(notification);
|
|
@@ -2659,36 +2813,45 @@ function normalizeAskUserQuestionInput(input) {
|
|
|
2659
2813
|
}
|
|
2660
2814
|
|
|
2661
2815
|
// src/execution-mode.ts
|
|
2662
|
-
var
|
|
2816
|
+
var ALLOW_BYPASS = !IS_ROOT;
|
|
2817
|
+
var availableModes = [
|
|
2663
2818
|
{
|
|
2664
2819
|
id: "default",
|
|
2665
|
-
name: "
|
|
2666
|
-
description: "
|
|
2820
|
+
name: "Default",
|
|
2821
|
+
description: "Standard behavior, prompts for dangerous operations"
|
|
2667
2822
|
},
|
|
2668
2823
|
{
|
|
2669
2824
|
id: "acceptEdits",
|
|
2670
2825
|
name: "Accept Edits",
|
|
2671
|
-
description: "
|
|
2826
|
+
description: "Auto-accept file edit operations"
|
|
2672
2827
|
},
|
|
2673
2828
|
{
|
|
2674
2829
|
id: "plan",
|
|
2675
2830
|
name: "Plan Mode",
|
|
2676
|
-
description: "
|
|
2677
|
-
},
|
|
2678
|
-
{
|
|
2679
|
-
id: "bypassPermissions",
|
|
2680
|
-
name: "Bypass Permissions",
|
|
2681
|
-
description: "Skips all permission prompts"
|
|
2831
|
+
description: "Planning mode, no actual tool execution"
|
|
2682
2832
|
}
|
|
2833
|
+
// {
|
|
2834
|
+
// id: "dontAsk",
|
|
2835
|
+
// name: "Don't Ask",
|
|
2836
|
+
// description: "Don't prompt for permissions, deny if not pre-approved",
|
|
2837
|
+
// },
|
|
2683
2838
|
];
|
|
2839
|
+
if (ALLOW_BYPASS) {
|
|
2840
|
+
availableModes.push({
|
|
2841
|
+
id: "bypassPermissions",
|
|
2842
|
+
name: "Bypass Permissions",
|
|
2843
|
+
description: "Bypass all permission checks"
|
|
2844
|
+
});
|
|
2845
|
+
}
|
|
2684
2846
|
var TWIG_EXECUTION_MODES = [
|
|
2685
2847
|
"default",
|
|
2686
2848
|
"acceptEdits",
|
|
2687
2849
|
"plan",
|
|
2850
|
+
// "dontAsk",
|
|
2688
2851
|
"bypassPermissions"
|
|
2689
2852
|
];
|
|
2690
2853
|
function getAvailableModes() {
|
|
2691
|
-
return IS_ROOT ?
|
|
2854
|
+
return IS_ROOT ? availableModes.filter((m) => m.id !== "bypassPermissions") : availableModes;
|
|
2692
2855
|
}
|
|
2693
2856
|
|
|
2694
2857
|
// src/adapters/claude/tools.ts
|
|
@@ -2716,6 +2879,7 @@ var AUTO_ALLOWED_TOOLS = {
|
|
|
2716
2879
|
default: new Set(BASE_ALLOWED_TOOLS),
|
|
2717
2880
|
acceptEdits: /* @__PURE__ */ new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),
|
|
2718
2881
|
plan: new Set(BASE_ALLOWED_TOOLS)
|
|
2882
|
+
// dontAsk: new Set(BASE_ALLOWED_TOOLS),
|
|
2719
2883
|
};
|
|
2720
2884
|
function isToolAllowedForMode(toolName, mode) {
|
|
2721
2885
|
if (mode === "bypassPermissions") {
|
|
@@ -2863,12 +3027,11 @@ async function validatePlanContent(planText, context) {
|
|
|
2863
3027
|
return { valid: true };
|
|
2864
3028
|
}
|
|
2865
3029
|
async function requestPlanApproval(context, updatedInput) {
|
|
2866
|
-
const { client, sessionId, toolUseID
|
|
2867
|
-
const toolInfo = toolInfoFromToolUse(
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
);
|
|
3030
|
+
const { client, sessionId, toolUseID } = context;
|
|
3031
|
+
const toolInfo = toolInfoFromToolUse({
|
|
3032
|
+
name: context.toolName,
|
|
3033
|
+
input: updatedInput
|
|
3034
|
+
});
|
|
2872
3035
|
return await client.requestPermission({
|
|
2873
3036
|
options: buildExitPlanModePermissionOptions(),
|
|
2874
3037
|
sessionId,
|
|
@@ -2887,7 +3050,14 @@ async function applyPlanApproval(response, context, updatedInput) {
|
|
|
2887
3050
|
if (response.outcome?.outcome === "selected" && (response.outcome.optionId === "default" || response.outcome.optionId === "acceptEdits")) {
|
|
2888
3051
|
session.permissionMode = response.outcome.optionId;
|
|
2889
3052
|
await session.query.setPermissionMode(response.outcome.optionId);
|
|
2890
|
-
await context.
|
|
3053
|
+
await context.client.sessionUpdate({
|
|
3054
|
+
sessionId: context.sessionId,
|
|
3055
|
+
update: {
|
|
3056
|
+
sessionUpdate: "current_mode_update",
|
|
3057
|
+
currentModeId: response.outcome.optionId
|
|
3058
|
+
}
|
|
3059
|
+
});
|
|
3060
|
+
await context.updateConfigOption("mode", response.outcome.optionId);
|
|
2891
3061
|
return {
|
|
2892
3062
|
behavior: "allow",
|
|
2893
3063
|
updatedInput,
|
|
@@ -2908,7 +3078,7 @@ async function handleEnterPlanModeTool(context) {
|
|
|
2908
3078
|
const { session, toolInput } = context;
|
|
2909
3079
|
session.permissionMode = "plan";
|
|
2910
3080
|
await session.query.setPermissionMode("plan");
|
|
2911
|
-
await context.
|
|
3081
|
+
await context.updateConfigOption("mode", "plan");
|
|
2912
3082
|
return {
|
|
2913
3083
|
behavior: "allow",
|
|
2914
3084
|
updatedInput: toolInput
|
|
@@ -2926,6 +3096,9 @@ async function handleExitPlanModeTool(context) {
|
|
|
2926
3096
|
return validationResult.error;
|
|
2927
3097
|
}
|
|
2928
3098
|
const response = await requestPlanApproval(context, updatedInput);
|
|
3099
|
+
if (context.signal?.aborted || response.outcome?.outcome === "cancelled") {
|
|
3100
|
+
throw new Error("Tool use aborted");
|
|
3101
|
+
}
|
|
2929
3102
|
return await applyPlanApproval(response, context, updatedInput);
|
|
2930
3103
|
}
|
|
2931
3104
|
function buildQuestionOptions(question) {
|
|
@@ -2949,14 +3122,13 @@ async function handleAskUserQuestionTool(context) {
|
|
|
2949
3122
|
interrupt: true
|
|
2950
3123
|
};
|
|
2951
3124
|
}
|
|
2952
|
-
const { client, sessionId, toolUseID, toolInput
|
|
3125
|
+
const { client, sessionId, toolUseID, toolInput } = context;
|
|
2953
3126
|
const firstQuestion = questions[0];
|
|
2954
3127
|
const options = buildQuestionOptions(firstQuestion);
|
|
2955
|
-
const toolInfo = toolInfoFromToolUse(
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
);
|
|
3128
|
+
const toolInfo = toolInfoFromToolUse({
|
|
3129
|
+
name: context.toolName,
|
|
3130
|
+
input: toolInput
|
|
3131
|
+
});
|
|
2960
3132
|
const response = await client.requestPermission({
|
|
2961
3133
|
options,
|
|
2962
3134
|
sessionId,
|
|
@@ -2971,6 +3143,9 @@ async function handleAskUserQuestionTool(context) {
|
|
|
2971
3143
|
}
|
|
2972
3144
|
}
|
|
2973
3145
|
});
|
|
3146
|
+
if (context.signal?.aborted || response.outcome?.outcome === "cancelled") {
|
|
3147
|
+
throw new Error("Tool use aborted");
|
|
3148
|
+
}
|
|
2974
3149
|
if (response.outcome?.outcome !== "selected") {
|
|
2975
3150
|
const customMessage = response._meta?.message;
|
|
2976
3151
|
return {
|
|
@@ -3003,14 +3178,9 @@ async function handleDefaultPermissionFlow(context) {
|
|
|
3003
3178
|
toolUseID,
|
|
3004
3179
|
client,
|
|
3005
3180
|
sessionId,
|
|
3006
|
-
fileContentCache,
|
|
3007
3181
|
suggestions
|
|
3008
3182
|
} = context;
|
|
3009
|
-
const toolInfo = toolInfoFromToolUse(
|
|
3010
|
-
{ name: toolName, input: toolInput },
|
|
3011
|
-
fileContentCache,
|
|
3012
|
-
context.logger
|
|
3013
|
-
);
|
|
3183
|
+
const toolInfo = toolInfoFromToolUse({ name: toolName, input: toolInput });
|
|
3014
3184
|
const options = buildPermissionOptions(
|
|
3015
3185
|
toolName,
|
|
3016
3186
|
toolInput,
|
|
@@ -3029,6 +3199,9 @@ async function handleDefaultPermissionFlow(context) {
|
|
|
3029
3199
|
rawInput: toolInput
|
|
3030
3200
|
}
|
|
3031
3201
|
});
|
|
3202
|
+
if (context.signal?.aborted || response.outcome?.outcome === "cancelled") {
|
|
3203
|
+
throw new Error("Tool use aborted");
|
|
3204
|
+
}
|
|
3032
3205
|
if (response.outcome?.outcome === "selected" && (response.outcome.optionId === "allow" || response.outcome.optionId === "allow_always")) {
|
|
3033
3206
|
if (response.outcome.optionId === "allow_always") {
|
|
3034
3207
|
return {
|
|
@@ -3105,16 +3278,18 @@ async function canUseTool(context) {
|
|
|
3105
3278
|
var UNSUPPORTED_COMMANDS = [
|
|
3106
3279
|
"context",
|
|
3107
3280
|
"cost",
|
|
3281
|
+
"keybindings-help",
|
|
3108
3282
|
"login",
|
|
3109
3283
|
"logout",
|
|
3110
3284
|
"output-style:new",
|
|
3111
3285
|
"release-notes",
|
|
3112
3286
|
"todos"
|
|
3113
3287
|
];
|
|
3114
|
-
|
|
3115
|
-
const commands = await q.supportedCommands();
|
|
3288
|
+
function getAvailableSlashCommands(commands) {
|
|
3116
3289
|
return commands.map((command) => {
|
|
3117
|
-
const input = command.argumentHint ? {
|
|
3290
|
+
const input = command.argumentHint != null ? {
|
|
3291
|
+
hint: Array.isArray(command.argumentHint) ? command.argumentHint.join(" ") : command.argumentHint
|
|
3292
|
+
} : null;
|
|
3118
3293
|
let name = command.name;
|
|
3119
3294
|
if (command.name.endsWith(" (MCP)")) {
|
|
3120
3295
|
name = `mcp:${name.replace(" (MCP)", "")}`;
|
|
@@ -3212,13 +3387,19 @@ function buildEnvironment() {
|
|
|
3212
3387
|
ENABLE_TOOL_SEARCH: "auto:0"
|
|
3213
3388
|
};
|
|
3214
3389
|
}
|
|
3215
|
-
function buildHooks(userHooks, onModeChange) {
|
|
3390
|
+
function buildHooks(userHooks, onModeChange, settingsManager, logger) {
|
|
3216
3391
|
return {
|
|
3217
3392
|
...userHooks,
|
|
3218
3393
|
PostToolUse: [
|
|
3219
3394
|
...userHooks?.PostToolUse || [],
|
|
3220
3395
|
{
|
|
3221
|
-
hooks: [createPostToolUseHook({ onModeChange })]
|
|
3396
|
+
hooks: [createPostToolUseHook({ onModeChange, logger })]
|
|
3397
|
+
}
|
|
3398
|
+
],
|
|
3399
|
+
PreToolUse: [
|
|
3400
|
+
...userHooks?.PreToolUse || [],
|
|
3401
|
+
{
|
|
3402
|
+
hooks: [createPreToolUseHook(settingsManager, logger)]
|
|
3222
3403
|
}
|
|
3223
3404
|
]
|
|
3224
3405
|
};
|
|
@@ -3312,12 +3493,22 @@ function buildSessionOptions(params) {
|
|
|
3312
3493
|
permissionMode: params.permissionMode,
|
|
3313
3494
|
canUseTool: params.canUseTool,
|
|
3314
3495
|
executable: "node",
|
|
3496
|
+
tools: { type: "preset", preset: "claude_code" },
|
|
3497
|
+
extraArgs: {
|
|
3498
|
+
...params.userProvidedOptions?.extraArgs,
|
|
3499
|
+
"replay-user-messages": ""
|
|
3500
|
+
},
|
|
3315
3501
|
mcpServers: buildMcpServers(
|
|
3316
3502
|
params.userProvidedOptions?.mcpServers,
|
|
3317
3503
|
params.mcpServers
|
|
3318
3504
|
),
|
|
3319
3505
|
env: buildEnvironment(),
|
|
3320
|
-
hooks: buildHooks(
|
|
3506
|
+
hooks: buildHooks(
|
|
3507
|
+
params.userProvidedOptions?.hooks,
|
|
3508
|
+
params.onModeChange,
|
|
3509
|
+
params.settingsManager,
|
|
3510
|
+
params.logger
|
|
3511
|
+
),
|
|
3321
3512
|
abortController: getAbortController(
|
|
3322
3513
|
params.userProvidedOptions?.abortController
|
|
3323
3514
|
),
|
|
@@ -3334,13 +3525,36 @@ function buildSessionOptions(params) {
|
|
|
3334
3525
|
}
|
|
3335
3526
|
if (params.isResume) {
|
|
3336
3527
|
options.resume = params.sessionId;
|
|
3337
|
-
options.forkSession = false;
|
|
3528
|
+
options.forkSession = params.forkSession ?? false;
|
|
3338
3529
|
} else {
|
|
3339
3530
|
options.sessionId = params.sessionId;
|
|
3531
|
+
options.model = DEFAULT_MODEL;
|
|
3340
3532
|
}
|
|
3341
3533
|
if (params.additionalDirectories) {
|
|
3342
3534
|
options.additionalDirectories = params.additionalDirectories;
|
|
3343
3535
|
}
|
|
3536
|
+
if (params.disableBuiltInTools) {
|
|
3537
|
+
const builtInTools = [
|
|
3538
|
+
"Read",
|
|
3539
|
+
"Write",
|
|
3540
|
+
"Edit",
|
|
3541
|
+
"Bash",
|
|
3542
|
+
"Glob",
|
|
3543
|
+
"Grep",
|
|
3544
|
+
"Task",
|
|
3545
|
+
"TodoWrite",
|
|
3546
|
+
"ExitPlanMode",
|
|
3547
|
+
"WebSearch",
|
|
3548
|
+
"WebFetch",
|
|
3549
|
+
"SlashCommand",
|
|
3550
|
+
"Skill",
|
|
3551
|
+
"NotebookEdit"
|
|
3552
|
+
];
|
|
3553
|
+
options.disallowedTools = [
|
|
3554
|
+
...options.disallowedTools ?? [],
|
|
3555
|
+
...builtInTools
|
|
3556
|
+
];
|
|
3557
|
+
}
|
|
3344
3558
|
clearStatsigCache();
|
|
3345
3559
|
return options;
|
|
3346
3560
|
}
|
|
@@ -3353,15 +3567,268 @@ function clearStatsigCache() {
|
|
|
3353
3567
|
});
|
|
3354
3568
|
}
|
|
3355
3569
|
|
|
3570
|
+
// src/adapters/claude/session/settings.ts
|
|
3571
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
3572
|
+
var os3 = __toESM(require("os"), 1);
|
|
3573
|
+
var path3 = __toESM(require("path"), 1);
|
|
3574
|
+
var import_minimatch = require("minimatch");
|
|
3575
|
+
var ACP_TOOL_NAME_PREFIX = "mcp__acp__";
|
|
3576
|
+
var acpToolNames = {
|
|
3577
|
+
read: `${ACP_TOOL_NAME_PREFIX}Read`,
|
|
3578
|
+
edit: `${ACP_TOOL_NAME_PREFIX}Edit`,
|
|
3579
|
+
write: `${ACP_TOOL_NAME_PREFIX}Write`,
|
|
3580
|
+
bash: `${ACP_TOOL_NAME_PREFIX}Bash`
|
|
3581
|
+
};
|
|
3582
|
+
var SHELL_OPERATORS = ["&&", "||", ";", "|", "$(", "`", "\n"];
|
|
3583
|
+
function containsShellOperator(str) {
|
|
3584
|
+
return SHELL_OPERATORS.some((op) => str.includes(op));
|
|
3585
|
+
}
|
|
3586
|
+
var FILE_EDITING_TOOLS = [acpToolNames.edit, acpToolNames.write];
|
|
3587
|
+
var FILE_READING_TOOLS = [acpToolNames.read];
|
|
3588
|
+
var TOOL_ARG_ACCESSORS = {
|
|
3589
|
+
[acpToolNames.read]: (input) => input?.file_path,
|
|
3590
|
+
[acpToolNames.edit]: (input) => input?.file_path,
|
|
3591
|
+
[acpToolNames.write]: (input) => input?.file_path,
|
|
3592
|
+
[acpToolNames.bash]: (input) => input?.command
|
|
3593
|
+
};
|
|
3594
|
+
function parseRule(rule) {
|
|
3595
|
+
const match = rule.match(/^(\w+)(?:\((.+)\))?$/);
|
|
3596
|
+
if (!match) {
|
|
3597
|
+
return { toolName: rule };
|
|
3598
|
+
}
|
|
3599
|
+
const toolName = match[1] ?? rule;
|
|
3600
|
+
const argument = match[2];
|
|
3601
|
+
if (argument?.endsWith(":*")) {
|
|
3602
|
+
return {
|
|
3603
|
+
toolName,
|
|
3604
|
+
argument: argument.slice(0, -2),
|
|
3605
|
+
isWildcard: true
|
|
3606
|
+
};
|
|
3607
|
+
}
|
|
3608
|
+
return { toolName, argument };
|
|
3609
|
+
}
|
|
3610
|
+
function normalizePath(filePath, cwd) {
|
|
3611
|
+
let resolved = filePath;
|
|
3612
|
+
if (resolved.startsWith("~/")) {
|
|
3613
|
+
resolved = path3.join(os3.homedir(), resolved.slice(2));
|
|
3614
|
+
} else if (resolved.startsWith("./")) {
|
|
3615
|
+
resolved = path3.join(cwd, resolved.slice(2));
|
|
3616
|
+
} else if (!path3.isAbsolute(resolved)) {
|
|
3617
|
+
resolved = path3.join(cwd, resolved);
|
|
3618
|
+
}
|
|
3619
|
+
return path3.normalize(resolved).replace(/\\/g, "/");
|
|
3620
|
+
}
|
|
3621
|
+
function matchesGlob(pattern, filePath, cwd) {
|
|
3622
|
+
const normalizedPattern = normalizePath(pattern, cwd);
|
|
3623
|
+
const normalizedPath = normalizePath(filePath, cwd);
|
|
3624
|
+
return (0, import_minimatch.minimatch)(normalizedPath, normalizedPattern, {
|
|
3625
|
+
dot: true,
|
|
3626
|
+
matchBase: false,
|
|
3627
|
+
nocase: process.platform === "win32"
|
|
3628
|
+
});
|
|
3629
|
+
}
|
|
3630
|
+
function matchesRule(rule, toolName, toolInput, cwd) {
|
|
3631
|
+
const ruleAppliesToTool = rule.toolName === "Bash" && toolName === acpToolNames.bash || rule.toolName === "Edit" && FILE_EDITING_TOOLS.includes(toolName) || rule.toolName === "Read" && FILE_READING_TOOLS.includes(toolName);
|
|
3632
|
+
if (!ruleAppliesToTool) {
|
|
3633
|
+
return false;
|
|
3634
|
+
}
|
|
3635
|
+
if (!rule.argument) {
|
|
3636
|
+
return true;
|
|
3637
|
+
}
|
|
3638
|
+
const argAccessor = TOOL_ARG_ACCESSORS[toolName];
|
|
3639
|
+
if (!argAccessor) {
|
|
3640
|
+
return true;
|
|
3641
|
+
}
|
|
3642
|
+
const actualArg = argAccessor(toolInput);
|
|
3643
|
+
if (!actualArg) {
|
|
3644
|
+
return false;
|
|
3645
|
+
}
|
|
3646
|
+
if (toolName === acpToolNames.bash) {
|
|
3647
|
+
if (rule.isWildcard) {
|
|
3648
|
+
if (!actualArg.startsWith(rule.argument)) {
|
|
3649
|
+
return false;
|
|
3650
|
+
}
|
|
3651
|
+
const remainder = actualArg.slice(rule.argument.length);
|
|
3652
|
+
if (containsShellOperator(remainder)) {
|
|
3653
|
+
return false;
|
|
3654
|
+
}
|
|
3655
|
+
return true;
|
|
3656
|
+
}
|
|
3657
|
+
return actualArg === rule.argument;
|
|
3658
|
+
}
|
|
3659
|
+
return matchesGlob(rule.argument, actualArg, cwd);
|
|
3660
|
+
}
|
|
3661
|
+
async function loadSettingsFile(filePath) {
|
|
3662
|
+
if (!filePath) {
|
|
3663
|
+
return {};
|
|
3664
|
+
}
|
|
3665
|
+
try {
|
|
3666
|
+
const content = await fs2.promises.readFile(filePath, "utf-8");
|
|
3667
|
+
return JSON.parse(content);
|
|
3668
|
+
} catch {
|
|
3669
|
+
return {};
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
function getManagedSettingsPath() {
|
|
3673
|
+
switch (process.platform) {
|
|
3674
|
+
case "darwin":
|
|
3675
|
+
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
3676
|
+
case "linux":
|
|
3677
|
+
return "/etc/claude-code/managed-settings.json";
|
|
3678
|
+
case "win32":
|
|
3679
|
+
return "C:\\Program Files\\ClaudeCode\\managed-settings.json";
|
|
3680
|
+
default:
|
|
3681
|
+
return "/etc/claude-code/managed-settings.json";
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
var SettingsManager = class {
|
|
3685
|
+
cwd;
|
|
3686
|
+
userSettings = {};
|
|
3687
|
+
projectSettings = {};
|
|
3688
|
+
localSettings = {};
|
|
3689
|
+
enterpriseSettings = {};
|
|
3690
|
+
mergedSettings = {};
|
|
3691
|
+
initialized = false;
|
|
3692
|
+
constructor(cwd) {
|
|
3693
|
+
this.cwd = cwd;
|
|
3694
|
+
}
|
|
3695
|
+
async initialize() {
|
|
3696
|
+
if (this.initialized) {
|
|
3697
|
+
return;
|
|
3698
|
+
}
|
|
3699
|
+
await this.loadAllSettings();
|
|
3700
|
+
this.initialized = true;
|
|
3701
|
+
}
|
|
3702
|
+
getUserSettingsPath() {
|
|
3703
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR || path3.join(os3.homedir(), ".claude");
|
|
3704
|
+
return path3.join(configDir, "settings.json");
|
|
3705
|
+
}
|
|
3706
|
+
getProjectSettingsPath() {
|
|
3707
|
+
return path3.join(this.cwd, ".claude", "settings.json");
|
|
3708
|
+
}
|
|
3709
|
+
getLocalSettingsPath() {
|
|
3710
|
+
return path3.join(this.cwd, ".claude", "settings.local.json");
|
|
3711
|
+
}
|
|
3712
|
+
async loadAllSettings() {
|
|
3713
|
+
const [userSettings, projectSettings, localSettings, enterpriseSettings] = await Promise.all([
|
|
3714
|
+
loadSettingsFile(this.getUserSettingsPath()),
|
|
3715
|
+
loadSettingsFile(this.getProjectSettingsPath()),
|
|
3716
|
+
loadSettingsFile(this.getLocalSettingsPath()),
|
|
3717
|
+
loadSettingsFile(getManagedSettingsPath())
|
|
3718
|
+
]);
|
|
3719
|
+
this.userSettings = userSettings;
|
|
3720
|
+
this.projectSettings = projectSettings;
|
|
3721
|
+
this.localSettings = localSettings;
|
|
3722
|
+
this.enterpriseSettings = enterpriseSettings;
|
|
3723
|
+
this.mergeAllSettings();
|
|
3724
|
+
}
|
|
3725
|
+
mergeAllSettings() {
|
|
3726
|
+
const allSettings = [
|
|
3727
|
+
this.userSettings,
|
|
3728
|
+
this.projectSettings,
|
|
3729
|
+
this.localSettings,
|
|
3730
|
+
this.enterpriseSettings
|
|
3731
|
+
];
|
|
3732
|
+
const permissions = {
|
|
3733
|
+
allow: [],
|
|
3734
|
+
deny: [],
|
|
3735
|
+
ask: []
|
|
3736
|
+
};
|
|
3737
|
+
const merged = { permissions };
|
|
3738
|
+
for (const settings of allSettings) {
|
|
3739
|
+
if (settings.permissions) {
|
|
3740
|
+
if (settings.permissions.allow) {
|
|
3741
|
+
permissions.allow?.push(...settings.permissions.allow);
|
|
3742
|
+
}
|
|
3743
|
+
if (settings.permissions.deny) {
|
|
3744
|
+
permissions.deny?.push(...settings.permissions.deny);
|
|
3745
|
+
}
|
|
3746
|
+
if (settings.permissions.ask) {
|
|
3747
|
+
permissions.ask?.push(...settings.permissions.ask);
|
|
3748
|
+
}
|
|
3749
|
+
if (settings.permissions.additionalDirectories) {
|
|
3750
|
+
permissions.additionalDirectories = [
|
|
3751
|
+
...permissions.additionalDirectories || [],
|
|
3752
|
+
...settings.permissions.additionalDirectories
|
|
3753
|
+
];
|
|
3754
|
+
}
|
|
3755
|
+
if (settings.permissions.defaultMode) {
|
|
3756
|
+
permissions.defaultMode = settings.permissions.defaultMode;
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
if (settings.env) {
|
|
3760
|
+
merged.env = { ...merged.env, ...settings.env };
|
|
3761
|
+
}
|
|
3762
|
+
if (settings.model) {
|
|
3763
|
+
merged.model = settings.model;
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
this.mergedSettings = merged;
|
|
3767
|
+
}
|
|
3768
|
+
checkPermission(toolName, toolInput) {
|
|
3769
|
+
if (!toolName.startsWith(ACP_TOOL_NAME_PREFIX)) {
|
|
3770
|
+
return { decision: "ask" };
|
|
3771
|
+
}
|
|
3772
|
+
const permissions = this.mergedSettings.permissions;
|
|
3773
|
+
if (!permissions) {
|
|
3774
|
+
return { decision: "ask" };
|
|
3775
|
+
}
|
|
3776
|
+
for (const rule of permissions.deny || []) {
|
|
3777
|
+
const parsed = parseRule(rule);
|
|
3778
|
+
if (matchesRule(parsed, toolName, toolInput, this.cwd)) {
|
|
3779
|
+
return { decision: "deny", rule, source: "deny" };
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
for (const rule of permissions.allow || []) {
|
|
3783
|
+
const parsed = parseRule(rule);
|
|
3784
|
+
if (matchesRule(parsed, toolName, toolInput, this.cwd)) {
|
|
3785
|
+
return { decision: "allow", rule, source: "allow" };
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
for (const rule of permissions.ask || []) {
|
|
3789
|
+
const parsed = parseRule(rule);
|
|
3790
|
+
if (matchesRule(parsed, toolName, toolInput, this.cwd)) {
|
|
3791
|
+
return { decision: "ask", rule, source: "ask" };
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
return { decision: "ask" };
|
|
3795
|
+
}
|
|
3796
|
+
getSettings() {
|
|
3797
|
+
return this.mergedSettings;
|
|
3798
|
+
}
|
|
3799
|
+
getCwd() {
|
|
3800
|
+
return this.cwd;
|
|
3801
|
+
}
|
|
3802
|
+
async setCwd(cwd) {
|
|
3803
|
+
if (this.cwd === cwd) {
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
this.dispose();
|
|
3807
|
+
this.cwd = cwd;
|
|
3808
|
+
this.initialized = false;
|
|
3809
|
+
await this.initialize();
|
|
3810
|
+
}
|
|
3811
|
+
dispose() {
|
|
3812
|
+
this.initialized = false;
|
|
3813
|
+
}
|
|
3814
|
+
};
|
|
3815
|
+
|
|
3356
3816
|
// src/adapters/claude/claude-agent.ts
|
|
3357
3817
|
var SESSION_VALIDATION_TIMEOUT_MS = 1e4;
|
|
3818
|
+
var MAX_TITLE_LENGTH = 256;
|
|
3819
|
+
function sanitizeTitle(text2) {
|
|
3820
|
+
const sanitized = text2.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
3821
|
+
if (sanitized.length <= MAX_TITLE_LENGTH) {
|
|
3822
|
+
return sanitized;
|
|
3823
|
+
}
|
|
3824
|
+
return `${sanitized.slice(0, MAX_TITLE_LENGTH - 1)}\u2026`;
|
|
3825
|
+
}
|
|
3358
3826
|
var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
3359
3827
|
adapterName = "claude";
|
|
3360
3828
|
toolUseCache;
|
|
3361
3829
|
backgroundTerminals = {};
|
|
3362
3830
|
clientCapabilities;
|
|
3363
3831
|
options;
|
|
3364
|
-
lastSentConfigOptions;
|
|
3365
3832
|
constructor(client, options) {
|
|
3366
3833
|
super(client);
|
|
3367
3834
|
this.options = options;
|
|
@@ -3382,125 +3849,416 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3382
3849
|
sse: true
|
|
3383
3850
|
},
|
|
3384
3851
|
loadSession: true,
|
|
3852
|
+
sessionCapabilities: {
|
|
3853
|
+
list: {},
|
|
3854
|
+
fork: {},
|
|
3855
|
+
resume: {}
|
|
3856
|
+
},
|
|
3385
3857
|
_meta: {
|
|
3386
3858
|
posthog: {
|
|
3387
3859
|
resumeSession: true
|
|
3860
|
+
},
|
|
3861
|
+
claudeCode: {
|
|
3862
|
+
promptQueueing: true
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
},
|
|
3866
|
+
agentInfo: {
|
|
3867
|
+
name: package_default.name,
|
|
3868
|
+
title: "Claude Agent",
|
|
3869
|
+
version: package_default.version
|
|
3870
|
+
},
|
|
3871
|
+
authMethods: []
|
|
3872
|
+
};
|
|
3873
|
+
}
|
|
3874
|
+
async newSession(params) {
|
|
3875
|
+
if (fs3.existsSync(path4.resolve(os4.homedir(), ".claude.json.backup")) && !fs3.existsSync(path4.resolve(os4.homedir(), ".claude.json"))) {
|
|
3876
|
+
throw import_sdk2.RequestError.authRequired();
|
|
3877
|
+
}
|
|
3878
|
+
const response = await this.createSession(params, {
|
|
3879
|
+
// Revisit these meta values once we support resume
|
|
3880
|
+
resume: params._meta?.claudeCode?.options?.resume
|
|
3881
|
+
});
|
|
3882
|
+
return response;
|
|
3883
|
+
}
|
|
3884
|
+
async unstable_forkSession(params) {
|
|
3885
|
+
return this.createSession(
|
|
3886
|
+
{
|
|
3887
|
+
cwd: params.cwd,
|
|
3888
|
+
mcpServers: params.mcpServers ?? [],
|
|
3889
|
+
_meta: params._meta
|
|
3890
|
+
},
|
|
3891
|
+
{ resume: params.sessionId, forkSession: true }
|
|
3892
|
+
);
|
|
3893
|
+
}
|
|
3894
|
+
async unstable_resumeSession(params) {
|
|
3895
|
+
const response = await this.createSession(
|
|
3896
|
+
{
|
|
3897
|
+
cwd: params.cwd,
|
|
3898
|
+
mcpServers: params.mcpServers ?? [],
|
|
3899
|
+
_meta: params._meta
|
|
3900
|
+
},
|
|
3901
|
+
{
|
|
3902
|
+
resume: params.sessionId
|
|
3903
|
+
}
|
|
3904
|
+
);
|
|
3905
|
+
return response;
|
|
3906
|
+
}
|
|
3907
|
+
async loadSession(params) {
|
|
3908
|
+
const response = await this.createSession(
|
|
3909
|
+
{
|
|
3910
|
+
cwd: params.cwd,
|
|
3911
|
+
mcpServers: params.mcpServers ?? [],
|
|
3912
|
+
_meta: params._meta
|
|
3913
|
+
},
|
|
3914
|
+
{ resume: params.sessionId, skipBackgroundFetches: true }
|
|
3915
|
+
);
|
|
3916
|
+
await this.replaySessionHistory(params.sessionId);
|
|
3917
|
+
this.deferBackgroundFetches(this.session.query);
|
|
3918
|
+
return {
|
|
3919
|
+
modes: response.modes,
|
|
3920
|
+
models: response.models,
|
|
3921
|
+
configOptions: response.configOptions
|
|
3922
|
+
};
|
|
3923
|
+
}
|
|
3924
|
+
async unstable_listSessions(params) {
|
|
3925
|
+
const sdkSessions = await (0, import_claude_agent_sdk.listSessions)({ dir: params.cwd ?? void 0 });
|
|
3926
|
+
const sessions = [];
|
|
3927
|
+
for (const session of sdkSessions) {
|
|
3928
|
+
if (!session.cwd) continue;
|
|
3929
|
+
sessions.push({
|
|
3930
|
+
sessionId: session.sessionId,
|
|
3931
|
+
cwd: session.cwd,
|
|
3932
|
+
title: sanitizeTitle(session.customTitle || session.summary || ""),
|
|
3933
|
+
updatedAt: new Date(session.lastModified).toISOString()
|
|
3934
|
+
});
|
|
3935
|
+
}
|
|
3936
|
+
return {
|
|
3937
|
+
sessions
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
async prompt(params) {
|
|
3941
|
+
this.session.cancelled = false;
|
|
3942
|
+
this.session.interruptReason = void 0;
|
|
3943
|
+
this.session.accumulatedUsage = {
|
|
3944
|
+
inputTokens: 0,
|
|
3945
|
+
outputTokens: 0,
|
|
3946
|
+
cachedReadTokens: 0,
|
|
3947
|
+
cachedWriteTokens: 0
|
|
3948
|
+
};
|
|
3949
|
+
const userMessage = promptToClaude(params);
|
|
3950
|
+
if (this.session.promptRunning) {
|
|
3951
|
+
const uuid = (0, import_node_crypto.randomUUID)();
|
|
3952
|
+
userMessage.uuid = uuid;
|
|
3953
|
+
this.session.input.push(userMessage);
|
|
3954
|
+
const order = this.session.nextPendingOrder++;
|
|
3955
|
+
const cancelled = await new Promise((resolve4) => {
|
|
3956
|
+
this.session.pendingMessages.set(uuid, { resolve: resolve4, order });
|
|
3957
|
+
});
|
|
3958
|
+
if (cancelled) {
|
|
3959
|
+
return { stopReason: "cancelled" };
|
|
3960
|
+
}
|
|
3961
|
+
} else {
|
|
3962
|
+
this.session.input.push(userMessage);
|
|
3963
|
+
}
|
|
3964
|
+
await this.broadcastUserMessage(params);
|
|
3965
|
+
this.session.promptRunning = true;
|
|
3966
|
+
let handedOff = false;
|
|
3967
|
+
let lastAssistantTotalUsage = null;
|
|
3968
|
+
const supportsTerminalOutput = this.clientCapabilities?._meta?.terminal_output === true;
|
|
3969
|
+
const context = {
|
|
3970
|
+
session: this.session,
|
|
3971
|
+
sessionId: params.sessionId,
|
|
3972
|
+
client: this.client,
|
|
3973
|
+
toolUseCache: this.toolUseCache,
|
|
3974
|
+
fileContentCache: this.fileContentCache,
|
|
3975
|
+
logger: this.logger,
|
|
3976
|
+
supportsTerminalOutput
|
|
3977
|
+
};
|
|
3978
|
+
try {
|
|
3979
|
+
while (true) {
|
|
3980
|
+
const { value: message, done } = await this.session.query.next();
|
|
3981
|
+
if (done || !message) {
|
|
3982
|
+
if (this.session.cancelled) {
|
|
3983
|
+
return {
|
|
3984
|
+
stopReason: "cancelled",
|
|
3985
|
+
_meta: this.session.interruptReason ? { interruptReason: this.session.interruptReason } : void 0
|
|
3986
|
+
};
|
|
3987
|
+
}
|
|
3988
|
+
break;
|
|
3989
|
+
}
|
|
3990
|
+
switch (message.type) {
|
|
3991
|
+
case "system":
|
|
3992
|
+
if (message.subtype === "compact_boundary") {
|
|
3993
|
+
lastAssistantTotalUsage = 0;
|
|
3994
|
+
}
|
|
3995
|
+
await handleSystemMessage(message, context);
|
|
3996
|
+
break;
|
|
3997
|
+
case "result": {
|
|
3998
|
+
if (this.session.cancelled) {
|
|
3999
|
+
return { stopReason: "cancelled" };
|
|
4000
|
+
}
|
|
4001
|
+
this.session.accumulatedUsage.inputTokens += message.usage.input_tokens;
|
|
4002
|
+
this.session.accumulatedUsage.outputTokens += message.usage.output_tokens;
|
|
4003
|
+
this.session.accumulatedUsage.cachedReadTokens += message.usage.cache_read_input_tokens;
|
|
4004
|
+
this.session.accumulatedUsage.cachedWriteTokens += message.usage.cache_creation_input_tokens;
|
|
4005
|
+
const contextWindows = Object.values(message.modelUsage).map(
|
|
4006
|
+
(m) => m.contextWindow
|
|
4007
|
+
);
|
|
4008
|
+
const contextWindowSize = contextWindows.length > 0 ? Math.min(...contextWindows) : 2e5;
|
|
4009
|
+
if (lastAssistantTotalUsage !== null) {
|
|
4010
|
+
await this.client.sessionUpdate({
|
|
4011
|
+
sessionId: params.sessionId,
|
|
4012
|
+
update: {
|
|
4013
|
+
sessionUpdate: "usage_update",
|
|
4014
|
+
used: lastAssistantTotalUsage,
|
|
4015
|
+
size: contextWindowSize,
|
|
4016
|
+
cost: {
|
|
4017
|
+
amount: message.total_cost_usd,
|
|
4018
|
+
currency: "USD"
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
});
|
|
4022
|
+
}
|
|
4023
|
+
await this.client.extNotification("_posthog/usage_update", {
|
|
4024
|
+
sessionId: params.sessionId,
|
|
4025
|
+
used: {
|
|
4026
|
+
inputTokens: message.usage.input_tokens,
|
|
4027
|
+
outputTokens: message.usage.output_tokens,
|
|
4028
|
+
cachedReadTokens: message.usage.cache_read_input_tokens,
|
|
4029
|
+
cachedWriteTokens: message.usage.cache_creation_input_tokens
|
|
4030
|
+
},
|
|
4031
|
+
cost: message.total_cost_usd
|
|
4032
|
+
});
|
|
4033
|
+
const usage = {
|
|
4034
|
+
inputTokens: this.session.accumulatedUsage.inputTokens,
|
|
4035
|
+
outputTokens: this.session.accumulatedUsage.outputTokens,
|
|
4036
|
+
cachedReadTokens: this.session.accumulatedUsage.cachedReadTokens,
|
|
4037
|
+
cachedWriteTokens: this.session.accumulatedUsage.cachedWriteTokens,
|
|
4038
|
+
totalTokens: this.session.accumulatedUsage.inputTokens + this.session.accumulatedUsage.outputTokens + this.session.accumulatedUsage.cachedReadTokens + this.session.accumulatedUsage.cachedWriteTokens
|
|
4039
|
+
};
|
|
4040
|
+
const result = handleResultMessage(message);
|
|
4041
|
+
if (result.error) throw result.error;
|
|
4042
|
+
switch (message.subtype) {
|
|
4043
|
+
case "error_max_budget_usd":
|
|
4044
|
+
case "error_max_turns":
|
|
4045
|
+
case "error_max_structured_output_retries":
|
|
4046
|
+
return { stopReason: "max_turn_requests", usage };
|
|
4047
|
+
default:
|
|
4048
|
+
return { stopReason: "end_turn", usage };
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
case "stream_event":
|
|
4052
|
+
await handleStreamEvent(message, context);
|
|
4053
|
+
break;
|
|
4054
|
+
case "user":
|
|
4055
|
+
case "assistant": {
|
|
4056
|
+
if (this.session.cancelled) {
|
|
4057
|
+
break;
|
|
4058
|
+
}
|
|
4059
|
+
if (message.type === "user" && "uuid" in message && message.uuid) {
|
|
4060
|
+
const pending = this.session.pendingMessages.get(
|
|
4061
|
+
message.uuid
|
|
4062
|
+
);
|
|
4063
|
+
if (pending) {
|
|
4064
|
+
pending.resolve(false);
|
|
4065
|
+
this.session.pendingMessages.delete(message.uuid);
|
|
4066
|
+
handedOff = true;
|
|
4067
|
+
return { stopReason: "end_turn" };
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
if ("usage" in message.message && message.parent_tool_use_id === null) {
|
|
4071
|
+
const usage = message.message.usage;
|
|
4072
|
+
lastAssistantTotalUsage = usage.input_tokens + usage.output_tokens + usage.cache_read_input_tokens + usage.cache_creation_input_tokens;
|
|
4073
|
+
}
|
|
4074
|
+
const result = await handleUserAssistantMessage(message, context);
|
|
4075
|
+
if (result.error) throw result.error;
|
|
4076
|
+
if (result.shouldStop) {
|
|
4077
|
+
return { stopReason: "end_turn" };
|
|
4078
|
+
}
|
|
4079
|
+
break;
|
|
3388
4080
|
}
|
|
4081
|
+
case "tool_progress":
|
|
4082
|
+
case "auth_status":
|
|
4083
|
+
case "tool_use_summary":
|
|
4084
|
+
break;
|
|
4085
|
+
default:
|
|
4086
|
+
unreachable(message, this.logger);
|
|
4087
|
+
break;
|
|
3389
4088
|
}
|
|
3390
|
-
}
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
id: "claude-login",
|
|
3399
|
-
name: "Log in with Claude Code",
|
|
3400
|
-
description: "Run `claude /login` in the terminal"
|
|
4089
|
+
}
|
|
4090
|
+
throw new Error("Session did not end in result");
|
|
4091
|
+
} finally {
|
|
4092
|
+
if (!handedOff) {
|
|
4093
|
+
this.session.promptRunning = false;
|
|
4094
|
+
for (const [key, pending] of this.session.pendingMessages) {
|
|
4095
|
+
pending.resolve(true);
|
|
4096
|
+
this.session.pendingMessages.delete(key);
|
|
3401
4097
|
}
|
|
3402
|
-
|
|
3403
|
-
}
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
3404
4100
|
}
|
|
3405
|
-
|
|
3406
|
-
|
|
4101
|
+
// Called by BaseAcpAgent#cancel() to interrupt the session
|
|
4102
|
+
async interrupt() {
|
|
4103
|
+
this.session.cancelled = true;
|
|
4104
|
+
for (const [, pending] of this.session.pendingMessages) {
|
|
4105
|
+
pending.resolve(true);
|
|
4106
|
+
}
|
|
4107
|
+
this.session.pendingMessages.clear();
|
|
4108
|
+
await this.session.query.interrupt();
|
|
3407
4109
|
}
|
|
3408
|
-
async
|
|
3409
|
-
|
|
4110
|
+
async unstable_setSessionModel(params) {
|
|
4111
|
+
const sdkModelId = toSdkModelId(params.modelId);
|
|
4112
|
+
await this.session.query.setModel(sdkModelId);
|
|
4113
|
+
this.session.modelId = params.modelId;
|
|
4114
|
+
await this.updateConfigOption("model", params.modelId);
|
|
4115
|
+
return {};
|
|
4116
|
+
}
|
|
4117
|
+
async setSessionMode(params) {
|
|
4118
|
+
await this.applySessionMode(params.modeId);
|
|
4119
|
+
await this.updateConfigOption("mode", params.modeId);
|
|
4120
|
+
return {};
|
|
4121
|
+
}
|
|
4122
|
+
async setSessionConfigOption(params) {
|
|
4123
|
+
const option = this.session.configOptions.find(
|
|
4124
|
+
(o) => o.id === params.configId
|
|
4125
|
+
);
|
|
4126
|
+
if (!option) {
|
|
4127
|
+
throw new Error(`Unknown config option: ${params.configId}`);
|
|
4128
|
+
}
|
|
4129
|
+
const allValues = "options" in option && Array.isArray(option.options) ? option.options.flatMap(
|
|
4130
|
+
(o) => "options" in o && Array.isArray(o.options) ? o.options : [o]
|
|
4131
|
+
) : [];
|
|
4132
|
+
const validValue = allValues.find((o) => o.value === params.value);
|
|
4133
|
+
if (!validValue) {
|
|
4134
|
+
throw new Error(
|
|
4135
|
+
`Invalid value for config option ${params.configId}: ${params.value}`
|
|
4136
|
+
);
|
|
4137
|
+
}
|
|
4138
|
+
if (params.configId === "mode") {
|
|
4139
|
+
await this.applySessionMode(params.value);
|
|
4140
|
+
await this.client.sessionUpdate({
|
|
4141
|
+
sessionId: this.sessionId,
|
|
4142
|
+
update: {
|
|
4143
|
+
sessionUpdate: "current_mode_update",
|
|
4144
|
+
currentModeId: params.value
|
|
4145
|
+
}
|
|
4146
|
+
});
|
|
4147
|
+
} else if (params.configId === "model") {
|
|
4148
|
+
const sdkModelId = toSdkModelId(params.value);
|
|
4149
|
+
await this.session.query.setModel(sdkModelId);
|
|
4150
|
+
this.session.modelId = params.value;
|
|
4151
|
+
}
|
|
4152
|
+
this.session.configOptions = this.session.configOptions.map(
|
|
4153
|
+
(o) => o.id === params.configId ? { ...o, currentValue: params.value } : o
|
|
4154
|
+
);
|
|
4155
|
+
return { configOptions: this.session.configOptions };
|
|
4156
|
+
}
|
|
4157
|
+
async updateConfigOption(configId, value) {
|
|
4158
|
+
this.session.configOptions = this.session.configOptions.map(
|
|
4159
|
+
(o) => o.id === configId ? { ...o, currentValue: value } : o
|
|
4160
|
+
);
|
|
4161
|
+
await this.client.sessionUpdate({
|
|
4162
|
+
sessionId: this.sessionId,
|
|
4163
|
+
update: {
|
|
4164
|
+
sessionUpdate: "config_option_update",
|
|
4165
|
+
configOptions: this.session.configOptions
|
|
4166
|
+
}
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
async applySessionMode(modeId) {
|
|
4170
|
+
if (!TWIG_EXECUTION_MODES.includes(modeId)) {
|
|
4171
|
+
throw new Error("Invalid Mode");
|
|
4172
|
+
}
|
|
4173
|
+
const previousMode = this.session.permissionMode;
|
|
4174
|
+
this.session.permissionMode = modeId;
|
|
4175
|
+
try {
|
|
4176
|
+
await this.session.query.setPermissionMode(modeId);
|
|
4177
|
+
} catch (error) {
|
|
4178
|
+
this.session.permissionMode = previousMode;
|
|
4179
|
+
if (error instanceof Error) {
|
|
4180
|
+
if (!error.message) {
|
|
4181
|
+
error.message = "Invalid Mode";
|
|
4182
|
+
}
|
|
4183
|
+
throw error;
|
|
4184
|
+
}
|
|
4185
|
+
throw new Error("Invalid Mode");
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
async createSession(params, creationOpts = {}) {
|
|
4189
|
+
const { cwd } = params;
|
|
4190
|
+
const { resume, forkSession } = creationOpts;
|
|
4191
|
+
const isResume = !!resume;
|
|
3410
4192
|
const meta = params._meta;
|
|
3411
4193
|
const taskId = meta?.persistence?.taskId;
|
|
3412
|
-
|
|
3413
|
-
|
|
4194
|
+
let sessionId;
|
|
4195
|
+
if (forkSession) {
|
|
4196
|
+
sessionId = (0, import_uuid.v7)();
|
|
4197
|
+
} else if (isResume) {
|
|
4198
|
+
sessionId = resume;
|
|
4199
|
+
} else {
|
|
4200
|
+
sessionId = (0, import_uuid.v7)();
|
|
4201
|
+
}
|
|
4202
|
+
const input = new Pushable();
|
|
4203
|
+
const settingsManager = new SettingsManager(cwd);
|
|
4204
|
+
await settingsManager.initialize();
|
|
4205
|
+
const mcpServers = parseMcpServers(params);
|
|
4206
|
+
const systemPrompt = buildSystemPrompt(meta?.systemPrompt);
|
|
4207
|
+
this.logger.info(isResume ? "Resuming session" : "Creating new session", {
|
|
3414
4208
|
sessionId,
|
|
3415
4209
|
taskId,
|
|
3416
4210
|
taskRunId: meta?.taskRunId,
|
|
3417
|
-
cwd
|
|
4211
|
+
cwd
|
|
3418
4212
|
});
|
|
3419
4213
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3420
|
-
const mcpServers = parseMcpServers(params);
|
|
3421
4214
|
const options = buildSessionOptions({
|
|
3422
|
-
cwd
|
|
4215
|
+
cwd,
|
|
3423
4216
|
mcpServers,
|
|
3424
4217
|
permissionMode,
|
|
3425
4218
|
canUseTool: this.createCanUseTool(sessionId),
|
|
3426
4219
|
logger: this.logger,
|
|
3427
|
-
systemPrompt
|
|
4220
|
+
systemPrompt,
|
|
3428
4221
|
userProvidedOptions: meta?.claudeCode?.options,
|
|
3429
4222
|
sessionId,
|
|
3430
|
-
isResume
|
|
3431
|
-
|
|
4223
|
+
isResume,
|
|
4224
|
+
forkSession,
|
|
4225
|
+
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories,
|
|
4226
|
+
disableBuiltInTools: meta?.disableBuiltInTools,
|
|
4227
|
+
settingsManager,
|
|
4228
|
+
onModeChange: this.createOnModeChange(),
|
|
3432
4229
|
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3433
4230
|
onProcessExited: this.options?.onProcessExited
|
|
3434
4231
|
});
|
|
3435
|
-
const
|
|
3436
|
-
options.model = DEFAULT_MODEL;
|
|
4232
|
+
const abortController = options.abortController;
|
|
3437
4233
|
const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
|
|
3438
|
-
const session =
|
|
3439
|
-
|
|
3440
|
-
q,
|
|
4234
|
+
const session = {
|
|
4235
|
+
query: q,
|
|
3441
4236
|
input,
|
|
4237
|
+
cancelled: false,
|
|
4238
|
+
settingsManager,
|
|
3442
4239
|
permissionMode,
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
const resolvedSdkModel = toSdkModelId(modelOptions.currentModelId);
|
|
3458
|
-
if (resolvedSdkModel !== DEFAULT_MODEL) {
|
|
3459
|
-
await this.trySetModel(q, modelOptions.currentModelId);
|
|
3460
|
-
}
|
|
3461
|
-
const configOptions = await this.buildConfigOptions(modelOptions);
|
|
3462
|
-
return {
|
|
3463
|
-
sessionId,
|
|
3464
|
-
configOptions
|
|
3465
|
-
};
|
|
3466
|
-
}
|
|
3467
|
-
async loadSession(params) {
|
|
3468
|
-
return this.resumeSession(params);
|
|
3469
|
-
}
|
|
3470
|
-
async resumeSession(params) {
|
|
3471
|
-
const meta = params._meta;
|
|
3472
|
-
const taskId = meta?.persistence?.taskId;
|
|
3473
|
-
const sessionId = meta?.sessionId;
|
|
3474
|
-
if (!sessionId) {
|
|
3475
|
-
throw new Error("Cannot resume session without sessionId");
|
|
3476
|
-
}
|
|
3477
|
-
if (this.sessionId === sessionId) {
|
|
3478
|
-
return {};
|
|
3479
|
-
}
|
|
3480
|
-
this.logger.info("Resuming session", {
|
|
3481
|
-
sessionId,
|
|
3482
|
-
taskId,
|
|
3483
|
-
taskRunId: meta?.taskRunId,
|
|
3484
|
-
cwd: params.cwd
|
|
3485
|
-
});
|
|
3486
|
-
const mcpServers = parseMcpServers(params);
|
|
3487
|
-
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3488
|
-
const { query: q, session } = await this.initializeQuery({
|
|
3489
|
-
cwd: params.cwd,
|
|
3490
|
-
permissionMode,
|
|
3491
|
-
mcpServers,
|
|
3492
|
-
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3493
|
-
userProvidedOptions: meta?.claudeCode?.options,
|
|
3494
|
-
sessionId,
|
|
3495
|
-
isResume: true,
|
|
3496
|
-
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3497
|
-
});
|
|
3498
|
-
this.logger.info("Session query initialized, awaiting resumption", {
|
|
3499
|
-
sessionId,
|
|
3500
|
-
taskId,
|
|
4240
|
+
abortController,
|
|
4241
|
+
accumulatedUsage: {
|
|
4242
|
+
inputTokens: 0,
|
|
4243
|
+
outputTokens: 0,
|
|
4244
|
+
cachedReadTokens: 0,
|
|
4245
|
+
cachedWriteTokens: 0
|
|
4246
|
+
},
|
|
4247
|
+
configOptions: [],
|
|
4248
|
+
promptRunning: false,
|
|
4249
|
+
pendingMessages: /* @__PURE__ */ new Map(),
|
|
4250
|
+
nextPendingOrder: 0,
|
|
4251
|
+
// Custom properties
|
|
4252
|
+
cwd,
|
|
4253
|
+
notificationHistory: [],
|
|
3501
4254
|
taskRunId: meta?.taskRunId
|
|
3502
|
-
}
|
|
3503
|
-
session
|
|
4255
|
+
};
|
|
4256
|
+
this.session = session;
|
|
4257
|
+
this.sessionId = sessionId;
|
|
4258
|
+
this.logger.info(
|
|
4259
|
+
isResume ? "Session query initialized, awaiting resumption" : "Session query initialized, awaiting initialization",
|
|
4260
|
+
{ sessionId, taskId, taskRunId: meta?.taskRunId }
|
|
4261
|
+
);
|
|
3504
4262
|
try {
|
|
3505
4263
|
const result = await withTimeout(
|
|
3506
4264
|
q.initializationResult(),
|
|
@@ -3508,231 +4266,181 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3508
4266
|
);
|
|
3509
4267
|
if (result.result === "timeout") {
|
|
3510
4268
|
throw new Error(
|
|
3511
|
-
`Session resumption timed out for sessionId=${sessionId}`
|
|
4269
|
+
`Session ${isResume ? forkSession ? "fork" : "resumption" : "initialization"} timed out for sessionId=${sessionId}`
|
|
3512
4270
|
);
|
|
3513
4271
|
}
|
|
3514
4272
|
} catch (err) {
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
4273
|
+
settingsManager.dispose();
|
|
4274
|
+
this.logger.error(
|
|
4275
|
+
isResume ? forkSession ? "Session fork failed" : "Session resumption failed" : "Session initialization failed",
|
|
4276
|
+
{
|
|
4277
|
+
sessionId,
|
|
4278
|
+
taskId,
|
|
4279
|
+
taskRunId: meta?.taskRunId,
|
|
4280
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4281
|
+
}
|
|
4282
|
+
);
|
|
3521
4283
|
throw err;
|
|
3522
4284
|
}
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
const configOptions = await this.buildConfigOptions();
|
|
3530
|
-
return { configOptions };
|
|
3531
|
-
}
|
|
3532
|
-
async prompt(params) {
|
|
3533
|
-
this.session.cancelled = false;
|
|
3534
|
-
this.session.interruptReason = void 0;
|
|
3535
|
-
await this.broadcastUserMessage(params);
|
|
3536
|
-
this.session.input.push(promptToClaude(params));
|
|
3537
|
-
return this.processMessages(params.sessionId);
|
|
3538
|
-
}
|
|
3539
|
-
async setSessionConfigOption(params) {
|
|
3540
|
-
const configId = params.configId;
|
|
3541
|
-
const value = params.value;
|
|
3542
|
-
if (configId === "mode") {
|
|
3543
|
-
const modeId = value;
|
|
3544
|
-
if (!TWIG_EXECUTION_MODES.includes(modeId)) {
|
|
3545
|
-
throw new Error("Invalid Mode");
|
|
3546
|
-
}
|
|
3547
|
-
this.session.permissionMode = modeId;
|
|
3548
|
-
await this.session.query.setPermissionMode(modeId);
|
|
3549
|
-
} else if (configId === "model") {
|
|
3550
|
-
await this.setModelWithFallback(this.session.query, value);
|
|
3551
|
-
this.session.modelId = value;
|
|
3552
|
-
} else {
|
|
3553
|
-
throw new Error("Unsupported config option");
|
|
3554
|
-
}
|
|
3555
|
-
await this.emitConfigOptionsUpdate();
|
|
3556
|
-
return { configOptions: await this.buildConfigOptions() };
|
|
3557
|
-
}
|
|
3558
|
-
async interruptSession() {
|
|
3559
|
-
await this.session.query.interrupt();
|
|
3560
|
-
}
|
|
3561
|
-
async extMethod(method, params) {
|
|
3562
|
-
if (method === "_posthog/session/resume") {
|
|
3563
|
-
const result = await this.resumeSession(
|
|
3564
|
-
params
|
|
3565
|
-
);
|
|
3566
|
-
return {
|
|
3567
|
-
_meta: {
|
|
3568
|
-
configOptions: result.configOptions
|
|
3569
|
-
}
|
|
3570
|
-
};
|
|
4285
|
+
if (meta?.taskRunId) {
|
|
4286
|
+
await this.client.extNotification("_posthog/sdk_session", {
|
|
4287
|
+
taskRunId: meta.taskRunId,
|
|
4288
|
+
sessionId,
|
|
4289
|
+
adapter: "claude"
|
|
4290
|
+
});
|
|
3571
4291
|
}
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
4292
|
+
const settingsModel = settingsManager.getSettings().model;
|
|
4293
|
+
const modelOptions = await this.getModelConfigOptions();
|
|
4294
|
+
const resolvedModelId = settingsModel || modelOptions.currentModelId;
|
|
4295
|
+
session.modelId = resolvedModelId;
|
|
4296
|
+
if (!isResume) {
|
|
4297
|
+
const resolvedSdkModel = toSdkModelId(resolvedModelId);
|
|
4298
|
+
if (resolvedSdkModel !== DEFAULT_MODEL) {
|
|
4299
|
+
await this.session.query.setModel(resolvedSdkModel);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
const availableModes2 = getAvailableModes();
|
|
4303
|
+
const modes = {
|
|
4304
|
+
currentModeId: permissionMode,
|
|
4305
|
+
availableModes: availableModes2.map((mode) => ({
|
|
4306
|
+
id: mode.id,
|
|
4307
|
+
name: mode.name,
|
|
4308
|
+
description: mode.description ?? void 0
|
|
4309
|
+
}))
|
|
4310
|
+
};
|
|
4311
|
+
const models = {
|
|
4312
|
+
currentModelId: resolvedModelId,
|
|
4313
|
+
availableModels: modelOptions.options.map(
|
|
4314
|
+
(opt) => ({
|
|
4315
|
+
modelId: opt.value,
|
|
4316
|
+
name: opt.name,
|
|
4317
|
+
description: opt.description
|
|
4318
|
+
})
|
|
4319
|
+
)
|
|
3583
4320
|
};
|
|
3584
|
-
this.
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
systemPrompt: config.systemPrompt,
|
|
3597
|
-
userProvidedOptions: config.userProvidedOptions,
|
|
3598
|
-
sessionId: config.sessionId,
|
|
3599
|
-
isResume: config.isResume,
|
|
3600
|
-
additionalDirectories: config.additionalDirectories,
|
|
3601
|
-
onModeChange: this.createOnModeChange(config.sessionId),
|
|
3602
|
-
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3603
|
-
onProcessExited: this.options?.onProcessExited
|
|
3604
|
-
});
|
|
3605
|
-
const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
|
|
3606
|
-
const abortController = options.abortController;
|
|
3607
|
-
const session = this.createSession(
|
|
3608
|
-
config.sessionId,
|
|
3609
|
-
q,
|
|
3610
|
-
input,
|
|
3611
|
-
config.permissionMode,
|
|
3612
|
-
config.cwd,
|
|
3613
|
-
abortController
|
|
4321
|
+
const configOptions = this.buildConfigOptions(permissionMode, modelOptions);
|
|
4322
|
+
session.configOptions = configOptions;
|
|
4323
|
+
if (!creationOpts.skipBackgroundFetches) {
|
|
4324
|
+
this.deferBackgroundFetches(q);
|
|
4325
|
+
}
|
|
4326
|
+
this.logger.info(
|
|
4327
|
+
isResume ? "Session resumed successfully" : "Session created successfully",
|
|
4328
|
+
{
|
|
4329
|
+
sessionId,
|
|
4330
|
+
taskId,
|
|
4331
|
+
taskRunId: meta?.taskRunId
|
|
4332
|
+
}
|
|
3614
4333
|
);
|
|
3615
|
-
return {
|
|
4334
|
+
return { sessionId, modes, models, configOptions };
|
|
3616
4335
|
}
|
|
3617
4336
|
createCanUseTool(sessionId) {
|
|
3618
|
-
return async (toolName, toolInput, { suggestions, toolUseID }) => canUseTool({
|
|
4337
|
+
return async (toolName, toolInput, { suggestions, toolUseID, signal }) => canUseTool({
|
|
3619
4338
|
session: this.session,
|
|
3620
4339
|
toolName,
|
|
3621
4340
|
toolInput,
|
|
3622
4341
|
toolUseID,
|
|
3623
4342
|
suggestions,
|
|
4343
|
+
signal,
|
|
3624
4344
|
client: this.client,
|
|
3625
4345
|
sessionId,
|
|
3626
4346
|
fileContentCache: this.fileContentCache,
|
|
3627
4347
|
logger: this.logger,
|
|
3628
|
-
|
|
4348
|
+
updateConfigOption: (configId, value) => this.updateConfigOption(configId, value)
|
|
3629
4349
|
});
|
|
3630
4350
|
}
|
|
3631
|
-
createOnModeChange(
|
|
4351
|
+
createOnModeChange() {
|
|
3632
4352
|
return async (newMode) => {
|
|
3633
4353
|
if (this.session) {
|
|
3634
4354
|
this.session.permissionMode = newMode;
|
|
3635
4355
|
}
|
|
3636
|
-
await this.
|
|
4356
|
+
await this.updateConfigOption("mode", newMode);
|
|
3637
4357
|
};
|
|
3638
4358
|
}
|
|
3639
|
-
|
|
3640
|
-
const options = [];
|
|
4359
|
+
buildConfigOptions(currentModeId, modelOptions) {
|
|
3641
4360
|
const modeOptions = getAvailableModes().map((mode) => ({
|
|
3642
4361
|
value: mode.id,
|
|
3643
4362
|
name: mode.name,
|
|
3644
4363
|
description: mode.description ?? void 0
|
|
3645
4364
|
}));
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
return options;
|
|
4365
|
+
return [
|
|
4366
|
+
{
|
|
4367
|
+
id: "mode",
|
|
4368
|
+
name: "Approval Preset",
|
|
4369
|
+
type: "select",
|
|
4370
|
+
currentValue: currentModeId,
|
|
4371
|
+
options: modeOptions,
|
|
4372
|
+
category: "mode",
|
|
4373
|
+
description: "Choose an approval and sandboxing preset for your session"
|
|
4374
|
+
},
|
|
4375
|
+
{
|
|
4376
|
+
id: "model",
|
|
4377
|
+
name: "Model",
|
|
4378
|
+
type: "select",
|
|
4379
|
+
currentValue: modelOptions.currentModelId,
|
|
4380
|
+
options: modelOptions.options,
|
|
4381
|
+
category: "model",
|
|
4382
|
+
description: "Choose which model Claude should use"
|
|
4383
|
+
}
|
|
4384
|
+
];
|
|
3667
4385
|
}
|
|
3668
|
-
async
|
|
3669
|
-
const
|
|
3670
|
-
const serialized = JSON.stringify(configOptions);
|
|
3671
|
-
if (this.lastSentConfigOptions && JSON.stringify(this.lastSentConfigOptions) === serialized) {
|
|
3672
|
-
return;
|
|
3673
|
-
}
|
|
3674
|
-
this.lastSentConfigOptions = configOptions;
|
|
4386
|
+
async sendAvailableCommandsUpdate() {
|
|
4387
|
+
const commands = await this.session.query.supportedCommands();
|
|
3675
4388
|
await this.client.sessionUpdate({
|
|
3676
|
-
sessionId:
|
|
4389
|
+
sessionId: this.sessionId,
|
|
3677
4390
|
update: {
|
|
3678
|
-
sessionUpdate: "
|
|
3679
|
-
|
|
4391
|
+
sessionUpdate: "available_commands_update",
|
|
4392
|
+
availableCommands: getAvailableSlashCommands(commands)
|
|
3680
4393
|
}
|
|
3681
4394
|
});
|
|
3682
4395
|
}
|
|
3683
|
-
|
|
3684
|
-
const backupExists = fs2.existsSync(
|
|
3685
|
-
path3.resolve(os3.homedir(), ".claude.json.backup")
|
|
3686
|
-
);
|
|
3687
|
-
const configExists = fs2.existsSync(
|
|
3688
|
-
path3.resolve(os3.homedir(), ".claude.json")
|
|
3689
|
-
);
|
|
3690
|
-
if (backupExists && !configExists) {
|
|
3691
|
-
throw import_sdk2.RequestError.authRequired();
|
|
3692
|
-
}
|
|
3693
|
-
}
|
|
3694
|
-
async trySetModel(q, modelId) {
|
|
4396
|
+
async replaySessionHistory(sessionId) {
|
|
3695
4397
|
try {
|
|
3696
|
-
await
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
4398
|
+
const messages = await (0, import_claude_agent_sdk.getSessionMessages)(sessionId, {
|
|
4399
|
+
dir: this.session.cwd
|
|
4400
|
+
});
|
|
4401
|
+
const replayContext = {
|
|
4402
|
+
session: this.session,
|
|
4403
|
+
sessionId,
|
|
4404
|
+
client: this.client,
|
|
4405
|
+
toolUseCache: this.toolUseCache,
|
|
4406
|
+
fileContentCache: this.fileContentCache,
|
|
4407
|
+
logger: this.logger,
|
|
4408
|
+
registerHooks: false
|
|
4409
|
+
};
|
|
4410
|
+
for (const msg of messages) {
|
|
4411
|
+
const sdkMessage = {
|
|
4412
|
+
type: msg.type,
|
|
4413
|
+
message: msg.message,
|
|
4414
|
+
parent_tool_use_id: msg.parent_tool_use_id
|
|
4415
|
+
};
|
|
4416
|
+
await handleUserAssistantMessage(
|
|
4417
|
+
sdkMessage,
|
|
4418
|
+
replayContext
|
|
4419
|
+
);
|
|
3708
4420
|
}
|
|
3709
|
-
|
|
4421
|
+
} catch (err) {
|
|
4422
|
+
this.logger.warn("Failed to replay session history", {
|
|
4423
|
+
sessionId,
|
|
4424
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4425
|
+
});
|
|
3710
4426
|
}
|
|
3711
4427
|
}
|
|
4428
|
+
// ================================
|
|
4429
|
+
// EXTENSION METHODS
|
|
4430
|
+
// ================================
|
|
3712
4431
|
/**
|
|
3713
4432
|
* Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
|
|
3714
4433
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
3715
4434
|
*/
|
|
3716
|
-
deferBackgroundFetches(q
|
|
4435
|
+
deferBackgroundFetches(q) {
|
|
3717
4436
|
Promise.all([
|
|
3718
|
-
|
|
4437
|
+
new Promise((resolve4) => setTimeout(resolve4, 10)).then(
|
|
4438
|
+
() => this.sendAvailableCommandsUpdate()
|
|
4439
|
+
),
|
|
3719
4440
|
fetchMcpToolMetadata(q, this.logger)
|
|
3720
|
-
]).
|
|
3721
|
-
this.
|
|
3722
|
-
|
|
3723
|
-
this.logger.warn("Failed to fetch deferred session data", { err });
|
|
3724
|
-
});
|
|
3725
|
-
}
|
|
3726
|
-
sendAvailableCommandsUpdate(sessionId, availableCommands) {
|
|
3727
|
-
setTimeout(() => {
|
|
3728
|
-
this.client.sessionUpdate({
|
|
3729
|
-
sessionId,
|
|
3730
|
-
update: {
|
|
3731
|
-
sessionUpdate: "available_commands_update",
|
|
3732
|
-
availableCommands
|
|
3733
|
-
}
|
|
3734
|
-
});
|
|
3735
|
-
}, 0);
|
|
4441
|
+
]).catch(
|
|
4442
|
+
(err) => this.logger.error("Background fetch failed", { error: err })
|
|
4443
|
+
);
|
|
3736
4444
|
}
|
|
3737
4445
|
async broadcastUserMessage(params) {
|
|
3738
4446
|
for (const chunk of params.prompt) {
|
|
@@ -3747,71 +4455,6 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3747
4455
|
this.appendNotification(params.sessionId, notification);
|
|
3748
4456
|
}
|
|
3749
4457
|
}
|
|
3750
|
-
async processMessages(sessionId) {
|
|
3751
|
-
const context = {
|
|
3752
|
-
session: this.session,
|
|
3753
|
-
sessionId,
|
|
3754
|
-
client: this.client,
|
|
3755
|
-
toolUseCache: this.toolUseCache,
|
|
3756
|
-
fileContentCache: this.fileContentCache,
|
|
3757
|
-
logger: this.logger
|
|
3758
|
-
};
|
|
3759
|
-
while (true) {
|
|
3760
|
-
const { value: message, done } = await this.session.query.next();
|
|
3761
|
-
if (done || !message) {
|
|
3762
|
-
return this.handleSessionEnd();
|
|
3763
|
-
}
|
|
3764
|
-
const response = await this.handleMessage(message, context);
|
|
3765
|
-
if (response) {
|
|
3766
|
-
return response;
|
|
3767
|
-
}
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
handleSessionEnd() {
|
|
3771
|
-
if (this.session.cancelled) {
|
|
3772
|
-
return {
|
|
3773
|
-
stopReason: "cancelled",
|
|
3774
|
-
_meta: this.session.interruptReason ? { interruptReason: this.session.interruptReason } : void 0
|
|
3775
|
-
};
|
|
3776
|
-
}
|
|
3777
|
-
throw new Error("Session did not end in result");
|
|
3778
|
-
}
|
|
3779
|
-
async handleMessage(message, context) {
|
|
3780
|
-
switch (message.type) {
|
|
3781
|
-
case "system":
|
|
3782
|
-
await handleSystemMessage(message, context);
|
|
3783
|
-
return null;
|
|
3784
|
-
case "result": {
|
|
3785
|
-
const result = handleResultMessage(message, context);
|
|
3786
|
-
if (result.error) throw result.error;
|
|
3787
|
-
if (result.shouldStop) {
|
|
3788
|
-
return {
|
|
3789
|
-
stopReason: result.stopReason
|
|
3790
|
-
};
|
|
3791
|
-
}
|
|
3792
|
-
return null;
|
|
3793
|
-
}
|
|
3794
|
-
case "stream_event":
|
|
3795
|
-
await handleStreamEvent(message, context);
|
|
3796
|
-
return null;
|
|
3797
|
-
case "user":
|
|
3798
|
-
case "assistant": {
|
|
3799
|
-
const result = await handleUserAssistantMessage(message, context);
|
|
3800
|
-
if (result.error) throw result.error;
|
|
3801
|
-
if (result.shouldStop) {
|
|
3802
|
-
return { stopReason: "end_turn" };
|
|
3803
|
-
}
|
|
3804
|
-
return null;
|
|
3805
|
-
}
|
|
3806
|
-
case "tool_progress":
|
|
3807
|
-
case "auth_status":
|
|
3808
|
-
case "tool_use_summary":
|
|
3809
|
-
return null;
|
|
3810
|
-
default:
|
|
3811
|
-
unreachable(message, this.logger);
|
|
3812
|
-
return null;
|
|
3813
|
-
}
|
|
3814
|
-
}
|
|
3815
4458
|
};
|
|
3816
4459
|
|
|
3817
4460
|
// src/adapters/codex/spawn.ts
|
|
@@ -4701,8 +5344,8 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4701
5344
|
};
|
|
4702
5345
|
|
|
4703
5346
|
// ../git/dist/queries.js
|
|
4704
|
-
var
|
|
4705
|
-
var
|
|
5347
|
+
var fs6 = __toESM(require("fs/promises"), 1);
|
|
5348
|
+
var path7 = __toESM(require("path"), 1);
|
|
4706
5349
|
|
|
4707
5350
|
// ../../node_modules/simple-git/dist/esm/index.js
|
|
4708
5351
|
var import_node_buffer = require("buffer");
|
|
@@ -4741,8 +5384,8 @@ function pathspec(...paths) {
|
|
|
4741
5384
|
cache.set(key, paths);
|
|
4742
5385
|
return key;
|
|
4743
5386
|
}
|
|
4744
|
-
function isPathSpec(
|
|
4745
|
-
return
|
|
5387
|
+
function isPathSpec(path9) {
|
|
5388
|
+
return path9 instanceof String && cache.has(path9);
|
|
4746
5389
|
}
|
|
4747
5390
|
function toPaths(pathSpec) {
|
|
4748
5391
|
return cache.get(pathSpec) || [];
|
|
@@ -4831,8 +5474,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
4831
5474
|
function forEachLineWithContent(input, callback) {
|
|
4832
5475
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
4833
5476
|
}
|
|
4834
|
-
function folderExists(
|
|
4835
|
-
return (0, import_file_exists.exists)(
|
|
5477
|
+
function folderExists(path9) {
|
|
5478
|
+
return (0, import_file_exists.exists)(path9, import_file_exists.FOLDER);
|
|
4836
5479
|
}
|
|
4837
5480
|
function append(target, item) {
|
|
4838
5481
|
if (Array.isArray(target)) {
|
|
@@ -5236,8 +5879,8 @@ function checkIsRepoRootTask() {
|
|
|
5236
5879
|
commands,
|
|
5237
5880
|
format: "utf-8",
|
|
5238
5881
|
onError,
|
|
5239
|
-
parser(
|
|
5240
|
-
return /^\.(git)?$/.test(
|
|
5882
|
+
parser(path9) {
|
|
5883
|
+
return /^\.(git)?$/.test(path9.trim());
|
|
5241
5884
|
}
|
|
5242
5885
|
};
|
|
5243
5886
|
}
|
|
@@ -5671,11 +6314,11 @@ function parseGrep(grep) {
|
|
|
5671
6314
|
const paths = /* @__PURE__ */ new Set();
|
|
5672
6315
|
const results = {};
|
|
5673
6316
|
forEachLineWithContent(grep, (input) => {
|
|
5674
|
-
const [
|
|
5675
|
-
paths.add(
|
|
5676
|
-
(results[
|
|
6317
|
+
const [path9, line, preview] = input.split(NULL);
|
|
6318
|
+
paths.add(path9);
|
|
6319
|
+
(results[path9] = results[path9] || []).push({
|
|
5677
6320
|
line: asNumber(line),
|
|
5678
|
-
path:
|
|
6321
|
+
path: path9,
|
|
5679
6322
|
preview
|
|
5680
6323
|
});
|
|
5681
6324
|
});
|
|
@@ -6440,14 +7083,14 @@ var init_hash_object = __esm({
|
|
|
6440
7083
|
init_task();
|
|
6441
7084
|
}
|
|
6442
7085
|
});
|
|
6443
|
-
function parseInit(bare,
|
|
7086
|
+
function parseInit(bare, path9, text2) {
|
|
6444
7087
|
const response = String(text2).trim();
|
|
6445
7088
|
let result;
|
|
6446
7089
|
if (result = initResponseRegex.exec(response)) {
|
|
6447
|
-
return new InitSummary(bare,
|
|
7090
|
+
return new InitSummary(bare, path9, false, result[1]);
|
|
6448
7091
|
}
|
|
6449
7092
|
if (result = reInitResponseRegex.exec(response)) {
|
|
6450
|
-
return new InitSummary(bare,
|
|
7093
|
+
return new InitSummary(bare, path9, true, result[1]);
|
|
6451
7094
|
}
|
|
6452
7095
|
let gitDir = "";
|
|
6453
7096
|
const tokens = response.split(" ");
|
|
@@ -6458,7 +7101,7 @@ function parseInit(bare, path8, text2) {
|
|
|
6458
7101
|
break;
|
|
6459
7102
|
}
|
|
6460
7103
|
}
|
|
6461
|
-
return new InitSummary(bare,
|
|
7104
|
+
return new InitSummary(bare, path9, /^re/i.test(response), gitDir);
|
|
6462
7105
|
}
|
|
6463
7106
|
var InitSummary;
|
|
6464
7107
|
var initResponseRegex;
|
|
@@ -6467,9 +7110,9 @@ var init_InitSummary = __esm({
|
|
|
6467
7110
|
"src/lib/responses/InitSummary.ts"() {
|
|
6468
7111
|
"use strict";
|
|
6469
7112
|
InitSummary = class {
|
|
6470
|
-
constructor(bare,
|
|
7113
|
+
constructor(bare, path9, existing, gitDir) {
|
|
6471
7114
|
this.bare = bare;
|
|
6472
|
-
this.path =
|
|
7115
|
+
this.path = path9;
|
|
6473
7116
|
this.existing = existing;
|
|
6474
7117
|
this.gitDir = gitDir;
|
|
6475
7118
|
}
|
|
@@ -6481,7 +7124,7 @@ var init_InitSummary = __esm({
|
|
|
6481
7124
|
function hasBareCommand(command) {
|
|
6482
7125
|
return command.includes(bareCommand);
|
|
6483
7126
|
}
|
|
6484
|
-
function initTask(bare = false,
|
|
7127
|
+
function initTask(bare = false, path9, customArgs) {
|
|
6485
7128
|
const commands = ["init", ...customArgs];
|
|
6486
7129
|
if (bare && !hasBareCommand(commands)) {
|
|
6487
7130
|
commands.splice(1, 0, bareCommand);
|
|
@@ -6490,7 +7133,7 @@ function initTask(bare = false, path8, customArgs) {
|
|
|
6490
7133
|
commands,
|
|
6491
7134
|
format: "utf-8",
|
|
6492
7135
|
parser(text2) {
|
|
6493
|
-
return parseInit(commands.includes("--bare"),
|
|
7136
|
+
return parseInit(commands.includes("--bare"), path9, text2);
|
|
6494
7137
|
}
|
|
6495
7138
|
};
|
|
6496
7139
|
}
|
|
@@ -7306,12 +7949,12 @@ var init_FileStatusSummary = __esm({
|
|
|
7306
7949
|
"use strict";
|
|
7307
7950
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
7308
7951
|
FileStatusSummary = class {
|
|
7309
|
-
constructor(
|
|
7310
|
-
this.path =
|
|
7952
|
+
constructor(path9, index, working_dir) {
|
|
7953
|
+
this.path = path9;
|
|
7311
7954
|
this.index = index;
|
|
7312
7955
|
this.working_dir = working_dir;
|
|
7313
7956
|
if (index === "R" || working_dir === "R") {
|
|
7314
|
-
const detail = fromPathRegex.exec(
|
|
7957
|
+
const detail = fromPathRegex.exec(path9) || [null, path9, path9];
|
|
7315
7958
|
this.from = detail[2] || "";
|
|
7316
7959
|
this.path = detail[1] || "";
|
|
7317
7960
|
}
|
|
@@ -7342,14 +7985,14 @@ function splitLine(result, lineStr) {
|
|
|
7342
7985
|
default:
|
|
7343
7986
|
return;
|
|
7344
7987
|
}
|
|
7345
|
-
function data(index, workingDir,
|
|
7988
|
+
function data(index, workingDir, path9) {
|
|
7346
7989
|
const raw = `${index}${workingDir}`;
|
|
7347
7990
|
const handler = parsers6.get(raw);
|
|
7348
7991
|
if (handler) {
|
|
7349
|
-
handler(result,
|
|
7992
|
+
handler(result, path9);
|
|
7350
7993
|
}
|
|
7351
7994
|
if (raw !== "##" && raw !== "!!") {
|
|
7352
|
-
result.files.push(new FileStatusSummary(
|
|
7995
|
+
result.files.push(new FileStatusSummary(path9, index, workingDir));
|
|
7353
7996
|
}
|
|
7354
7997
|
}
|
|
7355
7998
|
}
|
|
@@ -7662,9 +8305,9 @@ var init_simple_git_api = __esm({
|
|
|
7662
8305
|
next
|
|
7663
8306
|
);
|
|
7664
8307
|
}
|
|
7665
|
-
hashObject(
|
|
8308
|
+
hashObject(path9, write) {
|
|
7666
8309
|
return this._runTask(
|
|
7667
|
-
hashObjectTask(
|
|
8310
|
+
hashObjectTask(path9, write === true),
|
|
7668
8311
|
trailingFunctionArgument(arguments)
|
|
7669
8312
|
);
|
|
7670
8313
|
}
|
|
@@ -8017,8 +8660,8 @@ var init_branch = __esm({
|
|
|
8017
8660
|
}
|
|
8018
8661
|
});
|
|
8019
8662
|
function toPath(input) {
|
|
8020
|
-
const
|
|
8021
|
-
return
|
|
8663
|
+
const path9 = input.trim().replace(/^["']|["']$/g, "");
|
|
8664
|
+
return path9 && (0, import_node_path3.normalize)(path9);
|
|
8022
8665
|
}
|
|
8023
8666
|
var parseCheckIgnore;
|
|
8024
8667
|
var init_CheckIgnore = __esm({
|
|
@@ -8332,8 +8975,8 @@ __export(sub_module_exports, {
|
|
|
8332
8975
|
subModuleTask: () => subModuleTask,
|
|
8333
8976
|
updateSubModuleTask: () => updateSubModuleTask
|
|
8334
8977
|
});
|
|
8335
|
-
function addSubModuleTask(repo,
|
|
8336
|
-
return subModuleTask(["add", repo,
|
|
8978
|
+
function addSubModuleTask(repo, path9) {
|
|
8979
|
+
return subModuleTask(["add", repo, path9]);
|
|
8337
8980
|
}
|
|
8338
8981
|
function initSubModuleTask(customArgs) {
|
|
8339
8982
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -8663,8 +9306,8 @@ var require_git = __commonJS2({
|
|
|
8663
9306
|
}
|
|
8664
9307
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
8665
9308
|
};
|
|
8666
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
8667
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
9309
|
+
Git2.prototype.submoduleAdd = function(repo, path9, then) {
|
|
9310
|
+
return this._runTask(addSubModuleTask2(repo, path9), trailingFunctionArgument2(arguments));
|
|
8668
9311
|
};
|
|
8669
9312
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
8670
9313
|
return this._runTask(
|
|
@@ -9589,8 +10232,8 @@ var Saga = class {
|
|
|
9589
10232
|
|
|
9590
10233
|
// ../git/dist/sagas/tree.js
|
|
9591
10234
|
var import_node_fs3 = require("fs");
|
|
9592
|
-
var
|
|
9593
|
-
var
|
|
10235
|
+
var fs7 = __toESM(require("fs/promises"), 1);
|
|
10236
|
+
var path8 = __toESM(require("path"), 1);
|
|
9594
10237
|
var tar = __toESM(require("tar"), 1);
|
|
9595
10238
|
|
|
9596
10239
|
// ../git/dist/git-saga.js
|
|
@@ -9616,14 +10259,14 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9616
10259
|
tempIndexPath = null;
|
|
9617
10260
|
async executeGitOperations(input) {
|
|
9618
10261
|
const { baseDir, lastTreeHash, archivePath, signal } = input;
|
|
9619
|
-
const tmpDir =
|
|
10262
|
+
const tmpDir = path8.join(baseDir, ".git", "twig-tmp");
|
|
9620
10263
|
await this.step({
|
|
9621
10264
|
name: "create_tmp_dir",
|
|
9622
|
-
execute: () =>
|
|
10265
|
+
execute: () => fs7.mkdir(tmpDir, { recursive: true }),
|
|
9623
10266
|
rollback: async () => {
|
|
9624
10267
|
}
|
|
9625
10268
|
});
|
|
9626
|
-
this.tempIndexPath =
|
|
10269
|
+
this.tempIndexPath = path8.join(tmpDir, `index-${Date.now()}`);
|
|
9627
10270
|
const tempIndexGit = this.git.env({
|
|
9628
10271
|
...process.env,
|
|
9629
10272
|
GIT_INDEX_FILE: this.tempIndexPath
|
|
@@ -9633,7 +10276,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9633
10276
|
execute: () => tempIndexGit.raw(["read-tree", "HEAD"]),
|
|
9634
10277
|
rollback: async () => {
|
|
9635
10278
|
if (this.tempIndexPath) {
|
|
9636
|
-
await
|
|
10279
|
+
await fs7.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9637
10280
|
});
|
|
9638
10281
|
}
|
|
9639
10282
|
}
|
|
@@ -9642,7 +10285,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9642
10285
|
const treeHash = await this.readOnlyStep("write_tree", () => tempIndexGit.raw(["write-tree"]));
|
|
9643
10286
|
if (lastTreeHash && treeHash === lastTreeHash) {
|
|
9644
10287
|
this.log.debug("No changes since last capture", { treeHash });
|
|
9645
|
-
await
|
|
10288
|
+
await fs7.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9646
10289
|
});
|
|
9647
10290
|
return { snapshot: null, changed: false };
|
|
9648
10291
|
}
|
|
@@ -9654,7 +10297,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9654
10297
|
}
|
|
9655
10298
|
});
|
|
9656
10299
|
const changes = await this.readOnlyStep("get_changes", () => this.getChanges(this.git, baseCommit, treeHash));
|
|
9657
|
-
await
|
|
10300
|
+
await fs7.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9658
10301
|
});
|
|
9659
10302
|
const snapshot = {
|
|
9660
10303
|
treeHash,
|
|
@@ -9678,15 +10321,15 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9678
10321
|
if (filesToArchive.length === 0) {
|
|
9679
10322
|
return void 0;
|
|
9680
10323
|
}
|
|
9681
|
-
const existingFiles = filesToArchive.filter((f) => (0, import_node_fs3.existsSync)(
|
|
10324
|
+
const existingFiles = filesToArchive.filter((f) => (0, import_node_fs3.existsSync)(path8.join(baseDir, f)));
|
|
9682
10325
|
if (existingFiles.length === 0) {
|
|
9683
10326
|
return void 0;
|
|
9684
10327
|
}
|
|
9685
10328
|
await this.step({
|
|
9686
10329
|
name: "create_archive",
|
|
9687
10330
|
execute: async () => {
|
|
9688
|
-
const archiveDir =
|
|
9689
|
-
await
|
|
10331
|
+
const archiveDir = path8.dirname(archivePath);
|
|
10332
|
+
await fs7.mkdir(archiveDir, { recursive: true });
|
|
9690
10333
|
await tar.create({
|
|
9691
10334
|
gzip: true,
|
|
9692
10335
|
file: archivePath,
|
|
@@ -9694,7 +10337,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9694
10337
|
}, existingFiles);
|
|
9695
10338
|
},
|
|
9696
10339
|
rollback: async () => {
|
|
9697
|
-
await
|
|
10340
|
+
await fs7.rm(archivePath, { force: true }).catch(() => {
|
|
9698
10341
|
});
|
|
9699
10342
|
}
|
|
9700
10343
|
});
|
|
@@ -9793,9 +10436,9 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9793
10436
|
const filesToExtract = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
9794
10437
|
await this.readOnlyStep("backup_existing_files", async () => {
|
|
9795
10438
|
for (const filePath of filesToExtract) {
|
|
9796
|
-
const fullPath =
|
|
10439
|
+
const fullPath = path8.join(baseDir, filePath);
|
|
9797
10440
|
try {
|
|
9798
|
-
const content = await
|
|
10441
|
+
const content = await fs7.readFile(fullPath);
|
|
9799
10442
|
this.fileBackups.set(filePath, content);
|
|
9800
10443
|
} catch {
|
|
9801
10444
|
}
|
|
@@ -9812,16 +10455,16 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9812
10455
|
},
|
|
9813
10456
|
rollback: async () => {
|
|
9814
10457
|
for (const filePath of this.extractedFiles) {
|
|
9815
|
-
const fullPath =
|
|
10458
|
+
const fullPath = path8.join(baseDir, filePath);
|
|
9816
10459
|
const backup = this.fileBackups.get(filePath);
|
|
9817
10460
|
if (backup) {
|
|
9818
|
-
const dir =
|
|
9819
|
-
await
|
|
10461
|
+
const dir = path8.dirname(fullPath);
|
|
10462
|
+
await fs7.mkdir(dir, { recursive: true }).catch(() => {
|
|
9820
10463
|
});
|
|
9821
|
-
await
|
|
10464
|
+
await fs7.writeFile(fullPath, backup).catch(() => {
|
|
9822
10465
|
});
|
|
9823
10466
|
} else {
|
|
9824
|
-
await
|
|
10467
|
+
await fs7.rm(fullPath, { force: true }).catch(() => {
|
|
9825
10468
|
});
|
|
9826
10469
|
}
|
|
9827
10470
|
}
|
|
@@ -9829,10 +10472,10 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9829
10472
|
});
|
|
9830
10473
|
}
|
|
9831
10474
|
for (const change of changes.filter((c) => c.status === "D")) {
|
|
9832
|
-
const fullPath =
|
|
10475
|
+
const fullPath = path8.join(baseDir, change.path);
|
|
9833
10476
|
const backupContent = await this.readOnlyStep(`backup_${change.path}`, async () => {
|
|
9834
10477
|
try {
|
|
9835
|
-
return await
|
|
10478
|
+
return await fs7.readFile(fullPath);
|
|
9836
10479
|
} catch {
|
|
9837
10480
|
return null;
|
|
9838
10481
|
}
|
|
@@ -9840,15 +10483,15 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9840
10483
|
await this.step({
|
|
9841
10484
|
name: `delete_${change.path}`,
|
|
9842
10485
|
execute: async () => {
|
|
9843
|
-
await
|
|
10486
|
+
await fs7.rm(fullPath, { force: true });
|
|
9844
10487
|
this.log.debug(`Deleted file: ${change.path}`);
|
|
9845
10488
|
},
|
|
9846
10489
|
rollback: async () => {
|
|
9847
10490
|
if (backupContent) {
|
|
9848
|
-
const dir =
|
|
9849
|
-
await
|
|
10491
|
+
const dir = path8.dirname(fullPath);
|
|
10492
|
+
await fs7.mkdir(dir, { recursive: true }).catch(() => {
|
|
9850
10493
|
});
|
|
9851
|
-
await
|
|
10494
|
+
await fs7.writeFile(fullPath, backupContent).catch(() => {
|
|
9852
10495
|
});
|
|
9853
10496
|
}
|
|
9854
10497
|
}
|