Files
orca/src/main/workspace-space-worktree-row.ts
Neil c4988fa81c refactor workspace lifecycle modules (#16334)
* refactor(workspaces): split lifecycle modules

* preserve workspace cleanup consent contract

* restore workspace delete shortcut hint in context menu view

* restore host-qualified visit recency and viewed-candidate predicate

* test(cleanup): pin the viewed-mark upgrade path and host-qualified visit reads

Two invariants a refactor broke in this PR, both silent:

- viewed marks are persisted, so gating `shouldPreserveCleanupInspection` on any
  newer field voids the grace period for every entry written by an older build
- visits are stamped under `${hostId}|${worktreeId}` whenever the host is known
  (the normal case, including 'local'), so a bare map[worktreeId] read misses
  every modern entry and yields 0, disabling the recent-visible-context blocker

Verified discriminating: reintroducing each bug fails exactly its own test.
2026-08-24 22:44:08 -07:00

86 lines
2.7 KiB
TypeScript

import { posix, win32 } from 'node:path'
import type { Repo } from '../shared/repo-types'
import type { Worktree } from '../shared/worktree/types'
import type {
WorkspaceSpaceDirectoryScanResult,
WorkspaceSpaceItem,
WorkspaceSpaceScanStatus,
WorkspaceSpaceWorktree
} from '../shared/workspace-space-types'
import type { WorkspaceSpaceEntryScan } from '../shared/workspace-space-entry-traversal'
import { getWorktreeExecutionHostId } from '../shared/execution-host'
export function basenameWorkspaceFilesystemPath(pathValue: string): string {
return looksLikeWindowsPath(pathValue) ? win32.basename(pathValue) : posix.basename(pathValue)
}
export function joinWorkspaceFilesystemPath(parent: string, child: string): string {
return looksLikeWindowsPath(parent) ? win32.join(parent, child) : posix.join(parent, child)
}
function looksLikeWindowsPath(pathValue: string): boolean {
return /^[A-Za-z]:[\\/]/.test(pathValue) || pathValue.startsWith('\\\\')
}
export function toWorkspaceSpaceItem(stats: WorkspaceSpaceEntryScan): WorkspaceSpaceItem {
return { name: stats.name, path: stats.path, kind: stats.kind, sizeBytes: stats.sizeBytes }
}
function createBaseWorktreeRow(repo: Repo, worktree: Worktree, scannedAt: number) {
return {
worktreeId: worktree.id,
repoId: repo.id,
executionHostId: getWorktreeExecutionHostId(worktree, repo),
repoDisplayName: repo.displayName,
repoPath: repo.path,
displayName: worktree.displayName,
path: worktree.path,
branch: worktree.branch,
isMainWorktree: worktree.isMainWorktree,
isRemote: Boolean(repo.connectionId),
isSparse: worktree.isSparse === true,
canDelete: !worktree.isMainWorktree,
lastActivityAt: worktree.lastActivityAt,
scannedAt
}
}
export function createUnavailableWorkspaceSpaceRow(
repo: Repo,
worktree: Worktree,
scannedAt: number,
status: Exclude<WorkspaceSpaceScanStatus, 'ok'>,
error: string
): WorkspaceSpaceWorktree {
return {
...createBaseWorktreeRow(repo, worktree, scannedAt),
status,
error,
sizeBytes: 0,
reclaimableBytes: 0,
skippedEntryCount: 0,
topLevelItems: [],
omittedTopLevelItemCount: 0,
omittedTopLevelSizeBytes: 0
}
}
export function createScannedWorkspaceSpaceRow(
repo: Repo,
worktree: Worktree,
scannedAt: number,
scan: WorkspaceSpaceDirectoryScanResult
): WorkspaceSpaceWorktree {
return {
...createBaseWorktreeRow(repo, worktree, scannedAt),
status: 'ok',
error: null,
sizeBytes: scan.sizeBytes,
reclaimableBytes: worktree.isMainWorktree ? 0 : scan.sizeBytes,
skippedEntryCount: scan.skippedEntryCount,
topLevelItems: scan.topLevelItems,
omittedTopLevelItemCount: scan.omittedTopLevelItemCount,
omittedTopLevelSizeBytes: scan.omittedTopLevelSizeBytes
}
}