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.
- package/CHANGELOG.md +28 -217
- package/bun.lock +10 -0
- package/eslint.config.mjs +1 -1
- package/package.json +13 -5
- package/src/bin/cli.js +414 -499
- package/src/lib/args-parser.js +126 -0
- package/src/lib/command-stream.js +258 -0
- package/src/lib/execution-store.js +722 -0
- package/src/lib/failure-handler.js +397 -0
- package/src/lib/isolation.js +51 -0
- package/src/lib/status-formatter.js +121 -0
- package/src/lib/version.js +143 -0
- package/test/args-parser.test.js +140 -0
- package/test/cli.test.js +11 -1
- package/test/docker-autoremove.test.js +11 -16
- package/test/execution-store.test.js +483 -0
- package/test/isolation-cleanup.test.js +11 -16
- package/test/isolation.test.js +11 -17
- package/test/public-exports.test.js +105 -0
- package/test/status-query.test.js +195 -0
- package/.github/workflows/release.yml +0 -334
- package/.husky/pre-commit +0 -1
- package/ARCHITECTURE.md +0 -297
- package/LICENSE +0 -24
- package/README.md +0 -339
- package/REQUIREMENTS.md +0 -299
- package/docs/PIPES.md +0 -243
- package/docs/USAGE.md +0 -194
- package/docs/case-studies/issue-15/README.md +0 -208
- package/docs/case-studies/issue-18/README.md +0 -343
- package/docs/case-studies/issue-18/issue-comments.json +0 -1
- package/docs/case-studies/issue-18/issue-data.json +0 -7
- package/docs/case-studies/issue-22/analysis.md +0 -547
- package/docs/case-studies/issue-22/issue-data.json +0 -12
- package/docs/case-studies/issue-25/README.md +0 -232
- package/docs/case-studies/issue-25/issue-data.json +0 -21
- package/docs/case-studies/issue-28/README.md +0 -405
- package/docs/case-studies/issue-28/issue-data.json +0 -105
- package/docs/case-studies/issue-28/raw-issue-data.md +0 -92
- package/experiments/debug-regex.js +0 -49
- package/experiments/isolation-design.md +0 -131
- package/experiments/screen-output-test.js +0 -265
- package/experiments/test-cli.sh +0 -42
- package/experiments/test-screen-attached.js +0 -126
- package/experiments/test-screen-logfile.js +0 -286
- package/experiments/test-screen-modes.js +0 -128
- package/experiments/test-screen-output.sh +0 -27
- package/experiments/test-screen-tee-debug.js +0 -237
- package/experiments/test-screen-tee-fallback.js +0 -230
- package/experiments/test-substitution.js +0 -143
- package/experiments/user-isolation-research.md +0 -83
- package/scripts/changeset-version.mjs +0 -38
- package/scripts/check-file-size.mjs +0 -103
- package/scripts/create-github-release.mjs +0 -93
- package/scripts/create-manual-changeset.mjs +0 -89
- package/scripts/format-github-release.mjs +0 -83
- package/scripts/format-release-notes.mjs +0 -219
- package/scripts/instant-version-bump.mjs +0 -121
- package/scripts/publish-to-npm.mjs +0 -129
- package/scripts/setup-npm.mjs +0 -37
- package/scripts/validate-changeset.mjs +0 -107
- 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
|