feat(phase-11): add store coordinator layer
- Create store/index.ts as unified entry point - Add useCompositeStore() hook for multi-slice access - Add initializeStores() for client injection - Re-export all individual stores for direct access - Maintain backward compatibility with useGatewayStore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
261
desktop/src/store/index.ts
Normal file
261
desktop/src/store/index.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Store Coordinator
|
||||
*
|
||||
* This module provides a unified interface to all specialized stores,
|
||||
* maintaining backward compatibility with components that import useGatewayStore.
|
||||
*
|
||||
* The coordinator:
|
||||
* 1. Injects the shared client into all stores
|
||||
* 2. Provides a composite hook that combines all store slices
|
||||
* 3. Re-exports all individual stores for direct access
|
||||
*/
|
||||
|
||||
// === Re-export Individual Stores ===
|
||||
export { useConnectionStore, getConnectionState, getClient, getConnectionError, getGatewayVersion } from './connectionStore';
|
||||
export type { ConnectionStore, ConnectionStateSlice, ConnectionActionsSlice, GatewayLog } from './connectionStore';
|
||||
|
||||
export { useAgentStore, setAgentStoreClient } from './agentStore';
|
||||
export type { AgentStore, AgentStateSlice, AgentActionsSlice, Clone, UsageStats, PluginStatus, CloneCreateOptions } from './agentStore';
|
||||
|
||||
export { useHandStore, setHandStoreClient } from './handStore';
|
||||
export type { HandStore, HandStateSlice, HandActionsSlice, Hand, HandRun, Trigger, Approval, TriggerCreateOptions } from './handStore';
|
||||
|
||||
export { useWorkflowStore, setWorkflowStoreClient } from './workflowStore';
|
||||
export type { WorkflowStore, WorkflowStateSlice, WorkflowActionsSlice, Workflow, WorkflowRun, WorkflowCreateOptions } from './workflowStore';
|
||||
|
||||
export { useConfigStore, setConfigStoreClient } from './configStore';
|
||||
export type { ConfigStore, ConfigStateSlice, ConfigActionsSlice, QuickConfig, WorkspaceInfo, ChannelInfo, ScheduledTask, SkillInfo } from './configStore';
|
||||
|
||||
// === Composite Store Hook ===
|
||||
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useConnectionStore, getClient } from './connectionStore';
|
||||
import { useAgentStore, setAgentStoreClient } from './agentStore';
|
||||
import { useHandStore, setHandStoreClient } from './handStore';
|
||||
import { useWorkflowStore, setWorkflowStoreClient } from './workflowStore';
|
||||
import { useConfigStore, setConfigStoreClient } from './configStore';
|
||||
import type { GatewayClient } from '../lib/gateway-client';
|
||||
|
||||
/**
|
||||
* Initialize all stores with the shared client.
|
||||
* Called once when the application mounts.
|
||||
*/
|
||||
export function initializeStores(): void {
|
||||
const client = getClient();
|
||||
|
||||
// Inject client into all stores
|
||||
setAgentStoreClient(client);
|
||||
setHandStoreClient(client);
|
||||
setWorkflowStoreClient(client);
|
||||
setConfigStoreClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that provides a composite view of all stores.
|
||||
* Use this for components that need access to multiple store slices.
|
||||
*
|
||||
* For components that only need specific slices, import the individual
|
||||
* store hooks directly (e.g., useConnectionStore, useAgentStore).
|
||||
*/
|
||||
export function useCompositeStore() {
|
||||
// Subscribe to all stores
|
||||
const connectionState = useConnectionStore((s) => s.connectionState);
|
||||
const gatewayVersion = useConnectionStore((s) => s.gatewayVersion);
|
||||
const connectionError = useConnectionStore((s) => s.error);
|
||||
const logs = useConnectionStore((s) => s.logs);
|
||||
const localGateway = useConnectionStore((s) => s.localGateway);
|
||||
const localGatewayBusy = useConnectionStore((s) => s.localGatewayBusy);
|
||||
const isLoading = useConnectionStore((s) => s.isLoading);
|
||||
const client = useConnectionStore((s) => s.client);
|
||||
|
||||
const clones = useAgentStore((s) => s.clones);
|
||||
const usageStats = useAgentStore((s) => s.usageStats);
|
||||
const pluginStatus = useAgentStore((s) => s.pluginStatus);
|
||||
|
||||
const hands = useHandStore((s) => s.hands);
|
||||
const handRuns = useHandStore((s) => s.handRuns);
|
||||
const triggers = useHandStore((s) => s.triggers);
|
||||
const approvals = useHandStore((s) => s.approvals);
|
||||
|
||||
const workflows = useWorkflowStore((s) => s.workflows);
|
||||
const workflowRuns = useWorkflowStore((s) => s.workflowRuns);
|
||||
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
|
||||
const channels = useConfigStore((s) => s.channels);
|
||||
const scheduledTasks = useConfigStore((s) => s.scheduledTasks);
|
||||
const skillsCatalog = useConfigStore((s) => s.skillsCatalog);
|
||||
const models = useConfigStore((s) => s.models);
|
||||
const modelsLoading = useConfigStore((s) => s.modelsLoading);
|
||||
const modelsError = useConfigStore((s) => s.modelsError);
|
||||
|
||||
// Get all actions
|
||||
const connect = useConnectionStore((s) => s.connect);
|
||||
const disconnect = useConnectionStore((s) => s.disconnect);
|
||||
const clearLogs = useConnectionStore((s) => s.clearLogs);
|
||||
const refreshLocalGateway = useConnectionStore((s) => s.refreshLocalGateway);
|
||||
const startLocalGateway = useConnectionStore((s) => s.startLocalGateway);
|
||||
const stopLocalGateway = useConnectionStore((s) => s.stopLocalGateway);
|
||||
const restartLocalGateway = useConnectionStore((s) => s.restartLocalGateway);
|
||||
|
||||
const loadClones = useAgentStore((s) => s.loadClones);
|
||||
const createClone = useAgentStore((s) => s.createClone);
|
||||
const updateClone = useAgentStore((s) => s.updateClone);
|
||||
const deleteClone = useAgentStore((s) => s.deleteClone);
|
||||
const loadUsageStats = useAgentStore((s) => s.loadUsageStats);
|
||||
const loadPluginStatus = useAgentStore((s) => s.loadPluginStatus);
|
||||
|
||||
const loadHands = useHandStore((s) => s.loadHands);
|
||||
const getHandDetails = useHandStore((s) => s.getHandDetails);
|
||||
const triggerHand = useHandStore((s) => s.triggerHand);
|
||||
const loadHandRuns = useHandStore((s) => s.loadHandRuns);
|
||||
const loadTriggers = useHandStore((s) => s.loadTriggers);
|
||||
const createTrigger = useHandStore((s) => s.createTrigger);
|
||||
const deleteTrigger = useHandStore((s) => s.deleteTrigger);
|
||||
const loadApprovals = useHandStore((s) => s.loadApprovals);
|
||||
const approveRequest = useHandStore((s) => s.approveRequest);
|
||||
|
||||
const loadWorkflows = useWorkflowStore((s) => s.loadWorkflows);
|
||||
const getWorkflow = useWorkflowStore((s) => s.getWorkflow);
|
||||
const createWorkflow = useWorkflowStore((s) => s.createWorkflow);
|
||||
const updateWorkflow = useWorkflowStore((s) => s.updateWorkflow);
|
||||
const deleteWorkflow = useWorkflowStore((s) => s.deleteWorkflow);
|
||||
const triggerWorkflow = useWorkflowStore((s) => s.triggerWorkflow);
|
||||
const loadWorkflowRuns = useWorkflowStore((s) => s.loadWorkflowRuns);
|
||||
|
||||
const loadQuickConfig = useConfigStore((s) => s.loadQuickConfig);
|
||||
const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig);
|
||||
const loadWorkspaceInfo = useConfigStore((s) => s.loadWorkspaceInfo);
|
||||
const loadChannels = useConfigStore((s) => s.loadChannels);
|
||||
const getChannel = useConfigStore((s) => s.getChannel);
|
||||
const createChannel = useConfigStore((s) => s.createChannel);
|
||||
const updateChannel = useConfigStore((s) => s.updateChannel);
|
||||
const deleteChannel = useConfigStore((s) => s.deleteChannel);
|
||||
const loadScheduledTasks = useConfigStore((s) => s.loadScheduledTasks);
|
||||
const createScheduledTask = useConfigStore((s) => s.createScheduledTask);
|
||||
const loadSkillsCatalog = useConfigStore((s) => s.loadSkillsCatalog);
|
||||
const getSkill = useConfigStore((s) => s.getSkill);
|
||||
const createSkill = useConfigStore((s) => s.createSkill);
|
||||
const updateSkill = useConfigStore((s) => s.updateSkill);
|
||||
const deleteSkill = useConfigStore((s) => s.deleteSkill);
|
||||
const loadModels = useConfigStore((s) => s.loadModels);
|
||||
|
||||
// Memoize the composite store to prevent unnecessary re-renders
|
||||
return useMemo(() => ({
|
||||
// Connection state
|
||||
connectionState,
|
||||
gatewayVersion,
|
||||
error: connectionError,
|
||||
logs,
|
||||
localGateway,
|
||||
localGatewayBusy,
|
||||
isLoading,
|
||||
client,
|
||||
|
||||
// Agent state
|
||||
clones,
|
||||
usageStats,
|
||||
pluginStatus,
|
||||
|
||||
// Hand state
|
||||
hands,
|
||||
handRuns,
|
||||
triggers,
|
||||
approvals,
|
||||
|
||||
// Workflow state
|
||||
workflows,
|
||||
workflowRuns,
|
||||
|
||||
// Config state
|
||||
quickConfig,
|
||||
workspaceInfo,
|
||||
channels,
|
||||
scheduledTasks,
|
||||
skillsCatalog,
|
||||
models,
|
||||
modelsLoading,
|
||||
modelsError,
|
||||
|
||||
// Connection actions
|
||||
connect,
|
||||
disconnect,
|
||||
clearLogs,
|
||||
refreshLocalGateway,
|
||||
startLocalGateway,
|
||||
stopLocalGateway,
|
||||
restartLocalGateway,
|
||||
|
||||
// Agent actions
|
||||
loadClones,
|
||||
createClone,
|
||||
updateClone,
|
||||
deleteClone,
|
||||
loadUsageStats,
|
||||
loadPluginStatus,
|
||||
|
||||
// Hand actions
|
||||
loadHands,
|
||||
getHandDetails,
|
||||
triggerHand,
|
||||
loadHandRuns,
|
||||
loadTriggers,
|
||||
createTrigger,
|
||||
deleteTrigger,
|
||||
loadApprovals,
|
||||
approveRequest,
|
||||
|
||||
// Workflow actions
|
||||
loadWorkflows,
|
||||
getWorkflow,
|
||||
createWorkflow,
|
||||
updateWorkflow,
|
||||
deleteWorkflow,
|
||||
triggerWorkflow,
|
||||
loadWorkflowRuns,
|
||||
|
||||
// Config actions
|
||||
loadQuickConfig,
|
||||
saveQuickConfig,
|
||||
loadWorkspaceInfo,
|
||||
loadChannels,
|
||||
getChannel,
|
||||
createChannel,
|
||||
updateChannel,
|
||||
deleteChannel,
|
||||
loadScheduledTasks,
|
||||
createScheduledTask,
|
||||
loadSkillsCatalog,
|
||||
getSkill,
|
||||
createSkill,
|
||||
updateSkill,
|
||||
deleteSkill,
|
||||
loadModels,
|
||||
|
||||
// Legacy sendMessage (delegates to client)
|
||||
sendMessage: async (message: string, sessionKey?: string) => {
|
||||
return client.chat(message, { sessionKey });
|
||||
},
|
||||
}), [
|
||||
connectionState, gatewayVersion, connectionError, logs, localGateway, localGatewayBusy, isLoading, client,
|
||||
clones, usageStats, pluginStatus,
|
||||
hands, handRuns, triggers, approvals,
|
||||
workflows, workflowRuns,
|
||||
quickConfig, workspaceInfo, channels, scheduledTasks, skillsCatalog, models, modelsLoading, modelsError,
|
||||
connect, disconnect, clearLogs, refreshLocalGateway, startLocalGateway, stopLocalGateway, restartLocalGateway,
|
||||
loadClones, createClone, updateClone, deleteClone, loadUsageStats, loadPluginStatus,
|
||||
loadHands, getHandDetails, triggerHand, loadHandRuns, loadTriggers, createTrigger, deleteTrigger, loadApprovals, approveRequest,
|
||||
loadWorkflows, getWorkflow, createWorkflow, updateWorkflow, deleteWorkflow, triggerWorkflow, loadWorkflowRuns,
|
||||
loadQuickConfig, saveQuickConfig, loadWorkspaceInfo, loadChannels, getChannel, createChannel, updateChannel, deleteChannel,
|
||||
loadScheduledTasks, createScheduledTask, loadSkillsCatalog, getSkill, createSkill, updateSkill, deleteSkill, loadModels,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize stores on module load.
|
||||
* This ensures all stores have access to the shared client.
|
||||
*/
|
||||
if (typeof window !== 'undefined') {
|
||||
// Defer initialization to next tick to ensure all modules are loaded
|
||||
setTimeout(initializeStores, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user