public/Add-WtwEntry.ps1

function Add-WtwEntry {
    <#
    .SYNOPSIS
        Adopt an existing on-disk git worktree into wtw with full registration.
    .DESCRIPTION
        For a worktree directory that already exists (created by `git worktree
        add` outside wtw, or inherited from elsewhere). Wires it up with the
        same metadata that `wtw create` produces: color, workspace file from
        the repo template, pretty name with color circle, and registration
        in cmux / Codex / Superset / SourceGit / agentctl. Does NOT touch git
        — no branch is created, the worktree directory itself is left alone.

        Auto-detects the parent repo from the worktree's `.git` pointer file
        when -Repo is omitted. Use `wtw init` from inside the main checkout
        first if the parent repo isn't registered yet.
    .PARAMETER Path
        Path to the worktree directory (default: current directory).
    .PARAMETER Repo
        Parent repo alias. Auto-detected from the worktree's `.git` pointer
        when possible.
    .PARAMETER Task
        Registry key under the parent repo. Defaults to the worktree folder
        name (with the `${repoName}_` prefix stripped, if present).
    .PARAMETER Branch
        Override the branch name (default: auto-detected from git).
    .PARAMETER PrettyName
        Human-readable display name. A color-circle emoji is prepended
        automatically. Defaults to the folder suffix.
    .PARAMETER Color
        Color assignment. Same input format as `wtw create --color`: 'random'
        (default), '#rrggbb' / 'rrggbb', or a palette name.
    .EXAMPLE
        wtw add /path/to/snowmain1_foo --task foo
        Adopt an existing worktree as task 'foo' under its auto-detected parent.
        Generates the workspace file, picks a color, registers with cmux/SourceGit/etc.
    .EXAMPLE
        cd ../snowmain1_foo ; wtw add --task foo --color "forest green"
        Same, run from inside the worktree, with an explicit color.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Position = 0)]
        [string] $Path,

        [string] $Repo,
        [string] $Task,
        [string] $Branch,
        [string] $PrettyName,
        [string] $Color
    )

    if (-not $Path) { $Path = (Get-Location).Path }
    $Path = [System.IO.Path]::GetFullPath($Path)

    if (-not (Test-Path $Path)) {
        Write-Error "Path does not exist: $Path"
        return
    }

    $gitDir = Join-Path $Path '.git'
    if (-not (Test-Path $gitDir)) {
        Write-Error "Not a git repository: $Path"
        return
    }

    $dirName = Split-Path $Path -Leaf
    Write-Host " Path: $Path" -ForegroundColor Cyan

    # A worktree has a .git *file* (gitdir pointer); a primary checkout has
    # a .git *directory*. We only adopt worktrees here — use `wtw init` for
    # the primary checkout.
    $isWorktree = (Test-Path $gitDir -PathType Leaf)
    if (-not $isWorktree) {
        Write-Host " This is a primary checkout, not a worktree." -ForegroundColor Cyan
        Write-Host " Run 'wtw init' from inside it to register as a main repo." -ForegroundColor DarkGray
        return
    }

    # Auto-detect parent repo by asking git for the main worktree path —
    # `git worktree list --porcelain` always lists the primary checkout
    # first. Compare via realpath so symlink chains collapse (macOS routes
    # `/var/folders` and `/tmp` through `/private`, so `git`'s output and
    # the registry can end up referring to the same dir via different
    # strings).
    if (-not $Repo) {
        $porcelain = git -C $Path worktree list --porcelain 2>&1
        $parentRepoPath = $null
        if ($LASTEXITCODE -eq 0) {
            $first = ($porcelain -split "`n" | Select-String -Pattern '^worktree (.+)$' | Select-Object -First 1)
            if ($first) { $parentRepoPath = $first.Matches.Groups[1].Value.Trim() }
        }
        if (-not $parentRepoPath) {
            Write-Error "Could not determine main worktree path for $Path. Pass --repo <alias> explicitly."
            return
        }

        $parentCanonical = Resolve-WtwRealPath $parentRepoPath
        $registry = Get-WtwRegistry
        foreach ($name in $registry.repos.PSObject.Properties.Name) {
            $r = $registry.repos.$name
            $rCanonical = Resolve-WtwRealPath $r.mainPath
            if ($rCanonical -eq $parentCanonical) {
                $Repo = $name
                Write-Host " Detected parent repo: $Repo ($($r.mainPath))" -ForegroundColor Cyan
                break
            }
        }
        if (-not $Repo) {
            Write-Error "Parent repo at '$parentRepoPath' is not in the wtw registry. Run 'wtw init' from there first, or pass --repo <alias>."
            return
        }
    }

    $registry = Get-WtwRegistry
    if ($registry.repos.PSObject.Properties.Name -notcontains $Repo) {
        Write-Error "Repo '$Repo' not in registry. Run 'wtw init' from the main repo first."
        return
    }
    $repoEntry = $registry.repos.$Repo

    # Default Task to the folder name with the `${repo}_` prefix stripped
    # (matches wtw create's folder convention).
    if (-not $Task) {
        $Task = $dirName -replace "^${Repo}_", ''
        Write-Host " Task name: $Task" -ForegroundColor DarkGray
    }

    if ($repoEntry.worktrees.PSObject.Properties.Name -contains $Task) {
        Write-Error "Worktree '$Task' is already registered under '$Repo'. Use 'wtw remove $Task' first, or pick a different --task."
        return
    }

    if (-not $Branch) {
        $Branch = git -C $Path branch --show-current 2>$null
        if (-not $Branch) { $Branch = '(detached)' }
    }
    Write-Host " Branch: $Branch" -ForegroundColor Green

    # FolderSuffix is what `wtw create` would have used — drives the workspace
    # filename. Strip the repo prefix when the dir follows the standard pattern.
    $folderSuffix = $dirName -replace "^${Repo}_", ''
    if (-not $folderSuffix) { $folderSuffix = $dirName }

    $meta = Initialize-WtwWorktreeMetadata `
        -RepoName $Repo -RepoEntry $repoEntry `
        -Task $Task -Branch $Branch `
        -WorktreePath $Path -FolderSuffix $folderSuffix `
        -PrettyName $PrettyName -Color $Color

    if (-not $meta.Success) { return }

    Write-Host ''
    Write-Host " Adopted '$Task' under $Repo. Use 'wtw go $Task' to switch." -ForegroundColor Green
}