port-doctor-cli 1.0.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/bin/port-doctor.js +8 -0
  4. package/dist/cli/commands/free.d.ts +3 -0
  5. package/dist/cli/commands/free.d.ts.map +1 -0
  6. package/dist/cli/commands/free.js +120 -0
  7. package/dist/cli/commands/free.js.map +1 -0
  8. package/dist/cli/commands/overview.d.ts +3 -0
  9. package/dist/cli/commands/overview.d.ts.map +1 -0
  10. package/dist/cli/commands/overview.js +19 -0
  11. package/dist/cli/commands/overview.js.map +1 -0
  12. package/dist/cli/commands/run.d.ts +4 -0
  13. package/dist/cli/commands/run.d.ts.map +1 -0
  14. package/dist/cli/commands/run.js +133 -0
  15. package/dist/cli/commands/run.js.map +1 -0
  16. package/dist/cli/commands/why.d.ts +3 -0
  17. package/dist/cli/commands/why.d.ts.map +1 -0
  18. package/dist/cli/commands/why.js +24 -0
  19. package/dist/cli/commands/why.js.map +1 -0
  20. package/dist/cli/index.d.ts +3 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +200 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cli/output/formatter.d.ts +6 -0
  25. package/dist/cli/output/formatter.d.ts.map +1 -0
  26. package/dist/cli/output/formatter.js +177 -0
  27. package/dist/cli/output/formatter.js.map +1 -0
  28. package/dist/cli/output/json.d.ts +2 -0
  29. package/dist/cli/output/json.d.ts.map +1 -0
  30. package/dist/cli/output/json.js +6 -0
  31. package/dist/cli/output/json.js.map +1 -0
  32. package/dist/cli/output/tree.d.ts +3 -0
  33. package/dist/cli/output/tree.d.ts.map +1 -0
  34. package/dist/cli/output/tree.js +19 -0
  35. package/dist/cli/output/tree.js.map +1 -0
  36. package/dist/cli/prompts/confirm.d.ts +3 -0
  37. package/dist/cli/prompts/confirm.d.ts.map +1 -0
  38. package/dist/cli/prompts/confirm.js +53 -0
  39. package/dist/cli/prompts/confirm.js.map +1 -0
  40. package/dist/core/diagnosis/index.d.ts +4 -0
  41. package/dist/core/diagnosis/index.d.ts.map +1 -0
  42. package/dist/core/diagnosis/index.js +109 -0
  43. package/dist/core/diagnosis/index.js.map +1 -0
  44. package/dist/core/framework/index.d.ts +5 -0
  45. package/dist/core/framework/index.d.ts.map +1 -0
  46. package/dist/core/framework/index.js +211 -0
  47. package/dist/core/framework/index.js.map +1 -0
  48. package/dist/core/git/index.d.ts +3 -0
  49. package/dist/core/git/index.d.ts.map +1 -0
  50. package/dist/core/git/index.js +56 -0
  51. package/dist/core/git/index.js.map +1 -0
  52. package/dist/core/lifecycle/index.d.ts +8 -0
  53. package/dist/core/lifecycle/index.d.ts.map +1 -0
  54. package/dist/core/lifecycle/index.js +175 -0
  55. package/dist/core/lifecycle/index.js.map +1 -0
  56. package/dist/core/process/index.d.ts +9 -0
  57. package/dist/core/process/index.d.ts.map +1 -0
  58. package/dist/core/process/index.js +94 -0
  59. package/dist/core/process/index.js.map +1 -0
  60. package/dist/core/project/index.d.ts +3 -0
  61. package/dist/core/project/index.d.ts.map +1 -0
  62. package/dist/core/project/index.js +84 -0
  63. package/dist/core/project/index.js.map +1 -0
  64. package/dist/core/scanner/index.d.ts +5 -0
  65. package/dist/core/scanner/index.d.ts.map +1 -0
  66. package/dist/core/scanner/index.js +71 -0
  67. package/dist/core/scanner/index.js.map +1 -0
  68. package/dist/index.d.ts +11 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +11 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/platform/darwin.d.ts +27 -0
  73. package/dist/platform/darwin.d.ts.map +1 -0
  74. package/dist/platform/darwin.js +268 -0
  75. package/dist/platform/darwin.js.map +1 -0
  76. package/dist/platform/index.d.ts +4 -0
  77. package/dist/platform/index.d.ts.map +1 -0
  78. package/dist/platform/index.js +26 -0
  79. package/dist/platform/index.js.map +1 -0
  80. package/dist/platform/linux.d.ts +22 -0
  81. package/dist/platform/linux.d.ts.map +1 -0
  82. package/dist/platform/linux.js +217 -0
  83. package/dist/platform/linux.js.map +1 -0
  84. package/dist/platform/types.d.ts +40 -0
  85. package/dist/platform/types.d.ts.map +1 -0
  86. package/dist/platform/types.js +2 -0
  87. package/dist/platform/types.js.map +1 -0
  88. package/dist/platform/windows.d.ts +17 -0
  89. package/dist/platform/windows.d.ts.map +1 -0
  90. package/dist/platform/windows.js +138 -0
  91. package/dist/platform/windows.js.map +1 -0
  92. package/dist/types/index.d.ts +101 -0
  93. package/dist/types/index.d.ts.map +1 -0
  94. package/dist/types/index.js +2 -0
  95. package/dist/types/index.js.map +1 -0
  96. package/dist/utils/exec.d.ts +16 -0
  97. package/dist/utils/exec.d.ts.map +1 -0
  98. package/dist/utils/exec.js +51 -0
  99. package/dist/utils/exec.js.map +1 -0
  100. package/dist/utils/formatting.d.ts +10 -0
  101. package/dist/utils/formatting.d.ts.map +1 -0
  102. package/dist/utils/formatting.js +60 -0
  103. package/dist/utils/formatting.js.map +1 -0
  104. package/dist/utils/redaction.d.ts +5 -0
  105. package/dist/utils/redaction.d.ts.map +1 -0
  106. package/dist/utils/redaction.js +31 -0
  107. package/dist/utils/redaction.js.map +1 -0
  108. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Port Doctor Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ # Port Doctor 🩺
