1import type { EnvironmentProject } from "@t3tools/client-runtime/state/shell";
2import type { VcsRef } from "@t3tools/client-runtime/state/vcs";
3import {
4 type AtomCommandResult,
5 mapAtomCommandResult,
6} from "@t3tools/client-runtime/state/runtime";
7import type { VcsSwitchRefInput, VcsSwitchRefResult } from "@t3tools/contracts";
8import * as Cause from "effect/Cause";
9import { AsyncResult } from "effect/reactivity";
10
11import { shouldCheckoutNewTaskBranch } from "./new-task-context-presentation";
12
13/** Resolve a composer branch only after its checkout succeeds. Existing worktrees
14 * and new-worktree base selections already identify a separate workspace. */
15export async function checkoutNewTaskBranch<E>(input: {
16 readonly branch: VcsRef;
17 readonly project: Pick<EnvironmentProject, "environmentId" | "workspaceRoot"> | null;
18 readonly workspaceMode: "local" | "worktree";
19 readonly switchRef: (request: {
20 readonly environmentId: EnvironmentProject["environmentId"];
21 readonly input: VcsSwitchRefInput;
22 }) => Promise<AtomCommandResult<VcsSwitchRefResult, E>>;
23}): Promise<AtomCommandResult<VcsRef, E | Error>> {
24 if (!input.project) {
25 return AsyncResult.failure(
26 Cause.fail(new Error("The selected project is unavailable. Reconnect and try again.")),
27 );
28 }
29 if (
30 !shouldCheckoutNewTaskBranch({
31 branchIsCurrent: input.branch.current,
32 branchWorktreePath: input.branch.worktreePath,
33 workspaceMode: input.workspaceMode,
34 })
35 ) {
36 return AsyncResult.success(input.branch);
37 }
38
39 const result = await input.switchRef({
40 environmentId: input.project.environmentId,
41 input: { cwd: input.project.workspaceRoot, refName: input.branch.name },
42 });
43 return mapAtomCommandResult(result, (value) => ({
44 ...input.branch,
45 current: true,
46 isRemote: false,
47 name: value.refName ?? input.branch.name,
48 }));
49}