FN-6410: fix standalone pi runtime deps
Keep published CLI standalone installs from omitting the pi runtime packages.\n\n- Remove pi runtime packages from optional peer declarations so npm and pnpm install them as required dependencies.\n- Add a package manifest regression test for source and prepack-transformed publish manifests.\n- Add a patch changeset for the published CLI package.\n\nFiles changed:\n .changeset/fn-6410-standalone-pi-dependency.md | 5 +++\n packages/cli/package.json | 8 ----\n packages/cli/src/__tests__/package-config.test.ts | 47 +++++++++++++++++++++++\n 3 files changed, 52 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-6410 Fusion-Task-Lineage: 579c8a91-a021-4b36-94d7-e4651ce241cb
This commit is contained in:
5
.changeset/fn-6410-standalone-pi-dependency.md
Normal file
5
.changeset/fn-6410-standalone-pi-dependency.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
Fix standalone installs of the published CLI crashing with `ERR_MODULE_NOT_FOUND` for `@earendil-works/pi-coding-agent`. `@earendil-works/pi-coding-agent` and `@earendil-works/pi-ai` are now plain required dependencies instead of also being optional peers, so clean npm and pnpm installs resolve the pi runtime packages.
|
||||
@@ -74,17 +74,9 @@
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@earendil-works/pi-ai": "*",
|
||||
"@earendil-works/pi-coding-agent": "*",
|
||||
"typebox": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@earendil-works/pi-ai": {
|
||||
"optional": true
|
||||
},
|
||||
"@earendil-works/pi-coding-agent": {
|
||||
"optional": true
|
||||
},
|
||||
"typebox": {
|
||||
"optional": true
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { builtinModules } from "node:module";
|
||||
import { parse } from "yaml";
|
||||
import { applyPrepackTransform } from "../../scripts/prepare-publish-manifest.mjs";
|
||||
|
||||
const workspaceRoot = join(__dirname, "..", "..", "..", "..");
|
||||
|
||||
@@ -32,6 +33,43 @@ function hasProjectArg(script: string | undefined, project: string): boolean {
|
||||
return parts.some((part, index) => part === "--project" && parts[index + 1] === project);
|
||||
}
|
||||
|
||||
function assertRuntimeDepsAreNotOptionalPeers(pkg: any, label: string): void {
|
||||
const dependencies = pkg.dependencies ?? {};
|
||||
const peerDependencies = pkg.peerDependencies ?? {};
|
||||
const peerDependenciesMeta = pkg.peerDependenciesMeta ?? {};
|
||||
|
||||
for (const dependencyName of Object.keys(dependencies)) {
|
||||
expect(
|
||||
peerDependenciesMeta[dependencyName]?.optional,
|
||||
`${label}: runtime dependency "${dependencyName}" must not also be an optional peer; npm/pnpm may omit it from clean standalone installs.`,
|
||||
).not.toBe(true);
|
||||
}
|
||||
|
||||
for (const dependencyName of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai"]) {
|
||||
expect(dependencies, `${label}: ${dependencyName} must remain a required runtime dependency`).toHaveProperty(
|
||||
dependencyName,
|
||||
"^0.79.1",
|
||||
);
|
||||
expect(peerDependencies, `${label}: ${dependencyName} must not be a peer dependency`).not.toHaveProperty(
|
||||
dependencyName,
|
||||
);
|
||||
expect(peerDependenciesMeta, `${label}: ${dependencyName} must not have peer metadata`).not.toHaveProperty(
|
||||
dependencyName,
|
||||
);
|
||||
}
|
||||
|
||||
expect(dependencies, `${label}: typebox must not be promoted into runtime dependencies`).not.toHaveProperty(
|
||||
"typebox",
|
||||
);
|
||||
expect(peerDependencies, `${label}: typebox remains the optional peer control`).toHaveProperty(
|
||||
"typebox",
|
||||
"*",
|
||||
);
|
||||
expect(peerDependenciesMeta.typebox, `${label}: typebox remains optional peer metadata`).toEqual({
|
||||
optional: true,
|
||||
});
|
||||
}
|
||||
|
||||
describe("CLI package.json publishing config", () => {
|
||||
const pkg = loadPackageJson("cli");
|
||||
const prepackScript = loadCliPrepackScript();
|
||||
@@ -93,6 +131,15 @@ describe("CLI package.json publishing config", () => {
|
||||
expect(deps).toContain("ioredis");
|
||||
});
|
||||
|
||||
/**
|
||||
* FNXC:Packaging 2026-06-13-16:36:
|
||||
* Standalone npm/pnpm installs may omit a package when the published manifest declares it as both a runtime dependency and an optional peer. Keep the pi runtime packages as plain dependencies so dist/bin.js and dist/extension.js can resolve their static imports outside the monorepo, while leaving typebox as the optional-peer control because Fusion does not import it at runtime.
|
||||
*/
|
||||
it("does not declare runtime dependencies as optional peers in source or published manifests", () => {
|
||||
assertRuntimeDepsAreNotOptionalPeers(pkg, "source manifest");
|
||||
assertRuntimeDepsAreNotOptionalPeers(applyPrepackTransform(pkg), "published manifest");
|
||||
});
|
||||
|
||||
it("defines test:docs-index as a single-file docs README index lane", () => {
|
||||
const script = pkg.scripts?.["test:docs-index"];
|
||||
const parts = script?.trim().split(/\s+/) ?? [];
|
||||
|
||||
Reference in New Issue
Block a user