@take-out/scripts 0.1.38 → 0.1.39-1772569727101

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@take-out/scripts",
3
- "version": "0.1.38",
3
+ "version": "0.1.39-1772569727101",
4
4
  "type": "module",
5
5
  "main": "./src/run.ts",
6
6
  "sideEffects": false,
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@clack/prompts": "^0.8.2",
32
32
  "@lydell/node-pty": "^1.2.0-beta.3",
33
- "@take-out/helpers": "0.1.38",
33
+ "@take-out/helpers": "0.1.39-1772569727101",
34
34
  "picocolors": "^1.1.1"
35
35
  },
36
36
  "peerDependencies": {
@@ -13,32 +13,19 @@ interface HandleProcessExitReturn {
13
13
  exit: (code?: number) => Promise<void>
14
14
  }
15
15
 
16
- // kill an entire process group (works because children are spawned with detached: true,
17
- // which makes them process group leaders). negative pid = kill the whole group.
18
- // this is synchronous, no pgrep needed, no races.
19
- function killProcessGroup(
16
+ function killProcess(
20
17
  pid: number,
21
18
  signal: NodeJS.Signals = 'SIGTERM',
22
19
  forceful: boolean = false
23
20
  ): void {
24
- // kill the process group (negative pid)
25
21
  try {
26
- process.kill(-pid, signal)
22
+ process.kill(pid, signal)
27
23
  } catch (_) {
28
- // group may already be gone, try the individual process
29
- try {
30
- process.kill(pid, signal)
31
- } catch (_) {
32
- // process already gone
33
- }
24
+ // process already gone
34
25
  }
35
26
 
36
27
  if (forceful && signal !== 'SIGKILL') {
37
- // schedule a SIGKILL followup
38
28
  setTimeout(() => {
39
- try {
40
- process.kill(-pid, 'SIGKILL')
41
- } catch (_) {}
42
29
  try {
43
30
  process.kill(pid, 'SIGKILL')
44
31
  } catch (_) {}
@@ -85,15 +72,12 @@ export function handleProcessExit({
85
72
  return
86
73
  }
87
74
 
88
- // kill process groups synchronously - no pgrep, no races
89
- // detached: true makes each child a process group leader,
90
- // so kill(-pid) gets the entire group in one syscall
91
75
  const isInterrupt = signal === 'SIGINT'
92
76
  const killSignal = isInterrupt ? 'SIGTERM' : (signal as NodeJS.Signals)
93
77
 
94
78
  for (const proc of processes) {
95
79
  if (proc.pid) {
96
- killProcessGroup(proc.pid, killSignal, isInterrupt)
80
+ killProcess(proc.pid, killSignal, isInterrupt)
97
81
  }
98
82
  }
99
83
 
@@ -103,7 +87,7 @@ export function handleProcessExit({
103
87
  // force kill any remaining
104
88
  for (const proc of processes) {
105
89
  if (proc.pid && !proc.exitCode) {
106
- killProcessGroup(proc.pid, 'SIGKILL')
90
+ killProcess(proc.pid, 'SIGKILL')
107
91
  }
108
92
  }
109
93
  }
package/src/run-pty.mjs CHANGED
@@ -258,7 +258,7 @@ function handleInput(data) {
258
258
  pendingAction = null
259
259
  console.log(match.shortcut)
260
260
  match.killed = true
261
- match.terminal.kill()
261
+ killProcessTree(match.terminal.pid)
262
262
  setTimeout(() => {
263
263
  spawnScript(match.name, match.cwd, match.label, match.extraArgs, match.index)
264
264
  console.log(`${getPrefix(match.index)} restarted`)
@@ -268,7 +268,7 @@ function handleInput(data) {
268
268
  console.log(match.shortcut)
269
269
  if (!match.killed) {
270
270
  match.killed = true
271
- match.terminal.kill()
271
+ killProcessTree(match.terminal.pid)
272
272
  console.log(`${getPrefix(match.index)} killed`)
273
273
  }
274
274
  } else {
@@ -286,6 +286,28 @@ function handleInput(data) {
286
286
  }
287
287
  }
288
288
 
289
+ // kill entire process group to prevent orphans
290
+ function killProcessTree(pid) {
291
+ if (!pid) return
292
+ // try killing process group first (negative pid)
293
+ try {
294
+ process.kill(-pid, 'SIGTERM')
295
+ } catch {}
296
+ // also kill direct process
297
+ try {
298
+ process.kill(pid, 'SIGTERM')
299
+ } catch {}
300
+ // schedule force kill
301
+ setTimeout(() => {
302
+ try {
303
+ process.kill(-pid, 'SIGKILL')
304
+ } catch {}
305
+ try {
306
+ process.kill(pid, 'SIGKILL')
307
+ } catch {}
308
+ }, 100)
309
+ }
310
+
289
311
  function cleanup() {
290
312
  // restore terminal to cooked mode before exiting
291
313
  if (process.stdin.isTTY && process.stdin.setRawMode) {
@@ -299,10 +321,12 @@ function cleanup() {
299
321
  for (const p of processes) {
300
322
  if (!p.killed) {
301
323
  p.killed = true
302
- p.terminal.kill()
324
+ killProcessTree(p.terminal.pid)
303
325
  }
304
326
  }
305
- process.exit(0)
327
+
328
+ // wait for kills to complete before exit
329
+ setTimeout(() => process.exit(0), 150)
306
330
  }
307
331
 
308
332
  async function main() {
package/src/run.ts CHANGED
@@ -235,7 +235,6 @@ const runScript = async (
235
235
  const proc = spawn('bun', runArgs, {
236
236
  stdio: ['ignore', 'pipe', 'pipe'],
237
237
  shell: false,
238
- detached: true,
239
238
  env: {
240
239
  ...process.env,
241
240
  FORCE_COLOR: '3',