chore(deps): upgrade claude-code-acp to v0.8.4 and mark express dependencies as optional
This commit is contained in:
@@ -19,85 +19,51 @@ describe("AgentManager", () => {
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it(
|
||||
"should create file after accepting plan",
|
||||
async () => {
|
||||
let permissionRequest: RequestPermissionRequest | null = null;
|
||||
let requestId: string | null = null;
|
||||
const testFile = join(tmpDir, "test.txt");
|
||||
it("should create file after accepting plan", async () => {
|
||||
let permissionRequest: RequestPermissionRequest | null = null;
|
||||
let requestId: string | null = null;
|
||||
const testFile = join(tmpDir, "test.txt");
|
||||
|
||||
const agentId = await manager.createAgent({
|
||||
cwd: tmpDir,
|
||||
initialMode: "plan",
|
||||
});
|
||||
const agentId = await manager.createAgent({
|
||||
cwd: tmpDir,
|
||||
initialMode: "plan",
|
||||
});
|
||||
|
||||
const unsubscribe = manager.subscribeToUpdates(
|
||||
agentId,
|
||||
(update: AgentUpdate) => {
|
||||
const notification: AgentNotification = update.notification;
|
||||
if (notification.type === "permission") {
|
||||
permissionRequest = notification.request;
|
||||
requestId = notification.requestId;
|
||||
}
|
||||
const unsubscribe = manager.subscribeToUpdates(
|
||||
agentId,
|
||||
(update: AgentUpdate) => {
|
||||
const notification: AgentNotification = update.notification;
|
||||
if (notification.type === "permission") {
|
||||
permissionRequest = notification.request;
|
||||
requestId = notification.requestId;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
await manager.sendPrompt(
|
||||
agentId,
|
||||
"Create a file called test.txt with the content 'hello world'"
|
||||
);
|
||||
|
||||
try {
|
||||
await manager.sendPrompt(
|
||||
agentId,
|
||||
"Create a file called test.txt with the content 'hello world'"
|
||||
);
|
||||
|
||||
let attempts = 0;
|
||||
while (!permissionRequest && attempts < 40) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
attempts++;
|
||||
}
|
||||
|
||||
expect(permissionRequest).toBeDefined();
|
||||
expect(requestId).toBeDefined();
|
||||
|
||||
const acceptOption = permissionRequest!.options.find(
|
||||
(o) => o.kind === "allow_once" || o.kind === "allow_always"
|
||||
);
|
||||
expect(acceptOption).toBeDefined();
|
||||
|
||||
manager.respondToPermission(agentId, requestId!, acceptOption!.optionId);
|
||||
|
||||
let status = manager.getAgentStatus(agentId);
|
||||
attempts = 0;
|
||||
while (status !== "completed" && status !== "failed" && attempts < 60) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
status = manager.getAgentStatus(agentId);
|
||||
attempts++;
|
||||
}
|
||||
|
||||
expect(status).toBe("completed");
|
||||
|
||||
const content = await readFile(testFile, "utf-8");
|
||||
expect(content).toContain("hello world");
|
||||
|
||||
const agentInfo = manager.listAgents().find((a) => a.id === agentId);
|
||||
expect(agentInfo?.currentModeId).toBe("acceptEdits");
|
||||
} finally {
|
||||
unsubscribe();
|
||||
await manager.killAgent(agentId);
|
||||
let attempts = 0;
|
||||
while (!permissionRequest && attempts < 40) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
attempts++;
|
||||
}
|
||||
},
|
||||
120000
|
||||
);
|
||||
|
||||
it(
|
||||
"should load persisted agent and send new prompt",
|
||||
async () => {
|
||||
const agentId = await manager.createAgent({
|
||||
cwd: tmpDir,
|
||||
});
|
||||
expect(permissionRequest).toBeDefined();
|
||||
expect(requestId).toBeDefined();
|
||||
|
||||
await manager.sendPrompt(agentId, "echo 'first message'");
|
||||
const acceptOption = permissionRequest!.options.find(
|
||||
(o) => o.kind === "allow_once" || o.kind === "allow_always"
|
||||
);
|
||||
expect(acceptOption).toBeDefined();
|
||||
|
||||
manager.respondToPermission(agentId, requestId!, acceptOption!.optionId);
|
||||
|
||||
let status = manager.getAgentStatus(agentId);
|
||||
let attempts = 0;
|
||||
attempts = 0;
|
||||
while (status !== "completed" && status !== "failed" && attempts < 60) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
status = manager.getAgentStatus(agentId);
|
||||
@@ -106,45 +72,82 @@ describe("AgentManager", () => {
|
||||
|
||||
expect(status).toBe("completed");
|
||||
|
||||
const agentBeforeKill = manager.listAgents().find((a) => a.id === agentId);
|
||||
const claudeSessionId = manager.getClaudeSessionId(agentId);
|
||||
console.log("Before kill - ACP Session ID:", agentBeforeKill?.sessionId);
|
||||
console.log("Before kill - Claude Session ID:", claudeSessionId);
|
||||
console.log("Working directory:", tmpDir);
|
||||
const content = await readFile(testFile, "utf-8");
|
||||
expect(content).toContain("hello world");
|
||||
|
||||
const agentInfo = manager.listAgents().find((a) => a.id === agentId);
|
||||
expect(agentInfo?.currentModeId).toBe("acceptEdits");
|
||||
} finally {
|
||||
unsubscribe();
|
||||
await manager.killAgent(agentId);
|
||||
}
|
||||
}, 120000);
|
||||
|
||||
const newManager = new AgentManager();
|
||||
await newManager.initialize();
|
||||
it.only("should load persisted agent and send new prompt", async () => {
|
||||
const agentId = await manager.createAgent({
|
||||
cwd: tmpDir,
|
||||
});
|
||||
|
||||
const agents = newManager.listAgents();
|
||||
const loadedAgent = agents.find((a) => a.id === agentId);
|
||||
const loadedClaudeSessionId = newManager.getClaudeSessionId(agentId);
|
||||
await manager.sendPrompt(agentId, "echo 'first message'");
|
||||
|
||||
console.log("After reload - ACP Session ID:", loadedAgent?.sessionId);
|
||||
console.log("After reload - Claude Session ID:", loadedClaudeSessionId);
|
||||
let status = manager.getAgentStatus(agentId);
|
||||
let attempts = 0;
|
||||
while (status !== "completed" && status !== "failed" && attempts < 60) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
status = manager.getAgentStatus(agentId);
|
||||
attempts++;
|
||||
}
|
||||
|
||||
expect(loadedAgent).toBeDefined();
|
||||
expect(loadedAgent?.id).toBe(agentId);
|
||||
expect(loadedAgent?.cwd).toBe(tmpDir);
|
||||
expect(status).toBe("completed");
|
||||
|
||||
await newManager.sendPrompt(agentId, "echo 'second message'");
|
||||
const agentBeforeKill = manager.listAgents().find((a) => a.id === agentId);
|
||||
const claudeSessionId = manager.getClaudeSessionId(agentId);
|
||||
console.log("Before kill - ACP Session ID:", agentBeforeKill?.sessionId);
|
||||
console.log("Before kill - Claude Session ID:", claudeSessionId);
|
||||
console.log("Working directory:", tmpDir);
|
||||
|
||||
await manager.killAgent(agentId);
|
||||
|
||||
const newManager = new AgentManager();
|
||||
await newManager.initialize();
|
||||
|
||||
const agents = newManager.listAgents();
|
||||
const loadedAgent = agents.find((a) => a.id === agentId);
|
||||
const loadedClaudeSessionId = newManager.getClaudeSessionId(agentId);
|
||||
|
||||
console.log("After reload - ACP Session ID:", loadedAgent?.sessionId);
|
||||
console.log("After reload - Claude Session ID:", loadedClaudeSessionId);
|
||||
|
||||
expect(loadedAgent).toBeDefined();
|
||||
expect(loadedAgent?.id).toBe(agentId);
|
||||
expect(loadedAgent?.cwd).toBe(tmpDir);
|
||||
|
||||
await newManager.initializeAgentAndGetHistory(agentId);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
const persistedUpdates = newManager.getAgentUpdates(agentId);
|
||||
|
||||
console.log(
|
||||
"Persisted updates:",
|
||||
JSON.stringify(persistedUpdates, null, 2)
|
||||
);
|
||||
|
||||
await newManager.sendPrompt(agentId, "echo 'second message'");
|
||||
|
||||
status = newManager.getAgentStatus(agentId);
|
||||
attempts = 0;
|
||||
while (status !== "completed" && status !== "failed" && attempts < 60) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
status = newManager.getAgentStatus(agentId);
|
||||
attempts = 0;
|
||||
while (status !== "completed" && status !== "failed" && attempts < 60) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
status = newManager.getAgentStatus(agentId);
|
||||
attempts++;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
expect(status).toBe("completed");
|
||||
expect(status).toBe("completed");
|
||||
|
||||
const finalUpdates = newManager.getAgentUpdates(agentId);
|
||||
expect(finalUpdates.length).toBeGreaterThan(0);
|
||||
const finalUpdates = newManager.getAgentUpdates(agentId);
|
||||
expect(finalUpdates.length).toBeGreaterThan(0);
|
||||
|
||||
await newManager.killAgent(agentId);
|
||||
},
|
||||
120000
|
||||
);
|
||||
console.log("Final updates:", finalUpdates);
|
||||
|
||||
await newManager.killAgent(agentId);
|
||||
}, 120000);
|
||||
});
|
||||
|
||||
@@ -62,9 +62,7 @@ interface ManagedAgent {
|
||||
|
||||
type UpdateAgentCallback = (
|
||||
agentId: string,
|
||||
updateFn: (
|
||||
agent: ManagedAgent
|
||||
) => boolean | void | Promise<boolean | void>,
|
||||
updateFn: (agent: ManagedAgent) => boolean | void | Promise<boolean | void>,
|
||||
options?: { sessionId: string | null }
|
||||
) => Promise<void>;
|
||||
|
||||
@@ -113,7 +111,10 @@ class ACPClient implements Client {
|
||||
|
||||
async sessionUpdate(params: SessionNotification): Promise<void> {
|
||||
if (params.update.sessionUpdate === "agent_message_chunk") {
|
||||
console.log(`[Agent ${this.agentId}] Message chunk update:`, JSON.stringify(params, null, 2));
|
||||
console.log(
|
||||
`[Agent ${this.agentId}] Message chunk update:`,
|
||||
JSON.stringify(params, null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if this update contains a Claude session ID
|
||||
@@ -349,13 +350,15 @@ export class AgentManager {
|
||||
}
|
||||
|
||||
// Convert prompt to ContentBlock array if it's a string
|
||||
const contentBlocks: ContentBlock[] = typeof prompt === "string"
|
||||
? [{ type: "text", text: prompt }]
|
||||
: prompt;
|
||||
const contentBlocks: ContentBlock[] =
|
||||
typeof prompt === "string" ? [{ type: "text", text: prompt }] : prompt;
|
||||
|
||||
// Extract text for user message notification (use first text block)
|
||||
const firstTextBlock = contentBlocks.find(block => block.type === "text");
|
||||
const userMessageText = firstTextBlock && "text" in firstTextBlock ? firstTextBlock.text : "[message with attachments]";
|
||||
const firstTextBlock = contentBlocks.find((block) => block.type === "text");
|
||||
const userMessageText =
|
||||
firstTextBlock && "text" in firstTextBlock
|
||||
? firstTextBlock.text
|
||||
: "[message with attachments]";
|
||||
|
||||
// Emit user message notification
|
||||
const userMessageUpdate: AgentUpdate = {
|
||||
@@ -540,6 +543,7 @@ export class AgentManager {
|
||||
if (runtime) {
|
||||
setTimeout(() => {
|
||||
if (!runtime.process.killed) {
|
||||
console.log(`[Agent ${agentId}] Force killing process`);
|
||||
runtime.process.kill("SIGKILL");
|
||||
}
|
||||
}, 5000);
|
||||
@@ -898,9 +902,7 @@ export class AgentManager {
|
||||
|
||||
private async updateAgent(
|
||||
agentId: string,
|
||||
updateFn: (
|
||||
agent: ManagedAgent
|
||||
) => boolean | void | Promise<boolean | void>,
|
||||
updateFn: (agent: ManagedAgent) => boolean | void | Promise<boolean | void>,
|
||||
options?: { sessionId: string | null }
|
||||
): Promise<void> {
|
||||
const agent = this.agents.get(agentId);
|
||||
@@ -1185,7 +1187,9 @@ export class AgentManager {
|
||||
const runtime = this.getRuntime(agent);
|
||||
|
||||
if (runtime && runtime.currentModeId !== newModeId) {
|
||||
console.log(`[Agent ${agentId}] Mode changed: ${runtime.currentModeId} -> ${newModeId}`);
|
||||
console.log(
|
||||
`[Agent ${agentId}] Mode changed: ${runtime.currentModeId} -> ${newModeId}`
|
||||
);
|
||||
runtime.currentModeId = newModeId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user