diff --git a/mobile/app/h/[hostId]/session/[worktreeId].tsx b/mobile/app/h/[hostId]/session/[worktreeId].tsx index 6e1673d2bb2..988e652a059 100644 --- a/mobile/app/h/[hostId]/session/[worktreeId].tsx +++ b/mobile/app/h/[hostId]/session/[worktreeId].tsx @@ -228,7 +228,7 @@ import { } from '../../../../src/dictation/mobile-dictation-setup' import { TerminalPaneView } from '../../../../src/session/TerminalPaneView' import { MobileNativeChatOverlay } from '../../../../src/session/MobileNativeChatOverlay' -import { MobileStructuredAgentSessionView } from '../../../../src/session/MobileStructuredAgentSessionView' +import { MobileStructuredSessionPane } from '../../../../src/session/MobileStructuredSessionPane' import { MobileStructuredSessionCreateError } from '../../../../src/session/MobileStructuredSessionCreateError' import { useMobileStructuredSessionEntry } from '../../../../src/session/use-mobile-structured-session-entry' import { showMobileStructuredChatChoice } from '../../../../src/session/mobile-structured-session-create' @@ -4684,36 +4684,10 @@ export default function SessionScreen() { )} ) : activeStructuredTab ? ( - { - const accepted = await structuredSessionEntry.writes.send(text, [ - ...restored, - ...structuredSessionEntry.attachments.attachments - ]) - if (accepted) { - structuredSessionEntry.attachments.clear() - } - return accepted - }} - onTakeQueuedForEdit={structuredSessionEntry.writes.takeQueuedForEdit} - onRetry={structuredSessionEntry.writes.retry} - onRespondToPrompt={structuredSessionEntry.writes.respondToPrompt} - sessionOptions={structuredSessionEntry.sessionOptions} - attachments={structuredSessionEntry.attachments.attachments} - isAttaching={structuredSessionEntry.attachments.attaching} - onAttachImage={() => void structuredSessionEntry.attachments.attach('library')} - onRemoveAttachment={structuredSessionEntry.attachments.remove} - onCancel={structuredSessionEntry.writes.cancel} /> ) : activePendingTerminalTab ? ( diff --git a/mobile/src/session/MobileStructuredSessionPane.tsx b/mobile/src/session/MobileStructuredSessionPane.tsx new file mode 100644 index 00000000000..837b7ee5301 --- /dev/null +++ b/mobile/src/session/MobileStructuredSessionPane.tsx @@ -0,0 +1,46 @@ +// Wires one structured agent session entry into the chat view. Kept out of the +// session route so the route threads one object instead of eighteen props. + +import { MobileStructuredAgentSessionView } from './MobileStructuredAgentSessionView' +import type { useMobileStructuredSessionEntry } from './use-mobile-structured-session-entry' + +type StructuredSessionEntry = ReturnType + +export function MobileStructuredSessionPane({ + entry, + onOpenFile +}: { + entry: StructuredSessionEntry + onOpenFile: (path: string, line?: number) => void +}) { + const { session, writes, attachments, sessionOptions } = entry + return ( + { + const accepted = await writes.send(text, [...restored, ...attachments.attachments]) + if (accepted) { + attachments.clear() + } + return accepted + }} + onTakeQueuedForEdit={writes.takeQueuedForEdit} + onRetry={writes.retry} + onRespondToPrompt={writes.respondToPrompt} + sessionOptions={sessionOptions} + attachments={attachments.attachments} + isAttaching={attachments.attaching} + onAttachImage={() => void attachments.attach('library')} + onRemoveAttachment={attachments.remove} + onCancel={writes.cancel} + /> + ) +} diff --git a/src/renderer/src/app-shell/use-app-startup-actions.ts b/src/renderer/src/app-shell/use-app-startup-actions.ts new file mode 100644 index 00000000000..df7cec71ab1 --- /dev/null +++ b/src/renderer/src/app-shell/use-app-startup-actions.ts @@ -0,0 +1,39 @@ +// The renderer boot chain's store subscription, kept apart from the chain itself +// so one useShallow equality check covers every startup action. + +import { useShallow } from 'zustand/react/shallow' +import { useAppStore } from '../store' + +export function useStartupActions() { + // Why: consolidate action refs into one useShallow subscription so React runs one equality check per store mutation instead of one per action. + return useAppStore( + useShallow((s) => ({ + fetchReposForAllHosts: s.fetchReposForAllHosts, + awaitLocalRepoCatalogSettlement: s.awaitLocalRepoCatalogSettlement, + fetchProjectGroupsForAllHosts: s.fetchProjectGroupsForAllHosts, + fetchFolderWorkspacesForAllHosts: s.fetchFolderWorkspacesForAllHosts, + fetchAllWorktrees: s.fetchAllWorktrees, + fetchWorktrees: s.fetchWorktrees, + fetchWorktreeLineage: s.fetchWorktreeLineage, + fetchOrcaProfiles: s.fetchOrcaProfiles, + fetchSettings: s.fetchSettings, + awaitOwnerWorktreeVisibilityDefaultsHydration: + s.awaitOwnerWorktreeVisibilityDefaultsHydration, + fetchKeybindings: s.fetchKeybindings, + initGitHubCache: s.initGitHubCache, + hydrateWorkspaceSession: s.hydrateWorkspaceSession, + hydrateTabsSession: s.hydrateTabsSession, + hydrateEditorSession: s.hydrateEditorSession, + hydrateBrowserSession: s.hydrateBrowserSession, + fetchBrowserSessionProfiles: s.fetchBrowserSessionProfiles, + reconnectPersistedTerminals: s.reconnectPersistedTerminals, + setTerminalStartupRestorationReady: s.setTerminalStartupRestorationReady, + setDeferredSshReconnectTargets: s.setDeferredSshReconnectTargets, + setSshConnectionState: s.setSshConnectionState, + hydratePersistedUI: s.hydratePersistedUI, + setHydrationSucceeded: s.setHydrationSucceeded, + pruneLastVisitedTimestamps: s.pruneLastVisitedTimestamps, + seedActiveWorktreeLastVisitedIfMissing: s.seedActiveWorktreeLastVisitedIfMissing + })) + ) +} diff --git a/src/renderer/src/app-shell/use-app-startup-hydration.ts b/src/renderer/src/app-shell/use-app-startup-hydration.ts index 637eece13ff..091039fb793 100644 --- a/src/renderer/src/app-shell/use-app-startup-hydration.ts +++ b/src/renderer/src/app-shell/use-app-startup-hydration.ts @@ -1,8 +1,8 @@ import { useEffect, useRef } from 'react' -import { useShallow } from 'zustand/react/shallow' import { syncZoomCSSVar } from '@/lib/ui-zoom' import { installCodexDetachedPaneRestartExecutor } from '@/components/terminal-pane/codex-detached-pane-restart-scheduler' import { useAppStore } from '../store' +import { useStartupActions } from './use-app-startup-actions' import { WORKTREE_REFRESH_CONCURRENCY } from '../store/slices/worktrees' import { sweepRestoredCodexPanesForStaleAccounts } from '../lib/codex-stale-pane-sweep' import { fetchWorkspaceSessionWithRuntimeHostOwners } from '../lib/workspace-session-host-persistence' @@ -46,40 +46,6 @@ async function listRuntimeSessionHostIdsForStartup(): Promise } } -function useStartupActions() { - // Why: consolidate action refs into one useShallow subscription so React runs one equality check per store mutation instead of one per action. - return useAppStore( - useShallow((s) => ({ - fetchReposForAllHosts: s.fetchReposForAllHosts, - awaitLocalRepoCatalogSettlement: s.awaitLocalRepoCatalogSettlement, - fetchProjectGroupsForAllHosts: s.fetchProjectGroupsForAllHosts, - fetchFolderWorkspacesForAllHosts: s.fetchFolderWorkspacesForAllHosts, - fetchAllWorktrees: s.fetchAllWorktrees, - fetchWorktrees: s.fetchWorktrees, - fetchWorktreeLineage: s.fetchWorktreeLineage, - fetchOrcaProfiles: s.fetchOrcaProfiles, - fetchSettings: s.fetchSettings, - awaitOwnerWorktreeVisibilityDefaultsHydration: - s.awaitOwnerWorktreeVisibilityDefaultsHydration, - fetchKeybindings: s.fetchKeybindings, - initGitHubCache: s.initGitHubCache, - hydrateWorkspaceSession: s.hydrateWorkspaceSession, - hydrateTabsSession: s.hydrateTabsSession, - hydrateEditorSession: s.hydrateEditorSession, - hydrateBrowserSession: s.hydrateBrowserSession, - fetchBrowserSessionProfiles: s.fetchBrowserSessionProfiles, - reconnectPersistedTerminals: s.reconnectPersistedTerminals, - setTerminalStartupRestorationReady: s.setTerminalStartupRestorationReady, - setDeferredSshReconnectTargets: s.setDeferredSshReconnectTargets, - setSshConnectionState: s.setSshConnectionState, - hydratePersistedUI: s.hydratePersistedUI, - setHydrationSucceeded: s.setHydrationSucceeded, - pruneLastVisitedTimestamps: s.pruneLastVisitedTimestamps, - seedActiveWorktreeLastVisitedIfMissing: s.seedActiveWorktreeLastVisitedIfMissing - })) - ) -} - /** * Runs the renderer's one-shot boot chain: settings, persisted UI, the local repo catalog, * the workspace session, SSH reconnect, and terminal restoration — then unlocks the session