-
Notifications
You must be signed in to change notification settings - Fork 121
Expand file tree
/
Copy pathptySpawn.ts
More file actions
94 lines (83 loc) · 3.32 KB
/
Copy pathptySpawn.ts
File metadata and controls
94 lines (83 loc) · 3.32 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
import type * as NodePty from "@lydell/node-pty";
import type { IPty } from "@lydell/node-pty";
import { log } from "@/node/services/log";
import { getErrorMessage } from "@/common/utils/errors";
import { sanitizeMuxChildEnv, sanitizeMuxChildPath } from "./childProcessEnv";
interface PtySpawnRequest {
runtimeLabel: string;
command: string;
args: string[];
cwd: string;
cols: number;
rows: number;
preferElectronBuild: boolean;
env?: NodeJS.ProcessEnv;
pathEnv?: string;
logLocalEnv?: boolean;
}
function loadNodePty(runtimeType: string, preferElectronBuild: boolean): typeof NodePty {
const first = preferElectronBuild ? "node-pty" : "@lydell/node-pty";
const second = preferElectronBuild ? "@lydell/node-pty" : "node-pty";
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pty = require(first) as typeof NodePty;
log.debug(`Using ${first} for ${runtimeType}`);
return pty;
} catch {
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pty = require(second) as typeof NodePty;
log.debug(`Using ${second} for ${runtimeType} (fallback)`);
return pty;
} catch (err) {
log.error("Neither @lydell/node-pty nor node-pty available:", err);
throw new Error(
process.versions.electron
? `${runtimeType} terminals are not available. node-pty failed to load (likely due to Electron ABI version mismatch). Run 'make rebuild-native' to rebuild native modules.`
: `${runtimeType} terminals are not available. No prebuilt binaries found for your platform. Supported: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64.`
);
}
}
}
export function resolvePathEnv(
env: NodeJS.ProcessEnv,
pathEnvOverride?: string
): string | undefined {
const basePath =
pathEnvOverride ??
env.PATH ??
env.Path ??
(process.platform === "win32" ? undefined : "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin");
return sanitizeMuxChildPath(basePath, env);
}
export function spawnPtyProcess(request: PtySpawnRequest): IPty {
const pty = loadNodePty(request.runtimeLabel, request.preferElectronBuild);
const mergedEnv = sanitizeMuxChildEnv({ ...process.env, ...request.env });
const pathEnv = resolvePathEnv(mergedEnv, request.pathEnv);
const env: NodeJS.ProcessEnv = {
...mergedEnv,
TERM: "xterm-256color",
...(pathEnv ? { PATH: pathEnv } : {}),
};
try {
return pty.spawn(request.command, request.args, {
name: "xterm-256color",
cols: request.cols,
rows: request.rows,
cwd: request.cwd,
env,
});
} catch (err) {
log.error(`[PTY] Failed to spawn ${request.runtimeLabel} terminal:`, err);
const printableArgs = request.args.length > 0 ? ` ${request.args.join(" ")}` : "";
const cmd = `${request.command}${printableArgs}`;
const details = `cmd="${cmd}", cwd="${request.cwd}", platform="${process.platform}"`;
const errMessage = getErrorMessage(err);
if (request.logLocalEnv) {
log.error(`Local PTY spawn config: ${cmd} (cwd: ${request.cwd})`);
log.error(`process.env.SHELL: ${process.env.SHELL ?? "undefined"}`);
log.error(`process.env.PATH: ${process.env.PATH ?? process.env.Path ?? "undefined"}`);
}
throw new Error(`Failed to spawn ${request.runtimeLabel} terminal (${details}): ${errMessage}`);
}
}