import { EnvironmentId, ProjectId } from "@t3tools/contracts"; import { describe, expect, it } from "vite-plus/test"; import type { EnvironmentProject } from "@t3tools/client-runtime/state/shell"; import type { HomeProjectScope } from "../home/homeThreadList"; import { getProjectScopeSelectionTarget, resolveDraftProjectSelection, resolveEnvironmentProjectMatch, } from "./new-task-project-selection"; function makeProject( id: string, environmentId = "environment", options: { readonly title?: string; readonly workspaceRoot?: string; readonly repositoryKey?: string; } = {}, ): EnvironmentProject { return { environmentId: EnvironmentId.make(environmentId), id: ProjectId.make(id), title: options.title ?? id, workspaceRoot: options.workspaceRoot ?? `/work/${id}`, repositoryIdentity: options.repositoryKey ? { canonicalKey: options.repositoryKey, locator: { source: "git-remote", remoteName: "origin", remoteUrl: `https://${options.repositoryKey}.git`, }, } : null, defaultModelSelection: null, scripts: [], createdAt: "2026-07-01T00:00:00.000Z", updatedAt: "2026-07-01T00:00:00.000Z", }; } function makeScope(projects: ReadonlyArray): HomeProjectScope { return { key: "github.com/t3tools/t3code", title: "T3 Code", representative: projects[0]!, projects, projectRefs: projects.map((project) => ({ environmentId: project.environmentId, projectId: project.id, })), }; } describe("getProjectScopeSelectionTarget", () => { it("keeps the current environment when it hosts the selected logical project", () => { const projects = [makeProject("t3code-mac", "mac"), makeProject("t3code-server", "server")]; expect(getProjectScopeSelectionTarget(makeScope(projects), EnvironmentId.make("server"))).toBe( projects[1], ); }); it("falls back to the representative when the current environment does not host the project", () => { const projects = [makeProject("t3code-mac", "mac"), makeProject("t3code-server", "server")]; expect(getProjectScopeSelectionTarget(makeScope(projects), EnvironmentId.make("other"))).toBe( projects[0], ); }); }); describe("resolveEnvironmentProjectMatch", () => { it("follows the same repository onto the target machine", () => { const selected = makeProject("t3code", "mac", { repositoryKey: "github.com/t3tools/t3code" }); const target = [ makeProject("other", "server", { repositoryKey: "github.com/t3tools/other" }), makeProject("t3code-clone", "server", { repositoryKey: "github.com/t3tools/t3code" }), ]; expect(resolveEnvironmentProjectMatch(target, selected)).toBe(target[1]); }); it("falls back to workspace basename, then title, for unindexed projects", () => { const selected = makeProject("t3code", "mac", { workspaceRoot: "/Users/me/t3code" }); const byBasename = [ makeProject("other", "server"), makeProject("srv", "server", { workspaceRoot: "/home/me/t3code" }), ]; expect(resolveEnvironmentProjectMatch(byBasename, selected)).toBe(byBasename[1]); const byTitle = [ makeProject("other", "server"), makeProject("srv", "server", { title: "t3code" }), ]; expect(resolveEnvironmentProjectMatch(byTitle, selected)).toBe(byTitle[1]); }); it("does not treat a known different repository as a basename or title match", () => { const selected = makeProject("t3code", "mac", { repositoryKey: "github.com/t3tools/t3code", workspaceRoot: "/Users/me/t3code", }); const fork = makeProject("fork", "server", { repositoryKey: "github.com/someone/t3code", title: "t3code", workspaceRoot: "/home/me/t3code", }); const unindexed = makeProject("unindexed", "server", { workspaceRoot: "/srv/t3code" }); expect(resolveEnvironmentProjectMatch([fork, unindexed], selected)).toBe(unindexed); // Without any weaker match the fork is still the first-project fallback. expect(resolveEnvironmentProjectMatch([fork], selected)).toBe(fork); }); it("falls back to the first project on the target so the draft has a key to carry over to", () => { const selected = makeProject("t3code", "mac", { repositoryKey: "github.com/t3tools/t3code" }); const target = [makeProject("unrelated", "server"), makeProject("also-unrelated", "server")]; expect(resolveEnvironmentProjectMatch(target, selected)).toBe(target[0]); expect(resolveEnvironmentProjectMatch([], selected)).toBeNull(); }); }); describe("resolveDraftProjectSelection", () => { it("preserves an explicit project selection", () => { const project = makeProject("t3code"); expect( resolveDraftProjectSelection("environment:t3code", [project], [makeScope([project])]), ).toEqual({ kind: "preserve" }); }); it("selects the only physical project when no project was explicitly selected", () => { const project = makeProject("t3code"); expect(resolveDraftProjectSelection(null, [project], [makeScope([project])])).toEqual({ kind: "select", project, }); }); it("selects one logical project even when it has multiple physical workspaces", () => { const projects = [makeProject("t3code"), makeProject("t3code-2"), makeProject("t3code-3")]; expect(resolveDraftProjectSelection(null, projects, [makeScope(projects)])).toEqual({ kind: "select", project: projects[0], }); }); it("does not preserve a project key that is missing from the catalog", () => { const project = makeProject("t3code"); expect( resolveDraftProjectSelection("environment:removed", [project], [makeScope([project])]), ).toEqual({ kind: "select", project, }); }); });