The web N path sent the generated handle as the session name as well as the worktree branch, so the session was born named and never got its Haiku name from its first prompt. The TUI already spawns unnamed (#131); the handle now only seeds the branch.
133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
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>): 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("");
|
|
});
|
|
});
|