start-command 0.11.0 → 0.15.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 (62) hide show
  1. package/CHANGELOG.md +28 -217
  2. package/bun.lock +10 -0
  3. package/eslint.config.mjs +1 -1
  4. package/package.json +13 -5
  5. package/src/bin/cli.js +414 -499
  6. package/src/lib/args-parser.js +126 -0
  7. package/src/lib/command-stream.js +258 -0
  8. package/src/lib/execution-store.js +722 -0
  9. package/src/lib/failure-handler.js +397 -0
  10. package/src/lib/isolation.js +51 -0
  11. package/src/lib/status-formatter.js +121 -0
  12. package/src/lib/version.js +143 -0
  13. package/test/args-parser.test.js +140 -0
  14. package/test/cli.test.js +11 -1
  15. package/test/docker-autoremove.test.js +11 -16
  16. package/test/execution-store.test.js +483 -0
  17. package/test/isolation-cleanup.test.js +11 -16
  18. package/test/isolation.test.js +11 -17
  19. package/test/public-exports.test.js +105 -0
  20. package/test/status-query.test.js +195 -0
  21. package/.github/workflows/release.yml +0 -334
  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-screen-attached.js +0 -126
  45. package/experiments/test-screen-logfile.js +0 -286
  46. package/experiments/test-screen-modes.js +0 -128
  47. package/experiments/test-screen-output.sh +0 -27
  48. package/experiments/test-screen-tee-debug.js +0 -237
  49. package/experiments/test-screen-tee-fallback.js +0 -230
  50. package/experiments/test-substitution.js +0 -143
  51. package/experiments/user-isolation-research.md +0 -83
  52. package/scripts/changeset-version.mjs +0 -38
  53. package/scripts/check-file-size.mjs +0 -103
  54. package/scripts/create-github-release.mjs +0 -93
  55. package/scripts/create-manual-changeset.mjs +0 -89
  56. package/scripts/format-github-release.mjs +0 -83
  57. package/scripts/format-release-notes.mjs +0 -219
  58. package/scripts/instant-version-bump.mjs +0 -121
  59. package/scripts/publish-to-npm.mjs +0 -129
  60. package/scripts/setup-npm.mjs +0 -37
  61. package/scripts/validate-changeset.mjs +0 -107
  62. package/scripts/version-and-commit.mjs +0 -237
