@sudocode-ai/claude-code-acp 0.12.9 → 0.13.1
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/README.md +3 -9
- package/dist/acp-agent.d.ts +194 -0
- package/dist/acp-agent.d.ts.map +1 -0
- package/dist/acp-agent.js +371 -29
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib.d.ts +7 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/mcp-server.d.ts +21 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +214 -158
- package/dist/settings.d.ts +123 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/tools.d.ts +50 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +62 -39
- package/dist/utils.d.ts +32 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +22 -12
- package/dist/tests/acp-agent.test.js +0 -753
- package/dist/tests/extract-lines.test.js +0 -79
- package/dist/tests/fork-session.test.js +0 -83
- package/dist/tests/replace-and-calculate-location.test.js +0 -266
- package/dist/tests/settings.test.js +0 -462
package/dist/mcp-server.js
CHANGED
|
@@ -64,6 +64,20 @@ export const SYSTEM_REMINDER = `
|
|
|
64
64
|
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.
|
|
65
65
|
</system-reminder>`;
|
|
66
66
|
const defaults = { maxFileSize: 50000, linesToRead: 2000 };
|
|
67
|
+
function formatErrorMessage(error) {
|
|
68
|
+
if (error instanceof Error) {
|
|
69
|
+
return error.message;
|
|
70
|
+
}
|
|
71
|
+
if (typeof error === "string") {
|
|
72
|
+
return error;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return JSON.stringify(error);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return String(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
67
81
|
const unqualifiedToolNames = {
|
|
68
82
|
read: "Read",
|
|
69
83
|
edit: "Edit",
|
|
@@ -186,8 +200,8 @@ Usage:
|
|
|
186
200
|
if (result.wasLimited) {
|
|
187
201
|
readInfo += `Read ${result.linesRead} lines (hit 50KB limit). `;
|
|
188
202
|
}
|
|
189
|
-
else {
|
|
190
|
-
readInfo += `Read lines ${input.offset}-${result.linesRead}
|
|
203
|
+
else if (input.offset && input.offset > 1) {
|
|
204
|
+
readInfo += `Read lines ${input.offset}-${input.offset + result.linesRead}.`;
|
|
191
205
|
}
|
|
192
206
|
if (result.wasLimited) {
|
|
193
207
|
readInfo += `Continue with offset=${result.linesRead}.`;
|
|
@@ -205,10 +219,11 @@ Usage:
|
|
|
205
219
|
}
|
|
206
220
|
catch (error) {
|
|
207
221
|
return {
|
|
222
|
+
isError: true,
|
|
208
223
|
content: [
|
|
209
224
|
{
|
|
210
225
|
type: "text",
|
|
211
|
-
text: "Reading file failed: " + error
|
|
226
|
+
text: "Reading file failed: " + formatErrorMessage(error),
|
|
212
227
|
},
|
|
213
228
|
],
|
|
214
229
|
};
|
|
@@ -262,10 +277,11 @@ Usage:
|
|
|
262
277
|
}
|
|
263
278
|
catch (error) {
|
|
264
279
|
return {
|
|
280
|
+
isError: true,
|
|
265
281
|
content: [
|
|
266
282
|
{
|
|
267
283
|
type: "text",
|
|
268
|
-
text: "Writing file failed: " + error
|
|
284
|
+
text: "Writing file failed: " + formatErrorMessage(error),
|
|
269
285
|
},
|
|
270
286
|
],
|
|
271
287
|
};
|
|
@@ -343,10 +359,11 @@ Usage:
|
|
|
343
359
|
}
|
|
344
360
|
catch (error) {
|
|
345
361
|
return {
|
|
362
|
+
isError: true,
|
|
346
363
|
content: [
|
|
347
364
|
{
|
|
348
365
|
type: "text",
|
|
349
|
-
text: "Editing file failed: " + (error
|
|
366
|
+
text: "Editing file failed: " + formatErrorMessage(error),
|
|
350
367
|
},
|
|
351
368
|
],
|
|
352
369
|
};
|
|
@@ -381,114 +398,127 @@ Output: Create directory 'foo'`),
|
|
|
381
398
|
.describe(`Set to true to run this command in the background. The tool returns an \`id\` that can be used with the \`${acpToolNames.bashOutput}\` tool to retrieve the current output, or the \`${acpToolNames.killShell}\` tool to stop it early.`),
|
|
382
399
|
},
|
|
383
400
|
}, async (input, extra) => {
|
|
384
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
385
401
|
try {
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (typeof toolCallId !== "string") {
|
|
399
|
-
throw new Error("No tool call ID found");
|
|
400
|
-
}
|
|
401
|
-
if (!agent.clientCapabilities?.terminal || !agent.client.createTerminal) {
|
|
402
|
-
throw new Error("unreachable");
|
|
403
|
-
}
|
|
404
|
-
const handle = await agent.client.createTerminal({
|
|
405
|
-
command: input.command,
|
|
406
|
-
env: [{ name: "CLAUDECODE", value: "1" }],
|
|
407
|
-
sessionId,
|
|
408
|
-
outputByteLimit: 32000,
|
|
409
|
-
});
|
|
410
|
-
await agent.client.sessionUpdate({
|
|
411
|
-
sessionId,
|
|
412
|
-
update: {
|
|
413
|
-
sessionUpdate: "tool_call_update",
|
|
414
|
-
toolCallId,
|
|
415
|
-
status: "in_progress",
|
|
416
|
-
title: input.description,
|
|
417
|
-
content: [{ type: "terminal", terminalId: handle.id }],
|
|
418
|
-
},
|
|
419
|
-
});
|
|
420
|
-
const abortPromise = new Promise((resolve) => {
|
|
421
|
-
if (extra.signal.aborted) {
|
|
422
|
-
resolve(null);
|
|
402
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
403
|
+
try {
|
|
404
|
+
const session = agent.sessions[sessionId];
|
|
405
|
+
if (!session) {
|
|
406
|
+
return {
|
|
407
|
+
content: [
|
|
408
|
+
{
|
|
409
|
+
type: "text",
|
|
410
|
+
text: "The user has left the building",
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
};
|
|
423
414
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
});
|
|
415
|
+
const toolCallId = extra._meta?.["claudecode/toolUseId"];
|
|
416
|
+
if (typeof toolCallId !== "string") {
|
|
417
|
+
throw new Error("No tool call ID found");
|
|
428
418
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
419
|
+
if (!agent.clientCapabilities?.terminal || !agent.client.createTerminal) {
|
|
420
|
+
throw new Error("unreachable");
|
|
421
|
+
}
|
|
422
|
+
const handle = await agent.client.createTerminal({
|
|
423
|
+
command: input.command,
|
|
424
|
+
env: [{ name: "CLAUDECODE", value: "1" }],
|
|
425
|
+
sessionId,
|
|
426
|
+
outputByteLimit: 32000,
|
|
427
|
+
});
|
|
428
|
+
await agent.client.sessionUpdate({
|
|
429
|
+
sessionId,
|
|
430
|
+
update: {
|
|
431
|
+
sessionUpdate: "tool_call_update",
|
|
432
|
+
toolCallId,
|
|
433
|
+
status: "in_progress",
|
|
434
|
+
title: input.description,
|
|
435
|
+
content: [{ type: "terminal", terminalId: handle.id }],
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
const abortPromise = new Promise((resolve) => {
|
|
439
|
+
if (extra.signal.aborted) {
|
|
440
|
+
resolve(null);
|
|
436
441
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
agent.backgroundTerminals[handle.id] = {
|
|
442
|
-
handle,
|
|
443
|
-
lastOutput: null,
|
|
444
|
-
status: "started",
|
|
445
|
-
};
|
|
446
|
-
statusPromise.then(async ({ status, exitStatus }) => {
|
|
447
|
-
const bgTerm = agent.backgroundTerminals[handle.id];
|
|
448
|
-
if (bgTerm.status !== "started") {
|
|
449
|
-
return;
|
|
442
|
+
else {
|
|
443
|
+
extra.signal.addEventListener("abort", () => {
|
|
444
|
+
resolve(null);
|
|
445
|
+
});
|
|
450
446
|
}
|
|
451
|
-
|
|
447
|
+
});
|
|
448
|
+
const statusPromise = Promise.race([
|
|
449
|
+
handle.waitForExit().then((exitStatus) => ({ status: "exited", exitStatus })),
|
|
450
|
+
abortPromise.then(() => ({ status: "aborted", exitStatus: null })),
|
|
451
|
+
sleep(input.timeout ?? 2 * 60 * 1000).then(async () => {
|
|
452
|
+
if (agent.backgroundTerminals[handle.id]?.status === "started") {
|
|
453
|
+
await handle.kill();
|
|
454
|
+
}
|
|
455
|
+
return { status: "timedOut", exitStatus: null };
|
|
456
|
+
}),
|
|
457
|
+
]);
|
|
458
|
+
if (input.run_in_background) {
|
|
452
459
|
agent.backgroundTerminals[handle.id] = {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
|
|
457
|
-
exitStatus: exitStatus ?? currentOutput.exitStatus,
|
|
458
|
-
},
|
|
460
|
+
handle,
|
|
461
|
+
lastOutput: null,
|
|
462
|
+
status: "started",
|
|
459
463
|
};
|
|
460
|
-
|
|
461
|
-
|
|
464
|
+
statusPromise.then(async ({ status, exitStatus }) => {
|
|
465
|
+
const bgTerm = agent.backgroundTerminals[handle.id];
|
|
466
|
+
if (bgTerm.status !== "started") {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
const currentOutput = await handle.currentOutput();
|
|
470
|
+
agent.backgroundTerminals[handle.id] = {
|
|
471
|
+
status,
|
|
472
|
+
pendingOutput: {
|
|
473
|
+
...currentOutput,
|
|
474
|
+
output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
|
|
475
|
+
exitStatus: exitStatus ?? currentOutput.exitStatus,
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
return handle.release();
|
|
479
|
+
});
|
|
480
|
+
return {
|
|
481
|
+
content: [
|
|
482
|
+
{
|
|
483
|
+
type: "text",
|
|
484
|
+
text: `Command started in background with id: ${handle.id}`,
|
|
485
|
+
},
|
|
486
|
+
],
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const terminal = __addDisposableResource(env_1, handle, true);
|
|
490
|
+
const { status } = await statusPromise;
|
|
491
|
+
if (status === "aborted") {
|
|
492
|
+
return {
|
|
493
|
+
content: [{ type: "text", text: "Tool cancelled by user" }],
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const output = await terminal.currentOutput();
|
|
462
497
|
return {
|
|
463
|
-
content: [
|
|
464
|
-
{
|
|
465
|
-
type: "text",
|
|
466
|
-
text: `Command started in background with id: ${handle.id}`,
|
|
467
|
-
},
|
|
468
|
-
],
|
|
498
|
+
content: [{ type: "text", text: toolCommandOutput(status, output) }],
|
|
469
499
|
};
|
|
470
500
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
return {
|
|
475
|
-
content: [{ type: "text", text: "Tool cancelled by user" }],
|
|
476
|
-
};
|
|
501
|
+
catch (e_1) {
|
|
502
|
+
env_1.error = e_1;
|
|
503
|
+
env_1.hasError = true;
|
|
477
504
|
}
|
|
478
|
-
|
|
505
|
+
finally {
|
|
506
|
+
const result_1 = __disposeResources(env_1);
|
|
507
|
+
if (result_1)
|
|
508
|
+
await result_1;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
catch (error) {
|
|
479
512
|
return {
|
|
480
|
-
|
|
513
|
+
isError: true,
|
|
514
|
+
content: [
|
|
515
|
+
{
|
|
516
|
+
type: "text",
|
|
517
|
+
text: "Running bash command failed: " + formatErrorMessage(error),
|
|
518
|
+
},
|
|
519
|
+
],
|
|
481
520
|
};
|
|
482
521
|
}
|
|
483
|
-
catch (e_1) {
|
|
484
|
-
env_1.error = e_1;
|
|
485
|
-
env_1.hasError = true;
|
|
486
|
-
}
|
|
487
|
-
finally {
|
|
488
|
-
const result_1 = __disposeResources(env_1);
|
|
489
|
-
if (result_1)
|
|
490
|
-
await result_1;
|
|
491
|
-
}
|
|
492
522
|
});
|
|
493
523
|
server.registerTool(unqualifiedToolNames.bashOutput, {
|
|
494
524
|
title: unqualifiedToolNames.bashOutput,
|
|
@@ -505,32 +535,45 @@ In sessions with ${acpToolNames.bashOutput} always use it for output from Bash c
|
|
|
505
535
|
.describe(`The id of the background bash command as returned by \`${acpToolNames.bash}\``),
|
|
506
536
|
},
|
|
507
537
|
}, async (input) => {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
538
|
+
try {
|
|
539
|
+
const bgTerm = agent.backgroundTerminals[input.bash_id];
|
|
540
|
+
if (!bgTerm) {
|
|
541
|
+
throw new Error(`Unknown shell ${input.bash_id}`);
|
|
542
|
+
}
|
|
543
|
+
if (bgTerm.status === "started") {
|
|
544
|
+
const newOutput = await bgTerm.handle.currentOutput();
|
|
545
|
+
const strippedOutput = stripCommonPrefix(bgTerm.lastOutput?.output ?? "", newOutput.output);
|
|
546
|
+
bgTerm.lastOutput = newOutput;
|
|
547
|
+
return {
|
|
548
|
+
content: [
|
|
549
|
+
{
|
|
550
|
+
type: "text",
|
|
551
|
+
text: toolCommandOutput(bgTerm.status, {
|
|
552
|
+
...newOutput,
|
|
553
|
+
output: strippedOutput,
|
|
554
|
+
}),
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
return {
|
|
561
|
+
content: [
|
|
562
|
+
{
|
|
563
|
+
type: "text",
|
|
564
|
+
text: toolCommandOutput(bgTerm.status, bgTerm.pendingOutput),
|
|
565
|
+
},
|
|
566
|
+
],
|
|
567
|
+
};
|
|
568
|
+
}
|
|
527
569
|
}
|
|
528
|
-
|
|
570
|
+
catch (error) {
|
|
529
571
|
return {
|
|
572
|
+
isError: true,
|
|
530
573
|
content: [
|
|
531
574
|
{
|
|
532
575
|
type: "text",
|
|
533
|
-
text:
|
|
576
|
+
text: "Retrieving bash output failed: " + formatErrorMessage(error),
|
|
534
577
|
},
|
|
535
578
|
],
|
|
536
579
|
};
|
|
@@ -550,47 +593,60 @@ In sessions with ${acpToolNames.killShell} always use it instead of KillShell.`,
|
|
|
550
593
|
.describe(`The id of the background bash command as returned by \`${acpToolNames.bash}\``),
|
|
551
594
|
},
|
|
552
595
|
}, async (input) => {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
switch (bgTerm.status) {
|
|
558
|
-
case "started": {
|
|
559
|
-
await bgTerm.handle.kill();
|
|
560
|
-
const currentOutput = await bgTerm.handle.currentOutput();
|
|
561
|
-
agent.backgroundTerminals[bgTerm.handle.id] = {
|
|
562
|
-
status: "killed",
|
|
563
|
-
pendingOutput: {
|
|
564
|
-
...currentOutput,
|
|
565
|
-
output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
|
|
566
|
-
},
|
|
567
|
-
};
|
|
568
|
-
await bgTerm.handle.release();
|
|
569
|
-
return {
|
|
570
|
-
content: [{ type: "text", text: "Command killed successfully." }],
|
|
571
|
-
};
|
|
596
|
+
try {
|
|
597
|
+
const bgTerm = agent.backgroundTerminals[input.shell_id];
|
|
598
|
+
if (!bgTerm) {
|
|
599
|
+
throw new Error(`Unknown shell ${input.shell_id}`);
|
|
572
600
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
601
|
+
switch (bgTerm.status) {
|
|
602
|
+
case "started": {
|
|
603
|
+
await bgTerm.handle.kill();
|
|
604
|
+
const currentOutput = await bgTerm.handle.currentOutput();
|
|
605
|
+
agent.backgroundTerminals[bgTerm.handle.id] = {
|
|
606
|
+
status: "killed",
|
|
607
|
+
pendingOutput: {
|
|
608
|
+
...currentOutput,
|
|
609
|
+
output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
await bgTerm.handle.release();
|
|
613
|
+
return {
|
|
614
|
+
content: [{ type: "text", text: "Command killed successfully." }],
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
case "aborted":
|
|
618
|
+
return {
|
|
619
|
+
content: [{ type: "text", text: "Command aborted by user." }],
|
|
620
|
+
};
|
|
621
|
+
case "exited":
|
|
622
|
+
return {
|
|
623
|
+
content: [{ type: "text", text: "Command had already exited." }],
|
|
624
|
+
};
|
|
625
|
+
case "killed":
|
|
626
|
+
return {
|
|
627
|
+
content: [{ type: "text", text: "Command was already killed." }],
|
|
628
|
+
};
|
|
629
|
+
case "timedOut":
|
|
630
|
+
return {
|
|
631
|
+
content: [{ type: "text", text: "Command killed by timeout." }],
|
|
632
|
+
};
|
|
633
|
+
default: {
|
|
634
|
+
unreachable(bgTerm);
|
|
635
|
+
throw new Error("Unexpected background terminal status");
|
|
636
|
+
}
|
|
592
637
|
}
|
|
593
638
|
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
return {
|
|
641
|
+
isError: true,
|
|
642
|
+
content: [
|
|
643
|
+
{
|
|
644
|
+
type: "text",
|
|
645
|
+
text: "Killing shell failed: " + formatErrorMessage(error),
|
|
646
|
+
},
|
|
647
|
+
],
|
|
648
|
+
};
|
|
649
|
+
}
|
|
594
650
|
});
|
|
595
651
|
}
|
|
596
652
|
return server;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission rule format examples:
|
|
3
|
+
* - "Read" - matches all Read tool calls
|
|
4
|
+
* - "Read(./.env)" - matches specific path
|
|
5
|
+
* - "Read(./.env.*)" - glob pattern
|
|
6
|
+
* - "Read(./secrets/**)" - recursive glob
|
|
7
|
+
* - "Bash(npm run lint)" - exact command prefix
|
|
8
|
+
* - "Bash(npm run:*)" - command prefix with wildcard
|
|
9
|
+
*
|
|
10
|
+
* Docs: https://code.claude.com/docs/en/iam#tool-specific-permission-rules
|
|
11
|
+
*/
|
|
12
|
+
export interface PermissionSettings {
|
|
13
|
+
allow?: string[];
|
|
14
|
+
deny?: string[];
|
|
15
|
+
ask?: string[];
|
|
16
|
+
additionalDirectories?: string[];
|
|
17
|
+
defaultMode?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ClaudeCodeSettings {
|
|
20
|
+
permissions?: PermissionSettings;
|
|
21
|
+
env?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export type PermissionDecision = "allow" | "deny" | "ask";
|
|
24
|
+
export interface PermissionCheckResult {
|
|
25
|
+
decision: PermissionDecision;
|
|
26
|
+
rule?: string;
|
|
27
|
+
source?: "allow" | "deny" | "ask";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Gets the enterprise settings path based on the current platform
|
|
31
|
+
*/
|
|
32
|
+
export declare function getManagedSettingsPath(): string;
|
|
33
|
+
export interface SettingsManagerOptions {
|
|
34
|
+
onChange?: () => void;
|
|
35
|
+
logger?: {
|
|
36
|
+
log: (...args: any[]) => void;
|
|
37
|
+
error: (...args: any[]) => void;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Manages Claude Code settings from multiple sources with proper precedence.
|
|
42
|
+
*
|
|
43
|
+
* Settings are loaded from (in order of increasing precedence):
|
|
44
|
+
* 1. User settings (~/.claude/settings.json)
|
|
45
|
+
* 2. Project settings (<cwd>/.claude/settings.json)
|
|
46
|
+
* 3. Local project settings (<cwd>/.claude/settings.local.json)
|
|
47
|
+
* 4. Enterprise managed settings (platform-specific path)
|
|
48
|
+
*
|
|
49
|
+
* The manager watches all settings files for changes and automatically reloads.
|
|
50
|
+
*/
|
|
51
|
+
export declare class SettingsManager {
|
|
52
|
+
private cwd;
|
|
53
|
+
private userSettings;
|
|
54
|
+
private projectSettings;
|
|
55
|
+
private localSettings;
|
|
56
|
+
private enterpriseSettings;
|
|
57
|
+
private mergedSettings;
|
|
58
|
+
private watchers;
|
|
59
|
+
private onChange?;
|
|
60
|
+
private logger;
|
|
61
|
+
private initialized;
|
|
62
|
+
private debounceTimer;
|
|
63
|
+
constructor(cwd: string, options?: SettingsManagerOptions);
|
|
64
|
+
/**
|
|
65
|
+
* Initialize the settings manager by loading all settings and setting up file watchers
|
|
66
|
+
*/
|
|
67
|
+
initialize(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Returns the path to the user settings file
|
|
70
|
+
*/
|
|
71
|
+
private getUserSettingsPath;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the path to the project settings file
|
|
74
|
+
*/
|
|
75
|
+
private getProjectSettingsPath;
|
|
76
|
+
/**
|
|
77
|
+
* Returns the path to the local project settings file
|
|
78
|
+
*/
|
|
79
|
+
private getLocalSettingsPath;
|
|
80
|
+
/**
|
|
81
|
+
* Loads settings from all sources
|
|
82
|
+
*/
|
|
83
|
+
private loadAllSettings;
|
|
84
|
+
/**
|
|
85
|
+
* Merges all settings sources with proper precedence.
|
|
86
|
+
* For permissions, rules from all sources are combined.
|
|
87
|
+
* Deny rules always take precedence during permission checks.
|
|
88
|
+
*/
|
|
89
|
+
private mergeSettings;
|
|
90
|
+
/**
|
|
91
|
+
* Sets up file watchers for all settings files
|
|
92
|
+
*/
|
|
93
|
+
private setupWatchers;
|
|
94
|
+
/**
|
|
95
|
+
* Handles settings file changes with debouncing to avoid rapid reloads
|
|
96
|
+
*/
|
|
97
|
+
private handleSettingsChange;
|
|
98
|
+
/**
|
|
99
|
+
* Checks if a tool invocation is allowed based on the loaded settings.
|
|
100
|
+
*
|
|
101
|
+
* @param toolName - The tool name (can be ACP-prefixed like mcp__acp__Read or plain like Read)
|
|
102
|
+
* @param toolInput - The tool input object
|
|
103
|
+
* @returns The permission decision and matching rule info
|
|
104
|
+
*/
|
|
105
|
+
checkPermission(toolName: string, toolInput: unknown): PermissionCheckResult;
|
|
106
|
+
/**
|
|
107
|
+
* Returns the current merged settings
|
|
108
|
+
*/
|
|
109
|
+
getSettings(): ClaudeCodeSettings;
|
|
110
|
+
/**
|
|
111
|
+
* Returns the current working directory
|
|
112
|
+
*/
|
|
113
|
+
getCwd(): string;
|
|
114
|
+
/**
|
|
115
|
+
* Updates the working directory and reloads project-specific settings
|
|
116
|
+
*/
|
|
117
|
+
setCwd(cwd: string): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Disposes of file watchers and cleans up resources
|
|
120
|
+
*/
|
|
121
|
+
dispose(): void;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;CACnC;AAuLD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAW/C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAC7E;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,MAAM,CAAqE;IACnF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAA8C;gBAEvD,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAMzD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;YACW,eAAe;IAgB7B;;;;OAIG;IACH,OAAO,CAAC,aAAa;IA8CrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAgB5B;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,qBAAqB;IAuC5E;;OAEG;IACH,WAAW,IAAI,kBAAkB;IAIjC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
|
3
|
+
export declare const ACP_TOOL_NAME_PREFIX = "mcp__acp__";
|
|
4
|
+
export declare const acpToolNames: {
|
|
5
|
+
read: string;
|
|
6
|
+
edit: string;
|
|
7
|
+
write: string;
|
|
8
|
+
bash: string;
|
|
9
|
+
killShell: string;
|
|
10
|
+
bashOutput: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const EDIT_TOOL_NAMES: string[];
|
|
13
|
+
import { BetaBashCodeExecutionToolResultBlockParam, BetaCodeExecutionToolResultBlockParam, BetaRequestMCPToolResultBlockParam, BetaTextEditorCodeExecutionToolResultBlockParam, BetaToolSearchToolResultBlockParam, BetaWebFetchToolResultBlockParam, BetaWebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources/beta.mjs";
|
|
14
|
+
import { HookCallback } from "@anthropic-ai/claude-agent-sdk";
|
|
15
|
+
import { Logger } from "./acp-agent.js";
|
|
16
|
+
import { SettingsManager } from "./settings.js";
|
|
17
|
+
interface ToolInfo {
|
|
18
|
+
title: string;
|
|
19
|
+
kind: ToolKind;
|
|
20
|
+
content: ToolCallContent[];
|
|
21
|
+
locations?: ToolCallLocation[];
|
|
22
|
+
}
|
|
23
|
+
interface ToolUpdate {
|
|
24
|
+
title?: string;
|
|
25
|
+
content?: ToolCallContent[];
|
|
26
|
+
locations?: ToolCallLocation[];
|
|
27
|
+
}
|
|
28
|
+
export declare function toolInfoFromToolUse(toolUse: any): ToolInfo;
|
|
29
|
+
export declare function toolUpdateFromToolResult(toolResult: ToolResultBlockParam | BetaWebSearchToolResultBlockParam | BetaWebFetchToolResultBlockParam | WebSearchToolResultBlockParam | BetaCodeExecutionToolResultBlockParam | BetaBashCodeExecutionToolResultBlockParam | BetaTextEditorCodeExecutionToolResultBlockParam | BetaRequestMCPToolResultBlockParam | BetaToolSearchToolResultBlockParam, toolUse: any | undefined): ToolUpdate;
|
|
30
|
+
export type ClaudePlanEntry = {
|
|
31
|
+
content: string;
|
|
32
|
+
status: "pending" | "in_progress" | "completed";
|
|
33
|
+
activeForm: string;
|
|
34
|
+
};
|
|
35
|
+
export declare function planEntries(input: {
|
|
36
|
+
todos: ClaudePlanEntry[];
|
|
37
|
+
}): PlanEntry[];
|
|
38
|
+
export declare function markdownEscape(text: string): string;
|
|
39
|
+
export declare const registerHookCallback: (toolUseID: string, { onPostToolUseHook, }: {
|
|
40
|
+
onPostToolUseHook?: (toolUseID: string, toolInput: unknown, toolResponse: unknown) => Promise<void>;
|
|
41
|
+
}) => void;
|
|
42
|
+
export declare const createPostToolUseHook: (logger?: Logger) => HookCallback;
|
|
43
|
+
/**
|
|
44
|
+
* Creates a PreToolUse hook that checks permissions using the SettingsManager.
|
|
45
|
+
* This runs before the SDK's built-in permission rules, allowing us to enforce
|
|
46
|
+
* our own permission settings for ACP-prefixed tools.
|
|
47
|
+
*/
|
|
48
|
+
export declare const createPreToolUseHook: (settingsManager: SettingsManager, logger?: Logger) => HookCallback;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGlG,OAAO,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAWlG,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,YAAY;;;;;;;CAOxB,CAAC;AAEF,eAAO,MAAM,eAAe,UAA0C,CAAC;AAEvE,OAAO,EACL,yCAAyC,EACzC,qCAAqC,EACrC,kCAAkC,EAClC,+CAA+C,EAC/C,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,CA+V1D;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EACN,oBAAoB,GACpB,iCAAiC,GACjC,gCAAgC,GAChC,6BAA6B,GAC7B,qCAAqC,GACrC,yCAAyC,GACzC,+CAA+C,GAC/C,kCAAkC,GAClC,kCAAkC,EACtC,OAAO,EAAE,GAAG,GAAG,SAAS,GACvB,UAAU,CA4HZ;AAmCD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,SAAS,EAAE,CAM5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAcD,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,wBAEG;IACD,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,SAKF,CAAC;AAGF,eAAO,MAAM,qBAAqB,GAC/B,SAAQ,MAAgB,KAAG,YAa3B,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC9B,iBAAiB,eAAe,EAAE,SAAQ,MAAgB,KAAG,YA2C7D,CAAC"}
|