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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +71 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termbeam",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Beam your terminal to any device — mobile-optimized web terminal with multi-session support",
5
5
  "main": "src/server.js",
6
6
  "bin": {
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
- // Detect parent process on Windows via WMIC
43
- try {
44
- const result = execFileSync(
45
- 'wmic',
46
- ['process', 'where', `ProcessId=${ppid}`, 'get', 'Name', '/value'],
47
- { stdio: ['pipe', 'pipe', 'ignore'], encoding: 'utf8', timeout: 3000 },
48
- );
49
- const match = result.match(/Name=(.+)/);
50
- if (match) {
51
- const name = match[1].trim().toLowerCase();
52
- console.log(`[termbeam] Detected parent process: ${name}`);
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
- } catch (err) {
57
- console.log(`[termbeam] Could not detect parent process: ${err.message}`);
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}`);