nexus-agents 2.83.0 → 2.84.0
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/{child-mcp-config-XVPIO5HV.js → child-mcp-config-VSGPMVLL.js} +3 -3
- package/dist/{chunk-5T6SYCH2.js → chunk-2PKAWFEU.js} +3 -2
- package/dist/chunk-2PKAWFEU.js.map +1 -0
- package/dist/{chunk-I2HMWH4R.js → chunk-2WCYG75B.js} +13 -2
- package/dist/chunk-2WCYG75B.js.map +1 -0
- package/dist/{chunk-PMLVZXAE.js → chunk-3PFESR6I.js} +1864 -1633
- package/dist/chunk-3PFESR6I.js.map +1 -0
- package/dist/{chunk-54UXPJVM.js → chunk-4IXQ6IXI.js} +2 -2
- package/dist/{chunk-FI77TGBY.js → chunk-5LFUZ5IC.js} +2 -2
- package/dist/{chunk-633WH2ML.js → chunk-6T3EPABN.js} +1 -1
- package/dist/chunk-6T3EPABN.js.map +1 -0
- package/dist/{chunk-ZM5JKJHI.js → chunk-BX3MUA26.js} +2 -2
- package/dist/{chunk-3ASED5PR.js → chunk-CJHIKBWI.js} +4 -4
- package/dist/{chunk-Z64MSLEK.js → chunk-D5BKSM6H.js} +2 -2
- package/dist/{chunk-3WUVWZUC.js → chunk-GBGMTN7O.js} +2 -2
- package/dist/{chunk-RXVH52UI.js → chunk-HLNMWGW3.js} +27 -4
- package/dist/chunk-HLNMWGW3.js.map +1 -0
- package/dist/{chunk-3GJAAENS.js → chunk-I3O5WOGW.js} +4 -4
- package/dist/{chunk-AFPHR72D.js → chunk-KK2RZVPU.js} +2 -2
- package/dist/{chunk-PPBZQKRP.js → chunk-KRRBRT7B.js} +6 -6
- package/dist/{chunk-YO27YAEX.js → chunk-KVYQOOML.js} +8 -24
- package/dist/chunk-KVYQOOML.js.map +1 -0
- package/dist/{chunk-BZUEUD4G.js → chunk-MBD5EJBO.js} +3 -3
- package/dist/{chunk-FHGDJKCZ.js → chunk-OE7OL2BE.js} +155 -47
- package/dist/chunk-OE7OL2BE.js.map +1 -0
- package/dist/{chunk-WJFUTRHX.js → chunk-OROUYVUX.js} +2 -2
- package/dist/{chunk-RVRXKNND.js → chunk-QIRZSDJK.js} +2 -2
- package/dist/{chunk-L362KRSU.js → chunk-REH5BB67.js} +78 -63
- package/dist/chunk-REH5BB67.js.map +1 -0
- package/dist/{chunk-NLPMYBIV.js → chunk-RZVEVT3M.js} +7 -7
- package/dist/{chunk-WGSRH5EQ.js → chunk-T6B6CKU6.js} +4 -4
- package/dist/chunk-T6B6CKU6.js.map +1 -0
- package/dist/{chunk-Q6PZMGLU.js → chunk-UJMIGLZI.js} +2 -2
- package/dist/{chunk-ZIWEEVMI.js → chunk-V35FWPHD.js} +2 -2
- package/dist/{chunk-4BXQ2OZY.js → chunk-V7RC2PIY.js} +20 -38
- package/dist/chunk-V7RC2PIY.js.map +1 -0
- package/dist/{chunk-AINOJRZX.js → chunk-VQIWH6X4.js} +9 -9
- package/dist/{chunk-2W4QJ27D.js → chunk-VXHDZULO.js} +3 -3
- package/dist/{chunk-U6LDVJS7.js → chunk-XK523BNC.js} +2 -2
- package/dist/chunk-YVG32OQF.js +27 -0
- package/dist/chunk-YVG32OQF.js.map +1 -0
- package/dist/{chunk-6WDJ3IE4.js → chunk-ZJGCOJC6.js} +4 -4
- package/dist/{cli-circuit-breaker-Y26NPPNO.js → cli-circuit-breaker-6EQKYNAA.js} +5 -5
- package/dist/cli.js +37 -34
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-X2ZYIEHH.js → composite-router-SA4XHXA3.js} +3 -3
- package/dist/consensus-vote-QKUHNHS4.js +31 -0
- package/dist/context-retriever-XX4TQBIB.js +19 -0
- package/dist/{doctor-deep-2E2GBMYR.js → doctor-deep-NB7IDWJE.js} +4 -4
- package/dist/expert-bridge-4MHM77VW.js +13 -0
- package/dist/{factory-STNVY3Y3.js → factory-FKOPQXRS.js} +6 -5
- package/dist/factory-UHH4ZZ64.js +14 -0
- package/dist/index.d.ts +114 -149
- package/dist/index.js +63 -128
- package/dist/index.js.map +1 -1
- package/dist/{init-opencode-6LVZ4CAQ.js → init-opencode-AVYAC33Q.js} +6 -6
- package/dist/issue-triage-7PYND7PY.js +15 -0
- package/dist/{learning-persistence-NX2KHL5T.js → learning-persistence-5ALG6XRC.js} +2 -2
- package/dist/{registry-command-P5VIAEOL.js → registry-command-7SFNZRG5.js} +3 -3
- package/dist/{repo-security-plan-RHSLO7H6.js → repo-security-plan-MTVL5B73.js} +4 -4
- package/dist/{research-helpers-synthesize-PVP6JRZV.js → research-helpers-synthesize-6CJ5P4WL.js} +4 -4
- package/dist/{routing-memory-QRIJPRVD.js → routing-memory-Y577PXFP.js} +3 -3
- package/dist/{session-memory-WARRGYY7.js → session-memory-6YFGMEMP.js} +4 -4
- package/dist/{setup-command-GMP5FI7F.js → setup-command-YBTD6D53.js} +13 -12
- package/dist/setup-config-BQYLUJHY.js +10 -0
- package/dist/{setup-custom-api-B63X7ISD.js → setup-custom-api-ZB7LOQC5.js} +5 -5
- package/dist/{tool-memory-E7JW4YLT.js → tool-memory-GFYQFRQI.js} +7 -6
- package/dist/{weather-report-RACZWJQL.js → weather-report-CN6WPJI4.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-4BXQ2OZY.js.map +0 -1
- package/dist/chunk-5T6SYCH2.js.map +0 -1
- package/dist/chunk-633WH2ML.js.map +0 -1
- package/dist/chunk-FHGDJKCZ.js.map +0 -1
- package/dist/chunk-I2HMWH4R.js.map +0 -1
- package/dist/chunk-L362KRSU.js.map +0 -1
- package/dist/chunk-PMLVZXAE.js.map +0 -1
- package/dist/chunk-RXVH52UI.js.map +0 -1
- package/dist/chunk-WGSRH5EQ.js.map +0 -1
- package/dist/chunk-YO27YAEX.js.map +0 -1
- package/dist/consensus-vote-KZ6UURUI.js +0 -30
- package/dist/context-retriever-QY4FNTDZ.js +0 -18
- package/dist/expert-bridge-FHPWDFJX.js +0 -13
- package/dist/factory-W6KROBFN.js +0 -14
- package/dist/issue-triage-Y77JI7WF.js +0 -15
- package/dist/setup-config-G3KKZM7O.js +0 -10
- /package/dist/{child-mcp-config-XVPIO5HV.js.map → child-mcp-config-VSGPMVLL.js.map} +0 -0
- /package/dist/{chunk-54UXPJVM.js.map → chunk-4IXQ6IXI.js.map} +0 -0
- /package/dist/{chunk-FI77TGBY.js.map → chunk-5LFUZ5IC.js.map} +0 -0
- /package/dist/{chunk-ZM5JKJHI.js.map → chunk-BX3MUA26.js.map} +0 -0
- /package/dist/{chunk-3ASED5PR.js.map → chunk-CJHIKBWI.js.map} +0 -0
- /package/dist/{chunk-Z64MSLEK.js.map → chunk-D5BKSM6H.js.map} +0 -0
- /package/dist/{chunk-3WUVWZUC.js.map → chunk-GBGMTN7O.js.map} +0 -0
- /package/dist/{chunk-3GJAAENS.js.map → chunk-I3O5WOGW.js.map} +0 -0
- /package/dist/{chunk-AFPHR72D.js.map → chunk-KK2RZVPU.js.map} +0 -0
- /package/dist/{chunk-PPBZQKRP.js.map → chunk-KRRBRT7B.js.map} +0 -0
- /package/dist/{chunk-BZUEUD4G.js.map → chunk-MBD5EJBO.js.map} +0 -0
- /package/dist/{chunk-WJFUTRHX.js.map → chunk-OROUYVUX.js.map} +0 -0
- /package/dist/{chunk-RVRXKNND.js.map → chunk-QIRZSDJK.js.map} +0 -0
- /package/dist/{chunk-NLPMYBIV.js.map → chunk-RZVEVT3M.js.map} +0 -0
- /package/dist/{chunk-Q6PZMGLU.js.map → chunk-UJMIGLZI.js.map} +0 -0
- /package/dist/{chunk-ZIWEEVMI.js.map → chunk-V35FWPHD.js.map} +0 -0
- /package/dist/{chunk-AINOJRZX.js.map → chunk-VQIWH6X4.js.map} +0 -0
- /package/dist/{chunk-2W4QJ27D.js.map → chunk-VXHDZULO.js.map} +0 -0
- /package/dist/{chunk-U6LDVJS7.js.map → chunk-XK523BNC.js.map} +0 -0
- /package/dist/{chunk-6WDJ3IE4.js.map → chunk-ZJGCOJC6.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-Y26NPPNO.js.map → cli-circuit-breaker-6EQKYNAA.js.map} +0 -0
- /package/dist/{composite-router-X2ZYIEHH.js.map → composite-router-SA4XHXA3.js.map} +0 -0
- /package/dist/{consensus-vote-KZ6UURUI.js.map → consensus-vote-QKUHNHS4.js.map} +0 -0
- /package/dist/{context-retriever-QY4FNTDZ.js.map → context-retriever-XX4TQBIB.js.map} +0 -0
- /package/dist/{doctor-deep-2E2GBMYR.js.map → doctor-deep-NB7IDWJE.js.map} +0 -0
- /package/dist/{expert-bridge-FHPWDFJX.js.map → expert-bridge-4MHM77VW.js.map} +0 -0
- /package/dist/{factory-STNVY3Y3.js.map → factory-FKOPQXRS.js.map} +0 -0
- /package/dist/{factory-W6KROBFN.js.map → factory-UHH4ZZ64.js.map} +0 -0
- /package/dist/{init-opencode-6LVZ4CAQ.js.map → init-opencode-AVYAC33Q.js.map} +0 -0
- /package/dist/{issue-triage-Y77JI7WF.js.map → issue-triage-7PYND7PY.js.map} +0 -0
- /package/dist/{learning-persistence-NX2KHL5T.js.map → learning-persistence-5ALG6XRC.js.map} +0 -0
- /package/dist/{registry-command-P5VIAEOL.js.map → registry-command-7SFNZRG5.js.map} +0 -0
- /package/dist/{repo-security-plan-RHSLO7H6.js.map → repo-security-plan-MTVL5B73.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-PVP6JRZV.js.map → research-helpers-synthesize-6CJ5P4WL.js.map} +0 -0
- /package/dist/{routing-memory-QRIJPRVD.js.map → routing-memory-Y577PXFP.js.map} +0 -0
- /package/dist/{session-memory-WARRGYY7.js.map → session-memory-6YFGMEMP.js.map} +0 -0
- /package/dist/{setup-command-GMP5FI7F.js.map → setup-command-YBTD6D53.js.map} +0 -0
- /package/dist/{setup-config-G3KKZM7O.js.map → setup-config-BQYLUJHY.js.map} +0 -0
- /package/dist/{setup-custom-api-B63X7ISD.js.map → setup-custom-api-ZB7LOQC5.js.map} +0 -0
- /package/dist/{tool-memory-E7JW4YLT.js.map → tool-memory-GFYQFRQI.js.map} +0 -0
- /package/dist/{weather-report-RACZWJQL.js.map → weather-report-CN6WPJI4.js.map} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GitHubProvider,
|
|
3
3
|
ScmError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-REH5BB67.js";
|
|
5
5
|
import {
|
|
6
6
|
CACHE_TIMEOUTS,
|
|
7
7
|
createLogger,
|
|
8
8
|
err,
|
|
9
9
|
getTimeProvider,
|
|
10
10
|
ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HLNMWGW3.js";
|
|
12
12
|
|
|
13
13
|
// src/security/trust-types.ts
|
|
14
14
|
import { z } from "zod";
|
|
@@ -1656,4 +1656,4 @@ export {
|
|
|
1656
1656
|
IssueTriage,
|
|
1657
1657
|
createIssueTriage
|
|
1658
1658
|
};
|
|
1659
|
-
//# sourceMappingURL=chunk-
|
|
1659
|
+
//# sourceMappingURL=chunk-MBD5EJBO.js.map
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CliCircuitBreaker,
|
|
3
3
|
DEFAULT_CIRCUIT_BREAKER_CONFIG
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2PKAWFEU.js";
|
|
5
|
+
import {
|
|
6
|
+
generateHyphenId
|
|
7
|
+
} from "./chunk-YVG32OQF.js";
|
|
5
8
|
import {
|
|
6
9
|
CLI_SUBPROCESS_TIMEOUTS,
|
|
7
10
|
CLI_TIMEOUTS,
|
|
@@ -24,7 +27,7 @@ import {
|
|
|
24
27
|
getTimeProvider,
|
|
25
28
|
isRateLimitText,
|
|
26
29
|
ok
|
|
27
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-HLNMWGW3.js";
|
|
28
31
|
|
|
29
32
|
// src/cli-adapters/subprocess-adapter.ts
|
|
30
33
|
import { spawn } from "child_process";
|
|
@@ -150,10 +153,30 @@ var CapacityTracker = class {
|
|
|
150
153
|
usageHistory;
|
|
151
154
|
requestCount;
|
|
152
155
|
windowStart;
|
|
156
|
+
/**
|
|
157
|
+
* Timestamps of every recorded request (#3026 finding 4).
|
|
158
|
+
*
|
|
159
|
+
* Pre-fix, `requestCount` was a plain counter reset only by the
|
|
160
|
+
* tumbling-window branch of `pruneOldEntries`. Under continuous
|
|
161
|
+
* traffic across a window boundary, that branch drops requests that
|
|
162
|
+
* are still inside the *sliding* window — e.g. with windowMs=60s, a
|
|
163
|
+
* request at t=59s followed by one at t=61s would tumbling-reset
|
|
164
|
+
* the counter to 1 even though the t=59s request is still inside
|
|
165
|
+
* the [1s, 61s] window. The downstream `remainingRequests === 0`
|
|
166
|
+
* exhaustion check fired prematurely (or too late) depending on
|
|
167
|
+
* burst patterns.
|
|
168
|
+
*
|
|
169
|
+
* Counting via a per-request timestamp array that's pruned the same
|
|
170
|
+
* way as `usageHistory` keeps the two views consistent. Every
|
|
171
|
+
* `recordUsage` pushes here; `requestCount` is derived from
|
|
172
|
+
* `.length` after pruning.
|
|
173
|
+
*/
|
|
174
|
+
requestTimestamps;
|
|
153
175
|
constructor(config) {
|
|
154
176
|
this.config = config;
|
|
155
177
|
this.usageHistory = [];
|
|
156
178
|
this.requestCount = 0;
|
|
179
|
+
this.requestTimestamps = [];
|
|
157
180
|
this.windowStart = getTimeProvider().now();
|
|
158
181
|
}
|
|
159
182
|
/**
|
|
@@ -162,7 +185,8 @@ var CapacityTracker = class {
|
|
|
162
185
|
recordUsage(usage) {
|
|
163
186
|
const now = getTimeProvider().now();
|
|
164
187
|
this.pruneOldEntries(now);
|
|
165
|
-
this.
|
|
188
|
+
this.requestTimestamps.push(now);
|
|
189
|
+
this.requestCount = this.requestTimestamps.length;
|
|
166
190
|
if (usage !== void 0) {
|
|
167
191
|
const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;
|
|
168
192
|
this.usageHistory.push({
|
|
@@ -206,6 +230,7 @@ var CapacityTracker = class {
|
|
|
206
230
|
*/
|
|
207
231
|
reset() {
|
|
208
232
|
this.usageHistory.length = 0;
|
|
233
|
+
this.requestTimestamps.length = 0;
|
|
209
234
|
this.requestCount = 0;
|
|
210
235
|
this.windowStart = getTimeProvider().now();
|
|
211
236
|
}
|
|
@@ -226,16 +251,19 @@ var CapacityTracker = class {
|
|
|
226
251
|
*/
|
|
227
252
|
pruneOldEntries(now) {
|
|
228
253
|
const cutoff = now - this.config.windowMs;
|
|
229
|
-
|
|
230
|
-
this.usageHistory.length = 0;
|
|
231
|
-
this.requestCount = 0;
|
|
232
|
-
this.windowStart = now;
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
let firstEntry = this.usageHistory[0];
|
|
236
|
-
while (firstEntry !== void 0 && firstEntry.timestamp < cutoff) {
|
|
254
|
+
while (this.usageHistory[0] !== void 0 && this.usageHistory[0].timestamp < cutoff) {
|
|
237
255
|
this.usageHistory.shift();
|
|
238
|
-
|
|
256
|
+
}
|
|
257
|
+
while (this.requestTimestamps[0] !== void 0 && this.requestTimestamps[0] < cutoff) {
|
|
258
|
+
this.requestTimestamps.shift();
|
|
259
|
+
}
|
|
260
|
+
this.requestCount = this.requestTimestamps.length;
|
|
261
|
+
const earliestRequest = this.requestTimestamps[0];
|
|
262
|
+
const earliestUsage = this.usageHistory[0]?.timestamp;
|
|
263
|
+
if (earliestRequest === void 0 && earliestUsage === void 0) {
|
|
264
|
+
this.windowStart = now;
|
|
265
|
+
} else {
|
|
266
|
+
this.windowStart = Math.min(earliestRequest ?? Infinity, earliestUsage ?? Infinity);
|
|
239
267
|
}
|
|
240
268
|
}
|
|
241
269
|
};
|
|
@@ -842,6 +870,7 @@ var TRANSIENT_RETRY_DELAYS_MS = [500, 1e3];
|
|
|
842
870
|
var MAX_TRANSIENT_RETRIES = TRANSIENT_RETRY_DELAYS_MS.length;
|
|
843
871
|
var MAX_PARSE_RETRIES = 1;
|
|
844
872
|
var TIMEOUT_RETRY_MULTIPLIER = 1.5;
|
|
873
|
+
var SIGKILL_GRACE_MS = 5e3;
|
|
845
874
|
function isTransientError(code) {
|
|
846
875
|
return TRANSIENT_ERROR_CODES.has(code);
|
|
847
876
|
}
|
|
@@ -885,6 +914,42 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
885
914
|
shouldOuterRetry(opts) {
|
|
886
915
|
return opts.allowRetry && !this.transientRetry.enabled;
|
|
887
916
|
}
|
|
917
|
+
/**
|
|
918
|
+
* Invokes the optional cleanup hook supplied by getCommand(). Sync
|
|
919
|
+
* throws are swallowed (warn-only) and async rejections are caught
|
|
920
|
+
* so cleanup failures never bubble up and mask the real subprocess
|
|
921
|
+
* result.
|
|
922
|
+
*/
|
|
923
|
+
runSubprocessCleanup(cleanup) {
|
|
924
|
+
if (cleanup === void 0) return;
|
|
925
|
+
try {
|
|
926
|
+
const r = cleanup();
|
|
927
|
+
if (r instanceof Promise) {
|
|
928
|
+
r.catch((e) => {
|
|
929
|
+
this.logger.warn("Subprocess cleanup failed", { error: String(e) });
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
} catch (e) {
|
|
933
|
+
this.logger.warn("Subprocess cleanup threw", { error: String(e) });
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* #3026 finding 2: SIGTERM the child when the caller's AbortSignal
|
|
938
|
+
* aborts mid-execution. Listener auto-detaches on `'close'` so we
|
|
939
|
+
* don't leak across child lifetimes.
|
|
940
|
+
*/
|
|
941
|
+
attachAbortSignal(child, signal, resolve) {
|
|
942
|
+
const onAbort = () => {
|
|
943
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
944
|
+
child.kill("SIGTERM");
|
|
945
|
+
}
|
|
946
|
+
resolve(err(this.createError("TIMEOUT", "Aborted by caller signal")));
|
|
947
|
+
};
|
|
948
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
949
|
+
child.once("close", () => {
|
|
950
|
+
signal.removeEventListener("abort", onAbort);
|
|
951
|
+
});
|
|
952
|
+
}
|
|
888
953
|
/**
|
|
889
954
|
* Executes a task via subprocess, with optional transient-error retry.
|
|
890
955
|
* When `transientRetry.enabled` is true, transient errors (timeout,
|
|
@@ -892,15 +957,16 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
892
957
|
* (500ms, 1000ms). Parse errors get max 1 retry (#1533); others get 2.
|
|
893
958
|
*/
|
|
894
959
|
async executeTask(task, options) {
|
|
895
|
-
const
|
|
960
|
+
const requestId = generateHyphenId("cli-req", 8);
|
|
961
|
+
const result = await this.spawnSubprocess(task, options, requestId);
|
|
896
962
|
if (result.ok || !this.transientRetry.enabled) return result;
|
|
897
963
|
if (!isTransientError(result.error.code)) return result;
|
|
898
|
-
return this.retryTransient(task, options, result, 0);
|
|
964
|
+
return this.retryTransient(task, options, result, 0, requestId);
|
|
899
965
|
}
|
|
900
966
|
/**
|
|
901
967
|
* Retries a transient error with bounded exponential backoff.
|
|
902
968
|
*/
|
|
903
|
-
async retryTransient(task, options, lastResult, attempt) {
|
|
969
|
+
async retryTransient(task, options, lastResult, attempt, requestId) {
|
|
904
970
|
const isParseError = !lastResult.ok && lastResult.error.code === "PARSE_ERROR";
|
|
905
971
|
const maxRetries = isParseError ? MAX_PARSE_RETRIES : MAX_TRANSIENT_RETRIES;
|
|
906
972
|
if (attempt >= maxRetries) return lastResult;
|
|
@@ -908,40 +974,38 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
908
974
|
const isTimeout = !lastResult.ok && lastResult.error.code === "TIMEOUT";
|
|
909
975
|
subprocessLogger.debug("Retrying transient error", {
|
|
910
976
|
cli: this.name,
|
|
977
|
+
requestId,
|
|
911
978
|
attempt: attempt + 1,
|
|
912
979
|
delayMs,
|
|
913
980
|
errorCode: !lastResult.ok ? lastResult.error.code : void 0
|
|
914
981
|
});
|
|
915
982
|
await this.delay(delayMs);
|
|
916
983
|
const retryOptions = isTimeout ? { ...options, timeoutMs: Math.round(options.timeoutMs * TIMEOUT_RETRY_MULTIPLIER) } : options;
|
|
917
|
-
const result = await this.spawnSubprocess(task, retryOptions);
|
|
984
|
+
const result = await this.spawnSubprocess(task, retryOptions, requestId);
|
|
918
985
|
if (result.ok) return result;
|
|
919
986
|
if (!isTransientError(result.error.code)) return result;
|
|
920
|
-
return this.retryTransient(task, retryOptions, result, attempt + 1);
|
|
987
|
+
return this.retryTransient(task, retryOptions, result, attempt + 1, requestId);
|
|
921
988
|
}
|
|
922
989
|
/**
|
|
923
990
|
* Spawns a single subprocess execution (no retry).
|
|
924
|
-
|
|
925
|
-
|
|
991
|
+
*
|
|
992
|
+
* `requestId` (#2963 site 3) correlates the timing-breakdown log emitted
|
|
993
|
+
* on subprocess close back to the parent `executeTask` invocation —
|
|
994
|
+
* essential when multiple subprocesses for the same CLI run concurrently
|
|
995
|
+
* (pipelines, votes) and the JSDoc's stated goal ("group by cli + provider
|
|
996
|
+
* + model and surface tail-latency outliers") requires a way to
|
|
997
|
+
* disambiguate which timing row belongs to which call.
|
|
998
|
+
*/
|
|
999
|
+
spawnSubprocess(task, options, requestId) {
|
|
926
1000
|
const cmdConfig = this.getCommand(task);
|
|
927
1001
|
const startTime = getTimeProvider().now();
|
|
928
|
-
const
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const r = cleanup();
|
|
933
|
-
if (r instanceof Promise) {
|
|
934
|
-
r.catch((e) => {
|
|
935
|
-
this.logger.warn("Subprocess cleanup failed", { error: String(e) });
|
|
936
|
-
});
|
|
937
|
-
}
|
|
938
|
-
} catch (e) {
|
|
939
|
-
this.logger.warn("Subprocess cleanup threw", { error: String(e) });
|
|
940
|
-
}
|
|
941
|
-
};
|
|
1002
|
+
const signal = options.signal;
|
|
1003
|
+
if (signal?.aborted === true) {
|
|
1004
|
+
return Promise.resolve(err(this.createError("TIMEOUT", "Aborted before spawn")));
|
|
1005
|
+
}
|
|
942
1006
|
return new Promise((resolveOuter) => {
|
|
943
1007
|
const resolve = (result) => {
|
|
944
|
-
|
|
1008
|
+
this.runSubprocessCleanup(cmdConfig.cleanup);
|
|
945
1009
|
resolveOuter(result);
|
|
946
1010
|
};
|
|
947
1011
|
const childEnv = buildChildEnv(this.name);
|
|
@@ -950,13 +1014,17 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
950
1014
|
env: childEnv
|
|
951
1015
|
});
|
|
952
1016
|
const onProgress = options.onProgress;
|
|
953
|
-
const state = this.setupChildProcessHandlers(
|
|
1017
|
+
const state = this.setupChildProcessHandlers({
|
|
954
1018
|
child,
|
|
955
1019
|
startTime,
|
|
956
|
-
options.timeoutMs,
|
|
1020
|
+
timeoutMs: options.timeoutMs,
|
|
957
1021
|
resolve,
|
|
958
|
-
|
|
959
|
-
|
|
1022
|
+
requestId,
|
|
1023
|
+
...onProgress !== void 0 ? { onProgress } : {}
|
|
1024
|
+
});
|
|
1025
|
+
if (signal !== void 0) {
|
|
1026
|
+
this.attachAbortSignal(child, signal, resolve);
|
|
1027
|
+
}
|
|
960
1028
|
if (cmdConfig.stdin !== void 0) {
|
|
961
1029
|
child.stdin.write(cmdConfig.stdin);
|
|
962
1030
|
}
|
|
@@ -967,7 +1035,8 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
967
1035
|
/**
|
|
968
1036
|
* Sets up child process event handlers for output collection and error handling.
|
|
969
1037
|
*/
|
|
970
|
-
setupChildProcessHandlers(
|
|
1038
|
+
setupChildProcessHandlers(args) {
|
|
1039
|
+
const { child, startTime, timeoutMs, resolve, requestId, onProgress } = args;
|
|
971
1040
|
const state = {
|
|
972
1041
|
stdout: "",
|
|
973
1042
|
stderr: "",
|
|
@@ -988,17 +1057,55 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
988
1057
|
child.on("error", (error) => {
|
|
989
1058
|
resolveOnce(this.handleSubprocessError(error));
|
|
990
1059
|
});
|
|
991
|
-
const
|
|
992
|
-
child
|
|
993
|
-
|
|
994
|
-
|
|
1060
|
+
const timers = this.scheduleTimeoutWithSigkillEscalation({
|
|
1061
|
+
child,
|
|
1062
|
+
timeoutMs,
|
|
1063
|
+
requestId,
|
|
1064
|
+
resolveOnce
|
|
1065
|
+
});
|
|
995
1066
|
child.on("close", (code) => {
|
|
996
|
-
clearTimeout(timeoutId);
|
|
997
|
-
|
|
1067
|
+
clearTimeout(timers.timeoutId);
|
|
1068
|
+
if (timers.sigkillTimerId !== void 0) clearTimeout(timers.sigkillTimerId);
|
|
1069
|
+
this.logTimingBreakdown(state, startTime, code, requestId);
|
|
998
1070
|
resolveOnce(this.classifyCloseResult(code, state, startTime));
|
|
999
1071
|
});
|
|
1000
1072
|
return state;
|
|
1001
1073
|
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Schedules the SIGTERM-on-timeout + SIGKILL-on-grace escalation
|
|
1076
|
+
* (#3026 finding 1).
|
|
1077
|
+
*
|
|
1078
|
+
* The primary timer fires SIGTERM and resolves the caller's promise
|
|
1079
|
+
* immediately so it doesn't wait on a hung child. The escalation
|
|
1080
|
+
* timer (`SIGKILL_GRACE_MS` later) checks whether the child actually
|
|
1081
|
+
* exited and force-reaps it with SIGKILL if not — preventing
|
|
1082
|
+
* zombie accumulation when a child ignores SIGTERM (Node CLIs that
|
|
1083
|
+
* install graceful-shutdown handlers can hang on a broken stream).
|
|
1084
|
+
* Both timers are cleared from the `'close'` handler so a child
|
|
1085
|
+
* that exits within the grace window doesn't see the second signal.
|
|
1086
|
+
*/
|
|
1087
|
+
scheduleTimeoutWithSigkillEscalation(opts) {
|
|
1088
|
+
const { child, timeoutMs, requestId, resolveOnce } = opts;
|
|
1089
|
+
const timers = {
|
|
1090
|
+
timeoutId: setTimeout(() => {
|
|
1091
|
+
child.kill("SIGTERM");
|
|
1092
|
+
resolveOnce(err(this.createError("TIMEOUT", "Execution timed out")));
|
|
1093
|
+
timers.sigkillTimerId = setTimeout(() => {
|
|
1094
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
1095
|
+
this.logger.warn("Child ignored SIGTERM, escalating to SIGKILL", {
|
|
1096
|
+
cli: this.name,
|
|
1097
|
+
requestId,
|
|
1098
|
+
sigkillGraceMs: SIGKILL_GRACE_MS
|
|
1099
|
+
});
|
|
1100
|
+
child.kill("SIGKILL");
|
|
1101
|
+
}
|
|
1102
|
+
}, SIGKILL_GRACE_MS);
|
|
1103
|
+
timers.sigkillTimerId.unref();
|
|
1104
|
+
}, timeoutMs),
|
|
1105
|
+
sigkillTimerId: void 0
|
|
1106
|
+
};
|
|
1107
|
+
return timers;
|
|
1108
|
+
}
|
|
1002
1109
|
/** Attach stdout/stderr data handlers + capture first-byte time (#2472). */
|
|
1003
1110
|
attachStdoutHandlers(child, state, onProgress) {
|
|
1004
1111
|
if (child.stdout !== null) {
|
|
@@ -1029,13 +1136,14 @@ var SubprocessCliAdapter = class extends BaseCliAdapter {
|
|
|
1029
1136
|
* Structured fields chosen so existing query_trace tooling can group by
|
|
1030
1137
|
* cli + provider + model and surface tail-latency outliers.
|
|
1031
1138
|
*/
|
|
1032
|
-
logTimingBreakdown(state, startTime, code) {
|
|
1139
|
+
logTimingBreakdown(state, startTime, code, requestId) {
|
|
1033
1140
|
const now = getTimeProvider().now();
|
|
1034
1141
|
const totalMs = now - startTime;
|
|
1035
1142
|
const spawnLatencyMs = state.firstByteTime === null ? null : state.firstByteTime - startTime;
|
|
1036
1143
|
const streamingMs = state.firstByteTime === null ? null : now - state.firstByteTime;
|
|
1037
1144
|
this.logger.info("Subprocess timing", {
|
|
1038
1145
|
cli: this.name,
|
|
1146
|
+
requestId,
|
|
1039
1147
|
totalMs,
|
|
1040
1148
|
spawnLatencyMs,
|
|
1041
1149
|
streamingMs,
|
|
@@ -3183,4 +3291,4 @@ export {
|
|
|
3183
3291
|
isCliAvailable,
|
|
3184
3292
|
getAvailableClis
|
|
3185
3293
|
};
|
|
3186
|
-
//# sourceMappingURL=chunk-
|
|
3294
|
+
//# sourceMappingURL=chunk-OE7OL2BE.js.map
|