diff --git a/.changeset/compound-engineering-plugin-scaffold.md b/.changeset/compound-engineering-plugin-scaffold.md new file mode 100644 index 0000000000..e28d171a36 --- /dev/null +++ b/.changeset/compound-engineering-plugin-scaffold.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": minor +--- + +Add the Compound Engineering bundled plugin (scaffold): a dedicated dashboard surface for compound-engineering artifacts and interactive ce-* sessions. diff --git a/packages/cli/src/plugins/__tests__/bundled-plugin-install.test.ts b/packages/cli/src/plugins/__tests__/bundled-plugin-install.test.ts index 9b6dbc0de2..90887da9af 100644 --- a/packages/cli/src/plugins/__tests__/bundled-plugin-install.test.ts +++ b/packages/cli/src/plugins/__tests__/bundled-plugin-install.test.ts @@ -44,6 +44,7 @@ const CURSOR_PLUGIN_ID = "fusion-plugin-cursor-runtime"; const ROADMAP_PLUGIN_ID = "fusion-plugin-roadmap"; const REPORTS_PLUGIN_ID = "fusion-plugin-reports"; const CLI_PRINTING_PRESS_PLUGIN_ID = "fusion-plugin-cli-printing-press"; +const COMPOUND_ENGINEERING_PLUGIN_ID = "fusion-plugin-compound-engineering"; function makeManifest(overrides?: Partial<{ id: string; version: string; name: string }>) { return { @@ -315,6 +316,10 @@ describe("ensureBundledDependencyGraphPluginInstalled", () => { it("includes reports plugin in bundled plugin ids", () => { expect(BUNDLED_PLUGIN_IDS).toContain(REPORTS_PLUGIN_ID); }); + + it("includes compound engineering plugin in bundled plugin ids", () => { + expect(BUNDLED_PLUGIN_IDS).toContain(COMPOUND_ENGINEERING_PLUGIN_ID); + }); it("fresh install: registers and loads the plugin when not in DB", async () => { setupBundleExists(); const store = makePluginStore(); diff --git a/packages/cli/src/plugins/bundled-plugin-install.ts b/packages/cli/src/plugins/bundled-plugin-install.ts index 506235bc9f..7ddf24a102 100644 --- a/packages/cli/src/plugins/bundled-plugin-install.ts +++ b/packages/cli/src/plugins/bundled-plugin-install.ts @@ -17,6 +17,7 @@ export const BUNDLED_PLUGIN_IDS = [ "fusion-plugin-paperclip-runtime", "fusion-plugin-cursor-runtime", "fusion-plugin-cli-printing-press", + "fusion-plugin-compound-engineering", ] as const; export type BundledPluginId = (typeof BUNDLED_PLUGIN_IDS)[number]; diff --git a/plugins/fusion-plugin-compound-engineering/manifest.json b/plugins/fusion-plugin-compound-engineering/manifest.json new file mode 100644 index 0000000000..dc53db3c6b --- /dev/null +++ b/plugins/fusion-plugin-compound-engineering/manifest.json @@ -0,0 +1,18 @@ +{ + "id": "fusion-plugin-compound-engineering", + "name": "Compound Engineering", + "version": "0.1.0", + "description": "A dedicated dashboard surface for compound-engineering artifacts and interactive ce-* sessions.", + "author": "Fusion Team", + "fusionVersion": ">=0.1.0", + "dashboardViews": [ + { + "viewId": "compound-engineering", + "label": "Compound Engineering", + "componentPath": "./dashboard-view", + "icon": "Sparkles", + "placement": "primary", + "order": 36 + } + ] +} diff --git a/plugins/fusion-plugin-compound-engineering/package.json b/plugins/fusion-plugin-compound-engineering/package.json new file mode 100644 index 0000000000..80b2b8e082 --- /dev/null +++ b/plugins/fusion-plugin-compound-engineering/package.json @@ -0,0 +1,38 @@ +{ + "name": "@fusion-plugin-examples/compound-engineering", + "version": "0.1.0", + "type": "module", + "description": "Compound Engineering plugin for Fusion", + "private": true, + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts" + }, + "./dashboard-view": { + "types": "./src/dashboard-view.tsx", + "import": "./src/dashboard-view.tsx" + } + }, + "scripts": { + "build": "tsc", + "test": "vitest run --silent=passed-only --reporter=dot" + }, + "dependencies": { + "@fusion/core": "workspace:*", + "@fusion/dashboard": "workspace:*", + "@fusion/plugin-sdk": "workspace:*", + "lucide-react": "^0.542.0", + "react": "^19.0.0", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/react": "^19.0.0", + "@types/node": "^25.5.2", + "typescript": "^5.7.0", + "vitest": "^3.2.4" + } +} diff --git a/plugins/fusion-plugin-compound-engineering/src/__tests__/manifest.test.ts b/plugins/fusion-plugin-compound-engineering/src/__tests__/manifest.test.ts new file mode 100644 index 0000000000..6cbb2bcd0a --- /dev/null +++ b/plugins/fusion-plugin-compound-engineering/src/__tests__/manifest.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "vitest"; +import manifest from "../../manifest.json"; +import plugin from "../index.js"; + +describe("compound engineering plugin manifest", () => { + it("exports expected plugin id", () => { + expect(plugin.manifest.id).toBe("fusion-plugin-compound-engineering"); + }); + + it("keeps runtime manifest metadata aligned with manifest.json", () => { + expect(plugin.manifest.id).toBe(manifest.id); + expect(plugin.manifest.name).toBe(manifest.name); + expect(plugin.manifest.version).toBe(manifest.version); + expect(plugin.manifest.description).toBe(manifest.description); + expect(plugin.manifest.author).toBe(manifest.author); + expect(plugin.manifest.fusionVersion).toBe(manifest.fusionVersion); + }); + + it("registers a single dashboard view", () => { + expect(plugin.dashboardViews).toEqual([ + { + viewId: "compound-engineering", + label: "Compound Engineering", + componentPath: "./dashboard-view", + icon: "Sparkles", + placement: "primary", + order: 36, + }, + ]); + expect(manifest.dashboardViews).toEqual(plugin.dashboardViews); + }); + + it("ships an empty hooks/routes scaffold (U1)", () => { + expect(plugin.hooks).toEqual({}); + expect(plugin.routes).toEqual([]); + }); +}); diff --git a/plugins/fusion-plugin-compound-engineering/src/dashboard-view.tsx b/plugins/fusion-plugin-compound-engineering/src/dashboard-view.tsx new file mode 100644 index 0000000000..49af3fee7f --- /dev/null +++ b/plugins/fusion-plugin-compound-engineering/src/dashboard-view.tsx @@ -0,0 +1,13 @@ +import type { PluginDashboardViewContext } from "@fusion/dashboard/app/plugins/types"; + +/** + * Placeholder dashboard surface for the Compound Engineering plugin. + * + * U1 ships only a loadable scaffold. The real artifact hub and interactive + * ce-* session surface arrive in later units (U3+). + */ +export function CompoundEngineeringDashboardView(_props: { context?: PluginDashboardViewContext }) { + return