Merge branch 'storage-terminal-ui-dev' into dev

# Conflicts:
#	nix/package.nix
#	packages/app/src/app/_layout.tsx
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/hooks/use-command-center.ts
#	packages/app/src/screens/agent/draft-agent-screen.tsx
#	packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx
#	packages/app/src/screens/workspace/workspace-screen.tsx
#	packages/server/src/server/session.ts
#	packages/server/src/server/session.workspaces.test.ts
#	packages/server/src/terminal/terminal.test.ts
#	packages/server/src/terminal/terminal.ts
This commit is contained in:
Mohamed Boudra
2026-04-01 21:51:29 +07:00
217 changed files with 21075 additions and 4943 deletions
@@ -14,6 +14,7 @@ import {
ArrowRightToLine,
Columns2,
Copy,
Plus,
Rows2,
SquarePen,
SquareTerminal,
@@ -46,11 +47,6 @@ import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-
const DROPDOWN_WIDTH = 220;
const LOADING_TAB_LABEL_SKELETON_WIDTH = 80;
type NewTabOptionId = "__new_tab_agent__" | "__new_tab_terminal__";
type NewTabSelection = {
optionId: NewTabOptionId;
paneId?: string;
};
export interface WorkspaceDesktopTabRowItem {
tab: WorkspaceTabDescriptor;
@@ -74,10 +70,8 @@ type WorkspaceDesktopTabsRowProps = {
onCloseTabsToLeft: (tabId: string) => Promise<void> | void;
onCloseTabsToRight: (tabId: string) => Promise<void> | void;
onCloseOtherTabs: (tabId: string) => Promise<void> | void;
onSelectNewTabOption: (selection: NewTabSelection) => void;
newTabAgentOptionId: NewTabOptionId;
onCreateLauncherTab: (input: { paneId?: string }) => void;
onReorderTabs: (nextTabs: WorkspaceTabDescriptor[]) => void;
onNewTerminalTab: (input: { paneId?: string }) => void;
onSplitRight: () => void;
onSplitDown: () => void;
externalDndContext?: boolean;
@@ -87,6 +81,9 @@ type WorkspaceDesktopTabsRowProps = {
};
function getFallbackTabLabel(tab: WorkspaceTabDescriptor): string {
if (tab.target.kind === "launcher") {
return "New Tab";
}
if (tab.target.kind === "draft") {
return "New Agent";
}
@@ -338,10 +335,8 @@ export function WorkspaceDesktopTabsRow({
onCloseTabsToLeft,
onCloseTabsToRight,
onCloseOtherTabs,
onSelectNewTabOption,
newTabAgentOptionId,
onCreateLauncherTab,
onReorderTabs,
onNewTerminalTab,
onSplitRight,
onSplitDown,
externalDndContext = false,
@@ -350,8 +345,7 @@ export function WorkspaceDesktopTabsRow({
showPaneSplitActions = true,
}: WorkspaceDesktopTabsRowProps) {
const { theme } = useUnistyles();
const newAgentTabKeys = useShortcutKeys("workspace-tab-new");
const newTerminalTabKeys = useShortcutKeys("workspace-terminal-new");
const newTabKeys = useShortcutKeys("workspace-tab-new");
const splitRightKeys = useShortcutKeys("workspace-pane-split-right");
const splitDownKeys = useShortcutKeys("workspace-pane-split-down");
const [tabsContainerWidth, setTabsContainerWidth] = useState<number>(0);
@@ -478,48 +472,22 @@ export function WorkspaceDesktopTabsRow({
<View style={styles.tabsActions} onLayout={handleTabsActionsLayout}>
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
<TooltipTrigger
testID="workspace-new-agent-tab"
onPress={() =>
onSelectNewTabOption({
optionId: newTabAgentOptionId,
paneId,
})
}
testID="workspace-new-tab"
onPress={() => onCreateLauncherTab({ paneId })}
accessibilityRole="button"
accessibilityLabel="New agent tab"
accessibilityLabel="New tab"
style={({ hovered, pressed }) => [
styles.newTabActionButton,
(hovered || pressed) && styles.newTabActionButtonHovered,
]}
>
<SquarePen size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
<Plus size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
</TooltipTrigger>
<TooltipContent side="bottom" align="center" offset={8}>
<View style={styles.newTabTooltipRow}>
<Text style={styles.newTabTooltipText}>New agent tab</Text>
{newAgentTabKeys ? (
<Shortcut chord={newAgentTabKeys} style={styles.newTabTooltipShortcut} />
) : null}
</View>
</TooltipContent>
</Tooltip>
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
<TooltipTrigger
onPress={() => onNewTerminalTab({ paneId })}
accessibilityRole="button"
accessibilityLabel="New terminal tab"
style={({ hovered, pressed }) => [
styles.newTabActionButton,
(hovered || pressed) && styles.newTabActionButtonHovered,
]}
>
<SquareTerminal size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
</TooltipTrigger>
<TooltipContent side="bottom" align="center" offset={8}>
<View style={styles.newTabTooltipRow}>
<Text style={styles.newTabTooltipText}>New terminal tab</Text>
{newTerminalTabKeys ? (
<Shortcut chord={newTerminalTabKeys} style={styles.newTabTooltipShortcut} />
<Text style={styles.newTabTooltipText}>New tab</Text>
{newTabKeys ? (
<Shortcut chord={newTabKeys} style={styles.newTabTooltipShortcut} />
) : null}
</View>
</TooltipContent>