Revert "fix(coding-agent): routed foreign aliases to binary updates"
This reverts commit 834002adc5.
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed the parent TUI stalling after a subagent submits its result until terminal focus or resize wakes the event loop ([#8462](https://github.com/can1357/oh-my-pi/issues/8462)).
|
||||
- Fixed `omp update` routing foreign npm/bun bin-directory alias symlinks through the package manager, causing npm EEXIST instead of updating the aliased standalone binary ([#8468](https://github.com/can1357/oh-my-pi/issues/8468)).
|
||||
- Fixed `read` hashline headers collapsing nested in-workspace paths to the bare basename, which let a same-basename file at the session cwd capture a verbatim follow-up `edit` and deterministically reject it with `hash is not from this session`. Headers now retain the workspace-relative path (e.g. `[src/settings.json#0063]`) ([#8482](https://github.com/can1357/oh-my-pi/issues/8482)).
|
||||
|
||||
## [17.3.1] - 2026-08-13
|
||||
|
||||
@@ -481,11 +481,6 @@ interface UpdateMethodResolutionOptions {
|
||||
* target directory.
|
||||
*/
|
||||
ompIsRegularFile?: boolean;
|
||||
/**
|
||||
* Resolved symlink target. npm/bun own links into their manager root;
|
||||
* targets elsewhere are foreign aliases that must update as binaries.
|
||||
*/
|
||||
ompRealpath?: string;
|
||||
}
|
||||
|
||||
type UpdateTarget =
|
||||
@@ -501,7 +496,7 @@ function resolveUpdateMethod(
|
||||
bunBinDir: string | undefined,
|
||||
options: UpdateMethodResolutionOptions = {},
|
||||
): UpdateMethod {
|
||||
const { homebrewPrefix, miseBinDirs = [], miseDataDir, npmBinDir, ompIsRegularFile = false, ompRealpath } = options;
|
||||
const { homebrewPrefix, miseBinDirs = [], miseDataDir, npmBinDir, ompIsRegularFile = false } = options;
|
||||
const launcherExtension = path.extname(ompPath).toLowerCase();
|
||||
const isWindowsScriptLauncher =
|
||||
launcherExtension === ".cmd" || launcherExtension === ".ps1" || launcherExtension === ".bat";
|
||||
@@ -519,31 +514,9 @@ function resolveUpdateMethod(
|
||||
// (bun's .exe launcher, npm's .cmd/.ps1), so a regular file is NOT evidence
|
||||
// of a standalone install and the override would hijack managed installs.
|
||||
const isStandaloneRegularFile = ompIsRegularFile && process.platform !== "win32";
|
||||
if (
|
||||
bunBinDir &&
|
||||
isPathInDirectory(ompPath, bunBinDir) &&
|
||||
!isStandaloneRegularFile &&
|
||||
(!ompRealpath ||
|
||||
isPathInDirectoryLexical(
|
||||
ompRealpath,
|
||||
tryRealpath(path.dirname(bunBinDir)) ?? path.dirname(path.resolve(bunBinDir)),
|
||||
))
|
||||
) {
|
||||
return "bun";
|
||||
}
|
||||
if (
|
||||
npmBinDir &&
|
||||
isPathInDirectory(ompPath, npmBinDir) &&
|
||||
!isStandaloneRegularFile &&
|
||||
(!ompRealpath ||
|
||||
isPathInDirectoryLexical(
|
||||
ompRealpath,
|
||||
tryRealpath(path.dirname(npmBinDir)) ?? path.dirname(path.resolve(npmBinDir)),
|
||||
))
|
||||
) {
|
||||
if (bunBinDir && isPathInDirectory(ompPath, bunBinDir) && !isStandaloneRegularFile) return "bun";
|
||||
if ((npmBinDir && isPathInDirectory(ompPath, npmBinDir) && !isStandaloneRegularFile) || isWindowsScriptLauncher)
|
||||
return "npm";
|
||||
}
|
||||
if (isWindowsScriptLauncher) return "npm";
|
||||
return "binary";
|
||||
}
|
||||
|
||||
@@ -554,33 +527,6 @@ export function resolveUpdateMethodForTest(
|
||||
): UpdateMethod {
|
||||
return resolveUpdateMethod(ompPath, bunBinDir, options);
|
||||
}
|
||||
|
||||
/** Resolve an install target from a concrete PATH entry without probing package managers. */
|
||||
export function resolveUpdateTargetFromPathForTest(
|
||||
ompPath: string,
|
||||
bunBinDir: string | undefined,
|
||||
options: UpdateMethodResolutionOptions & { allowPackageManagers: boolean },
|
||||
): UpdateTarget {
|
||||
let ompIsRegularFile = false;
|
||||
let ompIsSymlink = false;
|
||||
let ompRealpath: string | undefined;
|
||||
try {
|
||||
const stat = fs.lstatSync(ompPath);
|
||||
ompIsRegularFile = stat.isFile() && !stat.isSymbolicLink();
|
||||
ompIsSymlink = stat.isSymbolicLink();
|
||||
if (ompIsSymlink) ompRealpath = tryRealpath(ompPath);
|
||||
} catch {}
|
||||
const method = resolveUpdateMethod(ompPath, bunBinDir, { ...options, ompIsRegularFile, ompRealpath });
|
||||
if (method === "binary") {
|
||||
// Preserve a foreign alias and replace the standalone binary it
|
||||
// resolves to. Binary-only releases still replace manager launchers
|
||||
// in place because package-manager detection is intentionally off.
|
||||
const binaryPath = options.allowPackageManagers ? (ompRealpath ?? ompPath) : ompPath;
|
||||
return { method, path: binaryPath, replacesSymlink: ompIsSymlink && binaryPath === ompPath };
|
||||
}
|
||||
if (method === "bun" || method === "npm") return { method, path: ompPath };
|
||||
return { method };
|
||||
}
|
||||
/**
|
||||
* Resolve how the running install should be updated.
|
||||
*
|
||||
@@ -600,13 +546,27 @@ async function resolveUpdateTarget(options: { allowPackageManagers: boolean }):
|
||||
const ompPath = resolveOmpPath();
|
||||
|
||||
if (ompPath) {
|
||||
return resolveUpdateTargetFromPathForTest(ompPath, bunBinDir, {
|
||||
allowPackageManagers: options.allowPackageManagers,
|
||||
// Package-manager installs symlink the bin entry into node_modules; the
|
||||
// standalone installer writes a plain executable. When the global bin dir
|
||||
// overlaps the installer's default (~/.local/bin), that file type — not
|
||||
// directory containment — distinguishes a binary install from npm/bun.
|
||||
let ompIsRegularFile = false;
|
||||
let ompIsSymlink = false;
|
||||
try {
|
||||
const stat = fs.lstatSync(ompPath);
|
||||
ompIsRegularFile = stat.isFile() && !stat.isSymbolicLink();
|
||||
ompIsSymlink = stat.isSymbolicLink();
|
||||
} catch {}
|
||||
const method = resolveUpdateMethod(ompPath, bunBinDir, {
|
||||
homebrewPrefix,
|
||||
miseBinDirs,
|
||||
miseDataDir,
|
||||
npmBinDir,
|
||||
ompIsRegularFile,
|
||||
});
|
||||
if (method === "binary") return { method, path: ompPath, replacesSymlink: ompIsSymlink };
|
||||
if (method === "bun" || method === "npm") return { method, path: ompPath };
|
||||
return { method };
|
||||
}
|
||||
|
||||
if (bunBinDir) return { method: "bun" };
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
resolveReleaseDist,
|
||||
resolveReleaseRename,
|
||||
resolveUpdateMethodForTest,
|
||||
resolveUpdateTargetFromPathForTest,
|
||||
shouldForceBinaryUpdate,
|
||||
sweepStaleUpdateArtifacts,
|
||||
updateViaBinaryAt,
|
||||
@@ -188,52 +187,6 @@ describe("update-cli install target detection", () => {
|
||||
expect(method).toBe("npm");
|
||||
});
|
||||
|
||||
it("updates the resolved standalone binary behind a foreign npm-bin alias", async () => {
|
||||
// realpath: macOS tmpdir lives behind the /var -> /private/var symlink and
|
||||
// the resolver returns realpathed targets.
|
||||
const dir = await fs.realpath(await makeTempDir());
|
||||
const npmBinDir = path.join(dir, ".npm-global", "bin");
|
||||
const standalonePath = path.join(dir, ".local", "bin", "omp");
|
||||
const aliasPath = path.join(npmBinDir, "omp");
|
||||
await fs.mkdir(npmBinDir, { recursive: true });
|
||||
await fs.mkdir(path.dirname(standalonePath), { recursive: true });
|
||||
await Bun.write(standalonePath, "binary");
|
||||
await fs.symlink(standalonePath, aliasPath);
|
||||
|
||||
const target = resolveUpdateTargetFromPathForTest(aliasPath, undefined, {
|
||||
allowPackageManagers: true,
|
||||
npmBinDir,
|
||||
});
|
||||
|
||||
expect(target).toEqual({ method: "binary", path: standalonePath, replacesSymlink: false });
|
||||
expect(await fs.readlink(aliasPath)).toBe(standalonePath);
|
||||
});
|
||||
|
||||
it("uses npm update when the bin symlink resolves into npm's global install tree", () => {
|
||||
const method = resolveUpdateMethodForTest("/home/u/.npm-global/bin/omp", undefined, {
|
||||
npmBinDir: "/home/u/.npm-global/bin",
|
||||
ompRealpath: "/home/u/.npm-global/lib/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js",
|
||||
});
|
||||
|
||||
expect(method).toBe("npm");
|
||||
});
|
||||
|
||||
it("uses binary update when the bun global bin entry is a foreign alias symlink", () => {
|
||||
const method = resolveUpdateMethodForTest("/home/u/.bun/bin/omp", "/home/u/.bun/bin", {
|
||||
ompRealpath: "/home/u/.local/bin/omp",
|
||||
});
|
||||
|
||||
expect(method).toBe("binary");
|
||||
});
|
||||
|
||||
it("uses bun update when the bin symlink resolves into bun's global install tree", () => {
|
||||
const method = resolveUpdateMethodForTest("/home/u/.bun/bin/omp", "/home/u/.bun/bin", {
|
||||
ompRealpath: "/home/u/.bun/install/global/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js",
|
||||
});
|
||||
|
||||
expect(method).toBe("bun");
|
||||
});
|
||||
|
||||
it("uses binary update when prioritized omp is outside bun global bin", () => {
|
||||
const method = resolveUpdateMethodForTest("/Users/test/.local/bin/omp", "/Users/test/.bun/bin");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user