Release v0.74.2

Fixes #4876
This commit is contained in:
Mario Zechner
2026-05-22 00:18:08 +02:00
Unverified
parent 2c708492e3
commit 8b57630bc9
17 changed files with 140 additions and 61 deletions
+11 -11
View File
@@ -7772,10 +7772,10 @@
},
"packages/agent": {
"name": "@earendil-works/pi-agent-core",
"version": "0.74.1",
"version": "0.74.2",
"license": "MIT",
"dependencies": {
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.2",
"ignore": "^7.0.5",
"typebox": "^1.1.24",
"yaml": "^2.8.2"
@@ -7809,7 +7809,7 @@
},
"packages/ai": {
"name": "@earendil-works/pi-ai",
"version": "0.74.1",
"version": "0.74.2",
"license": "MIT",
"dependencies": {
"@anthropic-ai/sdk": "^0.91.1",
@@ -7853,12 +7853,12 @@
},
"packages/coding-agent": {
"name": "@earendil-works/pi-coding-agent",
"version": "0.74.1",
"version": "0.74.2",
"license": "MIT",
"dependencies": {
"@earendil-works/pi-agent-core": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-tui": "^0.74.1",
"@earendil-works/pi-agent-core": "^0.74.2",
"@earendil-works/pi-ai": "^0.74.2",
"@earendil-works/pi-tui": "^0.74.2",
"@silvia-odwyer/photon-node": "^0.3.4",
"chalk": "^5.5.0",
"diff": "^8.0.2",
@@ -7949,7 +7949,7 @@
},
"packages/tui": {
"name": "@earendil-works/pi-tui",
"version": "0.74.1",
"version": "0.74.2",
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.3.0",
@@ -7969,11 +7969,11 @@
},
"packages/web-ui": {
"name": "@earendil-works/pi-web-ui",
"version": "0.74.1",
"version": "0.74.2",
"license": "MIT",
"dependencies": {
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-tui": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.2",
"@earendil-works/pi-tui": "^0.74.2",
"@lmstudio/sdk": "^1.5.0",
"docx-preview": "^0.3.7",
"jszip": "^3.10.1",
+2
View File
@@ -1,5 +1,7 @@
# Changelog
## [0.74.2] - 2026-05-21
## [0.74.1] - 2026-05-16
## [0.74.0] - 2026-05-07
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@earendil-works/pi-agent-core",
"version": "0.74.1",
"version": "0.74.2",
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
"type": "module",
"main": "./dist/index.js",
@@ -30,7 +30,7 @@
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.2",
"ignore": "^7.0.5",
"typebox": "^1.1.24",
"yaml": "^2.8.2"
+2
View File
@@ -1,5 +1,7 @@
# Changelog
## [0.74.2] - 2026-05-21
## [0.74.1] - 2026-05-16
### Added
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@earendil-works/pi-ai",
"version": "0.74.1",
"version": "0.74.2",
"description": "Unified LLM API with automatic model discovery and provider configuration",
"type": "module",
"main": "./dist/index.js",
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## [0.74.2] - 2026-05-21
### Fixed
- Fixed `pi update` on Node 20 to explain that newer Pi releases require Node >= 22.19.0 instead of reporting a successful no-op update ([#4876](https://github.com/earendil-works/pi/issues/4876)).
- Changed self-update package-manager commands to pass `--ignore-scripts`.
## [0.74.1] - 2026-05-16
### New Features
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@earendil-works/pi-coding-agent",
"version": "0.74.1",
"version": "0.74.2",
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
"type": "module",
"piConfig": {
@@ -38,9 +38,9 @@
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
"@earendil-works/pi-agent-core": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-tui": "^0.74.1",
"@earendil-works/pi-agent-core": "^0.74.2",
"@earendil-works/pi-ai": "^0.74.2",
"@earendil-works/pi-tui": "^0.74.2",
"@silvia-odwyer/photon-node": "^0.3.4",
"chalk": "^5.5.0",
"diff": "^8.0.2",
+10 -4
View File
@@ -111,21 +111,21 @@ function getSelfUpdateCommandForMethod(
return undefined;
case "pnpm":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("pnpm", ["install", "-g", updatePackageName]),
makeSelfUpdateCommandStep("pnpm", ["install", "-g", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("pnpm", ["remove", "-g", installedPackageName]),
);
case "yarn":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("yarn", ["global", "add", updatePackageName]),
makeSelfUpdateCommandStep("yarn", ["global", "add", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("yarn", ["global", "remove", installedPackageName]),
);
case "bun":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("bun", ["install", "-g", updatePackageName]),
makeSelfUpdateCommandStep("bun", ["install", "-g", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("bun", ["uninstall", "-g", installedPackageName]),
@@ -134,7 +134,13 @@ function getSelfUpdateCommandForMethod(
const [command = "npm", ...npmArgs] = npmCommand ?? [];
const inferred = npmCommand?.length ? undefined : getInferredNpmInstall();
const prefixArgs = [...npmArgs, ...(inferred ? ["--prefix", inferred.prefix] : [])];
const installStep = makeSelfUpdateCommandStep(command, [...prefixArgs, "install", "-g", updatePackageName]);
const installStep = makeSelfUpdateCommandStep(command, [
...prefixArgs,
"install",
"-g",
"--ignore-scripts",
updatePackageName,
]);
const uninstallStep =
updatePackageName === installedPackageName
? undefined
@@ -91,7 +91,11 @@ import { getCwdRelativePath } from "../../utils/paths.js";
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
import { killTrackedDetachedChildren } from "../../utils/shell.js";
import { ensureTool } from "../../utils/tools-manager.js";
import { checkForNewPiVersion } from "../../utils/version-check.js";
import {
checkForNewPiVersion,
getLatestPiNodeRequirementMessage,
isCurrentNodeVersionSupportedByLatestPi,
} from "../../utils/version-check.js";
import { ArminComponent } from "./components/armin.js";
import { AssistantMessageComponent } from "./components/assistant-message.js";
import { BashExecutionComponent } from "./components/bash-execution.js";
@@ -3568,8 +3572,14 @@ export class InteractiveMode {
}
showNewVersionNotification(newVersion: string): void {
const nodeVersionSupported = isCurrentNodeVersionSupportedByLatestPi();
const action = theme.fg("accent", `${APP_NAME} update`);
const updateInstruction = theme.fg("muted", `New version ${newVersion} is available. Run `) + action;
const updateInstruction = nodeVersionSupported
? theme.fg("muted", `New version ${newVersion} is available. Run `) + action
: theme.fg(
"muted",
`New version ${newVersion} is available. ${getLatestPiNodeRequirementMessage(`${APP_NAME} update`)}`,
);
const changelogUrl = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md";
const changelogLink = getCapabilities().hyperlinks
? hyperlink(theme.fg("accent", "open changelog"), changelogUrl)
@@ -3578,12 +3588,9 @@ export class InteractiveMode {
this.chatContainer.addChild(new Spacer(1));
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
const title = nodeVersionSupported ? "Update Available" : "Update Requires Newer Node";
this.chatContainer.addChild(
new Text(
`${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction}\n${changelogLine}`,
1,
0,
),
new Text(`${theme.bold(theme.fg("warning", title))}\n${updateInstruction}\n${changelogLine}`, 1, 0),
);
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
this.ui.requestRender();
@@ -13,7 +13,12 @@ import {
import { DefaultPackageManager } from "./core/package-manager.js";
import { SettingsManager } from "./core/settings-manager.js";
import { shouldUseWindowsShell } from "./utils/child-process.js";
import { getLatestPiRelease, isNewerPackageVersion } from "./utils/version-check.js";
import {
getLatestPiNodeRequirementMessage,
getLatestPiRelease,
isCurrentNodeVersionSupportedByLatestPi,
isNewerPackageVersion,
} from "./utils/version-check.js";
export type PackageCommand = "install" | "remove" | "update" | "list";
@@ -490,6 +495,11 @@ export async function handlePackageCommand(args: string[]): Promise<boolean> {
if (!selfUpdatePlan.shouldRun) {
return true;
}
if (!isCurrentNodeVersionSupportedByLatestPi()) {
console.error(chalk.yellow(getLatestPiNodeRequirementMessage(`${APP_NAME} update --self`)));
process.exitCode = 1;
return true;
}
const selfUpdateCommand = getSelfUpdateCommand(
PACKAGE_NAME,
selfUpdateNpmCommand,
@@ -3,6 +3,8 @@ import { getPiUserAgent } from "./pi-user-agent.js";
const LATEST_VERSION_URL = "https://pi.dev/api/latest-version";
const DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;
export const MINIMUM_NODE_VERSION_FOR_LATEST_PI = "22.19.0";
export interface LatestPiRelease {
version: string;
packageName?: string;
@@ -52,6 +54,22 @@ export function isNewerPackageVersion(candidateVersion: string, currentVersion:
return candidateVersion.trim() !== currentVersion.trim();
}
export function isNodeVersionAtLeast(version: string, minimumVersion: string): boolean {
const comparison = comparePackageVersions(version, minimumVersion);
if (comparison === undefined) {
return false;
}
return comparison >= 0;
}
export function isCurrentNodeVersionSupportedByLatestPi(): boolean {
return isNodeVersionAtLeast(process.versions.node, MINIMUM_NODE_VERSION_FOR_LATEST_PI);
}
export function getLatestPiNodeRequirementMessage(updateCommand: string): string {
return `Pi 0.75.0 and newer require Node >= ${MINIMUM_NODE_VERSION_FOR_LATEST_PI}. Current Node is ${process.version}. Update Node, then run ${updateCommand} again.`;
}
export async function getLatestPiRelease(
currentVersion: string,
options: { timeoutMs?: number } = {},
+35 -26
View File
@@ -147,7 +147,7 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("pnpm");
expect(getUpdateInstruction("@earendil-works/pi-coding-agent")).toBe(
"Run: pnpm install -g @earendil-works/pi-coding-agent",
"Run: pnpm install -g --ignore-scripts @earendil-works/pi-coding-agent",
);
});
@@ -169,8 +169,8 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("npm");
expect(command).toEqual({
command: "npm",
args: ["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"],
display: `npm --prefix ${prefix} install -g @earendil-works/pi-coding-agent`,
args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"],
display: `npm --prefix ${prefix} install -g --ignore-scripts @earendil-works/pi-coding-agent`,
});
});
@@ -181,8 +181,8 @@ describe("detectInstallMethod", () => {
expect(command).toEqual({
command: "npm",
args: ["--prefix", prefix, "install", "-g", "@new-scope/pi"],
display: `npm --prefix ${prefix} uninstall -g @mariozechner/pi-coding-agent && npm --prefix ${prefix} install -g @new-scope/pi`,
args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: `npm --prefix ${prefix} uninstall -g @mariozechner/pi-coding-agent && npm --prefix ${prefix} install -g --ignore-scripts @new-scope/pi`,
steps: [
{
command: "npm",
@@ -191,8 +191,8 @@ describe("detectInstallMethod", () => {
},
{
command: "npm",
args: ["--prefix", prefix, "install", "-g", "@new-scope/pi"],
display: `npm --prefix ${prefix} install -g @new-scope/pi`,
args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: `npm --prefix ${prefix} install -g --ignore-scripts @new-scope/pi`,
},
],
});
@@ -205,8 +205,8 @@ describe("detectInstallMethod", () => {
expect(command).toEqual({
command: "npm",
args: ["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"],
display: `npm --prefix ${prefix} install -g @earendil-works/pi-coding-agent`,
args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"],
display: `npm --prefix ${prefix} install -g --ignore-scripts @earendil-works/pi-coding-agent`,
});
});
@@ -215,7 +215,14 @@ describe("detectInstallMethod", () => {
const command = getSelfUpdateCommand("@earendil-works/pi-coding-agent", []);
expect(command?.args).toEqual(["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"]);
expect(command?.args).toEqual([
"--prefix",
prefix,
"install",
"-g",
"--ignore-scripts",
"@earendil-works/pi-coding-agent",
]);
});
test("quotes npm self-update display paths", () => {
@@ -223,7 +230,9 @@ describe("detectInstallMethod", () => {
const command = getSelfUpdateCommand("@earendil-works/pi-coding-agent");
expect(command?.display).toBe(`npm --prefix "${prefix}" install -g @earendil-works/pi-coding-agent`);
expect(command?.display).toBe(
`npm --prefix "${prefix}" install -g --ignore-scripts @earendil-works/pi-coding-agent`,
);
});
test("does not infer Windows npm custom prefixes from package paths", () => {
@@ -233,7 +242,7 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("npm");
expect(getUpdateInstruction("@earendil-works/pi-coding-agent")).toBe(
"Run: npm install -g @earendil-works/pi-coding-agent",
"Run: npm install -g --ignore-scripts @earendil-works/pi-coding-agent",
);
});
@@ -245,8 +254,8 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("bun");
expect(command).toEqual({
command: "bun",
args: ["install", "-g", "@earendil-works/pi-coding-agent"],
display: "bun install -g @earendil-works/pi-coding-agent",
args: ["install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"],
display: "bun install -g --ignore-scripts @earendil-works/pi-coding-agent",
});
});
@@ -258,8 +267,8 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("pnpm");
expect(command).toEqual({
command: "pnpm",
args: ["install", "-g", "@new-scope/pi"],
display: "pnpm remove -g @mariozechner/pi-coding-agent && pnpm install -g @new-scope/pi",
args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: "pnpm remove -g @mariozechner/pi-coding-agent && pnpm install -g --ignore-scripts @new-scope/pi",
steps: [
{
command: "pnpm",
@@ -268,8 +277,8 @@ describe("detectInstallMethod", () => {
},
{
command: "pnpm",
args: ["install", "-g", "@new-scope/pi"],
display: "pnpm install -g @new-scope/pi",
args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: "pnpm install -g --ignore-scripts @new-scope/pi",
},
],
});
@@ -283,8 +292,8 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("yarn");
expect(command).toEqual({
command: "yarn",
args: ["global", "add", "@new-scope/pi"],
display: "yarn global remove @mariozechner/pi-coding-agent && yarn global add @new-scope/pi",
args: ["global", "add", "--ignore-scripts", "@new-scope/pi"],
display: "yarn global remove @mariozechner/pi-coding-agent && yarn global add --ignore-scripts @new-scope/pi",
steps: [
{
command: "yarn",
@@ -293,8 +302,8 @@ describe("detectInstallMethod", () => {
},
{
command: "yarn",
args: ["global", "add", "@new-scope/pi"],
display: "yarn global add @new-scope/pi",
args: ["global", "add", "--ignore-scripts", "@new-scope/pi"],
display: "yarn global add --ignore-scripts @new-scope/pi",
},
],
});
@@ -308,8 +317,8 @@ describe("detectInstallMethod", () => {
expect(detectInstallMethod()).toBe("bun");
expect(command).toEqual({
command: "bun",
args: ["install", "-g", "@new-scope/pi"],
display: "bun uninstall -g @mariozechner/pi-coding-agent && bun install -g @new-scope/pi",
args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: "bun uninstall -g @mariozechner/pi-coding-agent && bun install -g --ignore-scripts @new-scope/pi",
steps: [
{
command: "bun",
@@ -318,8 +327,8 @@ describe("detectInstallMethod", () => {
},
{
command: "bun",
args: ["install", "-g", "@new-scope/pi"],
display: "bun install -g @new-scope/pi",
args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"],
display: "bun install -g --ignore-scripts @new-scope/pi",
},
],
});
@@ -5,6 +5,8 @@ import {
getLatestPiRelease,
getLatestPiVersion,
isNewerPackageVersion,
isNodeVersionAtLeast,
MINIMUM_NODE_VERSION_FOR_LATEST_PI,
} from "../src/utils/version-check.js";
const originalSkipVersionCheck = process.env.PI_SKIP_VERSION_CHECK;
@@ -33,6 +35,13 @@ describe("version checks", () => {
expect(isNewerPackageVersion("0.70.6", "0.70.5")).toBe(true);
});
it("checks the Node version required by current pi releases", () => {
expect(MINIMUM_NODE_VERSION_FOR_LATEST_PI).toBe("22.19.0");
expect(isNodeVersionAtLeast("20.19.4", MINIMUM_NODE_VERSION_FOR_LATEST_PI)).toBe(false);
expect(isNodeVersionAtLeast("22.19.0", MINIMUM_NODE_VERSION_FOR_LATEST_PI)).toBe(true);
expect(isNodeVersionAtLeast("23.0.0", MINIMUM_NODE_VERSION_FOR_LATEST_PI)).toBe(true);
});
it("returns only newer versions", async () => {
const fetchMock = vi.fn(async () => Response.json({ version: "1.2.3" }));
vi.stubGlobal("fetch", fetchMock);
+2
View File
@@ -1,5 +1,7 @@
# Changelog
## [0.74.2] - 2026-05-21
## [0.74.1] - 2026-05-16
### Added
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@earendil-works/pi-tui",
"version": "0.74.1",
"version": "0.74.2",
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
"type": "module",
"main": "dist/index.js",
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## [0.74.2] - 2026-05-21
### Fixed
- Fixed direct workspace publishing to build package artifacts before publish.
## [0.74.1] - 2026-05-16
## [0.74.0] - 2026-05-07
+5 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@earendil-works/pi-web-ui",
"version": "0.74.1",
"version": "0.74.2",
"description": "Reusable web UI components for AI chat interfaces powered by @earendil-works/pi-ai",
"type": "module",
"main": "dist/index.js",
@@ -14,12 +14,13 @@
"build": "tsc -p tsconfig.build.json && tailwindcss -i ./src/app.css -o ./dist/app.css --minify",
"dev": "concurrently --names \"build,example\" --prefix-colors \"cyan,green\" \"tsc -p tsconfig.build.json --watch --preserveWatchOutput\" \"tailwindcss -i ./src/app.css -o ./dist/app.css --watch\" \"npm run dev --prefix example\"",
"dev:tsc": "concurrently --names \"build\" --prefix-colors \"cyan\" \"tsc -p tsconfig.build.json --watch --preserveWatchOutput\" \"tailwindcss -i ./src/app.css -o ./dist/app.css --watch\"",
"check": "biome check --write --error-on-warnings . && tsc --noEmit && cd example && biome check --write --error-on-warnings . && tsc --noEmit"
"check": "biome check --write --error-on-warnings . && tsc --noEmit && cd example && biome check --write --error-on-warnings . && tsc --noEmit",
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
"@lmstudio/sdk": "^1.5.0",
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-tui": "^0.74.1",
"@earendil-works/pi-ai": "^0.74.2",
"@earendil-works/pi-tui": "^0.74.2",
"typebox": "^1.1.24",
"docx-preview": "^0.3.7",
"jszip": "^3.10.1",