mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-11 07:29:00 +02:00
fix(make-pdf): resolve the sibling browse binary from execPath, not argv[0]
In a bun-compiled binary process.argv[0] is the raw invocation string — often relative ('./pdf', 'pdf') — so dirname(argv[0]) yielded '.' and the sibling candidates (../browse/dist/browse etc.) resolved against the CWD instead of the install dir. Resolution was cwd-dependent: correct-by-luck when the fallbacks rescued it, wrong when a cwd-relative path matched. process.execPath is always the absolute binary path. The resolution step takes an injectable selfPath (defaulted) because under bun test the process path is the bun runtime and the compiled-binary shapes are otherwise unreachable.
The issue's other half — pdf setup failing on newtab('about:blank') — was already fixed on main in v1.64.0.0 (browse/src/url-validation.ts exact-match allows about:blank; its comment names this exact smoke). This commit closes what remains.
Regression tests (the sibling-via-selfPath case fails on v1.68.3.0 — pre-fix code ignores the seam and either resolves the global install or throws): sibling resolution from an install-shaped tree, and a decoy-browse-DIRECTORY case pinning that a directory never wins resolution.
Fixes #2156
This commit is contained in:
@@ -168,3 +168,51 @@ describe("BrowseClientError", () => {
|
||||
expect(err.name).toBe("BrowseClientError");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveBrowseBin — sibling resolution from execPath (#2156)", () => {
|
||||
// In a bun-compiled binary argv[0] is the raw invocation string (often
|
||||
// relative), so the old dirname(argv[0]) built sibling candidates against
|
||||
// the CWD. Under `bun test` the process path is the bun runtime, so these
|
||||
// shapes are only reachable through the selfPath seam.
|
||||
|
||||
test("sibling browse next to the install dir is found via selfPath", () => {
|
||||
const base = fs.mkdtempSync(path.join(os.tmpdir(), "mkpdf-sib-"));
|
||||
try {
|
||||
const distDir = path.join(base, "browse", "dist");
|
||||
fs.mkdirSync(distDir, { recursive: true });
|
||||
const sibling = path.join(distDir, "browse");
|
||||
fs.writeFileSync(sibling, "#!/bin/sh\nexit 0\n", { mode: 0o755 });
|
||||
const selfPath = path.join(base, "make-pdf", "dist", "pdf");
|
||||
// Receipts: pre-fix code ignores the selfPath seam entirely, so it can
|
||||
// never produce this sibling — it either finds a global install (wrong
|
||||
// value) or throws (PATH is empty). Red on v1.68.3.0 either way.
|
||||
const resolved = resolveBrowseBin({ PATH: "" }, selfPath);
|
||||
expect(resolved).toBe(path.resolve(path.join(base, "make-pdf"), "../browse/dist/browse"));
|
||||
} finally {
|
||||
fs.rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("a decoy browse DIRECTORY near selfPath never shadows a real PATH binary", () => {
|
||||
const base = fs.mkdtempSync(path.join(os.tmpdir(), "mkpdf-decoy-"));
|
||||
try {
|
||||
// The ~/.claude/skills/browse alias-directory shape from #2156: a
|
||||
// directory named exactly like the third sibling candidate.
|
||||
fs.mkdirSync(path.join(base, "browse"), { recursive: true });
|
||||
const pathDir = path.join(base, "pathbin");
|
||||
fs.mkdirSync(pathDir, { recursive: true });
|
||||
const onPath = path.join(pathDir, "browse");
|
||||
fs.writeFileSync(onPath, "#!/bin/sh\nexit 0\n", { mode: 0o755 });
|
||||
const selfPath = path.join(base, "tools", "pdf");
|
||||
// os.homedir() ignores a $HOME override under bun, so the global-install
|
||||
// probe may legitimately win on boxes with a real ~/.claude install. The
|
||||
// invariant under test is narrower: the decoy DIRECTORY never wins, and
|
||||
// whatever wins is a regular file.
|
||||
const resolved = resolveBrowseBin({ PATH: pathDir }, selfPath);
|
||||
expect(resolved).not.toBe(path.join(base, "browse"));
|
||||
expect(fs.statSync(resolved).isFile()).toBe(true);
|
||||
} finally {
|
||||
fs.rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user