forked from nicobailon/pi-subagents
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpi-spawn.ts
More file actions
98 lines (86 loc) · 2.88 KB
/
pi-spawn.ts
File metadata and controls
98 lines (86 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import * as fs from "node:fs";
import { createRequire } from "node:module";
import * as path from "node:path";
const require = createRequire(import.meta.url);
export function resolvePiPackageRoot(): string | undefined {
try {
const entry = process.argv[1];
if (!entry) return undefined;
let dir = path.dirname(fs.realpathSync(entry));
while (dir !== path.dirname(dir)) {
try {
const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf-8"));
if (pkg.name === "@mariozechner/pi-coding-agent") return dir;
} catch {}
dir = path.dirname(dir);
}
} catch {}
return undefined;
}
export interface PiSpawnDeps {
platform?: NodeJS.Platform;
execPath?: string;
argv1?: string;
existsSync?: (filePath: string) => boolean;
readFileSync?: (filePath: string, encoding: "utf-8") => string;
resolvePackageJson?: () => string;
piPackageRoot?: string;
}
export interface PiSpawnCommand {
command: string;
args: string[];
}
function isRunnableNodeScript(filePath: string, existsSync: (filePath: string) => boolean): boolean {
if (!existsSync(filePath)) return false;
return /\.(?:mjs|cjs|js)$/i.test(filePath);
}
function normalizePath(filePath: string): string {
return path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
}
export function resolveWindowsPiCliScript(deps: PiSpawnDeps = {}): string | undefined {
const existsSync = deps.existsSync ?? fs.existsSync;
const readFileSync = deps.readFileSync ?? ((filePath, encoding) => fs.readFileSync(filePath, encoding));
const argv1 = deps.argv1 ?? process.argv[1];
if (argv1) {
const argvPath = normalizePath(argv1);
if (isRunnableNodeScript(argvPath, existsSync)) {
return argvPath;
}
}
try {
const resolvePackageJson = deps.resolvePackageJson ?? (() => {
const root = deps.piPackageRoot ?? resolvePiPackageRoot();
if (root) return path.join(root, "package.json");
return require.resolve("@mariozechner/pi-coding-agent/package.json");
});
const packageJsonPath = resolvePackageJson();
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
bin?: string | Record<string, string>;
};
const binField = packageJson.bin;
const binPath = typeof binField === "string"
? binField
: binField?.pi ?? Object.values(binField ?? {})[0];
if (!binPath) return undefined;
const candidate = normalizePath(path.resolve(path.dirname(packageJsonPath), binPath));
if (isRunnableNodeScript(candidate, existsSync)) {
return candidate;
}
} catch {
return undefined;
}
return undefined;
}
export function getPiSpawnCommand(args: string[], deps: PiSpawnDeps = {}): PiSpawnCommand {
const platform = deps.platform ?? process.platform;
if (platform === "win32") {
const piCliPath = resolveWindowsPiCliScript(deps);
if (piCliPath) {
return {
command: deps.execPath ?? process.execPath,
args: [piCliPath, ...args],
};
}
}
return { command: "pi", args };
}