fix(tasks): route to checked-out task button#2518
Conversation
Refs ENG-1587
Greptile SummaryThis PR detects when a workspace branch is already checked out by another task and surfaces a clear error with a navigation button. It threads the
Confidence Score: 5/5Safe to merge — the change is additive, all error paths return early cleanly, and navigation targets are correctly scoped to the same project. The collision detection query is well-scoped and the error is propagated correctly through the store to the UI. The only inconsistency is that
|
| Filename | Overview |
|---|---|
| apps/emdash-desktop/src/main/core/workspaces/workspace-bootstrap-service.ts | Adds findOwningTask helper and plumbs the return value of persistPath to detect workspace key collisions, returning workspace-already-checked-out with the conflicting task's id/name. SQL query is properly scoped with projectId, isNull(archivedAt), ne(id, ignoredTaskId), and LIMIT 1. |
| apps/emdash-desktop/src/renderer/features/tasks/stores/task-manager.ts | Adds workspace-already-checked-out formatting to formatProvisionWorkspaceError and wires result.error into current.provisionError inside the existing runInAction block on provision failure. |
| apps/emdash-desktop/src/renderer/features/tasks/stores/task-store.ts | Adds provisionError observable field, cleared in three of four transition methods — transitionToUnregistered is the exception and does not clear the field. |
| apps/emdash-desktop/src/renderer/features/tasks/main-panel.tsx | Adds an "Open existing task" button to the provision-error panel that reads taskStore.provisionError and navigates to the owning task. The projectId passed to navigate correctly matches the project used by findOwningTask server-side. |
| apps/emdash-desktop/src/shared/core/tasks/tasks.ts | Extends ProvisionWorkspaceError union with the new workspace-already-checked-out variant; branchName is optional to handle cases without an intent branch name. |
Sequence Diagram
sequenceDiagram
participant UI as TaskMainPanel
participant TM as TaskManagerStore
participant RPC as rpc.tasks
participant BS as WorkspaceBootstrapService
participant DB as Database
UI->>TM: provision task
TM->>RPC: provisionWorkspace(taskId)
RPC->>BS: ensureWorkspaceSetup(...)
BS->>BS: executor.execute(spec)
BS->>BS: persistPath(workspaceRow.id, resolvedPath)
BS->>DB: "SELECT workspaces WHERE key = computedKey"
DB-->>BS: existing workspace (different ID)
BS-->>BS: persistedWorkspaceId ≠ workspaceRow.id
BS->>DB: findOwningTask(persistedWorkspaceId, projectId)
DB-->>BS: "{ id, name } of owning task"
BS-->>RPC: "err({ type: 'workspace-already-checked-out', taskId, taskName, branchName })"
RPC-->>TM: result.error
TM->>TM: "runInAction → phase='provision-error', provisionError=result.error"
TM-->>UI: store updated (MobX)
UI->>UI: render error panel + "Open existing task" button
UI->>UI: "onClick → navigate('task', { projectId, taskId: existingTask.taskId })"
Reviews (2): Last reviewed commit: "fix(workspaces): limit owning task looku..." | Re-trigger Greptile
Description
Checklist
messages and, when possible, the PR title