start-command 0.13.0 → 0.16.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +34 -227
  2. package/bun.lock +5 -0
  3. package/eslint.config.mjs +1 -1
  4. package/package.json +11 -6
  5. package/src/bin/cli.js +332 -171
  6. package/src/lib/args-parser.js +118 -0
  7. package/src/lib/execution-store.js +722 -0
  8. package/src/lib/isolation.js +51 -0
  9. package/src/lib/output-blocks.js +357 -0
  10. package/src/lib/status-formatter.js +148 -0
  11. package/src/lib/version.js +143 -0
  12. package/test/args-parser.test.js +107 -0
  13. package/test/cli.test.js +11 -1
  14. package/test/docker-autoremove.test.js +11 -16
  15. package/test/execution-store.test.js +483 -0
  16. package/test/isolation-cleanup.test.js +11 -16
  17. package/test/isolation.test.js +11 -17
  18. package/test/output-blocks.test.js +197 -0
  19. package/test/public-exports.test.js +105 -0
  20. package/test/status-query.test.js +197 -0
  21. package/.github/workflows/release.yml +0 -352
  22. package/.husky/pre-commit +0 -1
  23. package/ARCHITECTURE.md +0 -297
  24. package/LICENSE +0 -24
  25. package/README.md +0 -339
  26. package/REQUIREMENTS.md +0 -299
  27. package/docs/PIPES.md +0 -243
  28. package/docs/USAGE.md +0 -194
  29. package/docs/case-studies/issue-15/README.md +0 -208
  30. package/docs/case-studies/issue-18/README.md +0 -343
  31. package/docs/case-studies/issue-18/issue-comments.json +0 -1
  32. package/docs/case-studies/issue-18/issue-data.json +0 -7
  33. package/docs/case-studies/issue-22/analysis.md +0 -547
  34. package/docs/case-studies/issue-22/issue-data.json +0 -12
  35. package/docs/case-studies/issue-25/README.md +0 -232
  36. package/docs/case-studies/issue-25/issue-data.json +0 -21
  37. package/docs/case-studies/issue-28/README.md +0 -405
  38. package/docs/case-studies/issue-28/issue-data.json +0 -105
  39. package/docs/case-studies/issue-28/raw-issue-data.md +0 -92
  40. package/experiments/debug-regex.js +0 -49
  41. package/experiments/isolation-design.md +0 -131
  42. package/experiments/screen-output-test.js +0 -265
  43. package/experiments/test-cli.sh +0 -42
  44. package/experiments/test-command-stream-cjs.cjs +0 -30
  45. package/experiments/test-command-stream-wrapper.js +0 -54
  46. package/experiments/test-command-stream.mjs +0 -56
  47. package/experiments/test-screen-attached.js +0 -126
  48. package/experiments/test-screen-logfile.js +0 -286
  49. package/experiments/test-screen-modes.js +0 -128
  50. package/experiments/test-screen-output.sh +0 -27
  51. package/experiments/test-screen-tee-debug.js +0 -237
  52. package/experiments/test-screen-tee-fallback.js +0 -230
  53. package/experiments/test-substitution.js +0 -143
  54. package/experiments/user-isolation-research.md +0 -83
  55. package/scripts/changeset-version.mjs +0 -38
  56. package/scripts/check-file-size.mjs +0 -103
  57. package/scripts/create-github-release.mjs +0 -93
  58. package/scripts/create-manual-changeset.mjs +0 -89
  59. package/scripts/format-github-release.mjs +0 -83
  60. package/scripts/format-release-notes.mjs +0 -219
  61. package/scripts/instant-version-bump.mjs +0 -121
  62. package/scripts/publish-to-npm.mjs +0 -129
  63. package/scripts/setup-npm.mjs +0 -37
  64. package/scripts/validate-changeset.mjs +0 -107
  65. package/scripts/version-and-commit.mjs +0 -237
