diff --git a/packages/app/src/panels/draft-panel.tsx b/packages/app/src/panels/draft-panel.tsx
index be9623c60..5db7b5372 100644
--- a/packages/app/src/panels/draft-panel.tsx
+++ b/packages/app/src/panels/draft-panel.tsx
@@ -18,8 +18,15 @@ function useDraftPanelDescriptor() {
}
function DraftPanel() {
- const { serverId, workspaceId, tabId, target, openFileInWorkspace, retargetCurrentTab } =
- usePaneContext();
+ const {
+ serverId,
+ workspaceId,
+ tabId,
+ target,
+ openFileInWorkspace,
+ openImportSheet,
+ retargetCurrentTab,
+ } = usePaneContext();
const { isInteractive } = usePaneFocus();
invariant(target.kind === "draft", "DraftPanel requires draft target");
@@ -52,6 +59,7 @@ function DraftPanel() {
isPaneFocused={isInteractive}
onOpenWorkspaceFile={handleOpenWorkspaceFile}
onCreated={handleCreated}
+ onOpenImportSheet={openImportSheet}
/>
);
}
diff --git a/packages/app/src/panels/pane-context.tsx b/packages/app/src/panels/pane-context.tsx
index 4ee0c6c0a..34c5869f5 100644
--- a/packages/app/src/panels/pane-context.tsx
+++ b/packages/app/src/panels/pane-context.tsx
@@ -11,6 +11,7 @@ export interface PaneContextValue {
closeCurrentTab: () => void;
retargetCurrentTab: (target: WorkspaceTabTarget) => void;
openFileInWorkspace: (filePath: string) => void;
+ openImportSheet: () => void;
}
export interface PaneFocusContextValue {
diff --git a/packages/app/src/screens/workspace/composer-import-pill.tsx b/packages/app/src/screens/workspace/composer-import-pill.tsx
new file mode 100644
index 000000000..25267a834
--- /dev/null
+++ b/packages/app/src/screens/workspace/composer-import-pill.tsx
@@ -0,0 +1,63 @@
+import { useCallback, useMemo, useState } from "react";
+import { Pressable, Text, View } from "react-native";
+import { StyleSheet, withUnistyles } from "react-native-unistyles";
+import { Import as ImportIcon } from "lucide-react-native";
+import type { Theme } from "@/styles/theme";
+
+const ThemedImportIcon = withUnistyles(ImportIcon);
+const iconColorMapping = (theme: Theme) => ({ color: theme.colors.foregroundMuted });
+
+interface ComposerImportPillProps {
+ onPress: () => void;
+ disabled?: boolean;
+}
+
+export function ComposerImportPill({ onPress, disabled = false }: ComposerImportPillProps) {
+ const [isHovered, setIsHovered] = useState(false);
+ const handleHoverIn = useCallback(() => setIsHovered(true), []);
+ const handleHoverOut = useCallback(() => setIsHovered(false), []);
+ const bodyStyle = useMemo(() => [styles.body, isHovered && styles.bodyHovered], [isHovered]);
+ return (
+
+
+
+
+ Import agent
+
+
+
+ );
+}
+
+const styles = StyleSheet.create((theme) => ({
+ row: {
+ flexDirection: "row",
+ },
+ body: {
+ flexDirection: "row",
+ alignItems: "center",
+ gap: theme.spacing[2],
+ paddingHorizontal: theme.spacing[3],
+ paddingVertical: theme.spacing[2],
+ borderRadius: theme.borderRadius.md,
+ borderWidth: theme.borderWidth[1],
+ borderColor: theme.colors.borderAccent,
+ backgroundColor: theme.colors.surface1,
+ },
+ bodyHovered: {
+ backgroundColor: theme.colors.surface2,
+ },
+ label: {
+ color: theme.colors.foreground,
+ fontSize: theme.fontSize.sm,
+ },
+}));
diff --git a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx
index c8aca2261..6c2837052 100644
--- a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx
+++ b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx
@@ -4,6 +4,7 @@ import { StyleSheet } from "react-native-unistyles";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import invariant from "tiny-invariant";
import { Composer } from "@/components/composer";
+import { ComposerImportPill } from "@/screens/workspace/composer-import-pill";
import { FileDropZone } from "@/components/file-drop-zone";
import { AgentStreamView } from "@/components/agent-stream-view";
import { composerWorkspaceAttachment } from "@/attachments/composer-workspace-attachments";
@@ -28,7 +29,7 @@ import {
useWorkspaceAttachmentScopeKey,
} from "@/attachments/workspace-attachments-store";
import type { UserMessageImageAttachment } from "@/types/stream";
-import { useIsCompactFormFactor } from "@/constants/layout";
+import { MAX_CONTENT_WIDTH, useIsCompactFormFactor } from "@/constants/layout";
import { isWeb } from "@/constants/platform";
const EMPTY_PENDING_PERMISSIONS = new Map();
@@ -278,6 +279,7 @@ interface WorkspaceDraftAgentTabProps {
isPaneFocused: boolean;
onCreated: (snapshot: AgentSnapshotPayload) => void;
onOpenWorkspaceFile: (input: { filePath: string }) => void;
+ onOpenImportSheet?: () => void;
}
export function WorkspaceDraftAgentTab({
@@ -288,6 +290,7 @@ export function WorkspaceDraftAgentTab({
isPaneFocused,
onCreated,
onOpenWorkspaceFile,
+ onOpenImportSheet,
}: WorkspaceDraftAgentTabProps) {
const insets = useSafeAreaInsets();
const client = useHostRuntimeClient(serverId);
@@ -590,6 +593,13 @@ export function WorkspaceDraftAgentTab({
+ {onOpenImportSheet ? (
+
+
+
+
+
+ ) : null}
({
width: "100%",
backgroundColor: theme.colors.surface0,
},
+ importPillRow: {
+ width: "100%",
+ paddingHorizontal: theme.spacing[4],
+ paddingTop: theme.spacing[3],
+ paddingBottom: theme.spacing[3],
+ alignItems: "center",
+ },
+ importPillContent: {
+ width: "100%",
+ maxWidth: MAX_CONTENT_WIDTH,
+ flexDirection: "row",
+ },
errorContainer: {
marginTop: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
diff --git a/packages/app/src/screens/workspace/workspace-pane-content.test.tsx b/packages/app/src/screens/workspace/workspace-pane-content.test.tsx
index c4c422809..d700da58c 100644
--- a/packages/app/src/screens/workspace/workspace-pane-content.test.tsx
+++ b/packages/app/src/screens/workspace/workspace-pane-content.test.tsx
@@ -64,6 +64,7 @@ function buildContent() {
onCloseCurrentTab: vi.fn(),
onRetargetCurrentTab: vi.fn(),
onOpenWorkspaceFile: vi.fn(),
+ onOpenImportSheet: vi.fn(),
});
}
diff --git a/packages/app/src/screens/workspace/workspace-pane-content.tsx b/packages/app/src/screens/workspace/workspace-pane-content.tsx
index f0d9b3ab8..cef49ad59 100644
--- a/packages/app/src/screens/workspace/workspace-pane-content.tsx
+++ b/packages/app/src/screens/workspace/workspace-pane-content.tsx
@@ -24,6 +24,7 @@ export interface BuildWorkspacePaneContentModelInput {
onCloseCurrentTab: () => void;
onRetargetCurrentTab: (target: WorkspaceTabDescriptor["target"]) => void;
onOpenWorkspaceFile: (filePath: string) => void;
+ onOpenImportSheet: () => void;
}
export function buildWorkspacePaneContentModel({
@@ -34,6 +35,7 @@ export function buildWorkspacePaneContentModel({
onCloseCurrentTab,
onRetargetCurrentTab,
onOpenWorkspaceFile,
+ onOpenImportSheet,
}: BuildWorkspacePaneContentModelInput): WorkspacePaneContentModel {
ensurePanelsRegistered();
const registration = getPanelRegistration(tab.kind);
@@ -50,6 +52,7 @@ export function buildWorkspacePaneContentModel({
closeCurrentTab: onCloseCurrentTab,
retargetCurrentTab: onRetargetCurrentTab,
openFileInWorkspace: onOpenWorkspaceFile,
+ openImportSheet: onOpenImportSheet,
},
};
}
diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx
index 5bb8cf134..2725c430c 100644
--- a/packages/app/src/screens/workspace/workspace-screen.tsx
+++ b/packages/app/src/screens/workspace/workspace-screen.tsx
@@ -2833,6 +2833,7 @@ function WorkspaceScreenContent({
}
handleOpenFileFromChat({ filePath });
},
+ onOpenImportSheet: openImportSheet,
}),
[
handleCloseTabById,
@@ -2841,6 +2842,7 @@ function WorkspaceScreenContent({
navigateToTabId,
normalizedServerId,
normalizedWorkspaceId,
+ openImportSheet,
openWorkspaceTabFocused,
persistenceKey,
convertWorkspaceDraftToAgent,