Add getGitRepoInfo() to DaemonClient + E2E tests
- Added getGitRepoInfo(agentId) method that returns repo info (branches, currentBranch, isDirty, repoRoot) by looking up the agent's cwd and sending git_repo_info_request - Added 3 E2E tests: (1) returns repo info for git repo with branch and dirty state, (2) returns clean state when no uncommitted changes, (3) returns error for non-git directory 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
26ec7d20f0
commit
bf83908a42
@@ -1215,4 +1215,123 @@ describe("daemon E2E", () => {
|
|||||||
60000 // 1 minute timeout
|
60000 // 1 minute timeout
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getGitRepoInfo", () => {
|
||||||
|
test(
|
||||||
|
"returns repo info for git repo with branch and dirty state",
|
||||||
|
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 (makes repo dirty)
|
||||||
|
writeFileSync(testFile, "modified content\n");
|
||||||
|
|
||||||
|
// Create agent in the git repo
|
||||||
|
const agent = await ctx.client.createAgent({
|
||||||
|
provider: "codex",
|
||||||
|
cwd,
|
||||||
|
title: "Git Repo Info Test",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(agent.id).toBeTruthy();
|
||||||
|
expect(agent.status).toBe("idle");
|
||||||
|
|
||||||
|
// Get git repo info
|
||||||
|
const result = await ctx.client.getGitRepoInfo(agent.id);
|
||||||
|
|
||||||
|
// Verify repo info returned without error
|
||||||
|
expect(result.error).toBeNull();
|
||||||
|
// macOS symlinks /var to /private/var, so we check containment
|
||||||
|
expect(result.repoRoot).toContain("daemon-e2e-");
|
||||||
|
expect(result.currentBranch).toBeTruthy();
|
||||||
|
expect(result.branches.length).toBeGreaterThan(0);
|
||||||
|
expect(result.branches.some((b) => b.isCurrent)).toBe(true);
|
||||||
|
expect(result.isDirty).toBe(true);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
await ctx.client.deleteAgent(agent.id);
|
||||||
|
rmSync(cwd, { recursive: true, force: true });
|
||||||
|
},
|
||||||
|
60000 // 1 minute timeout
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
"returns clean state when no uncommitted 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 (no uncommitted changes)
|
||||||
|
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
|
||||||
|
const agent = await ctx.client.createAgent({
|
||||||
|
provider: "codex",
|
||||||
|
cwd,
|
||||||
|
title: "Git Repo Info Clean Test",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(agent.id).toBeTruthy();
|
||||||
|
|
||||||
|
// Get git repo info
|
||||||
|
const result = await ctx.client.getGitRepoInfo(agent.id);
|
||||||
|
|
||||||
|
expect(result.error).toBeNull();
|
||||||
|
expect(result.isDirty).toBe(false);
|
||||||
|
expect(result.currentBranch).toBeTruthy();
|
||||||
|
|
||||||
|
// 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 Repo Info Non-Git Test",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(agent.id).toBeTruthy();
|
||||||
|
|
||||||
|
// Get git repo info - should return error
|
||||||
|
const result = await ctx.client.getGitRepoInfo(agent.id);
|
||||||
|
|
||||||
|
// Server returns cwd as repoRoot even on error, so we just check for error
|
||||||
|
expect(result.error).toBeTruthy();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
await ctx.client.deleteAgent(agent.id);
|
||||||
|
rmSync(cwd, { recursive: true, force: true });
|
||||||
|
},
|
||||||
|
60000 // 1 minute timeout
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -389,6 +389,49 @@ export class DaemonClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getGitRepoInfo(agentId: string): Promise<{
|
||||||
|
repoRoot: string;
|
||||||
|
currentBranch: string | null;
|
||||||
|
branches: Array<{ name: string; isCurrent: boolean }>;
|
||||||
|
isDirty: boolean;
|
||||||
|
error: string | null;
|
||||||
|
}> {
|
||||||
|
// Get the agent's cwd from the current list
|
||||||
|
const agents = this.listAgents();
|
||||||
|
const agent = agents.find((a) => a.id === agentId);
|
||||||
|
if (!agent) {
|
||||||
|
return {
|
||||||
|
repoRoot: "",
|
||||||
|
currentBranch: null,
|
||||||
|
branches: [],
|
||||||
|
isDirty: false,
|
||||||
|
error: `Agent not found: ${agentId}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const cwd = agent.cwd;
|
||||||
|
const startPosition = this.messageQueue.length;
|
||||||
|
|
||||||
|
this.send({ type: "git_repo_info_request", cwd });
|
||||||
|
|
||||||
|
return this.waitFor(
|
||||||
|
(msg) => {
|
||||||
|
if (msg.type === "git_repo_info_response" && msg.payload.cwd === cwd) {
|
||||||
|
return {
|
||||||
|
repoRoot: msg.payload.repoRoot,
|
||||||
|
currentBranch: msg.payload.currentBranch ?? null,
|
||||||
|
branches: msg.payload.branches ?? [],
|
||||||
|
isDirty: msg.payload.isDirty ?? false,
|
||||||
|
error: msg.payload.error ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
10000,
|
||||||
|
{ skipQueueBefore: startPosition }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Permissions
|
// Permissions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user