refactor(desktop): remove deprecated gatewayStore.ts facade
- Remove gatewayStore.ts (358-line backward-compat facade) that no components import from - All consumers already use domain-specific stores directly (connectionStore, agentStore, handStore, etc.) - Update store/index.ts comment to remove useGatewayStore reference
This commit is contained in:
@@ -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<T>(selector: (state: GatewayFacade) => T): T;
|
||||
export function useGatewayStore<T>(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<string, WorkflowRun[]>,
|
||||
|
||||
// === 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<string, HandRun[]>;
|
||||
workflows: Workflow[];
|
||||
triggers: Trigger[];
|
||||
auditLogs: AuditLogEntry[];
|
||||
securityStatus: SecurityStatus | null;
|
||||
securityStatusLoading: boolean;
|
||||
securityStatusError: string | null;
|
||||
approvals: Approval[];
|
||||
sessions: Session[];
|
||||
sessionMessages: Record<string, SessionMessage[]>;
|
||||
workflowRuns: Record<string, WorkflowRun[]>;
|
||||
|
||||
// Connection Actions
|
||||
connect: (url?: string, token?: string) => Promise<void>;
|
||||
disconnect: () => void;
|
||||
clearLogs: () => void;
|
||||
refreshLocalGateway: () => Promise<LocalGatewayStatus>;
|
||||
startLocalGateway: () => Promise<LocalGatewayStatus | undefined>;
|
||||
stopLocalGateway: () => Promise<LocalGatewayStatus | undefined>;
|
||||
restartLocalGateway: () => Promise<LocalGatewayStatus | undefined>;
|
||||
|
||||
// Agent Actions
|
||||
loadClones: () => Promise<void>;
|
||||
createClone: (opts: { name: string; role?: string; nickname?: string; scenarios?: string[]; model?: string; workspaceDir?: string; restrictFiles?: boolean; privacyOptIn?: boolean; userName?: string; userRole?: string }) => Promise<Clone | undefined>;
|
||||
updateClone: (id: string, updates: Partial<Clone>) => Promise<Clone | undefined>;
|
||||
deleteClone: (id: string) => Promise<void>;
|
||||
loadUsageStats: () => Promise<void>;
|
||||
loadPluginStatus: () => Promise<void>;
|
||||
|
||||
// Hand Actions
|
||||
loadHands: () => Promise<void>;
|
||||
getHandDetails: (name: string) => Promise<Hand | undefined>;
|
||||
loadHandRuns: (name: string, opts?: { limit?: number; offset?: number }) => Promise<HandRun[]>;
|
||||
triggerHand: (name: string, params?: Record<string, unknown>) => Promise<HandRun | undefined>;
|
||||
approveHand: (name: string, runId: string, approved: boolean, reason?: string) => Promise<void>;
|
||||
cancelHand: (name: string, runId: string) => Promise<void>;
|
||||
loadTriggers: () => Promise<void>;
|
||||
getTrigger: (id: string) => Promise<Trigger | undefined>;
|
||||
createTrigger: (trigger: { type: string; name?: string; enabled?: boolean; config?: Record<string, unknown>; handName?: string; workflowId?: string }) => Promise<Trigger | undefined>;
|
||||
updateTrigger: (id: string, updates: { name?: string; enabled?: boolean; config?: Record<string, unknown>; handName?: string; workflowId?: string }) => Promise<Trigger | undefined>;
|
||||
deleteTrigger: (id: string) => Promise<void>;
|
||||
loadApprovals: (status?: ApprovalStatus) => Promise<void>;
|
||||
respondToApproval: (approvalId: string, approved: boolean, reason?: string) => Promise<void>;
|
||||
|
||||
// Workflow Actions
|
||||
loadWorkflows: () => Promise<void>;
|
||||
createWorkflow: (workflow: { name: string; description?: string; steps: Array<{ handName: string; name?: string; params?: Record<string, unknown>; condition?: string }> }) => Promise<Workflow | undefined>;
|
||||
updateWorkflow: (id: string, updates: { name?: string; description?: string; steps?: Array<{ handName: string; name?: string; params?: Record<string, unknown>; condition?: string }> }) => Promise<Workflow | undefined>;
|
||||
deleteWorkflow: (id: string) => Promise<void>;
|
||||
executeWorkflow: (id: string, input?: Record<string, unknown>) => Promise<WorkflowRun | undefined>;
|
||||
cancelWorkflow: (id: string, runId: string) => Promise<void>;
|
||||
loadWorkflowRuns: (workflowId: string, opts?: { limit?: number; offset?: number }) => Promise<WorkflowRun[]>;
|
||||
|
||||
// Config Actions
|
||||
loadQuickConfig: () => Promise<void>;
|
||||
saveQuickConfig: (updates: Partial<QuickConfig>) => Promise<void>;
|
||||
loadWorkspaceInfo: () => Promise<void>;
|
||||
loadChannels: () => Promise<void>;
|
||||
getChannel: (id: string) => Promise<ChannelInfo | undefined>;
|
||||
createChannel: (channel: { type: string; name: string; config: Record<string, unknown>; enabled?: boolean }) => Promise<ChannelInfo | undefined>;
|
||||
updateChannel: (id: string, updates: { name?: string; config?: Record<string, unknown>; enabled?: boolean }) => Promise<ChannelInfo | undefined>;
|
||||
deleteChannel: (id: string) => Promise<void>;
|
||||
loadScheduledTasks: () => Promise<void>;
|
||||
createScheduledTask: (task: { name: string; schedule: string; scheduleType: 'cron' | 'interval' | 'once'; target?: { type: 'agent' | 'hand' | 'workflow'; id: string }; description?: string; enabled?: boolean }) => Promise<ScheduledTask | undefined>;
|
||||
loadSkillsCatalog: () => Promise<void>;
|
||||
getSkill: (id: string) => Promise<SkillInfo | undefined>;
|
||||
createSkill: (skill: { name: string; description?: string; triggers: Array<{ type: string; pattern?: string }>; actions: Array<{ type: string; params?: Record<string, unknown> }>; enabled?: boolean }) => Promise<SkillInfo | undefined>;
|
||||
updateSkill: (id: string, updates: { name?: string; description?: string; triggers?: Array<{ type: string; pattern?: string }>; actions?: Array<{ type: string; params?: Record<string, unknown> }>; enabled?: boolean }) => Promise<SkillInfo | undefined>;
|
||||
deleteSkill: (id: string) => Promise<void>;
|
||||
loadModels: () => Promise<void>;
|
||||
|
||||
// Security Actions
|
||||
loadSecurityStatus: () => Promise<void>;
|
||||
loadAuditLogs: (opts?: { limit?: number; offset?: number }) => Promise<void>;
|
||||
|
||||
// Session Actions
|
||||
loadSessions: (opts?: { limit?: number; offset?: number }) => Promise<void>;
|
||||
getSession: (sessionId: string) => Promise<Session | undefined>;
|
||||
createSession: (agentId: string, metadata?: Record<string, unknown>) => Promise<Session | undefined>;
|
||||
deleteSession: (sessionId: string) => Promise<void>;
|
||||
loadSessionMessages: (sessionId: string, opts?: { limit?: number; offset?: number }) => Promise<SessionMessage[]>;
|
||||
|
||||
// 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
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user