FN-7936: alias @fusion/core to a runtime shim in bundled plugin outputs

Fix bundled example plugins (dependency-graph, grok-runtime, roadmap, acp-runtime, compound-engineering) crashing on enable with "Cannot find package '@fusion/core'" by aliasing the private import to a self-contained runtime shim during CLI bundling.

- packages/cli/tsup.config.ts: drop @fusion/core from bundlePluginEntry's external list and alias it to the existing pluginSdkCoreRuntimeShim so bundled.js no longer references the private workspace package at runtime
- packages/cli/src/__tests__/bundle-output.test.ts: add a regression test asserting every staged bundled plugin's bundled.js contains no bare @fusion/core import/reference
- docs/PLUGIN_AUTHORING.md: document that bundled.js outputs must be self-contained and must not leak private @fusion/* workspace imports
- .changeset/fn-7936-bundled-plugin-fusion-core-external.md: add a patch changeset for @runfusion/fusion describing the fix

Files changed:
 .changeset/fn-7936-bundled-plugin-fusion-core-external.md |  7 +++++
 docs/PLUGIN_AUTHORING.md                                  |  3 +++
 packages/cli/src/__tests__/bundle-output.test.ts          | 30 ++++++++++++++++++++++
 packages/cli/tsup.config.ts                               |  9 +++++--
 4 files changed, 47 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7936

Fusion-Task-Lineage: a8a391b2-9441-4a7c-92bc-f1675e1a8a0d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-13 07:32:50 -07:00
parent a81486559e
commit 281bb05161
4 changed files with 47 additions and 2 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Fix bundled example plugins failing to enable with a missing @fusion/core package error.
category: fix
dev: Aliases bundlePluginEntry @fusion/core imports to pluginSdkCoreRuntimeShim for self-contained bundled.js outputs.

View File

@@ -767,6 +767,9 @@ Bundled workspace plugin pattern:
- Register the lazy dashboard component in host code (currently `packages/dashboard/app/plugins/registerBundledPluginViews.ts`)
- CLI bundling inlines backend plugin code from workspace packages; dashboard view modules are imported by the dashboard build via the host registry
<!-- FNXC:BundledPlugins 2026-07-13-00:00: FN-7936 requires `@runfusion/fusion` bundled plugin backend outputs to be install-self-contained. The CLI bundler resolves plugin-sdk runtime re-exports from `@fusion/core` through `plugin-sdk-core-runtime-shim.ts`, so `packages/cli/dist/plugins/<id>/bundled.js` must not ship private `@fusion/*` runtime specifiers that npm installs cannot resolve. -->
Bundled `bundled.js` outputs must be self-contained at runtime. Do not leave private workspace package imports such as `@fusion/core` in emitted bundled plugin code; `@fusion/plugin-sdk` core runtime re-exports are resolved through the CLI runtime shim during packaging.
### Bundled plugin build-freshness guard
<!-- FNXC:BundledPlugins 2026-06-17-22:31: Bundled plugins can load gitignored compiled artifacts before source during workspace/dev resolution, so plugin authors need a documented recovery path when the generic freshness guard detects stale dist output. -->

View File

@@ -12,8 +12,16 @@ import {
} from "./bundle-output-helpers";
import { resolveClaudeCliExtensionFromModuleUrl } from "../commands/claude-cli-extension";
import { resolveDroidCliExtensionFromModuleUrl } from "../commands/droid-cli-extension";
import { RUNTIME_PLUGIN_IDS } from "../plugins/staged-bundled-plugin-ids";
const tsupConfigPath = join(cliRoot, "tsup.config.ts");
const bundlePluginEntryPluginIds = [
...RUNTIME_PLUGIN_IDS,
"fusion-plugin-dependency-graph",
"fusion-plugin-roadmap",
"fusion-plugin-compound-engineering",
"fusion-plugin-linear-import",
] as const;
describe("CLI bundle output", () => {
beforeAll(() => {
@@ -222,6 +230,28 @@ describe("CLI bundle output", () => {
expect(stagedPkg.dependencies?.["@fusion/core"]).toBeUndefined();
});
it("bundled plugin outputs do not import private @fusion/core at runtime", () => {
const inspectedPluginIds: string[] = [];
for (const pluginId of bundlePluginEntryPluginIds) {
const bundledPath = join(cliRoot, "dist", "plugins", pluginId, "bundled.js");
if (!existsSync(bundledPath)) {
continue;
}
inspectedPluginIds.push(pluginId);
const bundled = readFileSync(bundledPath, "utf-8");
expect(bundled, `${pluginId} should not keep a bare @fusion/core import`).not.toMatch(
/from\s+["']@fusion\/core["']/,
);
expect(bundled, `${pluginId} should not mention the private @fusion/core package`).not.toContain(
'"@fusion/core"',
);
}
expect(inspectedPluginIds.length).toBeGreaterThan(0);
});
it("dist/plugins/fusion-plugin-whatsapp-chat/ is staged with a valid manifest", () => {
const stagedRoot = join(cliRoot, "dist", "plugins", "fusion-plugin-whatsapp-chat");
const manifestPath = join(stagedRoot, "manifest.json");

View File

@@ -42,6 +42,7 @@ const compoundEngineeringPluginSrc = join(__dirname, "..", "..", "plugins", "fus
const compoundEngineeringPluginDest = join(__dirname, "dist", "plugins", "fusion-plugin-compound-engineering");
const linearImportPluginSrc = join(__dirname, "..", "..", "plugins", "fusion-plugin-linear-import");
const linearImportPluginDest = join(__dirname, "dist", "plugins", "fusion-plugin-linear-import");
const pluginSdkCoreRuntimeShim = join(__dirname, "src", "plugin-sdk-core-runtime-shim.ts");
const dashboardClientStub = `<!doctype html>
<html lang="en">
<head>
@@ -174,9 +175,14 @@ async function bundlePluginEntry({ pluginId, srcDir, destDir, withMcpAsset = fal
platform: "node",
target: "node22",
outfile: join(destDir, "bundled.js"),
external: ["@fusion/core", "@fusion/engine"],
external: ["@fusion/engine"],
alias: {
"@fusion/plugin-sdk": join(__dirname, "..", "plugin-sdk", "src", "index.ts"),
/*
* FNXC:BundledPlugins 2026-07-13-00:00:
* FN-7936 / issue #2059 requires every published bundled.js to be self-contained. The plugin-sdk source re-exports WORKFLOW_EXTENSION_SCHEMA_VERSION, workflowExtensionRegistryId, and createBoardActionServices from private @fusion/core; resolve those runtime values to the shared shim here so npm-installed bundled plugins never crash with Cannot find package '@fusion/core'.
*/
"@fusion/core": pluginSdkCoreRuntimeShim,
},
logLevel: "warning",
});
@@ -274,7 +280,6 @@ function assertAllStagedBundledPluginsLoadable() {
}
const pluginSdkEntry = join(__dirname, "..", "plugin-sdk", "src", "index.ts");
const pluginSdkCoreRuntimeShim = join(__dirname, "src", "plugin-sdk-core-runtime-shim.ts");
const cliBuildConfig = {
entry: ["src/bin.ts", "src/extension.ts"],