Skip to content

Commit 804cba4

Browse files
authored
revert: refresh workspace layouts and tool activity (#6657)
1 parent d7abd7f commit 804cba4

52 files changed

Lines changed: 1727 additions & 3228 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/desktop/src/electron/ElectronMenu.test.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,7 @@ describe("ElectronMenu", () => {
9898
const electronMenu = yield* ElectronMenu.ElectronMenu;
9999
const selectedItemId = yield* electronMenu.showContextMenu({
100100
window: makeWindow(2),
101-
items: [
102-
{ id: "copy", label: "Copy" },
103-
{ id: "delete", label: "Delete", destructive: true, separatorBefore: true },
104-
],
101+
items: [{ id: "copy", label: "Copy" }],
105102
position: Option.some({ x: 10.8, y: 20.2 }),
106103
});
107104

@@ -113,12 +110,6 @@ describe("ElectronMenu", () => {
113110
enabled: true,
114111
click: buildFromTemplateMock.mock.calls[0]?.[0][0].click,
115112
});
116-
assert.deepEqual(
117-
buildFromTemplateMock.mock.calls[0]?.[0].map(
118-
(item: Electron.MenuItemConstructorOptions) => item.type ?? item.label,
119-
),
120-
["Copy", "separator", "Delete"],
121-
);
122113
}).pipe(Effect.provide(TestLayer)),
123114
);
124115

apps/desktop/src/electron/ElectronMenu.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ function normalizeContextMenuItems(source: readonly ContextMenuItem[]): ContextM
7878
label: sourceItem.label,
7979
destructive: sourceItem.destructive === true,
8080
disabled: sourceItem.disabled === true,
81-
...(sourceItem.separatorBefore === true ? { separatorBefore: true } : {}),
8281
};
8382

