* Get or create a worktree
(params: GetOrCreateWorkTreeParams)
| 626 | * Get or create a worktree |
| 627 | */ |
| 628 | async function handleGetOrCreateWorkTree(params: GetOrCreateWorkTreeParams): Promise<GetOrCreateWorkTreeResponse> { |
| 629 | const startTime = Date.now() |
| 630 | logger.info("[Git:getOrCreateWorkTree] Processing worktree request", JSON.stringify({ |
| 631 | repoDir: params.repoDir, |
| 632 | id: params.id, |
| 633 | sourceTreeish: params.sourceTreeish, |
| 634 | })) |
| 635 | |
| 636 | try { |
| 637 | validateRepoDir(params.repoDir) |
| 638 | validateWorkTreeId(params.id) |
| 639 | |
| 640 | // Resolve git info (handles subdirectories) |
| 641 | const { repoRoot, relativePath } = await resolveGitInfo(params.repoDir) |
| 642 | logger.info("[Git:getOrCreateWorkTree] Resolved subdirectory", JSON.stringify({ |
| 643 | input: params.repoDir, |
| 644 | repoRoot, |
| 645 | relativePath: relativePath || "(root)", |
| 646 | })) |
| 647 | |
| 648 | const worktreePath = getWorktreePath(params.id) |
| 649 | const baseDir = getWorktreeBaseDir() |
| 650 | |
| 651 | // Calculate matching directory (worktree root + relative path) |
| 652 | const matchingDir = relativePath ? path.join(worktreePath, relativePath) : worktreePath |
| 653 | logger.info("[Git:getOrCreateWorkTree] Matching directory", JSON.stringify({ matchingDir })) |
| 654 | |
| 655 | // Ensure base directory exists |
| 656 | await fsExtra.ensureDir(baseDir) |
| 657 | logger.info("[Git:getOrCreateWorkTree] Base directory ensured", JSON.stringify({ baseDir })) |
| 658 | |
| 659 | // Check if worktree already exists |
| 660 | const expectedBranchName = `refs/heads/openade/${params.id}` |
| 661 | const listResult = await execGit(["worktree", "list", "--porcelain"], repoRoot) |
| 662 | if (listResult.success) { |
| 663 | const existingWorktrees = parseWorktreeList(listResult.stdout) |
| 664 | const existing = existingWorktrees.find((wt) => wt.path === worktreePath) |
| 665 | if (existing) { |
| 666 | // Check if the worktree is on the correct branch |
| 667 | if (existing.branch === expectedBranchName) { |
| 668 | logger.info("[Git:getOrCreateWorkTree] Worktree already exists on correct branch", JSON.stringify({ |
| 669 | worktreePath, |
| 670 | matchingDir, |
| 671 | branch: existing.branch, |
| 672 | duration: Date.now() - startTime |
| 673 | })) |
| 674 | return { worktreeDir: worktreePath, matchingDir, created: false } |
| 675 | } else { |
| 676 | // Worktree exists but on wrong branch - remove and recreate |
| 677 | logger.info("[Git:getOrCreateWorkTree] Worktree exists on wrong branch, removing", JSON.stringify({ |
| 678 | worktreePath, |
| 679 | existingBranch: existing.branch, |
| 680 | expectedBranch: expectedBranchName |
| 681 | })) |
| 682 | await execGit(["worktree", "remove", worktreePath, "--force"], repoRoot) |
| 683 | // Also try to remove directory manually |
| 684 | try { |
| 685 | await fsExtra.remove(worktreePath) |
no test coverage detected