diff --git a/src/tui/component/dialog-new.tsx b/src/tui/component/dialog-new.tsx index a13f436..2013f27 100644 --- a/src/tui/component/dialog-new.tsx +++ b/src/tui/component/dialog-new.tsx @@ -10,6 +10,7 @@ import { useSync } from "@tui/context/sync" import { useRoute } from "@tui/context/route" import { useConfig } from "@tui/context/config" import { useDialog, scrollDialogBy, scrollDialogTo } from "@tui/ui/dialog" +import { DialogSelect } from "@tui/ui/dialog-select" import { useToast } from "@tui/ui/toast" import { InputAutocomplete } from "@tui/ui/input-autocomplete" import { DialogHeader } from "@tui/ui/dialog-header" @@ -52,6 +53,20 @@ async function commandExists(cmd: string, cwd?: string): Promise { const projectPathHistory = new HistoryManager("dialog-new:project-paths", 15) const branchNameHistory = new HistoryManager("dialog-new:branch-names", 15) +// Persists form state across dialog.push/pop cycles (confirmation dialog) +interface SavedFormState { + title: string + selectedTool: Tool + toolIndex: number + claudeSessionMode: ClaudeSessionMode + skipPermissions: boolean + customCommand: string + projectPath: string + useWorktree: boolean + worktreeBranch: string +} +let _savedFormState: SavedFormState | null = null + const TOOLS: { value: Tool; label: string; description: string }[] = [ { value: "claude", label: "Claude Code", description: "Anthropic's Claude CLI" }, { value: "opencode", label: "OpenCode", description: "OpenCode CLI" }, @@ -72,13 +87,17 @@ export function DialogNew() { const renderer = useRenderer() const { config } = useConfig() - const defaultTool = config().defaultTool || "claude" + // Restore state saved before confirmation push, then clear it + const restore = _savedFormState + _savedFormState = null + + const defaultTool = restore?.selectedTool ?? (config().defaultTool || "claude") const defaultToolIndex = TOOLS.findIndex(t => t.value === defaultTool) - const [title, setTitle] = createSignal("") + const [title, setTitle] = createSignal(restore?.title ?? "") const [selectedTool, setSelectedTool] = createSignal(defaultTool) - const [customCommand, setCustomCommand] = createSignal("") - const [projectPath, setProjectPath] = createSignal(process.cwd()) + const [customCommand, setCustomCommand] = createSignal(restore?.customCommand ?? "") + const [projectPath, setProjectPath] = createSignal(restore?.projectPath ?? process.cwd()) const [creating, setCreating] = createSignal(false) const [statusMessage, setStatusMessage] = createSignal("") const [spinnerFrame, setSpinnerFrame] = createSignal(0) @@ -95,11 +114,11 @@ export function DialogNew() { } }) - const [claudeSessionMode, setClaudeSessionMode] = createSignal("new") - const [skipPermissions, setSkipPermissions] = createSignal(false) + const [claudeSessionMode, setClaudeSessionMode] = createSignal(restore?.claudeSessionMode ?? "new") + const [skipPermissions, setSkipPermissions] = createSignal(restore?.skipPermissions ?? false) - const [useWorktree, setUseWorktree] = createSignal(false) - const [worktreeBranch, setWorktreeBranch] = createSignal("") + const [useWorktree, setUseWorktree] = createSignal(restore?.useWorktree ?? false) + const [worktreeBranch, setWorktreeBranch] = createSignal(restore?.worktreeBranch ?? "") const [isInGitRepo, setIsInGitRepo] = createSignal(false) const [useBaseDevelop, setUseBaseDevelop] = createSignal(false) const [developExists, setDevelopExists] = createSignal(false) @@ -107,7 +126,7 @@ export function DialogNew() { const storage = getStorage() const [focusedField, setFocusedField] = createSignal("title") - const [toolIndex, setToolIndex] = createSignal(defaultToolIndex >= 0 ? defaultToolIndex : 0) + const [toolIndex, setToolIndex] = createSignal(restore?.toolIndex ?? (defaultToolIndex >= 0 ? defaultToolIndex : 0)) let titleInputRef: InputRenderable | undefined let customCommandInputRef: InputRenderable | undefined @@ -192,7 +211,7 @@ export function DialogNew() { return fields } - async function handleCreate() { + async function doCreate() { if (creating()) return setCreating(true) setStatusMessage("Preparing...") @@ -295,6 +314,53 @@ export function DialogNew() { } } + function handleCreate() { + // Save form state so it survives dialog.push/pop cycle + _savedFormState = { + title: title(), + selectedTool: selectedTool(), + toolIndex: toolIndex(), + claudeSessionMode: claudeSessionMode(), + skipPermissions: skipPermissions(), + customCommand: customCommand(), + projectPath: projectPath(), + useWorktree: useWorktree(), + worktreeBranch: worktreeBranch(), + } + + // Build summary lines for the confirmation dialog + const lines: string[] = [] + lines.push(`Tool: ${selectedTool()}`) + const t = title().trim() + lines.push(`Title: ${t || "(auto-generated)"}`) + lines.push(`Path: ${projectPath() || process.cwd()}`) + if (useWorktree()) { + const branch = worktreeBranch().trim() + lines.push(`Branch: ${branch || "(auto-generated)"}`) + } + + // Capture doCreate in closure before DialogNew is unmounted by dialog.push + const capturedDoCreate = doCreate + dialog.push(() => ( + { + if (opt.value === "confirm") { + _savedFormState = null + dialog.clear() + capturedDoCreate() + } else { + dialog.pop() + } + }} + /> + )) + } + useKeyboard((evt) => { if (evt.name === "escape") { evt.preventDefault()