Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -18,7 +19,7 @@ export function BootstrapConfig({ label, onSuccess }: BootstrapConfigProps) {
const [localError, setLocalError] = useState<string | null>(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(() => {
Expand Down Expand Up @@ -111,4 +112,4 @@ export function BootstrapConfig({ label, onSuccess }: BootstrapConfigProps) {
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
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 {
isRestoring?: boolean;
}

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 (
Expand Down
21 changes: 15 additions & 6 deletions apps/native/src/components/widget/evolve-flow.stories.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -158,7 +159,13 @@ const mockEvolveEvents: EvolveEvent[] = [

function WidgetWithState({ storeState }: { storeState: Record<string, unknown> }) {
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 <DarwinWidget />;
Expand All @@ -168,8 +175,8 @@ function AnimatedEvolveFlow() {
const timeoutsRef = useRef<ReturnType<typeof setTimeout>[]>([]);

useEffect(() => {
useViewModel.setState({ evolve: evolveStateBegin });
useWidgetStore.setState({
evolveState: evolveStateBegin,
evolvePrompt: "Add system monitoring tools like htop and btop",
});

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 (
<Button
Expand Down
7 changes: 4 additions & 3 deletions apps/native/src/components/widget/layout/debug-overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"use client";

import { useWidgetStore } from "@/stores/widget-store";
import { tauriAPI } from "@/ipc/api";
import { useViewModel } from "@/stores/view-model";
import { mirrorEvolveState } from "@/viewmodel/evolve";
import { useState } from "react";
import { GitStatusDebug } from "@/components/widget/layout/git-status-debug";

/**
* Debug overlay for development - shows current widget state
*/
export function DebugOverlay() {
const evolveState = useWidgetStore((s) => s.evolveState);
const evolveState = useViewModel((s) => s.evolve);
const [visible, setVisible] = useState(true);

if (!visible) {
Expand Down Expand Up @@ -47,7 +48,7 @@ export function DebugOverlay() {
</div>
<button
className="pointer-events-auto rounded bg-black/80 px-2 py-1 font-mono text-xs text-rose-400/60 hover:text-rose-400"
onClick={() => tauriAPI.evolveState.clear().then((s) => useWidgetStore.getState().setEvolveState(s))}
onClick={() => tauriAPI.evolveState.clear().then(mirrorEvolveState)}
style={{ backdropFilter: "blur(4px)" }}
type="button"
>
Expand Down
4 changes: 2 additions & 2 deletions apps/native/src/components/widget/layout/git-status-debug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// - Do not add fields that are not on the GitStatus type.

import { useState } from "react";
import { useWidgetStore } from "@/stores/widget-store";
import { useViewModel } from "@/stores/view-model";

function Bool({ label, value }: { label: string; value: boolean | undefined }) {
if (value === undefined || !value) {
Expand Down Expand Up @@ -44,7 +44,7 @@ function FieldRow({ label, display, full }: { label: string; display: string; fu

export function GitStatusDebug() {
const [expanded, setExpanded] = useState(false);
const gitStatus = useWidgetStore((s) => s.gitStatus);
const gitStatus = useViewModel((s) => s.git);

if (!gitStatus) {
return (
Expand Down
6 changes: 5 additions & 1 deletion apps/native/src/components/widget/layout/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Clock, FolderTree, Settings, MessageSquarePlus } from "lucide-react";
import { APP_NAME } from "../../../../shared/constants";
import { useWidgetStore } from "@/stores/widget-store";
import { computeCurrentStep } from "@/components/widget/utils";
import { useViewModel } from "@/stores/view-model";

export function Header() {
const setSettingsOpen = useWidgetStore((s) => s.setSettingsOpen);
Expand All @@ -21,7 +22,10 @@ export function Header() {
// Flash the feedback icon when an error occurs (subscribe to detect all changes)
useEffect(() => {
return useWidgetStore.subscribe((state, prevState) => {
const step = computeCurrentStep(state);
const step = computeCurrentStep({
...state,
evolveState: useViewModel.getState().evolve,
});
if (step !== "setup" && state.error && state.error !== prevState.error) {
setIsPulsing(true);
setTimeout(() => setIsPulsing(false), 2000);
Expand Down
3 changes: 2 additions & 1 deletion apps/native/src/components/widget/layout/merge-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useGitOperations } from "@/hooks/use-git-operations";
import { useSummary } from "@/hooks/use-summary";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";
import { GitMerge, Loader2 } from "lucide-react";
import { useEffect } from "react";
Expand All @@ -12,7 +13,7 @@ export function MergeSection() {
const isProcessing = useWidgetStore((s) => s.isProcessing);
const processingAction = useWidgetStore((s) => s.processingAction);
const commitMessageSuggestion = useWidgetStore((s) => s.commitMessageSuggestion);
const changeMap = useWidgetStore((s) => s.changeMap);
const changeMap = useViewModel((s) => s.changeMap);

const { handleCommit } = useGitOperations();
const { generateCommitMessage } = useSummary();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck - Storybook 10 alpha types have inference issues (resolves to `never`)
import preview from "#storybook/preview";
import type { EvolveState } from "@/stores/widget-store";
import { useWidgetStore } from "@/stores/widget-store";
import { useViewModel } from "@/stores/view-model";
import { fn } from "storybook/test";
import { useEffect } from "react";
import { ExternalBuildDetected } from "@/components/widget/notifications/external-build-detected";
Expand Down Expand Up @@ -47,9 +47,13 @@ function setup({
evolveState: EvolveState | null;
}) {
useEffect(() => {
const store = useWidgetStore.getState();
store.setExternalBuildDetected(externalBuildDetected);
store.setEvolveState(evolveState);
useViewModel.setState((state) => ({
evolve: evolveState,
build: {
...state.build,
externalBuildDetected,
},
}));
}, [externalBuildDetected, evolveState]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import { useState } from "react";
import { Hammer } from "lucide-react";
import { Spinner } from "@/components/ui/spinner";
import { useWidgetStore } from "@/stores/widget-store";
import { useViewModel } from "@/stores/view-model";
import { useApply } from "@/hooks/use-apply";

export function ExternalBuildDetected() {
const externalBuildDetected = useWidgetStore((s) => s.externalBuildDetected);
const externalBuildDetected = useViewModel((s) => s.build.externalBuildDetected);
const { handleManualBuildConfirm } = useApply();
const [isPending, setIsPending] = useState(false);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { RefObject } from "react";
import { Eraser } from "lucide-react";
import { cn } from "@/lib/utils";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";
import { ConfigDirBadge } from "@/components/widget/badges/config-dir-badge";
import { Button } from "@/components/ui/button";
Expand All @@ -16,7 +17,7 @@ export function UncommittedChangesDetected({
isFlashing,
onOpenDialog,
}: UncommittedChangesDetectedProps) {
const gitStatus = useWidgetStore((s) => s.gitStatus);
const gitStatus = useViewModel((s) => s.git);
const configDir = useWidgetStore((s) => s.configDir);
const fileCount = gitStatus?.files?.length ?? 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import { ConfigDirBadge } from "@/components/widget/badges/config-dir-badge";
import { AnalyzeCurrentButton } from "@/components/widget/summaries/analyze-current-button";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";

export function UnsummarizedChangesDetected() {
const configDir = useWidgetStore((s) => s.configDir);
const changeMap = useWidgetStore((s) => s.changeMap);
const changeMap = useViewModel((s) => s.changeMap);
if (!changeMap) return null;
const hasUnsummarized = changeMap?.unsummarizedHashes.length
if (!hasUnsummarized) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ConfigDirBadge } from "@/components/widget/badges/config-dir-badge";
import { useEvolve } from "@/hooks/use-evolve";
import { useGitOperations } from "@/hooks/use-git-operations";
import { useRollback } from "@/hooks/use-rollback";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";
import { Loader2, X } from "lucide-react";
import { useEffect, useRef, useState } from "react";
Expand All @@ -28,7 +29,7 @@ interface BeginEvolveWarningProps {
type BuildCheckStatus = "checking" | "passed" | "failed";

export function BeginEvolveWarning({ open, onOpenChange, handleEvolve }: BeginEvolveWarningProps) {
const gitStatus = useWidgetStore((s) => s.gitStatus);
const gitStatus = useViewModel((s) => s.git);
const evolvePrompt = useWidgetStore((s) => s.evolvePrompt);
const configDir = useWidgetStore((s) => s.configDir);
const files = gitStatus?.files ?? [];
Expand Down Expand Up @@ -57,7 +58,7 @@ export function BeginEvolveWarning({ open, onOpenChange, handleEvolve }: BeginEv

const handleDiscard = async () => {
await handleRollback();
const newFiles = useWidgetStore.getState().gitStatus?.files?.length ?? 1;
const newFiles = useViewModel.getState().git?.files?.length ?? 1;
if (newFiles === 0) {
toast.success("Changes discarded");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PopoverTrigger,
} from "@/components/ui/popover";
import { countDiffItems, useHomebrewDiff } from "@/hooks/use-homebrew-diff";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";
import { Package } from "lucide-react";

Expand All @@ -17,7 +18,7 @@ import { Package } from "lucide-react";
* the working tree is clean, and there are packages not yet in config.
*/
export function HomebrewBadge() {
const evolveState = useWidgetStore((s) => s.evolveState);
const evolveState = useViewModel((s) => s.evolve);
const prefsLoaded = useWidgetStore((s) => s.prefsLoaded);
const scanHomebrewOnStartup = useWidgetStore((s) => s.scanHomebrewOnStartup);
const shouldScan = prefsLoaded && scanHomebrewOnStartup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PromptHistoryBadge } from "@/components/widget/promptinput/prompt-histo
import { SystemDefaultsCTA } from "@/components/widget/promptinput/system-defaults-cta";
import { useEvolve } from "@/hooks/use-evolve";
import { getProviderConfigInvalidReason } from "@/lib/ai-provider-validation";
import { useViewModel } from "@/stores/view-model";
import { useWidgetStore } from "@/stores/widget-store";
import { tauriAPI } from "@/ipc/api";
import { ArrowUpIcon } from "lucide-react";
Expand All @@ -29,8 +30,8 @@ export function PromptInput() {
const setEvolvePrompt = useWidgetStore((s) => s.setEvolvePrompt);
const isProcessing = useWidgetStore((s) => s.isProcessing);
const processingAction = useWidgetStore((s) => s.processingAction);
const evolveState = useWidgetStore((s) => s.evolveState);
const gitStatus = useWidgetStore((s) => s.gitStatus);
const evolveState = useViewModel((s) => s.evolve);
const gitStatus = useViewModel((s) => s.git);
const settingsOpen = useWidgetStore((s) => s.settingsOpen);
const setSettingsOpen = useWidgetStore((s) => s.setSettingsOpen);
const { handleEvolve, evolveFromManual } = useEvolve();
Expand Down
Loading
Loading