nexus-agents 2.83.1 → 2.85.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.
Files changed (124) hide show
  1. package/dist/{child-mcp-config-3ZW2UPKZ.js → child-mcp-config-FARMFCA3.js} +3 -3
  2. package/dist/{chunk-DWOSFYI2.js → chunk-25AQZKMN.js} +2 -2
  3. package/dist/{chunk-I2HMWH4R.js → chunk-2WCYG75B.js} +13 -2
  4. package/dist/chunk-2WCYG75B.js.map +1 -0
  5. package/dist/{chunk-A6WC5I7V.js → chunk-4MYJNFYL.js} +4 -4
  6. package/dist/{chunk-W6MLS2UL.js → chunk-4S5GY2MF.js} +2 -2
  7. package/dist/{chunk-7V367KT4.js → chunk-4SU4Q37U.js} +7 -23
  8. package/dist/chunk-4SU4Q37U.js.map +1 -0
  9. package/dist/{chunk-J4ZBKE4B.js → chunk-6KZL5DMU.js} +910 -308
  10. package/dist/chunk-6KZL5DMU.js.map +1 -0
  11. package/dist/{chunk-JA6ON2RP.js → chunk-6QKMUPDP.js} +2 -2
  12. package/dist/{chunk-MATFDJRW.js → chunk-7J7D3LAL.js} +4 -4
  13. package/dist/{chunk-LM2S2QWO.js → chunk-CIW2BVSN.js} +3 -2
  14. package/dist/{chunk-LM2S2QWO.js.map → chunk-CIW2BVSN.js.map} +1 -1
  15. package/dist/{chunk-ZLGU7T6J.js → chunk-EL2KV773.js} +78 -63
  16. package/dist/chunk-EL2KV773.js.map +1 -0
  17. package/dist/{chunk-IM2B3FK2.js → chunk-ELVQORLX.js} +4 -4
  18. package/dist/chunk-ELVQORLX.js.map +1 -0
  19. package/dist/{chunk-VXIHHHLQ.js → chunk-FOG7PMGM.js} +2 -2
  20. package/dist/{chunk-HGPIHDC4.js → chunk-FR3P47J2.js} +4 -4
  21. package/dist/{chunk-ODKIRXN7.js → chunk-IF6TXCSE.js} +683 -227
  22. package/dist/chunk-IF6TXCSE.js.map +1 -0
  23. package/dist/{chunk-TKGVRHEI.js → chunk-J5S27RQ4.js} +2 -2
  24. package/dist/{chunk-UFUR6RBP.js → chunk-LY2KLNXM.js} +2 -2
  25. package/dist/{chunk-5QJPM5CB.js → chunk-NSOB2WRI.js} +3 -3
  26. package/dist/{chunk-4XSCU4B3.js → chunk-OXVOUVKH.js} +8 -8
  27. package/dist/{chunk-6XRNFLPI.js → chunk-POTGGTJD.js} +2 -2
  28. package/dist/{chunk-ZA6AZ7LK.js → chunk-QR4VYHMI.js} +6 -6
  29. package/dist/{chunk-FHY7I736.js → chunk-QR5KHIZG.js} +2 -2
  30. package/dist/{chunk-ELRNVADA.js → chunk-RTAIMK6P.js} +155 -47
  31. package/dist/chunk-RTAIMK6P.js.map +1 -0
  32. package/dist/{chunk-O3XJLOEX.js → chunk-SOKQOPTM.js} +2 -2
  33. package/dist/chunk-TRX7CAD5.js +27 -0
  34. package/dist/chunk-TRX7CAD5.js.map +1 -0
  35. package/dist/{chunk-BICIQYET.js → chunk-XZAWH36N.js} +3 -3
  36. package/dist/{chunk-6UI4NKT4.js → chunk-YLMB5MFQ.js} +27 -4
  37. package/dist/{chunk-6UI4NKT4.js.map → chunk-YLMB5MFQ.js.map} +1 -1
  38. package/dist/{chunk-BUXXAN6V.js → chunk-Z5BAZS6F.js} +2 -2
  39. package/dist/{chunk-SZZS57X7.js → chunk-ZF3MSYLG.js} +7 -7
  40. package/dist/{chunk-XODXYOFN.js → chunk-ZMERLMEP.js} +2 -2
  41. package/dist/{cli-circuit-breaker-LC4NZUGD.js → cli-circuit-breaker-LF22Z3QL.js} +5 -5
  42. package/dist/cli.d.ts +1 -1
  43. package/dist/cli.js +39 -34
  44. package/dist/cli.js.map +1 -1
  45. package/dist/{composite-router-GXQ25DO4.js → composite-router-TEXZI7WJ.js} +3 -3
  46. package/dist/{consensus-vote-MTLP6E72.js → consensus-vote-LPYEXUVC.js} +13 -12
  47. package/dist/{consensus-vote-types-CoGbAEjf.d.ts → consensus-vote-types-COAhHVIp.d.ts} +5 -0
  48. package/dist/{context-retriever-GQRC2MVM.js → context-retriever-3TKV4EEC.js} +7 -6
  49. package/dist/{dist-APHOQ26Z.js → dist-75MXB4R3.js} +917 -822
  50. package/dist/dist-75MXB4R3.js.map +1 -0
  51. package/dist/{doctor-deep-T3UUJX2E.js → doctor-deep-OUAKPLJX.js} +4 -4
  52. package/dist/expert-bridge-22UVN5TB.js +13 -0
  53. package/dist/{factory-OKNCTJO6.js → factory-IGHUOUBS.js} +6 -5
  54. package/dist/factory-JNXETBS4.js +14 -0
  55. package/dist/index.d.ts +137 -10
  56. package/dist/index.js +59 -26
  57. package/dist/index.js.map +1 -1
  58. package/dist/{init-opencode-KDTBKLXS.js → init-opencode-52TLZ2TO.js} +6 -6
  59. package/dist/issue-triage-WUK7L25X.js +15 -0
  60. package/dist/{learning-persistence-NX2KHL5T.js → learning-persistence-5ALG6XRC.js} +2 -2
  61. package/dist/{registry-command-D56ROMFJ.js → registry-command-ZIAJB2J3.js} +3 -3
  62. package/dist/{repo-security-plan-N3CDMW6L.js → repo-security-plan-THHLNGEQ.js} +4 -4
  63. package/dist/{research-helpers-synthesize-36QBOKII.js → research-helpers-synthesize-KNRCAIXK.js} +4 -4
  64. package/dist/{routing-memory-6IEPJ3EP.js → routing-memory-UY6KTGT2.js} +3 -3
  65. package/dist/{session-memory-X6SCDFER.js → session-memory-PUJMR6FE.js} +4 -4
  66. package/dist/{setup-command-5AEO5A4Z.js → setup-command-ZXDAR3GQ.js} +12 -11
  67. package/dist/setup-config-EYY5AYZ3.js +10 -0
  68. package/dist/{setup-custom-api-RBOJT3SS.js → setup-custom-api-5XRNYFOP.js} +5 -5
  69. package/dist/{tool-memory-EEHITQRJ.js → tool-memory-PNAHRFZM.js} +6 -5
  70. package/dist/{weather-report-6BC3JK5H.js → weather-report-RQMZOL7C.js} +3 -3
  71. package/package.json +4 -4
  72. package/dist/chunk-7V367KT4.js.map +0 -1
  73. package/dist/chunk-ELRNVADA.js.map +0 -1
  74. package/dist/chunk-I2HMWH4R.js.map +0 -1
  75. package/dist/chunk-IM2B3FK2.js.map +0 -1
  76. package/dist/chunk-J4ZBKE4B.js.map +0 -1
  77. package/dist/chunk-ODKIRXN7.js.map +0 -1
  78. package/dist/chunk-ZLGU7T6J.js.map +0 -1
  79. package/dist/dist-APHOQ26Z.js.map +0 -1
  80. package/dist/expert-bridge-7LPGCPPR.js +0 -13
  81. package/dist/factory-3XB5CAAA.js +0 -14
  82. package/dist/issue-triage-MURMDN2G.js +0 -15
  83. package/dist/setup-config-RPSVIQJO.js +0 -10
  84. /package/dist/{child-mcp-config-3ZW2UPKZ.js.map → child-mcp-config-FARMFCA3.js.map} +0 -0
  85. /package/dist/{chunk-DWOSFYI2.js.map → chunk-25AQZKMN.js.map} +0 -0
  86. /package/dist/{chunk-A6WC5I7V.js.map → chunk-4MYJNFYL.js.map} +0 -0
  87. /package/dist/{chunk-W6MLS2UL.js.map → chunk-4S5GY2MF.js.map} +0 -0
  88. /package/dist/{chunk-JA6ON2RP.js.map → chunk-6QKMUPDP.js.map} +0 -0
  89. /package/dist/{chunk-MATFDJRW.js.map → chunk-7J7D3LAL.js.map} +0 -0
  90. /package/dist/{chunk-VXIHHHLQ.js.map → chunk-FOG7PMGM.js.map} +0 -0
  91. /package/dist/{chunk-HGPIHDC4.js.map → chunk-FR3P47J2.js.map} +0 -0
  92. /package/dist/{chunk-TKGVRHEI.js.map → chunk-J5S27RQ4.js.map} +0 -0
  93. /package/dist/{chunk-UFUR6RBP.js.map → chunk-LY2KLNXM.js.map} +0 -0
  94. /package/dist/{chunk-5QJPM5CB.js.map → chunk-NSOB2WRI.js.map} +0 -0
  95. /package/dist/{chunk-4XSCU4B3.js.map → chunk-OXVOUVKH.js.map} +0 -0
  96. /package/dist/{chunk-6XRNFLPI.js.map → chunk-POTGGTJD.js.map} +0 -0
  97. /package/dist/{chunk-ZA6AZ7LK.js.map → chunk-QR4VYHMI.js.map} +0 -0
  98. /package/dist/{chunk-FHY7I736.js.map → chunk-QR5KHIZG.js.map} +0 -0
  99. /package/dist/{chunk-O3XJLOEX.js.map → chunk-SOKQOPTM.js.map} +0 -0
  100. /package/dist/{chunk-BICIQYET.js.map → chunk-XZAWH36N.js.map} +0 -0
  101. /package/dist/{chunk-BUXXAN6V.js.map → chunk-Z5BAZS6F.js.map} +0 -0
  102. /package/dist/{chunk-SZZS57X7.js.map → chunk-ZF3MSYLG.js.map} +0 -0
  103. /package/dist/{chunk-XODXYOFN.js.map → chunk-ZMERLMEP.js.map} +0 -0
  104. /package/dist/{cli-circuit-breaker-LC4NZUGD.js.map → cli-circuit-breaker-LF22Z3QL.js.map} +0 -0
  105. /package/dist/{composite-router-GXQ25DO4.js.map → composite-router-TEXZI7WJ.js.map} +0 -0
  106. /package/dist/{consensus-vote-MTLP6E72.js.map → consensus-vote-LPYEXUVC.js.map} +0 -0
  107. /package/dist/{context-retriever-GQRC2MVM.js.map → context-retriever-3TKV4EEC.js.map} +0 -0
  108. /package/dist/{doctor-deep-T3UUJX2E.js.map → doctor-deep-OUAKPLJX.js.map} +0 -0
  109. /package/dist/{expert-bridge-7LPGCPPR.js.map → expert-bridge-22UVN5TB.js.map} +0 -0
  110. /package/dist/{factory-3XB5CAAA.js.map → factory-IGHUOUBS.js.map} +0 -0
  111. /package/dist/{factory-OKNCTJO6.js.map → factory-JNXETBS4.js.map} +0 -0
  112. /package/dist/{init-opencode-KDTBKLXS.js.map → init-opencode-52TLZ2TO.js.map} +0 -0
  113. /package/dist/{issue-triage-MURMDN2G.js.map → issue-triage-WUK7L25X.js.map} +0 -0
  114. /package/dist/{learning-persistence-NX2KHL5T.js.map → learning-persistence-5ALG6XRC.js.map} +0 -0
  115. /package/dist/{registry-command-D56ROMFJ.js.map → registry-command-ZIAJB2J3.js.map} +0 -0
  116. /package/dist/{repo-security-plan-N3CDMW6L.js.map → repo-security-plan-THHLNGEQ.js.map} +0 -0
  117. /package/dist/{research-helpers-synthesize-36QBOKII.js.map → research-helpers-synthesize-KNRCAIXK.js.map} +0 -0
  118. /package/dist/{routing-memory-6IEPJ3EP.js.map → routing-memory-UY6KTGT2.js.map} +0 -0
  119. /package/dist/{session-memory-X6SCDFER.js.map → session-memory-PUJMR6FE.js.map} +0 -0
  120. /package/dist/{setup-command-5AEO5A4Z.js.map → setup-command-ZXDAR3GQ.js.map} +0 -0
  121. /package/dist/{setup-config-RPSVIQJO.js.map → setup-config-EYY5AYZ3.js.map} +0 -0
  122. /package/dist/{setup-custom-api-RBOJT3SS.js.map → setup-custom-api-5XRNYFOP.js.map} +0 -0
  123. /package/dist/{tool-memory-EEHITQRJ.js.map → tool-memory-PNAHRFZM.js.map} +0 -0
  124. /package/dist/{weather-report-6BC3JK5H.js.map → weather-report-RQMZOL7C.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createLogger,
6
6
  getTimeProvider
7
- } from "./chunk-6UI4NKT4.js";
7
+ } from "./chunk-YLMB5MFQ.js";
8
8
 
