feat(electrobun): hierarchical state tree (Rule 58)
New files: - project-state.types.ts: all per-project state interfaces - project-state.svelte.ts: unified per-project state with version counter - app-state.svelte.ts: root facade re-exporting all stores as appState.* Rewired components (no more local $state): - ProjectCard: reads via appState.agent.* and appState.project.tab.* - TerminalTabs: state in appState.project.terminals.* - FileBrowser: state in appState.project.files.* - CommsTab: state in appState.project.comms.* - TaskBoardTab: state in appState.project.tasks.* All follow Rule 57 (no $derived with new objects) and Rule 58 (state tree architecture, components are pure renderers).
This commit is contained in:
parent
ae4c07c160
commit
162b5417e4
9 changed files with 870 additions and 400 deletions
190
ui-electrobun/src/mainview/app-state.svelte.ts
Normal file
190
ui-electrobun/src/mainview/app-state.svelte.ts
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/**
|
||||
* Root state tree — unified API surface for all application state.
|
||||
*
|
||||
* Components import `appState` and access sub-domains:
|
||||
* appState.ui.getSettingsOpen()
|
||||
* appState.project.getState(id)
|
||||
* appState.project.terminals.addTab(id)
|
||||
*
|
||||
* This file is a pure re-export facade. No new state lives here.
|
||||
*/
|
||||
|
||||
// ── UI store ──────────────────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
getSettingsOpen, setSettingsOpen, toggleSettings,
|
||||
getSettingsCategory, setSettingsCategory, openSettingsCategory,
|
||||
getPaletteOpen, setPaletteOpen, togglePalette,
|
||||
getSearchOpen, setSearchOpen, toggleSearch,
|
||||
getNotifDrawerOpen, setNotifDrawerOpen, toggleNotifDrawer,
|
||||
getShowWizard, setShowWizard, toggleWizard,
|
||||
getProjectToDelete, setProjectToDelete,
|
||||
getShowAddGroup, setShowAddGroup, toggleAddGroup,
|
||||
getNewGroupName, setNewGroupName, resetAddGroupForm,
|
||||
} from './ui-store.svelte.ts';
|
||||
|
||||
// ── Workspace store ───────────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
getProjects, setProjects, getGroups, setGroups,
|
||||
getActiveGroupId, setActiveGroup,
|
||||
getFilteredProjects, getTotalCostDerived, getTotalTokensDerived,
|
||||
getMountedGroupIds, getActiveGroup as getActiveGroupObj,
|
||||
addProject, addProjectFromWizard, deleteProject,
|
||||
cloneCountForProject, handleClone,
|
||||
addGroup, loadGroupsFromDb, loadProjectsFromDb, trackAllProjects,
|
||||
getTotalCost, getTotalTokens,
|
||||
} from './workspace-store.svelte.ts';
|
||||
|
||||
// ── Agent store ───────────────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
startAgent, stopAgent, sendPrompt,
|
||||
getSession, hasSession, clearSession,
|
||||
loadLastSession, purgeSession, purgeProjectSessions,
|
||||
setAgentToastFn, setRetentionConfig, loadRetentionConfig,
|
||||
type AgentSession, type AgentMessage, type AgentStatus,
|
||||
} from './agent-store.svelte.ts';
|
||||
|
||||
// ── Project state (per-project tree) ──────────────────────────────────────
|
||||
|
||||
import {
|
||||
getProjectState,
|
||||
getActiveTab, isTabActivated, setActiveTab,
|
||||
addTerminalTab, closeTerminalTab, activateTerminalTab, toggleTerminalExpanded,
|
||||
setFileState, setFileMulti, nextFileRequestToken, getFileRequestToken,
|
||||
setCommsState, setCommsMulti,
|
||||
setTaskState, setTaskMulti, nextTaskPollToken, getTaskPollToken,
|
||||
removeProject as removeProjectState,
|
||||
} from './project-state.svelte.ts';
|
||||
|
||||
// ── Health store ──────────────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
trackProject, recordActivity, recordToolDone,
|
||||
recordTokenSnapshot, setProjectStatus,
|
||||
getProjectHealth, getAttentionQueue, getHealthAggregates,
|
||||
getActiveTools, getToolHistogram,
|
||||
untrackProject, stopHealthTick,
|
||||
} from './health-store.svelte.ts';
|
||||
|
||||
// ── Notifications store ───────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
getNotifications, getNotifCount,
|
||||
addNotification, removeNotification, clearAll as clearNotifications,
|
||||
} from './notifications-store.svelte.ts';
|
||||
|
||||
// ── Blink store ───────────────────────────────────────────────────────────
|
||||
|
||||
import {
|
||||
getBlinkVisible, startBlink, stopBlink,
|
||||
} from './blink-store.svelte.ts';
|
||||
|
||||
// ── Theme store ───────────────────────────────────────────────────────────
|
||||
|
||||
import { themeStore } from './theme-store.svelte.ts';
|
||||
|
||||
// ── i18n ──────────────────────────────────────────────────────────────────
|
||||
|
||||
import { t, setLocale, getLocale, getDir } from './i18n.svelte.ts';
|
||||
|
||||
// ── Unified API ───────────────────────────────────────────────────────────
|
||||
|
||||
export const appState = {
|
||||
ui: {
|
||||
getSettingsOpen, setSettingsOpen, toggleSettings,
|
||||
getSettingsCategory, setSettingsCategory, openSettingsCategory,
|
||||
getPaletteOpen, setPaletteOpen, togglePalette,
|
||||
getSearchOpen, setSearchOpen, toggleSearch,
|
||||
getNotifDrawerOpen, setNotifDrawerOpen, toggleNotifDrawer,
|
||||
getShowWizard, setShowWizard, toggleWizard,
|
||||
getProjectToDelete, setProjectToDelete,
|
||||
getShowAddGroup, setShowAddGroup, toggleAddGroup,
|
||||
getNewGroupName, setNewGroupName, resetAddGroupForm,
|
||||
},
|
||||
|
||||
workspace: {
|
||||
getProjects, setProjects, getGroups, setGroups,
|
||||
getActiveGroupId, setActiveGroup,
|
||||
getFilteredProjects, getTotalCostDerived, getTotalTokensDerived,
|
||||
getMountedGroupIds, getActiveGroup: getActiveGroupObj,
|
||||
addProject, addProjectFromWizard, deleteProject,
|
||||
cloneCountForProject, handleClone,
|
||||
addGroup, loadGroupsFromDb, loadProjectsFromDb, trackAllProjects,
|
||||
getTotalCost, getTotalTokens,
|
||||
},
|
||||
|
||||
agent: {
|
||||
startAgent, stopAgent, sendPrompt,
|
||||
getSession, hasSession, clearSession,
|
||||
loadLastSession, purgeSession, purgeProjectSessions,
|
||||
setToastFn: setAgentToastFn,
|
||||
setRetentionConfig, loadRetentionConfig,
|
||||
},
|
||||
|
||||
project: {
|
||||
getState: getProjectState,
|
||||
removeState: removeProjectState,
|
||||
|
||||
tab: {
|
||||
getActiveTab, isTabActivated, setActiveTab,
|
||||
},
|
||||
|
||||
terminals: {
|
||||
addTab: addTerminalTab,
|
||||
closeTab: closeTerminalTab,
|
||||
activateTab: activateTerminalTab,
|
||||
toggleExpanded: toggleTerminalExpanded,
|
||||
},
|
||||
|
||||
files: {
|
||||
setState: setFileState,
|
||||
setMulti: setFileMulti,
|
||||
nextRequestToken: nextFileRequestToken,
|
||||
getRequestToken: getFileRequestToken,
|
||||
},
|
||||
|
||||
comms: {
|
||||
setState: setCommsState,
|
||||
setMulti: setCommsMulti,
|
||||
},
|
||||
|
||||
tasks: {
|
||||
setState: setTaskState,
|
||||
setMulti: setTaskMulti,
|
||||
nextPollToken: nextTaskPollToken,
|
||||
getPollToken: getTaskPollToken,
|
||||
},
|
||||
},
|
||||
|
||||
health: {
|
||||
trackProject, recordActivity, recordToolDone,
|
||||
recordTokenSnapshot, setProjectStatus,
|
||||
getProjectHealth, getAttentionQueue, getHealthAggregates,
|
||||
getActiveTools, getToolHistogram,
|
||||
untrackProject, stopHealthTick,
|
||||
},
|
||||
|
||||
notifications: {
|
||||
getAll: getNotifications, getCount: getNotifCount,
|
||||
add: addNotification, remove: removeNotification, clear: clearNotifications,
|
||||
},
|
||||
|
||||
blink: {
|
||||
getVisible: getBlinkVisible, start: startBlink, stop: stopBlink,
|
||||
},
|
||||
|
||||
theme: themeStore,
|
||||
|
||||
i18n: { t, setLocale, getLocale, getDir },
|
||||
} as const;
|
||||
|
||||
// Re-export types for convenience
|
||||
export type { AgentSession, AgentMessage, AgentStatus };
|
||||
export type {
|
||||
ProjectState, TermTab, TerminalState, FileState,
|
||||
CommsState, TaskState, TabState, DirEntry,
|
||||
Channel, ChannelMessage, CommsAgent, DM, ChannelMember, Task,
|
||||
ProjectTab,
|
||||
} from './project-state.types.ts';
|
||||
Loading…
Add table
Add a link
Reference in a new issue