fix(desktop): pin complete Pi runtime closure (#2439)

## Summary
- pin `pi-agent-core`, `pi-ai`, `pi-coding-agent`, and `pi-tui` to one
exact 0.82.0 workspace override set
- extend the Pi version policy guard to reject missing, ranged, or
mismatched desktop runtime closure overrides
- add a patch changeset for the legacy desktop packaging fix

## Test plan
- `node --test scripts/__tests__/check-pi-versions-pinned.test.mjs` (5
passed)
- `node scripts/check-pi-versions-pinned.mjs`
- `corepack pnpm check:changesets --strict`
- focused engine fixtures: 4 files / 47 tests passed
- GitHub: Desktop packaging, Lint, Typecheck, Build, Gate, and Greptile
Review passed
This commit is contained in:
Phil Larson
2026-07-26 07:34:50 -07:00
committed by GitHub
parent 4633c6441b
commit 0643a64f0d
5 changed files with 111 additions and 3 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Keep legacy desktop builds on one packageable Pi runtime dependency closure.
category: fix
dev: Pins pi-agent-core and pi-tui with the 0.82.0 Pi runtime pair and extends the dependency policy guard to workspace overrides.

2
pnpm-lock.yaml generated
View File

@@ -7,8 +7,10 @@ settings:
overrides:
'@types/node': ^25.5.2
protobufjs: ^7.5.8
'@earendil-works/pi-agent-core': 0.82.0
'@earendil-works/pi-ai': 0.82.0
'@earendil-works/pi-coding-agent': 0.82.0
'@earendil-works/pi-tui': 0.82.0
importers:

View File

@@ -25,8 +25,13 @@ overrides:
# to match guarded package manifests (cli/core/engine/dashboard/pi-claude-cli).
# FNXC:ModelCatalog 2026-07-24-12:00: FN-8564 advances the matched runtime pair
# to 0.82.0. Wildcard consumers must resolve the exact guarded Pi API surface.
# FNXC:DesktopPackaging 2026-07-25-17:15: Legacy `pnpm deploy` resolves pi-coding-agent's
# transitive ranges without the workspace lockfile. Pin the complete Pi runtime closure to one
# exact version so new agent-core or tui patches cannot split the packageable desktop tree.
'@earendil-works/pi-agent-core': 0.82.0
'@earendil-works/pi-ai': 0.82.0
'@earendil-works/pi-coding-agent': 0.82.0
'@earendil-works/pi-tui': 0.82.0
# FNXC:DesktopEmbeddedPostgres 2026-07-14-09:30:
# Desktop release jobs cross-build Intel and ARM64 artifacts on one host. Install
# optional native payloads for both CPU families on the current OS so each

View File

@@ -1,8 +1,10 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
PI_RUNTIME_PACKAGES,
scanTrackedManifests,
validateManifestSet,
validateWorkspaceOverrides,
} from "../check-pi-versions-pinned.mjs";
const pinnedManifest = {
@@ -42,4 +44,32 @@ describe("check-pi-versions-pinned", () => {
it("accepts a clean exact matched pair", () => {
assert.deepEqual(validate(pinnedManifest), []);
});
/*
FNXC:DesktopPackaging 2026-07-25-17:15:
Legacy desktop deploy resolves transitive pi-mono ranges without the workspace
lockfile. Guard every Pi runtime package in the staged closure, not only the
direct pi-ai and pi-coding-agent declarations, so a newly published patch
cannot split agent-core or tui from the exact runtime version.
*/
it("requires one exact workspace override for every staged Pi runtime package", () => {
const coherentOverrides = Object.fromEntries(PI_RUNTIME_PACKAGES.map((packageName) => [packageName, "0.82.0"]));
assert.deepEqual(validateWorkspaceOverrides(coherentOverrides), []);
assert.equal(
validateWorkspaceOverrides({ ...coherentOverrides, "@earendil-works/pi-tui": undefined })
.some((violation) => violation.includes("pi-tui") && violation.includes("must be pinned")),
true,
);
assert.equal(
validateWorkspaceOverrides({ ...coherentOverrides, "@earendil-works/pi-agent-core": "^0.82.0" })
.some((violation) => violation.includes("pi-agent-core") && violation.includes("exact semver")),
true,
);
assert.equal(
validateWorkspaceOverrides({ ...coherentOverrides, "@earendil-works/pi-tui": "0.82.1" })
.some((violation) => violation.includes("one exact version")),
true,
);
});
});

View File

@@ -9,12 +9,27 @@ manifest declaration must be an exact semver and all declarations must agree.
import { readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import { parse as parseYaml } from "yaml";
export const PI_DEPENDENCIES = [
"@earendil-works/pi-ai",
"@earendil-works/pi-coding-agent",
];
/*
FNXC:DesktopPackaging 2026-07-25-17:15:
The legacy desktop deploy resolves pi-coding-agent's transitive pi-mono ranges
without the workspace lockfile. Keep every Pi package in that staged runtime
closure on one exact override so a new agent-core or tui patch cannot be hoisted
beside older direct ai/coding-agent dependencies.
*/
export const PI_RUNTIME_PACKAGES = [
"@earendil-works/pi-agent-core",
"@earendil-works/pi-ai",
"@earendil-works/pi-coding-agent",
"@earendil-works/pi-tui",
];
export const GUARDED_MANIFESTS = [
"packages/cli/package.json",
"packages/core/package.json",
@@ -30,6 +45,31 @@ export function isExactSemver(version) {
return typeof version === "string" && EXACT_SEMVER.test(version);
}
export function validateWorkspaceOverrides(overrides = {}) {
const violations = [];
const versions = [];
for (const packageName of PI_RUNTIME_PACKAGES) {
const version = overrides?.[packageName];
if (version === undefined) {
violations.push(`pnpm-workspace.yaml: overrides.${packageName} must be pinned for the staged desktop closure`);
continue;
}
if (!isExactSemver(version)) {
violations.push(`pnpm-workspace.yaml: overrides.${packageName} must be an exact semver, found ${JSON.stringify(version)}`);
continue;
}
versions.push(version);
}
const uniqueVersions = [...new Set(versions)];
if (uniqueVersions.length > 1) {
violations.push(`${PI_RUNTIME_PACKAGES.join(", ")} must use one exact version in pnpm-workspace.yaml overrides; found ${uniqueVersions.join(", ")}`);
}
return violations;
}
function listTrackedManifests() {
const result = spawnSync("git", ["ls-files", "--", ...GUARDED_MANIFESTS], {
encoding: "utf8",
@@ -99,13 +139,37 @@ export function scanTrackedManifests(files = listTrackedManifests(), options = {
return [`${filePath}: invalid JSON (${error instanceof Error ? error.message : String(error)})`];
}
}
return validateManifestSet(manifests);
const violations = validateManifestSet(manifests);
let workspaceConfig;
try {
workspaceConfig = parseYaml(readFile("pnpm-workspace.yaml", "utf8"));
} catch (error) {
return [...violations, `pnpm-workspace.yaml: invalid YAML (${error instanceof Error ? error.message : String(error)})`];
}
const workspaceOverrides = workspaceConfig?.overrides ?? {};
violations.push(...validateWorkspaceOverrides(workspaceOverrides));
const manifestVersions = new Set(
manifests.flatMap(({ manifest }) =>
DEPENDENCY_BLOCKS.flatMap((blockName) =>
PI_DEPENDENCIES.map((packageName) => manifest?.[blockName]?.[packageName]).filter(isExactSemver),
),
),
);
const overrideVersions = new Set(PI_RUNTIME_PACKAGES.map((packageName) => workspaceOverrides[packageName]).filter(isExactSemver));
const allRuntimeVersions = [...new Set([...manifestVersions, ...overrideVersions])];
if (allRuntimeVersions.length > 1) {
violations.push(`guarded Pi manifests and workspace overrides must use one exact runtime version; found ${allRuntimeVersions.join(", ")}`);
}
return violations;
}
export function formatFailureMessage(violations) {
return [
"[check-pi-versions-pinned] pi runtime dependencies must be exact, matched versions.",
"npm global installs do not use pnpm-lock.yaml; ranges can resolve an incompatible pi-mono patch set.",
"[check-pi-versions-pinned] Pi runtime dependencies and workspace overrides must be exact, matched versions.",
"npm global installs and legacy desktop deploy do not reliably use pnpm-lock.yaml; ranges can resolve an incompatible pi-mono patch set.",
...violations.map((violation) => `- ${violation}`),
].join("\n");
}