9
9
  // src/mcp/tools/scanner-registry-fetcher.ts
10
10
  import { z } from "zod";
@@ -721,4 +721,4 @@ export {
721
721
  generateSecurityPlan,
722
722
  buildPlanFromAnalysis
723
723
  };
724
- //# sourceMappingURL=chunk-TKGVRHEI.js.map
724
+ //# sourceMappingURL=chunk-J5S27RQ4.js.map
@@ -4,7 +4,7 @@ import {
4
4
  getErrorMessage,
5
5
  getTimeProvider,
6
6
  ok
7
- } from "./chunk-6UI4NKT4.js";
7
+ } from "./chunk-YLMB5MFQ.js";
8
8
 
9
9
  // src/context/session-memory.ts
10
10
  import * as fs from "fs";
@@ -351,4 +351,4 @@ export {
351
351
  SessionMemory,
352
352
  createSessionMemory
353
353
  };
354
- //# sourceMappingURL=chunk-UFUR6RBP.js.map
354
+ //# sourceMappingURL=chunk-LY2KLNXM.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-ZLGU7T6J.js";
4
+ } from "./chunk-EL2KV773.js";
5
5
  import {
6
6
  CACHE_TIMEOUTS,
7
7
  createLogger,
8
8
  err,
9
9
  getTimeProvider,
10
10
  ok
11
- } from "./chunk-6UI4NKT4.js";
11
+ } from "./chunk-YLMB5MFQ.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-5QJPM5CB.js.map
1659
+ //# sourceMappingURL=chunk-NSOB2WRI.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DEFAULTS
3
- } from "./chunk-DWOSFYI2.js";
3
+ } from "./chunk-25AQZKMN.js";
4
4
  import {
5
5
  resolveInsideRoot
6
6
  } from "./chunk-NUBSJGQZ.js";
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  createAllAdapters,
12
12
  probeCli
