consolidate checkout status handling and improve git detection

This commit is contained in:
Mohamed Boudra
2026-02-03 14:50:15 +07:00
parent ad632cb3bd
commit 14b0db55b0
12 changed files with 369 additions and 188 deletions
@@ -15,6 +15,9 @@ export function deriveBranchLabel(
if (!currentBranch) {
return null;
}
if (currentBranch === "HEAD") {
return null;
}
if (baseRef && currentBranch === baseRef) {
return null;
}
@@ -219,6 +219,65 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => {
}
});
test("parses apply_patch with kind object (type/move_path) into edit type", () => {
const input = {
files: [
{
path: "/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts",
kind: { type: "update", move_path: null },
},
],
};
const result = {
files: [
{
path: "/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts",
patch: "@@ -1,1 +1,1 @@\n-foo\n+bar",
kind: { type: "update", move_path: null },
},
],
success: true,
};
const display = parseToolCallDisplay("apply_patch", input, result);
expect(display.type).toBe("edit");
expect(display.toolName).toBe("Edit");
if (display.type === "edit") {
expect(display.filePath).toBe(
"/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts"
);
expect(display.unifiedDiff).toBe("@@ -1,1 +1,1 @@\n-foo\n+bar");
}
});
test("prefers move_path for display but still finds patch by original path", () => {
const input = {
files: [
{
path: "/some/old-path.txt",
kind: { type: "update", move_path: "/some/new-path.txt" },
},
],
};
const result = {
files: [
{
path: "/some/old-path.txt",
patch: "@@ -1,1 +1,1 @@\n-old\n+new",
kind: { type: "update", move_path: "/some/new-path.txt" },
},
],
success: true,
};
const display = parseToolCallDisplay("apply_patch", input, result);
expect(display.type).toBe("edit");
if (display.type === "edit") {
expect(display.filePath).toBe("/some/new-path.txt");
expect(display.unifiedDiff).toBe("@@ -1,1 +1,1 @@\n-old\n+new");
}
});
test("parses pending apply_patch (no result yet)", () => {
const input = {
files: [
+34 -6
View File
@@ -1041,20 +1041,42 @@ const EditToolCallSchema = z
};
});
// Codex apply_patch input: { files: [{ path: string, kind: string }] }
const ApplyPatchFileKindSchema = z
.union([
z.string(),
z
.object({
type: z.string().optional(),
move_path: z.string().nullable().optional(),
movePath: z.string().nullable().optional(),
})
.passthrough(),
])
.optional();
function getApplyPatchMovePath(kind: unknown): string | undefined {
if (!kind || typeof kind !== "object") return undefined;
const record = kind as Record<string, unknown>;
const movePath = typeof record.movePath === "string" ? record.movePath : undefined;
const movePathSnake =
typeof record.move_path === "string" ? record.move_path : undefined;
return movePath ?? movePathSnake ?? undefined;
}
// Codex apply_patch input: { files: [{ path: string, kind: string | object }] }
const ApplyPatchInputSchema = z.object({
files: z.array(z.object({
path: z.string(),
kind: z.string().optional(),
kind: ApplyPatchFileKindSchema,
})).min(1),
}).passthrough();
// Codex apply_patch result: { files: [{ path: string, patch: string, kind: string }], message: string, success: boolean }
// Codex apply_patch result: { files: [{ path: string, patch: string, kind: string | object }], message: string, success: boolean }
const ApplyPatchResultSchema = z.object({
files: z.array(z.object({
path: z.string(),
patch: z.string().optional(),
kind: z.string().optional(),
kind: ApplyPatchFileKindSchema,
})).optional(),
message: z.string().optional(),
success: z.boolean().optional(),
@@ -1068,13 +1090,19 @@ const ApplyPatchToolCallSchema = z
})
.transform((data): { type: "edit"; filePath: string; oldString: string; newString: string; unifiedDiff?: string } => {
const firstFile = data.input.files[0];
const filePath = firstFile.path;
const movePath = getApplyPatchMovePath(firstFile.kind);
const filePath = movePath ?? firstFile.path;
// Try to get the patch from the result
const resultParsed = ApplyPatchResultSchema.safeParse(data.result);
let unifiedDiff: string | undefined;
if (resultParsed.success && resultParsed.data.files) {
const resultFile = resultParsed.data.files.find(f => f.path === filePath) ?? resultParsed.data.files[0];
const matchPaths = new Set<string>([firstFile.path]);
if (movePath) matchPaths.add(movePath);
const resultFile =
resultParsed.data.files.find((f) => matchPaths.has(f.path)) ??
resultParsed.data.files[0];
unifiedDiff = resultFile?.patch;
}