Skip to content

Commit 404a011

Browse files
committed
chore: auto-commit unfinished agent work
1 parent 9177bf8 commit 404a011

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ docs/plans/
4747
# av daemon
4848
.av.pid
4949
.av.log
50+
.agent-valley/

packages/core/src/__tests__/merge-conflict.test.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,117 @@ describe("mergeAndPush — rebase-based delivery", () => {
231231
git(repoDir, ["checkout", "main"])
232232
expect(readFile(resolve(repoDir, "package-lock.json"))).toContain('"version": "2.0.0"')
233233
})
234+
235+
test("blocks merge when feature branch has pre-committed conflict markers", async () => {
236+
// Simulate an agent that accidentally committed conflict markers
237+
git(repoDir, ["checkout", "-b", "feature/TEST-6"])
238+
mkdirSync(resolve(repoDir, "src", "store"), { recursive: true })
239+
writeFileSync(
240+
resolve(repoDir, "src/store/auth.ts"),
241+
[
242+
"<<<<<<< HEAD",
243+
'import { authClient } from "./auth-client"',
244+
"=======",
245+
'import { betterAuth } from "better-auth"',
246+
">>>>>>> 2c83c4e",
247+
"",
248+
"export const store = {}",
249+
].join("\n") + "\n",
250+
)
251+
git(repoDir, ["add", "."])
252+
git(repoDir, ["commit", "-m", "feat(web,api): integrate better-auth for authentication"])
253+
254+
const workspace = {
255+
id: "t",
256+
key: "TEST-6",
257+
path: resolve(repoDir, "TEST-6"),
258+
issueId: "t",
259+
branch: "feature/TEST-6",
260+
status: "running" as const,
261+
createdAt: new Date().toISOString(),
262+
}
263+
const result = await manager.mergeAndPush(workspace)
264+
265+
expect(result.ok).toBe(false)
266+
expect(result.error).toContain("conflict marker")
267+
268+
// Verify origin/main was NOT corrupted
269+
const remoteMain = git(bareDir, ["log", "--oneline", "main"])
270+
expect(remoteMain).not.toContain("better-auth")
271+
})
272+
273+
test("blocks merge when feature branch has conflict markers in package.json", async () => {
274+
// Pre-committed conflict markers in a high-risk file
275+
git(repoDir, ["checkout", "-b", "feature/TEST-7"])
276+
writeFileSync(
277+
resolve(repoDir, "package.json"),
278+
[
279+
"{",
280+
' "name": "demo",',
281+
"<<<<<<< HEAD",
282+
' "dependencies": { "left-pad": "1.0.0" }',
283+
"=======",
284+
' "dependencies": { "right-pad": "2.0.0" }',
285+
">>>>>>>",
286+
"}",
287+
].join("\n") + "\n",
288+
)
289+
git(repoDir, ["add", "."])
290+
git(repoDir, ["commit", "-m", "feat: add dependencies"])
291+
292+
const workspace = {
293+
id: "t",
294+
key: "TEST-7",
295+
path: resolve(repoDir, "TEST-7"),
296+
issueId: "t",
297+
branch: "feature/TEST-7",
298+
status: "running" as const,
299+
createdAt: new Date().toISOString(),
300+
}
301+
const result = await manager.mergeAndPush(workspace)
302+
303+
expect(result.ok).toBe(false)
304+
expect(result.error).toContain("conflict marker")
305+
306+
// Verify origin/main is untouched — still has original initial commit only
307+
const remoteLog = git(bareDir, ["log", "--oneline", "main"])
308+
expect(remoteLog).not.toContain("add dependencies")
309+
310+
// Verify local main is also clean
311+
git(repoDir, ["checkout", "main"])
312+
const localLog = git(repoDir, ["log", "--oneline"])
313+
expect(localLog).not.toContain("add dependencies")
314+
})
315+
316+
test("origin/main is never pushed when pre-rebase validation fails", async () => {
317+
// Record the remote main HEAD before the merge attempt
318+
const remoteHeadBefore = git(bareDir, ["rev-parse", "main"])
319+
320+
// Feature branch with conflict markers in multiple files
321+
git(repoDir, ["checkout", "-b", "feature/TEST-8"])
322+
writeFileSync(
323+
resolve(repoDir, "middleware.ts"),
324+
"<<<<<<< HEAD\nexport default {}\n=======\nexport default { auth: true }\n>>>>>>>\n",
325+
)
326+
writeFileSync(resolve(repoDir, "clean-file.ts"), "export const clean = true\n")
327+
git(repoDir, ["add", "."])
328+
git(repoDir, ["commit", "-m", "feat: add middleware"])
329+
330+
const workspace = {
331+
id: "t",
332+
key: "TEST-8",
333+
path: resolve(repoDir, "TEST-8"),
334+
issueId: "t",
335+
branch: "feature/TEST-8",
336+
status: "running" as const,
337+
createdAt: new Date().toISOString(),
338+
}
339+
const result = await manager.mergeAndPush(workspace)
340+
341+
expect(result.ok).toBe(false)
342+
343+
// The critical guarantee: origin/main HEAD has not moved
344+
const remoteHeadAfter = git(bareDir, ["rev-parse", "main"])
345+
expect(remoteHeadAfter).toBe(remoteHeadBefore)
346+
})
234347
})

0 commit comments

Comments
 (0)