@rubytech/taskmaster 1.0.91 → 1.0.92
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.
|
@@ -19,9 +19,7 @@ const applyPatchSchema = Type.Object({
|
|
|
19
19
|
description: "Patch content using the *** Begin Patch/End Patch format.",
|
|
20
20
|
}),
|
|
21
21
|
});
|
|
22
|
-
export function createApplyPatchTool(options = {}
|
|
23
|
-
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
|
|
24
|
-
) {
|
|
22
|
+
export function createApplyPatchTool(options = {}) {
|
|
25
23
|
const cwd = options.cwd ?? process.cwd();
|
|
26
24
|
const sandboxRoot = options.sandboxRoot;
|
|
27
25
|
return {
|
|
@@ -513,9 +513,7 @@ async function runExecProcess(opts) {
|
|
|
513
513
|
kill: () => killSession(session),
|
|
514
514
|
};
|
|
515
515
|
}
|
|
516
|
-
export function createExecTool(defaults
|
|
517
|
-
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
|
|
518
|
-
) {
|
|
516
|
+
export function createExecTool(defaults) {
|
|
519
517
|
const defaultBackgroundMs = clampNumber(defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"), 10_000, 10, 120_000);
|
|
520
518
|
const allowBackground = defaults?.allowBackground ?? true;
|
|
521
519
|
const defaultTimeoutSec = typeof defaults?.timeoutSec === "number" && defaults.timeoutSec > 0
|
|
@@ -15,9 +15,7 @@ const processSchema = Type.Object({
|
|
|
15
15
|
offset: Type.Optional(Type.Number({ description: "Log offset" })),
|
|
16
16
|
limit: Type.Optional(Type.Number({ description: "Log length" })),
|
|
17
17
|
});
|
|
18
|
-
export function createProcessTool(defaults
|
|
19
|
-
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
|
|
20
|
-
) {
|
|
18
|
+
export function createProcessTool(defaults) {
|
|
21
19
|
if (defaults?.cleanupMs !== undefined) {
|
|
22
20
|
setJobTtlMs(defaults.cleanupMs);
|
|
23
21
|
}
|
package/dist/build-info.json
CHANGED
|
@@ -1,24 +1,65 @@
|
|
|
1
|
+
import { listPortListeners, forceFreePortAndWait } from "../../cli/ports.js";
|
|
1
2
|
import { GatewayLockError } from "../../infra/gateway-lock.js";
|
|
3
|
+
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
4
|
+
const log = createSubsystemLogger("http-listen");
|
|
5
|
+
function tryListen(httpServer, port, bindHost) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const onError = (err) => {
|
|
8
|
+
httpServer.off("listening", onListening);
|
|
9
|
+
reject(err);
|
|
10
|
+
};
|
|
11
|
+
const onListening = () => {
|
|
12
|
+
httpServer.off("error", onError);
|
|
13
|
+
resolve();
|
|
14
|
+
};
|
|
15
|
+
httpServer.once("error", onError);
|
|
16
|
+
httpServer.once("listening", onListening);
|
|
17
|
+
httpServer.listen(port, bindHost);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if the process holding the port is a previous gateway instance.
|
|
22
|
+
* Only returns true for node/bun processes (which is what the gateway runs as).
|
|
23
|
+
*/
|
|
24
|
+
function isStaleGatewayProcess(port) {
|
|
25
|
+
try {
|
|
26
|
+
const listeners = listPortListeners(port);
|
|
27
|
+
if (listeners.length === 0)
|
|
28
|
+
return false;
|
|
29
|
+
return listeners.every((proc) => {
|
|
30
|
+
const cmd = proc.command?.toLowerCase() ?? "";
|
|
31
|
+
return cmd.includes("node") || cmd.includes("bun") || cmd.includes("taskmaster");
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
2
38
|
export async function listenGatewayHttpServer(params) {
|
|
3
39
|
const { httpServer, bindHost, port } = params;
|
|
4
40
|
try {
|
|
5
|
-
await
|
|
6
|
-
const onError = (err) => {
|
|
7
|
-
httpServer.off("listening", onListening);
|
|
8
|
-
reject(err);
|
|
9
|
-
};
|
|
10
|
-
const onListening = () => {
|
|
11
|
-
httpServer.off("error", onError);
|
|
12
|
-
resolve();
|
|
13
|
-
};
|
|
14
|
-
httpServer.once("error", onError);
|
|
15
|
-
httpServer.once("listening", onListening);
|
|
16
|
-
httpServer.listen(port, bindHost);
|
|
17
|
-
});
|
|
41
|
+
await tryListen(httpServer, port, bindHost);
|
|
18
42
|
}
|
|
19
43
|
catch (err) {
|
|
20
44
|
const code = err.code;
|
|
21
45
|
if (code === "EADDRINUSE") {
|
|
46
|
+
// Self-healing: if the port is held by a stale gateway instance (e.g.
|
|
47
|
+
// left behind after an upgrade), kill it and retry once. This prevents
|
|
48
|
+
// crash-loops where systemd keeps spawning new instances that can't bind.
|
|
49
|
+
if (isStaleGatewayProcess(port)) {
|
|
50
|
+
log.warn(`port ${port} held by stale gateway process — killing and retrying`);
|
|
51
|
+
try {
|
|
52
|
+
await forceFreePortAndWait(port, {
|
|
53
|
+
timeoutMs: 8000,
|
|
54
|
+
sigtermTimeoutMs: 3000,
|
|
55
|
+
});
|
|
56
|
+
await tryListen(httpServer, port, bindHost);
|
|
57
|
+
return; // Retry succeeded
|
|
58
|
+
}
|
|
59
|
+
catch (retryErr) {
|
|
60
|
+
throw new GatewayLockError(`port ${port} still in use after killing stale process: ${String(retryErr)}`, retryErr);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
22
63
|
throw new GatewayLockError(`another gateway instance is already listening on ws://${bindHost}:${port}`, err);
|
|
23
64
|
}
|
|
24
65
|
throw new GatewayLockError(`failed to bind gateway socket on ws://${bindHost}:${port}: ${String(err)}`, err);
|