mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
190 lines
6.8 KiB
TypeScript
190 lines
6.8 KiB
TypeScript
import { Session } from "./packages/server/src/server/session.js";
|
||
import { AgentManager } from "./packages/server/src/server/acp/agent-manager.js";
|
||
import type { SessionInboundMessage, SessionOutboundMessage } from "./packages/server/src/server/messages.js";
|
||
import { exec } from "child_process";
|
||
import { promisify } from "util";
|
||
|
||
const execAsync = promisify(exec);
|
||
|
||
async function testWorktreeE2E() {
|
||
console.log("=== Testing End-to-End Worktree Agent Creation ===");
|
||
console.log("(Simulating frontend -> WebSocket -> Session -> AgentManager flow)\n");
|
||
|
||
const testBranchName = "test-e2e-worktree";
|
||
const cwd = process.cwd(); // voice-dev directory
|
||
let capturedMessages: SessionOutboundMessage[] = [];
|
||
let createdAgentId: string | null = null;
|
||
let worktreePath: string | null = null;
|
||
|
||
try {
|
||
// Step 1: Set up Session (like the WebSocket handler does)
|
||
console.log("Step 1: Creating Session and AgentManager...");
|
||
const agentManager = new AgentManager();
|
||
await agentManager.initialize();
|
||
|
||
const session = new Session(
|
||
"test-client",
|
||
(msg: SessionOutboundMessage) => {
|
||
capturedMessages.push(msg);
|
||
console.log(` [Session emit] ${msg.type}`);
|
||
|
||
// Capture agent_created message
|
||
if (msg.type === "agent_created") {
|
||
createdAgentId = msg.payload.agentId;
|
||
worktreePath = msg.payload.cwd;
|
||
console.log(` Agent ID: ${createdAgentId}`);
|
||
console.log(` CWD: ${worktreePath}`);
|
||
}
|
||
},
|
||
agentManager
|
||
);
|
||
console.log("✓ Session created\n");
|
||
|
||
// Step 2: Send create_agent_request message (like frontend does)
|
||
console.log("Step 2: Sending create_agent_request with worktreeName...");
|
||
const createAgentMessage: SessionInboundMessage = {
|
||
type: "create_agent_request",
|
||
cwd: cwd,
|
||
worktreeName: testBranchName,
|
||
requestId: "test-request-123",
|
||
};
|
||
|
||
console.log(` Message: ${JSON.stringify(createAgentMessage, null, 2)}`);
|
||
|
||
await session.handleMessage(createAgentMessage);
|
||
|
||
console.log("✓ Message handled\n");
|
||
|
||
// Step 3: Verify agent_created message was emitted
|
||
console.log("Step 3: Verifying agent_created message...");
|
||
const agentCreatedMsg = capturedMessages.find(m => m.type === "agent_created");
|
||
|
||
if (!agentCreatedMsg) {
|
||
throw new Error("No agent_created message emitted!");
|
||
}
|
||
|
||
if (agentCreatedMsg.type !== "agent_created") {
|
||
throw new Error("Wrong message type!");
|
||
}
|
||
|
||
console.log(`✓ agent_created message emitted`);
|
||
console.log(` Agent ID: ${agentCreatedMsg.payload.agentId}`);
|
||
console.log(` CWD: ${agentCreatedMsg.payload.cwd}`);
|
||
console.log(` Request ID: ${agentCreatedMsg.payload.requestId}\n`);
|
||
|
||
if (!createdAgentId) {
|
||
throw new Error("Agent ID not captured!");
|
||
}
|
||
|
||
if (!worktreePath) {
|
||
throw new Error("Worktree path not captured!");
|
||
}
|
||
|
||
// Step 4: Verify worktree was actually created
|
||
console.log("Step 4: Verifying worktree exists...");
|
||
const { stdout: worktreeList } = await execAsync("git worktree list");
|
||
|
||
if (!worktreeList.includes(worktreePath)) {
|
||
console.error("Git worktree list:");
|
||
console.error(worktreeList);
|
||
throw new Error(`Worktree not found in git! Expected: ${worktreePath}`);
|
||
}
|
||
console.log("✓ Worktree exists in git\n");
|
||
|
||
// Step 5: Verify the worktree path contains branch name
|
||
console.log("Step 5: Verifying worktree path...");
|
||
if (!worktreePath.includes(testBranchName)) {
|
||
throw new Error(`Worktree path doesn't contain branch name! Path: ${worktreePath}`);
|
||
}
|
||
console.log(`✓ Worktree path correct: ${worktreePath}\n`);
|
||
|
||
// Step 6: Verify agent is in the worktree
|
||
console.log("Step 6: Verifying agent CWD...");
|
||
const agentInfo = agentManager.listAgents().find(a => a.id === createdAgentId);
|
||
|
||
if (!agentInfo) {
|
||
throw new Error("Agent not found in manager!");
|
||
}
|
||
|
||
console.log(` Agent CWD: ${agentInfo.cwd}`);
|
||
console.log(` Expected: ${worktreePath}`);
|
||
|
||
if (agentInfo.cwd !== worktreePath) {
|
||
throw new Error(`Agent CWD mismatch! Expected ${worktreePath}, got ${agentInfo.cwd}`);
|
||
}
|
||
console.log("✓ Agent CWD matches worktree path\n");
|
||
|
||
// Step 7: Test agent can run commands in worktree
|
||
console.log("Step 7: Testing agent execution in worktree...");
|
||
await agentManager.sendPrompt(
|
||
createdAgentId,
|
||
"Run 'pwd' and 'git branch --show-current'. Just show me the output.",
|
||
);
|
||
|
||
let status = agentManager.getAgentStatus(createdAgentId);
|
||
let attempts = 0;
|
||
while (status === "processing" && attempts < 60) {
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
status = agentManager.getAgentStatus(createdAgentId);
|
||
attempts++;
|
||
}
|
||
|
||
console.log(` Agent status after prompt: ${status}`);
|
||
|
||
const updates = agentManager.getAgentUpdates(createdAgentId);
|
||
const messageChunks = updates
|
||
.filter(u => u.notification.type === "session" &&
|
||
u.notification.notification.update.sessionUpdate === "agent_message_chunk")
|
||
.map(u => {
|
||
const update = u.notification as any;
|
||
return update.notification.update.content?.text || "";
|
||
})
|
||
.join("");
|
||
|
||
console.log("\n Agent response:");
|
||
console.log(messageChunks);
|
||
|
||
if (!messageChunks.includes(testBranchName)) {
|
||
throw new Error("Agent response doesn't mention branch name!");
|
||
}
|
||
|
||
if (!messageChunks.includes(worktreePath)) {
|
||
throw new Error("Agent response doesn't show worktree path!");
|
||
}
|
||
|
||
console.log("\n✓ Agent successfully executing in worktree\n");
|
||
|
||
// Step 8: Cleanup
|
||
console.log("Step 8: Cleaning up...");
|
||
await agentManager.killAgent(createdAgentId);
|
||
console.log("✓ Agent killed\n");
|
||
|
||
console.log("=== END-TO-END TEST PASSED ===");
|
||
console.log("\n✅ The complete workflow works:");
|
||
console.log(" Frontend creates agent with worktreeName");
|
||
console.log(" → Message flows through Session");
|
||
console.log(" → Session creates worktree");
|
||
console.log(" → Agent is created in worktree");
|
||
console.log(" → Agent executes commands in worktree");
|
||
|
||
console.log("\n⚠️ Worktree still exists at:");
|
||
console.log(` ${worktreePath}`);
|
||
console.log("\nCleanup commands:");
|
||
console.log(` git worktree remove ${worktreePath}`);
|
||
console.log(` git branch -D ${testBranchName}`);
|
||
|
||
process.exit(0);
|
||
} catch (error) {
|
||
console.error("\n❌ END-TO-END TEST FAILED:");
|
||
console.error(error);
|
||
|
||
console.log("\n⚠️ Manual cleanup may be needed:");
|
||
console.log(` git worktree remove voice-dev-${testBranchName} 2>/dev/null || true`);
|
||
console.log(` git branch -D ${testBranchName} 2>/dev/null || true`);
|
||
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
testWorktreeE2E();
|