buncargo 1.0.11 → 1.0.13
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/core/process.ts +202 -12
- package/dist/bin.js +6 -6
- package/dist/cli.js +3 -3
- package/dist/core/index.js +10 -2
- package/dist/core/process.d.ts +39 -5
- package/dist/core/process.js +9 -1
- package/dist/core/watchdog.js +2 -2
- package/dist/environment.js +3 -3
- package/dist/index-6qd90dkp.js +117 -107
- package/dist/index-6srpc523.js +143 -0
- package/dist/index-75y4cg2z.js +58 -0
- package/dist/index-8gd8fkwx.js +99 -95
- package/dist/index-cty0bcry.js +248 -0
- package/dist/index-habjkmf5.js +51 -43
- package/dist/index-hb4y6f08.js +378 -371
- package/dist/index-j5a3rhx0.js +33 -31
- package/dist/index-ndnmnsej.js +390 -0
- package/dist/index-twc5zwja.js +127 -128
- package/dist/index-vhs88xhe.js +120 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -6
- package/dist/loader.js +4 -4
- package/environment.ts +2 -2
- package/index.ts +7 -1
- package/package.json +140 -140
package/core/process.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type SpawnOptions,
|
|
5
5
|
spawn,
|
|
6
6
|
} from "node:child_process";
|
|
7
|
+
import { platform } from "node:os";
|
|
7
8
|
import { resolve } from "node:path";
|
|
8
9
|
import type { AppConfig, DevServerPids, ExecOptions } from "../types";
|
|
9
10
|
|
|
@@ -93,19 +94,41 @@ export interface SpawnDevServerOptions {
|
|
|
93
94
|
verbose?: boolean;
|
|
94
95
|
detached?: boolean;
|
|
95
96
|
isCI?: boolean;
|
|
97
|
+
/** Kill any existing process using the port before starting. Default: true */
|
|
98
|
+
killExisting?: boolean;
|
|
99
|
+
/** The port this server will use (required if killExisting is true) */
|
|
100
|
+
port?: number;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
/**
|
|
99
104
|
* Spawn a dev server as a detached process.
|
|
105
|
+
* If killExisting is true and port is provided, kills any existing process on that port first.
|
|
100
106
|
*/
|
|
101
|
-
export function spawnDevServer(
|
|
107
|
+
export async function spawnDevServer(
|
|
102
108
|
command: string,
|
|
103
109
|
root: string,
|
|
104
110
|
appCwd: string | undefined,
|
|
105
111
|
envVars: Record<string, string>,
|
|
106
112
|
options: SpawnDevServerOptions = {},
|
|
107
|
-
): ChildProcess {
|
|
108
|
-
const {
|
|
113
|
+
): Promise<ChildProcess> {
|
|
114
|
+
const {
|
|
115
|
+
verbose = false,
|
|
116
|
+
detached = true,
|
|
117
|
+
isCI = false,
|
|
118
|
+
killExisting = true,
|
|
119
|
+
port,
|
|
120
|
+
} = options;
|
|
121
|
+
|
|
122
|
+
// Kill existing process on the port if requested
|
|
123
|
+
if (killExisting && port !== undefined) {
|
|
124
|
+
const existingPid = getProcessOnPort(port);
|
|
125
|
+
if (existingPid !== null) {
|
|
126
|
+
if (verbose) {
|
|
127
|
+
console.log(` ⚠️ Port ${port} is in use by process ${existingPid}`);
|
|
128
|
+
}
|
|
129
|
+
await killProcessOnPortAndWait(port, { verbose });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
109
132
|
|
|
110
133
|
// Parse command into parts
|
|
111
134
|
const parts = command.split(" ");
|
|
@@ -134,20 +157,31 @@ export function spawnDevServer(
|
|
|
134
157
|
return proc;
|
|
135
158
|
}
|
|
136
159
|
|
|
160
|
+
export interface StartDevServersOptions {
|
|
161
|
+
verbose?: boolean;
|
|
162
|
+
productionBuild?: boolean;
|
|
163
|
+
isCI?: boolean;
|
|
164
|
+
/** Kill any existing process using the port before starting. Default: true */
|
|
165
|
+
killExisting?: boolean;
|
|
166
|
+
}
|
|
167
|
+
|
|
137
168
|
/**
|
|
138
169
|
* Start all configured dev servers.
|
|
170
|
+
* If killExisting is true (default), any process already using a port will be killed first.
|
|
139
171
|
*/
|
|
140
|
-
export function startDevServers(
|
|
172
|
+
export async function startDevServers(
|
|
141
173
|
apps: Record<string, AppConfig>,
|
|
142
174
|
root: string,
|
|
143
175
|
envVars: Record<string, string>,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
176
|
+
ports: Record<string, number>,
|
|
177
|
+
options: StartDevServersOptions = {},
|
|
178
|
+
): Promise<DevServerPids> {
|
|
179
|
+
const {
|
|
180
|
+
verbose = true,
|
|
181
|
+
productionBuild = false,
|
|
182
|
+
isCI = false,
|
|
183
|
+
killExisting = true,
|
|
184
|
+
} = options;
|
|
151
185
|
const pids: DevServerPids = {};
|
|
152
186
|
|
|
153
187
|
if (verbose) {
|
|
@@ -163,9 +197,13 @@ export function startDevServers(
|
|
|
163
197
|
? (config.prodCommand ?? config.devCommand)
|
|
164
198
|
: config.devCommand;
|
|
165
199
|
|
|
166
|
-
const
|
|
200
|
+
const port = ports[name];
|
|
201
|
+
|
|
202
|
+
const proc = await spawnDevServer(command, root, config.cwd, envVars, {
|
|
167
203
|
verbose,
|
|
168
204
|
isCI,
|
|
205
|
+
killExisting,
|
|
206
|
+
port,
|
|
169
207
|
});
|
|
170
208
|
|
|
171
209
|
if (proc.pid) {
|
|
@@ -179,6 +217,158 @@ export function startDevServers(
|
|
|
179
217
|
return pids;
|
|
180
218
|
}
|
|
181
219
|
|
|
220
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
221
|
+
// Port Process Management
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get the PID of the process using a specific port.
|
|
226
|
+
* Returns null if no process is using the port.
|
|
227
|
+
*/
|
|
228
|
+
export function getProcessOnPort(port: number): number | null {
|
|
229
|
+
try {
|
|
230
|
+
const os = platform();
|
|
231
|
+
let output: string;
|
|
232
|
+
|
|
233
|
+
if (os === "win32") {
|
|
234
|
+
// Windows: use netstat
|
|
235
|
+
output = execSync(`netstat -ano | findstr :${port}`, {
|
|
236
|
+
encoding: "utf-8",
|
|
237
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
238
|
+
});
|
|
239
|
+
// Parse Windows netstat output: TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345
|
|
240
|
+
const lines = output.trim().split("\n");
|
|
241
|
+
for (const line of lines) {
|
|
242
|
+
// Only match LISTENING state
|
|
243
|
+
if (line.includes("LISTENING")) {
|
|
244
|
+
const parts = line.trim().split(/\s+/);
|
|
245
|
+
const pid = Number.parseInt(parts[parts.length - 1], 10);
|
|
246
|
+
if (!Number.isNaN(pid) && pid > 0) {
|
|
247
|
+
return pid;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
// macOS/Linux: use lsof
|
|
253
|
+
output = execSync(`lsof -ti :${port}`, {
|
|
254
|
+
encoding: "utf-8",
|
|
255
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
256
|
+
});
|
|
257
|
+
const pid = Number.parseInt(output.trim().split("\n")[0], 10);
|
|
258
|
+
if (!Number.isNaN(pid) && pid > 0) {
|
|
259
|
+
return pid;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return null;
|
|
264
|
+
} catch {
|
|
265
|
+
// No process found on port (command exits with error)
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Check if a port is currently in use.
|
|
272
|
+
*/
|
|
273
|
+
export function isPortInUse(port: number): boolean {
|
|
274
|
+
return getProcessOnPort(port) !== null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Kill the process using a specific port.
|
|
279
|
+
* Returns true if a process was killed, false if no process was using the port.
|
|
280
|
+
*/
|
|
281
|
+
export function killProcessOnPort(
|
|
282
|
+
port: number,
|
|
283
|
+
options: { verbose?: boolean; signal?: NodeJS.Signals } = {},
|
|
284
|
+
): boolean {
|
|
285
|
+
const { verbose = false, signal = "SIGTERM" } = options;
|
|
286
|
+
|
|
287
|
+
const pid = getProcessOnPort(port);
|
|
288
|
+
if (pid === null) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
if (verbose) {
|
|
294
|
+
console.log(` Killing process ${pid} on port ${port}`);
|
|
295
|
+
}
|
|
296
|
+
process.kill(pid, signal);
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
// Process may have already exited
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Kill the process on port and wait for it to fully release the port.
|
|
306
|
+
* Uses SIGTERM first, then SIGKILL if the process doesn't exit.
|
|
307
|
+
*/
|
|
308
|
+
export async function killProcessOnPortAndWait(
|
|
309
|
+
port: number,
|
|
310
|
+
options: { verbose?: boolean; timeout?: number } = {},
|
|
311
|
+
): Promise<boolean> {
|
|
312
|
+
const { verbose = false, timeout = 5000 } = options;
|
|
313
|
+
|
|
314
|
+
const pid = getProcessOnPort(port);
|
|
315
|
+
if (pid === null) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (verbose) {
|
|
320
|
+
console.log(` Killing process ${pid} on port ${port}...`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// First try SIGTERM
|
|
324
|
+
try {
|
|
325
|
+
process.kill(pid, "SIGTERM");
|
|
326
|
+
} catch {
|
|
327
|
+
// Process may have already exited
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Wait for port to be released
|
|
332
|
+
const startTime = Date.now();
|
|
333
|
+
const checkInterval = 100;
|
|
334
|
+
|
|
335
|
+
while (Date.now() - startTime < timeout) {
|
|
336
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
337
|
+
|
|
338
|
+
if (!isPortInUse(port)) {
|
|
339
|
+
if (verbose) {
|
|
340
|
+
console.log(` ✓ Port ${port} released`);
|
|
341
|
+
}
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// If still running, try SIGKILL
|
|
347
|
+
if (verbose) {
|
|
348
|
+
console.log(` Process ${pid} didn't exit, sending SIGKILL...`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
process.kill(pid, "SIGKILL");
|
|
353
|
+
} catch {
|
|
354
|
+
// Process may have already exited
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Wait a bit more for SIGKILL
|
|
358
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
359
|
+
|
|
360
|
+
const released = !isPortInUse(port);
|
|
361
|
+
if (verbose) {
|
|
362
|
+
if (released) {
|
|
363
|
+
console.log(` ✓ Port ${port} released after SIGKILL`);
|
|
364
|
+
} else {
|
|
365
|
+
console.log(` ⚠ Port ${port} still in use`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return released;
|
|
370
|
+
}
|
|
371
|
+
|
|
182
372
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
183
373
|
// Process Management
|
|
184
374
|
// ═══════════════════════════════════════════════════════════════════════════
|
package/dist/bin.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
runCli
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-6srpc523.js";
|
|
5
5
|
import {
|
|
6
6
|
loadDevEnv
|
|
7
|
-
} from "./index-
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-
|
|
7
|
+
} from "./index-75y4cg2z.js";
|
|
8
|
+
import"./index-ndnmnsej.js";
|
|
9
|
+
import"./index-vhs88xhe.js";
|
|
10
|
+
import"./index-cty0bcry.js";
|
|
11
11
|
import"./index-tjqw9vtj.js";
|
|
12
12
|
import"./index-5hka0tff.js";
|
|
13
13
|
import"./index-2fr3g85b.js";
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
var require_package = __commonJS((exports, module) => {
|
|
22
22
|
module.exports = {
|
|
23
23
|
name: "buncargo",
|
|
24
|
-
version: "1.0.
|
|
24
|
+
version: "1.0.13",
|
|
25
25
|
description: "A Bun-powered development environment CLI for managing Docker Compose services, dev servers, and environment variables",
|
|
26
26
|
type: "module",
|
|
27
27
|
module: "./dist/index.js",
|
package/dist/cli.js
CHANGED
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
getFlagValue,
|
|
3
3
|
hasFlag,
|
|
4
4
|
runCli
|
|
5
|
-
} from "./index-
|
|
6
|
-
import"./index-
|
|
7
|
-
import"./index-
|
|
5
|
+
} from "./index-6srpc523.js";
|
|
6
|
+
import"./index-vhs88xhe.js";
|
|
7
|
+
import"./index-cty0bcry.js";
|
|
8
8
|
import"./index-qnx9j3qa.js";
|
|
9
9
|
export {
|
|
10
10
|
runCli,
|
package/dist/core/index.js
CHANGED
|
@@ -9,17 +9,21 @@ import {
|
|
|
9
9
|
startHeartbeat,
|
|
10
10
|
stopHeartbeat,
|
|
11
11
|
stopWatchdog
|
|
12
|
-
} from "../index-
|
|
12
|
+
} from "../index-vhs88xhe.js";
|
|
13
13
|
import {
|
|
14
14
|
buildApps,
|
|
15
15
|
exec,
|
|
16
16
|
execAsync,
|
|
17
|
+
getProcessOnPort,
|
|
18
|
+
isPortInUse,
|
|
17
19
|
isProcessAlive,
|
|
20
|
+
killProcessOnPort,
|
|
21
|
+
killProcessOnPortAndWait,
|
|
18
22
|
spawnDevServer,
|
|
19
23
|
startDevServers,
|
|
20
24
|
stopAllProcesses,
|
|
21
25
|
stopProcess
|
|
22
|
-
} from "../index-
|
|
26
|
+
} from "../index-cty0bcry.js";
|
|
23
27
|
import {
|
|
24
28
|
MAX_ATTEMPTS,
|
|
25
29
|
POLL_INTERVAL,
|
|
@@ -78,9 +82,12 @@ export {
|
|
|
78
82
|
logFrontendPort,
|
|
79
83
|
logExpoApiUrl,
|
|
80
84
|
logApiUrl,
|
|
85
|
+
killProcessOnPortAndWait,
|
|
86
|
+
killProcessOnPort,
|
|
81
87
|
isWorktree,
|
|
82
88
|
isWatchdogRunning,
|
|
83
89
|
isProcessAlive,
|
|
90
|
+
isPortInUse,
|
|
84
91
|
isPortAvailable,
|
|
85
92
|
isContainerRunning,
|
|
86
93
|
isCI,
|
|
@@ -88,6 +95,7 @@ export {
|
|
|
88
95
|
getWatchdogPidFile,
|
|
89
96
|
getWatchdogPid,
|
|
90
97
|
getProjectName,
|
|
98
|
+
getProcessOnPort,
|
|
91
99
|
getLocalIp,
|
|
92
100
|
getHeartbeatFile,
|
|
93
101
|
getEnvVar,
|
package/dist/core/process.d.ts
CHANGED
|
@@ -17,19 +17,53 @@ export interface SpawnDevServerOptions {
|
|
|
17
17
|
verbose?: boolean;
|
|
18
18
|
detached?: boolean;
|
|
19
19
|
isCI?: boolean;
|
|
20
|
+
/** Kill any existing process using the port before starting. Default: true */
|
|
21
|
+
killExisting?: boolean;
|
|
22
|
+
/** The port this server will use (required if killExisting is true) */
|
|
23
|
+
port?: number;
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
26
|
* Spawn a dev server as a detached process.
|
|
27
|
+
* If killExisting is true and port is provided, kills any existing process on that port first.
|
|
23
28
|
*/
|
|
24
|
-
export declare function spawnDevServer(command: string, root: string, appCwd: string | undefined, envVars: Record<string, string>, options?: SpawnDevServerOptions): ChildProcess
|
|
29
|
+
export declare function spawnDevServer(command: string, root: string, appCwd: string | undefined, envVars: Record<string, string>, options?: SpawnDevServerOptions): Promise<ChildProcess>;
|
|
30
|
+
export interface StartDevServersOptions {
|
|
31
|
+
verbose?: boolean;
|
|
32
|
+
productionBuild?: boolean;
|
|
33
|
+
isCI?: boolean;
|
|
34
|
+
/** Kill any existing process using the port before starting. Default: true */
|
|
35
|
+
killExisting?: boolean;
|
|
36
|
+
}
|
|
25
37
|
/**
|
|
26
38
|
* Start all configured dev servers.
|
|
39
|
+
* If killExisting is true (default), any process already using a port will be killed first.
|
|
40
|
+
*/
|
|
41
|
+
export declare function startDevServers(apps: Record<string, AppConfig>, root: string, envVars: Record<string, string>, ports: Record<string, number>, options?: StartDevServersOptions): Promise<DevServerPids>;
|
|
42
|
+
/**
|
|
43
|
+
* Get the PID of the process using a specific port.
|
|
44
|
+
* Returns null if no process is using the port.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getProcessOnPort(port: number): number | null;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a port is currently in use.
|
|
27
49
|
*/
|
|
28
|
-
export declare function
|
|
50
|
+
export declare function isPortInUse(port: number): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Kill the process using a specific port.
|
|
53
|
+
* Returns true if a process was killed, false if no process was using the port.
|
|
54
|
+
*/
|
|
55
|
+
export declare function killProcessOnPort(port: number, options?: {
|
|
29
56
|
verbose?: boolean;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
57
|
+
signal?: NodeJS.Signals;
|
|
58
|
+
}): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Kill the process on port and wait for it to fully release the port.
|
|
61
|
+
* Uses SIGTERM first, then SIGKILL if the process doesn't exit.
|
|
62
|
+
*/
|
|
63
|
+
export declare function killProcessOnPortAndWait(port: number, options?: {
|
|
64
|
+
verbose?: boolean;
|
|
65
|
+
timeout?: number;
|
|
66
|
+
}): Promise<boolean>;
|
|
33
67
|
/**
|
|
34
68
|
* Stop a process by PID.
|
|
35
69
|
*/
|
package/dist/core/process.js
CHANGED
|
@@ -2,19 +2,27 @@ import {
|
|
|
2
2
|
buildApps,
|
|
3
3
|
exec,
|
|
4
4
|
execAsync,
|
|
5
|
+
getProcessOnPort,
|
|
6
|
+
isPortInUse,
|
|
5
7
|
isProcessAlive,
|
|
8
|
+
killProcessOnPort,
|
|
9
|
+
killProcessOnPortAndWait,
|
|
6
10
|
spawnDevServer,
|
|
7
11
|
startDevServers,
|
|
8
12
|
stopAllProcesses,
|
|
9
13
|
stopProcess
|
|
10
|
-
} from "../index-
|
|
14
|
+
} from "../index-cty0bcry.js";
|
|
11
15
|
import"../index-qnx9j3qa.js";
|
|
12
16
|
export {
|
|
13
17
|
stopProcess,
|
|
14
18
|
stopAllProcesses,
|
|
15
19
|
startDevServers,
|
|
16
20
|
spawnDevServer,
|
|
21
|
+
killProcessOnPortAndWait,
|
|
22
|
+
killProcessOnPort,
|
|
17
23
|
isProcessAlive,
|
|
24
|
+
isPortInUse,
|
|
25
|
+
getProcessOnPort,
|
|
18
26
|
execAsync,
|
|
19
27
|
exec,
|
|
20
28
|
buildApps
|
package/dist/core/watchdog.js
CHANGED
package/dist/environment.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createDevEnvironment
|
|
3
|
-
} from "./index-
|
|
4
|
-
import"./index-
|
|
5
|
-
import"./index-
|
|
3
|
+
} from "./index-ndnmnsej.js";
|
|
4
|
+
import"./index-vhs88xhe.js";
|
|
5
|
+
import"./index-cty0bcry.js";
|
|
6
6
|
import"./index-tjqw9vtj.js";
|
|
7
7
|
import"./index-5hka0tff.js";
|
|
8
8
|
import"./index-2fr3g85b.js";
|