fix: harden pi package resolution

This commit is contained in:
Peter Steinberger
2025-12-13 20:37:46 +00:00
parent 5a1687484c
commit 41dd3b11b7
2 changed files with 64 additions and 16 deletions

View File

@@ -1,26 +1,73 @@
import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
// Resolve the bundled pi/tau binary path from the installed dependency.
export function resolveBundledPiBinary(): string | null {
const candidatePkgDirs: string[] = [];
// Preferred: ESM resolution to the package entry, then walk up to package.json.
try {
const require = createRequire(import.meta.url);
const pkgPath = require.resolve(
"@mariozechner/pi-coding-agent/package.json",
);
const pkgDir = path.dirname(pkgPath);
// Prefer compiled binary if present, else fall back to dist/cli.js (has shebang).
const binCandidates = [
path.join(pkgDir, "dist", "pi"),
path.join(pkgDir, "dist", "cli.js"),
path.join(pkgDir, "bin", "tau-dev.mjs"),
];
for (const candidate of binCandidates) {
if (fs.existsSync(candidate)) return candidate;
const resolved = (import.meta as { resolve?: (s: string) => string })
.resolve;
const entryUrl = resolved?.("@mariozechner/pi-coding-agent");
if (typeof entryUrl === "string" && entryUrl.startsWith("file:")) {
const entryPath = fileURLToPath(entryUrl);
let dir = path.dirname(entryPath);
for (let i = 0; i < 12; i += 1) {
const pkgJson = path.join(dir, "package.json");
if (fs.existsSync(pkgJson)) {
candidatePkgDirs.push(dir);
break;
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
}
} catch {
// Dependency missing or resolution failed.
// ignore; we'll try filesystem fallbacks below
}
// Fallback: walk up from this module's directory to find node_modules.
try {
let dir = path.dirname(fileURLToPath(import.meta.url));
for (let i = 0; i < 12; i += 1) {
candidatePkgDirs.push(
path.join(dir, "node_modules", "@mariozechner", "pi-coding-agent"),
);
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
} catch {
// ignore
}
// Fallback: assume CWD is project root.
candidatePkgDirs.push(
path.resolve(
process.cwd(),
"node_modules",
"@mariozechner",
"pi-coding-agent",
),
);
for (const pkgDir of candidatePkgDirs) {
try {
if (!fs.existsSync(pkgDir)) continue;
const binCandidates = [
path.join(pkgDir, "dist", "pi"),
path.join(pkgDir, "dist", "cli.js"),
path.join(pkgDir, "bin", "tau-dev.mjs"),
];
for (const candidate of binCandidates) {
if (fs.existsSync(candidate)) return candidate;
}
} catch {
// ignore this candidate
}
}
return null;
}

View File

@@ -97,7 +97,8 @@ function safeReadJson(filePath: string): Record<string, unknown> | null {
if (!exists(filePath)) return null;
const raw = fs.readFileSync(filePath, "utf-8");
const parsed = JSON.parse(raw) as unknown;
if (typeof parsed !== "object" || parsed === null) return null;
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
return null;
return parsed as Record<string, unknown>;
} catch {
return null;