diff --git a/packages/tm-core/src/services/preflight-checker.service.ts b/packages/tm-core/src/services/preflight-checker.service.ts index 9531ee92..30ff45e2 100644 --- a/packages/tm-core/src/services/preflight-checker.service.ts +++ b/packages/tm-core/src/services/preflight-checker.service.ts @@ -3,7 +3,7 @@ * Validates environment and prerequisites for autopilot execution */ -import { readFileSync, existsSync } from 'fs'; +import { readFileSync, existsSync, readdirSync } from 'fs'; import { join } from 'path'; import { execSync } from 'child_process'; import { getLogger } from '../logger/factory.js'; @@ -169,10 +169,8 @@ export class PreflightChecker { if (existsSync(join(this.projectRoot, 'Cargo.toml'))) types.push('rust'); if (existsSync(join(this.projectRoot, 'composer.json'))) types.push('php'); if (existsSync(join(this.projectRoot, 'Gemfile'))) types.push('ruby'); - if ( - existsSync(join(this.projectRoot, '*.csproj')) || - existsSync(join(this.projectRoot, '*.sln')) - ) + const files = readdirSync(this.projectRoot); + if (files.some((f) => f.endsWith('.csproj') || f.endsWith('.sln'))) types.push('dotnet'); return types; diff --git a/packages/tm-core/src/utils/git-utils.ts b/packages/tm-core/src/utils/git-utils.ts index 5dacc803..722614c2 100644 --- a/packages/tm-core/src/utils/git-utils.ts +++ b/packages/tm-core/src/utils/git-utils.ts @@ -326,3 +326,83 @@ export function isValidBranchForTag(branchName: string): boolean { const sanitized = sanitizeBranchNameForTag(branchName); return sanitized.length > 0 && sanitized !== 'unknown-branch'; } + +/** + * Git worktree information + */ +export interface GitWorktree { + path: string; + branch: string | null; + head: string; +} + +/** + * Get list of all git worktrees + */ +export async function getWorktrees( + projectRoot: string +): Promise { + if (!projectRoot) { + throw new Error('projectRoot is required for getWorktrees'); + } + + try { + const { stdout } = await execAsync('git worktree list --porcelain', { + cwd: projectRoot + }); + + const worktrees: GitWorktree[] = []; + const lines = stdout.trim().split('\n'); + let current: Partial = {}; + + for (const line of lines) { + if (line.startsWith('worktree ')) { + current.path = line.substring(9); + } else if (line.startsWith('HEAD ')) { + current.head = line.substring(5); + } else if (line.startsWith('branch ')) { + current.branch = line.substring(7).replace('refs/heads/', ''); + } else if (line === '' && current.path) { + worktrees.push({ + path: current.path, + branch: current.branch || null, + head: current.head || '' + }); + current = {}; + } + } + + // Handle last entry if no trailing newline + if (current.path) { + worktrees.push({ + path: current.path, + branch: current.branch || null, + head: current.head || '' + }); + } + + return worktrees; + } catch (error) { + return []; + } +} + +/** + * Check if a branch is checked out in any worktree + * Returns the worktree path if found, null otherwise + */ +export async function isBranchCheckedOut( + projectRoot: string, + branchName: string +): Promise { + if (!projectRoot) { + throw new Error('projectRoot is required for isBranchCheckedOut'); + } + if (!branchName) { + throw new Error('branchName is required for isBranchCheckedOut'); + } + + const worktrees = await getWorktrees(projectRoot); + const worktree = worktrees.find((wt) => wt.branch === branchName); + return worktree ? worktree.path : null; +} diff --git a/scripts/create-worktree.sh b/scripts/create-worktree.sh index 2674104f..f144df93 100755 --- a/scripts/create-worktree.sh +++ b/scripts/create-worktree.sh @@ -44,8 +44,11 @@ fi # Create worktree (new or existing branch) if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then git worktree add "$WORKTREE_PATH" "$BRANCH_NAME" -elif git ls-remote --exit-code --heads origin "$BRANCH_NAME" >/dev/null 2>&1; then - git worktree add "$WORKTREE_PATH" "origin/$BRANCH_NAME" +elif git remote get-url origin >/dev/null 2>&1 && git ls-remote --exit-code --heads origin "$BRANCH_NAME" >/dev/null 2>&1; then + # Create a local branch from the remote and attach worktree + git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" "origin/$BRANCH_NAME" + # Ensure the new branch tracks the remote + git -C "$WORKTREE_PATH" branch --set-upstream-to="origin/$BRANCH_NAME" "$BRANCH_NAME" else git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" fi