fix(coding-agent): allow Windows pnpm self-update

closes #4157
This commit is contained in:
Armin Ronacher
2026-05-18 09:13:12 +02:00
parent 96cad24a07
commit c65177370b
3 changed files with 16 additions and 9 deletions

View File

@@ -6,6 +6,7 @@
- Fixed Windows npm self-updates to move loaded native dependency packages out of the active install before reinstalling pi ([#4157](https://github.com/earendil-works/pi/issues/4157)).
- Fixed `pi update --self` detection for pnpm v11 global installs whose package path resolves through the pnpm store ([#4647](https://github.com/earendil-works/pi/issues/4647)).
- Fixed Windows pnpm self-updates to resolve pnpm command shims and run through pnpm instead of requiring manual updates ([#4157](https://github.com/earendil-works/pi/issues/4157)).
## [0.75.1] - 2026-05-18

View File

@@ -506,8 +506,10 @@ export async function handlePackageCommand(args: string[]): Promise<boolean> {
return true;
}
const installMethod = detectInstallMethod();
if (process.platform === "win32" && installMethod !== "npm") {
console.error(chalk.red(`${APP_NAME} self-update on Windows is only supported for npm installs.`));
if (process.platform === "win32" && installMethod !== "npm" && installMethod !== "pnpm") {
console.error(
chalk.red(`${APP_NAME} self-update on Windows is only supported for npm and pnpm installs.`),
);
console.error(chalk.dim(`Detected install method: ${installMethod}. Update ${APP_NAME} manually.`));
process.exitCode = 1;
return true;
@@ -523,7 +525,9 @@ export async function handlePackageCommand(args: string[]): Promise<boolean> {
return true;
}
try {
prepareWindowsNpmSelfUpdate();
if (installMethod === "npm") {
prepareWindowsNpmSelfUpdate();
}
await runSelfUpdate(selfUpdateCommand);
} catch (error: unknown) {
const message = error instanceof Error ? error.message : "Unknown package command error";

View File

@@ -3,9 +3,9 @@ import { existsSync, readFileSync } from "node:fs";
import { dirname, extname, join, resolve, sep } from "node:path";
const EXIT_STDIO_GRACE_MS = 100;
const WINDOWS_COMMAND_EXTENSIONS = ["", ".exe", ".cmd", ".bat"];
const WINDOWS_COMMAND_EXTENSIONS = [".exe", ".cmd", ".bat", ""];
const WINDOWS_COMMAND_SHIM_RE = /\.(?:cmd|bat)$/i;
const NODE_SHIM_SCRIPT_RE = /(?:%~dp0|%dp0%|%basedir%)[^"'\r\n<>|&]*?\.(?:cjs|mjs|js)/i;
const NODE_SHIM_SCRIPT_RE = /(?:%~dp0|%dp0%|%basedir%)[^"'\r\n<>|&]*?\.(?:cjs|mjs|js)/gi;
export interface ResolvedSpawnCommand {
command: string;
@@ -45,10 +45,12 @@ function expandShimPath(path: string, shimPath: string): string {
}
function findNodeShimScript(shimPath: string): string | undefined {
const match = readFileSync(shimPath, "utf-8").match(NODE_SHIM_SCRIPT_RE);
if (!match) return undefined;
const scriptPath = expandShimPath(match[0], shimPath);
return existsSync(scriptPath) ? scriptPath : undefined;
const matches = [...readFileSync(shimPath, "utf-8").matchAll(NODE_SHIM_SCRIPT_RE)];
for (const match of matches.reverse()) {
const scriptPath = expandShimPath(match[0], shimPath);
if (existsSync(scriptPath)) return scriptPath;
}
return undefined;
}
export function resolveSpawnCommand(