start-command 0.23.0 → 0.24.0
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 +24 -0
- package/package.json +1 -1
- package/src/lib/isolation.js +35 -34
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# start-command
|
|
2
2
|
|
|
3
|
+
## 0.24.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2ea7f43: feat: Use interactive shell mode in isolation environments to source startup files
|
|
8
|
+
|
|
9
|
+
In docker and ssh isolation environments, bash and zsh are now invoked with
|
|
10
|
+
the `-i` (interactive) flag when executing commands. This ensures that startup
|
|
11
|
+
files like `.bashrc` and `.zshrc` are sourced, making environment-dependent
|
|
12
|
+
tools like `nvm`, `rbenv`, `pyenv`, and similar version managers available
|
|
13
|
+
in isolated commands.
|
|
14
|
+
|
|
15
|
+
Previously, even though bash was correctly detected and used over sh, running
|
|
16
|
+
`nvm --version` in a Docker container would fail with "command not found"
|
|
17
|
+
because bash was started in non-interactive mode and did not source `.bashrc`.
|
|
18
|
+
|
|
19
|
+
With this fix:
|
|
20
|
+
- Docker: `docker run <image> bash -i -c "nvm --version"` sources `.bashrc`
|
|
21
|
+
- SSH: `ssh <host> bash -i -c "nvm --version"` sources `.bashrc` on the remote host
|
|
22
|
+
- `zsh` also gets the `-i` flag for the same reason
|
|
23
|
+
- `sh` does not get `-i` as it is used as a fallback for minimal containers
|
|
24
|
+
|
|
25
|
+
Fixes #79
|
|
26
|
+
|
|
3
27
|
## 0.23.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/package.json
CHANGED
package/src/lib/isolation.js
CHANGED
|
@@ -211,6 +211,12 @@ function detectShellInEnvironment(
|
|
|
211
211
|
return 'sh';
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/** Returns "-i" for bash/zsh (enables .bashrc sourcing), null otherwise. */
|
|
215
|
+
function getShellInteractiveFlag(shellPath) {
|
|
216
|
+
const shellName = shellPath.split('/').pop();
|
|
217
|
+
return shellName === 'bash' || shellName === 'zsh' ? '-i' : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
214
220
|
/**
|
|
215
221
|
* Check if the current process has a TTY attached
|
|
216
222
|
* @returns {boolean} True if TTY is available
|
|
@@ -648,30 +654,31 @@ function runInSsh(command, options = {}) {
|
|
|
648
654
|
const sessionName = options.session || generateSessionName('ssh');
|
|
649
655
|
const sshTarget = options.endpoint;
|
|
650
656
|
|
|
651
|
-
// Detect the shell to use on the remote host
|
|
652
|
-
// In auto mode, detection may fall back to passing command directly to leverage
|
|
653
|
-
// the remote user's default login shell (which may already be bash)
|
|
654
657
|
const shellToUse = detectShellInEnvironment('ssh', options, options.shell);
|
|
655
|
-
//
|
|
658
|
+
// In auto mode, SSH login shells already source startup files (.bashrc etc.);
|
|
659
|
+
// only wrap with an explicit shell when user requests one.
|
|
656
660
|
const useExplicitShell =
|
|
657
661
|
options.shell && options.shell !== 'auto' ? shellToUse : null;
|
|
662
|
+
const shellInteractiveFlag = useExplicitShell
|
|
663
|
+
? getShellInteractiveFlag(useExplicitShell)
|
|
664
|
+
: null;
|
|
658
665
|
|
|
659
666
|
try {
|
|
660
667
|
if (options.detached) {
|
|
661
|
-
// Detached mode: Run command in background
|
|
662
|
-
// The command will continue running even after SSH connection closes
|
|
668
|
+
// Detached mode: Run command in background via nohup; continues after SSH closes
|
|
663
669
|
const remoteShell = useExplicitShell || shellToUse;
|
|
664
|
-
const
|
|
670
|
+
const shellInvocation = shellInteractiveFlag
|
|
671
|
+
? `${remoteShell} ${shellInteractiveFlag}`
|
|
672
|
+
: remoteShell;
|
|
673
|
+
const remoteCommand = `nohup ${shellInvocation} -c ${JSON.stringify(command)} > /tmp/${sessionName}.log 2>&1 &`;
|
|
665
674
|
const sshArgs = [sshTarget, remoteCommand];
|
|
666
675
|
|
|
667
676
|
if (DEBUG) {
|
|
668
677
|
console.log(`[DEBUG] Running: ssh ${sshArgs.join(' ')}`);
|
|
669
|
-
console.log(`[DEBUG] shell: ${
|
|
678
|
+
console.log(`[DEBUG] shell: ${shellInvocation}`);
|
|
670
679
|
}
|
|
671
680
|
|
|
672
|
-
const result = spawnSync('ssh', sshArgs, {
|
|
673
|
-
stdio: 'inherit',
|
|
674
|
-
});
|
|
681
|
+
const result = spawnSync('ssh', sshArgs, { stdio: 'inherit' });
|
|
675
682
|
|
|
676
683
|
if (result.error) {
|
|
677
684
|
throw result.error;
|
|
@@ -683,11 +690,10 @@ function runInSsh(command, options = {}) {
|
|
|
683
690
|
message: `Command started in detached SSH session on ${sshTarget}\nSession: ${sessionName}\nView logs: ssh ${sshTarget} "tail -f /tmp/${sessionName}.log"`,
|
|
684
691
|
});
|
|
685
692
|
} else {
|
|
686
|
-
// Attached mode:
|
|
687
|
-
|
|
688
|
-
// In auto mode, pass the command directly and let the remote's default shell handle it.
|
|
693
|
+
// Attached mode: pass command directly (auto) or wrap with explicit shell + -i flag (bash/zsh).
|
|
694
|
+
const extraFlags = shellInteractiveFlag ? [shellInteractiveFlag] : [];
|
|
689
695
|
const sshArgs = useExplicitShell
|
|
690
|
-
? [sshTarget, useExplicitShell, '-c', command]
|
|
696
|
+
? [sshTarget, useExplicitShell, ...extraFlags, '-c', command]
|
|
691
697
|
: [sshTarget, command];
|
|
692
698
|
|
|
693
699
|
if (DEBUG) {
|
|
@@ -769,8 +775,8 @@ function runInDocker(command, options = {}) {
|
|
|
769
775
|
}
|
|
770
776
|
}
|
|
771
777
|
|
|
772
|
-
// Detect the shell to use in the container
|
|
773
778
|
const shellToUse = detectShellInEnvironment('docker', options, options.shell);
|
|
779
|
+
const shellInteractiveFlag = getShellInteractiveFlag(shellToUse);
|
|
774
780
|
|
|
775
781
|
// Print the user command (this appears after any virtual commands like docker pull)
|
|
776
782
|
const { createCommandLine } = require('./output-blocks');
|
|
@@ -780,20 +786,12 @@ function runInDocker(command, options = {}) {
|
|
|
780
786
|
try {
|
|
781
787
|
if (options.detached) {
|
|
782
788
|
// Detached mode: docker run -d --name <name> [--user <user>] <image> <shell> -c '<command>'
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
if (options.keepAlive) {
|
|
788
|
-
// With keep-alive: run command, then keep shell alive
|
|
789
|
-
effectiveCommand = `${command}; exec ${shellToUse}`;
|
|
790
|
-
}
|
|
791
|
-
// Without keep-alive: container exits naturally when command completes
|
|
792
|
-
|
|
789
|
+
const effectiveCommand = options.keepAlive
|
|
790
|
+
? `${command}; exec ${shellToUse}`
|
|
791
|
+
: command;
|
|
793
792
|
const dockerArgs = ['run', '-d', '--name', containerName];
|
|
794
793
|
|
|
795
|
-
//
|
|
796
|
-
// Note: --rm must come before the image name
|
|
794
|
+
// --rm must come before the image name
|
|
797
795
|
if (options.autoRemoveDockerContainer) {
|
|
798
796
|
dockerArgs.splice(2, 0, '--rm');
|
|
799
797
|
}
|
|
@@ -803,7 +801,10 @@ function runInDocker(command, options = {}) {
|
|
|
803
801
|
dockerArgs.push('--user', options.user);
|
|
804
802
|
}
|
|
805
803
|
|
|
806
|
-
|
|
804
|
+
const shellArgs = shellInteractiveFlag
|
|
805
|
+
? [shellToUse, shellInteractiveFlag]
|
|
806
|
+
: [shellToUse];
|
|
807
|
+
dockerArgs.push(options.image, ...shellArgs, '-c', effectiveCommand);
|
|
807
808
|
|
|
808
809
|
if (DEBUG) {
|
|
809
810
|
console.log(`[DEBUG] Running: docker ${dockerArgs.join(' ')}`);
|
|
@@ -840,19 +841,19 @@ function runInDocker(command, options = {}) {
|
|
|
840
841
|
message,
|
|
841
842
|
});
|
|
842
843
|
} else {
|
|
843
|
-
// Attached mode: docker run -it --name <name> [--user <user>] <image> <shell> -c '<
|
|
844
|
+
// Attached mode: docker run -it --rm --name <name> [--user <user>] <image> <shell> -c '<cmd>'
|
|
844
845
|
const dockerArgs = ['run', '-it', '--rm', '--name', containerName];
|
|
845
|
-
|
|
846
|
-
// Add --user flag if specified
|
|
847
846
|
if (options.user) {
|
|
848
847
|
dockerArgs.push('--user', options.user);
|
|
849
848
|
}
|
|
850
|
-
|
|
851
849
|
if (DEBUG) {
|
|
852
850
|
console.log(`[DEBUG] shell: ${shellToUse}`);
|
|
853
851
|
}
|
|
854
852
|
|
|
855
|
-
|
|
853
|
+
const shellCmdArgs = shellInteractiveFlag
|
|
854
|
+
? [shellToUse, shellInteractiveFlag]
|
|
855
|
+
: [shellToUse];
|
|
856
|
+
dockerArgs.push(options.image, ...shellCmdArgs, '-c', command);
|
|
856
857
|
|
|
857
858
|
if (DEBUG) {
|
|
858
859
|
console.log(`[DEBUG] Running: docker ${dockerArgs.join(' ')}`);
|