2
+
3
+ > Developer-first diagnostic, troubleshooting, and forensic CLI for local development ports.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/port-doctor-cli.svg?style=flat-square)](https://www.npmjs.com/package/port-doctor-cli)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)
7
+
8
+ **Port Doctor** answers the question every developer asks:
9
+ **`"Why won't my development server start?"`**
10
+
11
+ It bridges low-level kernel sockets and opaque PIDs with rich developer workspace context: **Project Name, Git Repository, Branch, Dirty Status, Framework, Process Tree, and Uptime**.
12
+
13
+ ---
14
+
15
+ ## ⚡ Why Port Doctor?
16
+
17
+ | Feature | `kill-port` | `fkill` | Raw `lsof` / `netstat` | **Port Doctor** |
18
+ | :--- | :---: | :---: | :---: | :---: |
19
+ | **Identifies Git Repo & Branch** | ❌ | ❌ | ❌ | **✅ Yes** |
20
+ | **Identifies Web Framework / Database** | ❌ | ❌ | ❌ | **✅ Yes** |
21
+ | **Shows Full Process Tree & CWD** | ❌ | ❌ | ❌ | **✅ Yes** |
22
+ | **Safe Graceful Termination (SIGINT first)** | ❌ (blind kill -9) | ⚠️ Partial | ❌ | **✅ Yes** |
23
+ | **PID Race Condition Protection** | ❌ | ❌ | ❌ | **✅ Yes** |
24
+ | **Auto-Healing `run` Wrapper** | ❌ | ❌ | ❌ | **✅ Yes** |
25
+ | **Redacts Passwords / Tokens in CLI** | ❌ | ❌ | ❌ | **✅ Yes** |
26
+ | **Minimal Dependencies & Fast Startup** | ⚠️ | ❌ | ⚠️ | **✅ Yes** |
27
+
28
+ ---
29
+
30
+ ## 🚀 Quick Start
31
+
32
+ Run directly with `npx` (using the `port-doctor-cli` package) — no global installation required:
33
+
34
+ ```bash
35
+ npx port-doctor-cli
36
+ ```
37
+
38
+ Or install globally to use the `port-doctor` command anywhere:
39
+
40
+ ```bash
41
+ npm install -g port-doctor-cli
42
+ ```
43
+
44
+ Once installed globally, you can run `port-doctor` directly:
45
+
46
+ ```bash
47
+ port-doctor
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 📖 Command Reference
53
+
54
+ ### 1. Default Overview: `port-doctor`
55
+ Scans common development and database ports (`3000-3005, 5173-5175, 8000, 8080, 5432, 6379, 27017, ...`) and displays active services.
56
+
57
+ ```bash
58
+ npx port-doctor-cli
59
+ ```
60
+
61
+ ```text
62
+ PORT DOCTOR v1.0.0 — Local Port Forensics & Diagnostics
63
+
64
+ PORT STATUS PROCESS PID PROJECT / SERVICE UPTIME
65
+ ──────────────────────────────────────────────────────────────────────────────
66
+ 3000 BUSY node 8212 storefront-ui (Next.js) 2h 14m
67
+ 5173 FREE - - - -
68
+ 6379 BUSY redis-server 8121 Redis 5h 30m
69
+ 27017 FREE - - - -
70
+ ──────────────────────────────────────────────────────────────────────────────
71
+ Scanned 18 ports • 2 occupied • 16 available
72
+ ```
73
+
74
+ Scan custom port ranges:
75
+ ```bash
76
+ npx port-doctor-cli --ports 3000,5173,8000-8080
77
+ ```
78
+
79
+ ---
80
+
81
+ ### 2. Forensic Diagnosis: `port-doctor why <port>`
82
+ The signature command. Explains exactly what process, directory, Git branch, and service is holding a port.
83
+
84
+ ```bash
85
+ npx port-doctor-cli why 3000
86
+ ```
87
+
88
+ ```text
89
+ ● PORT 3000 IS OCCUPIED
90
+
91
+ Process
92
+ Name: node
93
+ PID: 8212 (User: developer)
94
+ Command: npm run dev
95
+ Uptime: 2h 14m
96
+ Memory: 148.5 MB
97
+
98
+ Project
99
+ Name: storefront-ui
100
+ Path: /Users/developer/Projects/storefront-ui
101
+ Git: storefront-ui
102
+ Branch: feature/checkout-v2 [dirty: +3 files]
103
+
104
+ Service / Framework
105
+ Type: Next.js (web-framework)
106
+
107
+ Process Tree
108
+ VS Code (PID 4102)
109
+ └─ zsh (PID 4210)
110
+ └─ npm (PID 8200)
111
+ └─ node (PID 8212)
112
+
113
+ Listening on
114
+ 127.0.0.1:3000 (TCP)
115
+
116
+ Diagnosis
117
+ Port 3000 is occupied by Next.js (storefront-ui on branch 'feature/checkout-v2').
118
+
119
+ Suggested Action
120
+ Run 'port-doctor free 3000' to safely release the port.
121
+ ```
122
+
123
+ ---
124
+
125
+ ### 3. Safe Release: `port-doctor free <port...>`
126
+ Safely stops the process occupying a port. It first shows process and project details, attempts graceful `SIGINT` (Ctrl+C), then `SIGTERM`, and returns an error with instructions to use `--force` if the process resists graceful exit. It also verifies process identity immediately before sending kill signals to prevent PID race conditions.
127
+
128
+ ```bash
129
+ # Safe interactive release with confirmation (SIGINT -> SIGTERM)
130
+ npx port-doctor-cli free 3000
131
+
132
+ # Release multiple ports
133
+ npx port-doctor-cli free 3000 8080
134
+
135
+ # Explicit force termination (SIGKILL) without confirmation
136
+ npx port-doctor-cli free 3000 --force
137
+
138
+ # Dry run mode (simulate what would happen)
139
+ npx port-doctor-cli free 3000 --dry-run
140
+ ```
141
+
142
+ *(Aliases: `kill`, `release`)*
143
+
144
+ ---
145
+
146
+ ### 4. Auto-Healing Runner: `port-doctor run "<command>"`
147
+ Runs your development startup script. If the port is already occupied by a leftover process, it detects the conflict before starting and prompts you to safely release it gracefully before booting the dev server.
148
+
149
+ ```bash
150
+ npx port-doctor-cli run "npm run dev"
151
+ ```
152
+
153
+ ```text
154
+ ⚠ Port 3000 is already in use.
155
+ Process: node (PID 8212)
156
+ Project: old-storefront (branch: staging)
157
+ Command: npm run dev
158
+
159
+ How would you like to proceed?
160
+ 1. Stop existing process gracefully and start
161
+ 2. Cancel
162
+
163
+ Enter your choice (1-2): 1
164
+
165
+ Attempting graceful release of port 3000...
166
+ ✓ Port 3000 released.
167
+
168
+ Starting: npm run dev
169
+ ```
170
+
171
+ ---
172
+
173
+ ### 5. Global `--json` Mode
174
+ Outputs pure, machine-readable JSON across all commands for script automation and CI/CD pipelines.
175
+
176
+ ```bash
177
+ npx port-doctor-cli why 3000 --json
178
+ ```
179
+
180
+ ```json
181
+ {
182
+ "port": 3000,
183
+ "status": "busy",
184
+ "protocol": "tcp",
185
+ "address": "127.0.0.1",
186
+ "allAddresses": ["127.0.0.1", "::1"],
187
+ "pid": 8212,
188
+ "process": {
189
+ "pid": 8212,
190
+ "name": "node",
191
+ "command": "npm run dev",
192
+ "cwd": "/Users/developer/Projects/storefront-ui",
193
+ "uptimeSeconds": 8040,
194
+ "uptimeFormatted": "2h 14m"
195
+ },
196
+ "project": {
197
+ "name": "storefront-ui",
198
+ "rootDirectory": "/Users/developer/Projects/storefront-ui"
199
+ },
200
+ "git": {
201
+ "isGitRepo": true,
202
+ "repoName": "storefront-ui",
203
+ "branch": "feature/checkout-v2",
204
+ "isDirty": true,
205
+ "uncommittedFilesCount": 3
206
+ },
207
+ "framework": {
208
+ "name": "Next.js",
209
+ "category": "web-framework",
210
+ "confidence": "high"
211
+ },
212
+ "diagnosis": {
213
+ "type": "dev_server",
214
+ "severity": "warning",
215
+ "summary": "Port 3000 is occupied by Next.js (storefront-ui on branch 'feature/checkout-v2').",
216
+ "safeToFree": true
217
+ }
218
+ }
219
+ ```
220
+
221
+ For `port-doctor run "<command>" --json`, it executes a pre-flight port collision inspection and emits a structured `{ status: "ready" | "conflict", ... }` JSON payload without corrupting `stdout`.
222
+
223
+ ---
224
+
225
+ ## 💻 Programmatic Node.js API
226
+
227
+ You can also use Port Doctor inside your own Node.js / TypeScript code:
228
+
229
+ ```typescript
230
+ import { inspectPort, releasePort, scanDevPorts } from 'port-doctor-cli';
231
+
232
+ // Inspect a specific port
233
+ const info = await inspectPort(3000);
234
+ if (info.status === 'busy') {
235
+ console.log(`Port 3000 is used by ${info.project?.name} (${info.framework?.name})`);
236
+ }
237
+
238
+ // Safely release a port
239
+ const result = await releasePort(3000, { force: false });
240
+ console.log(`Port released: ${result.success}`);
241
+
242
+ // Scan active dev ports
243
+ const devPorts = await scanDevPorts();
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 🛡️ Security & Privacy
249
+
250
+ - **Credential Redaction**: Passwords, API tokens, bearer keys, and database connection strings in process command lines are automatically masked before terminal display or JSON output.
251
+ - **Command Execution**: `port-doctor run "<command>"` intentionally executes the user-supplied command through the platform shell. Internal process-management and diagnostic commands use structured argument execution instead of unnecessary shell interpolation.
252
+ - **Graceful Shutdown & Verification**: Attempts graceful shutdown (`SIGINT` then `SIGTERM`) and verifies process identity before sending signals to prevent PID race conditions. Escalates to force-kill (`SIGKILL`) only upon explicit user request (`--force`).
253
+
254
+ ---
255
+
256
+ ## 🌐 Platform Support
257
+
258
+ - **macOS** (Apple Silicon & Intel)
259
+ - **Linux** (Ubuntu, Debian, Fedora, Arch, Alpine)
260
+ - **Windows** (Windows 10, 11, Windows Server)
261
+
262
+ ---
263
+
264
+ ## 📄 License
265
+
266
+ MIT © Port Doctor Contributors
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runCLI } from '../dist/cli/index.js';
4
+
5
+ runCLI().catch((err) => {
6
+ console.error('\n✗ Unexpected Error:', err.message || err);
7
+ process.exit(1);
8
+ });
@@ -0,0 +1,3 @@
1
+ import { CLIArgs } from '../../types/index.js';
2
+ export declare function handleFree(ports: number[], args: CLIArgs): Promise<void>;
3
+ //# sourceMappingURL=free.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/free.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAc,MAAM,sBAAsB,CAAC;AAO3D,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA2H9E"}
@@ -0,0 +1,120 @@
1
+ import pc from 'picocolors';
2
+ import { inspectPort } from '../../core/process/index.js';
3
+ import { releasePort } from '../../core/lifecycle/index.js';
4
+ import { formatFreeResult } from '../output/formatter.js';
5
+ import { printJson } from '../output/json.js';
6
+ import { askConfirmation } from '../prompts/confirm.js';
7
+ export async function handleFree(ports, args) {
8
+ if (!ports || ports.length === 0) {
9
+ if (args.json) {
10
+ printJson({ status: 'error', error: 'No port specified to free.' });
11
+ }
12
+ else {
13
+ console.error(pc.red('\n✗ Error: Please specify at least one port to free (e.g. `port-doctor free 3000`).\n'));
14
+ }
15
+ process.exit(1);
16
+ }
17
+ const results = [];
18
+ for (const port of ports) {
19
+ if (isNaN(port) || port <= 0 || port > 65535) {
20
+ console.error(pc.red(`✗ Invalid port: ${port}`));
21
+ continue;
22
+ }
23
+ const info = await inspectPort(port, { deep: true });
24
+ if (info.status === 'free') {
25
+ const res = {
26
+ port,
27
+ pid: 0,
28
+ processName: 'none',
29
+ success: true,
30
+ method: 'none',
31
+ timeTakenMs: 0,
32
+ };
33
+ results.push(res);
34
+ if (!args.json) {
35
+ console.log(formatFreeResult(res));
36
+ }
37
+ continue;
38
+ }
39
+ // Dry run mode
40
+ if (args.dryRun) {
41
+ if (!args.json) {
42
+ console.log(pc.yellow(`[Dry Run] Would release port ${port} (PID ${info.pid} - ${info.process?.name || 'unknown'}, Project: ${info.project?.name || 'none'})`));
43
+ }
44
+ results.push({
45
+ port,
46
+ pid: info.pid || 0,
47
+ processName: info.process?.name || 'unknown',
48
+ projectName: info.project?.name,
49
+ success: true,
50
+ method: 'none',
51
+ timeTakenMs: 0,
52
+ });
53
+ continue;
54
+ }
55
+ // Safety protection: protect system processes and databases from accidental termination
56
+ if (info.diagnosis?.safeToFree === false && !args.force) {
57
+ const typeDesc = info.diagnosis.type === 'database' ? 'database' : 'system service';
58
+ const serviceName = info.framework?.name || info.process?.name || 'system process';
59
+ const reason = `Refusing to terminate ${serviceName} (PID ${info.pid}) on port ${port} because it is classified as a protected ${typeDesc}. Use 'port-doctor free ${port} --force' if you explicitly intend to terminate it.`;
60
+ if (!args.json) {
61
+ console.error(pc.red(`\n✗ Safety Protection: ${reason}\n`));
62
+ }
63
+ results.push({
64
+ port,
65
+ pid: info.pid || 0,
66
+ processName: info.process?.name || 'unknown',
67
+ projectName: info.project?.name,
68
+ success: false,
69
+ method: 'none',
70
+ timeTakenMs: 0,
71
+ error: reason,
72
+ });
73
+ continue;
74
+ }
75
+ // Confirmation prompt if not forced and in interactive terminal
76
+ if (!args.force && process.stdin.isTTY && !args.json) {
77
+ console.log('');
78
+ console.log(pc.bold(`Target: Port ${port}`));
79
+ console.log(` Process: ${pc.bold(info.process?.name || 'unknown')} (PID ${info.pid})`);
80
+ if (info.project?.name) {
81
+ console.log(` Project: ${pc.cyan(info.project.name)}${info.git?.branch ? ` (branch: ${info.git.branch})` : ''}`);
82
+ }
83
+ if (info.process?.fullCommand) {
84
+ console.log(` Command: ${info.process.fullCommand}`);
85
+ }
86
+ const confirmed = await askConfirmation(`Are you sure you want to release port ${port}?`, false);
87
+ if (!confirmed) {
88
+ console.log(pc.yellow(`Aborted release for port ${port}.\n`));
89
+ results.push({
90
+ port,
91
+ pid: info.pid || 0,
92
+ processName: info.process?.name || 'unknown',
93
+ projectName: info.project?.name,
94
+ success: false,
95
+ method: 'none',
96
+ timeTakenMs: 0,
97
+ error: 'User cancelled operation.',
98
+ });
99
+ continue;
100
+ }
101
+ }
102
+ const onProgress = !args.json ? (msg) => console.log(pc.dim(` ${msg}`)) : undefined;
103
+ const res = await releasePort(port, {
104
+ force: args.force,
105
+ timeoutMs: args.timeout,
106
+ onProgress,
107
+ });
108
+ results.push(res);
109
+ if (!args.json) {
110
+ console.log(formatFreeResult(res));
111
+ }
112
+ }
113
+ if (args.json) {
114
+ printJson({
115
+ status: results.every((r) => r.success) ? 'success' : 'partial_failure',
116
+ results,
117
+ });
118
+ }
119
+ }
120
+ //# sourceMappingURL=free.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free.js","sourceRoot":"","sources":["../../../src/cli/commands/free.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { CLIArgs } from '../../types/index.js';
2
+ export declare function handleOverview(args: CLIArgs): Promise<void>;
3
+ //# sourceMappingURL=overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overview.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/overview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAK/C,wBAAsB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjE"}
@@ -0,0 +1,19 @@
1
+ import { scanDevPorts, parsePortList } from '../../core/scanner/index.js';
2
+ import { formatOverviewTable } from '../output/formatter.js';
3
+ import { printJson } from '../output/json.js';
4
+ export async function handleOverview(args) {
5
+ const targetPorts = args.ports || parsePortList();
6
+ const results = await scanDevPorts(targetPorts);
7
+ if (args.json) {
8
+ printJson({
9
+ status: 'success',
10
+ totalScanned: results.length,
11
+ busyCount: results.filter((r) => r.status === 'busy').length,
12
+ freeCount: results.filter((r) => r.status === 'free').length,
13
+ ports: results,
14
+ });
15
+ return;
16
+ }
17
+ console.log(formatOverviewTable(results));
18
+ }
19
+ //# sourceMappingURL=overview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overview.js","sourceRoot":"","sources":["../../../src/cli/commands/overview.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAa;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;IAEhD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,SAAS,CAAC;YACR,MAAM,EAAE,SAAS;YACjB,YAAY,EAAE,OAAO,CAAC,MAAM;YAC5B,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;YAC5D,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;YAC5D,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { CLIArgs } from '../../types/index.js';
2
+ export declare function detectExpectedPort(command: string, cwd?: string): Promise<number | undefined>;
3
+ export declare function handleRun(rawCommand: string, args: CLIArgs): Promise<void>;
4
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAM/C,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsC1G;AAED,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFhF"}
@@ -0,0 +1,133 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs/promises';
3
+ import { spawn } from 'node:child_process';
4
+ import pc from 'picocolors';
5
+ import { inspectPort } from '../../core/process/index.js';
6
+ import { releasePort } from '../../core/lifecycle/index.js';
7
+ import { printJson } from '../output/json.js';
8
+ import { askChoice } from '../prompts/confirm.js';
9
+ export async function detectExpectedPort(command, cwd = process.cwd()) {
10
+ // 1. Check command line flags like --port 3000 or -p 5173 or PORT=3000
11
+ const portFlagMatch = command.match(/(?:--port|-p)\s+(\d+)/i) || command.match(/PORT=(\d+)/i);
12
+ if (portFlagMatch) {
13
+ const p = parseInt(portFlagMatch[1], 10);
14
+ if (!isNaN(p) && p > 0 && p <= 65535)
15
+ return p;
16
+ }
17
+ // 2. Check .env, .env.local, .env.development in cwd
18
+ const envFiles = ['.env.local', '.env.development', '.env'];
19
+ for (const envFile of envFiles) {
20
+ try {
21
+ const content = await fs.readFile(path.join(cwd, envFile), 'utf8');
22
+ const match = content.match(/^PORT\s*=\s*(\d+)/m);
23
+ if (match) {
24
+ const p = parseInt(match[1], 10);
25
+ if (!isNaN(p) && p > 0 && p <= 65535)
26
+ return p;
27
+ }
28
+ }
29
+ catch {
30
+ // ignore
31
+ }
32
+ }
33
+ // 3. Inspect package.json
34
+ try {
35
+ const pkgContent = await fs.readFile(path.join(cwd, 'package.json'), 'utf8');
36
+ const pkg = JSON.parse(pkgContent);
37
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
38
+ if (allDeps['vite'])
39
+ return 5173;
40
+ if (allDeps['next'])
41
+ return 3000;
42
+ if (allDeps['astro'])
43
+ return 4321;
44
+ if (allDeps['@nestjs/core'] || allDeps['express'] || allDeps['fastify'])
45
+ return 3000;
46
+ }
47
+ catch {
48
+ // ignore
49
+ }
50
+ return undefined;
51
+ }
52
+ export async function handleRun(rawCommand, args) {
53
+ if (!rawCommand || !rawCommand.trim()) {
54
+ if (args.json) {
55
+ printJson({ status: 'error', error: 'No command specified for `run`.' });
56
+ }
57
+ else {
58
+ console.error(pc.red('\n✗ Error: Please specify a command to run (e.g. `port-doctor run "npm run dev"`).\n'));
59
+ }
60
+ process.exit(1);
61
+ }
62
+ const expectedPort = await detectExpectedPort(rawCommand);
63
+ if (expectedPort) {
64
+ const portInfo = await inspectPort(expectedPort, { deep: true });
65
+ if (portInfo.status === 'busy') {
66
+ if (args.json) {
67
+ printJson({
68
+ status: 'conflict',
69
+ message: `Port ${expectedPort} is already in use.`,
70
+ port: expectedPort,
71
+ occupyingProcess: portInfo.process,
72
+ project: portInfo.project,
73
+ });
74
+ process.exit(1);
75
+ }
76
+ console.log('');
77
+ console.log(pc.yellow(pc.bold(`⚠ Port ${expectedPort} is already in use.`)));
78
+ console.log(` Process: ${pc.bold(portInfo.process?.name || 'unknown')} (PID ${portInfo.pid})`);
79
+ if (portInfo.project?.name) {
80
+ console.log(` Project: ${pc.cyan(portInfo.project.name)}${portInfo.git?.branch ? ` (branch: ${portInfo.git.branch})` : ''}`);
81
+ }
82
+ if (portInfo.process?.fullCommand) {
83
+ console.log(` Command: ${portInfo.process.fullCommand}`);
84
+ }
85
+ const choices = [
86
+ `Stop existing process gracefully and start`,
87
+ `Cancel`,
88
+ ];
89
+ const choiceIdx = await askChoice('How would you like to proceed?', choices);
90
+ if (choiceIdx === 0) {
91
+ // Attempt graceful release ONLY
92
+ console.log(pc.dim(`\nAttempting graceful release of port ${expectedPort}...`));
93
+ const freeRes = await releasePort(expectedPort, { force: false });
94
+ if (!freeRes.success) {
95
+ console.error(pc.red(`\n✗ Graceful stop failed (PID ${portInfo.pid} did not exit within timeout).`));
96
+ console.error(` To force-kill this process, run: ${pc.cyan(`port-doctor free ${expectedPort} --force`)}\n`);
97
+ process.exit(1);
98
+ }
99
+ console.log(pc.green(`✓ Port ${expectedPort} released.`));
100
+ }
101
+ else {
102
+ console.log(pc.dim('Operation cancelled.'));
103
+ process.exit(0);
104
+ }
105
+ }
106
+ }
107
+ // Handle JSON preflight mode without corrupting stdout
108
+ if (args.json) {
109
+ printJson({
110
+ status: 'ready',
111
+ message: expectedPort ? `Port ${expectedPort} is available.` : 'Command pre-flight passed.',
112
+ port: expectedPort,
113
+ command: rawCommand,
114
+ });
115
+ return;
116
+ }
117
+ // Execute user command with inherited stdio
118
+ console.log(pc.cyan(`\nStarting: ${pc.bold(rawCommand)}\n`));
119
+ const child = spawn(rawCommand, {
120
+ shell: true,
121
+ stdio: 'inherit',
122
+ env: process.env,
123
+ });
124
+ child.on('exit', (code, signal) => {
125
+ if (signal) {
126
+ process.kill(process.pid, signal);
127
+ }
128
+ else {
129
+ process.exit(code || 0);
130
+ }
131
+ });
132
+ }
133
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { CLIArgs } from '../../types/index.js';
2
+ export declare function handleWhy(port: number, args: CLIArgs): Promise<void>;
3
+ //# sourceMappingURL=why.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"why.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/why.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAK/C,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1E"}
@@ -0,0 +1,24 @@
1
+ import { inspectPort } from '../../core/process/index.js';
2
+ import { formatWhyReport } from '../output/formatter.js';
3
+ import { printJson } from '../output/json.js';
4
+ export async function handleWhy(port, args) {
5
+ if (isNaN(port) || port <= 0 || port > 65535) {
6
+ if (args.json) {
7
+ printJson({
8
+ status: 'error',
9
+ error: `Invalid port number: ${port}. Port must be an integer between 1 and 65535.`,
10
+ });
11
+ }
12
+ else {
13
+ console.error(`\n✗ Error: Invalid port number "${port}". Must be between 1 and 65535.\n`);
14
+ }
15
+ process.exit(1);
16
+ }
17
+ const info = await inspectPort(port, { deep: true });
18
+ if (args.json) {
19
+ printJson(info);
20
+ return;
21
+ }
22
+ console.log(formatWhyReport(info));
23
+ }
24
+ //# sourceMappingURL=why.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"why.js","sourceRoot":"","sources":["../../../src/cli/commands/why.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,IAAa;IACzD,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,SAAS,CAAC;gBACR,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,wBAAwB,IAAI,gDAAgD;aACpF,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,mCAAmC,IAAI,mCAAmC,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAErD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC"}