import { describe, expect, it } from "vitest"; import { DEFAULT_THREAD_TERMINAL_HEIGHT, DEFAULT_THREAD_TERMINAL_ID, type Thread } from "./types";import { formatWorktreePathForDisplay, getOrphanedWorktreePathForThread } from "./worktreeCleanup"; function makeThread(overrides: Partial<Thread> = {}): Thread { return { id: "thread-1", codexThreadId: null, projectId: "project-1", title: "Thread", model: "gpt-5.3-codex", terminalOpen: false, terminalHeight: DEFAULT_THREAD_TERMINAL_HEIGHT, terminalIds: [DEFAULT_THREAD_TERMINAL_ID], runningTerminalIds: [], activeTerminalId: DEFAULT_THREAD_TERMINAL_ID, terminalGroups: [ { id: `group-${DEFAULT_THREAD_TERMINAL_ID}`, terminalIds: [DEFAULT_THREAD_TERMINAL_ID], }, ], activeTerminalGroupId: `group-${DEFAULT_THREAD_TERMINAL_ID}`, session: null, messages: [], events: [], error: null, createdAt: "2026-02-13T00:00:00.000Z", branch: null, worktreePath: null, ...overrides, };} describe("getOrphanedWorktreePathForThread", () => { it("returns null when the target thread does not exist", () => { const result = getOrphanedWorktreePathForThread([], "missing-thread"); expect(result).toBeNull(); }); it("returns null when the target thread has no worktree", () => { const threads = [makeThread()]; const result = getOrphanedWorktreePathForThread(threads, "thread-1"); expect(result).toBeNull(); }); it("returns the path when no other thread links to that worktree", () => { const threads = [makeThread({ worktreePath: "/tmp/repo/worktrees/feature-a" })]; const result = getOrphanedWorktreePathForThread(threads, "thread-1"); expect(result).toBe("/tmp/repo/worktrees/feature-a"); }); it("returns null when another thread links to the same worktree", () => { const threads = [ makeThread({ id: "thread-1", worktreePath: "/tmp/repo/worktrees/feature-a" }), makeThread({ id: "thread-2", worktreePath: "/tmp/repo/worktrees/feature-a" }), ]; const result = getOrphanedWorktreePathForThread(threads, "thread-1"); expect(result).toBeNull(); }); it("ignores threads linked to different worktrees", () => { const threads = [ makeThread({ id: "thread-1", worktreePath: "/tmp/repo/worktrees/feature-a" }), makeThread({ id: "thread-2", worktreePath: "/tmp/repo/worktrees/feature-b" }), ]; const result = getOrphanedWorktreePathForThread(threads, "thread-1"); expect(result).toBe("/tmp/repo/worktrees/feature-a"); });}); describe("formatWorktreePathForDisplay", () => { it("shows only the last path segment for unix-like paths", () => { const result = formatWorktreePathForDisplay( "/Users/julius/.t3/worktrees/codething-mvp/codething-4e609bb8", ); expect(result).toBe("codething-4e609bb8"); }); it("normalizes windows separators before selecting the final segment", () => { const result = formatWorktreePathForDisplay( "C:\\Users\\julius\\.t3\\worktrees\\codething-mvp\\codething-4e609bb8", ); expect(result).toBe("codething-4e609bb8"); }); it("uses the final segment even when outside ~/.t3/worktrees", () => { const result = formatWorktreePathForDisplay("/tmp/custom-worktrees/my-worktree"); expect(result).toBe("my-worktree"); }); it("ignores trailing slashes", () => { const result = formatWorktreePathForDisplay("/tmp/custom-worktrees/my-worktree/"); expect(result).toBe("my-worktree"); });});
import { describe, expect, it } from "vitest";
import { DEFAULT_THREAD_TERMINAL_HEIGHT, DEFAULT_THREAD_TERMINAL_ID, type Thread } from "./types";
import { formatWorktreePathForDisplay, getOrphanedWorktreePathForThread } from "./worktreeCleanup";
function makeThread(overrides: Partial<Thread> = {}): Thread {
return {
id: "thread-1",
codexThreadId: null,
projectId: "project-1",
title: "Thread",
model: "gpt-5.3-codex",
terminalOpen: false,
terminalHeight: DEFAULT_THREAD_TERMINAL_HEIGHT,
terminalIds: [DEFAULT_THREAD_TERMINAL_ID],
runningTerminalIds: [],
activeTerminalId: DEFAULT_THREAD_TERMINAL_ID,
terminalGroups: [
{
id: `group-${DEFAULT_THREAD_TERMINAL_ID}`,
terminalIds: [DEFAULT_THREAD_TERMINAL_ID],
},
],
activeTerminalGroupId: `group-${DEFAULT_THREAD_TERMINAL_ID}`,
session: null,
messages: [],
events: [],
error: null,
createdAt: "2026-02-13T00:00:00.000Z",
branch: null,
worktreePath: null,
...overrides,
};
}
describe("getOrphanedWorktreePathForThread", () => {
it("returns null when the target thread does not exist", () => {
const result = getOrphanedWorktreePathForThread([], "missing-thread");
expect(result).toBeNull();
});
it("returns null when the target thread has no worktree", () => {
const threads = [makeThread()];
const result = getOrphanedWorktreePathForThread(threads, "thread-1");
expect(result).toBeNull();
});
it("returns the path when no other thread links to that worktree", () => {
const threads = [makeThread({ worktreePath: "/tmp/repo/worktrees/feature-a" })];
const result = getOrphanedWorktreePathForThread(threads, "thread-1");
expect(result).toBe("/tmp/repo/worktrees/feature-a");
});
it("returns null when another thread links to the same worktree", () => {
const threads = [
makeThread({ id: "thread-1", worktreePath: "/tmp/repo/worktrees/feature-a" }),
makeThread({ id: "thread-2", worktreePath: "/tmp/repo/worktrees/feature-a" }),
];
const result = getOrphanedWorktreePathForThread(threads, "thread-1");
expect(result).toBeNull();
});
it("ignores threads linked to different worktrees", () => {
const threads = [
makeThread({ id: "thread-1", worktreePath: "/tmp/repo/worktrees/feature-a" }),
makeThread({ id: "thread-2", worktreePath: "/tmp/repo/worktrees/feature-b" }),
];
const result = getOrphanedWorktreePathForThread(threads, "thread-1");
expect(result).toBe("/tmp/repo/worktrees/feature-a");
});
});
describe("formatWorktreePathForDisplay", () => {
it("shows only the last path segment for unix-like paths", () => {
const result = formatWorktreePathForDisplay(
"/Users/julius/.t3/worktrees/codething-mvp/codething-4e609bb8",
);
expect(result).toBe("codething-4e609bb8");
});
it("normalizes windows separators before selecting the final segment", () => {
const result = formatWorktreePathForDisplay(
"C:\\Users\\julius\\.t3\\worktrees\\codething-mvp\\codething-4e609bb8",
);
expect(result).toBe("codething-4e609bb8");
});
it("uses the final segment even when outside ~/.t3/worktrees", () => {
const result = formatWorktreePathForDisplay("/tmp/custom-worktrees/my-worktree");
expect(result).toBe("my-worktree");
});
it("ignores trailing slashes", () => {
const result = formatWorktreePathForDisplay("/tmp/custom-worktrees/my-worktree/");
expect(result).toBe("my-worktree");
});
});