feat(core,engine): split smart merge strategy into prefer-main / prefer-branch
The single "smart" strategy is now two flavors with the new default flipped to prefer-main. Both share a pre-cascade `git fetch origin <currentBranch>` + best-effort fast-forward so a freshly-pushed sibling commit doesn't get clobbered when the fallback resolves a conflict against a stale base. - "smart-prefer-main" (new default): -X ours fallback. Protects just-merged sibling work from being regressed by a concurrent task branch. - "smart-prefer-branch": -X theirs fallback. Equivalent to legacy "smart". Legacy "smart" / "prefer-main" enum values are accepted and normalized via `normalizeMergeConflictStrategy()` so existing settings.json files migrate seamlessly. The fast-forward step gracefully degrades on fetch failure or divergent local main (logs and continues). Updates settings UI dropdown, test helpers, and adds 5 fetch+ff regression tests + 7 normalize-helper tests. Lint cleanup of two empty catch blocks in scripts/release.mjs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
32
packages/core/src/__tests__/merge-conflict-strategy.test.ts
Normal file
32
packages/core/src/__tests__/merge-conflict-strategy.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeMergeConflictStrategy } from "../types.js";
|
||||
|
||||
describe("normalizeMergeConflictStrategy", () => {
|
||||
it("maps legacy 'smart' to 'smart-prefer-branch'", () => {
|
||||
expect(normalizeMergeConflictStrategy("smart")).toBe("smart-prefer-branch");
|
||||
});
|
||||
|
||||
it("maps legacy 'prefer-main' to 'smart-prefer-main'", () => {
|
||||
expect(normalizeMergeConflictStrategy("prefer-main")).toBe("smart-prefer-main");
|
||||
});
|
||||
|
||||
it("returns 'smart-prefer-main' as the default when undefined", () => {
|
||||
expect(normalizeMergeConflictStrategy(undefined)).toBe("smart-prefer-main");
|
||||
});
|
||||
|
||||
it("passes through canonical 'smart-prefer-main'", () => {
|
||||
expect(normalizeMergeConflictStrategy("smart-prefer-main")).toBe("smart-prefer-main");
|
||||
});
|
||||
|
||||
it("passes through canonical 'smart-prefer-branch'", () => {
|
||||
expect(normalizeMergeConflictStrategy("smart-prefer-branch")).toBe("smart-prefer-branch");
|
||||
});
|
||||
|
||||
it("passes through 'ai-only' unchanged", () => {
|
||||
expect(normalizeMergeConflictStrategy("ai-only")).toBe("ai-only");
|
||||
});
|
||||
|
||||
it("passes through 'abort' unchanged", () => {
|
||||
expect(normalizeMergeConflictStrategy("abort")).toBe("abort");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user