termbeam 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli.js +71 -15
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -33,28 +33,84 @@ Environment:
|
|
|
33
33
|
`);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Get ancestor process names on Windows by walking up the process tree.
|
|
38
|
+
* Fetches all processes in a single wmic call, then walks the tree in memory.
|
|
39
|
+
*/
|
|
40
|
+
function getWindowsAncestors(startPid, maxDepth = 4) {
|
|
41
|
+
const { execFileSync } = require('child_process');
|
|
42
|
+
const names = [];
|
|
43
|
+
const safePid = parseInt(startPid, 10);
|
|
44
|
+
if (!Number.isFinite(safePid) || safePid <= 0) return names;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const result = execFileSync(
|
|
48
|
+
'wmic',
|
|
49
|
+
['process', 'get', 'Name,ParentProcessId,ProcessId', '/format:csv'],
|
|
50
|
+
{ stdio: ['pipe', 'pipe', 'ignore'], encoding: 'utf8', timeout: 5000 },
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Parse CSV output — first non-empty line is the header
|
|
54
|
+
const lines = result.split(/\r?\n/).filter((l) => l.trim());
|
|
55
|
+
if (lines.length === 0) return names;
|
|
56
|
+
|
|
57
|
+
const header = lines[0].split(',').map((h) => h.trim());
|
|
58
|
+
const nameIdx = header.indexOf('Name');
|
|
59
|
+
const pidIdx = header.indexOf('ProcessId');
|
|
60
|
+
const ppidIdx = header.indexOf('ParentProcessId');
|
|
61
|
+
if (nameIdx === -1 || pidIdx === -1 || ppidIdx === -1) return names;
|
|
62
|
+
|
|
63
|
+
const processes = new Map();
|
|
64
|
+
for (let i = 1; i < lines.length; i++) {
|
|
65
|
+
const cols = lines[i].split(',');
|
|
66
|
+
if (cols.length <= Math.max(nameIdx, pidIdx, ppidIdx)) continue;
|
|
67
|
+
const pid = parseInt(cols[pidIdx], 10);
|
|
68
|
+
if (Number.isFinite(pid)) {
|
|
69
|
+
processes.set(pid, { name: cols[nameIdx].trim().toLowerCase(), ppid: parseInt(cols[ppidIdx], 10) });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Walk up the tree in memory — no more subprocess calls
|
|
74
|
+
let currentPid = safePid;
|
|
75
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
76
|
+
const proc = processes.get(currentPid);
|
|
77
|
+
if (!proc) break;
|
|
78
|
+
console.log(`[termbeam] Process tree: ${proc.name}`);
|
|
79
|
+
names.push(proc.name);
|
|
80
|
+
if (!Number.isFinite(proc.ppid) || proc.ppid === 0 || proc.ppid === currentPid) break;
|
|
81
|
+
currentPid = proc.ppid;
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.log(`[termbeam] Could not query process tree: ${err.message}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return names;
|
|
88
|
+
}
|
|
89
|
+
|
|
36
90
|
function getDefaultShell() {
|
|
37
91
|
const { execFileSync } = require('child_process');
|
|
38
92
|
const ppid = process.ppid;
|
|
39
93
|
console.log(`[termbeam] Detecting shell (parent PID: ${ppid}, platform: ${os.platform()})`);
|
|
40
94
|
|
|
41
95
|
if (os.platform() === 'win32') {
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (name === 'pwsh.exe') return 'pwsh.exe';
|
|
54
|
-
if (name === 'powershell.exe') return 'powershell.exe';
|
|
96
|
+
// Walk up the process tree (up to 4 ancestors) to find the real user shell.
|
|
97
|
+
// npx/npm on Windows spawns cmd.exe as intermediary, so the immediate
|
|
98
|
+
// parent is often cmd.exe or node.exe rather than the user's actual shell.
|
|
99
|
+
const ancestors = getWindowsAncestors(ppid);
|
|
100
|
+
const preferredShells = ['pwsh.exe', 'powershell.exe'];
|
|
101
|
+
|
|
102
|
+
let foundCmd = false;
|
|
103
|
+
for (const name of ancestors) {
|
|
104
|
+
if (preferredShells.includes(name)) {
|
|
105
|
+
console.log(`[termbeam] Found shell in process tree: ${name}`);
|
|
106
|
+
return name;
|
|
55
107
|
}
|
|
56
|
-
|
|
57
|
-
|
|
108
|
+
if (name === 'cmd.exe') foundCmd = true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (foundCmd) {
|
|
112
|
+
console.log(`[termbeam] Using detected shell: cmd.exe`);
|
|
113
|
+
return 'cmd.exe';
|
|
58
114
|
}
|
|
59
115
|
const fallback = process.env.COMSPEC || 'cmd.exe';
|
|
60
116
|
console.log(`[termbeam] Falling back to: ${fallback}`);
|