/** * Thin launchers for one-off dialog JSX sites in main.tsx. * Each launcher dynamically imports its component and wires the `done` callback * identically to the original inline call site. Zero behavior change. * * Part of the main.tsx React/JSX extraction effort. See sibling PRs * perf/extract-interactive-helpers and perf/launch-repl. */ import React from 'react'; import type { AssistantSession } from './assistant/sessionDiscovery.js'; import type { StatsStore } from './context/stats.js'; import type { Root } from './ink.js'; import { renderAndRun, showSetupDialog } from './interactiveHelpers.js'; import { KeybindingSetup } from './keybindings/KeybindingProviderSetup.js'; import type { AppState } from './state/AppStateStore.js'; import type { AgentMemoryScope } from './tools/AgentTool/agentMemory.js'; import type { TeleportRemoteResponse } from './utils/conversationRecovery.js'; import type { FpsMetrics } from './utils/fpsTracker.js'; import type { ValidationError } from './utils/settings/validation.js'; // Type-only access to ResumeConversation's Props via the module type. // No runtime cost - erased at compile time. type ResumeConversationProps = React.ComponentProps; /** * Site ~3173: SnapshotUpdateDialog (agent memory snapshot update prompt). * Original callback wiring: onComplete={done}, onCancel={() => done('keep')}. */ export async function launchSnapshotUpdateDialog(root: Root, props: { agentType: string; scope: AgentMemoryScope; snapshotTimestamp: string; }): Promise<'merge' | 'keep' | 'replace'> { const { SnapshotUpdateDialog } = await import('./components/agents/SnapshotUpdateDialog.js'); return showSetupDialog<'merge' | 'keep' | 'replace'>(root, done => done('keep')} />); } /** * Site ~3250: InvalidSettingsDialog (settings validation errors). * Original callback wiring: onContinue={done}, onExit passed through from caller. */ export async function launchInvalidSettingsDialog(root: Root, props: { settingsErrors: ValidationError[]; onExit: () => void; }): Promise { const { InvalidSettingsDialog } = await import('./components/InvalidSettingsDialog.js'); return showSetupDialog(root, done => ); } /** * Site ~4229: AssistantSessionChooser (pick a bridge session to attach to). * Original callback wiring: onSelect={id => done(id)}, onCancel={() => done(null)}. */ export async function launchAssistantSessionChooser(root: Root, props: { sessions: AssistantSession[]; }): Promise { const { AssistantSessionChooser } = await import('./assistant/AssistantSessionChooser.js'); return showSetupDialog(root, done => done(id)} onCancel={() => done(null)} />); } /** * `claude assistant` found zero sessions — show the same install wizard * as `/assistant` when daemon.json is empty. Resolves to the installed dir on * success, null on cancel. Rejects on install failure so the caller can * distinguish errors from user cancellation. */ export async function launchAssistantInstallWizard(root: Root): Promise { const { NewInstallWizard, computeDefaultInstallDir } = await import('./commands/assistant/assistant.js'); const defaultDir = await computeDefaultInstallDir(); let rejectWithError: (reason: Error) => void; const errorPromise = new Promise((_, reject) => { rejectWithError = reject; }); const resultPromise = showSetupDialog(root, done => done(dir)} onCancel={() => done(null)} onError={message => rejectWithError(new Error(`Installation failed: ${message}`))} />); return Promise.race([resultPromise, errorPromise]); } /** * Site ~4549: TeleportResumeWrapper (interactive teleport session picker). * Original callback wiring: onComplete={done}, onCancel={() => done(null)}, source="cliArg". */ export async function launchTeleportResumeWrapper(root: Root): Promise { const { TeleportResumeWrapper } = await import('./components/TeleportResumeWrapper.js'); return showSetupDialog(root, done => done(null)} source="cliArg" />); } /** * Site ~4597: TeleportRepoMismatchDialog (pick a local checkout of the target repo). * Original callback wiring: onSelectPath={done}, onCancel={() => done(null)}. */ export async function launchTeleportRepoMismatchDialog(root: Root, props: { targetRepo: string; initialPaths: string[]; }): Promise { const { TeleportRepoMismatchDialog } = await import('./components/TeleportRepoMismatchDialog.js'); return showSetupDialog(root, done => done(null)} />); } /** * Site ~4903: ResumeConversation mount (interactive session picker). * Uses renderAndRun, NOT showSetupDialog. Wraps in . * Preserves original Promise.all parallelism between getWorktreePaths and imports. */ export async function launchResumeChooser(root: Root, appProps: { getFpsMetrics: () => FpsMetrics | undefined; stats: StatsStore; initialState: AppState; }, worktreePathsPromise: Promise, resumeProps: Omit): Promise { const [worktreePaths, { ResumeConversation }, { App }] = await Promise.all([worktreePathsPromise, import('./screens/ResumeConversation.js'), import('./components/App.js')]); await renderAndRun(root, ); }