import { describe, expect, it } from "vitest"; import { buildFastForwardRequest, fastForwardSeed, resolveFastForward, } from "./fastForward.js"; import type { Project, SpawnPreset } from "./types.js"; const presets: SpawnPreset[] = [ { id: "custom", label: "Custom…", command: "" }, { id: "claude", label: "Claude", command: "claude" }, ]; function project(overrides: Partial): Project { return { path: "/repos/p", name: "p", last_activity: new Date().toISOString(), ...overrides, }; } describe("resolveFastForward (#67)", () => { it("resolves every default from the most recent project", () => { const projects = [ project({ path: "/repos/old", name: "old", last_activity: "2020-01-01T00:00:00Z" }), project({ path: "/repos/fresh", name: "fresh", base_repo: "/repos/fresh", last_command: "aider", }), ]; const res = resolveFastForward(projects, presets, "amber-falcon"); expect(res.project?.path).toBe("/repos/fresh"); expect(res.command).toBe("aider"); expect(res.handle).toBe("amber-falcon"); const req = buildFastForwardRequest(res)!; expect(req.cwd).toBe("/repos/fresh"); expect(req.command).toBe("aider"); // No name (#131): the daemon names the session after its first prompt, // and a name here would collide with the branch handle. expect(req.metadata).toBeUndefined(); expect(req.worktree).toEqual({ base_repo: "/repos/fresh", branch: "amber-falcon", create_branch: true, }); }); it("prefers the focused session's project over the freshest one", () => { const projects = [ project({ path: "/repos/fresh", name: "fresh", last_command: "claude" }), project({ path: "/repos/current", name: "current", last_activity: "2020-01-01T00:00:00Z", last_command: "zsh", }), ]; const res = resolveFastForward(projects, presets, "n", "/repos/current"); expect(res.project?.path).toBe("/repos/current"); expect(res.command).toBe("zsh"); }); it("falls back to the freshest project when the focused cwd is unknown", () => { const projects = [ project({ path: "/repos/old", name: "old", last_activity: "2020-01-01T00:00:00Z" }), project({ path: "/repos/fresh", name: "fresh" }), ]; const res = resolveFastForward(projects, presets, "n", "/repos/gone"); expect(res.project?.path).toBe("/repos/fresh"); }); it("falls back to the first non-custom preset when there is no last command", () => { const res = resolveFastForward([project({ last_command: undefined })], presets, "n"); expect(res.command).toBe("claude"); }); it("treats an empty last command as no command", () => { const res = resolveFastForward([project({ last_command: "" })], [presets[0]], "n"); expect(res.command).toBeUndefined(); expect(buildFastForwardRequest(res)).toBeNull(); }); it("resolves nothing when no projects are known yet", () => { const res = resolveFastForward([], presets, "n"); expect(res.project).toBeUndefined(); expect(buildFastForwardRequest(res)).toBeNull(); }); it("downgrades to a draft when the generated handle is missing", () => { const res = resolveFastForward([project({ last_command: "claude" })], presets); expect(res.handle).toBeUndefined(); expect(buildFastForwardRequest(res)).toBeNull(); }); it("seeds the fallback draft with whatever did resolve", () => { const res = resolveFastForward( [project({ path: "/repos/p", base_repo: "/repos/p", last_command: "aider" })], presets, ); expect(fastForwardSeed(res)).toEqual({ cwd: "/repos/p", command: "aider", name: "", worktreeEnabled: true, worktreeBranch: undefined, }); }); it("seeds the handle as the branch and leaves the name field empty (#131)", () => { const res = resolveFastForward( [project({ path: "/repos/p", base_repo: "/repos/p", last_command: "aider" })], presets, "amber-falcon", ); const seed = fastForwardSeed(res); expect(seed.name).toBe(""); expect(seed.worktreeBranch).toBe("amber-falcon"); }); it("leaves the worktree default alone when not even a project resolved", () => { // Not `false`: the form defaults the toggle on and a false would stick, // so the fallback draft would disagree with a normally-opened draft and // with the TUI's fast path. const seed = fastForwardSeed(resolveFastForward([], presets)); expect(seed.worktreeEnabled).toBeUndefined(); expect(seed.cwd).toBe(""); }); });