(
projectPath: string,
workspaceName: string,
force: boolean,
trusted?: boolean
)
| 490 | } |
| 491 | |
| 492 | async deleteWorkspace( |
| 493 | projectPath: string, |
| 494 | workspaceName: string, |
| 495 | force: boolean, |
| 496 | trusted?: boolean |
| 497 | ): Promise<{ success: true; deletedPath: string } | { success: false; error: string }> { |
| 498 | // Clean up stale lock before git operations on main repo |
| 499 | cleanStaleLock(projectPath); |
| 500 | |
| 501 | // Disable git hooks for untrusted projects |
| 502 | const noHooksEnv = this.getGitExecOptions(trusted); |
| 503 | |
| 504 | // In-place workspaces are identified by projectPath === workspaceName. |
| 505 | // These are direct workspace directories (e.g., CLI/benchmark sessions), not git worktrees. |
| 506 | const isInPlace = projectPath === workspaceName; |
| 507 | const deletedPath = this.getWorkspacePath(projectPath, workspaceName); |
| 508 | const branchName = isInPlace |
| 509 | ? null |
| 510 | : await this.getPersistedWorkspaceBranchName(projectPath, workspaceName); |
| 511 | // Preserve legacy cleanup semantics for workspaces that predate branch-map persistence. |
| 512 | // Those older workspaces always used workspaceName === branchName, so if this specific |
| 513 | // workspace has no stored mapping we can safely fall back to the workspace name. |
| 514 | const allowWorkspaceNameFallback = !branchName && !isInPlace; |
| 515 | const branchDeleteArgs = { |
| 516 | projectPath, |
| 517 | workspaceName, |
| 518 | branchName, |
| 519 | force, |
| 520 | isInPlace, |
| 521 | noHooksEnv, |
| 522 | allowWorkspaceNameFallback, |
| 523 | }; |
| 524 | const deleteBranchAndSucceed = async (pruneWorktrees = false) => { |
| 525 | if (pruneWorktrees) { |
| 526 | await this.pruneWorktreesBestEffort(projectPath, noHooksEnv); |
| 527 | } |
| 528 | await this.deleteWorkspaceBranchIfSafe(branchDeleteArgs); |
| 529 | await this.deletePersistedWorkspaceBranchMapping(projectPath, workspaceName); |
| 530 | return { success: true as const, deletedPath }; |
| 531 | }; |
| 532 | |
| 533 | try { |
| 534 | await fsPromises.access(deletedPath); |
| 535 | } catch { |
| 536 | return deleteBranchAndSucceed(!isInPlace); |
| 537 | } |
| 538 | |
| 539 | // For in-place workspaces, there's no worktree to remove. |
| 540 | // The workspace directory itself is the user's real project checkout. |
| 541 | if (isInPlace) { |
| 542 | return { success: true, deletedPath }; |
| 543 | } |
| 544 | |
| 545 | try { |
| 546 | await this.removeGitWorktree(projectPath, deletedPath, force, noHooksEnv); |
| 547 | return deleteBranchAndSucceed(); |
| 548 | } catch (error) { |
| 549 | const message = getErrorMessage(error); |
nothing calls this directly
no test coverage detected