Add getGitDiff() to DaemonClient + E2E tests

- Add getGitDiff(agentId) method to DaemonClient that sends git_diff_request
  and waits for git_diff_response
- Add 3 E2E tests covering:
  1. Modified file in git repo returns correct diff
  2. Clean repo returns empty diff
  3. Non-git directory returns error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2025-12-25 18:10:00 +07:00
co-authored by Claude Opus 4.5
parent 46ddb5a20c
commit 26ec7d20f0
3 changed files with 146 additions and 1 deletions
@@ -1098,4 +1098,121 @@ describe("daemon E2E", () => {
180000
);
});
describe("getGitDiff", () => {
test(
"returns diff for modified file in git repo",
async () => {
const cwd = tmpCwd();
// Initialize git repo
const { execSync } = await import("child_process");
execSync("git init", { cwd, stdio: "pipe" });
execSync("git config user.email 'test@test.com'", { cwd, stdio: "pipe" });
execSync("git config user.name 'Test'", { cwd, stdio: "pipe" });
// Create and commit a file
const testFile = path.join(cwd, "test.txt");
writeFileSync(testFile, "original content\n");
execSync("git add test.txt", { cwd, stdio: "pipe" });
execSync("git commit -m 'Initial commit'", { cwd, stdio: "pipe" });
// Modify the file (creates unstaged changes)
writeFileSync(testFile, "modified content\n");
// Create agent in the git repo
const agent = await ctx.client.createAgent({
provider: "codex",
cwd,
title: "Git Diff Test",
});
expect(agent.id).toBeTruthy();
expect(agent.status).toBe("idle");
// Get git diff
const result = await ctx.client.getGitDiff(agent.id);
// Verify diff returned without error
expect(result.error).toBeNull();
expect(result.diff).toBeTruthy();
expect(result.diff).toContain("test.txt");
expect(result.diff).toContain("-original content");
expect(result.diff).toContain("+modified content");
// Cleanup
await ctx.client.deleteAgent(agent.id);
rmSync(cwd, { recursive: true, force: true });
},
60000 // 1 minute timeout
);
test(
"returns empty diff when no changes",
async () => {
const cwd = tmpCwd();
// Initialize git repo with clean state
const { execSync } = await import("child_process");
execSync("git init", { cwd, stdio: "pipe" });
execSync("git config user.email 'test@test.com'", { cwd, stdio: "pipe" });
execSync("git config user.name 'Test'", { cwd, stdio: "pipe" });
// Create and commit a file
const testFile = path.join(cwd, "test.txt");
writeFileSync(testFile, "content\n");
execSync("git add test.txt", { cwd, stdio: "pipe" });
execSync("git commit -m 'Initial commit'", { cwd, stdio: "pipe" });
// Create agent in the git repo (no modifications)
const agent = await ctx.client.createAgent({
provider: "codex",
cwd,
title: "Git Diff Clean Test",
});
expect(agent.id).toBeTruthy();
// Get git diff - should be empty
const result = await ctx.client.getGitDiff(agent.id);
expect(result.error).toBeNull();
expect(result.diff).toBe("");
// Cleanup
await ctx.client.deleteAgent(agent.id);
rmSync(cwd, { recursive: true, force: true });
},
60000 // 1 minute timeout
);
test(
"returns error for non-git directory",
async () => {
const cwd = tmpCwd();
// Don't initialize git - just a regular directory
// Create agent in a non-git directory
const agent = await ctx.client.createAgent({
provider: "codex",
cwd,
title: "Git Diff Non-Git Test",
});
expect(agent.id).toBeTruthy();
// Get git diff - should return error
const result = await ctx.client.getGitDiff(agent.id);
expect(result.diff).toBe("");
expect(result.error).toBeTruthy();
expect(result.error).toContain("git");
// Cleanup
await ctx.client.deleteAgent(agent.id);
rmSync(cwd, { recursive: true, force: true });
},
60000 // 1 minute timeout
);
});
});
@@ -363,6 +363,32 @@ export class DaemonClient {
this.send({ type: "set_agent_mode", agentId, modeId });
}
// ============================================================================
// Git Operations
// ============================================================================
async getGitDiff(
agentId: string
): Promise<{ diff: string; error: string | null }> {
const startPosition = this.messageQueue.length;
this.send({ type: "git_diff_request", agentId });
return this.waitFor(
(msg) => {
if (
msg.type === "git_diff_response" &&
msg.payload.agentId === agentId
) {
return { diff: msg.payload.diff, error: msg.payload.error };
}
return null;
},
10000,
{ skipQueueBefore: startPosition }
);
}
// ============================================================================
// Permissions
// ============================================================================