Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
84 lines
2.2 KiB
TypeScript
84 lines
2.2 KiB
TypeScript
import type {
|
|
WorkspaceCleanupCandidate,
|
|
WorkspaceCleanupScanError,
|
|
WorkspaceCleanupScanProgress
|
|
} from '../../shared/workspace-cleanup'
|
|
import { appendWorkspaceCleanupItems } from './workspace-cleanup-scan-primitives'
|
|
|
|
const WORKSPACE_CLEANUP_PROGRESS_EMIT_INTERVAL_MS = 100
|
|
|
|
export type WorkspaceCleanupScanOptions = {
|
|
onProgress?: (progress: WorkspaceCleanupScanProgress) => void
|
|
signal?: AbortSignal
|
|
}
|
|
|
|
export type WorkspaceCleanupProgressEmitter = {
|
|
addDiscovered: (count: number) => void
|
|
addCandidate: (candidate: WorkspaceCleanupCandidate) => void
|
|
addErrors: (errors: WorkspaceCleanupScanError[]) => void
|
|
flush: () => void
|
|
}
|
|
|
|
/** Caps renderer projection churn while preserving an immediate final progress state. */
|
|
export function createWorkspaceCleanupProgressEmitter(
|
|
scanId: string | undefined,
|
|
scannedAt: number,
|
|
options: WorkspaceCleanupScanOptions
|
|
): WorkspaceCleanupProgressEmitter {
|
|
const errors: WorkspaceCleanupScanError[] = []
|
|
let pendingCandidates: WorkspaceCleanupCandidate[] = []
|
|
let totalWorktreeCount = 0
|
|
let scannedWorktreeCount = 0
|
|
let dirty = false
|
|
let emittedInitialDiscovery = false
|
|
let timer: NodeJS.Timeout | null = null
|
|
const flush = (): void => {
|
|
if (!scanId || !dirty) {
|
|
return
|
|
}
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
timer = null
|
|
}
|
|
dirty = false
|
|
const candidates = pendingCandidates
|
|
pendingCandidates = []
|
|
options.onProgress?.({
|
|
scanId,
|
|
scannedAt,
|
|
totalWorktreeCount,
|
|
scannedWorktreeCount,
|
|
candidates,
|
|
errors: [...errors],
|
|
candidateMode: 'append'
|
|
})
|
|
}
|
|
const schedule = (): void => {
|
|
if (!scanId) {
|
|
return
|
|
}
|
|
dirty = true
|
|
timer ??= setTimeout(flush, WORKSPACE_CLEANUP_PROGRESS_EMIT_INTERVAL_MS)
|
|
}
|
|
return {
|
|
addDiscovered: (count) => {
|
|
totalWorktreeCount += count
|
|
schedule()
|
|
if (!emittedInitialDiscovery) {
|
|
emittedInitialDiscovery = true
|
|
flush()
|
|
}
|
|
},
|
|
addCandidate: (candidate) => {
|
|
pendingCandidates.push(candidate)
|
|
scannedWorktreeCount += 1
|
|
schedule()
|
|
},
|
|
addErrors: (newErrors) => {
|
|
appendWorkspaceCleanupItems(errors, newErrors)
|
|
schedule()
|
|
},
|
|
flush
|
|
}
|
|
}
|