private/Get-WtwCmuxWorkspaceGroup.ps1
|
function ConvertTo-WtwCmuxGroupSlug { <# .SYNOPSIS Stable token for a cmux group idempotency key. #> [CmdletBinding()] param([AllowNull()][AllowEmptyString()][string] $Value) $slug = ("$Value").Trim().ToLowerInvariant() $slug = $slug -replace '[^a-z0-9]+', '-' $slug = $slug.Trim('-') if (-not $slug) { return 'unknown' } return $slug } function ConvertTo-WtwCmuxGroupKey { <# .SYNOPSIS Idempotency key ``wtw.group.<machine>.<repo>`` (repo omitted for host-home). #> [CmdletBinding()] param( [Parameter(Mandatory)][string] $MachineId, [AllowNull()][AllowEmptyString()][string] $RepoId ) $machine = ConvertTo-WtwCmuxGroupSlug -Value $MachineId if ($RepoId) { return "wtw.group.$machine.$(ConvertTo-WtwCmuxGroupSlug -Value $RepoId)" } return "wtw.group.$machine" } function Format-WtwCmuxGroupName { <# .SYNOPSIS Sidebar title ``🍏SP/🎸 snowmain1`` or ``🧊AT`` when there is no repo. #> [CmdletBinding()] param( [Parameter(Mandatory)][string] $MachineBadge, [AllowNull()][AllowEmptyString()][string] $ProjectName ) if ($ProjectName) { return "$MachineBadge/$ProjectName" } return $MachineBadge } function Get-WtwCmuxWorkspaceGroupCwd { [CmdletBinding()] param([AllowNull()][AllowEmptyString()][string] $Preferred) if ($Preferred -and (Test-Path -LiteralPath $Preferred)) { return [System.IO.Path]::GetFullPath($Preferred) } if ($HOME -and (Test-Path $HOME)) { return [System.IO.Path]::GetFullPath($HOME) } return (Get-Location).Path } function Get-WtwCmuxLocalWorkspaceGroupSpec { <# .SYNOPSIS Machine/project group for a local ``wtw cmux`` target. #> [CmdletBinding()] param([Parameter(Mandatory)] $Target) $repoName = [string](Get-WtwPropertyValue -Object $Target -Name 'RepoName') $repoEntry = Get-WtwPropertyValue -Object $Target -Name 'RepoEntry' $projectName = if ($repoName) { Format-WtwRepoDisplayName -Name $repoName -RepoEntry $repoEntry } else { '' } $mainPath = Get-WtwPropertyValue -Object $repoEntry -Name 'mainPath' $worktreePath = Get-WtwPropertyValue -Object (Get-WtwPropertyValue -Object $Target -Name 'WorktreeEntry') -Name 'path' return [PSCustomObject]@{ Name = (Format-WtwCmuxGroupName -MachineBadge (Get-WtwSelfBadge) -ProjectName $projectName) Key = (ConvertTo-WtwCmuxGroupKey -MachineId 'self' -RepoId $repoName) Cwd = (Get-WtwCmuxWorkspaceGroupCwd -Preferred ($mainPath ?? $worktreePath)) MachineId = 'self' RepoId = $repoName } } function Get-WtwCmuxRemoteWorkspaceGroupSpec { <# .SYNOPSIS Machine/project group for ``wtw --on <host> cmux [name]``. #> [CmdletBinding()] param( [Parameter(Mandatory)] $HostEntry, [Parameter(Mandatory)] $Session ) $repoName = [string](Get-WtwPropertyValue -Object $Session -Name 'RepoName') $repoEmoji = Get-WtwPropertyValue -Object $Session -Name 'RepoEmoji' if ($repoName -and -not $repoEmoji) { $localRepo = Get-WtwPropertyValue -Object (Get-WtwPropertyValue -Object (Get-WtwRegistry) -Name 'repos') -Name $repoName $repoEmoji = Get-WtwRepoEmoji -RepoEntry $localRepo } $projectName = if ($repoName) { Format-WtwRepoDisplayName -Name $repoName -Emoji $repoEmoji } else { '' } $hostName = [string](Get-WtwPropertyValue -Object $HostEntry -Name 'Name') return [PSCustomObject]@{ Name = (Format-WtwCmuxGroupName -MachineBadge (Get-WtwMachineBadge -HostEntry $HostEntry) -ProjectName $projectName) Key = (ConvertTo-WtwCmuxGroupKey -MachineId $hostName -RepoId $repoName) Cwd = (Get-WtwCmuxWorkspaceGroupCwd) MachineId = $hostName RepoId = $repoName } } function ConvertFrom-WtwCmuxWorkspaceGroupObject { [CmdletBinding()] param([Parameter(Mandatory)] $Group) $members = @(Get-WtwCmuxObjectValue -Object $Group -Names @('member_workspace_refs', 'memberWorkspaceRefs')) $generated = Get-WtwCmuxObjectValue -Object $Group -Names @('anchor_workspace_is_generated', 'anchorWorkspaceIsGenerated') return [PSCustomObject]@{ Ref = [string](Get-WtwCmuxObjectValue -Object $Group -Names @('ref', 'group_ref', 'groupRef')) Name = [string](Get-WtwCmuxObjectValue -Object $Group -Names @('name', 'title')) Key = [string](Get-WtwCmuxObjectValue -Object $Group -Names @('idempotency_key', 'idempotencyKey', 'external_id', 'externalId')) AnchorRef = [string](Get-WtwCmuxObjectValue -Object $Group -Names @('anchor_workspace_ref', 'anchorWorkspaceRef')) Generated = [bool]$generated MemberRefs = @($members | ForEach-Object { "$_" } | Where-Object { $_ }) } } function Get-WtwCmuxWorkspaceGroups { <# .SYNOPSIS Live cmux sidebar groups in the current window. #> [CmdletBinding()] param() $result = Invoke-WtwCmuxCommand -ArgumentList @('workspace-group', 'list', '--json') if ($result.ExitCode -ne 0) { return @() } $parsed = ConvertFrom-WtwCmuxJsonOutput -Output $result.Output if (-not $parsed) { return @() } $raw = if ((Get-WtwPropertyNames -Object $parsed) -contains 'groups') { @($parsed.groups) } elseif ($parsed -is [array]) { @($parsed) } else { @() } return @($raw | Where-Object { $_ } | ForEach-Object { ConvertFrom-WtwCmuxWorkspaceGroupObject -Group $_ }) } function Find-WtwCmuxWorkspaceGroup { [CmdletBinding()] param([Parameter(Mandatory)] $Spec) $groups = @(Get-WtwCmuxWorkspaceGroups) $byKey = $groups | Where-Object { $_.Key -and [string]::Equals($_.Key, $Spec.Key, [System.StringComparison]::OrdinalIgnoreCase) } | Select-Object -First 1 if ($byKey) { return $byKey } return $groups | Where-Object { $_.Name -and [string]::Equals($_.Name, $Spec.Name, [System.StringComparison]::Ordinal) } | Select-Object -First 1 } function Sync-WtwCmuxWorkspaceGroupAnchorTitle { <# .SYNOPSIS Keep a generated group header titled as the machine/project name. #> [CmdletBinding()] param( [Parameter(Mandatory)] $Group, [Parameter(Mandatory)][string] $Name ) $anchor = Get-WtwPropertyValue -Object $Group -Name 'AnchorRef' $generated = [bool](Get-WtwPropertyValue -Object $Group -Name 'Generated') if (-not ($anchor -and $generated -and $Name)) { return } Invoke-WtwCmuxCommand -ArgumentList @( 'workspace-action', '--workspace', "$anchor", '--action', 'rename', '--title', $Name ) | Out-Null } function Ensure-WtwCmuxWorkspaceGroup { <# .SYNOPSIS Find or create the generated-header group for a machine/project pair. .DESCRIPTION Uses ``cmux workspace-group create`` without ``--from`` so the header is a generated workspace, not the first worktree. Recreate is keyed by ``wtw.group.<machine>.<repo>``. If the stored name drifted (emoji or label change), the group is renamed in place. #> [CmdletBinding()] param([Parameter(Mandatory)] $Spec) if (-not ($Spec.Name -and $Spec.Key)) { return $null } $existing = Find-WtwCmuxWorkspaceGroup -Spec $Spec if ($existing -and $existing.Ref) { if ($existing.Name -and -not [string]::Equals($existing.Name, $Spec.Name, [System.StringComparison]::Ordinal)) { Invoke-WtwCmuxCommand -ArgumentList @('workspace-group', 'rename', $existing.Ref, '--name', $Spec.Name) | Out-Null $existing.Name = $Spec.Name } Sync-WtwCmuxWorkspaceGroupAnchorTitle -Group $existing -Name $Spec.Name return $existing } $create = Invoke-WtwCmuxCommand -ArgumentList @( 'workspace-group', 'create', '--name', $Spec.Name, '--cwd', $Spec.Cwd, '--idempotency-key', $Spec.Key, '--external-id', $Spec.Key, '--json' ) $parsed = ConvertFrom-WtwCmuxJsonOutput -Output $create.Output $rawGroup = Get-WtwPropertyValue -Object $parsed -Name 'group' if ($rawGroup) { $created = ConvertFrom-WtwCmuxWorkspaceGroupObject -Group $rawGroup Sync-WtwCmuxWorkspaceGroupAnchorTitle -Group $created -Name $Spec.Name return $created } return Find-WtwCmuxWorkspaceGroup -Spec $Spec } function Get-WtwCmuxNewWorkspaceGroupArgs { <# .SYNOPSIS Extra ``new-workspace`` flags that place the tab into a group. #> [CmdletBinding()] param([AllowNull()] $Group) $ref = Get-WtwPropertyValue -Object $Group -Name 'Ref' if (-not $ref) { return @() } return @('--group', "$ref") } function Add-WtwCmuxWorkspaceToGroup { <# .SYNOPSIS Attach an already-open workspace to its machine/project group. #> [CmdletBinding()] param( [AllowNull()] $Group, [AllowNull()][AllowEmptyString()][string] $WorkspaceRef ) $groupRef = Get-WtwPropertyValue -Object $Group -Name 'Ref' if (-not ($groupRef -and $WorkspaceRef)) { return } $members = @(Get-WtwPropertyValue -Object $Group -Name 'MemberRefs' -DefaultValue @()) if ($members -contains $WorkspaceRef) { return } Invoke-WtwCmuxCommand -ArgumentList @( 'workspace-group', 'add', '--group', "$groupRef", '--workspace', "$WorkspaceRef" ) | Out-Null } function Resolve-WtwCmuxWorkspaceGroup { <# .SYNOPSIS Ensure the group exists, then optionally attach a live workspace. #> [CmdletBinding()] param( [Parameter(Mandatory)] $Spec, [AllowNull()][AllowEmptyString()][string] $WorkspaceRef ) $group = Ensure-WtwCmuxWorkspaceGroup -Spec $Spec if ($WorkspaceRef) { Add-WtwCmuxWorkspaceToGroup -Group $group -WorkspaceRef $WorkspaceRef } return $group } |