13
- } from "./chunk-ELRNVADA.js";
13
+ } from "./chunk-RTAIMK6P.js";
14
14
  import {
15
15
  CliNameSchema,
16
16
  DEFAULT_CAPABILITIES,
@@ -26,7 +26,7 @@ import {
26
26
  ok,
27
27
  symbols,
28
28
  writeLine
29
- } from "./chunk-6UI4NKT4.js";
29
+ } from "./chunk-YLMB5MFQ.js";
30
30
  import {
31
31
  detectSandbox,
32
32
  getLearningDir,
@@ -37,10 +37,10 @@ import {
37
37
  getRulesFile,
38
38
  isPersistenceEnabled,
39
39
  nexusDataPath
40
- } from "./chunk-I2HMWH4R.js";
40
+ } from "./chunk-2WCYG75B.js";
41
41
 
42
42
  // src/version.ts
43
- var VERSION = true ? "2.83.1" : "dev";
43
+ var VERSION = true ? "2.85.0" : "dev";
44
44
 
45
45
  // src/config/schemas-core.ts
46
46
  import { z } from "zod";
@@ -2096,7 +2096,7 @@ async function runDoctorFix(result) {
2096
2096
  writeLine2("\u2500".repeat(40));
2097
2097
  let fixCount = 0;
2098
2098
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
2099
- const { runSetup } = await import("./setup-command-5AEO5A4Z.js");
2099
+ const { runSetup } = await import("./setup-command-ZXDAR3GQ.js");
2100
2100
  const setupResult = runSetup({
2101
2101
  skipMcp: true,
2102
2102
  skipRules: true,
@@ -2110,7 +2110,7 @@ async function runDoctorFix(result) {
2110
2110
  }
2111
2111
  }
2112
2112
  if (!result.configFile.found) {
2113
- const { runConfigInitSync } = await import("./setup-config-RPSVIQJO.js");
2113
+ const { runConfigInitSync } = await import("./setup-config-EYY5AYZ3.js");
2114
2114
  const configResult = runConfigInitSync(process.cwd(), false, false);
2115
2115
  if (configResult.success && configResult.created) {
2116
2116
  writeLine2(`\u2713 Generated config: ${configResult.path}`);
@@ -2208,4 +2208,4 @@ export {
2208
2208
  startStdioServer,
2209
2209
  closeServer
2210
2210
  };
2211
- //# sourceMappingURL=chunk-4XSCU4B3.js.map
2211
+ //# sourceMappingURL=chunk-OXVOUVKH.js.map
@@ -2,7 +2,7 @@ import {
2
2
  ConfigError,
3
3
  err,
4
4
  ok
5
- } from "./chunk-6UI4NKT4.js";
5
+ } from "./chunk-YLMB5MFQ.js";
6
6
 
7
7
  // src/adapters/sdk/types.ts
8
8
  var PROVIDER_ENV_KEYS = {
@@ -117,4 +117,4 @@ export {
117
117
  CUSTOM_API_ALLOW_PRIVATE_ENV,
118
118
  validateCustomApiBaseUrl
119
119
  };
120
- //# sourceMappingURL=chunk-6XRNFLPI.js.map
120
+ //# sourceMappingURL=chunk-POTGGTJD.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runConfigInitSync
3
- } from "./chunk-BUXXAN6V.js";
3
+ } from "./chunk-Z5BAZS6F.js";
4
4
  import {
5
5
  VERSION,
6
6
  checkApiKeys,
@@ -8,10 +8,10 @@ import {
8
8
  checkSqlite,
9
9
  defaultConfig,
10
10
  initDataDirectories
11
- } from "./chunk-4XSCU4B3.js";
11
+ } from "./chunk-OXVOUVKH.js";
12
12
  import {
13
13
  probeAllClis
14
- } from "./chunk-ELRNVADA.js";
14
+ } from "./chunk-RTAIMK6P.js";
15
15
  import {
16
16
  BUILT_IN_EXPERTS
17
17
  } from "./chunk-ZM4O442V.js";
@@ -25,11 +25,11 @@ import {
25
25
  getErrorMessage,
26
26
  getTimeProvider,
27
27
  symbols
28
- } from "./chunk-6UI4NKT4.js";
28
+ } from "./chunk-YLMB5MFQ.js";
29
29
  import {
30
30
  ensureGitignored,
31
31
  findRepoRoot
32
- } from "./chunk-I2HMWH4R.js";
32
+ } from "./chunk-2WCYG75B.js";
33
33
 
