termbeam 1.21.0 → 1.21.1
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/cli/index.js +62 -31
- package/src/cli/service.js +22 -9
- package/src/tunnel/index.js +24 -7
- package/src/tunnel/install.js +3 -2
- package/src/utils/agents.js +23 -18
- package/src/utils/git.js +6 -2
- package/src/utils/shells.js +1 -0
- package/src/utils/update-executor.js +14 -9
- package/src/utils/version.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.21.1] - 2026-04-21
|
|
4
|
+
|
|
5
|
+
- fix(windows): service wizard uses getDefaultShell instead of COMSPEC
|
|
6
|
+
- fix(windows): use tasklist fallback when wmic unavailable for shell detection
|
|
7
|
+
- fix(windows): add windowsHide to all child_process calls
|
|
8
|
+
- fix(windows): hide devtunnel console windows and fix DEP0190 deprecation
|
|
9
|
+
|
|
3
10
|
## [1.21.0] - 2026-04-20
|
|
4
11
|
|
|
5
12
|
- feat(review): add Review Mode to diff viewer + SessionsHub filter chips (#195)
|
package/package.json
CHANGED
package/src/cli/index.js
CHANGED
|
@@ -75,48 +75,66 @@ function getWindowsAncestors(startPid, maxDepth = 4) {
|
|
|
75
75
|
const safePid = parseInt(startPid, 10);
|
|
76
76
|
if (!Number.isFinite(safePid) || safePid <= 0) return names;
|
|
77
77
|
|
|
78
|
+
// Strategy 1: wmic (available on older Windows builds)
|
|
78
79
|
try {
|
|
79
80
|
const result = execFileSync(
|
|
80
81
|
'wmic',
|
|
81
82
|
['process', 'get', 'Name,ParentProcessId,ProcessId', '/format:csv'],
|
|
82
|
-
{ stdio: ['pipe', 'pipe', 'ignore'], encoding: 'utf8', timeout: 5000 },
|
|
83
|
+
{ stdio: ['pipe', 'pipe', 'ignore'], encoding: 'utf8', timeout: 5000, windowsHide: true },
|
|
83
84
|
);
|
|
84
85
|
|
|
85
|
-
// Parse CSV output — first non-empty line is the header
|
|
86
86
|
const lines = result.split(/\r?\n/).filter((l) => l.trim());
|
|
87
|
-
if (lines.length
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
87
|
+
if (lines.length > 0) {
|
|
88
|
+
const header = lines[0].split(',').map((h) => h.trim());
|
|
89
|
+
const nameIdx = header.indexOf('Name');
|
|
90
|
+
const pidIdx = header.indexOf('ProcessId');
|
|
91
|
+
const ppidIdx = header.indexOf('ParentProcessId');
|
|
92
|
+
if (nameIdx !== -1 && pidIdx !== -1 && ppidIdx !== -1) {
|
|
93
|
+
const processes = new Map();
|
|
94
|
+
for (let i = 1; i < lines.length; i++) {
|
|
95
|
+
const cols = lines[i].split(',');
|
|
96
|
+
if (cols.length <= Math.max(nameIdx, pidIdx, ppidIdx)) continue;
|
|
97
|
+
const pid = parseInt(cols[pidIdx], 10);
|
|
98
|
+
if (Number.isFinite(pid)) {
|
|
99
|
+
processes.set(pid, {
|
|
100
|
+
name: cols[nameIdx].trim().toLowerCase(),
|
|
101
|
+
ppid: parseInt(cols[ppidIdx], 10),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let currentPid = safePid;
|
|
107
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
108
|
+
const proc = processes.get(currentPid);
|
|
109
|
+
if (!proc) break;
|
|
110
|
+
log.debug(`Process tree: ${proc.name}`);
|
|
111
|
+
names.push(proc.name);
|
|
112
|
+
if (!Number.isFinite(proc.ppid) || proc.ppid === 0 || proc.ppid === currentPid) break;
|
|
113
|
+
currentPid = proc.ppid;
|
|
114
|
+
}
|
|
115
|
+
if (names.length > 0) return names;
|
|
105
116
|
}
|
|
106
117
|
}
|
|
118
|
+
} catch (err) {
|
|
119
|
+
log.debug(`wmic not available: ${err.message}`);
|
|
120
|
+
}
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
// Strategy 2: tasklist for direct parent name (always available on Windows)
|
|
123
|
+
try {
|
|
124
|
+
const result = execFileSync('tasklist', ['/FI', `PID eq ${safePid}`, '/FO', 'CSV', '/NH'], {
|
|
125
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
126
|
+
encoding: 'utf8',
|
|
127
|
+
timeout: 5000,
|
|
128
|
+
windowsHide: true,
|
|
129
|
+
});
|
|
130
|
+
const match = result.match(/"([^"]+)"/);
|
|
131
|
+
if (match) {
|
|
132
|
+
const name = match[1].toLowerCase();
|
|
133
|
+
log.debug(`Process tree (tasklist): ${name}`);
|
|
134
|
+
names.push(name);
|
|
117
135
|
}
|
|
118
136
|
} catch (err) {
|
|
119
|
-
log.debug(`
|
|
137
|
+
log.debug(`tasklist failed: ${err.message}`);
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
return names;
|
|
@@ -188,6 +206,19 @@ function getDefaultShell() {
|
|
|
188
206
|
log.debug(`Using detected shell: cmd.exe`);
|
|
189
207
|
return 'cmd.exe';
|
|
190
208
|
}
|
|
209
|
+
|
|
210
|
+
// Heuristic: PSModulePath env var is set by PowerShell and inherited by children.
|
|
211
|
+
// When the tree walk only found intermediaries (node.exe), this detects the real shell.
|
|
212
|
+
const psModulePath = (process.env.PSModulePath || '').toLowerCase();
|
|
213
|
+
if (psModulePath.includes('\\powershell\\')) {
|
|
214
|
+
log.debug('Detected pwsh.exe via PSModulePath');
|
|
215
|
+
return 'pwsh.exe';
|
|
216
|
+
}
|
|
217
|
+
if (psModulePath.includes('\\windowspowershell\\')) {
|
|
218
|
+
log.debug('Detected powershell.exe via PSModulePath');
|
|
219
|
+
return 'powershell.exe';
|
|
220
|
+
}
|
|
221
|
+
|
|
191
222
|
const fallback = process.env.COMSPEC || 'cmd.exe';
|
|
192
223
|
log.debug(`Falling back to: ${fallback}`);
|
|
193
224
|
return fallback;
|
|
@@ -384,4 +415,4 @@ function parseArgs() {
|
|
|
384
415
|
return config;
|
|
385
416
|
}
|
|
386
417
|
|
|
387
|
-
module.exports = { parseArgs, printHelp, isKnownShell, getWindowsAncestors };
|
|
418
|
+
module.exports = { parseArgs, printHelp, isKnownShell, getWindowsAncestors, getDefaultShell };
|
package/src/cli/service.js
CHANGED
|
@@ -32,6 +32,7 @@ function findPm2() {
|
|
|
32
32
|
encoding: 'utf8',
|
|
33
33
|
stdio: ['pipe', 'pipe', 'ignore'],
|
|
34
34
|
timeout: 5000,
|
|
35
|
+
windowsHide: true,
|
|
35
36
|
});
|
|
36
37
|
return result.trim().split('\n')[0].trim();
|
|
37
38
|
} catch {
|
|
@@ -43,10 +44,13 @@ function installPm2Global() {
|
|
|
43
44
|
log.info('Installing PM2 globally');
|
|
44
45
|
console.log(yellow('\nInstalling PM2 globally...'));
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
+
const isWin = os.platform() === 'win32';
|
|
48
|
+
const cmd = isWin ? process.env.ComSpec || 'cmd.exe' : 'npm';
|
|
49
|
+
const cmdArgs = isWin ? ['/c', 'npm', 'install', '-g', 'pm2'] : ['install', '-g', 'pm2'];
|
|
50
|
+
execFileSync(cmd, cmdArgs, {
|
|
47
51
|
stdio: 'inherit',
|
|
48
52
|
timeout: 120000,
|
|
49
|
-
|
|
53
|
+
windowsHide: true,
|
|
50
54
|
});
|
|
51
55
|
console.log(green('✓ PM2 installed successfully.\n'));
|
|
52
56
|
return true;
|
|
@@ -141,13 +145,17 @@ function readEcosystemName() {
|
|
|
141
145
|
|
|
142
146
|
function pm2Exec(args, opts = {}) {
|
|
143
147
|
log.debug(`PM2 command: pm2 ${args.join(' ')}`);
|
|
148
|
+
const isWin = os.platform() === 'win32';
|
|
149
|
+
// Windows npm globals are .cmd wrappers — use cmd.exe /c to resolve them
|
|
150
|
+
// without shell:true (which triggers DEP0190 when combined with args).
|
|
151
|
+
const cmd = isWin ? process.env.ComSpec || 'cmd.exe' : 'pm2';
|
|
152
|
+
const cmdArgs = isWin ? ['/c', 'pm2', ...args] : args;
|
|
144
153
|
try {
|
|
145
|
-
return execFileSync(
|
|
154
|
+
return execFileSync(cmd, cmdArgs, {
|
|
146
155
|
encoding: 'utf8',
|
|
147
156
|
stdio: opts.inherit ? 'inherit' : ['pipe', 'pipe', 'pipe'],
|
|
148
157
|
timeout: 30000,
|
|
149
|
-
|
|
150
|
-
shell: os.platform() === 'win32',
|
|
158
|
+
windowsHide: true,
|
|
151
159
|
...opts,
|
|
152
160
|
});
|
|
153
161
|
} catch (err) {
|
|
@@ -347,8 +355,9 @@ async function actionInstall() {
|
|
|
347
355
|
config.cwd = await ask(rl, 'Working directory:', process.cwd());
|
|
348
356
|
decisions.push({ label: 'Directory', value: config.cwd });
|
|
349
357
|
|
|
350
|
-
// Shell —
|
|
351
|
-
|
|
358
|
+
// Shell — detect the actual shell the user is running from
|
|
359
|
+
const { getDefaultShell } = require('./index');
|
|
360
|
+
config.shell = getDefaultShell();
|
|
352
361
|
decisions.push({ label: 'Shell', value: config.shell });
|
|
353
362
|
|
|
354
363
|
// Log level
|
|
@@ -665,9 +674,13 @@ function actionLogs() {
|
|
|
665
674
|
process.exit(1);
|
|
666
675
|
}
|
|
667
676
|
const { spawn } = require('child_process');
|
|
668
|
-
const
|
|
677
|
+
const isWin = os.platform() === 'win32';
|
|
678
|
+
const cmd = isWin ? process.env.ComSpec || 'cmd.exe' : 'pm2';
|
|
679
|
+
const logsArgs = ['logs', readEcosystemName(), '--lines', '200'];
|
|
680
|
+
const cmdArgs = isWin ? ['/c', 'pm2', ...logsArgs] : logsArgs;
|
|
681
|
+
const child = spawn(cmd, cmdArgs, {
|
|
669
682
|
stdio: 'inherit',
|
|
670
|
-
|
|
683
|
+
windowsHide: true,
|
|
671
684
|
});
|
|
672
685
|
child.on('error', (err) => {
|
|
673
686
|
console.error(red(`✗ Failed to stream logs: ${err.message}`));
|
package/src/tunnel/index.js
CHANGED
|
@@ -106,6 +106,7 @@ function isLoggedIn() {
|
|
|
106
106
|
encoding: 'utf-8',
|
|
107
107
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
108
108
|
timeout: 10_000,
|
|
109
|
+
windowsHide: true,
|
|
109
110
|
});
|
|
110
111
|
return out && !out.toLowerCase().includes('not logged in');
|
|
111
112
|
} catch {
|
|
@@ -119,6 +120,7 @@ function getLoginInfo() {
|
|
|
119
120
|
encoding: 'utf-8',
|
|
120
121
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
121
122
|
timeout: 10_000,
|
|
123
|
+
windowsHide: true,
|
|
122
124
|
});
|
|
123
125
|
return parseLoginInfo(out);
|
|
124
126
|
} catch {
|
|
@@ -148,6 +150,7 @@ function deviceCodeLogin(cmd) {
|
|
|
148
150
|
return new Promise((resolve, reject) => {
|
|
149
151
|
const proc = spawn(cmd, ['user', 'login', '-e', '-d'], {
|
|
150
152
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
153
|
+
windowsHide: true,
|
|
151
154
|
});
|
|
152
155
|
|
|
153
156
|
let gotOutput = false;
|
|
@@ -197,7 +200,7 @@ function deviceCodeLogin(cmd) {
|
|
|
197
200
|
function findDevtunnel() {
|
|
198
201
|
// Try devtunnel directly
|
|
199
202
|
try {
|
|
200
|
-
execSync('devtunnel --version', { stdio: 'pipe' });
|
|
203
|
+
execSync('devtunnel --version', { stdio: 'pipe', windowsHide: true });
|
|
201
204
|
return 'devtunnel';
|
|
202
205
|
} catch {}
|
|
203
206
|
|
|
@@ -222,7 +225,7 @@ function findDevtunnel() {
|
|
|
222
225
|
);
|
|
223
226
|
if (fs.existsSync(homeBin)) {
|
|
224
227
|
try {
|
|
225
|
-
execFileSync(homeBin, ['--version'], { stdio: 'pipe' });
|
|
228
|
+
execFileSync(homeBin, ['--version'], { stdio: 'pipe', windowsHide: true });
|
|
226
229
|
return homeBin;
|
|
227
230
|
} catch {}
|
|
228
231
|
}
|
|
@@ -253,6 +256,7 @@ function isTunnelValid(id) {
|
|
|
253
256
|
execFileSync(devtunnelCmd, ['show', id, '--json'], {
|
|
254
257
|
encoding: 'utf-8',
|
|
255
258
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
259
|
+
windowsHide: true,
|
|
256
260
|
});
|
|
257
261
|
return true;
|
|
258
262
|
} catch {
|
|
@@ -273,7 +277,7 @@ function checkTunnelHealth() {
|
|
|
273
277
|
execFile(
|
|
274
278
|
devtunnelCmd,
|
|
275
279
|
['show', tunnelId],
|
|
276
|
-
{ encoding: 'utf-8', signal: abortCtrl.signal },
|
|
280
|
+
{ encoding: 'utf-8', signal: abortCtrl.signal, windowsHide: true },
|
|
277
281
|
(err, stdout) => {
|
|
278
282
|
clearTimeout(timer);
|
|
279
283
|
|
|
@@ -401,6 +405,7 @@ function killTunnelProc() {
|
|
|
401
405
|
execFileSync('taskkill', ['/pid', String(tunnelProc.pid), '/T', '/F'], {
|
|
402
406
|
stdio: 'pipe',
|
|
403
407
|
timeout: 5000,
|
|
408
|
+
windowsHide: true,
|
|
404
409
|
});
|
|
405
410
|
} catch {
|
|
406
411
|
/* best effort */
|
|
@@ -566,6 +571,7 @@ function scheduleRestart() {
|
|
|
566
571
|
function hostTunnel() {
|
|
567
572
|
const hostProc = spawn(devtunnelCmd, ['host', tunnelId], {
|
|
568
573
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
574
|
+
windowsHide: true,
|
|
569
575
|
});
|
|
570
576
|
tunnelProc = hostProc;
|
|
571
577
|
|
|
@@ -657,7 +663,11 @@ async function startTunnel(port, options = {}) {
|
|
|
657
663
|
if (!loggedIn) {
|
|
658
664
|
log.info('Logging in to DevTunnel with Microsoft Entra (recommended for long sessions)...');
|
|
659
665
|
try {
|
|
660
|
-
execFileSync(devtunnelCmd, ['user', 'login', '-e'], {
|
|
666
|
+
execFileSync(devtunnelCmd, ['user', 'login', '-e'], {
|
|
667
|
+
stdio: 'inherit',
|
|
668
|
+
timeout: 30000,
|
|
669
|
+
windowsHide: true,
|
|
670
|
+
});
|
|
661
671
|
} catch {
|
|
662
672
|
log.info('Browser login failed or unavailable, falling back to device code flow...');
|
|
663
673
|
log.info('A code will be displayed — open the URL on any device to authenticate.');
|
|
@@ -694,6 +704,7 @@ async function startTunnel(port, options = {}) {
|
|
|
694
704
|
}
|
|
695
705
|
const createOut = execFileSync(devtunnelCmd, ['create', '--expiration', '30d', '--json'], {
|
|
696
706
|
encoding: 'utf-8',
|
|
707
|
+
windowsHide: true,
|
|
697
708
|
});
|
|
698
709
|
const tunnelData = JSON.parse(createOut);
|
|
699
710
|
tunnelId = tunnelData.tunnel.tunnelId;
|
|
@@ -706,6 +717,7 @@ async function startTunnel(port, options = {}) {
|
|
|
706
717
|
// Ephemeral tunnel — create fresh, will be deleted on shutdown
|
|
707
718
|
const createOut = execFileSync(devtunnelCmd, ['create', '--expiration', '1d', '--json'], {
|
|
708
719
|
encoding: 'utf-8',
|
|
720
|
+
windowsHide: true,
|
|
709
721
|
});
|
|
710
722
|
const tunnelData = JSON.parse(createOut);
|
|
711
723
|
tunnelId = tunnelData.tunnel.tunnelId;
|
|
@@ -717,7 +729,7 @@ async function startTunnel(port, options = {}) {
|
|
|
717
729
|
execFileSync(
|
|
718
730
|
devtunnelCmd,
|
|
719
731
|
['port', 'create', tunnelId, '-p', String(port), '--protocol', 'http'],
|
|
720
|
-
{ stdio: 'pipe' },
|
|
732
|
+
{ stdio: 'pipe', windowsHide: true },
|
|
721
733
|
);
|
|
722
734
|
} catch {}
|
|
723
735
|
// Set tunnel access: public (anonymous) or private (owner-only via Microsoft login)
|
|
@@ -726,7 +738,7 @@ async function startTunnel(port, options = {}) {
|
|
|
726
738
|
execFileSync(
|
|
727
739
|
devtunnelCmd,
|
|
728
740
|
['access', 'create', tunnelId, '-p', String(port), '--anonymous'],
|
|
729
|
-
{ stdio: 'pipe' },
|
|
741
|
+
{ stdio: 'pipe', windowsHide: true },
|
|
730
742
|
);
|
|
731
743
|
} catch {}
|
|
732
744
|
log.info('Tunnel access: public (anonymous)');
|
|
@@ -735,6 +747,7 @@ async function startTunnel(port, options = {}) {
|
|
|
735
747
|
try {
|
|
736
748
|
execFileSync(devtunnelCmd, ['access', 'reset', tunnelId], {
|
|
737
749
|
stdio: 'pipe',
|
|
750
|
+
windowsHide: true,
|
|
738
751
|
});
|
|
739
752
|
} catch {}
|
|
740
753
|
log.info('Tunnel access: private (owner-only via Microsoft login)');
|
|
@@ -773,7 +786,11 @@ function cleanupTunnel() {
|
|
|
773
786
|
log.info('Tunnel host stopped (tunnel preserved for reuse)');
|
|
774
787
|
} else {
|
|
775
788
|
try {
|
|
776
|
-
execFileSync(devtunnelCmd, ['delete', id, '-f'], {
|
|
789
|
+
execFileSync(devtunnelCmd, ['delete', id, '-f'], {
|
|
790
|
+
stdio: 'pipe',
|
|
791
|
+
timeout: 10000,
|
|
792
|
+
windowsHide: true,
|
|
793
|
+
});
|
|
777
794
|
log.info('Tunnel cleaned up');
|
|
778
795
|
} catch {
|
|
779
796
|
/* best effort — tunnel will expire on its own */
|
package/src/tunnel/install.js
CHANGED
|
@@ -98,7 +98,7 @@ async function installDevtunnel() {
|
|
|
98
98
|
function findInstalledBinary() {
|
|
99
99
|
// Check PATH first
|
|
100
100
|
try {
|
|
101
|
-
execSync('devtunnel --version', { stdio: 'pipe', timeout: 10000 });
|
|
101
|
+
execSync('devtunnel --version', { stdio: 'pipe', timeout: 10000, windowsHide: true });
|
|
102
102
|
return 'devtunnel';
|
|
103
103
|
} catch {}
|
|
104
104
|
|
|
@@ -110,6 +110,7 @@ function findInstalledBinary() {
|
|
|
110
110
|
encoding: 'utf-8',
|
|
111
111
|
stdio: 'pipe',
|
|
112
112
|
timeout: 10000,
|
|
113
|
+
windowsHide: true,
|
|
113
114
|
})
|
|
114
115
|
.trim()
|
|
115
116
|
.split(/\r?\n/)[0];
|
|
@@ -130,7 +131,7 @@ function findInstalledBinary() {
|
|
|
130
131
|
const homeBin = path.join(os.homedir(), 'bin', getBinaryName());
|
|
131
132
|
if (fs.existsSync(homeBin)) {
|
|
132
133
|
try {
|
|
133
|
-
execFileSync(homeBin, ['--version'], { stdio: 'pipe', timeout: 10000 });
|
|
134
|
+
execFileSync(homeBin, ['--version'], { stdio: 'pipe', timeout: 10000, windowsHide: true });
|
|
134
135
|
return homeBin;
|
|
135
136
|
} catch {}
|
|
136
137
|
}
|
package/src/utils/agents.js
CHANGED
|
@@ -62,24 +62,29 @@ function tryDetectAgent(agent) {
|
|
|
62
62
|
let remaining = candidates.length;
|
|
63
63
|
|
|
64
64
|
for (const bin of candidates) {
|
|
65
|
-
child_process.execFile(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
65
|
+
child_process.execFile(
|
|
66
|
+
bin,
|
|
67
|
+
args,
|
|
68
|
+
{ timeout: 5000, encoding: 'utf8', windowsHide: true },
|
|
69
|
+
(err, stdout) => {
|
|
70
|
+
remaining--;
|
|
71
|
+
if (resolved) return;
|
|
72
|
+
if (!err) {
|
|
73
|
+
resolved = true;
|
|
74
|
+
const version = (stdout || '').trim().split('\n')[0] || 'unknown';
|
|
75
|
+
resolve({
|
|
76
|
+
id: agent.id,
|
|
77
|
+
name: agent.name,
|
|
78
|
+
cmd: agent.cmd,
|
|
79
|
+
args: agent.args || [],
|
|
80
|
+
icon: agent.icon,
|
|
81
|
+
version,
|
|
82
|
+
});
|
|
83
|
+
} else if (remaining === 0) {
|
|
84
|
+
resolve(null);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
);
|
|
83
88
|
}
|
|
84
89
|
});
|
|
85
90
|
}
|
package/src/utils/git.js
CHANGED
|
@@ -3,7 +3,9 @@ const path = require('path');
|
|
|
3
3
|
const log = require('./logger');
|
|
4
4
|
|
|
5
5
|
function git(cmd, cwd) {
|
|
6
|
-
return execSync(`git ${cmd}`, { cwd, stdio: 'pipe', timeout: 3000 })
|
|
6
|
+
return execSync(`git ${cmd}`, { cwd, stdio: 'pipe', timeout: 3000, windowsHide: true })
|
|
7
|
+
.toString()
|
|
8
|
+
.trim();
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
function getGitInfo(cwd) {
|
|
@@ -144,7 +146,7 @@ async function getGitRoot(cwd) {
|
|
|
144
146
|
require('child_process').execFile(
|
|
145
147
|
'git',
|
|
146
148
|
['rev-parse', '--show-toplevel'],
|
|
147
|
-
{ cwd, timeout: GIT_TIMEOUT },
|
|
149
|
+
{ cwd, timeout: GIT_TIMEOUT, windowsHide: true },
|
|
148
150
|
(err, stdout) => {
|
|
149
151
|
if (err) return reject(err);
|
|
150
152
|
resolve(stdout.trim());
|
|
@@ -167,6 +169,7 @@ async function gitAsync(args, cwd, options = {}) {
|
|
|
167
169
|
cwd,
|
|
168
170
|
timeout: options.timeout || GIT_TIMEOUT,
|
|
169
171
|
maxBuffer: options.maxBuffer || MAX_DIFF_BUFFER,
|
|
172
|
+
windowsHide: true,
|
|
170
173
|
},
|
|
171
174
|
(err, stdout) => {
|
|
172
175
|
if (err) return reject(err);
|
|
@@ -343,6 +346,7 @@ async function getFileDiff(cwd, filePath, options = {}) {
|
|
|
343
346
|
cwd: root,
|
|
344
347
|
timeout: GIT_TIMEOUT,
|
|
345
348
|
maxBuffer: MAX_DIFF_BUFFER,
|
|
349
|
+
windowsHide: true,
|
|
346
350
|
},
|
|
347
351
|
(err, stdout) => {
|
|
348
352
|
// git diff --no-index exits with 1 when files differ — that's expected
|
package/src/utils/shells.js
CHANGED
|
@@ -339,15 +339,20 @@ function clearUpdateResult() {
|
|
|
339
339
|
|
|
340
340
|
function execFilePromise(cmd, args, options = {}) {
|
|
341
341
|
return new Promise((resolve, reject) => {
|
|
342
|
-
execFile(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
342
|
+
execFile(
|
|
343
|
+
cmd,
|
|
344
|
+
args,
|
|
345
|
+
{ encoding: 'utf8', windowsHide: true, ...options },
|
|
346
|
+
(err, stdout, stderr) => {
|
|
347
|
+
if (err) {
|
|
348
|
+
err.stdout = stdout;
|
|
349
|
+
err.stderr = stderr;
|
|
350
|
+
reject(err);
|
|
351
|
+
} else {
|
|
352
|
+
resolve({ stdout, stderr });
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
);
|
|
351
356
|
});
|
|
352
357
|
}
|
|
353
358
|
|
package/src/utils/version.js
CHANGED