teapot-coding-agent 0.37.101 → 0.37.103
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/dist/agent/kill.js
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
export function canKillProcessGroup(platform = process.platform) {
|
|
2
3
|
return platform !== "win32";
|
|
3
4
|
}
|
|
4
|
-
|
|
5
|
+
const runTaskkill = (file, args) => {
|
|
6
|
+
try {
|
|
7
|
+
const r = spawnSync(file, args, { stdio: "ignore", windowsHide: true });
|
|
8
|
+
return { status: r.status };
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return { status: null };
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export function killTree(child, platform = process.platform, run = runTaskkill) {
|
|
5
15
|
if (!child?.pid)
|
|
6
16
|
return { killed: false, wholeTree: false, reason: "no-pid" };
|
|
7
17
|
if (!canKillProcessGroup(platform)) {
|
|
18
|
+
/**
|
|
19
|
+
* Windows has no process groups, and `process.kill(pid)` terminates ONLY the process you name — the
|
|
20
|
+
* shell — so everything it started keeps running. That is not just a leak: the caller waits for the
|
|
21
|
+
* child's stdio to close, and a surviving grandchild holds those pipes open, so the tool call never
|
|
22
|
+
* returns even though the timeout fired (#190).
|
|
23
|
+
*
|
|
24
|
+
* `taskkill /T` walks the parent-child tree and is the only way to get all of it. If it is missing or
|
|
25
|
+
* refuses, fall back to the direct kill and SAY the tree is uncovered.
|
|
26
|
+
*/
|
|
27
|
+
const r = run("taskkill", ["/pid", String(child.pid), "/T", "/F"]);
|
|
28
|
+
if (r.status === 0)
|
|
29
|
+
return { killed: true, wholeTree: true };
|
|
8
30
|
try {
|
|
9
31
|
process.kill(child.pid, "SIGKILL");
|
|
10
32
|
return { killed: true, wholeTree: false };
|
|
@@ -39,11 +61,13 @@ export function killTree(child, platform = process.platform) {
|
|
|
39
61
|
}
|
|
40
62
|
}
|
|
41
63
|
export function describeKill(outcome) {
|
|
64
|
+
// "tree", not "process group": on Windows the mechanism is `taskkill /T`, and the report is read by an
|
|
65
|
+
// operator who cannot see which platform it came from
|
|
42
66
|
if (outcome.killed && outcome.wholeTree)
|
|
43
|
-
return "killed (whole process
|
|
67
|
+
return "killed (whole process tree)";
|
|
44
68
|
if (outcome.killed) {
|
|
45
|
-
return ("killed the process, but
|
|
46
|
-
"background
|
|
69
|
+
return ("killed the process, but its children may still be running — " +
|
|
70
|
+
"a background command it started could survive this");
|
|
47
71
|
}
|
|
48
72
|
switch (outcome.reason) {
|
|
49
73
|
case "no-pid":
|
package/dist/agent/tools.js
CHANGED
|
@@ -466,7 +466,7 @@ function runShell(cmd, ctx, timeoutMs, explicitTimeout = false) {
|
|
|
466
466
|
resolve({ ok: false, result: `spawn error: ${err.message}${elapsed(t0)}` });
|
|
467
467
|
}
|
|
468
468
|
});
|
|
469
|
-
|
|
469
|
+
const finish = (code, signal) => {
|
|
470
470
|
clearTimeout(timer);
|
|
471
471
|
ctx.signal?.removeEventListener("abort", onAbort);
|
|
472
472
|
if (done)
|
|
@@ -485,7 +485,23 @@ function runShell(cmd, ctx, timeoutMs, explicitTimeout = false) {
|
|
|
485
485
|
clip(out.trim() || "(no output)", ctx.maxOutputBytes) +
|
|
486
486
|
elapsed(t0),
|
|
487
487
|
});
|
|
488
|
+
};
|
|
489
|
+
/**
|
|
490
|
+
* `close` is the normal end: it fires only once the child AND everything holding its stdio has gone, so
|
|
491
|
+
* the output is complete.
|
|
492
|
+
*
|
|
493
|
+
* `exit` is the escape hatch for the kill paths, and without it a timeout can hang forever. `close`
|
|
494
|
+
* waits for the pipes to close, and a surviving grandchild holds those pipes open — measured on Linux
|
|
495
|
+
* with a child that leaves the process group: `exit` at 501ms, `close` still not fired 2.5s later. On
|
|
496
|
+
* Windows that is the NORMAL case, because `process.kill` cannot end anything but the shell (#190,
|
|
497
|
+
* "timeout時間超過って / stopおしても継続しちゃった"). Once a kill has been requested there is no more
|
|
498
|
+
* waiting to do, so settle on `exit`.
|
|
499
|
+
*/
|
|
500
|
+
child.on("exit", (code, signal) => {
|
|
501
|
+
if (killReason)
|
|
502
|
+
finish(code, signal);
|
|
488
503
|
});
|
|
504
|
+
child.on("close", (code, signal) => finish(code, signal));
|
|
489
505
|
});
|
|
490
506
|
}
|
|
491
507
|
function matchLines(text, needle) {
|