goke 6.14.0 → 6.14.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA6IH,UAAU,kBAAkB;IAC1B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;;;GAUG;AACH,cAAM,aAAa;;IACjB,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAYxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAc1C;;;;;;OAMG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAkF9C;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDxD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAcpC;AAED;;;GAGG;AACH,iBAAS,mBAAmB,CAC1B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACvC,aAAa,CAEf;AAED,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAA;AAC7C,YAAY,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA6IH,UAAU,kBAAkB;IAC1B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;;;GAUG;AACH,cAAM,aAAa;;IACjB,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAYxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAc1C;;;;;;OAMG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAkF9C;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoExD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAcpC;AAED;;;GAGG;AACH,iBAAS,mBAAmB,CAC1B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACvC,aAAa,CAEf;AAED,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAA;AAC7C,YAAY,EAAE,kBAAkB,EAAE,CAAA"}
package/dist/daemon.js CHANGED
@@ -281,11 +281,38 @@ class DaemonContext {
281
281
  const execPath = this.#argv[0];
282
282
  const args = this.#argv.slice(1);
283
283
  const child = spawn(execPath, args, {
284
- detached: true,
284
+ // Detach only when running in background so the daemon outlives the
285
+ // parent. In attached mode, keep the child in the same process group
286
+ // so signals propagate naturally and the parent stays alive.
287
+ detached: !attach,
285
288
  stdio: attach ? ['ignore', 'inherit', 'inherit'] : 'ignore',
286
289
  env,
287
290
  });
288
- child.unref();
291
+ // Only unref when detached (non-attached) so the parent can exit
292
+ // immediately. In attached mode, the parent must stay alive to wait for
293
+ // the child's 'close' event — unref() would let the event loop drain
294
+ // and the parent would exit before the child finishes.
295
+ if (!attach) {
296
+ child.unref();
297
+ }
298
+ // Register close/error listeners immediately after spawn, before the
299
+ // PID file polling loop. If the child exits very quickly (writes PID
300
+ // file then exits), registering listeners after seeing the PID file
301
+ // could miss the 'close' event and hang the promise forever.
302
+ let childDone;
303
+ if (attach) {
304
+ childDone = new Promise((resolve, reject) => {
305
+ child.on('close', (code) => {
306
+ if (code && code !== 0) {
307
+ reject(new Error(`Daemon "${this.#cliName} ${this.#commandName}" exited with code ${code}`));
308
+ }
309
+ else {
310
+ resolve();
311
+ }
312
+ });
313
+ child.on('error', reject);
314
+ });
315
+ }
289
316
  // Brief wait to confirm the daemon started and wrote its PID file
290
317
  const startDeadline = Date.now() + 5000;
291
318
  while (Date.now() < startDeadline) {
@@ -294,18 +321,7 @@ class DaemonContext {
294
321
  if (pidData && isProcessAlive(pidData.pid)) {
295
322
  if (!attach)
296
323
  return;
297
- // Attached mode: wait for the daemon process to exit
298
- return new Promise((resolve, reject) => {
299
- child.on('close', (code) => {
300
- if (code && code !== 0) {
301
- reject(new Error(`Daemon "${this.#cliName} ${this.#commandName}" exited with code ${code}`));
302
- }
303
- else {
304
- resolve();
305
- }
306
- });
307
- child.on('error', reject);
308
- });
324
+ return childDone;
309
325
  }
310
326
  }
311
327
  throw new Error(`Failed to start daemon for "${this.#cliName} ${this.#commandName}"`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goke",
3
- "version": "6.14.0",
3
+ "version": "6.14.1",
4
4
  "type": "module",
5
5
  "description": "Simple yet powerful framework for building command-line apps. Inspired by cac.",
6
6
  "repository": {
package/src/daemon.ts CHANGED
@@ -340,12 +340,39 @@ class DaemonContext {
340
340
  const args = this.#argv.slice(1)
341
341
 
342
342
  const child = spawn(execPath, args, {
343
- detached: true,
343
+ // Detach only when running in background so the daemon outlives the
344
+ // parent. In attached mode, keep the child in the same process group
345
+ // so signals propagate naturally and the parent stays alive.
346
+ detached: !attach,
344
347
  stdio: attach ? ['ignore', 'inherit', 'inherit'] : 'ignore',
345
348
  env,
346
349
  })
347
350
 
348
- child.unref()
351
+ // Only unref when detached (non-attached) so the parent can exit
352
+ // immediately. In attached mode, the parent must stay alive to wait for
353
+ // the child's 'close' event — unref() would let the event loop drain
354
+ // and the parent would exit before the child finishes.
355
+ if (!attach) {
356
+ child.unref()
357
+ }
358
+
359
+ // Register close/error listeners immediately after spawn, before the
360
+ // PID file polling loop. If the child exits very quickly (writes PID
361
+ // file then exits), registering listeners after seeing the PID file
362
+ // could miss the 'close' event and hang the promise forever.
363
+ let childDone: Promise<void> | undefined
364
+ if (attach) {
365
+ childDone = new Promise<void>((resolve, reject) => {
366
+ child.on('close', (code) => {
367
+ if (code && code !== 0) {
368
+ reject(new Error(`Daemon "${this.#cliName} ${this.#commandName}" exited with code ${code}`))
369
+ } else {
370
+ resolve()
371
+ }
372
+ })
373
+ child.on('error', reject)
374
+ })
375
+ }
349
376
 
350
377
  // Brief wait to confirm the daemon started and wrote its PID file
351
378
  const startDeadline = Date.now() + 5000
@@ -354,18 +381,7 @@ class DaemonContext {
354
381
  const pidData = readPidFile(this.#pidFile)
355
382
  if (pidData && isProcessAlive(pidData.pid)) {
356
383
  if (!attach) return
357
-
358
- // Attached mode: wait for the daemon process to exit
359
- return new Promise<void>((resolve, reject) => {
360
- child.on('close', (code) => {
361
- if (code && code !== 0) {
362
- reject(new Error(`Daemon "${this.#cliName} ${this.#commandName}" exited with code ${code}`))
363
- } else {
364
- resolve()
365
- }
366
- })
367
- child.on('error', reject)
368
- })
384
+ return childDone
369
385
  }
370
386
  }
371
387