1import { sanitizeNewRefName } from "@t3tools/shared/git";
2import { parseChangeRequestUrl } from "@t3tools/shared/changeRequestUrl";
3
4type WorkspaceMode = "local" | "worktree";
5
6export function resolveNewTaskWorkspaceLabel(input: {
7 readonly workspaceMode: WorkspaceMode;
8 readonly worktreePath: string | null;
9}): "Current checkout" | "Current worktree" | "New worktree" {
10 if (input.workspaceMode === "worktree") {
11 return "New worktree";
12 }
13 return input.worktreePath ? "Current worktree" : "Current checkout";
14}
15
16export function resolveNewTaskBranchWorktreePath(input: {
17 readonly workspaceMode: WorkspaceMode;
18 readonly projectCwd: string;
19 readonly branchWorktreePath: string | null | undefined;
20}): string | null {
21 if (
22 input.workspaceMode === "worktree" ||
23 !input.branchWorktreePath ||
24 input.branchWorktreePath === input.projectCwd
25 ) {
26 return null;
27 }
28 return input.branchWorktreePath;
29}
30
31export function resolveNewTaskLocalWorkspaceSelection(input: {
32 readonly branches: ReadonlyArray<{
33 readonly name: string;
34 readonly current: boolean;
35 readonly worktreePath?: string | null;
36 }>;
37 readonly projectCwd: string;
38}): {
39 readonly branch: string | null;
40 readonly worktreePath: string | null;
41 readonly awaitsCurrentBranch: boolean;
42} {
43 const currentBranch = input.branches.find((branch) => branch.current) ?? null;
44 if (!currentBranch) {
45 return {
46 branch: null,
47 worktreePath: null,
48 awaitsCurrentBranch: true,
49 };
50 }
51
52 return {
53 branch: currentBranch.name,
54 worktreePath: resolveNewTaskBranchWorktreePath({
55 workspaceMode: "local",
56 projectCwd: input.projectCwd,
57 branchWorktreePath: currentBranch.worktreePath,
58 }),
59 awaitsCurrentBranch: false,
60 };
61}
62
63export function resolveNewTaskBranchLabel(input: {
64 readonly branchName: string | null;
65 readonly startFromOrigin: boolean;
66 readonly workspaceMode: WorkspaceMode;
67 readonly pullRequestReference?: string;
68}): string {
69 if (input.workspaceMode === "worktree" && input.pullRequestReference) {
70 const pr = parseChangeRequestUrl(input.pullRequestReference);
71 if (pr) return `From PR #${pr.number}`;
72 }
73 if (!input.branchName) {
74 return "Choose branch";
75 }
76
77 if (input.workspaceMode === "local") {
78 return input.branchName;
79 }
80
81 const baseRef = input.startFromOrigin ? `origin/${input.branchName}` : input.branchName;
82 return `From ${baseRef}`;
83}
84
85export function shouldCheckoutNewTaskBranch(input: {
86 readonly branchIsCurrent: boolean;
87 readonly branchWorktreePath: string | null | undefined;
88 readonly workspaceMode: WorkspaceMode;
89}): boolean {
90 return input.workspaceMode === "local" && !input.branchIsCurrent && !input.branchWorktreePath;
91}
92
93export function filterNewTaskBranches<T extends { readonly name: string }>(
94 branches: ReadonlyArray<T>,
95 rawQuery: string,
96): ReadonlyArray<T> {
97 const query = sanitizeNewRefName(rawQuery).toLowerCase();
98 return query.length === 0
99 ? branches
100 : branches.filter((branch) => branch.name.toLowerCase().includes(query));
101}