8483
if (sourceItem.children) {
@@ -142,17 +141,10 @@ export const make = Effect.gen(function* () {
142141
): Electron.MenuItemConstructorOptions[] => {
143142
const template: Electron.MenuItemConstructorOptions[] = [];
144143
let hasInsertedDestructiveSeparator = false;
145-
const appendSeparator = () => {
146-
if (template.length === 0 || template.at(-1)?.type === "separator") return;
147-
template.push({ type: "separator" });
148-
};
149144

150145
for (const item of entries) {
151-
if (item.separatorBefore) {
152-
appendSeparator();
153-
}
154146
if (item.destructive && !hasInsertedDestructiveSeparator && template.length > 0) {
155-
appendSeparator();
147+
template.push({ type: "separator" });
156148
hasInsertedDestructiveSeparator = true;
157149
}
158150

apps/server/src/orchestration/ActivityPayloadProjection.test.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function activity(payload: Record<string, unknown>): OrchestrationThreadActivity
2020
* If slimming ever moves to an allowlist over the whole payload, these
2121
* assertions are the tripwire.
2222
*/
23-
describe("projectActivityPayload", () => {
23+
describe("projectActivityPayload agent-field survival", () => {
2424
it("preserves tool attribution (agentId/parentToolUseId) through data slimming", () => {
2525
const projected = projectActivityPayload(
2626
activity({
@@ -44,45 +44,6 @@ describe("projectActivityPayload", () => {
4444
expect(data.somethingClientNeverReads).toBeUndefined();
4545
});
4646

47-
it("normalizes Claude and OpenCode command inputs before slimming provider data", () => {
48-
const claude = projectActivityPayload(
49-
activity({
50-
itemType: "command_execution",
51-
toolCallId: "claude-call-1",
52-
data: {
53-
toolName: "Bash",
54-
input: { command: "vp test run" },
55-
result: { content: "x".repeat(5_000) },
56-
},
57-
}),
58-
);
59-
const openCode = projectActivityPayload(
60-
activity({
61-
itemType: "command_execution",
62-
toolCallId: "opencode-call-1",
63-
data: {
64-
tool: "bash",
65-
state: {
66-
status: "running",
67-
input: { command: "vp lint" },
68-
output: "x".repeat(5_000),
69-
},
70-
},
71-
}),
72-
);
73-
74-
expect(claude.payload).toMatchObject({
75-
toolCallId: "claude-call-1",
76-
data: { command: "vp test run" },
77-
});
78-
expect(openCode.payload).toMatchObject({
79-
toolCallId: "opencode-call-1",
80-
data: { command: "vp lint" },
81-
});
82-
expect(JSON.stringify(claude.payload).length).toBeLessThan(200);
83-
expect(JSON.stringify(openCode.payload).length).toBeLessThan(200);
84-
});
85-
8647
it("slims Codex-shaped mcp_tool_call items to rendered fields plus a result summary", () => {
8748
const projected = projectActivityPayload(
8849
activity({

apps/server/src/orchestration/ActivityPayloadProjection.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,24 +104,6 @@ function projectCommandData(data: Record<string, unknown>): Record<string, unkno
104104
return Object.keys(projectedItem).length > 0 ? projectedItem : undefined;
105105
}
106106

107-
function projectCommandValue(data: Record<string, unknown>): unknown {
108-
if (data.command !== undefined) {
109-
return data.command;
110-
}
111-
112-
const input = asRecord(data.input);
113-
if (input?.command !== undefined) {
114-
return input.command;
115-
}
116-
117-
const stateInput = asRecord(asRecord(data.state)?.input);
118-
if (stateInput?.command !== undefined) {
119-
return stateInput.command;
120-
}
121-
122-
return undefined;
123-
}
124-
125107
function summarizeToolTextOutput(value: string): string | null {
126108
const lines: string[] = [];
127109
for (const rawLine of value.split(/\r?\n/u)) {
@@ -305,9 +287,8 @@ export function projectActivityPayload(
305287
if (item) {
306288
projectedData.item = item;
307289
}
308-
const command = projectCommandValue(data);
309-
if (command !== undefined) {
310-
projectedData.command = command;
290+
if ("command" in data) {
291+
projectedData.command = data.command;
311292
}
312293

313294
const changedFiles: string[] = [];
@@ -387,19 +368,18 @@ function dropStaleContextWindowActivities(
387368
/**
388369
* Identity both clients use to fold a tool lifecycle row into the call it
389370
* belongs to (`deriveToolLifecycleCollapseKey` in web's `session-logic` and
390-
* mobile's `threadActivity`): the runtime item id ingestion stamps as
391-
* `toolCallId`, a legacy `data.toolCallId`, or the itemType/title/detail triple.
392-
* Returns null for rows with no identity at all — those never collapse on the
393-
* client either, so they must not be dropped here.
371+
* mobile's `threadActivity`): an explicit `data.toolCallId` when the adapter
372+
* emits one, otherwise the itemType/title/detail triple. Returns null for rows
373+
* with no identity at all — those never collapse on the client either, so they
374+
* must not be dropped here.
394375
*/
395376
function toolLifecycleIdentity(activity: OrchestrationThreadActivity): string | null {
396377
const payload = asRecord(activity.payload);
397378
if (!payload) {
398379
return null;
399380
}
400381

401-
const toolCallId =
402-
asTrimmedString(payload.toolCallId) ?? asTrimmedString(asRecord(payload.data)?.toolCallId);
382+
const toolCallId = asTrimmedString(asRecord(payload.data)?.toolCallId);
403383
if (toolCallId) {
404384
return `id:${toolCallId}`;
405385
}

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2811,16 +2811,11 @@ describe("ProviderRuntimeIngestion", () => {
28112811
createdAt: now,
28122812
threadId: asThreadId("thread-1"),
28132813
turnId: asTurnId("turn-9"),
2814-
itemId: asItemId("tool-call-9"),
28152814
payload: {
28162815
itemType: "command_execution",
2817-
status: "inProgress",
2818-
title: "Command run",
2819-
detail: "Bash: vp test run",
2820-
data: {
2821-
toolName: "Bash",
2822-
input: { command: "vp test run" },
2823-
},
2816+
status: "in_progress",
2817+
title: "Read file",
2818+
detail: "/tmp/file.ts",
28242819
},
28252820
});
28262821

@@ -2835,20 +2830,11 @@ describe("ProviderRuntimeIngestion", () => {
28352830
);
28362831

28372832
expect(thread.session?.status).toBe("ready");
2838-
const activity = thread.activities.find(
2839-
(entry: ProviderRuntimeTestActivity) => entry.kind === "tool.started",
2840-
);
2841-
const payload = activity?.payload as Record<string, unknown> | undefined;
2842-
expect(payload).toMatchObject({
2843-
itemType: "command_execution",
2844-
toolCallId: "tool-call-9",
2845-
status: "inProgress",
2846-
detail: "Bash: vp test run",
2847-
data: {
2848-
toolName: "Bash",
2849-
input: { command: "vp test run" },
2850-
},
2851-
});
2833+
expect(
2834+
thread.activities.some(
2835+
(activity: ProviderRuntimeTestActivity) => activity.kind === "tool.started",
2836+
),
2837+
).toBe(true);
28522838
});
28532839

28542840
it("consumes P1 runtime events into thread metadata, diff checkpoints, and activities", async () => {

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,6 @@ export function runtimeEventToActivities(
794794
summary: event.payload.title ?? "Tool updated",
795795
payload: {
796796
itemType: event.payload.itemType,
797-
...(event.itemId !== undefined ? { toolCallId: event.itemId } : {}),
798797
...(event.payload.status ? { status: event.payload.status } : {}),
799798
...(event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {}),
800799
...(event.payload.data !== undefined ? { data: event.payload.data } : {}),
@@ -822,8 +821,6 @@ export function runtimeEventToActivities(
822821
summary: event.payload.title ?? "Tool",
823822
payload: {
824823
itemType: event.payload.itemType,
825-
...(event.itemId !== undefined ? { toolCallId: event.itemId } : {}),
826-
...(event.payload.status ? { status: event.payload.status } : {}),
827824
...(event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {}),
828825
...(event.payload.data !== undefined ? { data: event.payload.data } : {}),
829826
...(event.payload.agentId ? { agentId: event.payload.agentId } : {}),
@@ -850,10 +847,7 @@ export function runtimeEventToActivities(
850847
summary: `${event.payload.title ?? "Tool"} started`,
851848
payload: {
852849
itemType: event.payload.itemType,
853-
...(event.itemId !== undefined ? { toolCallId: event.itemId } : {}),
854-
...(event.payload.status ? { status: event.payload.status } : {}),
855850
...(event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {}),
856-
...(event.payload.data !== undefined ? { data: event.payload.data } : {}),
857851
...(event.payload.agentId ? { agentId: event.payload.agentId } : {}),
858852
...(event.payload.parentToolUseId
859853
? { parentToolUseId: event.payload.parentToolUseId }

apps/web/src/components/ChatView.tsx

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ import {
167167
WifiOffIcon,
168168
} from "lucide-react";
169169
import { cn, randomHex } from "~/lib/utils";
170+
import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "~/workspaceTitlebar";
170171
import { stackedThreadToast, toastManager } from "./ui/toast";
171172
import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings";
172173
import { type NewProjectScriptInput } from "./ProjectScriptsControl";
@@ -219,11 +220,7 @@ import {
219220
import { appendPreviewAnnotationPrompt } from "../lib/previewAnnotation";
220221
import { appendReviewCommentsToPrompt, type ReviewCommentContext } from "../reviewCommentContext";
221222
import { environmentCatalog } from "../connection/catalog";
222-
import {
223-
selectThreadTerminalCustomLabels,
224-
selectThreadTerminalUiState,
225-
useTerminalUiStateStore,
226-
} from "../terminalUiStateStore";
223+
import { selectThreadTerminalUiState, useTerminalUiStateStore } from "../terminalUiStateStore";
227224
import { useKnownTerminalSessions, useThreadRunningTerminalIds } from "../state/terminalSessions";
228225
import { projectEnvironment } from "../state/projects";
229226
import { useEnvironmentQuery } from "../state/query";
@@ -259,7 +256,6 @@ import { ChatHeader } from "./chat/ChatHeader";
259256
import { PanelLayoutControls, RightPanelMaximizeControl } from "./chat/PanelLayoutControls";
260257
import { type ExpandedImagePreview } from "./chat/ExpandedImagePreview";
261258
import { NoActiveThreadState } from "./NoActiveThreadState";
262-
import { WorkspacePageHeader } from "./WorkspacePageContainer";
263259
import {
264260
resolveEffectiveEnvMode,
265261
resolveLocalCheckoutBranchMismatch,
@@ -657,7 +653,6 @@ interface PersistentThreadTerminalDrawerProps {
657653
newShortcutLabel: string | undefined;
658654
closeShortcutLabel: string | undefined;
659655
keybindings: ResolvedKeybindingsConfig;
660-
onHide: () => void;
661656
onAddTerminalContext: (selection: TerminalContextSelection) => void;
662657
}
663658

@@ -672,7 +667,6 @@ const PersistentThreadTerminalDrawer = memo(function PersistentThreadTerminalDra
672667
newShortcutLabel,
673668
closeShortcutLabel,
674669
keybindings,
675-
onHide,
676670
onAddTerminalContext,
677671
}: PersistentThreadTerminalDrawerProps) {
678672
const openTerminal = useAtomCommand(terminalEnvironment.open, "terminal open");
@@ -996,7 +990,6 @@ const PersistentThreadTerminalDrawer = memo(function PersistentThreadTerminalDra
996990
onSplitTerminal={splitTerminal}
997991
onSplitTerminalVertical={splitTerminalVertical}
998992
onNewTerminal={createNewTerminal}
999-
onHide={onHide}
1000993
splitShortcutLabel={visible ? splitShortcutLabel : undefined}
1001994
splitVerticalShortcutLabel={visible ? splitVerticalShortcutLabel : undefined}
1002995
newShortcutLabel={visible ? newShortcutLabel : undefined}
@@ -1547,16 +1540,6 @@ function ChatViewContent(props: ChatViewProps) {
15471540
const canCheckoutPullRequestIntoThread = isLocalDraftThread;
15481541
const activeThreadId = activeThread?.id ?? null;
15491542
const activeThreadEnvironmentId = activeThread?.environmentId ?? null;
1550-
const activeThreadRef = useMemo(
1551-
() =>
1552-
activeThreadEnvironmentId && activeThreadId
1553-
? scopeThreadRef(activeThreadEnvironmentId, activeThreadId)
1554-
: null,
1555-
[activeThreadEnvironmentId, activeThreadId],
1556-
);
1557-
const activeTerminalCustomLabels = useTerminalUiStateStore((state) =>
1558-
selectThreadTerminalCustomLabels(state.terminalCustomLabelsByThreadKey, activeThreadRef),
1559-
);
15601543
const runningTerminalIds = useThreadRunningTerminalIds({
15611544
environmentId: activeThread?.environmentId ?? null,
15621545
threadId: activeThreadId,
@@ -1586,15 +1569,18 @@ function ChatViewContent(props: ChatViewProps) {
15861569
for (const session of activeThreadKnownSessions) {
15871570
labels.set(
15881571
session.target.terminalId,
1589-
activeTerminalCustomLabels[session.target.terminalId] ??
1590-
resolveTerminalSessionLabel(session.target.terminalId, session.state.summary),
1572+
resolveTerminalSessionLabel(session.target.terminalId, session.state.summary),
15911573
);
15921574
}
1593-
for (const [terminalId, label] of Object.entries(activeTerminalCustomLabels)) {
1594-
if (!labels.has(terminalId)) labels.set(terminalId, label);
1595-
}
15961575
return labels;
1597-
}, [activeTerminalCustomLabels, activeThreadKnownSessions]);
1576+
}, [activeThreadKnownSessions]);
1577+
const activeThreadRef = useMemo(
1578+
() =>
1579+
activeThreadEnvironmentId && activeThreadId
1580+
? scopeThreadRef(activeThreadEnvironmentId, activeThreadId)
1581+
: null,
1582+
[activeThreadEnvironmentId, activeThreadId],
1583+
);
15981584
const activeThreadKey = activeThreadRef ? scopedThreadKey(activeThreadRef) : null;
15991585
const [timelineAnchor, setTimelineAnchor] = useState<{
16001586
readonly threadKey: string | null;
@@ -2822,7 +2808,6 @@ function ChatViewContent(props: ChatViewProps) {
28222808
},
28232809
[activeThreadRef, storeSetTerminalOpen],
28242810
);
2825-
const hideTerminal = useCallback(() => setTerminalOpen(false), [setTerminalOpen]);
28262811
const toggleTerminalVisibility = useCallback(() => {
28272812
if (!activeThreadRef) return;
28282813
const nextOpen = !terminalUiState.terminalOpen;
@@ -6129,6 +6114,7 @@ function ChatViewContent(props: ChatViewProps) {
61296114
? "thread"
61306115
: "page"
61316116
}
6117+
chromeVariant="collapse"
61326118
composerDraftTarget={composerDraftTarget}
61336119
onStateChange={handlePullRequestTabStatusChange}
61346120
/>
@@ -6174,11 +6160,20 @@ function ChatViewContent(props: ChatViewProps) {
61746160
data-chat-column-maximized-away={rightPanelMaximized ? "true" : "false"}
61756161
>
61766162
{/* Top bar */}
6177-
<WorkspacePageHeader
6163+
<header
61786164
data-chat-header
6179-
electron={isElectron}
6180-
reserveNativeControls={reserveTitleBarControlInset && !inlineRightPanelOwnsTitleBar}
6181-
className="relative bg-background"
6165+
className={cn(
6166+
"bg-background transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none",
6167+
isElectron
6168+
? cn(
6169+
"drag-region relative flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center px-3 sm:px-5",
6170+
reserveTitleBarControlInset &&
6171+
!inlineRightPanelOwnsTitleBar &&
6172+
"wco:pr-[var(--workspace-native-controls-inset)]",
6173+
)
6174+
: "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)]",
6175+
COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,
6176+
)}
61826177
>
61836178
{!rightPanelOpen ? panelLayoutControls : null}
61846179
<ChatHeader
@@ -6209,7 +6204,7 @@ function ChatViewContent(props: ChatViewProps) {
62096204
onUpdateProjectScript={updateProjectScript}
62106205
onDeleteProjectScript={deleteProjectScript}
62116206
/>
6212-
</WorkspacePageHeader>
6207+
</header>
62136208

62146209
<ThreadErrorBanner
62156210
error={visibleThreadError}
@@ -6547,7 +6542,6 @@ function ChatViewContent(props: ChatViewProps) {
65476542
newShortcutLabel={newTerminalShortcutLabel ?? undefined}
65486543
closeShortcutLabel={closeTerminalShortcutLabel ?? undefined}
65496544
keybindings={keybindings}
6550-
onHide={hideTerminal}
65516545
onAddTerminalContext={addTerminalContextToDraft}
65526546
/>
65536547
))}

0 commit comments

Comments
 (0)