diff --git a/desktop/src/store/gatewayStore.ts b/desktop/src/store/gatewayStore.ts deleted file mode 100644 index 0781642..0000000 --- a/desktop/src/store/gatewayStore.ts +++ /dev/null @@ -1,358 +0,0 @@ -/** - * gatewayStore.ts - Backward-Compatible Facade - * - * This file was the original monolithic store (1800+ lines). - * It is now a thin facade that re-exports types and provides - * a composite useGatewayStore hook from the domain-specific stores: - * - * connectionStore.ts - Connection, local gateway management - * agentStore.ts - Clones, usage stats, plugins - * handStore.ts - Hands, triggers, approvals - * workflowStore.ts - Workflows, workflow runs - * configStore.ts - Config, channels, skills, models, workspace - * securityStore.ts - Security status, audit logs - * sessionStore.ts - Sessions, session messages - * - * Components should gradually migrate to import from the specific stores. - * This facade exists only for backward compatibility. - */ -import { useConnectionStore } from './connectionStore'; -import { useAgentStore } from './agentStore'; -import { useHandStore } from './handStore'; -import { useWorkflowStore } from './workflowStore'; -import { useConfigStore } from './configStore'; -import { useSecurityStore } from './securityStore'; -import { useSessionStore } from './sessionStore'; -import { useChatStore } from './chatStore'; -import type { GatewayClient, ConnectionState } from '../lib/gateway-client'; -import type { KernelClient } from '../lib/kernel-client'; -import type { GatewayModelChoice } from '../lib/gateway-config'; -import type { LocalGatewayStatus } from '../lib/tauri-gateway'; -import type { Hand, HandRun, Trigger, Approval, ApprovalStatus } from './handStore'; -import type { Workflow, WorkflowRun } from './workflowStore'; -import type { Clone, PluginStatus, UsageStats } from './agentStore'; -import type { QuickConfig, ChannelInfo, ScheduledTask, SkillInfo, WorkspaceInfo } from './configStore'; -import type { SecurityStatus, AuditLogEntry } from './securityStore'; -import type { Session, SessionMessage } from './sessionStore'; -import type { GatewayLog } from './connectionStore'; - -// === Re-export Types from Domain Stores === -// These re-exports maintain backward compatibility for all 34+ consumer files. - -export type { Hand, HandRun, HandRequirement, Trigger, Approval, ApprovalStatus } from './handStore'; -export type { Workflow, WorkflowRun } from './workflowStore'; -export type { Clone, UsageStats, PluginStatus } from './agentStore'; -export type { QuickConfig, WorkspaceInfo, ChannelInfo, ScheduledTask, SkillInfo } from './configStore'; -export type { SecurityLayer, SecurityStatus, AuditLogEntry } from './securityStore'; -export type { Session, SessionMessage } from './sessionStore'; -export type { GatewayLog } from './connectionStore'; - -// === Composite useGatewayStore Hook === -// Provides a single store interface that delegates to all domain stores. -// Components should gradually migrate to import from the specific stores. - -/** - * Composite gateway store hook. - * - * Reads state from all domain stores and delegates actions. - * This is a React hook (not a Zustand store) — it subscribes to - * all underlying stores and returns a unified interface. - * - * @deprecated Components should migrate to use domain-specific stores directly: - * useConnectionStore, useAgentStore, useHandStore, useWorkflowStore, - * useConfigStore, useSecurityStore, useSessionStore - */ -export function useGatewayStore(): GatewayFacade; -export function useGatewayStore(selector: (state: GatewayFacade) => T): T; -export function useGatewayStore(selector?: (state: GatewayFacade) => T): T | GatewayFacade { - // Subscribe to all stores (React will re-render when any changes) - const conn = useConnectionStore(); - const agent = useAgentStore(); - const hand = useHandStore(); - const workflow = useWorkflowStore(); - const config = useConfigStore(); - const security = useSecurityStore(); - const session = useSessionStore(); - - const facade: GatewayFacade = { - // === Connection State === - connectionState: conn.connectionState, - gatewayVersion: conn.gatewayVersion, - error: conn.error || agent.error || hand.error || workflow.error || config.error || session.error || security.securityStatusError, - logs: conn.logs, - localGateway: conn.localGateway, - localGatewayBusy: conn.localGatewayBusy, - isLoading: conn.isLoading || agent.isLoading || hand.isLoading || workflow.isLoading, - client: conn.client, - - // === Agent State === - clones: agent.clones, - usageStats: agent.usageStats, - pluginStatus: agent.pluginStatus, - - // === Hand State === - hands: hand.hands, - handRuns: hand.handRuns, - triggers: hand.triggers, - approvals: hand.approvals, - - // === Workflow State === - workflows: workflow.workflows, - workflowRuns: workflow.workflowRuns as Record, - - // === Config State === - quickConfig: config.quickConfig, - workspaceInfo: config.workspaceInfo, - channels: config.channels, - scheduledTasks: config.scheduledTasks, - skillsCatalog: config.skillsCatalog, - models: config.models, - modelsLoading: config.modelsLoading, - modelsError: config.modelsError, - - // === Security State === - securityStatus: security.securityStatus, - securityStatusLoading: security.securityStatusLoading, - securityStatusError: security.securityStatusError, - auditLogs: security.auditLogs, - - // === Session State === - sessions: session.sessions, - sessionMessages: session.sessionMessages, - - // === Connection Actions === - connect: async (url?: string, token?: string) => { - await conn.connect(url, token); - // Post-connect: load all data from domain stores - await Promise.allSettled([ - config.loadQuickConfig(), - config.loadWorkspaceInfo(), - agent.loadClones().then(() => { - // Sync agents to chat store after loading (use getState for latest) - useChatStore.getState().syncAgents(useAgentStore.getState().clones); - }), - agent.loadUsageStats(), - agent.loadPluginStatus(), - config.loadScheduledTasks(), - config.loadSkillsCatalog(), - hand.loadHands(), - workflow.loadWorkflows(), - hand.loadTriggers(), - security.loadSecurityStatus(), - config.loadModels(), - ]); - await config.loadChannels(); - }, - disconnect: conn.disconnect, - clearLogs: conn.clearLogs, - refreshLocalGateway: conn.refreshLocalGateway, - startLocalGateway: conn.startLocalGateway, - stopLocalGateway: conn.stopLocalGateway, - restartLocalGateway: conn.restartLocalGateway, - - // === Agent Actions === - loadClones: agent.loadClones, - createClone: agent.createClone as GatewayFacade['createClone'], - updateClone: agent.updateClone as GatewayFacade['updateClone'], - deleteClone: agent.deleteClone, - loadUsageStats: agent.loadUsageStats, - loadPluginStatus: agent.loadPluginStatus, - - // === Hand Actions === - loadHands: hand.loadHands, - getHandDetails: hand.getHandDetails, - triggerHand: hand.triggerHand, - loadHandRuns: hand.loadHandRuns, - approveHand: hand.approveHand, - cancelHand: hand.cancelHand, - loadTriggers: hand.loadTriggers, - getTrigger: hand.getTrigger, - createTrigger: hand.createTrigger as GatewayFacade['createTrigger'], - updateTrigger: hand.updateTrigger, - deleteTrigger: hand.deleteTrigger, - loadApprovals: hand.loadApprovals, - respondToApproval: hand.respondToApproval, - - // === Workflow Actions === - loadWorkflows: workflow.loadWorkflows, - createWorkflow: workflow.createWorkflow as GatewayFacade['createWorkflow'], - updateWorkflow: workflow.updateWorkflow as GatewayFacade['updateWorkflow'], - deleteWorkflow: workflow.deleteWorkflow, - executeWorkflow: workflow.triggerWorkflow as GatewayFacade['executeWorkflow'], - cancelWorkflow: workflow.cancelWorkflow, - loadWorkflowRuns: workflow.loadWorkflowRuns as GatewayFacade['loadWorkflowRuns'], - - // === Config Actions === - loadQuickConfig: config.loadQuickConfig, - saveQuickConfig: config.saveQuickConfig, - loadWorkspaceInfo: config.loadWorkspaceInfo, - loadChannels: config.loadChannels, - getChannel: config.getChannel, - createChannel: config.createChannel, - updateChannel: config.updateChannel, - deleteChannel: config.deleteChannel, - loadScheduledTasks: config.loadScheduledTasks, - createScheduledTask: config.createScheduledTask, - loadSkillsCatalog: config.loadSkillsCatalog, - getSkill: config.getSkill, - createSkill: config.createSkill, - updateSkill: config.updateSkill, - deleteSkill: config.deleteSkill, - loadModels: config.loadModels, - - // === Security Actions === - loadSecurityStatus: security.loadSecurityStatus, - loadAuditLogs: security.loadAuditLogs, - - // === Session Actions === - loadSessions: session.loadSessions, - getSession: session.getSession, - createSession: session.createSession, - deleteSession: session.deleteSession, - loadSessionMessages: session.loadSessionMessages, - - // === Legacy === - sendMessage: async (message: string, sessionKey?: string) => { - return conn.client.chat(message, { sessionKey }); - }, - }; - - if (selector) { - return selector(facade); - } - return facade; -} - -// === Facade Interface (matches the old GatewayStore shape) === - -interface GatewayFacade { - // Connection state - connectionState: ConnectionState; - gatewayVersion: string | null; - error: string | null; - logs: GatewayLog[]; - localGateway: LocalGatewayStatus; - localGatewayBusy: boolean; - isLoading: boolean; - client: GatewayClient | KernelClient; - - // Data - clones: Clone[]; - usageStats: UsageStats | null; - pluginStatus: PluginStatus[]; - channels: ChannelInfo[]; - scheduledTasks: ScheduledTask[]; - skillsCatalog: SkillInfo[]; - quickConfig: QuickConfig; - workspaceInfo: WorkspaceInfo | null; - models: GatewayModelChoice[]; - modelsLoading: boolean; - modelsError: string | null; - - // ZCLAW Data - hands: Hand[]; - handRuns: Record; - workflows: Workflow[]; - triggers: Trigger[]; - auditLogs: AuditLogEntry[]; - securityStatus: SecurityStatus | null; - securityStatusLoading: boolean; - securityStatusError: string | null; - approvals: Approval[]; - sessions: Session[]; - sessionMessages: Record; - workflowRuns: Record; - - // Connection Actions - connect: (url?: string, token?: string) => Promise; - disconnect: () => void; - clearLogs: () => void; - refreshLocalGateway: () => Promise; - startLocalGateway: () => Promise; - stopLocalGateway: () => Promise; - restartLocalGateway: () => Promise; - - // Agent Actions - loadClones: () => Promise; - createClone: (opts: { name: string; role?: string; nickname?: string; scenarios?: string[]; model?: string; workspaceDir?: string; restrictFiles?: boolean; privacyOptIn?: boolean; userName?: string; userRole?: string }) => Promise; - updateClone: (id: string, updates: Partial) => Promise; - deleteClone: (id: string) => Promise; - loadUsageStats: () => Promise; - loadPluginStatus: () => Promise; - - // Hand Actions - loadHands: () => Promise; - getHandDetails: (name: string) => Promise; - loadHandRuns: (name: string, opts?: { limit?: number; offset?: number }) => Promise; - triggerHand: (name: string, params?: Record) => Promise; - approveHand: (name: string, runId: string, approved: boolean, reason?: string) => Promise; - cancelHand: (name: string, runId: string) => Promise; - loadTriggers: () => Promise; - getTrigger: (id: string) => Promise; - createTrigger: (trigger: { type: string; name?: string; enabled?: boolean; config?: Record; handName?: string; workflowId?: string }) => Promise; - updateTrigger: (id: string, updates: { name?: string; enabled?: boolean; config?: Record; handName?: string; workflowId?: string }) => Promise; - deleteTrigger: (id: string) => Promise; - loadApprovals: (status?: ApprovalStatus) => Promise; - respondToApproval: (approvalId: string, approved: boolean, reason?: string) => Promise; - - // Workflow Actions - loadWorkflows: () => Promise; - createWorkflow: (workflow: { name: string; description?: string; steps: Array<{ handName: string; name?: string; params?: Record; condition?: string }> }) => Promise; - updateWorkflow: (id: string, updates: { name?: string; description?: string; steps?: Array<{ handName: string; name?: string; params?: Record; condition?: string }> }) => Promise; - deleteWorkflow: (id: string) => Promise; - executeWorkflow: (id: string, input?: Record) => Promise; - cancelWorkflow: (id: string, runId: string) => Promise; - loadWorkflowRuns: (workflowId: string, opts?: { limit?: number; offset?: number }) => Promise; - - // Config Actions - loadQuickConfig: () => Promise; - saveQuickConfig: (updates: Partial) => Promise; - loadWorkspaceInfo: () => Promise; - loadChannels: () => Promise; - getChannel: (id: string) => Promise; - createChannel: (channel: { type: string; name: string; config: Record; enabled?: boolean }) => Promise; - updateChannel: (id: string, updates: { name?: string; config?: Record; enabled?: boolean }) => Promise; - deleteChannel: (id: string) => Promise; - loadScheduledTasks: () => Promise; - createScheduledTask: (task: { name: string; schedule: string; scheduleType: 'cron' | 'interval' | 'once'; target?: { type: 'agent' | 'hand' | 'workflow'; id: string }; description?: string; enabled?: boolean }) => Promise; - loadSkillsCatalog: () => Promise; - getSkill: (id: string) => Promise; - createSkill: (skill: { name: string; description?: string; triggers: Array<{ type: string; pattern?: string }>; actions: Array<{ type: string; params?: Record }>; enabled?: boolean }) => Promise; - updateSkill: (id: string, updates: { name?: string; description?: string; triggers?: Array<{ type: string; pattern?: string }>; actions?: Array<{ type: string; params?: Record }>; enabled?: boolean }) => Promise; - deleteSkill: (id: string) => Promise; - loadModels: () => Promise; - - // Security Actions - loadSecurityStatus: () => Promise; - loadAuditLogs: (opts?: { limit?: number; offset?: number }) => Promise; - - // Session Actions - loadSessions: (opts?: { limit?: number; offset?: number }) => Promise; - getSession: (sessionId: string) => Promise; - createSession: (agentId: string, metadata?: Record) => Promise; - deleteSession: (sessionId: string) => Promise; - loadSessionMessages: (sessionId: string, opts?: { limit?: number; offset?: number }) => Promise; - - // Legacy - sendMessage: (message: string, sessionKey?: string) => Promise<{ runId: string }>; -} - -// Dev-only: Expose stores to window for E2E testing -if (import.meta.env.DEV && typeof window !== 'undefined') { - (window as any).__ZCLAW_STORES__ = (window as any).__ZCLAW_STORES__ || {}; - (window as any).__ZCLAW_STORES__.gateway = useGatewayStore; - (window as any).__ZCLAW_STORES__.connection = useConnectionStore; - (window as any).__ZCLAW_STORES__.agent = useAgentStore; - (window as any).__ZCLAW_STORES__.hand = useHandStore; - (window as any).__ZCLAW_STORES__.workflow = useWorkflowStore; - (window as any).__ZCLAW_STORES__.config = useConfigStore; - (window as any).__ZCLAW_STORES__.security = useSecurityStore; - (window as any).__ZCLAW_STORES__.session = useSessionStore; - // Dynamically import chatStore to avoid circular dependency - import('./chatStore').then(({ useChatStore }) => { - (window as any).__ZCLAW_STORES__.chat = useChatStore; - }).catch(() => { - // Ignore if chatStore is not available - }); -} - diff --git a/desktop/src/store/index.ts b/desktop/src/store/index.ts index fe7e875..75d0083 100644 --- a/desktop/src/store/index.ts +++ b/desktop/src/store/index.ts @@ -1,8 +1,7 @@ /** * Store Coordinator * - * This module provides a unified interface to all specialized stores, - * maintaining backward compatibility with components that import useGatewayStore. + * This module provides a unified interface to all specialized stores. * * The coordinator: * 1. Injects the shared client into all stores