Threads born committed: local drafts + startThread - #71
Conversation
Opening a conversation is now controller-local; the worker only creates a row, worktree, session, and turn when startThread runs, so abandoned drafts leave no debris (#67). Co-authored-by: Cursor <cursoragent@cursor.com>
Skip listThreads for controller-local drafts, clear draft UI state on leave, and prove failed startThread threads can bind and prompt again. Co-authored-by: Cursor <cursoragent@cursor.com>
DraftWorkspace uses Result.tryPromise for startThread; knip requires it as a direct dependency. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughAdds controller-local draft conversations and a compound ChangesThread startup and draft workflow
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/cli/src/core/threads/coordinator.start-thread.test.ts`:
- Around line 195-228: Update the test setup and mocks used by createCoordinator
to record repository/runtime operation calls, then assert in the “births a
thread with a bound session ready to prompt” test that startup operations occur
in order: createThread, Git setup, createBoundSession, preferences,
bindThreadAgent, and setAgentLocked. Keep the existing final-state and prompt
assertions.
In `@apps/cli/src/core/threads/coordinator.ts`:
- Around line 210-214: Update Coordinator.startThread to serialize the entire
startThreadFn operation with a mutex keyed by projectId or the resolved project
directory. Acquire the project-scoped lock before invoking startThreadFn and
release it after completion, including failures, while preserving the existing
Result return behavior.
In `@apps/cli/src/core/threads/start-thread.ts`:
- Around line 52-84: Update persistFailure to commit the user message, thread
error, and turn_interrupted entries as one atomic operation when supported, and
propagate any persistence failure instead of silently returning after isErr().
Update the retryable-failure flow around the callers of persistFailure so it
does not return Result.ok(...) unless all required conversation entries were
successfully persisted.
- Around line 94-113: Update the worktree flow in the thread-start logic around
createGitWorktree and updateThreadWorktreePath to require a branch whenever
worktree or worktreePath is requested, and persist the path only after
successful creation. If updateThreadWorktreePath fails after creation, remove
the newly created worktree before returning the repository error, while
preserving the existing error mappings.
In `@apps/cli/src/handlers/controller/turn-emit.ts`:
- Around line 143-170: Update the runTurn promise handling in the turn emission
flow to track whether a terminal event has been published. In the rejection
catch, when no terminal event was emitted, call emitTerminal with a
turn_interrupted event before or alongside logging the error; preserve the
existing logging and avoid publishing duplicate interruptions after a terminal
event.
In `@apps/web/src/components/chat/composer/index.tsx`:
- Around line 565-567: Add key={thread.id} to the ComposerBranchToolbar rendered
in the isGitRepo branch so it remounts whenever the thread changes, preventing
workspaceMode state from leaking between threads. Leave the existing props and
conditional rendering unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9af4f3c9-aa63-4f10-a9a9-8315d8b874c0
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (21)
apps/cli/src/core/threads/coordinator.start-thread.test.tsapps/cli/src/core/threads/coordinator.tsapps/cli/src/core/threads/start-thread.tsapps/cli/src/handlers/controller/chat.tsapps/cli/src/handlers/controller/turn-emit.tsapps/web/package.jsonapps/web/src/components/chat/composer/composer-branch-toolbar.tsxapps/web/src/components/chat/composer/index.tsxapps/web/src/components/chat/main/draft-workspace.tsxapps/web/src/components/chat/main/thread-header.tsxapps/web/src/components/sidebar/projects/project-thread-explorer.tsxapps/web/src/routeTree.gen.tsapps/web/src/routes/_workspace/workers/$workerId/p/$projectId/d/$draftId/index.tsxshared/connections/src/contracts/controller.tsshared/constants/src/operation-keys.tsshared/hooks/src/agent-catalog/use-agent-catalog.tsshared/hooks/src/queries/use-git.tsshared/hooks/src/queries/use-start-thread.tsshared/hooks/src/stores/local-draft.tsshared/schemas/src/rtc/threads.test.tsshared/schemas/src/rtc/threads.ts
Serialize project checkouts, require committed failure entries, clean up orphan worktrees, and emit turn_interrupted on uncaught turn rejection so draft first-send stays retryable and agent-safe. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
/d/$draftId) opens without creating a worker thread row; first send runs compoundstartThread(row → git/worktree → session → prefs → binding → turn).thread_error/turn_interrupted; the thread can be bound and prompted again in place.Method not found(e.g.session/set_model) as best-effort so agents that advertise models but lack setters can still bind and prompt.Closes #67.
Test plan
bun test apps/cli/src/core/threads/coordinator.start-thread.test.tsbun run check:typesinapps/cli,apps/web,shared/hooksSummary by CodeRabbit
New Features
Bug Fixes
Refactor