diff --git a/apps/native/src-tauri/migrations/03-evolutions-origin-branch/up.sql b/apps/native/src-tauri/migrations/03-evolutions-origin-branch/up.sql deleted file mode 100644 index ef5999d13..000000000 --- a/apps/native/src-tauri/migrations/03-evolutions-origin-branch/up.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Legacy databases created before rusqlite_migration used `evolutions.branch`. --- The Rust hook for this migration performs the conditional column repair. -SELECT 1; diff --git a/apps/native/src/components/widget/controls/bootstrap-config.tsx b/apps/native/src/components/widget/controls/bootstrap-config.tsx index f6c8a4ad7..6a961369a 100644 --- a/apps/native/src/components/widget/controls/bootstrap-config.tsx +++ b/apps/native/src/components/widget/controls/bootstrap-config.tsx @@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useDarwinConfig } from "@/hooks/use-darwin-config"; +import { useViewModel } from "@/stores/view-model"; import { useWidgetStore } from "@/stores/widget-store"; import { tauriAPI } from "@/ipc/api"; import { AlertCircle, GitCommit, Sparkles } from "lucide-react"; @@ -18,7 +19,7 @@ export function BootstrapConfig({ label, onSuccess }: BootstrapConfigProps) { const [localError, setLocalError] = useState(null); const { bootstrap, isBootstrapping } = useDarwinConfig(); const configDir = useWidgetStore((state) => state.configDir); - const gitStatus = useWidgetStore((state) => state.gitStatus); + const gitStatus = useViewModel((state) => state.git); const [flakeExists, setFlakeExists] = useState(false); useEffect(() => { @@ -111,4 +112,4 @@ export function BootstrapConfig({ label, onSuccess }: BootstrapConfigProps) { ); -} \ No newline at end of file +} diff --git a/apps/native/src/components/widget/controls/build-head-button.tsx b/apps/native/src/components/widget/controls/build-head-button.tsx index 16871d888..38803a5f3 100644 --- a/apps/native/src/components/widget/controls/build-head-button.tsx +++ b/apps/native/src/components/widget/controls/build-head-button.tsx @@ -1,7 +1,7 @@ import { Wrench } from "lucide-react"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; -import { useWidgetStore } from "@/stores/widget-store"; +import { useViewModel } from "@/stores/view-model"; import { useApply } from "@/hooks/use-apply"; interface BuildHeadButtonProps { @@ -9,7 +9,7 @@ interface BuildHeadButtonProps { } export function BuildHeadButton({ isRestoring = false }: BuildHeadButtonProps) { - const uncommittedChanges = useWidgetStore((s) => (s.gitStatus?.files?.length ?? 0) > 0); + const uncommittedChanges = useViewModel((s) => (s.git?.files?.length ?? 0) > 0); const { handleHistoryBuild } = useApply(); return ( diff --git a/apps/native/src/components/widget/evolve-flow.stories.tsx b/apps/native/src/components/widget/evolve-flow.stories.tsx index bd99f062e..312d1a427 100644 --- a/apps/native/src/components/widget/evolve-flow.stories.tsx +++ b/apps/native/src/components/widget/evolve-flow.stories.tsx @@ -1,5 +1,6 @@ // @ts-nocheck - Storybook 10 alpha types have inference issues (resolves to `never`) import preview from "#storybook/preview"; +import { useViewModel } from "@/stores/view-model"; import { useWidgetStore } from "@/stores/widget-store"; import type { EvolveEvent } from "@/stores/widget-store"; import type { SemanticChangeMap, EvolveState, GitStatus, Change } from "@/ipc/types"; @@ -158,7 +159,13 @@ const mockEvolveEvents: EvolveEvent[] = [ function WidgetWithState({ storeState }: { storeState: Record }) { useEffect(() => { - useWidgetStore.setState(storeState); + const { evolveState, gitStatus, changeMap, ...widgetState } = storeState; + useWidgetStore.setState(widgetState); + useViewModel.setState({ + evolve: (evolveState as EvolveState | undefined) ?? null, + git: (gitStatus as GitStatus | undefined) ?? null, + changeMap: (changeMap as SemanticChangeMap | undefined) ?? null, + }); }, [storeState]); return ; @@ -168,8 +175,8 @@ function AnimatedEvolveFlow() { const timeoutsRef = useRef[]>([]); useEffect(() => { + useViewModel.setState({ evolve: evolveStateBegin }); useWidgetStore.setState({ - evolveState: evolveStateBegin, evolvePrompt: "Add system monitoring tools like htop and btop", }); @@ -195,19 +202,21 @@ function AnimatedEvolveFlow() { // Phase 2: Evolution complete -> show review step with changes const completionTime = 800 + mockEvolveEvents[mockEvolveEvents.length - 1].timestampMs + 1500; const t2 = setTimeout(() => { + useViewModel.setState({ + evolve: evolveStateEvolve, + git: mockGitStatus, + changeMap: mockChangeMap, + }); useWidgetStore.setState({ isGenerating: false, - evolveState: evolveStateEvolve, - gitStatus: mockGitStatus, - changeMap: mockChangeMap, }); }, completionTime); timeoutsRef.current.push(t2); // Phase 3: Transition to merge step const t3 = setTimeout(() => { + useViewModel.setState({ evolve: evolveStateMerge }); useWidgetStore.setState({ - evolveState: evolveStateMerge, commitMessageSuggestion: "feat: add system monitoring tools (htop, btop, bottom, bandwhich, procs)", }); }, completionTime + 5000); diff --git a/apps/native/src/components/widget/history/analyze-history-button.tsx b/apps/native/src/components/widget/history/analyze-history-button.tsx index 339fc9100..7bd491653 100644 --- a/apps/native/src/components/widget/history/analyze-history-button.tsx +++ b/apps/native/src/components/widget/history/analyze-history-button.tsx @@ -1,12 +1,13 @@ import { Button } from "@/components/ui/button"; import { AnalyzeButton } from "@/components/widget/summaries/analyze-button"; import { useHistory } from "@/hooks/use-history"; +import { useViewModel } from "@/stores/view-model"; import { useWidgetStore } from "@/stores/widget-store"; import { Dna, Square } from "lucide-react"; // Generates commit (if need be) and summary metadata for history items that are missing it. export function AnalyzeHistoryButton() { - const history = useWidgetStore((state) => state.history); + const history = useViewModel((state) => state.history); const analyzingSize = useWidgetStore( (state) => state.analyzingHistoryForHashes.size, ); diff --git a/apps/native/src/components/widget/history/discard-uncommitted-dialog.tsx b/apps/native/src/components/widget/history/discard-uncommitted-dialog.tsx index 7d864d8af..d9c0b6a94 100644 --- a/apps/native/src/components/widget/history/discard-uncommitted-dialog.tsx +++ b/apps/native/src/components/widget/history/discard-uncommitted-dialog.tsx @@ -8,6 +8,7 @@ import { } from "@/components/ui/dialog"; import { ConfigDirBadge } from "@/components/widget/badges/config-dir-badge"; import { useRollback } from "@/hooks/use-rollback"; +import { useViewModel } from "@/stores/view-model"; import { useWidgetStore } from "@/stores/widget-store"; import { toast } from "sonner"; @@ -17,14 +18,14 @@ interface DiscardUncommittedDialogProps { } export function DiscardUncommittedDialog({ open, onOpenChange }: DiscardUncommittedDialogProps) { - const gitStatus = useWidgetStore((s) => s.gitStatus); + const gitStatus = useViewModel((s) => s.git); const configDir = useWidgetStore((s) => s.configDir); const files = gitStatus?.files ?? []; const { handleRollback } = useRollback(); const handleDiscard = async () => { await handleRollback(); - const remaining = useWidgetStore.getState().gitStatus?.files?.length ?? 1; + const remaining = useViewModel.getState().git?.files?.length ?? 1; if (remaining === 0) { toast.success("Changes discarded"); onOpenChange(false); diff --git a/apps/native/src/components/widget/history/history-restore-item-button.tsx b/apps/native/src/components/widget/history/history-restore-item-button.tsx index b7a89f986..b135030a4 100644 --- a/apps/native/src/components/widget/history/history-restore-item-button.tsx +++ b/apps/native/src/components/widget/history/history-restore-item-button.tsx @@ -1,7 +1,7 @@ import { Loader2, RotateCcw } from "lucide-react"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; -import { useWidgetStore } from "@/stores/widget-store"; +import { useViewModel } from "@/stores/view-model"; interface HistoryRestoreItemButtonProps { hash: string; @@ -14,7 +14,7 @@ export function HistoryRestoreItemButton({ isRestoring = false, onRequestRestore, }: HistoryRestoreItemButtonProps) { - const uncommittedChanges = useWidgetStore((s) => (s.gitStatus?.files?.length ?? 0) > 0); + const uncommittedChanges = useViewModel((s) => (s.git?.files?.length ?? 0) > 0); return (