Skip to content

fix(tasks): route to checked-out task button#2518

Open
janburzinski wants to merge 2 commits into
mainfrom
jan/eng-1587-route-users-to-existing-checked-out-branch-task
Open

fix(tasks): route to checked-out task button#2518
janburzinski wants to merge 2 commits into
mainfrom
jan/eng-1587-route-users-to-existing-checked-out-branch-task

Conversation

@janburzinski

Copy link
Copy Markdown
Collaborator

Description

  • detects when a branch/workspace is already checked out by another task
  • show a clear provision error and add button
    • "{branchname} is already checked out by task {taskname}"
    • [Open existing task]
Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This 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 persistPath return value through ensureWorkspaceSetup to identify collisions, introduces a findOwningTask DB query, and wires the result through the store and UI.

  • workspace-bootstrap-service.ts: Captures the persistPath return value, and when it differs from the expected workspace ID calls findOwningTask (scoped to the same project, non-archived tasks, with LIMIT 1) to identify the owning task and return a typed workspace-already-checked-out error.
  • task-store.ts / task-manager.ts: Adds provisionError: ProvisionWorkspaceError | undefined to TaskStore, populated inside the existing runInAction on provision failure and cleared on all provisioned/unprovisioned transitions.
  • main-panel.tsx: Reads taskStore.provisionError inside the provision-error panel and renders an "Open existing task" button that navigates to the owning task using the same projectId.

Confidence Score: 5/5

Safe 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 transitionToUnregistered does not clear the new provisionError field, unlike the three other transition methods — but in practice the value is always overwritten before it can be displayed.

task-store.tstransitionToUnregistered should clear provisionError for consistency with the other transition methods.

Important Files Changed

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 })"
Loading

Reviews (2): Last reviewed commit: "fix(workspaces): limit owning task looku..." | Re-trigger Greptile

Comment thread apps/emdash-desktop/src/main/core/workspaces/workspace-bootstrap-service.ts Outdated
@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant