diff --git a/packages/coding-agent/src/config.ts b/packages/coding-agent/src/config.ts index fc3dd17f..bf268a77 100644 --- a/packages/coding-agent/src/config.ts +++ b/packages/coding-agent/src/config.ts @@ -81,24 +81,19 @@ export function detectInstallMethod(): InstallMethod { return "unknown"; } -function getInferredNpmInstall(packageName: string): { root: string; prefix: string } | undefined { +function getInferredNpmInstall(): { root: string; prefix: string } | undefined { const packageDir = getPackageDir(); const path = process.platform === "win32" || packageDir.includes("\\") ? win32 : { basename, dirname }; - const [scope, name] = packageName.split("/"); + const parent = path.dirname(packageDir); let root: string | undefined; - if ( - name && - scope?.startsWith("@") && - path.basename(path.dirname(packageDir)) === scope && - path.basename(packageDir) === name - ) { - root = path.dirname(path.dirname(packageDir)); - } else if (!name && path.basename(packageDir) === packageName) { - root = path.dirname(packageDir); + if (path.basename(parent).startsWith("@") && path.basename(path.dirname(parent)) === "node_modules") { + root = path.dirname(parent); + } else if (path.basename(parent) === "node_modules") { + root = parent; } - if (!root || path.basename(root) !== "node_modules") return undefined; - const parent = path.dirname(root); - if (path.basename(parent) === "lib") return { root, prefix: path.dirname(parent) }; + if (!root) return undefined; + const rootParent = path.dirname(root); + if (path.basename(rootParent) === "lib") return { root, prefix: path.dirname(rootParent) }; // Windows global npm prefixes use `\\node_modules`, which is // indistinguishable from local project installs by path shape alone. Do not // infer unsupported Windows custom prefixes without `npm root -g` evidence. @@ -137,7 +132,7 @@ function getSelfUpdateCommandForMethod( ); case "npm": { const [command = "npm", ...npmArgs] = npmCommand ?? []; - const inferred = npmCommand?.length ? undefined : getInferredNpmInstall(installedPackageName); + const inferred = npmCommand?.length ? undefined : getInferredNpmInstall(); const prefixArgs = [...npmArgs, ...(inferred ? ["--prefix", inferred.prefix] : [])]; const installStep = makeSelfUpdateCommandStep(command, [...prefixArgs, "install", "-g", updatePackageName]); const uninstallStep = @@ -169,7 +164,7 @@ function readCommandOutput( return undefined; } -function getGlobalPackageRoots(method: InstallMethod, packageName: string, npmCommand?: string[]): string[] { +function getGlobalPackageRoots(method: InstallMethod, _packageName: string, npmCommand?: string[]): string[] { switch (method) { case "npm": { const configured = !!npmCommand?.length; @@ -187,7 +182,7 @@ function getGlobalPackageRoots(method: InstallMethod, packageName: string, npmCo const root = readCommandOutput(command, [...npmArgs, "root", "-g"], { requireSuccess: configured, }); - const inferred = configured ? undefined : getInferredNpmInstall(packageName); + const inferred = configured ? undefined : getInferredNpmInstall(); return [root, inferred?.root].filter((x): x is string => !!x); } case "pnpm": { diff --git a/packages/coding-agent/test/package-command-paths.test.ts b/packages/coding-agent/test/package-command-paths.test.ts index 3d6d5968..03c8f4ca 100644 --- a/packages/coding-agent/test/package-command-paths.test.ts +++ b/packages/coding-agent/test/package-command-paths.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "no import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { ENV_AGENT_DIR, PACKAGE_NAME } from "../src/config.js"; +import { ENV_AGENT_DIR, PACKAGE_NAME, VERSION } from "../src/config.js"; import { main } from "../src/main.js"; describe("package commands", () => { @@ -16,6 +16,11 @@ describe("package commands", () => { let originalExitCode: typeof process.exitCode; let originalExecPath: string; + function getNewerPatchVersion(): string { + const [major = "0", minor = "0", patch = "0"] = VERSION.split("."); + return `${major}.${minor}.${Number.parseInt(patch, 10) + 1}`; + } + beforeEach(() => { tempDir = join(tmpdir(), `pi-package-commands-${Date.now()}-${Math.random().toString(36).slice(2)}`); agentDir = join(tempDir, "agent"); @@ -201,7 +206,7 @@ else fs.writeFileSync(${JSON.stringify(recordPath)},JSON.stringify(args)); value: join(selfPackageDir, "dist", "cli.js"), configurable: true, }); - const fetchMock = vi.fn(async () => Response.json({ version: "0.73.1" })); + const fetchMock = vi.fn(async () => Response.json({ version: getNewerPatchVersion() })); vi.stubGlobal("fetch", fetchMock); const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});