@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 +28 -0
- package/README.md +271 -181
- package/dist/index.js +697 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
###
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
#
|
|
143
|
-
just-one -n storybook
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|