feat(FN-1400): add getPluginStore() lazy getter to TaskStore

- Add PluginStore lazy getter to TaskStore class
- Update memory documentation with plugin foundation learnings
This commit is contained in:
gsxdsm
2026-04-09 15:50:57 -07:00
parent ef9b4edd12
commit 4c01437134
2 changed files with 48 additions and 1 deletions

View File

@@ -38,7 +38,7 @@
- There are **34 unique color themes** in `packages/dashboard/app/styles.css` (ocean, forest, sunset, berry, monochrome, slate, ash, graphite, silver, zen, high-contrast, industrial, solarized, factory, ayu, one-dark, nord, dracula, gruvbox, tokyo-night, catppuccin-mocha, github-dark, everforest, rose-pine, kanagawa, night-owl, palenight, monokai-pro, slime, brutalist, neon-city, parchment, terminal, glass). Each has a dark variant `[data-color-theme="<name>"]` and a light variant `[data-color-theme="<name>"][data-theme="light"]`.
- When adding CSS custom properties that should be theme-aware (like `--accent`, `--status-*-bg`), add them to all 34 theme blocks plus `:root` and `[data-theme="light"]` base blocks. The test in `status-colors-theme.test.ts` iterates all blocks programmatically to prevent regressions.
## Plugin System (FN-1111)
## Plugin System (FN-1111 / FN-1400)
The plugin system is built on three layers:
1. **PluginStore** (`packages/core/src/plugin-store.ts`) — SQLite-backed CRUD operations for plugin installations, stored in the `plugins` table (schema v24)
@@ -158,3 +158,36 @@ The `create-fusion-plugin` skill teaches agents how to create Fusion plugins. Lo
- Tools: JSON Schema parameters, return `PluginToolResult`
- Routes: GET/POST/PUT/DELETE, mounted at `/api/plugins/{pluginId}/{path}`
- vitest.config.ts: use `pool: "threads"` (NOT `vmThreads`)
## FN-1400 Plugin Core Foundation
Key implementation details from the plugin core foundation task:
**Database Schema (v24)**:
- `plugins` table stores plugin metadata, path, enabled flag, state, settings (JSON), settingsSchema (JSON), error message
- Migration adds table via `applyMigration(24, ...)` in `db.ts`
- Schema version assertions in `db.test.ts` and `__tests__/task-documents.test.ts` must be updated to expect v24
**PluginStore patterns**:
- Lazy initialization pattern: `_db` starts null, initialized on first access via `get db()`
- EventEmitter for state change notifications: `plugin:registered`, `plugin:unregistered`, `plugin:enabled`, `plugin:disabled`, `plugin:updated`, `plugin:stateChanged`
- Settings validation against `settingsSchema` before persisting
- Deterministic state transitions enforced in `updatePluginState()`
**PluginLoader patterns**:
- Uses topological sort (`resolveLoadOrder()`) for deterministic load order based on dependencies
- Circular dependency detection throws Error during sort
- Error isolation: plugin failures set `state: "error"` in store but don't crash loader
- Hook invocation via `safeCallHook()` with try/catch per plugin
- `getPluginTools()` and `getPluginRoutes()` aggregate from successfully loaded plugins only
**TaskStore integration**:
- `getPluginStore()` lazy getter following the same pattern as `getMissionStore()`
- Import PluginStore at top of store.ts: `import { PluginStore } from "./plugin-store.js";`
- Private field: `private pluginStore: PluginStore | null = null;`
**Public exports** (from `@fusion/core`):
- Types: `PluginManifest`, `PluginSettingSchema`, `PluginOnLoad`, `PluginOnUnload`, `PluginOnTaskCreated`, `PluginOnTaskMoved`, `PluginOnTaskCompleted`, `PluginOnError`, `PluginToolDefinition`, `PluginToolResult`, `PluginRouteDefinition`, `PluginContext`, `PluginLogger`, `FusionPlugin`, `PluginState`, `PluginInstallation`
- Functions: `validatePluginManifest()`
- Classes: `PluginStore`, `PluginLoader`
- Interfaces: `PluginStoreEvents`, `PluginRegistrationInput`, `PluginUpdateInput`, `PluginLoaderOptions`

View File

@@ -10,6 +10,7 @@ import { GlobalSettingsStore } from "./global-settings.js";
import { Database, toJson, toJsonNullable, fromJson } from "./db.js";
import { detectLegacyData, migrateFromLegacy } from "./db-migrate.js";
import { MissionStore } from "./mission-store.js";
import { PluginStore } from "./plugin-store.js";
import { BackwardCompat, ProjectRequiredError } from "./migration.js";
import { CentralCore } from "./central-core.js";
import { getTaskMergeBlocker } from "./task-merge.js";
@@ -95,6 +96,8 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
}
/** Cached MissionStore instance */
private missionStore: MissionStore | null = null;
/** Cached PluginStore instance */
private pluginStore: PluginStore | null = null;
constructor(private rootDir: string, globalSettingsDir?: string) {
super();
@@ -3890,6 +3893,17 @@ ${notificationsSection}`;
return this.missionStore;
}
/**
* Get the PluginStore instance for plugin registry operations.
* Lazily initializes the PluginStore on first access.
*/
getPluginStore(): PluginStore {
if (!this.pluginStore) {
this.pluginStore = new PluginStore(this.rootDir);
}
return this.pluginStore;
}
// ── Backward Compatibility (Multi-Project Support) ────────────────────────
}