package/REQUIREMENTS.md DELETED
@@ -1,299 +0,0 @@
1
- # Requirements for `$` Command (start-command)
2
-
3
- ## Overview
4
-
5
- The `$` command is a CLI tool that wraps any shell command and provides automatic logging, error reporting, issue creation capabilities, and natural language command aliases.
6
-
7
- ## Core Requirements
8
-
9
- ### 1. Command Proxy Functionality
10
-
11
- - Act as a transparent proxy for any shell command
12
- - Pass all arguments directly to the underlying shell (bash/powershell/sh)
13
- - Support all standard commands: `$ ls`, `$ cat`, `$ mkdir`, etc.
14
- - Preserve exit codes from wrapped commands
15
- - Support natural language command aliases via pattern matching
16
-
17
- ### 2. Logging Requirements
18
-
19
- #### 2.1 Log Storage
20
-
21
- - Save full command output (stdout + stderr) to temporary OS directory
22
- - Use platform-appropriate temp directory:
23
- - Linux/macOS: `/tmp/` or `os.tmpdir()`
24
- - Windows: `%TEMP%`
25
- - Log file naming: `start-command-{timestamp}-{random}.log`
26
-
27
- #### 2.2 Log Content
28
-
29
- - Include timestamp at the start of logging
30
- - Include timestamp at the end of logging
31
- - Capture both stdout and stderr
32
- - Store the complete command that was executed
33
- - Store the exit code
34
-
35
- #### 2.3 Log Display
36
-
37
- - Print full log content to console after command finishes
38
- - Always print the exit code (success or failure)
39
- - Make exit code prominent as "it may usually be unclear"
40
-
41
- ### 3. Repository Detection
42
-
43
- #### 3.1 NPM Package Detection
44
-
45
- - Detect if the executed command is a globally installed NPM package
46
- - Use `which` (Unix) or `where` (Windows) to find command location
47
- - Check if command resolves to a path within npm global modules
48
- - Extract package name from the path
49
- - Use `npm view <package> repository.url` to get repository URL
50
-
51
- #### 3.2 Supported Command Types
52
-
53
- - Globally installed NPM packages (primary focus)
54
- - Future: other package managers (pip, gem, etc.)
55
-
56
- ### 4. Automatic Issue Reporting (On Failure)
57
-
58
- #### 4.1 Preconditions for Auto-Reporting
59
-
60
- - Command must have failed (non-zero exit code)
61
- - Repository must be detected for the command
62
- - `gh` CLI tool must be authenticated
63
- - User must have permission to create issues in target repository
64
-
65
- #### 4.2 Log Upload
66
-
67
- - Use `gh-upload-log` tool to upload the log file
68
- - Upload as a gist (for logs ≤100MB)
69
- - Print the uploaded log URL to console
70
-
71
- #### 4.3 Issue Creation
72
-
73
- - Create an issue in the detected repository
74
- - Issue title: Include command name and error summary
75
- - Issue body: Include:
76
- - Command that was executed
77
- - Exit code
78
- - Link to uploaded log
79
- - System information (OS, Bun/Node.js version)
80
- - Timestamp
81
- - Print the created issue URL to console
82
-
83
- ### 5. Graceful Degradation
84
-
85
- #### 5.1 When Repository Cannot Be Detected
86
-
87
- - Still log everything to temp directory
88
- - Still print logs and exit code to console
89
- - Skip log upload and issue creation
90
-
91
- #### 5.2 When `gh` Is Not Authenticated
92
-
93
- - Still log everything to temp directory
94
- - Still print logs and exit code to console
95
- - Print a message that auto-reporting is skipped
96
- - Skip log upload and issue creation
97
-
98
- #### 5.3 When `gh-upload-log` Is Not Installed
99
-
100
- - Still log everything to temp directory
101
- - Still print logs and exit code to console
102
- - Print a message that log upload is skipped
103
- - Skip issue creation (no log link available)
104
-
105
- ### 5. Command Aliases / Substitutions
106
-
107
- #### 5.1 Pattern Matching
108
-
109
- - Support natural language patterns defined in `substitutions.lino`
110
- - Use Links Notation style with variables like `$packageName`, `$version`
111
- - Match input against patterns and substitute with actual commands
112
- - More specific patterns (more variables, longer patterns) take precedence
113
- - Non-matching commands pass through unchanged
114
-
115
- #### 5.2 Built-in Patterns
116
-
117
- - NPM: `install $packageName npm package` -> `npm install $packageName`
118
- - NPM with version: `install $version version of $packageName npm package` -> `npm install $packageName@$version`
119
- - Git clone: `clone $repository repository` -> `git clone $repository`
120
- - Git checkout: `checkout $branch branch` -> `git checkout $branch`
121
- - Common operations: `list files` -> `ls -la`, `show current directory` -> `pwd`
122
-
123
- #### 5.3 Custom Patterns
124
-
125
- - Support user-defined patterns in `~/.start-command/substitutions.lino`
126
- - User patterns take precedence over built-in patterns
127
- - Support custom path via `START_SUBSTITUTIONS_PATH` environment variable
128
-
129
- ### 6. Process Isolation
130
-
131
- #### 6.1 Command Syntax
132
-
133
- Support two patterns for passing wrapper options:
134
-
135
- - `$ [wrapper-options] -- [command] [command-options]` (explicit separator)
136
- - `$ [wrapper-options] command [command-options]` (options before command)
137
-
138
- #### 6.2 Isolation Options
139
-
140
- - `--isolated, -i <backend>`: Run command in isolated environment
141
- - `--attached, -a`: Run in attached/foreground mode (default)
142
- - `--detached, -d`: Run in detached/background mode
143
- - `--session, -s <name>`: Custom session name
144
- - `--image <image>`: Docker image (required for docker backend)
145
- - `--isolated-user, -u [username]`: Create new isolated user with same group permissions as current user
146
- - `--keep-user`: Keep isolated user after command completes (don't delete)
147
- - `--keep-alive, -k`: Keep isolation environment alive after command exits (disabled by default)
148
- - `--auto-remove-docker-container`: Automatically remove docker container after exit (disabled by default, only valid with --isolated docker)
149
-
150
- #### 6.3 Supported Backends
151
-
152
- - `screen`: GNU Screen terminal multiplexer
153
- - `tmux`: tmux terminal multiplexer
154
- - `docker`: Docker containers (requires --image option)
155
-
156
- #### 6.4 Mode Behavior
157
-
158
- - **Attached mode**: Command runs in foreground, user can interact
159
- - **Detached mode**: Command runs in background, session info displayed for reattachment
160
- - **Conflict handling**: If both --attached and --detached are specified, show error asking user to choose one
161
-
162
- #### 6.5 User Isolation
163
-
164
- - `--isolated-user, -u [username]`: Create a new isolated user with same permissions
165
- - Creates user with same group memberships as current user (sudo, docker, wheel, etc.)
166
- - Automatically generates username if not specified
167
- - User is automatically deleted after command completes (unless `--keep-user` is specified)
168
- - For screen/tmux: Wraps command with `sudo -n -u <username>`
169
- - Requires sudo NOPASSWD for useradd/userdel commands
170
- - Works with screen and tmux isolation (not docker)
171
-
172
- #### 6.6 Keep User Option
173
-
174
- - `--keep-user`: Keep the isolated user after command completes
175
- - Only valid with `--isolated-user` option
176
- - User must be manually deleted later with `sudo userdel -r <username>`
177
-
178
- Example usage:
179
-
180
- ```bash
181
- # Create isolated user and run command (user auto-deleted after)
182
- $ --isolated-user -- npm test
183
-
184
- # Custom username for isolated user
185
- $ --isolated-user myrunner -- npm start
186
- $ -u myrunner -- npm start
187
-
188
- # Combine with screen isolation
189
- $ --isolated screen --isolated-user -- npm test
190
-
191
- # Combine with tmux detached mode
192
- $ -i tmux -d --isolated-user testuser -- npm run build
193
-
194
- # Keep user after command completes
195
- $ --isolated-user --keep-user -- npm test
196
- ```
197
-
198
- Benefits:
199
-
200
- - Clean user environment for each run
201
- - Inherits sudo/docker access from current user
202
- - Files created during execution belong to isolated user
203
- - Automatic cleanup after execution (unless --keep-user)
204
-
205
- #### 6.7 Auto-Exit Behavior
206
-
207
- By default, all isolation environments (screen, tmux, docker) automatically exit after the target command completes execution. This ensures:
208
-
209
- - Resources are freed immediately after command execution
210
- - No orphaned sessions/containers remain running
211
- - Uniform behavior across all isolation backends
212
- - Command output is still captured and logged before exit
213
-
214
- The `--keep-alive` flag can be used to override this behavior and keep the isolation environment running after command completion, useful for debugging or interactive workflows.
215
-
216
- **Docker Container Filesystem Preservation:**
217
- By default, when using Docker isolation, the container filesystem is preserved after the container exits. This allows you to re-enter the container and access any files created during command execution, which is useful for retrieving additional output files or debugging. The container appears in `docker ps -a` in an "exited" state but is not removed.
218
-
219
- The `--auto-remove-docker-container` flag enables automatic removal of the container after exit, which is useful when you don't need to preserve the container filesystem and want to clean up resources completely. When this flag is enabled:
220
-
221
- - The container is removed immediately after exiting (using docker's `--rm` flag)
222
- - The container will not appear in `docker ps -a` after command completion
223
- - You cannot re-enter the container to access files
224
- - Resources are freed more aggressively
225
-
226
- Note: `--auto-remove-docker-container` is only valid with `--isolated docker` and is independent of the `--keep-alive` flag.
227
-
228
- #### 6.8 Graceful Degradation
229
-
230
- - If isolation backend is not installed, show informative error with installation instructions
231
- - If session creation fails, report error with details
232
- - If sudo fails due to password requirement, command will fail with sudo error
233
-
234
- ## Configuration Options
235
-
236
- - `START_DISABLE_AUTO_ISSUE`: Disable automatic issue creation
237
- - `START_DISABLE_LOG_UPLOAD`: Disable log upload
238
- - `START_LOG_DIR`: Custom log directory
239
- - `START_VERBOSE`: Enable verbose output
240
- - `START_DISABLE_SUBSTITUTIONS`: Disable pattern matching/aliases
241
- - `START_SUBSTITUTIONS_PATH`: Custom path to substitutions file
242
-
243
- ## Output Format
244
-
245
- ### Success Case
246
-
247
- ```
248
- [2024-01-15 10:30:45] Starting: ls -la
249
- ... command output ...
250
- [2024-01-15 10:30:45] Finished
251
- Exit code: 0
252
- Log saved: /tmp/start-command-1705312245-abc123.log
253
- ```
254
-
255
- ### Failure Case (With Auto-Reporting)
256
-
257
- ```
258
- [2024-01-15 10:30:45] Starting: failing-npm-command --arg
259
- ... command output/error ...
260
- [2024-01-15 10:30:46] Finished
261
- Exit code: 1
262
- Log saved: /tmp/start-command-1705312246-def456.log
263
- Detected repository: https://github.com/owner/repo
264
- Log uploaded: https://gist.github.com/...
265
- Issue created: https://github.com/owner/repo/issues/123
266
- ```
267
-
268
- ### Failure Case (Without Auto-Reporting)
269
-
270
- ```
271
- [2024-01-15 10:30:45] Starting: unknown-command
272
- ... command output/error ...
273
- [2024-01-15 10:30:45] Finished
274
- Exit code: 127
275
- Log saved: /tmp/start-command-1705312245-ghi789.log
276
- Repository not detected - automatic issue creation skipped
277
- ```
278
-
279
- ## Dependencies
280
-
281
- ### Required
282
-
283
- - **Bun >= 1.0.0** (primary runtime)
284
- - `child_process` (built-in)
285
- - `os` (built-in)
286
- - `fs` (built-in)
287
- - `path` (built-in)
288
-
289
- ### Optional (for full functionality)
290
-
291
- - `gh` CLI - GitHub CLI for authentication and issue creation
292
- - `gh-upload-log` - For uploading log files to GitHub
293
-
294
- ## Security Considerations
295
-
296
- - Do not include sensitive environment variables in logs
297
- - Do not include authentication tokens in issue reports
298
- - Respect `.gitignore` patterns when detecting repositories
299
- - Only create issues in public repositories unless explicitly authorized
package/docs/PIPES.md DELETED
@@ -1,243 +0,0 @@
1
- # Piping with start-command (`$`)
2
-
3
- This document explains how to use pipes with the `$` command effectively.
4
-
5
- ## Table of Contents
6
-
7
- - [Quick Summary](#quick-summary)
8
- - [The Preferred Way: Pipe TO `$`](#the-preferred-way-pipe-to-)
9
- - [Alternative: Quoting](#alternative-quoting)
10
- - [Why This Matters](#why-this-matters)
11
- - [Examples](#examples)
12
- - [Troubleshooting](#troubleshooting)
13
-
14
- ## Quick Summary
15
-
16
- When piping data to a command wrapped with `$`, **put `$` on the receiving command**:
17
-
18
- ```bash
19
- # Preferred - pipe TO the $-wrapped command
20
- echo "hi" | $ agent
21
-
22
- # Alternative - quote the entire pipeline (more verbose)
23
- $ 'echo "hi" | agent'
24
- ```
25
-
26
- Both approaches work, but piping TO `$` is simpler and requires fewer quotes.
27
-
28
- ## The Preferred Way: Pipe TO `$`
29
-
30
- The cleanest way to use pipes with `$` is to place `$` on the command that **receives** the piped input:
31
-
32
- ```bash
33
- # Data flows: echo "hi" -> agent (wrapped with $)
34
- echo "hi" | $ agent
35
- ```
36
-
37
- This works because:
38
-
39
- 1. The shell creates a pipeline: `echo "hi"` piped to `$ agent`
40
- 2. `$ agent` receives "hi" on stdin
41
- 3. The `$` command wraps `agent`, which processes the input
42
-
43
- ### Real-World Examples
44
-
45
- ```bash
46
- # Pipe text to an AI agent
47
- echo "Explain this code" | $ agent
48
-
49
- # Pipe file contents to a processor
50
- cat file.txt | $ processor
51
-
52
- # Pipe command output to an analyzer
53
- ls -la | $ analyzer
54
-
55
- # Chain multiple commands, wrap the final one
56
- cat data.json | jq '.items[]' | $ handler
57
- ```
58
-
59
- ### When to Use This Approach
60
-
61
- Use `command | $ target` when:
62
-
63
- - You want to pipe data INTO a command that `$` wraps
64
- - You want the `$` logging and monitoring for the receiving command
65
- - You prefer minimal quoting
66
-
67
- ## Alternative: Quoting
68
-
69
- You can also wrap the entire pipeline in quotes:
70
-
71
- ```bash
72
- # Single quotes preserve the pipe literally
73
- $ 'echo "hi" | agent'
74
-
75
- # The $ command receives the whole pipeline as one argument
76
- $ 'cat file.txt | grep pattern | wc -l'
77
- ```
78
-
79
- ### When to Use Quoting
80
-
81
- Use quotes when:
82
-
83
- - You want `$` to wrap the ENTIRE pipeline (logging all commands)
84
- - You need the pipeline to run as a single tracked unit
85
- - You want a single log file for the whole operation
86
-
87
- ### Quote Types
88
-
89
- | Quote Type | Behavior | Example |
90
- | ---------- | ------------------ | ---------------------- |
91
- | `'single'` | Everything literal | `$ 'echo $HOME \| wc'` |
92
- | `"double"` | Variables expand | `$ "echo $HOME \| wc"` |
93
-
94
- ## Why This Matters
95
-
96
- ### Shell Parsing Order
97
-
98
- When you type a command, the shell parses it **before** any program runs:
99
-
100
- ```
101
- Without quotes or positioning:
102
- $ echo "hi" | agent
103
- └───┬────┘ └──┬──┘
104
- │ │
105
- Command 1 Command 2
106
- ($ echo "hi") (agent)
107
-
108
- Result: agent receives $ output, not "hi"
109
- ```
110
-
111
- The pipe `|` is a shell operator, so the shell splits the command at that point.
112
-
113
- ### Solution Comparison
114
-
115
- ```
116
- Preferred - Pipe TO $:
117
- echo "hi" | $ agent
118
- └───┬────┘ └──┬──┘
119
- │ │
120
- Command 1 Command 2
121
- (echo "hi") ($ agent)
122
-
123
- Result: $ agent receives "hi" - correct!
124
-
125
- Alternative - Quoting:
126
- $ 'echo "hi" | agent'
127
- └─────────┬──────────┘
128
-
129
- Single command
130
- (pipeline runs inside $)
131
-
132
- Result: agent receives "hi" - correct!
133
- ```
134
-
135
- ## Examples
136
-
137
- ### Basic Piping
138
-
139
- ```bash
140
- # Pipe text to a command
141
- echo "hello world" | $ processor
142
-
143
- # Pipe file contents
144
- cat config.json | $ validator
145
-
146
- # Pipe command output
147
- git diff | $ reviewer
148
- ```
149
-
150
- ### Multiple Pipes
151
-
152
- ```bash
153
- # $ wraps only the final command
154
- cat file.txt | grep "error" | $ reporter
155
-
156
- # $ wraps the entire pipeline (quoted)
157
- $ 'cat file.txt | grep "error" | wc -l'
158
- ```
159
-
160
- ### With Variables
161
-
162
- ```bash
163
- # Variable expands before piping (shell handles it)
164
- echo "$HOME" | $ agent
165
-
166
- # Variable preserved literally (single quotes)
167
- $ 'echo $HOME | wc -c'
168
- ```
169
-
170
- ### Complex Commands
171
-
172
- ```bash
173
- # Process JSON and pipe to handler
174
- curl -s https://api.example.com/data | jq '.items' | $ handler
175
-
176
- # Pipe to a command with arguments
177
- echo "analyze this" | $ agent --verbose --format json
178
- ```
179
-
180
- ## Troubleshooting
181
-
182
- ### Problem: Output goes to wrong place
183
-
184
- **Symptom:** Running `$ cmd1 | cmd2` and cmd2 receives unexpected output.
185
-
186
- **Cause:** Shell parses `|` before `$` runs, so cmd2 gets `$` output.
187
-
188
- **Solutions:**
189
-
190
- 1. Pipe TO $: `cmd1 | $ cmd2`
191
- 2. Quote: `$ 'cmd1 | cmd2'`
192
-
193
- ### Problem: Command not receiving stdin
194
-
195
- **Symptom:** `echo "data" | $ cmd` but cmd doesn't see the data.
196
-
197
- **Check:** Does `cmd` read from stdin? Not all commands do.
198
-
199
- **Test:** Try `echo "data" | cmd` without `$` first.
200
-
201
- ### Problem: Quotes inside quotes
202
-
203
- **Symptom:** `$ 'echo "hello 'world'"'` causes errors.
204
-
205
- **Solutions:**
206
-
207
- ```bash
208
- # Use double quotes with escaping
209
- $ "echo \"hello 'world'\""
210
-
211
- # Or mix quote styles
212
- echo "hello 'world'" | $ processor
213
- ```
214
-
215
- ### Problem: Variables not expanding
216
-
217
- **Symptom:** `$ 'echo $HOME'` prints literal "$HOME".
218
-
219
- **Cause:** Single quotes prevent expansion.
220
-
221
- **Solutions:**
222
-
223
- ```bash
224
- # Use double quotes (escape the pipe)
225
- $ "echo $HOME | wc -c"
226
-
227
- # Or pipe TO $ (variable expands in source command)
228
- echo "$HOME" | $ wc -c
229
- ```
230
-
231
- ## Summary
232
-
233
- | Approach | Syntax | Best For |
234
- | --------- | ------------------ | --------------------------- |
235
- | Pipe TO $ | `cmd1 \| $ cmd2` | Simple piping, less quoting |
236
- | Quoted | `$ 'cmd1 \| cmd2'` | Logging entire pipeline |
237
-
238
- The preferred approach is **piping TO `$`** - it's simpler and avoids quote complexity.
239
-
240
- ## See Also
241
-
242
- - [USAGE.md](USAGE.md) - General usage guide
243
- - [Case Study: Issue #28](case-studies/issue-28/README.md) - Detailed analysis