Run draft-thread project scripts from resolved project/worktree cwd#1178
Run draft-thread project scripts from resolved project/worktree cwd#1178juliusmarminge merged 6 commits intomainfrom
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
b06a638 to
1caf2db
Compare
- use shared `projectScriptCwd` to choose worktree path or project root - allow script execution from local draft threads with correct terminal env/cwd - add ChatView and helper tests covering local and worktree draft cases
- Treat detached `xterm-helper-textarea` nodes as unfocused in `isTerminalFocused` - Add unit tests for connected vs detached terminal focus behavior - Harden ChatView shortcut test flow by waiting for keybindings/config and retrying route transition
1caf2db to
6fe2331
Compare
- Remove draft prompt state alongside draft thread cleanup - Update tests for terminal context removal and new-thread shortcut
- Clean up existing draft image object URLs when a thread is removed - Prevent stale preview URLs from leaking after draft-thread resets
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed:
clearDraftThreadis now identical toclearThreadDraft- Removed the duplicate
clearThreadDraftmethod and its type declaration, and updated the single production caller in Sidebar.tsx to useclearDraftThreadinstead.
- Removed the duplicate
Or push these changes by commenting:
@cursor push e0d6b2ab71
Preview (e0d6b2ab71)
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -258,7 +258,7 @@
const markThreadUnread = useStore((store) => store.markThreadUnread);
const toggleProject = useStore((store) => store.toggleProject);
const reorderProjects = useStore((store) => store.reorderProjects);
- const clearComposerDraftForThread = useComposerDraftStore((store) => store.clearThreadDraft);
+ const clearComposerDraftForThread = useComposerDraftStore((store) => store.clearDraftThread);
const getDraftThreadByProjectId = useComposerDraftStore(
(store) => store.getDraftThreadByProjectId,
);
diff --git a/apps/web/src/composerDraftStore.ts b/apps/web/src/composerDraftStore.ts
--- a/apps/web/src/composerDraftStore.ts
+++ b/apps/web/src/composerDraftStore.ts
@@ -219,7 +219,6 @@
attachments: PersistedComposerImageAttachment[],
) => void;
clearComposerContent: (threadId: ThreadId) => void;
- clearThreadDraft: (threadId: ThreadId) => void;
}
const EMPTY_PROVIDER_MODEL_OPTIONS = Object.freeze<ProviderModelOptions>({});
@@ -1748,41 +1747,6 @@
return { draftsByThreadId: nextDraftsByThreadId };
});
},
- clearThreadDraft: (threadId) => {
- if (threadId.length === 0) {
- return;
- }
- const existing = get().draftsByThreadId[threadId];
- if (existing) {
- for (const image of existing.images) {
- revokeObjectPreviewUrl(image.previewUrl);
- }
- }
- set((state) => {
- const hasComposerDraft = state.draftsByThreadId[threadId] !== undefined;
- const hasDraftThread = state.draftThreadsByThreadId[threadId] !== undefined;
- const hasProjectMapping = Object.values(state.projectDraftThreadIdByProjectId).includes(
- threadId,
- );
- if (!hasComposerDraft && !hasDraftThread && !hasProjectMapping) {
- return state;
- }
- const { [threadId]: _removedComposerDraft, ...restComposerDraftsByThreadId } =
- state.draftsByThreadId;
- const { [threadId]: _removedDraftThread, ...restDraftThreadsByThreadId } =
- state.draftThreadsByThreadId;
- const nextProjectDraftThreadIdByProjectId = Object.fromEntries(
- Object.entries(state.projectDraftThreadIdByProjectId).filter(
- ([, draftThreadId]) => draftThreadId !== threadId,
- ),
- ) as Record<ProjectId, ThreadId>;
- return {
- draftsByThreadId: restComposerDraftsByThreadId,
- draftThreadsByThreadId: restDraftThreadsByThreadId,
- projectDraftThreadIdByProjectId: nextProjectDraftThreadIdByProjectId,
- };
- });
- },
}),
{
name: COMPOSER_DRAFT_STORAGE_KEY,clearThreadDraft was functionally identical to clearDraftThread after recent changes. Remove the duplicate and update the single production caller in Sidebar.tsx to use clearDraftThread instead. Applied via @cursor push command


Summary
projectScriptCwdhelper.ChatView.mockServiceWorker.js(MSW package version bump) and include updated Vitest attachment artifact.Testing
apps/web/src/projectScripts.test.ts: verifiesprojectScriptCwdprefersworktreePathand falls back to projectcwd.apps/web/src/components/ChatView.browser.tsx: verifiesterminalOpenfor local draft thread usescwd: /repo/projectand env includesT3CODE_PROJECT_ROOT.apps/web/src/components/ChatView.browser.tsx: verifies worktree draft thread usescwd: /repo/worktrees/feature-draftand env includes bothT3CODE_PROJECT_ROOTandT3CODE_WORKTREE_PATH.apps/web/src/components/ChatView.browser.tsx: verifies script command dispatch (terminalWrite) sends the expected command (bun run lint\r).bun fmt,bun lint,bun typecheck.Note
Medium Risk
Changes how project scripts and “Open in…” resolve
cwdand removes a guard that blocked script runs on local draft threads, which could affect terminal execution behavior across thread types. Also consolidates draft-clearing to delete composer drafts and revoke image preview URLs, so regressions could impact draft persistence and attachments.Overview
Project scripts and related actions now resolve their execution directory via a new
projectScriptCwdhelper, preferringworktreePathwhen present and falling back to the projectcwd;ChatViewuses this consistently (including the header “Open in…” cwd).The script runner no longer blocks execution on non-server (local draft) threads, and new browser tests assert
terminalOpen/terminalWritebehavior for both local-draft and worktree-draft threads.Draft cleanup is consolidated into
clearDraftThread(replacingclearThreadDraft), which now also clears composer drafts and revokes image preview URLs;isTerminalFocusedis updated to ignore detached xterm helper elements with new unit tests, and.gitignoreadds.tanstack.Written by Cursor Bugbot for commit d7dea68. This will update automatically on new commits. Configure here.
Note
Run project scripts from draft threads using resolved project/worktree cwd
projectScriptCwdin projectScripts.ts to resolve the execution cwd for project scripts, preferringworktreePathwhen set, otherwise using the project's cwd.ChatView.runProjectScriptthat blocked script execution on non-server (local draft) threads, allowing scripts to run from both local and worktree-backed draft threads.clearDraftThreadin composerDraftStore.ts, which now also clears the composer draft and revokes image preview URLs.isTerminalFocusedto returnfalsefor detached xterm helper textareas.T3CODE_PROJECT_ROOT(andT3CODE_WORKTREE_PATHfor worktrees) set in the terminal environment.Macroscope summarized d7dea68.