@agentclientprotocol/claude-agent-acp 0.65.0 → 0.67.0
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 +1 -0
- package/dist/acp-agent.d.ts +27 -0
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +606 -69
- package/dist/goal-extension.d.ts +36 -0
- package/dist/goal-extension.d.ts.map +1 -0
- package/dist/goal-extension.js +50 -0
- package/dist/tools.d.ts +4 -6
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +127 -15
- package/package.json +9 -8
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { SDKActiveGoalMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
export declare const GOAL_EXTENSION_VERSION: 1;
|
|
3
|
+
export declare const GOAL_CONTROL_METHOD = "_session/goal";
|
|
4
|
+
export declare const GOAL_ACTIONS: readonly ["set", "clear"];
|
|
5
|
+
export type GoalAction = (typeof GOAL_ACTIONS)[number];
|
|
6
|
+
export type GoalCapability = {
|
|
7
|
+
version: typeof GOAL_EXTENSION_VERSION;
|
|
8
|
+
controlMethod: typeof GOAL_CONTROL_METHOD;
|
|
9
|
+
actions: GoalAction[];
|
|
10
|
+
};
|
|
11
|
+
export type GoalStatus = "active" | "paused" | "blocked" | "limited" | "complete";
|
|
12
|
+
export type GoalSnapshot = {
|
|
13
|
+
objective: string;
|
|
14
|
+
status: GoalStatus;
|
|
15
|
+
iterations?: number;
|
|
16
|
+
lastReason?: string | null;
|
|
17
|
+
createdAt?: number;
|
|
18
|
+
updatedAt?: number;
|
|
19
|
+
tokenBudget?: number | null;
|
|
20
|
+
tokensUsed?: number;
|
|
21
|
+
timeUsedSeconds?: number;
|
|
22
|
+
controlMethod: typeof GOAL_CONTROL_METHOD;
|
|
23
|
+
};
|
|
24
|
+
export type GoalRequest = {
|
|
25
|
+
sessionId: string;
|
|
26
|
+
action: "clear";
|
|
27
|
+
} | {
|
|
28
|
+
sessionId: string;
|
|
29
|
+
action: "set";
|
|
30
|
+
objective: string;
|
|
31
|
+
};
|
|
32
|
+
export type GoalControlResponse = Record<string, never>;
|
|
33
|
+
export declare function goalUpdateFromPrompt(prompt: string): GoalSnapshot | null | undefined;
|
|
34
|
+
export declare function parseGoalRequest(params: unknown): GoalRequest;
|
|
35
|
+
export declare function toGoalSnapshot(message: SDKActiveGoalMessage): GoalSnapshot | null;
|
|
36
|
+
//# sourceMappingURL=goal-extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-extension.d.ts","sourceRoot":"","sources":["../src/goal-extension.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAE3E,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AACjD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AAEnD,eAAO,MAAM,YAAY,2BAA4B,CAAC;AACtD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,OAAO,sBAAsB,CAAC;IACvC,aAAa,EAAE,OAAO,mBAAmB,CAAC;IAC1C,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,mBAAmB,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,WAAW,GACrB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAExD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,CAcpF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAiB7D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CAYjF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { RequestError } from "@agentclientprotocol/sdk";
|
|
2
|
+
export const GOAL_EXTENSION_VERSION = 1;
|
|
3
|
+
export const GOAL_CONTROL_METHOD = "_session/goal";
|
|
4
|
+
export const GOAL_ACTIONS = ["set", "clear"];
|
|
5
|
+
export function goalUpdateFromPrompt(prompt) {
|
|
6
|
+
const match = /^\/goal(?:\s+([\s\S]*))?$/.exec(prompt);
|
|
7
|
+
const argument = match?.[1]?.trim();
|
|
8
|
+
if (!argument) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
if (argument === "clear") {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
objective: argument,
|
|
16
|
+
status: "active",
|
|
17
|
+
controlMethod: GOAL_CONTROL_METHOD,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function parseGoalRequest(params) {
|
|
21
|
+
if (!params || typeof params !== "object") {
|
|
22
|
+
throw RequestError.invalidParams(undefined, "goal params must be an object");
|
|
23
|
+
}
|
|
24
|
+
const { sessionId, action, objective } = params;
|
|
25
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
26
|
+
throw RequestError.invalidParams(undefined, "goal params require a non-empty sessionId");
|
|
27
|
+
}
|
|
28
|
+
if (!GOAL_ACTIONS.includes(action)) {
|
|
29
|
+
throw RequestError.invalidParams(undefined, 'goal action must be "set" or "clear"');
|
|
30
|
+
}
|
|
31
|
+
if (action === "set" && (typeof objective !== "string" || objective.trim().length === 0)) {
|
|
32
|
+
throw RequestError.invalidParams(undefined, 'goal action "set" requires a non-empty objective');
|
|
33
|
+
}
|
|
34
|
+
return action === "set"
|
|
35
|
+
? { sessionId, action, objective: objective.trim() }
|
|
36
|
+
: { sessionId, action: "clear" };
|
|
37
|
+
}
|
|
38
|
+
export function toGoalSnapshot(message) {
|
|
39
|
+
if (message.value === null) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
objective: message.value.condition.trim(),
|
|
44
|
+
status: "active",
|
|
45
|
+
iterations: message.value.iterations,
|
|
46
|
+
lastReason: message.value.last_reason ?? null,
|
|
47
|
+
createdAt: message.value.set_at,
|
|
48
|
+
controlMethod: GOAL_CONTROL_METHOD,
|
|
49
|
+
};
|
|
50
|
+
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk";
|
|
2
2
|
import { HookCallback } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
-
import { TaskCreateInput, TaskCreateOutput, TaskUpdateInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
|
|
3
|
+
import { TaskCreateInput, TaskCreateOutput, TaskListOutput, TaskUpdateInput, TaskUpdateOutput } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
|
|
4
4
|
import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
|
5
5
|
import { BetaBashCodeExecutionToolResultBlockParam, BetaCodeExecutionToolResultBlockParam, BetaRequestMCPToolResultBlockParam, BetaTextEditorCodeExecutionToolResultBlockParam, BetaToolResultBlockParam, BetaToolSearchToolResultBlockParam, BetaWebFetchToolResultBlockParam, BetaWebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources/beta.mjs";
|
|
6
6
|
interface ToolInfo {
|
|
@@ -57,14 +57,12 @@ export type TaskEntry = {
|
|
|
57
57
|
description?: string;
|
|
58
58
|
};
|
|
59
59
|
export type TaskState = Map<string, TaskEntry>;
|
|
60
|
-
/**
|
|
61
|
-
* Best-effort parse of a TaskCreate tool_result content into the structured
|
|
62
|
-
* TaskCreateOutput. The SDK delivers tool outputs either as a string or as
|
|
63
|
-
* an array of TextBlockParam-like blocks containing JSON text; try both.
|
|
64
|
-
*/
|
|
65
60
|
export declare function parseTaskCreateOutput(content: unknown): TaskCreateOutput | undefined;
|
|
61
|
+
export declare function parseTaskListOutput(content: unknown): TaskListOutput | undefined;
|
|
62
|
+
export declare function parseTaskUpdateOutput(content: unknown, expectedTaskId?: string): TaskUpdateOutput | undefined;
|
|
66
63
|
export declare function applyTaskCreate(state: TaskState, input: TaskCreateInput | undefined, output: TaskCreateOutput | undefined): void;
|
|
67
64
|
export declare function applyTaskUpdate(state: TaskState, input: TaskUpdateInput | undefined): void;
|
|
65
|
+
export declare function applyTaskList(state: TaskState, output: TaskListOutput): void;
|
|
68
66
|
export declare function taskStateToPlanEntries(state: TaskState): PlanEntry[];
|
|
69
67
|
export declare function markdownEscape(text: string): string;
|
|
70
68
|
/**
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAaL,eAAe,EACf,gBAAgB,EAChB,eAAe,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
CHANGED
|
@@ -96,7 +96,7 @@ export function toolInfoFromToolUse(toolUse, supportsTerminalOutput = false, cwd
|
|
|
96
96
|
}
|
|
97
97
|
const displayPath = input?.file_path ? toDisplayPath(input.file_path, cwd) : undefined;
|
|
98
98
|
return {
|
|
99
|
-
title: displayPath ? `Write ${displayPath}` : "
|
|
99
|
+
title: displayPath ? `Write ${displayPath}` : "Preparing file…",
|
|
100
100
|
kind: "edit",
|
|
101
101
|
content,
|
|
102
102
|
locations: input?.file_path ? [{ path: input.file_path }] : [],
|
|
@@ -291,6 +291,15 @@ export function toolInfoFromToolUse(toolUse, supportsTerminalOutput = false, cwd
|
|
|
291
291
|
: [],
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
|
+
case "Skill": {
|
|
295
|
+
const input = toolUse.input;
|
|
296
|
+
const skillName = input?.skill;
|
|
297
|
+
return {
|
|
298
|
+
title: skillName ? `Load skill: ${skillName}` : "Load skill",
|
|
299
|
+
kind: "other",
|
|
300
|
+
content: [],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
294
303
|
case "AskUserQuestion": {
|
|
295
304
|
const input = toolUse.input;
|
|
296
305
|
const questions = Array.isArray(input?.questions) ? input.questions : [];
|
|
@@ -658,6 +667,9 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
|
|
|
658
667
|
// renders, no worse than before.
|
|
659
668
|
return toAcpContentUpdate(stripAgentTrailerFromContent(toolResult.content), "is_error" in toolResult ? toolResult.is_error : false);
|
|
660
669
|
}
|
|
670
|
+
case "Skill": {
|
|
671
|
+
return {};
|
|
672
|
+
}
|
|
661
673
|
case "Edit": // Edit is handled in hooks
|
|
662
674
|
case "Write": {
|
|
663
675
|
return {};
|
|
@@ -798,35 +810,32 @@ function toAcpContentBlock(content, isError) {
|
|
|
798
810
|
}
|
|
799
811
|
export function planEntries(input) {
|
|
800
812
|
return (input?.todos ?? []).map((todo) => ({
|
|
801
|
-
content: todo.content,
|
|
813
|
+
content: todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content,
|
|
802
814
|
status: todo.status,
|
|
803
815
|
priority: "medium",
|
|
804
816
|
}));
|
|
805
817
|
}
|
|
806
818
|
/**
|
|
807
|
-
* Best-effort parse of a
|
|
808
|
-
*
|
|
809
|
-
*
|
|
819
|
+
* Best-effort parse of a structured Task* tool_result. The SDK delivers tool
|
|
820
|
+
* outputs either as a string or as an array of TextBlockParam-like blocks
|
|
821
|
+
* containing JSON text; try both.
|
|
810
822
|
*/
|
|
811
|
-
|
|
823
|
+
function parseJsonToolOutput(content, isExpectedOutput) {
|
|
812
824
|
const tryParse = (text) => {
|
|
813
825
|
try {
|
|
814
826
|
const parsed = JSON.parse(text);
|
|
815
|
-
|
|
816
|
-
typeof parsed === "object" &&
|
|
817
|
-
parsed.task &&
|
|
818
|
-
typeof parsed.task.id === "string") {
|
|
819
|
-
return parsed;
|
|
820
|
-
}
|
|
827
|
+
return isExpectedOutput(parsed) ? parsed : undefined;
|
|
821
828
|
}
|
|
822
829
|
catch {
|
|
823
|
-
|
|
830
|
+
return undefined;
|
|
824
831
|
}
|
|
825
|
-
return undefined;
|
|
826
832
|
};
|
|
827
833
|
if (typeof content === "string") {
|
|
828
834
|
return tryParse(content);
|
|
829
835
|
}
|
|
836
|
+
if (content && typeof content === "object" && !Array.isArray(content)) {
|
|
837
|
+
return isExpectedOutput(content) ? content : undefined;
|
|
838
|
+
}
|
|
830
839
|
if (Array.isArray(content)) {
|
|
831
840
|
for (const block of content) {
|
|
832
841
|
if (block && typeof block === "object" && "type" in block && block.type === "text") {
|
|
@@ -841,6 +850,96 @@ export function parseTaskCreateOutput(content) {
|
|
|
841
850
|
}
|
|
842
851
|
return undefined;
|
|
843
852
|
}
|
|
853
|
+
function toolOutputTexts(content) {
|
|
854
|
+
if (typeof content === "string")
|
|
855
|
+
return [content];
|
|
856
|
+
if (!Array.isArray(content))
|
|
857
|
+
return [];
|
|
858
|
+
return content.flatMap((block) => block &&
|
|
859
|
+
typeof block === "object" &&
|
|
860
|
+
"type" in block &&
|
|
861
|
+
block.type === "text" &&
|
|
862
|
+
"text" in block &&
|
|
863
|
+
typeof block.text === "string"
|
|
864
|
+
? [block.text]
|
|
865
|
+
: []);
|
|
866
|
+
}
|
|
867
|
+
export function parseTaskCreateOutput(content) {
|
|
868
|
+
const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed &&
|
|
869
|
+
typeof parsed === "object" &&
|
|
870
|
+
"task" in parsed &&
|
|
871
|
+
parsed.task &&
|
|
872
|
+
typeof parsed.task === "object" &&
|
|
873
|
+
"id" in parsed.task &&
|
|
874
|
+
typeof parsed.task.id === "string"));
|
|
875
|
+
if (structured)
|
|
876
|
+
return structured;
|
|
877
|
+
for (const text of toolOutputTexts(content)) {
|
|
878
|
+
const match = /^Task #(\S+) created successfully: (.+)$/.exec(text.trim());
|
|
879
|
+
if (match)
|
|
880
|
+
return { task: { id: match[1], subject: match[2] } };
|
|
881
|
+
}
|
|
882
|
+
return undefined;
|
|
883
|
+
}
|
|
884
|
+
export function parseTaskListOutput(content) {
|
|
885
|
+
const validStatuses = new Set(["pending", "in_progress", "completed"]);
|
|
886
|
+
const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed &&
|
|
887
|
+
typeof parsed === "object" &&
|
|
888
|
+
"tasks" in parsed &&
|
|
889
|
+
Array.isArray(parsed.tasks) &&
|
|
890
|
+
parsed.tasks.every((task) => task &&
|
|
891
|
+
typeof task === "object" &&
|
|
892
|
+
typeof task.id === "string" &&
|
|
893
|
+
typeof task.subject === "string" &&
|
|
894
|
+
typeof task.status === "string" &&
|
|
895
|
+
validStatuses.has(task.status))));
|
|
896
|
+
if (structured)
|
|
897
|
+
return structured;
|
|
898
|
+
for (const text of toolOutputTexts(content)) {
|
|
899
|
+
if (text.trim() === "No tasks found")
|
|
900
|
+
return { tasks: [] };
|
|
901
|
+
const tasks = [];
|
|
902
|
+
const lines = text.trim().split("\n");
|
|
903
|
+
for (const line of lines) {
|
|
904
|
+
const match = /^#(\S+) \[(pending|in_progress|completed)\] (.+?)(?: \(([^()]*)\))?(?: \[blocked by ((?:#[^,\]]+(?:, )?)+)\])?$/.exec(line);
|
|
905
|
+
if (!match) {
|
|
906
|
+
tasks.length = 0;
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
tasks.push({
|
|
910
|
+
id: match[1],
|
|
911
|
+
subject: match[3],
|
|
912
|
+
status: match[2],
|
|
913
|
+
...(match[4] ? { owner: match[4] } : {}),
|
|
914
|
+
blockedBy: match[5] ? match[5].split(", ").map((id) => id.slice(1)) : [],
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
if (tasks.length > 0)
|
|
918
|
+
return { tasks };
|
|
919
|
+
}
|
|
920
|
+
return undefined;
|
|
921
|
+
}
|
|
922
|
+
export function parseTaskUpdateOutput(content, expectedTaskId) {
|
|
923
|
+
const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed &&
|
|
924
|
+
typeof parsed === "object" &&
|
|
925
|
+
"success" in parsed &&
|
|
926
|
+
typeof parsed.success === "boolean" &&
|
|
927
|
+
"taskId" in parsed &&
|
|
928
|
+
typeof parsed.taskId === "string" &&
|
|
929
|
+
"updatedFields" in parsed &&
|
|
930
|
+
Array.isArray(parsed.updatedFields) &&
|
|
931
|
+
parsed.updatedFields.every((field) => typeof field === "string")));
|
|
932
|
+
if (structured)
|
|
933
|
+
return structured;
|
|
934
|
+
for (const text of toolOutputTexts(content)) {
|
|
935
|
+
const notFound = /^Task #(\S+) not found$/.exec(text.trim());
|
|
936
|
+
const taskId = notFound?.[1] ?? expectedTaskId;
|
|
937
|
+
if (taskId && (notFound || text.trim() === "Failed to delete task")) {
|
|
938
|
+
return { success: false, taskId, updatedFields: [], error: text.trim() };
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return undefined;
|
|
942
|
+
}
|
|
844
943
|
export function applyTaskCreate(state, input, output) {
|
|
845
944
|
const taskId = output?.task?.id;
|
|
846
945
|
if (!taskId || !input)
|
|
@@ -872,9 +971,22 @@ export function applyTaskUpdate(state, input) {
|
|
|
872
971
|
description: input.description ?? existing?.description,
|
|
873
972
|
});
|
|
874
973
|
}
|
|
974
|
+
export function applyTaskList(state, output) {
|
|
975
|
+
const previous = new Map(state);
|
|
976
|
+
state.clear();
|
|
977
|
+
for (const task of output.tasks) {
|
|
978
|
+
const existing = previous.get(task.id);
|
|
979
|
+
state.set(task.id, {
|
|
980
|
+
subject: task.subject,
|
|
981
|
+
status: task.status,
|
|
982
|
+
activeForm: existing?.activeForm,
|
|
983
|
+
description: existing?.description,
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
}
|
|
875
987
|
export function taskStateToPlanEntries(state) {
|
|
876
988
|
return Array.from(state.values()).map((task) => ({
|
|
877
|
-
content: task.subject,
|
|
989
|
+
content: task.status === "in_progress" && task.activeForm ? task.activeForm : task.subject,
|
|
878
990
|
status: task.status,
|
|
879
991
|
priority: "medium",
|
|
880
992
|
}));
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.67.0",
|
|
7
7
|
"description": "An ACP-compatible coding agent powered by the Claude Agent SDK (TypeScript)",
|
|
8
8
|
"main": "dist/lib.js",
|
|
9
9
|
"types": "dist/lib.d.ts",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"format": "prettier --write .",
|
|
36
36
|
"format:check": "prettier --check .",
|
|
37
37
|
"check": "npm run lint && npm run format:check",
|
|
38
|
+
"release:preflight": "bash scripts/release-preflight.sh",
|
|
38
39
|
"test": "vitest",
|
|
39
40
|
"test:integration": "RUN_INTEGRATION_TESTS=true vitest run",
|
|
40
41
|
"test:run": "vitest run",
|
|
@@ -65,19 +66,19 @@
|
|
|
65
66
|
},
|
|
66
67
|
"dependencies": {
|
|
67
68
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
68
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
69
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.232",
|
|
69
70
|
"zod": "^3.25.0 || ^4.0.0"
|
|
70
71
|
},
|
|
71
72
|
"devDependencies": {
|
|
72
|
-
"@anthropic-ai/sdk": "0.
|
|
73
|
+
"@anthropic-ai/sdk": "0.117.1",
|
|
73
74
|
"@eslint/js": "10.0.1",
|
|
74
75
|
"@tsconfig/node22": "22.0.5",
|
|
75
|
-
"@types/node": "26.
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
77
|
-
"@typescript-eslint/parser": "8.
|
|
78
|
-
"eslint": "10.8.
|
|
76
|
+
"@types/node": "26.2.0",
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "8.67.0",
|
|
78
|
+
"@typescript-eslint/parser": "8.67.0",
|
|
79
|
+
"eslint": "10.8.1",
|
|
79
80
|
"eslint-config-prettier": "10.1.8",
|
|
80
|
-
"globals": "17.
|
|
81
|
+
"globals": "17.11.0",
|
|
81
82
|
"prettier": "3.9.6",
|
|
82
83
|
"ts-node": "10.9.2",
|
|
83
84
|
"typescript": "6.0.3",
|