diff --git a/packages/app/src/app/agent/[serverId]/[agentId].tsx b/packages/app/src/app/agent/[serverId]/[agentId].tsx
index 68b8027c6..99c984a77 100644
--- a/packages/app/src/app/agent/[serverId]/[agentId].tsx
+++ b/packages/app/src/app/agent/[serverId]/[agentId].tsx
@@ -29,7 +29,6 @@ import {
GitBranch,
Folder,
RotateCcw,
- Download,
Users,
ChevronRight,
PlusIcon,
@@ -39,7 +38,6 @@ import { MenuHeader } from "@/components/headers/menu-header";
import { BackHeader } from "@/components/headers/back-header";
import { AgentStreamView } from "@/components/agent-stream-view";
import { AgentInputArea } from "@/components/agent-input-area";
-import { ImportAgentModal } from "@/components/create-agent-modal";
import { ExplorerSidebar } from "@/components/explorer-sidebar";
import { FileDropZone } from "@/components/file-drop-zone";
import type { ImageAttachment } from "@/components/message-input";
@@ -184,7 +182,6 @@ function AgentScreenContent({
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
const [menuContentHeight, setMenuContentHeight] = useState(0);
const menuButtonRef = useRef(null);
- const [showImportAgentModal, setShowImportAgentModal] = useState(false);
const addImagesRef = useRef<((images: ImageAttachment[]) => void) | null>(null);
const handleFilesDropped = useCallback((files: ImageAttachment[]) => {
@@ -636,15 +633,6 @@ function AgentScreenContent({
router.push({ pathname: "/", params });
}, [agent, agentModel, handleCloseMenu, router, serverId]);
- const handleImportAgent = useCallback(() => {
- handleCloseMenu();
- setShowImportAgentModal(true);
- }, [handleCloseMenu]);
-
- const handleCloseImportAgentModal = useCallback(() => {
- setShowImportAgentModal(false);
- }, []);
-
const handleNavigateToChildAgent = useCallback(
(childAgentId: string) => {
handleCloseMenu();
@@ -659,25 +647,14 @@ function AgentScreenContent({
[handleCloseMenu, router, serverId]
);
- const importAgentModal = (
-
- );
-
if (!agent) {
return (
- <>
-
-
-
- Agent not found
-
+
+
+
+ Agent not found
- {importAgentModal}
- >
+
);
}
@@ -879,10 +856,6 @@ function AgentScreenContent({
Browse Files
-
-
- Import Agent
-
New Agent
@@ -934,8 +907,6 @@ function AgentScreenContent({
{isMobile && resolvedAgentId && (
)}
-
- {importAgentModal}
>
);
}
diff --git a/packages/app/src/components/create-agent-modal.tsx b/packages/app/src/components/create-agent-modal.tsx
index f54e31992..3cc2022a0 100644
--- a/packages/app/src/components/create-agent-modal.tsx
+++ b/packages/app/src/components/create-agent-modal.tsx
@@ -11,14 +11,11 @@ import {
Text,
Pressable,
ScrollView,
- FlatList,
ActivityIndicator,
InteractionManager,
- TextInput,
Modal,
useWindowDimensions,
type LayoutChangeEvent,
- type ListRenderItem,
Platform,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
@@ -31,7 +28,7 @@ import Animated, {
runOnJS,
} from "react-native-reanimated";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
-import { Monitor, X } from "lucide-react-native";
+import { X } from "lucide-react-native";
import { theme as defaultTheme } from "@/styles/theme";
import { useRecentPaths } from "@/hooks/use-recent-paths";
import { useRouter } from "expo-router";
@@ -41,8 +38,6 @@ import { useDaemonConnections, type ConnectionStatus } from "@/contexts/daemon-c
import type {
AgentProvider,
AgentSessionConfig,
- AgentPersistenceHandle,
- AgentTimelineItem,
} from "@server/server/agent/agent-sdk-types";
import { useDaemonRequest } from "@/hooks/use-daemon-request";
import type { WSInboundMessage, SessionOutboundMessage } from "@server/server/messages";
@@ -53,8 +48,8 @@ import type { UseWebSocketReturn } from "@/hooks/use-websocket";
import { useSessionStore, type Agent } from "@/stores/session-store";
import {
AssistantDropdown,
- DropdownField,
DropdownSheet,
+ GitOptionsSection,
ModelDropdown,
PermissionsDropdown,
WorkingDirectoryDropdown,
@@ -67,7 +62,6 @@ import {
interface AgentFlowModalProps {
isVisible: boolean;
onClose: () => void;
- flow: "create" | "import";
initialValues?: CreateAgentInitialValues;
serverId?: string | null;
onAfterClose?: () => void;
@@ -90,7 +84,6 @@ type CreateAgentSessionSlice = {
worktreeName?: string;
requestId?: string;
}) => void;
- resumeAgent: (options: { handle: any; overrides?: any; requestId?: string }) => void;
sendAgentAudio: (
agentId: string | undefined,
audioBlob: Blob,
@@ -101,20 +94,8 @@ type CreateAgentSessionSlice = {
};
const BACKDROP_OPACITY = 0.55;
-const IMPORT_PAGE_SIZE = 20;
const IS_WEB = Platform.OS === "web";
-type ImportCandidate = {
- provider: AgentProvider;
- sessionId: string;
- cwd: string;
- title: string;
- lastActivityAt: Date;
- persistence: AgentPersistenceHandle;
- timeline: AgentTimelineItem[];
-};
-
-type ProviderFilter = "all" | AgentProvider;
type DropdownKey =
| "assistant"
| "permissions"
@@ -136,43 +117,9 @@ type GitRepoInfoResponseMessage = Extract<
{ type: "git_repo_info_response" }
>;
-function formatRelativeTime(date: Date): string {
- const now = Date.now();
- const diffMs = now - date.getTime();
- if (!Number.isFinite(diffMs)) {
- return "unknown";
- }
- const minutes = Math.max(0, Math.floor(diffMs / 60000));
- if (minutes < 1) {
- return "just now";
- }
- if (minutes < 60) {
- return `${minutes}m ago`;
- }
- const hours = Math.floor(minutes / 60);
- if (hours < 24) {
- return `${hours}h ago`;
- }
- const days = Math.floor(hours / 24);
- return `${days}d ago`;
-}
-
-function getImportPreview(candidate: ImportCandidate): string {
- for (const item of candidate.timeline) {
- if (item.type === "user_message") {
- const text = item.text.trim();
- if (text.length > 0) {
- return text;
- }
- }
- }
- return candidate.title || candidate.cwd;
-}
-
function AgentFlowModal({
isVisible,
onClose,
- flow,
initialValues,
serverId,
onAfterClose,
@@ -182,10 +129,7 @@ function AgentFlowModal({
const slideOffset = useSharedValue(screenHeight);
const backdropOpacity = useSharedValue(0);
const { height: keyboardHeight } = useReanimatedKeyboardAnimation();
- const isCompactLayout = screenWidth < 720;
const shouldAutoFocusPrompt = IS_WEB;
- const isImportFlow = flow === "import";
- const isCreateFlow = !isImportFlow;
const { addRecentPath } = useRecentPaths();
const { connectionStates } = useDaemonConnections();
@@ -223,7 +167,7 @@ function AgentFlowModal({
initialServerId,
initialValues,
isVisible,
- isCreateFlow,
+ isCreateFlow: true,
});
const sessionState = useSessionStore((state) =>
@@ -239,7 +183,6 @@ function AgentFlowModal({
serverId: selectedServerId,
ws: sessionState.ws,
createAgent: sessionState.methods.createAgent,
- resumeAgent: sessionState.methods.resumeAgent,
sendAgentAudio: sessionState.methods.sendAgentAudio,
agents: sessionState.agents,
};
@@ -299,7 +242,6 @@ function AgentFlowModal({
const ws = session?.ws ?? null;
const effectiveWs: UseWebSocketReturn = ws ?? inertWebSocket;
const createAgent = session?.createAgent;
- const resumeAgent = session?.resumeAgent;
const sessionSendAgentAudio = session?.sendAgentAudio;
const noopSendAgentAudio = useCallback(async () => {}, []);
const sendAgentAudio = sessionSendAgentAudio ?? noopSendAgentAudio;
@@ -377,11 +319,10 @@ function AgentFlowModal({
"Selected host";
const selectedDaemonStatusLabel = formatConnectionStatus(selectedDaemonStatus);
const hasSelectedDaemon = Boolean(selectedServerId);
- const hostBadgeLabel = hasSelectedDaemon ? selectedDaemonLabel : "Select host";
const selectedDaemonIsOffline = selectedDaemonStatus !== "online";
const selectedDaemonLastError = selectedDaemonConnection?.lastError?.trim();
const daemonAvailabilityError = !hasSelectedDaemon
- ? "Select a host before creating or importing agents."
+ ? "Select a host before creating agents."
: selectedDaemonIsOffline
? `${selectedDaemonLabel} is ${selectedDaemonStatusLabel}. We'll reconnect automatically and enable actions once it's online.${
selectedDaemonLastError ? ` ${selectedDaemonLastError}` : ""
@@ -396,29 +337,14 @@ function AgentFlowModal({
const [isMounted, setIsMounted] = useState(isVisible);
const [initialPrompt, setInitialPrompt] = useState("");
- const [baseBranch, setBaseBranch] = useState("");
- const [createNewBranch, setCreateNewBranch] = useState(false);
- const [branchName, setBranchName] = useState("");
- const [createWorktree, setCreateWorktree] = useState(false);
- const [worktreeSlug, setWorktreeSlug] = useState("");
- const [branchNameEdited, setBranchNameEdited] = useState(false);
- const [worktreeSlugEdited, setWorktreeSlugEdited] = useState(false);
+ const [useWorktree, setUseWorktree] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const [isLoading, setIsLoading] = useState(false);
- const [importProviderFilter, setImportProviderFilter] =
- useState("all");
- const [importSearchQuery, setImportSearchQuery] = useState("");
- const [importCandidates, setImportCandidates] = useState(
- []
- );
- const [isImportLoading, setIsImportLoading] = useState(false);
- const [importError, setImportError] = useState(null);
const [openDropdown, setOpenDropdown] = useState(null);
const pendingRequestIdRef = useRef(null);
- const shouldSyncBaseBranchRef = useRef(true);
- const hasPendingCreateOrResume = pendingRequestIdRef.current !== null;
- const shouldListenForStatus = isVisible || hasPendingCreateOrResume;
+ const hasPendingCreate = pendingRequestIdRef.current !== null;
+ const shouldListenForStatus = isVisible || hasPendingCreate;
const idleProviderPrefetchHandleRef = useRef {
setWorkingDirFromUser(value);
setErrorMessage("");
- shouldSyncBaseBranchRef.current = true;
},
[setWorkingDirFromUser]
);
- const handleBaseBranchChange = useCallback(
- (value: string) => {
- shouldSyncBaseBranchRef.current = false;
- setBaseBranch(value);
- setErrorMessage("");
- },
- [setErrorMessage]
- );
-
-
- const providerFilterOptions = useMemo(
- () => [
- { id: "all" as ProviderFilter, label: "All" },
- ...providerDefinitions.map((definition) => ({
- id: definition.id as ProviderFilter,
- label: definition.label,
- })),
- ],
- []
- );
- const getProviderLabel = useCallback(
- (provider: AgentProvider) =>
- providerDefinitionMap.get(provider)?.label ?? provider,
- []
- );
-
- const activeSessionIds = useMemo(() => {
- const ids = new Set();
- if (!agents) {
- return ids;
- }
- // Use persistence.sessionId for filtering - this is the canonical reference
- // to the provider's session file (Claude resume token, Codex thread ID, etc.)
- agents.forEach((agent) => {
- const persistedSessionId = agent.persistence?.sessionId;
- if (persistedSessionId) {
- ids.add(persistedSessionId);
- }
- });
- return ids;
- }, [agents]);
- const filteredImportCandidates = useMemo(() => {
- const providerFilter = importProviderFilter;
- const query = importSearchQuery.trim().toLowerCase();
- return importCandidates
- .filter((candidate) => !activeSessionIds.has(candidate.sessionId))
- .filter(
- (candidate) =>
- providerFilter === "all" || candidate.provider === providerFilter
- )
- .filter((candidate) => {
- if (query.length === 0) {
- return true;
- }
- const titleText = candidate.title.toLowerCase();
- const cwdText = candidate.cwd.toLowerCase();
- return titleText.includes(query) || cwdText.includes(query);
- })
- .sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime());
- }, [
- activeSessionIds,
- importCandidates,
- importProviderFilter,
- importSearchQuery,
- ]);
-
const logOfflineDaemonAction = useCallback(
- (action: "create" | "resume" | "dictation" | "import_list", reason?: string | null) => {
+ (action: "create" | "dictation", reason?: string | null) => {
trackAnalyticsEvent({
type: "offline_daemon_action_attempt",
action,
@@ -526,20 +385,13 @@ function AgentFlowModal({
const resetFormState = useCallback(() => {
setInitialPrompt("");
- setBaseBranch("");
- setCreateNewBranch(false);
- setBranchName("");
- setCreateWorktree(false);
- setWorktreeSlug("");
- setBranchNameEdited(false);
- setWorktreeSlugEdited(false);
+ setUseWorktree(false);
setErrorMessage("");
setIsLoading(false);
resetRepoInfo();
setOpenDropdown(null);
pendingRequestIdRef.current = null;
pendingNavigationServerIdRef.current = null;
- shouldSyncBaseBranchRef.current = true;
cancelRepoInfo();
}, [cancelRepoInfo, resetRepoInfo]);
@@ -578,41 +430,6 @@ function AgentFlowModal({
onAfterClose?.();
}, [navigateToAgentIfNeeded, onAfterClose, resetFormState]);
- const requestImportCandidates = useCallback(
- (provider?: AgentProvider) => {
- if (!isTargetDaemonReady || !ws || !ws.isConnected) {
- setIsImportLoading(false);
- logOfflineDaemonAction("import_list");
- setImportError(
- daemonAvailabilityError ??
- "Import candidates load automatically once the selected host is back online."
- );
- return;
- }
- setIsImportLoading(true);
- setImportError(null);
- const msg: WSInboundMessage = {
- type: "session",
- message: {
- type: "list_persisted_agents_request",
- ...(provider ? { provider } : {}),
- limit: IMPORT_PAGE_SIZE,
- },
- };
- try {
- ws.send(msg);
- } catch (error) {
- console.error(
- "[CreateAgentModal] Failed to request persisted agents:",
- error
- );
- setIsImportLoading(false);
- setImportError("Unable to load agents to import. Please try again.");
- }
- },
- [daemonAvailabilityError, isTargetDaemonReady, logOfflineDaemonAction, ws]
- );
-
useEffect(() => {
if (!isVisible) {
console.log(
@@ -754,27 +571,6 @@ function AgentFlowModal({
onClose();
}, [onClose]);
- useEffect(() => {
- const slug = slugifyWorktreeName(initialPrompt);
- if (!branchNameEdited) {
- setBranchName(slug);
- }
- if (!worktreeSlugEdited) {
- setWorktreeSlug(slug);
- }
- }, [
- initialPrompt,
- branchNameEdited,
- worktreeSlugEdited,
- slugifyWorktreeName,
- ]);
-
- useEffect(() => {
- if (!isCreateFlow || !isVisible) {
- return;
- }
- shouldSyncBaseBranchRef.current = true;
- }, [isCreateFlow, isVisible, workingDir]);
useEffect(() => {
idleProviderPrefetchHandleRef.current?.cancel?.();
@@ -802,7 +598,7 @@ function AgentFlowModal({
]);
const trimmedWorkingDir = workingDir.trim();
- const shouldInspectRepo = isCreateFlow && isVisible && trimmedWorkingDir.length > 0;
+ const shouldInspectRepo = isVisible && trimmedWorkingDir.length > 0;
const repoAvailabilityError = shouldInspectRepo && (!isTargetDaemonReady || !isWsConnected)
? daemonAvailabilityError ??
"Repository details will load automatically once the selected host is back online."
@@ -854,45 +650,32 @@ function AgentFlowModal({
]);
useEffect(() => {
- if (!repoInfo) {
- return;
+ if (isNonGitDirectory && useWorktree) {
+ setUseWorktree(false);
}
- setBaseBranch((prev) => {
- if (shouldSyncBaseBranchRef.current || prev.trim().length === 0) {
- shouldSyncBaseBranchRef.current = false;
- return repoInfo.currentBranch ?? "";
- }
- return prev;
- });
- }, [repoInfo]);
+ }, [isNonGitDirectory, useWorktree]);
- useEffect(() => {
- if (!isNonGitDirectory) {
- return;
+ const gitBlockingError = useMemo(() => {
+ if (!useWorktree || isNonGitDirectory) {
+ return null;
}
- if (
- createNewBranch ||
- createWorktree ||
- baseBranch.trim().length > 0 ||
- branchName.trim().length > 0 ||
- worktreeSlug.trim().length > 0
- ) {
- setCreateNewBranch(false);
- setCreateWorktree(false);
- setBaseBranch("");
- setBranchName("");
- setWorktreeSlug("");
- setBranchNameEdited(false);
- setWorktreeSlugEdited(false);
- shouldSyncBaseBranchRef.current = true;
+ const slug = slugifyWorktreeName(initialPrompt);
+ if (!slug) {
+ return null;
}
+ const validation = validateWorktreeName(slug);
+ if (!validation.valid) {
+ return `Invalid worktree name: ${
+ validation.error ?? "Must use lowercase letters, numbers, or hyphens"
+ }`;
+ }
+ return null;
}, [
- baseBranch,
- branchName,
- createNewBranch,
- createWorktree,
+ useWorktree,
isNonGitDirectory,
- worktreeSlug,
+ initialPrompt,
+ slugifyWorktreeName,
+ validateWorktreeName,
]);
const handleCreate = useCallback(async () => {
@@ -926,8 +709,6 @@ function AgentFlowModal({
return;
}
- const trimmedBaseBranch = baseBranch.trim();
-
try {
await addRecentPath(trimmedPath);
} catch (error) {
@@ -952,24 +733,11 @@ function AgentFlowModal({
...(trimmedModel ? { model: trimmedModel } : {}),
};
- const currentBranch = repoInfo?.currentBranch ?? "";
- const shouldIncludeBase =
- createNewBranch ||
- createWorktree ||
- (trimmedBaseBranch.length > 0 && trimmedBaseBranch !== currentBranch);
-
- const gitOptions = shouldIncludeBase && !isNonGitDirectory
+ const worktreeSlug = slugifyWorktreeName(trimmedPrompt);
+ const gitOptions = useWorktree && !isNonGitDirectory && worktreeSlug
? {
- ...(trimmedBaseBranch ? { baseBranch: trimmedBaseBranch } : {}),
- ...(createNewBranch
- ? { createNewBranch: true, newBranchName: branchName.trim() }
- : {}),
- ...(createWorktree
- ? {
- createWorktree: true,
- worktreeSlug: (worktreeSlug || branchName).trim(),
- }
- : {}),
+ createWorktree: true,
+ worktreeSlug,
}
: undefined;
@@ -990,117 +758,23 @@ function AgentFlowModal({
}, [
workingDir,
initialPrompt,
- baseBranch,
- createNewBranch,
- branchName,
- createWorktree,
- worktreeSlug,
- repoInfo,
+ useWorktree,
+ slugifyWorktreeName,
selectedMode,
modeOptions,
logOfflineDaemonAction,
selectedProvider,
isLoading,
- validateWorktreeName,
addRecentPath,
createAgent,
daemonAvailabilityError,
isTargetDaemonReady,
selectedDaemonId,
+ isNonGitDirectory,
+ gitBlockingError,
+ selectedModel,
]);
- const handleImportCandidatePress = useCallback(
- (candidate: ImportCandidate) => {
- if (isLoading) {
- return;
- }
- if (!resumeAgent || !isTargetDaemonReady) {
- logOfflineDaemonAction("resume");
- setImportError(
- daemonAvailabilityError ??
- "Importing agents will resume automatically once the selected host is online."
- );
- return;
- }
- setErrorMessage("");
- const requestId = generateMessageId();
- pendingRequestIdRef.current = requestId;
- pendingNavigationServerIdRef.current = selectedDaemonId ?? null;
- setIsLoading(true);
- resumeAgent({
- handle: candidate.persistence,
- requestId,
- });
- },
- [
- daemonAvailabilityError,
- isLoading,
- logOfflineDaemonAction,
- isTargetDaemonReady,
- resumeAgent,
- selectedDaemonId,
- setImportError,
- ]
- );
-
- const renderImportItem = useCallback>(
- ({ item }) => (
- handleImportCandidatePress(item)}
- disabled={isLoading || !isTargetDaemonReady}
- style={styles.resumeItem}
- >
-
-
- {getImportPreview(item)}
-
-
- {formatRelativeTime(item.lastActivityAt)}
-
-
-
- {item.cwd}
-
-
-
-
- {getProviderLabel(item.provider)}
-
-
- Tap to import
-
-
- ),
- [getProviderLabel, handleImportCandidatePress, isLoading, isTargetDaemonReady]
- );
-
- useEffect(() => {
- if (!isImportFlow || !isVisible || !ws) {
- return;
- }
- const unsubscribe = ws.on("list_persisted_agents_response", (message) => {
- if (message.type !== "list_persisted_agents_response") {
- return;
- }
- const mapped = message.payload.items.map((item) => ({
- provider: item.provider,
- sessionId: item.sessionId,
- cwd: item.cwd,
- title: item.title ?? `Session ${item.sessionId.slice(0, 8)}`,
- lastActivityAt: new Date(item.lastActivityAt),
- persistence: item.persistence,
- timeline: item.timeline ?? [],
- })) as ImportCandidate[];
-
- setImportCandidates(mapped);
- setIsImportLoading(false);
- });
-
- return () => {
- unsubscribe();
- };
- }, [isImportFlow, isVisible, ws]);
-
useEffect(() => {
if (!shouldListenForStatus || !ws) {
return;
@@ -1132,11 +806,7 @@ function AgentFlowModal({
return;
}
- if (
- (payload.status !== "agent_created" &&
- payload.status !== "agent_resumed") ||
- !payload.agentId
- ) {
+ if (payload.status !== "agent_created" || !payload.agentId) {
return;
}
@@ -1157,79 +827,7 @@ function AgentFlowModal({
};
}, [handleClose, shouldListenForStatus, ws]);
- useEffect(() => {
- if (!isVisible || !isImportFlow) {
- return;
- }
- const provider =
- importProviderFilter === "all" ? undefined : importProviderFilter;
- requestImportCandidates(provider);
- }, [importProviderFilter, isImportFlow, isVisible, requestImportCandidates]);
-
- const refreshImportList = useCallback(() => {
- const provider =
- importProviderFilter === "all" ? undefined : importProviderFilter;
- requestImportCandidates(provider);
- }, [requestImportCandidates, importProviderFilter]);
-
const shouldRender = isVisible || isMounted;
- const modalTitle = isImportFlow ? "Import Agent" : "Create New Agent";
-
- const gitBlockingError = useMemo(() => {
- if (isNonGitDirectory) {
- return null;
- }
- const trimmedBase = baseBranch.trim();
- const currentBranch = repoInfo?.currentBranch ?? "";
- const isCustomBase =
- trimmedBase.length > 0 &&
- (currentBranch.length === 0 || trimmedBase !== currentBranch);
- const requiresBase = createNewBranch || createWorktree || isCustomBase;
-
- if (requiresBase && !trimmedBase) {
- return "Select a base branch before launching the agent";
- }
-
- if (createNewBranch) {
- const slug = branchName.trim();
- const validation = validateWorktreeName(slug);
- if (!slug || !validation.valid) {
- return `Invalid branch name: ${
- validation.error ?? "Must use lowercase letters, numbers, hyphens, or forward slashes"
- }`;
- }
- }
-
- if (createWorktree) {
- const slug = (worktreeSlug || branchName).trim();
- const validation = validateWorktreeName(slug);
- if (!slug || !validation.valid) {
- return `Invalid worktree name: ${
- validation.error ?? "Must use lowercase letters, numbers, or hyphens"
- }`;
- }
- }
-
- if (!createWorktree && repoInfo?.isDirty) {
- const intendsCheckout =
- createNewBranch ||
- (trimmedBase.length > 0 && trimmedBase !== repoInfo.currentBranch);
- if (intendsCheckout) {
- return "Working directory has uncommitted changes. Clean up or create a worktree first.";
- }
- }
-
- return null;
- }, [
- baseBranch,
- branchName,
- createNewBranch,
- createWorktree,
- isNonGitDirectory,
- repoInfo,
- validateWorktreeName,
- worktreeSlug,
- ]);
const promptIsEmpty = !initialPrompt.trim();
const createDisabled =
@@ -1291,27 +889,9 @@ function AgentFlowModal({
paddingLeft={horizontalPaddingLeft}
paddingRight={horizontalPaddingRight}
onClose={handleClose}
- title={modalTitle}
- rightContent={
- isImportFlow ? (
- openDropdownSheet("host")}
- >
-
- {hostBadgeLabel}
-
-
- ) : undefined
- }
+ title="Create New Agent"
/>
- {isCreateFlow ? (
- <>
+ <>
-
- openDropdownSheet("assistant")}
- onClose={closeDropdown}
- onSelect={setProviderFromUser}
- />
- openDropdownSheet("permissions")}
- onClose={closeDropdown}
- onSelect={setModeFromUser}
- />
- {
- refreshProviderModels();
- openDropdownSheet("model");
- }}
- onClose={closeDropdown}
- onSelect={(modelId) => {
- setModelFromUser(modelId);
- setErrorMessage("");
- }}
- onClear={() => {
- setModelFromUser("");
- setErrorMessage("");
- }}
- onRefresh={refreshProviderModels}
- />
-
-
openDropdownSheet("workingDir")}
- onClose={closeDropdown}
disabled={isLoading}
suggestedPaths={agentWorkingDirSuggestions}
onSelectPath={handleUserWorkingDirChange}
/>
- {
- setCreateNewBranch(next);
- if (next) {
- if (!branchNameEdited) {
- const slug = slugifyWorktreeName(
- initialPrompt || baseBranch || ""
- );
- setBranchName(slug);
- }
- } else {
- setBranchName("");
- setBranchNameEdited(false);
- }
- }}
- branchName={branchName}
- onBranchNameChange={(value) => {
- setBranchName(slugifyWorktreeName(value));
- setBranchNameEdited(true);
- }}
- createWorktree={createWorktree}
- onToggleCreateWorktree={(next) => {
- setCreateWorktree(next);
- if (next) {
- if (!worktreeSlugEdited) {
- const slug = slugifyWorktreeName(
- initialPrompt || branchName || baseBranch || ""
- );
- setWorktreeSlug(slug);
- }
- } else {
- setWorktreeSlug("");
- setWorktreeSlugEdited(false);
- }
- }}
- worktreeSlug={worktreeSlug}
- onWorktreeSlugChange={(value) => {
- setWorktreeSlug(slugifyWorktreeName(value));
- setWorktreeSlugEdited(true);
- }}
- gitValidationError={gitBlockingError}
- isBaseDropdownOpen={openDropdown === "baseBranch"}
- onToggleBaseDropdown={() => openDropdownSheet("baseBranch")}
- onCloseDropdown={closeDropdown}
+
+
+ {!isNonGitDirectory ? (
+
+ ) : null}
>
- ) : (
-
- {daemonAvailabilityError ? (
-
- {daemonAvailabilityError}
-
- ) : null}
-
-
- {providerFilterOptions.map((option) => {
- const isActive = importProviderFilter === option.id;
- return (
- setImportProviderFilter(option.id)}
- style={[
- styles.providerFilterButton,
- isActive && styles.providerFilterButtonActive,
- ]}
- >
-
- {option.label}
-
-
- );
- })}
-
-
-
-
- Refresh
-
-
-
- {importError ? (
- {importError}
- ) : null}
- {isImportLoading ? (
-
-
-
- Loading agents to import...
-
-
- ) : filteredImportCandidates.length === 0 ? (
-
- No agents to import
-
- We will load the latest Claude and Codex sessions from your
- local history so you can import them.
-
-
- Try Again
-
-
- ) : (
-
- `${item.provider}:${item.sessionId}`
- }
- ItemSeparatorComponent={() => (
-
- )}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={styles.resumeListContent}
- />
- )}
-
- )}
-
- {daemonEntries.length === 0 ? (
- No hosts available yet.
- ) : (
-
- {daemonEntries.map(({ daemon, status }) => {
- const isSelected = daemon.id === selectedServerId;
- const label = daemon.label ?? daemon.wsUrl ?? daemon.id;
- return (
- {
- setSelectedServerIdFromUser(daemon.id);
- closeDropdown();
- }}
- >
- {label}
-
- {formatConnectionStatus(status)}
-
-
- );
- })}
-
- )}
-
@@ -1685,7 +1040,7 @@ function AgentFlowModal({
);
}
-function LazyAgentFlowModal(props: Omit) {
+function LazyCreateAgentModal(props: Omit) {
const { isVisible } = props;
const [shouldRender, setShouldRender] = useState(isVisible);
@@ -1706,8 +1061,8 @@ function LazyAgentFlowModal(props: Omit) {
return ;
}
-export function ImportAgentModal(props: ModalWrapperProps) {
- return ;
+export function CreateAgentModal(props: ModalWrapperProps) {
+ return ;
}
interface ModalHeaderProps {
@@ -1740,241 +1095,6 @@ function ModalHeader({
);
}
-interface GitOptionsSectionProps {
- baseBranch: string;
- onBaseBranchChange: (value: string) => void;
- branches: Array<{ name: string; isCurrent: boolean }>;
- status: "idle" | "loading" | "ready" | "error";
- repoError: string | null;
- helperText?: string | null;
- warning: string | null;
- createNewBranch: boolean;
- onToggleCreateNewBranch: (value: boolean) => void;
- branchName: string;
- onBranchNameChange: (value: string) => void;
- createWorktree: boolean;
- onToggleCreateWorktree: (value: boolean) => void;
- worktreeSlug: string;
- onWorktreeSlugChange: (value: string) => void;
- gitValidationError: string | null;
- isGitDisabled?: boolean;
- isBaseDropdownOpen: boolean;
- onToggleBaseDropdown: () => void;
- onCloseDropdown: () => void;
-}
-
-function GitOptionsSection({
- baseBranch,
- onBaseBranchChange,
- branches,
- status,
- repoError,
- helperText,
- warning,
- createNewBranch,
- onToggleCreateNewBranch,
- branchName,
- onBranchNameChange,
- createWorktree,
- onToggleCreateWorktree,
- worktreeSlug,
- onWorktreeSlugChange,
- gitValidationError,
- isGitDisabled,
- isBaseDropdownOpen,
- onToggleBaseDropdown,
- onCloseDropdown,
-}: GitOptionsSectionProps): ReactElement {
- const [branchSearch, setBranchSearch] = useState("");
- const branchFilter = branchSearch.trim().toLowerCase();
- const filteredBranches =
- branchFilter.length === 0
- ? branches
- : branches.filter((branch) =>
- branch.name.toLowerCase().includes(branchFilter)
- );
- const maxVisible = 30;
- const currentBranchLabel =
- branches.find((branch) => branch.isCurrent)?.name ?? "";
- const baseInputRef = useRef(null);
- const gitInputsDisabled = Boolean(isGitDisabled) || status === "loading";
-
- useEffect(() => {
- if (isBaseDropdownOpen) {
- setBranchSearch("");
- baseInputRef.current?.focus();
- }
- }, [isBaseDropdownOpen]);
-
- return (
-
- Git Setup
-
- Choose a base branch, then optionally create a feature branch or
- isolated worktree.
-
-
-
-
-
- {status === "loading" ? (
-
-
- Inspecting repository…
-
- ) : filteredBranches.length === 0 ? (
-
- {branchFilter.length === 0
- ? "No branches detected yet."
- : "No branches match your search."}
-
- ) : (
-
- {filteredBranches.slice(0, maxVisible).map((branch) => {
- const isActive = branch.name === baseBranch;
- return (
- {
- onBaseBranchChange(branch.name);
- onCloseDropdown();
- }}
- >
-
- {branch.name}
- {branch.isCurrent ? " (current)" : ""}
-
-
- );
- })}
-
- )}
- {filteredBranches.length > maxVisible ? (
-
- Showing first {maxVisible} matches. Keep typing to narrow it down.
-
- ) : null}
-
-
-
- {createNewBranch ? (
-
- ) : null}
-
-
- {createWorktree ? (
-
- ) : null}
-
- {gitValidationError ? (
- {gitValidationError}
- ) : null}
-
- );
-}
-
-interface ToggleRowProps {
- label: string;
- description?: string;
- value: boolean;
- onToggle: (value: boolean) => void;
- disabled?: boolean;
-}
-
-function ToggleRow({
- label,
- description,
- value,
- onToggle,
- disabled,
-}: ToggleRowProps): ReactElement {
- return (
- {
- if (!disabled) {
- onToggle(!value);
- }
- }}
- style={[styles.toggleRow, disabled && styles.toggleRowDisabled]}
- >
-
- {value ? : null}
-
-
- {label}
- {description ? (
- {description}
- ) : null}
-
-
- );
-}
-
const styles = StyleSheet.create(((theme: any) => ({
overlay: {
flex: 1,
@@ -2031,29 +1151,6 @@ const styles = StyleSheet.create(((theme: any) => ({
alignItems: "center",
justifyContent: "center",
},
- hostBadge: {
- flexDirection: "row",
- alignItems: "center",
- gap: theme.spacing[2],
- paddingHorizontal: theme.spacing[3],
- paddingVertical: theme.spacing[2],
- backgroundColor: theme.colors.muted,
- borderRadius: theme.borderRadius.full,
- },
- hostBadgeLabel: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.xs,
- fontWeight: theme.fontWeight.semibold,
- },
- hostStatusDot: {
- width: 6,
- height: 6,
- borderRadius: theme.borderRadius.full,
- backgroundColor: theme.colors.mutedForeground,
- },
- hostStatusDotOnline: {
- backgroundColor: theme.colors.palette.green[500],
- },
scroll: {
flex: 1,
},
@@ -2328,161 +1425,4 @@ const styles = StyleSheet.create(((theme: any) => ({
alignItems: "center",
gap: theme.spacing[2],
},
- resumeContainer: {
- flex: 1,
- gap: theme.spacing[4],
- },
- resumeFilters: {
- gap: theme.spacing[3],
- },
- providerFilterRow: {
- flexDirection: "row",
- flexWrap: "wrap",
- gap: theme.spacing[2],
- },
- providerFilterButton: {
- paddingHorizontal: theme.spacing[4],
- paddingVertical: theme.spacing[2],
- borderRadius: theme.borderRadius.full,
- borderWidth: theme.borderWidth[1],
- borderColor: theme.colors.border,
- backgroundColor: theme.colors.background,
- },
- providerFilterButtonActive: {
- borderColor: theme.colors.palette.blue[500],
- backgroundColor: theme.colors.muted,
- },
- providerFilterText: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.sm,
- fontWeight: theme.fontWeight.normal,
- },
- providerFilterTextActive: {
- color: theme.colors.foreground,
- fontWeight: theme.fontWeight.semibold,
- },
- resumeSearchRow: {
- flexDirection: "row",
- gap: theme.spacing[3],
- alignItems: "center",
- },
- resumeSearchInput: {
- flex: 1,
- borderRadius: theme.borderRadius.lg,
- borderWidth: theme.borderWidth[1],
- borderColor: theme.colors.border,
- backgroundColor: theme.colors.background,
- paddingHorizontal: theme.spacing[4],
- paddingVertical: theme.spacing[3],
- color: theme.colors.foreground,
- },
- refreshButton: {
- borderRadius: theme.borderRadius.lg,
- borderWidth: theme.borderWidth[1],
- borderColor: theme.colors.border,
- paddingHorizontal: theme.spacing[4],
- paddingVertical: theme.spacing[3],
- },
- refreshButtonText: {
- color: theme.colors.foreground,
- fontSize: theme.fontSize.sm,
- fontWeight: theme.fontWeight.semibold,
- },
- importErrorText: {
- color: theme.colors.palette.red[500],
- fontSize: theme.fontSize.sm,
- },
- resumeLoading: {
- flex: 1,
- alignItems: "center",
- justifyContent: "center",
- gap: theme.spacing[2],
- },
- resumeLoadingText: {
- color: theme.colors.mutedForeground,
- },
- resumeEmptyState: {
- flex: 1,
- alignItems: "center",
- justifyContent: "center",
- gap: theme.spacing[2],
- paddingHorizontal: theme.spacing[6],
- textAlign: "center",
- },
- resumeEmptyTitle: {
- color: theme.colors.foreground,
- fontSize: theme.fontSize.lg,
- fontWeight: theme.fontWeight.semibold,
- textAlign: "center",
- },
- resumeEmptySubtitle: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.sm,
- textAlign: "center",
- },
- refreshButtonAlt: {
- marginTop: theme.spacing[2],
- borderRadius: theme.borderRadius.lg,
- backgroundColor: theme.colors.palette.blue[500],
- paddingHorizontal: theme.spacing[6],
- paddingVertical: theme.spacing[3],
- },
- refreshButtonAltText: {
- color: theme.colors.palette.white,
- fontWeight: theme.fontWeight.semibold,
- },
- resumeListContent: {
- paddingBottom: theme.spacing[8],
- gap: theme.spacing[2],
- },
- resumeItem: {
- borderWidth: theme.borderWidth[1],
- borderColor: theme.colors.border,
- borderRadius: theme.borderRadius.lg,
- padding: theme.spacing[4],
- backgroundColor: theme.colors.background,
- gap: theme.spacing[2],
- },
- resumeItemHeader: {
- flexDirection: "row",
- justifyContent: "space-between",
- alignItems: "center",
- gap: theme.spacing[2],
- },
- resumeItemTitle: {
- color: theme.colors.foreground,
- fontWeight: theme.fontWeight.semibold,
- flex: 1,
- },
- resumeItemTimestamp: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.sm,
- },
- resumeItemPath: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.sm,
- },
- resumeItemMetaRow: {
- flexDirection: "row",
- alignItems: "center",
- justifyContent: "space-between",
- },
- resumeProviderBadge: {
- paddingHorizontal: theme.spacing[3],
- paddingVertical: theme.spacing[1],
- borderRadius: theme.borderRadius.full,
- backgroundColor: theme.colors.muted,
- },
- resumeProviderBadgeText: {
- color: theme.colors.foreground,
- fontSize: theme.fontSize.xs,
- fontWeight: theme.fontWeight.semibold,
- },
- resumeItemHint: {
- color: theme.colors.mutedForeground,
- fontSize: theme.fontSize.xs,
- },
- resumeItemSeparator: {
- height: theme.spacing[2],
- },
})) as any) as Record;
diff --git a/packages/app/src/components/home-footer.tsx b/packages/app/src/components/home-footer.tsx
index bddc6b5a7..a32a680b3 100644
--- a/packages/app/src/components/home-footer.tsx
+++ b/packages/app/src/components/home-footer.tsx
@@ -3,12 +3,11 @@ import { View, Pressable, Text, Platform, Modal, Alert } from "react-native";
import { useRouter } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
-import { AudioLines, Users, Plus, Download } from "lucide-react-native";
+import { AudioLines, Users, Plus } from "lucide-react-native";
import { useRealtime } from "@/contexts/realtime-context";
import { useDaemonConnections } from "@/contexts/daemon-connections-context";
import { FOOTER_HEIGHT } from "@/constants/layout";
import { RealtimeControls } from "./realtime-controls";
-import { ImportAgentModal } from "./create-agent-modal";
import Animated, {
FadeIn,
FadeOut,
@@ -22,7 +21,6 @@ export function HomeFooter() {
const router = useRouter();
const { isRealtimeMode, startRealtime } = useRealtime();
const { connectionStates } = useDaemonConnections();
- const [showImportModal, setShowImportModal] = useState(false);
const [showRealtimeHostPicker, setShowRealtimeHostPicker] = useState(false);
// Guard Reanimated entry/exit transitions on Android to avoid ViewGroup.dispatchDraw crashes
// tracked in react-native-reanimated#8422.
@@ -141,25 +139,6 @@ export function HomeFooter() {
Agents
- {
- setShowImportModal(true);
- }}
- style={({ pressed }) => [
- styles.footerButton,
- pressed && styles.buttonPressed,
- ]}
- >
-
-
-
- Import
-
-
{
console.log("[HomeFooter] New Agent button pressed");
@@ -202,10 +181,6 @@ export function HomeFooter() {
- setShowImportModal(false)}
- />
void;
- resumeAgent: (options: { handle: any; overrides?: any; requestId?: string }) => void;
setAgentMode: (agentId: string, modeId: string) => void;
respondToPermission: (agentId: string, requestId: string, response: any) => void;
}
@@ -1573,19 +1572,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
ws.send(msg);
}, [encodeImages, ws]);
- const resumeAgent = useCallback(({ handle, overrides, requestId }: { handle: any; overrides?: any; requestId?: string }) => {
- const msg: WSInboundMessage = {
- type: "session",
- message: {
- type: "resume_agent_request",
- handle,
- ...(overrides ? { overrides } : {}),
- ...(requestId ? { requestId } : {}),
- },
- };
- ws.send(msg);
- }, [ws]);
-
const setAgentMode = useCallback((agentId: string, modeId: string) => {
const msg: WSInboundMessage = {
type: "session",
@@ -1816,7 +1802,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
sendAgentMessage,
sendAgentAudio,
createAgent,
- resumeAgent,
setAgentMode,
respondToPermission,
}),
@@ -1840,7 +1825,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
sendAgentMessage,
sendAgentAudio,
createAgent,
- resumeAgent,
setAgentMode,
respondToPermission,
]
@@ -1866,7 +1850,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
sendAgentAudio,
deleteAgent,
createAgent,
- resumeAgent,
setAgentMode,
respondToPermission,
}), [
@@ -1886,7 +1869,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
sendAgentAudio,
deleteAgent,
createAgent,
- resumeAgent,
setAgentMode,
respondToPermission,
]);
diff --git a/packages/app/src/lib/send-rpc-request.ts b/packages/app/src/lib/send-rpc-request.ts
index 8deeb5a49..a4d6d471f 100644
--- a/packages/app/src/lib/send-rpc-request.ts
+++ b/packages/app/src/lib/send-rpc-request.ts
@@ -105,7 +105,6 @@ const RESPONSE_TYPE_MAP: Record = {
git_repo_info_request: "git_repo_info_response",
list_provider_models_request: "list_provider_models_response",
list_conversations_request: "list_conversations_response",
- list_persisted_agents_request: "list_persisted_agents_response",
create_agent_request: "agent_state",
refresh_agent_request: "agent_state",
initialize_agent_request: "initialize_agent_request",
diff --git a/packages/app/src/stores/session-store.ts b/packages/app/src/stores/session-store.ts
index 2fb55ee41..93fb08822 100644
--- a/packages/app/src/stores/session-store.ts
+++ b/packages/app/src/stores/session-store.ts
@@ -204,7 +204,6 @@ export interface SessionState {
worktreeName?: string;
requestId?: string;
}) => Promise;
- resumeAgent: (options: { handle: any; overrides?: any; requestId?: string }) => void;
setAgentMode: (agentId: string, modeId: string) => void;
respondToPermission: (agentId: string, requestId: string, response: any) => void;
} | null;
diff --git a/packages/server/src/server/messages.ts b/packages/server/src/server/messages.ts
index 0ef52f699..4d66780a2 100644
--- a/packages/server/src/server/messages.ts
+++ b/packages/server/src/server/messages.ts
@@ -407,12 +407,6 @@ export const RestartServerRequestMessageSchema = z.object({
reason: z.string().optional(),
});
-export const ListPersistedAgentsRequestMessageSchema = z.object({
- type: z.literal("list_persisted_agents_request"),
- provider: AgentProviderSchema.optional(),
- limit: z.number().int().positive().optional(),
-});
-
export const InitializeAgentRequestMessageSchema = z.object({
type: z.literal("initialize_agent_request"),
agentId: z.string(),
@@ -557,7 +551,6 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
HighlightedDiffRequestSchema,
FileExplorerRequestSchema,
FileDownloadTokenRequestSchema,
- ListPersistedAgentsRequestMessageSchema,
GitRepoInfoRequestMessageSchema,
ClearAgentAttentionMessageSchema,
]);
@@ -750,25 +743,6 @@ export const AgentDeletedMessageSchema = z.object({
}),
});
-const PersistedAgentDescriptorPayloadSchema = z.object({
- provider: AgentProviderSchema,
- sessionId: z.string(),
- cwd: z.string(),
- title: z.string(),
- lastActivityAt: z.string(),
- persistence: AgentPersistenceHandleSchema,
- timeline: z.array(AgentTimelineItemPayloadSchema),
-});
-
-export type PersistedAgentDescriptorPayload = z.infer;
-
-export const ListPersistedAgentsResponseSchema = z.object({
- type: z.literal("list_persisted_agents_response"),
- payload: z.object({
- items: z.array(PersistedAgentDescriptorPayloadSchema),
- }),
-});
-
export const GitDiffResponseSchema = z.object({
type: z.literal("git_diff_response"),
payload: z.object({
@@ -863,7 +837,6 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
AgentPermissionRequestMessageSchema,
AgentPermissionResolvedMessageSchema,
AgentDeletedMessageSchema,
- ListPersistedAgentsResponseSchema,
GitDiffResponseSchema,
HighlightedDiffResponseSchema,
FileExplorerResponseSchema,
@@ -896,7 +869,6 @@ export type DeleteConversationResponseMessage = z.infer;
export type AgentPermissionResolvedMessage = z.infer;
export type AgentDeletedMessage = z.infer;
-export type ListPersistedAgentsResponseMessage = z.infer;
export type ListProviderModelsResponseMessage = z.infer<
typeof ListProviderModelsResponseMessageSchema
>;
@@ -916,7 +888,6 @@ export type ListProviderModelsRequestMessage = z.infer<
>;
export type ResumeAgentRequestMessage = z.infer;
export type DeleteAgentRequestMessage = z.infer;
-export type ListPersistedAgentsRequestMessage = z.infer;
export type InitializeAgentRequestMessage = z.infer;
export type SetAgentModeMessage = z.infer;
export type AgentPermissionResponseMessage = z.infer;
diff --git a/packages/server/src/server/session.ts b/packages/server/src/server/session.ts
index c456d51b2..5fcccf571 100644
--- a/packages/server/src/server/session.ts
+++ b/packages/server/src/server/session.ts
@@ -856,10 +856,6 @@ export class Session {
await this.handleFileDownloadTokenRequest(msg);
break;
- case "list_persisted_agents_request":
- await this.handleListPersistedAgentsRequest(msg);
- break;
-
case "git_repo_info_request":
await this.handleGitRepoInfoRequest(msg);
break;
@@ -1550,9 +1546,18 @@ export class Session {
}
if (normalized.createWorktree) {
- const targetBranch = normalized.createNewBranch
- ? normalized.newBranchName
- : normalized.baseBranch;
+ let targetBranch: string;
+
+ if (normalized.createNewBranch) {
+ targetBranch = normalized.newBranchName!;
+ } else {
+ // Resolve current branch name from HEAD
+ const { stdout } = await execAsync("git rev-parse --abbrev-ref HEAD", {
+ cwd,
+ env: READ_ONLY_GIT_ENV,
+ });
+ targetBranch = stdout.trim();
+ }
if (!targetBranch) {
throw new Error(
@@ -1730,12 +1735,6 @@ export class Session {
}
}
- if (createWorktree && !createNewBranch && !baseBranch) {
- throw new Error(
- "Base branch is required when creating a worktree without a new branch"
- );
- }
-
return {
baseBranch,
createNewBranch,
@@ -1836,48 +1835,6 @@ export class Session {
}
}
- private async handleListPersistedAgentsRequest(
- msg: Extract
- ): Promise {
- const { provider, limit } = msg;
- try {
- const entries = await this.agentManager.listPersistedAgents({
- provider,
- limit,
- });
- this.emit({
- type: "list_persisted_agents_response",
- payload: {
- items: entries.map((entry) => ({
- provider: entry.provider,
- sessionId: entry.sessionId,
- cwd: entry.cwd,
- title: entry.title ?? `Session ${entry.sessionId.slice(0, 8)}`,
- lastActivityAt: entry.lastActivityAt.toISOString(),
- persistence: entry.persistence,
- timeline: entry.timeline ?? [],
- })),
- },
- });
- } catch (error) {
- console.error(
- `[Session ${this.clientId}] Failed to list persisted agents:`,
- error
- );
- this.emit({
- type: "activity_log",
- payload: {
- id: uuidv4(),
- timestamp: new Date(),
- type: "error",
- content: `Failed to list saved agents: ${
- (error as Error)?.message ?? error
- }`,
- },
- });
- }
- }
-
/**
* Handle set agent mode request
*/
diff --git a/packages/server/src/server/test-utils/daemon-client.ts b/packages/server/src/server/test-utils/daemon-client.ts
index c706d3183..6cc20a095 100644
--- a/packages/server/src/server/test-utils/daemon-client.ts
+++ b/packages/server/src/server/test-utils/daemon-client.ts
@@ -5,7 +5,6 @@ import type {
SessionOutboundMessage,
AgentSnapshotPayload,
AgentStreamEventPayload,
- PersistedAgentDescriptorPayload,
} from "../messages.js";
import type {
AgentModelDefinition,
@@ -296,16 +295,6 @@ export class DaemonClient {
);
}
- async listPersistedAgents(): Promise {
- this.send({ type: "list_persisted_agents_request" });
- return this.waitFor((msg) => {
- if (msg.type === "list_persisted_agents_response") {
- return msg.payload.items;
- }
- return null;
- });
- }
-
async resumeAgent(
handle: AgentPersistenceHandle,
overrides?: Partial