@radleta/just-one 1.1.0 → 1.3.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 CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [1.3.0](https://github.com/radleta/just-one/compare/v1.2.0...v1.3.0) (2026-02-12)
6
+
7
+ ### Features
8
+
9
+ - **cli:** add daemon mode with log capture, viewing, and real-time follow ([4b6b7ae](https://github.com/radleta/just-one/commit/4b6b7ae84117c895782d272aa0ae62f107fb2e13))
10
+ - **process:** add graceful kill with SIGKILL escalation and --grace flag ([84f90d9](https://github.com/radleta/just-one/commit/84f90d90652f376bcac9ae781967578a657c3dd4))
11
+
12
+ ### Bug Fixes
13
+
14
+ - **ci:** enforce LF line endings to fix Windows format check ([e208149](https://github.com/radleta/just-one/commit/e2081493b21663011ef9431944bd25eb22d121aa))
15
+ - **log:** replace fs.watchFile with setInterval polling in tailLogFile ([26200fc](https://github.com/radleta/just-one/commit/26200fcb47632800fecb508b85696ad3ceffadea))
16
+ - **process:** pass args array to spawn on Windows instead of joining ([5e3d13a](https://github.com/radleta/just-one/commit/5e3d13ace04175dfb92404bd06aac2e1dadcf04d))
17
+ - **process:** remove shell: true from daemon mode on Windows ([2411f5f](https://github.com/radleta/just-one/commit/2411f5f8a7ee43aac00d784a360d996d02fb715d))
18
+ - **tests:** increase tailLogFile poll timeout for slow CI runners ([bde9a92](https://github.com/radleta/just-one/commit/bde9a92839f986e0270ca9fb5f81ea98d9228aef))
19
+ - **tests:** stabilize flaky polling-based tests ([02d4639](https://github.com/radleta/just-one/commit/02d463928b3e4f59829babd24bd74549c6fc9a68))
20
+ - **tests:** stabilize Windows E2E tests for daemon mode ([92dee91](https://github.com/radleta/just-one/commit/92dee9100d0eae133d5db045e0c65425fb73669f))
21
+ - **tests:** use script files instead of node -e in daemon tests ([bc47ab5](https://github.com/radleta/just-one/commit/bc47ab5ab98076813bedb58dd3a7d869d3e738e7))
22
+
23
+ ## [1.2.0](https://github.com/radleta/just-one/compare/v1.1.0...v1.2.0) (2026-02-11)
24
+
25
+ ### Features
26
+
27
+ - **cli:** add status, kill-all, ensure, clean, pid, and wait operations ([5d1909b](https://github.com/radleta/just-one/commit/5d1909bc794a7a5b357d725fa59c7942dca7023d))
28
+
29
+ ### Bug Fixes
30
+
31
+ - **windows:** allow child process to run cleanup handlers on Ctrl+C ([ac3bca0](https://github.com/radleta/just-one/commit/ac3bca07fcbfeb39e98ad3f31c280b45152525e0))
32
+
5
33
  ## [1.1.0](https://github.com/radleta/just-one/compare/v1.0.0...v1.1.0) (2026-01-29)
6
34
 
7
35
  ### Features
package/README.md CHANGED
@@ -1,181 +1,271 @@
1
- # just-one
2
-
3
- A CLI tool that ensures only one instance of a command runs at a time. Kills the previous instance before starting a new one.
4
-
5
- ## Why This Exists
6
-
7
- When developing with dev servers (Storybook, Vite, webpack-dev-server, etc.), you often get:
8
-
9
- ```
10
- Error: Port 6006 is already in use
11
- ```
12
-
13
- Existing solutions have drawbacks:
14
- - **kill-port** - Kills ANY process on that port (imprecise, might kill unrelated processes)
15
- - **Manual** - Find PID, kill it, restart (tedious)
16
- - **pm2** - Overkill for dev servers
17
-
18
- `just-one` tracks processes by name using PID files. When you run a command, it kills the previous instance (if any) and starts fresh—precisely targeting only the process it started.
19
-
20
- ## Features
21
-
22
- - **Named process tracking** - Each process gets a unique name for precise targeting
23
- - **Automatic cleanup** - Previous instance killed before starting new one
24
- - **Cross-platform** - Works on Windows, macOS, and Linux
25
- - **Minimal dependencies** - Only [pidusage](https://github.com/soyuka/pidusage) for process verification
26
- - **PID file management** - Survives terminal closes and system restarts
27
- - **PID reuse protection** - Verifies process identity before killing to prevent accidents
28
-
29
- ## Installation
30
-
31
- ```bash
32
- npm install -g @radleta/just-one
33
- ```
34
-
35
- Or use with npx (no install required):
36
-
37
- ```bash
38
- npx @radleta/just-one -n myapp -- npm run dev
39
- ```
40
-
41
- ## Usage
42
-
43
- ### Basic usage
44
-
45
- ```bash
46
- # Run storybook, killing any previous instance named "storybook"
47
- just-one -n storybook -- npx storybook dev -p 6006
48
-
49
- # Run vite dev server
50
- just-one -n vite -- npm run dev
51
-
52
- # Run any command
53
- just-one -n myapp -- node server.js
54
- ```
55
-
56
- ### Kill a named process
57
-
58
- ```bash
59
- just-one -k storybook
60
- just-one --kill myapp
61
- ```
62
-
63
- ### List tracked processes
64
-
65
- ```bash
66
- just-one -l
67
- just-one --list
68
- ```
69
-
70
- ### Specify custom PID directory
71
-
72
- ```bash
73
- # Default: ./.just-one/<name>.pid
74
- just-one -n storybook -- npx storybook dev
75
-
76
- # Custom directory
77
- just-one -n storybook -d /tmp -- npx storybook dev
78
- ```
79
-
80
- ## CLI Options
81
-
82
- | Option | Alias | Description |
83
- |--------|-------|-------------|
84
- | `--name <name>` | `-n` | Required for run. Name to identify this process |
85
- | `--kill <name>` | `-k` | Kill the named process and exit |
86
- | `--list` | `-l` | List all tracked processes and their status |
87
- | `--pid-dir <dir>` | `-d` | Directory for PID files (default: `.just-one/`) |
88
- | `--quiet` | `-q` | Suppress output |
89
- | `--help` | `-h` | Show help |
90
- | `--version` | `-v` | Show version |
91
-
92
- ## package.json Scripts
93
-
94
- ```json
95
- {
96
- "scripts": {
97
- "storybook": "just-one -n storybook -- storybook dev -p 6006",
98
- "dev": "just-one -n vite -- vite",
99
- "dev:api": "just-one -n api -- node server.js",
100
- "stop": "just-one -k storybook && just-one -k vite && just-one -k api"
101
- }
102
- }
103
- ```
104
-
105
- ## How It Works
106
-
107
- ```
108
- .just-one/
109
- storybook.pid # Contains: 12345
110
- vite.pid # Contains: 67890
111
- ```
112
-
113
- 1. Check if a PID file exists for that name
114
- 2. If yes, verify it's the same process we started (by comparing start times)
115
- 3. If verified, kill that specific process (and its children)
116
- 4. Start the new process
117
- 5. Save its PID for next time
118
-
119
- ### PID Reuse Protection
120
-
121
- Operating systems can reuse PIDs after a process terminates. To prevent accidentally killing an unrelated process that received the same PID, `just-one` compares:
122
- - The PID file's modification time (when we recorded the PID)
123
- - The process's actual start time (from the OS)
124
-
125
- If these don't match within 5 seconds, the PID file is considered stale and the process is not killed.
126
-
127
- ### Cross-Platform Process Handling
128
-
129
- | Platform | Kill Method |
130
- |----------|-------------|
131
- | Windows | `taskkill /PID <pid> /T /F` (kills process tree) |
132
- | Unix/Mac | `kill -SIGTERM -<pid>` (process group) |
133
-
134
- ## Use Cases
135
-
136
- - **Dev servers** - Storybook, Vite, webpack-dev-server, Next.js
137
- - **Background processes** - API servers, database seeders, watchers
138
- - **CI/CD** - Ensure clean state before running tests
139
- - **Multiple instances** - Run named instances on different ports
140
-
141
- ```bash
142
- # Run two storybooks on different ports
143
- just-one -n storybook-main -- storybook dev -p 6006
144
- just-one -n storybook-docs -- storybook dev -p 6007
145
- ```
146
-
147
- ## Comparison
148
-
149
- | Feature | just-one | kill-port | pm2 |
150
- |---------|----------|-----------|-----|
151
- | Kills by PID (precise) | Yes | No (by port) | Yes |
152
- | PID reuse protection | Yes | No | No |
153
- | Cross-platform | Yes | Yes | Yes |
154
- | Zero config | Yes | Yes | No |
155
- | Remembers processes | Yes (PID file) | No | Yes (daemon) |
156
- | Lightweight | Yes (1 dep) | Yes | Heavy |
157
- | Daemon required | No | No | Yes |
158
-
159
- ## Requirements
160
-
161
- - Node.js >= 18.0.0
162
-
163
- ## Development
164
-
165
- ```bash
166
- # Install dependencies
167
- npm install
168
-
169
- # Build
170
- npm run build
171
-
172
- # Run tests
173
- npm test
174
-
175
- # Lint + typecheck + test
176
- npm run validate
177
- ```
178
-
179
- ## License
180
-
181
- MIT
1
+ # just-one
2
+
3
+ A CLI tool that ensures only one instance of a command runs at a time. Kills the previous instance before starting a new one.
4
+
5
+ ## Why This Exists
6
+
7
+ When developing with dev servers (Storybook, Vite, webpack-dev-server, etc.), you often get:
8
+
9
+ ```
10
+ Error: Port 6006 is already in use
11
+ ```
12
+
13
+ Existing solutions have drawbacks:
14
+
15
+ - **kill-port** - Kills ANY process on that port (imprecise, might kill unrelated processes)
16
+ - **Manual** - Find PID, kill it, restart (tedious)
17
+ - **pm2** - Overkill for dev servers
18
+
19
+ `just-one` tracks processes by name using PID files. When you run a command, it kills the previous instance (if any) and starts fresh—precisely targeting only the process it started.
20
+
21
+ ## Features
22
+
23
+ - **Named process tracking** - Each process gets a unique name for precise targeting
24
+ - **Automatic cleanup** - Previous instance killed before starting new one
25
+ - **Daemon mode** - Run processes in the background with log file capture
26
+ - **Log viewing** - View captured logs, follow in real-time (like `tail -f`)
27
+ - **Log rotation** - Automatic rotation at 10MB (keeps 1 backup)
28
+ - **Cross-platform** - Works on Windows, macOS, and Linux
29
+ - **Minimal dependencies** - Only [pidusage](https://github.com/soyuka/pidusage) for process verification
30
+ - **PID file management** - Survives terminal closes and system restarts
31
+ - **PID reuse protection** - Verifies process identity before killing to prevent accidents
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install -g @radleta/just-one
37
+ ```
38
+
39
+ Or use with npx (no install required):
40
+
41
+ ```bash
42
+ npx @radleta/just-one -n myapp -- npm run dev
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ### Basic usage
48
+
49
+ ```bash
50
+ # Run storybook, killing any previous instance named "storybook"
51
+ just-one -n storybook -- npx storybook dev -p 6006
52
+
53
+ # Run vite dev server
54
+ just-one -n vite -- npm run dev
55
+
56
+ # Run any command
57
+ just-one -n myapp -- node server.js
58
+ ```
59
+
60
+ ### Ensure a process is running (idempotent)
61
+
62
+ ```bash
63
+ # Only starts if not already running — safe to call repeatedly
64
+ just-one -n vite -e -- npm run dev
65
+ ```
66
+
67
+ ### Daemon mode (background with log capture)
68
+
69
+ ```bash
70
+ # Run in background — parent exits immediately, output captured to log file
71
+ just-one -n myapp -D -- npm start
72
+
73
+ # Logs are written to .just-one/myapp.log
74
+ ```
75
+
76
+ ### Viewing logs
77
+
78
+ ```bash
79
+ # View all captured logs
80
+ just-one -L myapp
81
+
82
+ # View last 50 lines
83
+ just-one -L myapp --lines 50
84
+
85
+ # Follow logs in real-time (like tail -f) auto-exits when process dies
86
+ just-one -L myapp -f
87
+
88
+ # Show last 20 lines then follow
89
+ just-one -L myapp -f --lines 20
90
+ ```
91
+
92
+ ### Check if a process is running
93
+
94
+ ```bash
95
+ just-one -s storybook # exit 0 if running, exit 1 if stopped
96
+ just-one --status myapp
97
+ ```
98
+
99
+ ### Get the PID for scripting
100
+
101
+ ```bash
102
+ pid=$(just-one -p myapp -q) # prints just the PID number
103
+ ```
104
+
105
+ ### Kill a named process
106
+
107
+ ```bash
108
+ just-one -k storybook
109
+ just-one --kill myapp
110
+ ```
111
+
112
+ ### Kill all tracked processes
113
+
114
+ ```bash
115
+ just-one -K
116
+ just-one --kill-all
117
+ ```
118
+
119
+ ### Wait for a process to exit
120
+
121
+ ```bash
122
+ just-one -w myapp # wait indefinitely
123
+ just-one -w myapp -t 30 # wait up to 30 seconds
124
+ ```
125
+
126
+ ### List tracked processes
127
+
128
+ ```bash
129
+ just-one -l
130
+ just-one --list
131
+ ```
132
+
133
+ ### Clean up stale PID files and logs
134
+
135
+ ```bash
136
+ just-one --clean # removes stale PID files and their associated log files
137
+ ```
138
+
139
+ ### Specify custom PID directory
140
+
141
+ ```bash
142
+ # Default: ./.just-one/<name>.pid
143
+ just-one -n storybook -- npx storybook dev
144
+
145
+ # Custom directory
146
+ just-one -n storybook -d /tmp -- npx storybook dev
147
+ ```
148
+
149
+ ## CLI Options
150
+
151
+ | Option | Alias | Description |
152
+ | ------------------ | ----- | -------------------------------------------------- |
153
+ | `--name <name>` | `-n` | Required for run. Name to identify this process |
154
+ | `--daemon` | `-D` | Run in background with output captured to log file |
155
+ | `--logs <name>` | `-L` | View captured logs for a named process |
156
+ | `--tail` | `-f` | Follow log output in real-time (use with `--logs`) |
157
+ | `--lines <n>` | | Number of lines to show (use with `--logs`) |
158
+ | `--kill <name>` | `-k` | Kill the named process and exit |
159
+ | `--kill-all` | `-K` | Kill all tracked processes |
160
+ | `--status <name>` | `-s` | Check if a named process is running (exit 0/1) |
161
+ | `--ensure` | `-e` | Only start if not already running (use with `-n`) |
162
+ | `--pid <name>` | `-p` | Print the PID of a named process |
163
+ | `--wait <name>` | `-w` | Wait for a named process to exit |
164
+ | `--timeout <secs>` | `-t` | Timeout in seconds (use with `--wait`) |
165
+ | `--grace <secs>` | `-g` | Grace period before force kill (default: 5s) |
166
+ | `--clean` | | Remove stale PID files and orphaned log files |
167
+ | `--list` | `-l` | List all tracked processes and their status |
168
+ | `--pid-dir <dir>` | `-d` | Directory for PID files (default: `.just-one/`) |
169
+ | `--quiet` | `-q` | Suppress output |
170
+ | `--help` | `-h` | Show help |
171
+ | `--version` | `-v` | Show version |
172
+
173
+ ## package.json Scripts
174
+
175
+ ```json
176
+ {
177
+ "scripts": {
178
+ "storybook": "just-one -n storybook -- storybook dev -p 6006",
179
+ "dev": "just-one -n vite -e -- vite",
180
+ "dev:api": "just-one -n api -D -- node server.js",
181
+ "dev:logs": "just-one -L api -f",
182
+ "stop": "just-one -K"
183
+ }
184
+ }
185
+ ```
186
+
187
+ ## How It Works
188
+
189
+ ```
190
+ .just-one/
191
+ storybook.pid # Contains: 12345
192
+ storybook.log # Captured output (daemon mode only)
193
+ storybook.log.1 # Rotated backup (auto-managed)
194
+ vite.pid # Contains: 67890
195
+ ```
196
+
197
+ 1. Check if a PID file exists for that name
198
+ 2. If yes, verify it's the same process we started (by comparing start times)
199
+ 3. If verified, send SIGTERM and wait up to 5 seconds (configurable with `--grace`)
200
+ 4. If still alive, escalate to SIGKILL (force kill)
201
+ 5. Start the new process
202
+ 6. Save its PID for next time
203
+
204
+ ### PID Reuse Protection
205
+
206
+ Operating systems can reuse PIDs after a process terminates. To prevent accidentally killing an unrelated process that received the same PID, `just-one` compares:
207
+
208
+ - The PID file's modification time (when we recorded the PID)
209
+ - The process's actual start time (from the OS)
210
+
211
+ If these don't match within 5 seconds, the PID file is considered stale and the process is not killed.
212
+
213
+ ### Cross-Platform Process Handling
214
+
215
+ | Platform | Kill Method | Signal Handling |
216
+ | -------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
217
+ | Windows | `taskkill /PID <pid> /T /F` (kills process tree) | On Ctrl+C, relies on OS-delivered `CTRL_C_EVENT` for graceful shutdown with a force-kill safety net |
218
+ | Unix/Mac | `kill -SIGTERM -<pid>` (process group) | Forwards `SIGTERM` to child process |
219
+
220
+ **Windows graceful shutdown**: When the child shares the console (`stdio: 'inherit'`), Windows delivers `CTRL_C_EVENT` to all processes in the console group. `just-one` avoids calling `process.kill()` on the child (which uses `TerminateProcess` on Windows) to give the child time to run cleanup handlers. If the child doesn't exit within 2 seconds, it is force-killed as a safety net.
221
+
222
+ ## Use Cases
223
+
224
+ - **Dev servers** - Storybook, Vite, webpack-dev-server, Next.js
225
+ - **Background processes** - API servers, database seeders, watchers
226
+ - **CI/CD** - Ensure clean state before running tests
227
+ - **Multiple instances** - Run named instances on different ports
228
+
229
+ ```bash
230
+ # Run two storybooks on different ports
231
+ just-one -n storybook-main -- storybook dev -p 6006
232
+ just-one -n storybook-docs -- storybook dev -p 6007
233
+ ```
234
+
235
+ ## Comparison
236
+
237
+ | Feature | just-one | kill-port | pm2 |
238
+ | ---------------------- | -------------- | ------------ | ------------ |
239
+ | Kills by PID (precise) | Yes | No (by port) | Yes |
240
+ | PID reuse protection | Yes | No | No |
241
+ | Status check | Yes | No | Yes |
242
+ | Cross-platform | Yes | Yes | Yes |
243
+ | Zero config | Yes | Yes | No |
244
+ | Remembers processes | Yes (PID file) | No | Yes (daemon) |
245
+ | Lightweight | Yes (1 dep) | Yes | Heavy |
246
+ | Daemon mode | Optional | No | Yes |
247
+ | Log capture | Yes | No | Yes |
248
+
249
+ ## Requirements
250
+
251
+ - Node.js >= 20.0.0
252
+
253
+ ## Development
254
+
255
+ ```bash
256
+ # Install dependencies
257
+ npm install
258
+
259
+ # Build
260
+ npm run build
261
+
262
+ # Run tests
263
+ npm test
264
+
265
+ # Lint + typecheck + test
266
+ npm run validate
267
+ ```
268
+
269
+ ## License
270
+
271
+ MIT