@@ -1,105 +0,0 @@
1
- {
2
- "issue": {
3
- "number": 28,
4
- "title": "Can we somehow overcome the need of `'` quotes with `|` and `\"` in a sequence?",
5
- "url": "https://github.com/link-foundation/start/issues/28",
6
- "state": "open",
7
- "labels": ["bug", "documentation", "enhancement", "question"],
8
- "author": "konard",
9
- "created_at": "2025-12-24"
10
- },
11
- "environment": {
12
- "platform": "darwin",
13
- "shell": "/bin/zsh",
14
- "bun_version": "1.2.20",
15
- "working_directory": "/Users/konard"
16
- },
17
- "scenarios": [
18
- {
19
- "name": "unquoted_command",
20
- "input": "$ echo \"hi\" | agent",
21
- "timestamp": "2025-12-24 15:07:08.894",
22
- "shell_interpretation": {
23
- "command_1": "$ echo \"hi\"",
24
- "operator": "|",
25
- "command_2": "agent"
26
- },
27
- "actual_execution": {
28
- "start_command_received": "echo \"hi\"",
29
- "start_command_output": "hi",
30
- "agent_received": "JSON output from start-command stdout"
31
- },
32
- "user_expectation": "agent should receive 'hi' from echo",
33
- "actual_result": "agent received start-command JSON output",
34
- "exit_code": 0
35
- },
36
- {
37
- "name": "quoted_command",
38
- "input": "$ 'echo \"hi\" | agent'",
39
- "timestamp": "2025-12-24 15:07:33.420",
40
- "shell_interpretation": {
41
- "command": "$",
42
- "argument": "echo \"hi\" | agent"
43
- },
44
- "actual_execution": {
45
- "start_command_received": "echo \"hi\" | agent",
46
- "pipeline_executed": true,
47
- "echo_output": "hi",
48
- "agent_received": "hi"
49
- },
50
- "user_expectation": "agent should receive 'hi' from echo",
51
- "actual_result": "agent received 'hi' from echo",
52
- "exit_code": 0
53
- }
54
- ],
55
- "root_cause": {
56
- "category": "shell_parsing_behavior",
57
- "is_bug": false,
58
- "description": "The pipe operator (|) is a shell metacharacter that is parsed by the shell before command arguments are passed. This is standard POSIX shell behavior, not a bug in start-command.",
59
- "affected_shells": ["bash", "zsh", "sh", "dash", "ksh"],
60
- "shell_parsing_order": [
61
- "1. Tokenization - command line split into tokens",
62
- "2. Operator recognition - | && || ; & recognized as metacharacters",
63
- "3. Command grouping - commands grouped based on operators",
64
- "4. Quote processing - quoted strings preserved",
65
- "5. Expansion - variables, commands, etc. expanded"
66
- ]
67
- },
68
- "solutions": {
69
- "recommended": "documentation_enhancement",
70
- "options": [
71
- {
72
- "id": "documentation_enhancement",
73
- "name": "Documentation Enhancement",
74
- "description": "Add clear documentation about quoting requirements",
75
- "pros": ["No code changes", "Educates users", "POSIX compliant"],
76
- "cons": ["Requires users to learn quoting rules"],
77
- "complexity": "low"
78
- },
79
- {
80
- "id": "warning_detection",
81
- "name": "Optional Warning Detection",
82
- "description": "Detect when stdout is piped and emit helpful warning",
83
- "pros": ["Helps users understand behavior", "Non-breaking"],
84
- "cons": ["May add noise to output"],
85
- "complexity": "medium"
86
- },
87
- {
88
- "id": "here_document",
89
- "name": "Here-Document Wrapper",
90
- "description": "Support $$ <<'CMD' syntax for multi-line commands",
91
- "pros": ["No quoting issues", "Clear syntax"],
92
- "cons": ["More verbose", "New syntax to learn"],
93
- "complexity": "high"
94
- }
95
- ]
96
- },
97
- "references": {
98
- "bash_manual": "https://www.gnu.org/software/bash/manual/bash.html",
99
- "pipelines_doc": "https://www.gnu.org/software/bash/manual/html_node/Pipelines.html",
100
- "quoting_doc": "https://www.gnu.org/software/bash/manual/html_node/Quoting.html",
101
- "posix_shell": "https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html"
102
- },
103
- "analysis_date": "2025-12-24",
104
- "analyst": "AI Issue Solver"
105
- }
@@ -1,92 +0,0 @@
1
- # Issue #28 Raw Data
2
-
3
- ## Issue Title
4
-
5
- Can we somehow overcome the need of `'` quotes with `|` and `"` in a sequence?
6
-
7
- ## Issue State
8
-
9
- OPEN
10
-
11
- ## Issue Labels
12
-
13
- bug, documentation, enhancement, question
14
-
15
- ## Issue Author
16
-
17
- konard
18
-
19
- ## Issue Content
20
-
21
- The issue shows two terminal sessions demonstrating different behaviors:
22
-
23
- ### Session 1: Without quoting the entire command
24
-
25
- ```bash
26
- konard@MacBook-Pro-Konstantin ~ % $ echo "hi" | agent
27
- ```
28
-
29
- **Result:** The `echo "hi"` command ran directly in the shell, and only its OUTPUT was piped to `agent`. The agent then processed the log file that was created by the `$` command (start-command), not the original command input.
30
-
31
- The agent received the OUTPUT of `$ echo "hi"` which was captured in a log file, and then read that log file.
32
-
33
- ### Session 2: With quoting the entire command
34
-
35
- ```bash
36
- konard@MacBook-Pro-Konstantin ~ % $ 'echo "hi" | agent'
37
- ```
38
-
39
- **Result:** The entire string `echo "hi" | agent` was passed TO the `$` command (start-command). The start-command then executed this complete pipeline, which resulted in the `echo "hi"` output being piped to `agent` correctly.
40
-
41
- ## Terminal Logs
42
-
43
- ### Session 1 Output (problematic behavior)
44
-
45
- ```json
46
- {
47
- "type": "status",
48
- "mode": "stdin-stream",
49
- "message": "Agent CLI in continuous listening mode. Accepts JSON and plain text input.",
50
- "hint": "Press CTRL+C to exit. Use --help for options.",
51
- "acceptedFormats": ["JSON object with \"message\" field", "Plain text"],
52
- "options": {
53
- "interactive": true,
54
- "autoMergeQueuedMessages": true,
55
- "alwaysAcceptStdin": true,
56
- "compactJson": false
57
- }
58
- }
59
- ```
60
-
61
- The agent then read a log file:
62
-
63
- ```
64
- === Start Command Log ===
65
- Timestamp: 2025-12-24 15:07:08.894
66
- Command: echo hi
67
- Shell: /bin/zsh
68
- Platform: darwin
69
- Bun Version: 1.2.20
70
- Working Directory: /Users/konard
71
- ==================================================
72
-
73
- hi
74
-
75
- ==================================================
76
- Finished: 2025-12-24 15:07:08.906
77
- Exit Code: 0
78
- ```
79
-
80
- And responded:
81
-
82
- > "It looks like you executed the command `echo hi`, which successfully output \"hi\" with exit code 0..."
83
-
84
- ### Session 2 Output (desired behavior)
85
-
86
- The agent received "hi" directly as input and responded:
87
-
88
- > "Hello! How can I help you today?"
89
-
90
- ## User Request
91
-
92
- > Please download all logs and data related about the issue to this repository, make sure we compile that data to `./docs/case-studies/issue-{id}` folder, and use it to do deep case study analysis (also make sure to search online for additional facts and data), in which we will reconstruct timeline/sequence of events, find root causes of the problem, and propose possible solutions.
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Debug script to understand regex generation
4
- */
5
-
6
- const { createRule, parseLinoContent } = require('../src/lib/substitution');
7
-
8
- // Test creating a simple rule
9
- const rule = createRule(
10
- 'install $packageName npm package',
11
- 'npm install $packageName'
12
- );
13
-
14
- console.log('Pattern:', 'install $packageName npm package');
15
- console.log('Replacement:', 'npm install $packageName');
16
- console.log('Generated Regex:', rule.regex);
17
- console.log('Variables:', rule.variables);
18
- console.log('');
19
-
20
- // Test matching
21
- const input = 'install gh-upload-log npm package';
22
- const match = input.match(rule.regex);
23
- console.log('Input:', input);
24
- console.log('Match result:', match);
25
-
26
- if (match) {
27
- console.log('Groups:', match.groups);
28
- }
29
-
30
- // Test simpler lino content
31
- const simpleContent = `
32
- (install $packageName npm package)
33
- (npm install $packageName)
34
- `;
35
-
36
- const rules = parseLinoContent(simpleContent);
37
- console.log(
38
- '\nParsed rules:',
39
- JSON.stringify(
40
- rules,
41
- (key, value) => {
42
- if (key === 'regex') {
43
- return value.toString();
44
- }
45
- return value;
46
- },
47
- 2
48
- )
49
- );
@@ -1,131 +0,0 @@
1
- # Isolation Support Design
2
-
3
- ## Overview
4
-
5
- This document outlines the design for adding process isolation support to start-command.
6
-
7
- ## Supported Isolation Backends
8
-
9
- ### Terminal Multiplexers
10
-
11
- 1. **screen** - GNU Screen, classic session manager
12
- 2. **tmux** - Modern terminal multiplexer
13
-
14
- ### Container Isolation
15
-
16
- 3. **docker** - Docker containers
17
-
18
- ## Command Syntax
19
-
20
- Two syntax patterns are supported:
21
-
22
- ```bash
23
- # Pattern 1: Using -- separator
24
- $ [wrapper-options] -- [command] [command-options]
25
-
26
- # Pattern 2: Options before command
27
- $ [wrapper-options] command [command-options]
28
- ```
29
-
30
- ### Wrapper Options
31
-
32
- - `--isolated <backend>` or `-i <backend>`: Run command in isolated environment
33
- - Backends: `screen`, `tmux`, `docker`
34
- - `--attached` or `-a`: Run in attached mode (foreground)
35
- - `--detached` or `-d`: Run in detached mode (background)
36
- - `--session <name>` or `-s <name>`: Name for the session (optional)
37
-
38
- ### Examples
39
-
40
- ```bash
41
- # Run in tmux (attached by default for multiplexers)
42
- $ --isolated tmux -- npm test
43
-
44
- # Run in screen detached
45
- $ --isolated screen --detached -- npm start
46
-
47
- # Run in docker container
48
- $ --isolated docker --image node:20 -- npm install
49
-
50
- # Short form
51
- $ -i tmux -d npm start
52
- ```
53
-
54
- ## Mode Behavior
55
-
56
- ### Attached Mode (--attached)
57
-
58
- - Default for terminal multiplexers (screen, tmux)
59
- - Command runs in foreground
60
- - User can interact with the terminal
61
- - For docker: runs with -it flags
62
-
63
- ### Detached Mode (--detached)
64
-
65
- - Command runs in background
66
- - For multiplexers: creates a session that can be reattached later
67
- - For docker: runs with -d flag
68
- - Session info is printed for later access
69
-
70
- ### Error Handling
71
-
72
- - If both --attached and --detached are specified, throw an error
73
- - Error message should ask user to choose only one
74
-
75
- ## Implementation Details
76
-
77
- ### Session Naming
78
-
79
- - Auto-generate session name: `start-{timestamp}-{random}`
80
- - Allow custom name via --session option
81
- - Session names used for reattachment
82
-
83
- ### Backend Commands
84
-
85
- #### Screen
86
-
87
- ```bash
88
- # Attached
89
- screen -S <session> bash -c '<command>'
90
-
91
- # Detached
92
- screen -dmS <session> bash -c '<command>'
93
- ```
94
-
95
- #### Tmux
96
-
97
- ```bash
98
- # Attached
99
- tmux new-session -s <session> '<command>'
100
-
101
- # Detached
102
- tmux new-session -d -s <session> '<command>'
103
- ```
104
-
105
- #### Docker
106
-
107
- ```bash
108
- # Attached
109
- docker run -it --name <name> <image> <command>
110
-
111
- # Detached
112
- docker run -d --name <name> <image> <command>
113
- ```
114
-
115
- ## Testing Strategy
116
-
117
- ### Unit Tests
118
-
119
- - Argument parsing tests
120
- - Backend detection tests
121
- - Session name generation tests
122
- - Conflict detection (attached + detached)
123
-
124
- ### Integration Tests
125
-
126
- - Actual execution with mocked backends
127
- - End-to-end tests with real backends (when available)
128
-
129
- ### E2E Tests
130
-
131
- - Full workflow tests with screen/tmux (if installed)
@@ -1,265 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Experiment: Test screen output capture behavior
4
- *
5
- * This experiment tests different approaches to capture output from GNU screen
6
- * sessions, specifically addressing issue #25 where output is lost on macOS
7
- * with screen 4.00.03.
8
- */
9
-
10
- const { execSync, spawn, spawnSync } = require('child_process');
11
- const fs = require('fs');
12
- const os = require('os');
13
- const path = require('path');
14
-
15
- // Check if screen is available
16
- function isScreenAvailable() {
17
- try {
18
- execSync('which screen', { stdio: ['pipe', 'pipe', 'pipe'] });
19
- return true;
20
- } catch {
21
- return false;
22
- }
23
- }
24
-
25
- // Get screen version
26
- function getScreenVersion() {
27
- try {
28
- const output = execSync('screen --version', {
29
- encoding: 'utf8',
30
- stdio: ['pipe', 'pipe', 'pipe'],
31
- });
32
- const match = output.match(/(\d+)\.(\d+)\.(\d+)/);
33
- if (match) {
34
- return {
35
- major: parseInt(match[1], 10),
36
- minor: parseInt(match[2], 10),
37
- patch: parseInt(match[3], 10),
38
- raw: output.trim(),
39
- };
40
- }
41
- } catch {
42
- // Ignore
43
- }
44
- return null;
45
- }
46
-
47
- // Check if -Logfile is supported (screen >= 4.5.1)
48
- function supportsLogfileOption(version) {
49
- if (!version) {
50
- return false;
51
- }
52
- if (version.major > 4) {
53
- return true;
54
- }
55
- if (version.major < 4) {
56
- return false;
57
- }
58
- if (version.minor > 5) {
59
- return true;
60
- }
61
- if (version.minor < 5) {
62
- return false;
63
- }
64
- return version.patch >= 1;
65
- }
66
-
67
- // Test 1: Direct screen invocation (current approach for TTY)
68
- async function testDirectScreen(command) {
69
- console.log('\n=== Test 1: Direct screen invocation (TTY mode) ===');
70
- const sessionName = `test-direct-${Date.now()}`;
71
- const shell = process.env.SHELL || '/bin/sh';
72
-
73
- console.log(`Command: screen -S ${sessionName} ${shell} -c '${command}'`);
74
- console.log('Note: This approach loses output for quick commands');
75
-
76
- // This is what happens currently with TTY
77
- return new Promise((resolve) => {
78
- const child = spawn('screen', ['-S', sessionName, shell, '-c', command], {
79
- stdio: 'inherit',
80
- });
81
-
82
- child.on('exit', (code) => {
83
- console.log(`Exit code: ${code}`);
84
- resolve({ success: code === 0, output: '(output not captured)' });
85
- });
86
-
87
- child.on('error', (err) => {
88
- console.error(`Error: ${err.message}`);
89
- resolve({ success: false, output: '' });
90
- });
91
- });
92
- }
93
-
94
- // Test 2: Detached screen with log file (current approach for no-TTY)
95
- async function testDetachedWithLog(command) {
96
- console.log('\n=== Test 2: Detached screen with log capture ===');
97
- const sessionName = `test-detached-${Date.now()}`;
98
- const shell = process.env.SHELL || '/bin/sh';
99
- const logFile = path.join(os.tmpdir(), `screen-test-${sessionName}.log`);
100
-
101
- const version = getScreenVersion();
102
- const useNativeLogging = supportsLogfileOption(version);
103
-
104
- console.log(`Screen version: ${version ? version.raw : 'unknown'}`);
105
- console.log(`Supports -Logfile: ${useNativeLogging}`);
106
-
107
- let screenArgs;
108
- let effectiveCommand = command;
109
-
110
- if (useNativeLogging) {
111
- // Modern screen
112
- screenArgs = [
113
- '-dmS',
114
- sessionName,
115
- '-L',
116
- '-Logfile',
117
- logFile,
118
- shell,
119
- '-c',
120
- command,
121
- ];
122
- } else {
123
- // Older screen - use tee fallback
124
- effectiveCommand = `(${command}) 2>&1 | tee "${logFile}"`;
125
- screenArgs = ['-dmS', sessionName, shell, '-c', effectiveCommand];
126
- }
127
-
128
- console.log(`Command: screen ${screenArgs.join(' ')}`);
129
-
130
- return new Promise((resolve) => {
131
- try {
132
- const result = spawnSync('screen', screenArgs, { stdio: 'inherit' });
133
-
134
- if (result.error) {
135
- console.error(`Error: ${result.error.message}`);
136
- resolve({ success: false, output: '' });
137
- return;
138
- }
139
-
140
- // Poll for session completion
141
- const checkInterval = 100;
142
- const maxWait = 10000;
143
- let waited = 0;
144
-
145
- const checkCompletion = () => {
146
- try {
147
- const sessions = execSync('screen -ls', {
148
- encoding: 'utf8',
149
- stdio: ['pipe', 'pipe', 'pipe'],
150
- });
151
-
152
- if (!sessions.includes(sessionName)) {
153
- // Session ended
154
- let output = '';
155
- try {
156
- output = fs.readFileSync(logFile, 'utf8');
157
- console.log(`Captured output: "${output.trim()}"`);
158
- fs.unlinkSync(logFile);
159
- } catch {
160
- console.log('Log file not found or empty');
161
- }
162
- resolve({ success: true, output });
163
- return;
164
- }
165
-
166
- waited += checkInterval;
167
- if (waited >= maxWait) {
168
- resolve({ success: false, output: 'timeout' });
169
- return;
170
- }
171
-
172
- setTimeout(checkCompletion, checkInterval);
173
- } catch {
174
- let output = '';
175
- try {
176
- output = fs.readFileSync(logFile, 'utf8');
177
- console.log(`Captured output: "${output.trim()}"`);
178
- fs.unlinkSync(logFile);
179
- } catch {
180
- // Ignore
181
- }
182
- resolve({ success: true, output });
183
- }
184
- };
185
-
186
- setTimeout(checkCompletion, checkInterval);
187
- } catch (err) {
188
- console.error(`Error: ${err.message}`);
189
- resolve({ success: false, output: '' });
190
- }
191
- });
192
- }
193
-
194
- // Test 3: Script command for output capture (alternative approach)
195
- async function testScriptCapture(command) {
196
- console.log('\n=== Test 3: Using script command for output capture ===');
197
- const logFile = path.join(os.tmpdir(), `script-test-${Date.now()}.log`);
198
- const shell = process.env.SHELL || '/bin/sh';
199
-
200
- // Use 'script' command which is available on both macOS and Linux
201
- // script -q logfile command (macOS/BSD)
202
- // script -q -c command logfile (Linux)
203
- const isMac = process.platform === 'darwin';
204
-
205
- let scriptArgs;
206
- if (isMac) {
207
- scriptArgs = ['-q', logFile, shell, '-c', command];
208
- } else {
209
- scriptArgs = ['-q', '-c', `${shell} -c '${command}'`, logFile];
210
- }
211
-
212
- console.log(`Command: script ${scriptArgs.join(' ')}`);
213
-
214
- return new Promise((resolve) => {
215
- const child = spawn('script', scriptArgs, {
216
- stdio: 'inherit',
217
- });
218
-
219
- child.on('exit', (code) => {
220
- let output = '';
221
- try {
222
- output = fs.readFileSync(logFile, 'utf8');
223
- console.log(`Captured output: "${output.trim()}"`);
224
- fs.unlinkSync(logFile);
225
- } catch {
226
- console.log('Log file not found');
227
- }
228
- resolve({ success: code === 0, output });
229
- });
230
-
231
- child.on('error', (err) => {
232
- console.error(`Error: ${err.message}`);
233
- resolve({ success: false, output: '' });
234
- });
235
- });
236
- }
237
-
238
- // Main
239
- async function main() {
240
- console.log('Screen Output Capture Experiment');
241
- console.log('=================================');
242
- console.log(`Platform: ${process.platform}`);
243
- console.log(
244
- `TTY: stdin=${process.stdin.isTTY}, stdout=${process.stdout.isTTY}`
245
- );
246
-
247
- if (!isScreenAvailable()) {
248
- console.log('Screen is not installed. Exiting.');
249
- return;
250
- }
251
-
252
- const version = getScreenVersion();
253
- console.log(`Screen version: ${version ? version.raw : 'unknown'}`);
254
-
255
- const testCommand = 'echo "hello from screen"';
256
-
257
- // Test 2 is the recommended approach
258
- const result = await testDetachedWithLog(testCommand);
259
- console.log('\n=== Summary ===');
260
- console.log(
261
- `Test 2 (detached with log): Success=${result.success}, Output captured=${result.output.includes('hello')}`
262
- );
263
- }
264
-
265
- main().catch(console.error);
@@ -1,42 +0,0 @@
1
- #!/bin/bash
2
- # Test script for start-command CLI
3
-
4
- set -e
5
-
6
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
- CLI_PATH="${SCRIPT_DIR}/../bin/cli.js"
8
-
9
- echo "=== Testing start-command CLI ==="
10
- echo ""
11
-
12
- # Test 1: No arguments - should show usage
13
- echo "Test 1: No arguments (should show usage)"
14
- node "$CLI_PATH" || true
15
- echo ""
16
-
17
- # Test 2: Successful command
18
- echo "Test 2: Successful command (echo)"
19
- node "$CLI_PATH" echo "Hello from test!"
20
- echo ""
21
-
22
- # Test 3: List directory
23
- echo "Test 3: List directory (ls)"
24
- node "$CLI_PATH" ls -la "$SCRIPT_DIR"
25
- echo ""
26
-
27
- # Test 4: Failing command (system command)
28
- echo "Test 4: Failing system command (false) - should NOT detect repository"
29
- node "$CLI_PATH" false || true
30
- echo ""
31
-
32
- # Test 5: Non-existent command
33
- echo "Test 5: Non-existent command - should NOT detect repository"
34
- node "$CLI_PATH" this_command_does_not_exist_xyz123 || true
35
- echo ""
36
-
37
- # Test 6: Check log file creation
38
- echo "Test 6: Verify log files are created"
39
- ls -la /tmp/start-command-*.log 2>/dev/null | head -5 || echo "No log files found (unexpected)"
40
- echo ""
41
-
42
- echo "=== All tests completed ==="