Skip to content

Commit a789d30

Browse files
authored
Merge branch 'main' into t3code/git-usage-audit
2 parents e7a63e0 + cf2c628 commit a789d30

4 files changed

Lines changed: 70 additions & 8 deletions

File tree

apps/web/src/components/ChatView.browser.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,6 +2818,55 @@ describe("ChatView timeline estimator parity (full app)", () => {
28182818
}
28192819
});
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+
28212870
it("keeps pending-question footer actions inside the composer after a real resize", async () => {
28222871
const mounted = await mountChatView({
28232872
viewport: WIDE_FOOTER_VIEWPORT,

apps/web/src/components/ChatView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
15291529
);
15301530
const activeProjectCwd = activeProject?.cwd ?? null;
15311531
const activeThreadWorktreePath = activeThread?.worktreePath ?? null;
1532+
const activeWorkspaceRoot = activeThreadWorktreePath ?? activeProjectCwd ?? undefined;
15321533
const activeTerminalLaunchContext =
15331534
terminalLaunchContext?.threadId === activeThreadId
15341535
? terminalLaunchContext
@@ -4007,7 +4008,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
40074008
markdownCwd={gitCwd ?? undefined}
40084009
resolvedTheme={resolvedTheme}
40094010
timestampFormat={timestampFormat}
4010-
workspaceRoot={activeProject?.cwd ?? undefined}
4011+
workspaceRoot={activeWorkspaceRoot}
40114012
/>
40124013
</div>
40134014

@@ -4441,7 +4442,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
44414442
activePlan={activePlan}
44424443
activeProposedPlan={sidebarProposedPlan}
44434444
markdownCwd={gitCwd ?? undefined}
4444-
workspaceRoot={activeProject?.cwd ?? undefined}
4445+
workspaceRoot={activeWorkspaceRoot}
44454446
timestampFormat={timestampFormat}
44464447
onClose={() => {
44474448
setPlanSidebarOpen(false);

apps/web/src/rpc/requestLatencyState.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { Atom } from "effect/unstable/reactivity";
33

44
import { appAtomRegistry } from "./atomRegistry";
55

6-
export const SLOW_RPC_ACK_THRESHOLD_MS = 2_500;
6+
export const SLOW_RPC_ACK_THRESHOLD_MS = 15_000;
77
export const MAX_TRACKED_RPC_ACK_REQUESTS = 256;
8+
let slowRpcAckThresholdMs = SLOW_RPC_ACK_THRESHOLD_MS;
89

910
export interface SlowRpcAckRequest {
1011
readonly requestId: string;
@@ -56,12 +57,12 @@ export function trackRpcRequestSent(requestId: string, tag: string): void {
5657
startedAt: new Date(startedAtMs).toISOString(),
5758
startedAtMs,
5859
tag,
59-
thresholdMs: SLOW_RPC_ACK_THRESHOLD_MS,
60+
thresholdMs: slowRpcAckThresholdMs,
6061
};
6162
const timeoutId = setTimeout(() => {
6263
pendingRpcAckRequests.delete(requestId);
6364
appendSlowRpcAckRequest(request);
64-
}, SLOW_RPC_ACK_THRESHOLD_MS);
65+
}, slowRpcAckThresholdMs);
6566

6667
pendingRpcAckRequests.set(requestId, {
6768
request,
@@ -119,9 +120,14 @@ function evictOldestPendingRpcRequestIfNeeded(): void {
119120
}
120121

121122
export function resetRequestLatencyStateForTests(): void {
123+
slowRpcAckThresholdMs = SLOW_RPC_ACK_THRESHOLD_MS;
122124
clearAllTrackedRpcRequests();
123125
}
124126

127+
export function setSlowRpcAckThresholdMsForTests(thresholdMs: number): void {
128+
slowRpcAckThresholdMs = thresholdMs;
129+
}
130+
125131
export function useSlowRpcAckRequests(): ReadonlyArray<SlowRpcAckRequest> {
126132
return useAtomValue(slowRpcAckRequestsAtom);
127133
}

apps/web/src/wsTransport.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import {
55
__resetClientTracingForTests,
66
configureClientTracing,
77
} from "./observability/clientTracing";
8-
import { getSlowRpcAckRequests, resetRequestLatencyStateForTests } from "./rpc/requestLatencyState";
8+
import {
9+
getSlowRpcAckRequests,
10+
resetRequestLatencyStateForTests,
11+
setSlowRpcAckThresholdMsForTests,
12+
} from "./rpc/requestLatencyState";
913
import {
1014
getWsConnectionStatus,
1115
getWsConnectionUiState,
@@ -292,6 +296,8 @@ describe("WsTransport", () => {
292296
});
293297

294298
it("marks unary requests as slow until the first server ack arrives", async () => {
299+
const slowAckThresholdMs = 25;
300+
setSlowRpcAckThresholdMsForTests(slowAckThresholdMs);
295301
const transport = new WsTransport("ws://localhost:3020");
296302

297303
const requestPromise = transport.request((client) =>
@@ -320,7 +326,7 @@ describe("WsTransport", () => {
320326
tag: WS_METHODS.serverUpsertKeybinding,
321327
},
322328
]);
323-
}, 5_000);
329+
}, 1_000);
324330

325331
socket.serverMessage(
326332
JSON.stringify({
@@ -343,7 +349,7 @@ describe("WsTransport", () => {
343349
expect(getSlowRpcAckRequests()).toEqual([]);
344350

345351
await transport.dispose();
346-
}, 10_000);
352+
}, 5_000);
347353

348354
it("sends unary RPC requests and resolves successful exits", async () => {
349355
const transport = new WsTransport("ws://localhost:3020");

0 commit comments

Comments
 (0)