@oh-my-pi/pi-utils 14.5.10 → 14.5.12
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 +2 -2
- package/src/index.ts +0 -1
- package/src/procmgr.ts +8 -138
- package/src/ptree.ts +6 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-utils",
|
|
4
|
-
"version": "14.5.
|
|
4
|
+
"version": "14.5.12",
|
|
5
5
|
"description": "Shared utilities for pi packages",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/bun": "^1.3",
|
|
41
|
-
"@oh-my-pi/pi-natives": "14.5.
|
|
41
|
+
"@oh-my-pi/pi-natives": "14.5.12"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"bun": ">=1.3.7"
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,6 @@ export * from "./mime";
|
|
|
15
15
|
export * from "./peek-file";
|
|
16
16
|
export * as postmortem from "./postmortem";
|
|
17
17
|
export * as procmgr from "./procmgr";
|
|
18
|
-
export { setNativeKillTree } from "./procmgr";
|
|
19
18
|
export * as prompt from "./prompt";
|
|
20
19
|
export * as ptree from "./ptree";
|
|
21
20
|
export { AbortError, ChildProcess, Exception, NonZeroExitError } from "./ptree";
|
package/src/procmgr.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { Process, ProcessStatus } from "@oh-my-pi/pi-natives";
|
|
4
4
|
import type { Subprocess } from "bun";
|
|
5
5
|
import { $env } from "./env";
|
|
6
6
|
import { $which } from "./which";
|
|
@@ -14,9 +14,6 @@ export interface ShellConfig {
|
|
|
14
14
|
|
|
15
15
|
let cachedShellConfig: ShellConfig | null = null;
|
|
16
16
|
|
|
17
|
-
const IS_WINDOWS = process.platform === "win32";
|
|
18
|
-
const TERM_SIGNAL = IS_WINDOWS ? undefined : "SIGTERM";
|
|
19
|
-
|
|
20
17
|
/**
|
|
21
18
|
* Check if a shell binary is executable.
|
|
22
19
|
*/
|
|
@@ -174,64 +171,20 @@ export function getShellConfig(customShellPath?: string): ShellConfig {
|
|
|
174
171
|
return cachedShellConfig;
|
|
175
172
|
}
|
|
176
173
|
|
|
177
|
-
/**
|
|
178
|
-
* Function signature for native process tree killing.
|
|
179
|
-
* Returns the number of processes killed.
|
|
180
|
-
*/
|
|
181
|
-
export type KillTreeFn = (pid: number, signal: number) => number;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Global native kill tree function, injected by pi-natives when loaded.
|
|
185
|
-
* Falls back to platform-specific behavior if not set.
|
|
186
|
-
*/
|
|
187
|
-
export let nativeKillTree: KillTreeFn | undefined;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Set the native kill tree function. Called by pi-natives on load.
|
|
191
|
-
*/
|
|
192
|
-
export function setNativeKillTree(fn: KillTreeFn): void {
|
|
193
|
-
nativeKillTree = fn;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Options for terminating a process and all its descendants.
|
|
198
|
-
*/
|
|
199
|
-
export interface TerminateOptions {
|
|
200
|
-
/** The process to terminate */
|
|
201
|
-
target: Subprocess | number;
|
|
202
|
-
/** Whether to terminate the process tree (all descendants) */
|
|
203
|
-
group?: boolean;
|
|
204
|
-
/** Timeout in milliseconds */
|
|
205
|
-
timeout?: number;
|
|
206
|
-
/** Abort signal */
|
|
207
|
-
signal?: AbortSignal;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
174
|
/**
|
|
211
175
|
* Check if a process is running.
|
|
212
176
|
*/
|
|
213
177
|
export function isPidRunning(pid: number | Subprocess): boolean {
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
} else {
|
|
218
|
-
if (pid.killed) return false;
|
|
219
|
-
if (pid.exitCode !== null) return false;
|
|
220
|
-
}
|
|
178
|
+
if (typeof pid !== "number") {
|
|
179
|
+
if (pid.killed) return false;
|
|
180
|
+
if (pid.exitCode !== null) return false;
|
|
221
181
|
return true;
|
|
222
|
-
} catch {
|
|
223
|
-
return false;
|
|
224
182
|
}
|
|
225
|
-
}
|
|
226
183
|
|
|
227
|
-
|
|
228
|
-
const nn = sigs.filter(Boolean) as AbortSignal[];
|
|
229
|
-
if (nn.length === 0) return undefined;
|
|
230
|
-
if (nn.length === 1) return nn[0];
|
|
231
|
-
return AbortSignal.any(nn);
|
|
184
|
+
return Process.fromPid(pid)?.status() === ProcessStatus.Running;
|
|
232
185
|
}
|
|
233
186
|
|
|
234
|
-
export function onProcessExit(proc: Subprocess | number, abortSignal?: AbortSignal): Promise<boolean> {
|
|
187
|
+
export async function onProcessExit(proc: Subprocess | number, abortSignal?: AbortSignal): Promise<boolean> {
|
|
235
188
|
if (typeof proc !== "number") {
|
|
236
189
|
return proc.exited.then(
|
|
237
190
|
() => true,
|
|
@@ -239,88 +192,5 @@ export function onProcessExit(proc: Subprocess | number, abortSignal?: AbortSign
|
|
|
239
192
|
);
|
|
240
193
|
}
|
|
241
194
|
|
|
242
|
-
|
|
243
|
-
return Promise.resolve(true);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const { promise, resolve, reject } = Promise.withResolvers<boolean>();
|
|
247
|
-
const localAbortController = new AbortController();
|
|
248
|
-
|
|
249
|
-
const timer = timers.promises.setInterval(300, null, {
|
|
250
|
-
signal: joinSignals(abortSignal, localAbortController.signal),
|
|
251
|
-
});
|
|
252
|
-
void (async () => {
|
|
253
|
-
try {
|
|
254
|
-
for await (const _ of timer) {
|
|
255
|
-
if (!isPidRunning(proc)) {
|
|
256
|
-
resolve(true);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
} catch (error) {
|
|
261
|
-
return reject(error);
|
|
262
|
-
} finally {
|
|
263
|
-
localAbortController.abort();
|
|
264
|
-
}
|
|
265
|
-
resolve(false);
|
|
266
|
-
})();
|
|
267
|
-
|
|
268
|
-
return promise;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Terminate a process and all its descendants.
|
|
273
|
-
*/
|
|
274
|
-
export async function terminate(options: TerminateOptions): Promise<boolean> {
|
|
275
|
-
const { target, group = false, timeout = 5000, signal } = options;
|
|
276
|
-
|
|
277
|
-
const abortController = new AbortController();
|
|
278
|
-
try {
|
|
279
|
-
const abortSignal = joinSignals(signal, abortController.signal);
|
|
280
|
-
|
|
281
|
-
// Determine PID
|
|
282
|
-
let pid: number | undefined;
|
|
283
|
-
const exitPromise = onProcessExit(target, abortSignal);
|
|
284
|
-
if (typeof target === "number") {
|
|
285
|
-
pid = target;
|
|
286
|
-
} else {
|
|
287
|
-
pid = target.pid;
|
|
288
|
-
if (target.killed) return true;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Give it a moment to exit gracefully first.
|
|
292
|
-
try {
|
|
293
|
-
if (typeof target === "number") {
|
|
294
|
-
process.kill(target, TERM_SIGNAL);
|
|
295
|
-
} else {
|
|
296
|
-
target.kill(TERM_SIGNAL);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (exitPromise) {
|
|
300
|
-
const exited = await Promise.race([Bun.sleep(1000).then(() => false), exitPromise]);
|
|
301
|
-
if (exited) return true;
|
|
302
|
-
}
|
|
303
|
-
} catch {}
|
|
304
|
-
|
|
305
|
-
if (nativeKillTree) {
|
|
306
|
-
nativeKillTree(pid, 9);
|
|
307
|
-
} else {
|
|
308
|
-
if (group && !IS_WINDOWS) {
|
|
309
|
-
try {
|
|
310
|
-
process.kill(-pid, "SIGKILL");
|
|
311
|
-
} catch {}
|
|
312
|
-
}
|
|
313
|
-
try {
|
|
314
|
-
if (typeof target === "number") {
|
|
315
|
-
process.kill(target, "SIGKILL");
|
|
316
|
-
} else {
|
|
317
|
-
target.kill("SIGKILL");
|
|
318
|
-
}
|
|
319
|
-
} catch {}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return await Promise.race([Bun.sleep(timeout).then(() => false), exitPromise]);
|
|
323
|
-
} finally {
|
|
324
|
-
abortController.abort();
|
|
325
|
-
}
|
|
195
|
+
return (await Process.fromPid(proc)?.waitForExit({ signal: abortSignal })) ?? true;
|
|
326
196
|
}
|
package/src/ptree.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* - Cross-platform tree kill for process groups (Windows taskkill, Unix -pid).
|
|
7
7
|
* - Convenience helpers: captureText / execText, AbortSignal, timeouts.
|
|
8
8
|
*/
|
|
9
|
+
|
|
10
|
+
import { Process } from "@oh-my-pi/pi-natives";
|
|
9
11
|
import type { Spawn, Subprocess } from "bun";
|
|
10
|
-
import { terminate } from "./procmgr";
|
|
11
12
|
|
|
12
13
|
type InMask = "pipe" | "ignore" | Buffer | Uint8Array | null;
|
|
13
14
|
|
|
@@ -215,7 +216,10 @@ export class ChildProcess<In extends InMask = InMask> {
|
|
|
215
216
|
|
|
216
217
|
kill(reason?: Exception) {
|
|
217
218
|
if (reason && !this.#exitReasonPending) this.#exitReasonPending = reason;
|
|
218
|
-
if (!this.proc.killed)
|
|
219
|
+
if (!this.proc.killed)
|
|
220
|
+
void Process.fromPid(this.proc.pid)
|
|
221
|
+
?.terminate()
|
|
222
|
+
?.catch(e => void e);
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
// ── Output helpers ───────────────────────────────────────────────────
|