start-command 0.10.0 → 0.13.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/.github/workflows/release.yml +52 -0
- package/CHANGELOG.md +24 -0
- package/README.md +12 -7
- package/bun.lock +5 -0
- package/experiments/test-command-stream-cjs.cjs +30 -0
- package/experiments/test-command-stream-wrapper.js +54 -0
- package/experiments/test-command-stream.mjs +56 -0
- package/package.json +4 -1
- package/src/bin/cli.js +175 -392
- package/src/lib/args-parser.js +41 -3
- package/src/lib/command-stream.js +258 -0
- package/src/lib/failure-handler.js +397 -0
- package/src/lib/isolation.js +97 -1
- package/test/args-parser.test.js +91 -1
- package/test/isolation.test.js +40 -0
- package/test/ssh-integration.test.js +328 -0
|
@@ -122,6 +122,58 @@ jobs:
|
|
|
122
122
|
- name: Run tests
|
|
123
123
|
run: bun test
|
|
124
124
|
|
|
125
|
+
# Test both execution modes (default and command-stream)
|
|
126
|
+
- name: Test default execution mode
|
|
127
|
+
run: |
|
|
128
|
+
bun run src/bin/cli.js echo "Testing default mode"
|
|
129
|
+
echo "Default mode test passed"
|
|
130
|
+
|
|
131
|
+
- name: Test command-stream execution mode
|
|
132
|
+
run: |
|
|
133
|
+
bun run src/bin/cli.js --use-command-stream echo "Testing command-stream mode"
|
|
134
|
+
echo "Command-stream mode test passed"
|
|
135
|
+
|
|
136
|
+
- name: Test command-stream via env variable
|
|
137
|
+
env:
|
|
138
|
+
START_USE_COMMAND_STREAM: '1'
|
|
139
|
+
run: |
|
|
140
|
+
bun run src/bin/cli.js echo "Testing env var mode"
|
|
141
|
+
echo "Env var mode test passed"
|
|
142
|
+
|
|
143
|
+
# SSH Integration Tests - Linux only (most reliable for SSH testing)
|
|
144
|
+
- name: Setup SSH server for integration tests (Linux)
|
|
145
|
+
if: runner.os == 'Linux'
|
|
146
|
+
run: |
|
|
147
|
+
# Install openssh-server if not present
|
|
148
|
+
sudo apt-get install -y openssh-server
|
|
149
|
+
|
|
150
|
+
# Start SSH service
|
|
151
|
+
sudo systemctl start ssh
|
|
152
|
+
|
|
153
|
+
# Generate SSH key without passphrase for testing
|
|
154
|
+
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "ci-test-key"
|
|
155
|
+
|
|
156
|
+
# Add the public key to authorized_keys for passwordless login
|
|
157
|
+
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
|
|
158
|
+
chmod 600 ~/.ssh/authorized_keys
|
|
159
|
+
|
|
160
|
+
# Configure SSH to accept localhost connections without prompts
|
|
161
|
+
mkdir -p ~/.ssh
|
|
162
|
+
cat >> ~/.ssh/config << 'EOF'
|
|
163
|
+
Host localhost
|
|
164
|
+
StrictHostKeyChecking no
|
|
165
|
+
UserKnownHostsFile /dev/null
|
|
166
|
+
LogLevel ERROR
|
|
167
|
+
EOF
|
|
168
|
+
chmod 600 ~/.ssh/config
|
|
169
|
+
|
|
170
|
+
# Test SSH connectivity
|
|
171
|
+
ssh localhost "echo 'SSH connection successful'"
|
|
172
|
+
|
|
173
|
+
- name: Run SSH integration tests (Linux)
|
|
174
|
+
if: runner.os == 'Linux'
|
|
175
|
+
run: bun test test/ssh-integration.test.js
|
|
176
|
+
|
|
125
177
|
# Release - only runs on main after tests pass (for push events)
|
|
126
178
|
release:
|
|
127
179
|
name: Release
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# start-command
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7763ae1: Use command-stream library for command execution in CLI
|
|
8
|
+
|
|
9
|
+
This update integrates the command-stream library to handle command execution, replacing direct usage of execSync and spawnSync in the main CLI flow. The change provides a more consistent API for running shell commands and better output handling.
|
|
10
|
+
|
|
11
|
+
Key changes:
|
|
12
|
+
- Added command-stream as a dependency
|
|
13
|
+
- Created a wrapper module for async command execution utilities
|
|
14
|
+
- Refactored printVersion(), runDirect(), and detectRepository() to use command-stream
|
|
15
|
+
- Converted main CLI flow to async for proper integration
|
|
16
|
+
|
|
17
|
+
## 0.11.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 1240a29: Add SSH isolation support for remote command execution.
|
|
22
|
+
- Implements SSH backend for executing commands on remote servers via SSH, similar to screen/tmux/docker isolation
|
|
23
|
+
- Uses `--endpoint` option to specify SSH target (e.g., `--endpoint user@remote.server`)
|
|
24
|
+
- Supports both attached (interactive) and detached (background) modes
|
|
25
|
+
- Includes comprehensive SSH integration tests in CI with a local SSH server
|
|
26
|
+
|
|
3
27
|
## 0.10.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -136,7 +136,7 @@ Issue created: https://github.com/owner/some-npm-tool/issues/42
|
|
|
136
136
|
|
|
137
137
|
### Process Isolation
|
|
138
138
|
|
|
139
|
-
Run commands in isolated environments using terminal multiplexers or
|
|
139
|
+
Run commands in isolated environments using terminal multiplexers, containers, or remote servers:
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
# Run in tmux (attached by default)
|
|
@@ -148,6 +148,9 @@ $ --isolated screen --detached -- bun start
|
|
|
148
148
|
# Run in docker container
|
|
149
149
|
$ --isolated docker --image oven/bun:latest -- bun install
|
|
150
150
|
|
|
151
|
+
# Run on remote server via SSH
|
|
152
|
+
$ --isolated ssh --endpoint user@remote.server -- npm test
|
|
153
|
+
|
|
151
154
|
# Short form with custom session name
|
|
152
155
|
$ -i tmux -s my-session -d bun start
|
|
153
156
|
```
|
|
@@ -192,21 +195,23 @@ This is useful for:
|
|
|
192
195
|
|
|
193
196
|
#### Supported Backends
|
|
194
197
|
|
|
195
|
-
| Backend | Description
|
|
196
|
-
| -------- |
|
|
197
|
-
| `screen` | GNU Screen terminal multiplexer
|
|
198
|
-
| `tmux` | Modern terminal multiplexer
|
|
199
|
-
| `docker` | Container isolation (requires --image)
|
|
198
|
+
| Backend | Description | Installation |
|
|
199
|
+
| -------- | ---------------------------------------------- | ---------------------------------------------------------- |
|
|
200
|
+
| `screen` | GNU Screen terminal multiplexer | `apt install screen` / `brew install screen` |
|
|
201
|
+
| `tmux` | Modern terminal multiplexer | `apt install tmux` / `brew install tmux` |
|
|
202
|
+
| `docker` | Container isolation (requires --image) | [Docker Installation](https://docs.docker.com/get-docker/) |
|
|
203
|
+
| `ssh` | Remote execution via SSH (requires --endpoint) | `apt install openssh-client` / `brew install openssh` |
|
|
200
204
|
|
|
201
205
|
#### Isolation Options
|
|
202
206
|
|
|
203
207
|
| Option | Description |
|
|
204
208
|
| -------------------------------- | --------------------------------------------------------- |
|
|
205
|
-
| `--isolated, -i` | Isolation backend (screen, tmux, docker)
|
|
209
|
+
| `--isolated, -i` | Isolation backend (screen, tmux, docker, ssh) |
|
|
206
210
|
| `--attached, -a` | Run in attached/foreground mode (default) |
|
|
207
211
|
| `--detached, -d` | Run in detached/background mode |
|
|
208
212
|
| `--session, -s` | Custom session/container name |
|
|
209
213
|
| `--image` | Docker image (required for docker isolation) |
|
|
214
|
+
| `--endpoint` | SSH endpoint (required for ssh, e.g., user@host) |
|
|
210
215
|
| `--isolated-user, -u [name]` | Create isolated user with same permissions (screen/tmux) |
|
|
211
216
|
| `--keep-user` | Keep isolated user after command completes (don't delete) |
|
|
212
217
|
| `--keep-alive, -k` | Keep session alive after command completes |
|
package/bun.lock
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
"workspaces": {
|
|
5
5
|
"": {
|
|
6
6
|
"name": "start-command",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"command-stream": "^0.8.3",
|
|
9
|
+
},
|
|
7
10
|
"devDependencies": {
|
|
8
11
|
"@changesets/cli": "^2.29.7",
|
|
9
12
|
"eslint": "^9.38.0",
|
|
@@ -142,6 +145,8 @@
|
|
|
142
145
|
|
|
143
146
|
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
|
|
144
147
|
|
|
148
|
+
"command-stream": ["command-stream@0.8.3", "", {}, "sha512-vwNf5AWLhD4awaYSIyjHEu7JrAMTu8BaJg1LIpE4HqTXFYtgzSTN/j1VnwHDTNz8sAG7zvZgtKYm9lmi4+0Z7Q=="],
|
|
149
|
+
|
|
145
150
|
"commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="],
|
|
146
151
|
|
|
147
152
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/* global console */
|
|
3
|
+
/**
|
|
4
|
+
* Experiment: Test command-stream with CommonJS require
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
(async () => {
|
|
8
|
+
console.log(
|
|
9
|
+
'=== Testing command-stream with dynamic import in CommonJS ===\n'
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
// Need to use dynamic import since command-stream is ESM
|
|
13
|
+
const { $ } = await import('command-stream');
|
|
14
|
+
|
|
15
|
+
// Test 1: Basic sync command
|
|
16
|
+
console.log('Test 1: Basic sync command');
|
|
17
|
+
const result1 = $`echo "Hello from CJS"`.sync();
|
|
18
|
+
console.log('stdout:', result1.stdout);
|
|
19
|
+
console.log('exit code:', result1.code);
|
|
20
|
+
console.log('');
|
|
21
|
+
|
|
22
|
+
// Test 2: which command
|
|
23
|
+
console.log('Test 2: which command');
|
|
24
|
+
const result2 = $`which echo`.sync();
|
|
25
|
+
console.log('stdout:', result2.stdout.trim());
|
|
26
|
+
console.log('exit code:', result2.code);
|
|
27
|
+
console.log('');
|
|
28
|
+
|
|
29
|
+
console.log('=== All tests completed ===');
|
|
30
|
+
})();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Experiment: Test command-stream wrapper module
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
execCommand,
|
|
8
|
+
execCommandAsync,
|
|
9
|
+
commandExists,
|
|
10
|
+
getCommandPath,
|
|
11
|
+
getToolVersion,
|
|
12
|
+
} = require('../src/lib/command-stream');
|
|
13
|
+
|
|
14
|
+
(async () => {
|
|
15
|
+
console.log('=== Testing command-stream wrapper ===\n');
|
|
16
|
+
|
|
17
|
+
// Test 1: Basic sync command
|
|
18
|
+
console.log('Test 1: execCommand (sync-like via promise)');
|
|
19
|
+
const result1 = await execCommand('echo "Hello from wrapper"');
|
|
20
|
+
console.log('stdout:', result1.stdout);
|
|
21
|
+
console.log('code:', result1.code);
|
|
22
|
+
console.log('');
|
|
23
|
+
|
|
24
|
+
// Test 2: Check if command exists
|
|
25
|
+
console.log('Test 2: commandExists');
|
|
26
|
+
const hasScreen = await commandExists('screen');
|
|
27
|
+
const hasFakeCmd = await commandExists('nonexistent-command-xyz');
|
|
28
|
+
console.log('screen exists:', hasScreen);
|
|
29
|
+
console.log('nonexistent-command-xyz exists:', hasFakeCmd);
|
|
30
|
+
console.log('');
|
|
31
|
+
|
|
32
|
+
// Test 3: Get command path
|
|
33
|
+
console.log('Test 3: getCommandPath');
|
|
34
|
+
const echoPath = await getCommandPath('echo');
|
|
35
|
+
console.log('echo path:', echoPath);
|
|
36
|
+
console.log('');
|
|
37
|
+
|
|
38
|
+
// Test 4: Get tool version
|
|
39
|
+
console.log('Test 4: getToolVersion');
|
|
40
|
+
const screenVersion = await getToolVersion('screen', '-v', true);
|
|
41
|
+
console.log('screen version:', screenVersion);
|
|
42
|
+
const tmuxVersion = await getToolVersion('tmux', '-V', true);
|
|
43
|
+
console.log('tmux version:', tmuxVersion);
|
|
44
|
+
console.log('');
|
|
45
|
+
|
|
46
|
+
// Test 5: Async command
|
|
47
|
+
console.log('Test 5: execCommandAsync');
|
|
48
|
+
const result5 = await execCommandAsync('uname -r');
|
|
49
|
+
console.log('stdout:', result5.stdout);
|
|
50
|
+
console.log('code:', result5.code);
|
|
51
|
+
console.log('');
|
|
52
|
+
|
|
53
|
+
console.log('=== All tests completed ===');
|
|
54
|
+
})();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Experiment: Test command-stream basic usage
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { $ } from 'command-stream';
|
|
7
|
+
|
|
8
|
+
console.log('=== Testing command-stream ===\n');
|
|
9
|
+
|
|
10
|
+
// Test 1: Basic async command
|
|
11
|
+
console.log('Test 1: Basic async command');
|
|
12
|
+
const result1 = await $`echo "Hello from command-stream"`;
|
|
13
|
+
console.log('stdout:', result1.stdout);
|
|
14
|
+
console.log('exit code:', result1.code);
|
|
15
|
+
console.log('');
|
|
16
|
+
|
|
17
|
+
// Test 2: Sync command
|
|
18
|
+
console.log('Test 2: Sync command');
|
|
19
|
+
const result2 = $`echo "Sync hello"`.sync();
|
|
20
|
+
console.log('stdout:', result2.stdout);
|
|
21
|
+
console.log('exit code:', result2.code);
|
|
22
|
+
console.log('');
|
|
23
|
+
|
|
24
|
+
// Test 3: Command that uses system tools
|
|
25
|
+
console.log('Test 3: which command');
|
|
26
|
+
try {
|
|
27
|
+
const result3 = $`which echo`.sync();
|
|
28
|
+
console.log('stdout:', result3.stdout);
|
|
29
|
+
console.log('exit code:', result3.code);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.log('Error:', e.message);
|
|
32
|
+
}
|
|
33
|
+
console.log('');
|
|
34
|
+
|
|
35
|
+
// Test 4: Get OS version on Linux
|
|
36
|
+
console.log('Test 4: uname command');
|
|
37
|
+
const result4 = $`uname -r`.sync();
|
|
38
|
+
console.log('stdout:', result4.stdout.trim());
|
|
39
|
+
console.log('exit code:', result4.code);
|
|
40
|
+
console.log('');
|
|
41
|
+
|
|
42
|
+
// Test 5: Silent mode (no mirror)
|
|
43
|
+
console.log('Test 5: Silent mode with $({ mirror: false })');
|
|
44
|
+
const $silent = $({ mirror: false, capture: true });
|
|
45
|
+
const result5 = await $silent`echo "This should be silent"`;
|
|
46
|
+
console.log('stdout:', result5.stdout);
|
|
47
|
+
console.log('');
|
|
48
|
+
|
|
49
|
+
// Test 6: Check if command exists
|
|
50
|
+
console.log('Test 6: Check if screen exists');
|
|
51
|
+
const result6 = $`which screen`.sync();
|
|
52
|
+
console.log('screen exists:', result6.code === 0);
|
|
53
|
+
console.log('screen path:', result6.stdout.trim());
|
|
54
|
+
console.log('');
|
|
55
|
+
|
|
56
|
+
console.log('=== All tests completed ===');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "start-command",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Gamification of coding, execute any command with ability to auto-report issues on GitHub",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -59,5 +59,8 @@
|
|
|
59
59
|
"prettier --write",
|
|
60
60
|
"prettier --check"
|
|
61
61
|
]
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"command-stream": "^0.8.3"
|
|
62
65
|
}
|
|
63
66
|
}
|