authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-04-05 11:22:24-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-04-05 11:22:24-07:00
logcf2c628bc005f3c88911a6fcb957f56e6d1ce45f
treec5189d8bb42ce42acf441b6a6ba5cc9ed3d944b9
parente0874b651d5c5fa5c578be932aada627b95c3f52
signature Signed by PGP key B5690EEEBB952194

Use active worktree path for workspace saves (#1762)


2 files changed, 52 insertions(+), 2 deletions(-)

apps/web/src/components/ChatView.browser.tsx+49
...@@ -2818,6 +2818,55 @@ describe("ChatView timeline estimator parity (full app)", () => {...@@ -2818,6 +2818,55 @@ describe("ChatView timeline estimator parity (full app)", () => {
2818 }2818 }
2819 });2819 });
28202820
2821 it("uses the active worktree path when saving a proposed plan to the workspace", async () => {
2822 const snapshot = createSnapshotWithLongProposedPlan();
2823 const threads = snapshot.threads.slice();
2824 const targetThreadIndex = threads.findIndex((thread) => thread.id === THREAD_ID);
2825 const targetThread = targetThreadIndex >= 0 ? threads[targetThreadIndex] : undefined;
2826 if (targetThread) {
2827 threads[targetThreadIndex] = {
2828 ...targetThread,
2829 worktreePath: "/repo/worktrees/plan-thread",
2830 };
2831 }
2832
2833 const mounted = await mountChatView({
2834 viewport: DEFAULT_VIEWPORT,
2835 snapshot: {
2836 ...snapshot,
2837 threads,
2838 },
2839 });
2840
2841 try {
2842 const planActionsButton = await waitForElement(
2843 () => document.querySelector<HTMLButtonElement>('button[aria-label="Plan actions"]'),
2844 "Unable to find proposed plan actions button.",
2845 );
2846 planActionsButton.click();
2847
2848 const saveToWorkspaceItem = await waitForElement(
2849 () =>
2850 (Array.from(document.querySelectorAll('[data-slot="menu-item"]')).find(
2851 (item) => item.textContent?.trim() === "Save to workspace",
2852 ) ?? null) as HTMLElement | null,
2853 'Unable to find "Save to workspace" menu item.',
2854 );
2855 saveToWorkspaceItem.click();
2856
2857 await vi.waitFor(
2858 () => {
2859 expect(document.body.textContent).toContain(
2860 "Enter a path relative to /repo/worktrees/plan-thread.",
2861 );
2862 },
2863 { timeout: 8_000, interval: 16 },
2864 );
2865 } finally {
2866 await mounted.cleanup();
2867 }
2868 });
2869
2821 it("keeps pending-question footer actions inside the composer after a real resize", async () => {2870 it("keeps pending-question footer actions inside the composer after a real resize", async () => {
2822 const mounted = await mountChatView({2871 const mounted = await mountChatView({
2823 viewport: WIDE_FOOTER_VIEWPORT,2872 viewport: WIDE_FOOTER_VIEWPORT,
apps/web/src/components/ChatView.tsx+3-2
...@@ -1526,6 +1526,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -1526,6 +1526,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
1526 );1526 );
1527 const activeProjectCwd = activeProject?.cwd ?? null;1527 const activeProjectCwd = activeProject?.cwd ?? null;
1528 const activeThreadWorktreePath = activeThread?.worktreePath ?? null;1528 const activeThreadWorktreePath = activeThread?.worktreePath ?? null;
1529 const activeWorkspaceRoot = activeThreadWorktreePath ?? activeProjectCwd ?? undefined;
1529 const activeTerminalLaunchContext =1530 const activeTerminalLaunchContext =
1530 terminalLaunchContext?.threadId === activeThreadId1531 terminalLaunchContext?.threadId === activeThreadId
1531 ? terminalLaunchContext1532 ? terminalLaunchContext
...@@ -4004,7 +4005,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -4004,7 +4005,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
4004 markdownCwd={gitCwd ?? undefined}4005 markdownCwd={gitCwd ?? undefined}
4005 resolvedTheme={resolvedTheme}4006 resolvedTheme={resolvedTheme}
4006 timestampFormat={timestampFormat}4007 timestampFormat={timestampFormat}
4007 workspaceRoot={activeProject?.cwd ?? undefined}4008 workspaceRoot={activeWorkspaceRoot}
4008 />4009 />
4009 </div>4010 </div>
40104011
...@@ -4438,7 +4439,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -4438,7 +4439,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
4438 activePlan={activePlan}4439 activePlan={activePlan}
4439 activeProposedPlan={sidebarProposedPlan}4440 activeProposedPlan={sidebarProposedPlan}
4440 markdownCwd={gitCwd ?? undefined}4441 markdownCwd={gitCwd ?? undefined}
4441 workspaceRoot={activeProject?.cwd ?? undefined}4442 workspaceRoot={activeWorkspaceRoot}
4442 timestampFormat={timestampFormat}4443 timestampFormat={timestampFormat}
4443 onClose={() => {4444 onClose={() => {
4444 setPlanSidebarOpen(false);4445 setPlanSidebarOpen(false);