claude-code-acp-ts 0.16.0 → 0.24.2
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/LICENSE +15 -46
- package/README.md +3 -3
- package/dist/acp-agent.d.ts +69 -12
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +970 -537
- package/dist/index.js +22 -16
- package/dist/lib.d.ts +2 -3
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -2
- package/dist/settings.d.ts +2 -18
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +43 -224
- package/dist/tools.d.ts +32 -20
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +191 -244
- package/dist/utils.d.ts +0 -14
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -63
- package/package.json +13 -14
package/dist/tools.js
CHANGED
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
killShell: ACP_TOOL_NAME_PREFIX + acpUnqualifiedToolNames.killShell,
|
|
18
|
-
bashOutput: ACP_TOOL_NAME_PREFIX + acpUnqualifiedToolNames.bashOutput,
|
|
19
|
-
};
|
|
20
|
-
export const EDIT_TOOL_NAMES = [acpToolNames.edit, acpToolNames.write];
|
|
21
|
-
export function toolInfoFromToolUse(toolUse) {
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Convert an absolute file path to a project-relative path for display.
|
|
4
|
+
* Returns the original path if it's outside the project directory or if no cwd is provided.
|
|
5
|
+
*/
|
|
6
|
+
export function toDisplayPath(filePath, cwd) {
|
|
7
|
+
if (!cwd)
|
|
8
|
+
return filePath;
|
|
9
|
+
const resolvedCwd = path.resolve(cwd);
|
|
10
|
+
const resolvedFile = path.resolve(filePath);
|
|
11
|
+
if (resolvedFile.startsWith(resolvedCwd + path.sep) || resolvedFile === resolvedCwd) {
|
|
12
|
+
return path.relative(resolvedCwd, resolvedFile);
|
|
13
|
+
}
|
|
14
|
+
return filePath;
|
|
15
|
+
}
|
|
16
|
+
export function toolInfoFromToolUse(toolUse, supportsTerminalOutput = false, cwd) {
|
|
22
17
|
const name = toolUse.name;
|
|
23
|
-
const input = toolUse.input;
|
|
24
18
|
switch (name) {
|
|
25
|
-
case "
|
|
19
|
+
case "Agent":
|
|
20
|
+
case "Task": {
|
|
21
|
+
const input = toolUse.input;
|
|
26
22
|
return {
|
|
27
23
|
title: input?.description ? input.description : "Task",
|
|
28
24
|
kind: "think",
|
|
29
|
-
content: input && input
|
|
25
|
+
content: input && "prompt" in input
|
|
30
26
|
? [
|
|
31
27
|
{
|
|
32
28
|
type: "content",
|
|
@@ -35,119 +31,50 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
35
31
|
]
|
|
36
32
|
: [],
|
|
37
33
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
kind: "read",
|
|
42
|
-
content: [],
|
|
43
|
-
locations: input?.notebook_path ? [{ path: input.notebook_path }] : [],
|
|
44
|
-
};
|
|
45
|
-
case "NotebookEdit":
|
|
46
|
-
return {
|
|
47
|
-
title: input?.notebook_path ? `Edit Notebook ${input.notebook_path}` : "Edit Notebook",
|
|
48
|
-
kind: "edit",
|
|
49
|
-
content: input && input.new_source
|
|
50
|
-
? [
|
|
51
|
-
{
|
|
52
|
-
type: "content",
|
|
53
|
-
content: { type: "text", text: input.new_source },
|
|
54
|
-
},
|
|
55
|
-
]
|
|
56
|
-
: [],
|
|
57
|
-
locations: input?.notebook_path ? [{ path: input.notebook_path }] : [],
|
|
58
|
-
};
|
|
59
|
-
case "Bash":
|
|
60
|
-
case acpToolNames.bash:
|
|
61
|
-
return {
|
|
62
|
-
title: input?.command ? "`" + input.command.replaceAll("`", "\\`") + "`" : "Terminal",
|
|
63
|
-
kind: "execute",
|
|
64
|
-
content: input && input.description
|
|
65
|
-
? [
|
|
66
|
-
{
|
|
67
|
-
type: "content",
|
|
68
|
-
content: { type: "text", text: input.description },
|
|
69
|
-
},
|
|
70
|
-
]
|
|
71
|
-
: [],
|
|
72
|
-
};
|
|
73
|
-
case "BashOutput":
|
|
74
|
-
case acpToolNames.bashOutput:
|
|
75
|
-
return {
|
|
76
|
-
title: "Tail Logs",
|
|
77
|
-
kind: "execute",
|
|
78
|
-
content: [],
|
|
79
|
-
};
|
|
80
|
-
case "KillShell":
|
|
81
|
-
case acpToolNames.killShell:
|
|
34
|
+
}
|
|
35
|
+
case "Bash": {
|
|
36
|
+
const input = toolUse.input;
|
|
82
37
|
return {
|
|
83
|
-
title:
|
|
38
|
+
title: input?.command ? input.command : "Terminal",
|
|
84
39
|
kind: "execute",
|
|
85
|
-
content:
|
|
40
|
+
content: supportsTerminalOutput
|
|
41
|
+
? [{ type: "terminal", terminalId: toolUse.id }]
|
|
42
|
+
: input && input.description
|
|
43
|
+
? [
|
|
44
|
+
{
|
|
45
|
+
type: "content",
|
|
46
|
+
content: { type: "text", text: input.description },
|
|
47
|
+
},
|
|
48
|
+
]
|
|
49
|
+
: [],
|
|
86
50
|
};
|
|
87
|
-
|
|
51
|
+
}
|
|
52
|
+
case "Read": {
|
|
53
|
+
const input = toolUse.input;
|
|
88
54
|
let limit = "";
|
|
89
|
-
if (input.limit) {
|
|
90
|
-
limit =
|
|
91
|
-
" (" + ((input.offset ?? 0) + 1) + " - " + ((input.offset ?? 0) + input.limit) + ")";
|
|
55
|
+
if (input.limit && input.limit > 0) {
|
|
56
|
+
limit = " (" + (input.offset ?? 1) + " - " + ((input.offset ?? 1) + input.limit - 1) + ")";
|
|
92
57
|
}
|
|
93
58
|
else if (input.offset) {
|
|
94
|
-
limit = " (from line " +
|
|
59
|
+
limit = " (from line " + input.offset + ")";
|
|
95
60
|
}
|
|
61
|
+
const displayPath = input.file_path ? toDisplayPath(input.file_path, cwd) : "File";
|
|
96
62
|
return {
|
|
97
|
-
title: "Read " +
|
|
63
|
+
title: "Read " + displayPath + limit,
|
|
98
64
|
kind: "read",
|
|
99
65
|
locations: input.file_path
|
|
100
66
|
? [
|
|
101
67
|
{
|
|
102
68
|
path: input.file_path,
|
|
103
|
-
line: input.offset ??
|
|
69
|
+
line: input.offset ?? 1,
|
|
104
70
|
},
|
|
105
71
|
]
|
|
106
72
|
: [],
|
|
107
73
|
content: [],
|
|
108
74
|
};
|
|
109
75
|
}
|
|
110
|
-
case "
|
|
111
|
-
|
|
112
|
-
title: "Read File",
|
|
113
|
-
kind: "read",
|
|
114
|
-
content: [],
|
|
115
|
-
locations: input.file_path
|
|
116
|
-
? [
|
|
117
|
-
{
|
|
118
|
-
path: input.file_path,
|
|
119
|
-
line: input.offset ?? 0,
|
|
120
|
-
},
|
|
121
|
-
]
|
|
122
|
-
: [],
|
|
123
|
-
};
|
|
124
|
-
case "LS":
|
|
125
|
-
return {
|
|
126
|
-
title: `List the ${input?.path ? "`" + input.path + "`" : "current"} directory's contents`,
|
|
127
|
-
kind: "search",
|
|
128
|
-
content: [],
|
|
129
|
-
locations: [],
|
|
130
|
-
};
|
|
131
|
-
case acpToolNames.edit:
|
|
132
|
-
case "Edit": {
|
|
133
|
-
const path = input?.file_path ?? input?.file_path;
|
|
134
|
-
return {
|
|
135
|
-
title: path ? `Edit \`${path}\`` : "Edit",
|
|
136
|
-
kind: "edit",
|
|
137
|
-
content: input && path
|
|
138
|
-
? [
|
|
139
|
-
{
|
|
140
|
-
type: "diff",
|
|
141
|
-
path,
|
|
142
|
-
oldText: input.old_string ?? null,
|
|
143
|
-
newText: input.new_string ?? "",
|
|
144
|
-
},
|
|
145
|
-
]
|
|
146
|
-
: [],
|
|
147
|
-
locations: path ? [{ path }] : undefined,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
case acpToolNames.write: {
|
|
76
|
+
case "Write": {
|
|
77
|
+
const input = toolUse.input;
|
|
151
78
|
let content = [];
|
|
152
79
|
if (input && input.file_path) {
|
|
153
80
|
content = [
|
|
@@ -167,30 +94,37 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
167
94
|
},
|
|
168
95
|
];
|
|
169
96
|
}
|
|
97
|
+
const displayPath = input?.file_path ? toDisplayPath(input.file_path, cwd) : undefined;
|
|
170
98
|
return {
|
|
171
|
-
title:
|
|
99
|
+
title: displayPath ? `Write ${displayPath}` : "Write",
|
|
172
100
|
kind: "edit",
|
|
173
101
|
content,
|
|
174
102
|
locations: input?.file_path ? [{ path: input.file_path }] : [],
|
|
175
103
|
};
|
|
176
104
|
}
|
|
177
|
-
case "
|
|
105
|
+
case "Edit": {
|
|
106
|
+
const input = toolUse.input;
|
|
107
|
+
let content = [];
|
|
108
|
+
if (input && input.file_path && (input.old_string || input.new_string)) {
|
|
109
|
+
content = [
|
|
110
|
+
{
|
|
111
|
+
type: "diff",
|
|
112
|
+
path: input.file_path,
|
|
113
|
+
oldText: input.old_string || null,
|
|
114
|
+
newText: input.new_string ?? "",
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
const displayPath = input?.file_path ? toDisplayPath(input.file_path, cwd) : undefined;
|
|
178
119
|
return {
|
|
179
|
-
title:
|
|
120
|
+
title: displayPath ? `Edit ${displayPath}` : "Edit",
|
|
180
121
|
kind: "edit",
|
|
181
|
-
content
|
|
182
|
-
? [
|
|
183
|
-
{
|
|
184
|
-
type: "diff",
|
|
185
|
-
path: input.file_path,
|
|
186
|
-
oldText: null,
|
|
187
|
-
newText: input.content,
|
|
188
|
-
},
|
|
189
|
-
]
|
|
190
|
-
: [],
|
|
122
|
+
content,
|
|
191
123
|
locations: input?.file_path ? [{ path: input.file_path }] : [],
|
|
192
124
|
};
|
|
125
|
+
}
|
|
193
126
|
case "Glob": {
|
|
127
|
+
const input = toolUse.input;
|
|
194
128
|
let label = "Find";
|
|
195
129
|
if (input.path) {
|
|
196
130
|
label += ` \`${input.path}\``;
|
|
@@ -206,6 +140,7 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
206
140
|
};
|
|
207
141
|
}
|
|
208
142
|
case "Grep": {
|
|
143
|
+
const input = toolUse.input;
|
|
209
144
|
let label = "grep";
|
|
210
145
|
if (input["-i"]) {
|
|
211
146
|
label += " -i";
|
|
@@ -224,13 +159,13 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
224
159
|
}
|
|
225
160
|
if (input.output_mode) {
|
|
226
161
|
switch (input.output_mode) {
|
|
227
|
-
case "
|
|
162
|
+
case "files_with_matches":
|
|
228
163
|
label += " -l";
|
|
229
164
|
break;
|
|
230
|
-
case "
|
|
165
|
+
case "count":
|
|
231
166
|
label += " -c";
|
|
232
167
|
break;
|
|
233
|
-
case "
|
|
168
|
+
case "content":
|
|
234
169
|
default:
|
|
235
170
|
break;
|
|
236
171
|
}
|
|
@@ -259,7 +194,8 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
259
194
|
content: [],
|
|
260
195
|
};
|
|
261
196
|
}
|
|
262
|
-
case "WebFetch":
|
|
197
|
+
case "WebFetch": {
|
|
198
|
+
const input = toolUse.input;
|
|
263
199
|
return {
|
|
264
200
|
title: input?.url ? `Fetch ${input.url}` : "Fetch",
|
|
265
201
|
kind: "fetch",
|
|
@@ -272,7 +208,9 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
272
208
|
]
|
|
273
209
|
: [],
|
|
274
210
|
};
|
|
211
|
+
}
|
|
275
212
|
case "WebSearch": {
|
|
213
|
+
const input = toolUse.input;
|
|
276
214
|
let label = `"${input.query}"`;
|
|
277
215
|
if (input.allowed_domains && input.allowed_domains.length > 0) {
|
|
278
216
|
label += ` (allowed: ${input.allowed_domains.join(", ")})`;
|
|
@@ -286,7 +224,8 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
286
224
|
content: [],
|
|
287
225
|
};
|
|
288
226
|
}
|
|
289
|
-
case "TodoWrite":
|
|
227
|
+
case "TodoWrite": {
|
|
228
|
+
const input = toolUse.input;
|
|
290
229
|
return {
|
|
291
230
|
title: Array.isArray(input?.todos)
|
|
292
231
|
? `Update TODOs: ${input.todos.map((todo) => todo.content).join(", ")}`
|
|
@@ -294,15 +233,19 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
294
233
|
kind: "think",
|
|
295
234
|
content: [],
|
|
296
235
|
};
|
|
297
|
-
|
|
236
|
+
}
|
|
237
|
+
case "ExitPlanMode": {
|
|
238
|
+
const planInput = toolUse.input;
|
|
298
239
|
return {
|
|
299
240
|
title: "Ready to code?",
|
|
300
241
|
kind: "switch_mode",
|
|
301
|
-
content:
|
|
302
|
-
? [{ type: "content", content: { type: "text", text:
|
|
242
|
+
content: planInput?.plan
|
|
243
|
+
? [{ type: "content", content: { type: "text", text: planInput.plan } }]
|
|
303
244
|
: [],
|
|
304
245
|
};
|
|
246
|
+
}
|
|
305
247
|
case "Other": {
|
|
248
|
+
const input = toolUse.input;
|
|
306
249
|
let output;
|
|
307
250
|
try {
|
|
308
251
|
output = JSON.stringify(input, null, 2);
|
|
@@ -332,7 +275,7 @@ export function toolInfoFromToolUse(toolUse) {
|
|
|
332
275
|
};
|
|
333
276
|
}
|
|
334
277
|
}
|
|
335
|
-
export function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
278
|
+
export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOutput = false) {
|
|
336
279
|
if ("is_error" in toolResult &&
|
|
337
280
|
toolResult.is_error &&
|
|
338
281
|
toolResult.content &&
|
|
@@ -342,7 +285,6 @@ export function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
|
342
285
|
}
|
|
343
286
|
switch (toolUse?.name) {
|
|
344
287
|
case "Read":
|
|
345
|
-
case acpToolNames.read:
|
|
346
288
|
if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {
|
|
347
289
|
return {
|
|
348
290
|
content: toolResult.content.map((content) => ({
|
|
@@ -350,9 +292,9 @@ export function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
|
350
292
|
content: content.type === "text"
|
|
351
293
|
? {
|
|
352
294
|
type: "text",
|
|
353
|
-
text: markdownEscape(content.text
|
|
295
|
+
text: markdownEscape(content.text),
|
|
354
296
|
}
|
|
355
|
-
: content,
|
|
297
|
+
: toAcpContentBlock(content, false),
|
|
356
298
|
})),
|
|
357
299
|
};
|
|
358
300
|
}
|
|
@@ -363,83 +305,82 @@ export function toolUpdateFromToolResult(toolResult, toolUse) {
|
|
|
363
305
|
type: "content",
|
|
364
306
|
content: {
|
|
365
307
|
type: "text",
|
|
366
|
-
text: markdownEscape(toolResult.content
|
|
308
|
+
text: markdownEscape(toolResult.content),
|
|
367
309
|
},
|
|
368
310
|
},
|
|
369
311
|
],
|
|
370
312
|
};
|
|
371
313
|
}
|
|
372
314
|
return {};
|
|
373
|
-
case
|
|
374
|
-
const
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
else if (line.startsWith("+")) {
|
|
391
|
-
newText.push(line.slice(1));
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
oldText.push(line.slice(1));
|
|
395
|
-
newText.push(line.slice(1));
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
if (oldText.length > 0 || newText.length > 0) {
|
|
399
|
-
locations.push({ path: newFileName || oldFileName, line: newStart });
|
|
400
|
-
content.push({
|
|
401
|
-
type: "diff",
|
|
402
|
-
path: newFileName || oldFileName,
|
|
403
|
-
oldText: oldText.join("\n") || null,
|
|
404
|
-
newText: newText.join("\n"),
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
315
|
+
case "Bash": {
|
|
316
|
+
const result = toolResult.content;
|
|
317
|
+
const terminalId = "tool_use_id" in toolResult ? String(toolResult.tool_use_id) : "";
|
|
318
|
+
const isError = "is_error" in toolResult && toolResult.is_error;
|
|
319
|
+
// Extract output and exit code from either format:
|
|
320
|
+
// 1. BetaBashCodeExecutionResultBlock: { type: "bash_code_execution_result", stdout, stderr, return_code }
|
|
321
|
+
// 2. Plain string content from a regular tool_result
|
|
322
|
+
// 3. Array content (e.g. [{ type: "text", text: "..." }])
|
|
323
|
+
let output = "";
|
|
324
|
+
let exitCode = isError ? 1 : 0;
|
|
325
|
+
if (result &&
|
|
326
|
+
typeof result === "object" &&
|
|
327
|
+
"type" in result &&
|
|
328
|
+
result.type === "bash_code_execution_result") {
|
|
329
|
+
const bashResult = result;
|
|
330
|
+
output = [bashResult.stdout, bashResult.stderr].filter(Boolean).join("\n");
|
|
331
|
+
exitCode = bashResult.return_code;
|
|
409
332
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
result.content = content;
|
|
333
|
+
else if (typeof result === "string") {
|
|
334
|
+
output = result;
|
|
413
335
|
}
|
|
414
|
-
if (
|
|
415
|
-
result.
|
|
336
|
+
else if (Array.isArray(result) &&
|
|
337
|
+
result.length > 0 &&
|
|
338
|
+
"text" in result[0] &&
|
|
339
|
+
typeof result[0].text === "string") {
|
|
340
|
+
output = result.map((c) => c.text).join("\n");
|
|
341
|
+
}
|
|
342
|
+
if (supportsTerminalOutput) {
|
|
343
|
+
return {
|
|
344
|
+
content: [{ type: "terminal", terminalId }],
|
|
345
|
+
_meta: {
|
|
346
|
+
terminal_info: {
|
|
347
|
+
terminal_id: terminalId,
|
|
348
|
+
},
|
|
349
|
+
terminal_output: {
|
|
350
|
+
terminal_id: terminalId,
|
|
351
|
+
data: output,
|
|
352
|
+
},
|
|
353
|
+
terminal_exit: {
|
|
354
|
+
terminal_id: terminalId,
|
|
355
|
+
exit_code: exitCode,
|
|
356
|
+
signal: null,
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
};
|
|
416
360
|
}
|
|
417
|
-
|
|
361
|
+
// Fallback: format output as a code block without terminal _meta
|
|
362
|
+
if (output.trim()) {
|
|
363
|
+
return {
|
|
364
|
+
content: [
|
|
365
|
+
{
|
|
366
|
+
type: "content",
|
|
367
|
+
content: {
|
|
368
|
+
type: "text",
|
|
369
|
+
text: `\`\`\`console\n${output.trimEnd()}\n\`\`\``,
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
return {};
|
|
418
376
|
}
|
|
419
|
-
case
|
|
420
|
-
case "edit":
|
|
421
|
-
case "Edit":
|
|
422
|
-
case acpToolNames.write:
|
|
377
|
+
case "Edit": // Edit is handled in hooks
|
|
423
378
|
case "Write": {
|
|
424
379
|
return {};
|
|
425
380
|
}
|
|
426
381
|
case "ExitPlanMode": {
|
|
427
382
|
return { title: "Exited Plan Mode" };
|
|
428
383
|
}
|
|
429
|
-
case "Task":
|
|
430
|
-
case "NotebookEdit":
|
|
431
|
-
case "NotebookRead":
|
|
432
|
-
case "TodoWrite":
|
|
433
|
-
case "exit_plan_mode":
|
|
434
|
-
case "Bash":
|
|
435
|
-
case "BashOutput":
|
|
436
|
-
case "KillBash":
|
|
437
|
-
case "LS":
|
|
438
|
-
case "Glob":
|
|
439
|
-
case "Grep":
|
|
440
|
-
case "WebFetch":
|
|
441
|
-
case "WebSearch":
|
|
442
|
-
case "Other":
|
|
443
384
|
default: {
|
|
444
385
|
return toAcpContentUpdate(toolResult.content, "is_error" in toolResult ? toolResult.is_error : false);
|
|
445
386
|
}
|
|
@@ -551,6 +492,52 @@ export function markdownEscape(text) {
|
|
|
551
492
|
}
|
|
552
493
|
return escape + "\n" + text + (text.endsWith("\n") ? "" : "\n") + escape;
|
|
553
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* Builds diff ToolUpdate content from the structured Edit toolResponse provided
|
|
497
|
+
* by the PostToolUse hook. Unlike parsing the plain unified diff string, this uses
|
|
498
|
+
* the pre-parsed structuredPatch which supports multiple replacement sites (replaceAll)
|
|
499
|
+
* and always includes context lines for better readability.
|
|
500
|
+
*/
|
|
501
|
+
export function toolUpdateFromEditToolResponse(toolResponse) {
|
|
502
|
+
if (!toolResponse || typeof toolResponse !== "object")
|
|
503
|
+
return {};
|
|
504
|
+
const response = toolResponse;
|
|
505
|
+
if (!response.filePath || !Array.isArray(response.structuredPatch))
|
|
506
|
+
return {};
|
|
507
|
+
const content = [];
|
|
508
|
+
const locations = [];
|
|
509
|
+
for (const { lines, newStart } of response.structuredPatch) {
|
|
510
|
+
const oldText = [];
|
|
511
|
+
const newText = [];
|
|
512
|
+
for (const line of lines) {
|
|
513
|
+
if (line.startsWith("-")) {
|
|
514
|
+
oldText.push(line.slice(1));
|
|
515
|
+
}
|
|
516
|
+
else if (line.startsWith("+")) {
|
|
517
|
+
newText.push(line.slice(1));
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
oldText.push(line.slice(1));
|
|
521
|
+
newText.push(line.slice(1));
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (oldText.length > 0 || newText.length > 0) {
|
|
525
|
+
locations.push({ path: response.filePath, line: newStart });
|
|
526
|
+
content.push({
|
|
527
|
+
type: "diff",
|
|
528
|
+
path: response.filePath,
|
|
529
|
+
oldText: oldText.join("\n") || null,
|
|
530
|
+
newText: newText.join("\n"),
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const result = {};
|
|
535
|
+
if (content.length > 0)
|
|
536
|
+
result.content = content;
|
|
537
|
+
if (locations.length > 0)
|
|
538
|
+
result.locations = locations;
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
554
541
|
/* A global variable to store callbacks that should be executed when receiving hooks from Claude Code */
|
|
555
542
|
const toolUseCallbacks = {};
|
|
556
543
|
/* Setup callbacks that will be called when receiving hooks from Claude Code */
|
|
@@ -580,43 +567,3 @@ export const createPostToolUseHook = (logger = console, options) => async (input
|
|
|
580
567
|
}
|
|
581
568
|
return { continue: true };
|
|
582
569
|
};
|
|
583
|
-
/**
|
|
584
|
-
* Creates a PreToolUse hook that checks permissions using the SettingsManager.
|
|
585
|
-
* This runs before the SDK's built-in permission rules, allowing us to enforce
|
|
586
|
-
* our own permission settings for ACP-prefixed tools.
|
|
587
|
-
*/
|
|
588
|
-
export const createPreToolUseHook = (settingsManager, logger = console) => async (input, _toolUseID) => {
|
|
589
|
-
if (input.hook_event_name !== "PreToolUse") {
|
|
590
|
-
return { continue: true };
|
|
591
|
-
}
|
|
592
|
-
const toolName = input.tool_name;
|
|
593
|
-
const toolInput = input.tool_input;
|
|
594
|
-
const permissionCheck = settingsManager.checkPermission(toolName, toolInput);
|
|
595
|
-
if (permissionCheck.decision !== "ask") {
|
|
596
|
-
logger.log(`[PreToolUseHook] Tool: ${toolName}, Decision: ${permissionCheck.decision}, Rule: ${permissionCheck.rule}`);
|
|
597
|
-
}
|
|
598
|
-
switch (permissionCheck.decision) {
|
|
599
|
-
case "allow":
|
|
600
|
-
return {
|
|
601
|
-
continue: true,
|
|
602
|
-
hookSpecificOutput: {
|
|
603
|
-
hookEventName: "PreToolUse",
|
|
604
|
-
permissionDecision: "allow",
|
|
605
|
-
permissionDecisionReason: `Allowed by settings rule: ${permissionCheck.rule}`,
|
|
606
|
-
},
|
|
607
|
-
};
|
|
608
|
-
case "deny":
|
|
609
|
-
return {
|
|
610
|
-
continue: true,
|
|
611
|
-
hookSpecificOutput: {
|
|
612
|
-
hookEventName: "PreToolUse",
|
|
613
|
-
permissionDecision: "deny",
|
|
614
|
-
permissionDecisionReason: `Denied by settings rule: ${permissionCheck.rule}`,
|
|
615
|
-
},
|
|
616
|
-
};
|
|
617
|
-
case "ask":
|
|
618
|
-
default:
|
|
619
|
-
// Let the normal permission flow continue
|
|
620
|
-
return { continue: true };
|
|
621
|
-
}
|
|
622
|
-
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -16,18 +16,4 @@ export declare function unreachable(value: never, logger?: Logger): void;
|
|
|
16
16
|
export declare function sleep(time: number): Promise<void>;
|
|
17
17
|
export declare function loadManagedSettings(): ClaudeCodeSettings | null;
|
|
18
18
|
export declare function applyEnvironmentSettings(settings: ClaudeCodeSettings): void;
|
|
19
|
-
export interface ExtractLinesResult {
|
|
20
|
-
content: string;
|
|
21
|
-
wasLimited: boolean;
|
|
22
|
-
linesRead: number;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Extracts lines from file content with byte limit enforcement.
|
|
26
|
-
*
|
|
27
|
-
* @param fullContent - The complete file content
|
|
28
|
-
* @param maxContentLength - Maximum number of UTF-16 Code Units to return
|
|
29
|
-
* @returns Object containing extracted content and metadata
|
|
30
|
-
*/
|
|
31
|
-
export declare function extractLinesWithByteLimit(fullContent: string, maxContentLength: number): ExtractLinesResult;
|
|
32
|
-
export declare function encodeProjectPath(cwd: string): string;
|
|
33
19
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAA0B,MAAM,eAAe,CAAC;AAG3E,qBAAa,QAAQ,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,IAAI,EAAE,CAAC;IASZ,GAAG;IAQH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CAgB3C;AAGD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAclF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAUlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAgB,QAQjE;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,GAAG,IAAI,CAM/D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAM3E
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAA0B,MAAM,eAAe,CAAC;AAG3E,qBAAa,QAAQ,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,IAAI,EAAE,CAAC;IASZ,GAAG;IAQH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CAgB3C;AAGD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAclF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAUlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAgB,QAQjE;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,GAAG,IAAI,CAM/D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAM3E"}
|