34
34
  // src/cli/setup-command.ts
35
35
  import { existsSync as existsSync4 } from "fs";
@@ -1987,4 +1987,4 @@ export {
1987
1987
  setupCommand,
1988
1988
  setupCommandAsync
1989
1989
  };
1990
- //# sourceMappingURL=chunk-ZA6AZ7LK.js.map
1990
+ //# sourceMappingURL=chunk-QR4VYHMI.js.map
@@ -7,7 +7,7 @@ import {
7
7
  err,
8
8
  getErrorMessage,
9
9
  ok
10
- } from "./chunk-6UI4NKT4.js";
10
+ } from "./chunk-YLMB5MFQ.js";
11
11
 
12
12
  // src/cli/research-helpers-synthesize.ts
13
13
  import { z } from "zod";
@@ -1015,4 +1015,4 @@ export {
1015
1015
  AttributedInsightSchema,
1016
1016
  synthesizeResearch
1017
1017
  };
1018
- //# sourceMappingURL=chunk-FHY7I736.js.map
1018
+ //# sourceMappingURL=chunk-QR5KHIZG.js.map
@@ -1,7 +1,10 @@
1
1
  import {
2
2
  CliCircuitBreaker,
3
3
  DEFAULT_CIRCUIT_BREAKER_CONFIG
4
- } from "./chunk-LM2S2QWO.js";
4
+ } from "./chunk-CIW2BVSN.js";
5
+ import {
6
+ generateHyphenId
7
+ } from "./chunk-TRX7CAD5.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-6UI4NKT4.js";
30
+ } from "./chunk-YLMB5MFQ.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.requestCount++;
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
- if (this.windowStart < cutoff) {
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
- firstEntry = this.usageHistory[0];
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 result = await this.spawnSubprocess(task, options);
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
- spawnSubprocess(task, options) {
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 cleanup = cmdConfig.cleanup;
929
- const runCleanup = () => {
930
- if (cleanup === void 0) return;
931
- try {
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
- runCleanup();
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
- onProgress
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(child, startTime, timeoutMs, resolve, onProgress) {
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 timeoutId = setTimeout(() => {
992
- child.kill("SIGTERM");
993
- resolveOnce(err(this.createError("TIMEOUT", "Execution timed out")));
994
- }, timeoutMs);
1060
+ const timers = this.scheduleTimeoutWithSigkillEscalation({
1061
+ child,
1062
+ timeoutMs,
1063
+ requestId,
1064
+ resolveOnce
1065
+ });
995
1066
  child.on("close", (code) => {
996
- clearTimeout(timeoutId);
997
- this.logTimingBreakdown(state, startTime, code);
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-ELRNVADA.js.map
3294
+ //# sourceMappingURL=chunk-RTAIMK6P.js.map