nexus-agents 8.122.3 → 8.124.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 (138) hide show
  1. package/dist/{ast-rule-runner-D63SEZBA.js → ast-rule-runner-CZ5O4YR7.js} +3 -4
  2. package/dist/{child-mcp-config-SYKZPE4K.js → child-mcp-config-DQGG7CTI.js} +2 -2
  3. package/dist/{chunk-G6C4CB2P.js → chunk-23FQPFI4.js} +2 -2
  4. package/dist/{chunk-IL3ES3J6.js → chunk-35KEWIMV.js} +2 -2
  5. package/dist/{chunk-DKJITSJK.js → chunk-3CBBUAZZ.js} +5 -5
  6. package/dist/{chunk-BSB4FOLG.js → chunk-3G73BY6C.js} +3 -3
  7. package/dist/{chunk-SAFMMDQJ.js → chunk-5AALTS3S.js} +2 -2
  8. package/dist/{chunk-W4VWFQRC.js → chunk-6WRH3LBP.js} +2 -2
  9. package/dist/{chunk-KMPEC7MU.js → chunk-7FISXMZD.js} +3 -3
  10. package/dist/{chunk-V4GLPTHB.js → chunk-AFYFKT6T.js} +5 -5
  11. package/dist/{chunk-3XW3QNOW.js → chunk-B3ALYUFL.js} +7 -7
  12. package/dist/{chunk-MVFKTFMM.js → chunk-BGQA53QQ.js} +2 -2
  13. package/dist/{chunk-DRNW3QRY.js → chunk-BKQ3ALKH.js} +2 -2
  14. package/dist/{chunk-2FCB5UBG.js → chunk-CDWHC2OZ.js} +2 -2
  15. package/dist/{chunk-ELTV6L22.js → chunk-DK5FPG6K.js} +4 -6
  16. package/dist/{chunk-ELTV6L22.js.map → chunk-DK5FPG6K.js.map} +1 -1
  17. package/dist/{chunk-TXXXWVPX.js → chunk-EL6WVSX2.js} +6 -6
  18. package/dist/{chunk-NGVBCGM6.js → chunk-FEOYDA6G.js} +12 -12
  19. package/dist/{chunk-XJGVR65R.js → chunk-G3RQ3ECZ.js} +6 -8
  20. package/dist/{chunk-XJGVR65R.js.map → chunk-G3RQ3ECZ.js.map} +1 -1
  21. package/dist/{chunk-WBIO7WHW.js → chunk-I7WLZ3KF.js} +2 -2
  22. package/dist/{chunk-BJUIPCJ5.js → chunk-IYKF6Q6B.js} +2 -2
  23. package/dist/{chunk-EEXUKXZQ.js → chunk-KEBW55DQ.js} +2 -2
  24. package/dist/{chunk-PM2ECWCL.js → chunk-L5CDQ7QK.js} +437 -156
  25. package/dist/chunk-L5CDQ7QK.js.map +1 -0
  26. package/dist/{chunk-XO7OU6FK.js → chunk-LK7GODI6.js} +2 -2
  27. package/dist/{chunk-4SZQYMMO.js → chunk-MBBQDXX6.js} +3 -3
  28. package/dist/{chunk-WW2MBD5I.js → chunk-NAXLQIOQ.js} +2 -2
  29. package/dist/{chunk-7IMCFFHH.js → chunk-P4HUSF6P.js} +11 -11
  30. package/dist/{chunk-LTYFP4MJ.js → chunk-RMLNW376.js} +9 -9
  31. package/dist/{chunk-7IXILU76.js → chunk-RMMA4HDL.js} +2 -2
  32. package/dist/{chunk-XXOLRZRQ.js → chunk-T2AOQTW4.js} +5 -5
  33. package/dist/{chunk-YCTJNJKU.js → chunk-T7ZKHG5T.js} +4 -4
  34. package/dist/{chunk-3NQVZQCT.js → chunk-TGWRNNHQ.js} +4 -6
  35. package/dist/{chunk-3NQVZQCT.js.map → chunk-TGWRNNHQ.js.map} +1 -1
  36. package/dist/{chunk-62T7LI7Y.js → chunk-VTBFGRRP.js} +2 -2
  37. package/dist/{chunk-UCSIPEJK.js → chunk-WI4N7QDC.js} +3 -3
  38. package/dist/{chunk-UA35ZBK5.js → chunk-WLVNNTZZ.js} +46 -51
  39. package/dist/chunk-WLVNNTZZ.js.map +1 -0
  40. package/dist/{chunk-5UD62EYQ.js → chunk-XYAVROLE.js} +4 -4
  41. package/dist/{chunk-LDKIDJQM.js → chunk-Y7EVXWYU.js} +5 -7
  42. package/dist/{chunk-LDKIDJQM.js.map → chunk-Y7EVXWYU.js.map} +1 -1
  43. package/dist/{chunk-CTE55G3Y.js → chunk-YVS2FXT6.js} +3 -3
  44. package/dist/{cli-circuit-breaker-2NCL4BJG.js → cli-circuit-breaker-RG4UF6FN.js} +3 -3
  45. package/dist/cli.js +58 -49
  46. package/dist/cli.js.map +1 -1
  47. package/dist/{composite-router-FMSFSUY4.js → composite-router-4TSZUALA.js} +2 -2
  48. package/dist/{consensus-vote-SSA6HZOI.js → consensus-vote-ALEIBLKC.js} +17 -18
  49. package/dist/{context-retriever-JQVOCYWB.js → context-retriever-3W2OL4RO.js} +8 -9
  50. package/dist/{doctor-deep-TI74R6WM.js → doctor-deep-ZAAY3WB6.js} +3 -3
  51. package/dist/doctor-gateway-report-A7MZPJWD.js +19 -0
  52. package/dist/{doctor-live-ESPDY2UT.js → doctor-live-OAXLRPDE.js} +11 -11
  53. package/dist/{expert-bridge-SLDH3I4Q.js → expert-bridge-EE4IIZIN.js} +4 -4
  54. package/dist/{factory-UO4YVMT4.js → factory-IBHDXXNR.js} +5 -5
  55. package/dist/{factory-T5Z4H7I4.js → factory-XS7U6MG5.js} +10 -10
  56. package/dist/{improvement-review-CQVAUN26.js → improvement-review-JCBJBN7E.js} +6 -7
  57. package/dist/index.d.ts +27 -5
  58. package/dist/index.js +45 -120
  59. package/dist/index.js.map +1 -1
  60. package/dist/{init-opencode-4FK75Q4I.js → init-opencode-HQEPB7PI.js} +6 -6
  61. package/dist/{issue-triage-UM2N433F.js → issue-triage-H2GGXC65.js} +6 -6
  62. package/dist/{openai-compat-adapter-EHKDFXNR.js → openai-compat-adapter-2HYHVJEM.js} +6 -6
  63. package/dist/{pr-reviewer-helpers-TOSTLTWB.js → pr-reviewer-helpers-QTH6O3FZ.js} +4 -4
  64. package/dist/{registry-command-YZSKM2GA.js → registry-command-OARQZTUJ.js} +2 -2
  65. package/dist/{repo-security-plan-C66VWEOJ.js → repo-security-plan-RPYE5VPC.js} +3 -3
  66. package/dist/{research-helpers-synthesize-CWN7TZPP.js → research-helpers-synthesize-SLA3EJSS.js} +4 -5
  67. package/dist/{routing-memory-IYLRTH55.js → routing-memory-4M3QWUJJ.js} +2 -2
  68. package/dist/{session-memory-LC2KINJU.js → session-memory-VW4QQB6K.js} +3 -3
  69. package/dist/{setup-config-TLKV6TBJ.js → setup-config-TNAEREJ2.js} +3 -3
  70. package/dist/{setup-custom-api-CPJ6OX4O.js → setup-custom-api-K47DQWSS.js} +4 -4
  71. package/dist/setup-data-dir-DUDPUBXE.js +33 -0
  72. package/dist/{tool-memory-OQMZREAX.js → tool-memory-B57RSRDM.js} +5 -5
  73. package/dist/{unified-registry-QA2DYYO6.js → unified-registry-3UZKUZEW.js} +11 -11
  74. package/dist/{weather-report-C4TRZMJZ.js → weather-report-NQ7DXWEY.js} +2 -2
  75. package/package.json +1 -1
  76. package/dist/chunk-PM2ECWCL.js.map +0 -1
  77. package/dist/chunk-UA35ZBK5.js.map +0 -1
  78. package/dist/chunk-XEPZSDN5.js +0 -91
  79. package/dist/chunk-XEPZSDN5.js.map +0 -1
  80. package/dist/doctor-gateway-report-QQVWP3P5.js +0 -19
  81. package/dist/setup-data-dir-46AJGMKK.js +0 -33
  82. /package/dist/{ast-rule-runner-D63SEZBA.js.map → ast-rule-runner-CZ5O4YR7.js.map} +0 -0
  83. /package/dist/{child-mcp-config-SYKZPE4K.js.map → child-mcp-config-DQGG7CTI.js.map} +0 -0
  84. /package/dist/{chunk-G6C4CB2P.js.map → chunk-23FQPFI4.js.map} +0 -0
  85. /package/dist/{chunk-IL3ES3J6.js.map → chunk-35KEWIMV.js.map} +0 -0
  86. /package/dist/{chunk-DKJITSJK.js.map → chunk-3CBBUAZZ.js.map} +0 -0
  87. /package/dist/{chunk-BSB4FOLG.js.map → chunk-3G73BY6C.js.map} +0 -0
  88. /package/dist/{chunk-SAFMMDQJ.js.map → chunk-5AALTS3S.js.map} +0 -0
  89. /package/dist/{chunk-W4VWFQRC.js.map → chunk-6WRH3LBP.js.map} +0 -0
  90. /package/dist/{chunk-KMPEC7MU.js.map → chunk-7FISXMZD.js.map} +0 -0
  91. /package/dist/{chunk-V4GLPTHB.js.map → chunk-AFYFKT6T.js.map} +0 -0
  92. /package/dist/{chunk-3XW3QNOW.js.map → chunk-B3ALYUFL.js.map} +0 -0
  93. /package/dist/{chunk-MVFKTFMM.js.map → chunk-BGQA53QQ.js.map} +0 -0
  94. /package/dist/{chunk-DRNW3QRY.js.map → chunk-BKQ3ALKH.js.map} +0 -0
  95. /package/dist/{chunk-2FCB5UBG.js.map → chunk-CDWHC2OZ.js.map} +0 -0
  96. /package/dist/{chunk-TXXXWVPX.js.map → chunk-EL6WVSX2.js.map} +0 -0
  97. /package/dist/{chunk-NGVBCGM6.js.map → chunk-FEOYDA6G.js.map} +0 -0
  98. /package/dist/{chunk-WBIO7WHW.js.map → chunk-I7WLZ3KF.js.map} +0 -0
  99. /package/dist/{chunk-BJUIPCJ5.js.map → chunk-IYKF6Q6B.js.map} +0 -0
  100. /package/dist/{chunk-EEXUKXZQ.js.map → chunk-KEBW55DQ.js.map} +0 -0
  101. /package/dist/{chunk-XO7OU6FK.js.map → chunk-LK7GODI6.js.map} +0 -0
  102. /package/dist/{chunk-4SZQYMMO.js.map → chunk-MBBQDXX6.js.map} +0 -0
  103. /package/dist/{chunk-WW2MBD5I.js.map → chunk-NAXLQIOQ.js.map} +0 -0
  104. /package/dist/{chunk-7IMCFFHH.js.map → chunk-P4HUSF6P.js.map} +0 -0
  105. /package/dist/{chunk-LTYFP4MJ.js.map → chunk-RMLNW376.js.map} +0 -0
  106. /package/dist/{chunk-7IXILU76.js.map → chunk-RMMA4HDL.js.map} +0 -0
  107. /package/dist/{chunk-XXOLRZRQ.js.map → chunk-T2AOQTW4.js.map} +0 -0
  108. /package/dist/{chunk-YCTJNJKU.js.map → chunk-T7ZKHG5T.js.map} +0 -0
  109. /package/dist/{chunk-62T7LI7Y.js.map → chunk-VTBFGRRP.js.map} +0 -0
  110. /package/dist/{chunk-UCSIPEJK.js.map → chunk-WI4N7QDC.js.map} +0 -0
  111. /package/dist/{chunk-5UD62EYQ.js.map → chunk-XYAVROLE.js.map} +0 -0
  112. /package/dist/{chunk-CTE55G3Y.js.map → chunk-YVS2FXT6.js.map} +0 -0
  113. /package/dist/{cli-circuit-breaker-2NCL4BJG.js.map → cli-circuit-breaker-RG4UF6FN.js.map} +0 -0
  114. /package/dist/{composite-router-FMSFSUY4.js.map → composite-router-4TSZUALA.js.map} +0 -0
  115. /package/dist/{consensus-vote-SSA6HZOI.js.map → consensus-vote-ALEIBLKC.js.map} +0 -0
  116. /package/dist/{context-retriever-JQVOCYWB.js.map → context-retriever-3W2OL4RO.js.map} +0 -0
  117. /package/dist/{doctor-deep-TI74R6WM.js.map → doctor-deep-ZAAY3WB6.js.map} +0 -0
  118. /package/dist/{doctor-gateway-report-QQVWP3P5.js.map → doctor-gateway-report-A7MZPJWD.js.map} +0 -0
  119. /package/dist/{doctor-live-ESPDY2UT.js.map → doctor-live-OAXLRPDE.js.map} +0 -0
  120. /package/dist/{expert-bridge-SLDH3I4Q.js.map → expert-bridge-EE4IIZIN.js.map} +0 -0
  121. /package/dist/{factory-T5Z4H7I4.js.map → factory-IBHDXXNR.js.map} +0 -0
  122. /package/dist/{factory-UO4YVMT4.js.map → factory-XS7U6MG5.js.map} +0 -0
  123. /package/dist/{improvement-review-CQVAUN26.js.map → improvement-review-JCBJBN7E.js.map} +0 -0
  124. /package/dist/{init-opencode-4FK75Q4I.js.map → init-opencode-HQEPB7PI.js.map} +0 -0
  125. /package/dist/{issue-triage-UM2N433F.js.map → issue-triage-H2GGXC65.js.map} +0 -0
  126. /package/dist/{openai-compat-adapter-EHKDFXNR.js.map → openai-compat-adapter-2HYHVJEM.js.map} +0 -0
  127. /package/dist/{pr-reviewer-helpers-TOSTLTWB.js.map → pr-reviewer-helpers-QTH6O3FZ.js.map} +0 -0
  128. /package/dist/{registry-command-YZSKM2GA.js.map → registry-command-OARQZTUJ.js.map} +0 -0
  129. /package/dist/{repo-security-plan-C66VWEOJ.js.map → repo-security-plan-RPYE5VPC.js.map} +0 -0
  130. /package/dist/{research-helpers-synthesize-CWN7TZPP.js.map → research-helpers-synthesize-SLA3EJSS.js.map} +0 -0
  131. /package/dist/{routing-memory-IYLRTH55.js.map → routing-memory-4M3QWUJJ.js.map} +0 -0
  132. /package/dist/{session-memory-LC2KINJU.js.map → session-memory-VW4QQB6K.js.map} +0 -0
  133. /package/dist/{setup-config-TLKV6TBJ.js.map → setup-config-TNAEREJ2.js.map} +0 -0
  134. /package/dist/{setup-custom-api-CPJ6OX4O.js.map → setup-custom-api-K47DQWSS.js.map} +0 -0
  135. /package/dist/{setup-data-dir-46AJGMKK.js.map → setup-data-dir-DUDPUBXE.js.map} +0 -0
  136. /package/dist/{tool-memory-OQMZREAX.js.map → tool-memory-B57RSRDM.js.map} +0 -0
  137. /package/dist/{unified-registry-QA2DYYO6.js.map → unified-registry-3UZKUZEW.js.map} +0 -0
  138. /package/dist/{weather-report-C4TRZMJZ.js.map → weather-report-NQ7DXWEY.js.map} +0 -0
@@ -9,9 +9,8 @@ import {
9
9
  getBuiltInAstRulesPath,
10
10
  loadRules,
11
11
  runAstQaRules
12
- } from "./chunk-ELTV6L22.js";
13
- import "./chunk-XEPZSDN5.js";
14
- import "./chunk-PM2ECWCL.js";
12
+ } from "./chunk-DK5FPG6K.js";
13
+ import "./chunk-L5CDQ7QK.js";
15
14
  import "./chunk-UE7A2XHM.js";
16
15
  import "./chunk-LWOX65CP.js";
17
16
  import "./chunk-PX6F3LHL.js";
@@ -27,4 +26,4 @@ export {
27
26
  loadRules,
28
27
  runAstQaRules
29
28
  };
30
- //# sourceMappingURL=ast-rule-runner-D63SEZBA.js.map
29
+ //# sourceMappingURL=ast-rule-runner-CZ5O4YR7.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-OITVVSWO.js";
4
4
  import {
5
5
  createLogger
6
- } from "./chunk-PM2ECWCL.js";
6
+ } from "./chunk-L5CDQ7QK.js";
7
7
  import "./chunk-UE7A2XHM.js";
8
8
  import "./chunk-LWOX65CP.js";
9
9
  import "./chunk-PX6F3LHL.js";
@@ -49,4 +49,4 @@ async function generateMcpConfig(options) {
49
49
  export {
50
50
  generateMcpConfig
51
51
  };
52
- //# sourceMappingURL=child-mcp-config-SYKZPE4K.js.map
52
+ //# sourceMappingURL=child-mcp-config-DQGG7CTI.js.map
@@ -8,7 +8,7 @@ import {
8
8
  MCP_TIMEOUTS,
9
9
  TEST_TIMEOUTS,
10
10
  WORKFLOW_TIMEOUTS
11
- } from "./chunk-PM2ECWCL.js";
11
+ } from "./chunk-L5CDQ7QK.js";
12
12
  import {
13
13
  createGetToolRateLimit
14
14
  } from "./chunk-LWOX65CP.js";
@@ -223,4 +223,4 @@ export {
223
223
  CUSTOM_API_DEFAULT_MODEL,
224
224
  DEFAULTS
225
225
  };
226
- //# sourceMappingURL=chunk-G6C4CB2P.js.map
226
+ //# sourceMappingURL=chunk-23FQPFI4.js.map
@@ -4,7 +4,7 @@ import {
4
4
  err,
5
5
  getErrorMessage,
6
6
  ok
7
- } from "./chunk-PM2ECWCL.js";
7
+ } from "./chunk-L5CDQ7QK.js";
8
8
 
9
9
  // src/scm/types.ts
10
10
  var ScmError = class extends Error {
@@ -281,4 +281,4 @@ export {
281
281
  ScmError,
282
282
  GitHubProvider
283
283
  };
284
- //# sourceMappingURL=chunk-IL3ES3J6.js.map
284
+ //# sourceMappingURL=chunk-35KEWIMV.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createAutoAdapter
3
- } from "./chunk-LTYFP4MJ.js";
3
+ } from "./chunk-RMLNW376.js";
4
4
  import {
5
5
  ensureGatewayDiscovered,
6
6
  gatewayDiscoveryGeneration
7
- } from "./chunk-KMPEC7MU.js";
7
+ } from "./chunk-7FISXMZD.js";
8
8
  import {
9
9
  getDefaultCliCircuitBreakerRegistry,
10
10
  mapModelErrorToCategory
11
- } from "./chunk-EEXUKXZQ.js";
11
+ } from "./chunk-KEBW55DQ.js";
12
12
  import {
13
13
  CircularBuffer,
14
14
  ConfigError,
@@ -33,7 +33,7 @@ import {
33
33
  recordRateLimitEvent,
34
34
  toRateLimitError,
35
35
  warnIfGatewayCostUndeclared
36
- } from "./chunk-PM2ECWCL.js";
36
+ } from "./chunk-L5CDQ7QK.js";
37
37
 
38
38
  // src/agents/collaboration/event-bus-helpers.ts
39
39
  import { randomUUID } from "node:crypto";
@@ -1040,4 +1040,4 @@ export {
1040
1040
  getGlobalRegistry,
1041
1041
  resetGlobalRegistry
1042
1042
  };
1043
- //# sourceMappingURL=chunk-DKJITSJK.js.map
1043
+ //# sourceMappingURL=chunk-3CBBUAZZ.js.map
@@ -7,7 +7,7 @@ import {
7
7
  toolStructuredError,
8
8
  toolSuccessStructured,
9
9
  wrapToolWithTimeout
10
- } from "./chunk-LDKIDJQM.js";
10
+ } from "./chunk-Y7EVXWYU.js";
11
11
  import {
12
12
  JsonlStore,
13
13
  SECURITY_KEYWORDS,
@@ -21,7 +21,7 @@ import {
21
21
  hasMeasuredCategory,
22
22
  isDeclaredNeverDeprecate,
23
23
  isRegisteredToolName
24
- } from "./chunk-PM2ECWCL.js";
24
+ } from "./chunk-L5CDQ7QK.js";
25
25
  import {
26
26
  getNexusDataDir,
27
27
  nexusDataPath
@@ -2293,4 +2293,4 @@ export {
2293
2293
  runImprovementReview,
2294
2294
  registerImprovementReviewTool
2295
2295
  };
2296
- //# sourceMappingURL=chunk-BSB4FOLG.js.map
2296
+ //# sourceMappingURL=chunk-3G73BY6C.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createLogger,
6
6
  getTimeProvider
7
- } from "./chunk-PM2ECWCL.js";
7
+ } from "./chunk-L5CDQ7QK.js";
8
8
 
9
9
  // src/mcp/tools/scanner-registry-fetcher.ts
10
10
  import { z } from "zod";
@@ -740,4 +740,4 @@ export {
740
740
  generateSecurityPlan,
741
741
  buildPlanFromAnalysis
742
742
  };
743
- //# sourceMappingURL=chunk-SAFMMDQJ.js.map
743
+ //# sourceMappingURL=chunk-5AALTS3S.js.map
@@ -2,7 +2,7 @@ import {
2
2
  createLogger,
3
3
  err,
4
4
  ok
5
- } from "./chunk-PM2ECWCL.js";
5
+ } from "./chunk-L5CDQ7QK.js";
6
6
 
7
7
  // src/scm/token-resolver.ts
8
8
  import { execFile } from "node:child_process";
@@ -87,4 +87,4 @@ export {
87
87
  hasToken,
88
88
  getTokenEnvVars
89
89
  };
90
- //# sourceMappingURL=chunk-W4VWFQRC.js.map
90
+ //# sourceMappingURL=chunk-6WRH3LBP.js.map
@@ -7,7 +7,7 @@ import {
7
7
  logGatewaySlotMapping,
8
8
  resolveOwnerCli,
9
9
  setGatewaySlotCatalog
10
- } from "./chunk-PM2ECWCL.js";
10
+ } from "./chunk-L5CDQ7QK.js";
11
11
 
12
12
  // src/config/model-availability.ts
13
13
  var DEFAULT_TTL_MS = 6e4;
@@ -139,7 +139,7 @@ function discoverGatewayOnce(logger = defaultLogger) {
139
139
  }
140
140
  async function runProbe(logger) {
141
141
  try {
142
- const { buildOpenAICompatAdapters: build } = await import("./openai-compat-adapter-EHKDFXNR.js");
142
+ const { buildOpenAICompatAdapters: build } = await import("./openai-compat-adapter-2HYHVJEM.js");
143
143
  return await build(logger);
144
144
  } catch (error) {
145
145
  return err(new ConfigError(`Gateway discovery threw: ${getErrorMessage(error)}`));
@@ -269,4 +269,4 @@ export {
269
269
  setGatewayRediscovery,
270
270
  ensureGatewayDiscovered
271
271
  };
272
- //# sourceMappingURL=chunk-KMPEC7MU.js.map
272
+ //# sourceMappingURL=chunk-7FISXMZD.js.map
@@ -8,16 +8,16 @@ import {
8
8
  requireApiKey,
9
9
  validateApiKeyPresence,
10
10
  withGatewayUsageRecording
11
- } from "./chunk-DRNW3QRY.js";
11
+ } from "./chunk-BKQ3ALKH.js";
12
12
  import {
13
13
  assertCustomApiHostResolvesPublic,
14
14
  hostnameOf,
15
15
  redactGatewaySecrets
16
- } from "./chunk-MVFKTFMM.js";
16
+ } from "./chunk-BGQA53QQ.js";
17
17
  import {
18
18
  REDACTED_KEY_PLACEHOLDER,
19
19
  sanitizeErrorDetails
20
- } from "./chunk-BJUIPCJ5.js";
20
+ } from "./chunk-IYKF6Q6B.js";
21
21
  import {
22
22
  CUSTOM_API_ALLOW_PRIVATE_ENV,
23
23
  ConfigError,
@@ -39,7 +39,7 @@ import {
39
39
  ok,
40
40
  readModelAllowlist,
41
41
  refineGatewayCatalog
42
- } from "./chunk-PM2ECWCL.js";
42
+ } from "./chunk-L5CDQ7QK.js";
43
43
 
44
44
  // src/adapters/openai-compat-adapter.ts
45
45
  import OpenAI2 from "openai";
@@ -992,4 +992,4 @@ export {
992
992
  createOpenAICompatAdapter,
993
993
  buildOpenAICompatAdapters
994
994
  };
995
- //# sourceMappingURL=chunk-V4GLPTHB.js.map
995
+ //# sourceMappingURL=chunk-AFYFKT6T.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  ensureGatewayDiscovered,
3
3
  gatewayDiscoveryGeneration
4
- } from "./chunk-KMPEC7MU.js";
4
+ } from "./chunk-7FISXMZD.js";
5
5
  import {
6
6
  createLogger,
7
7
  getTimeProvider,
8
8
  isRateLimitText,
9
9
  resolveCliSlot
10
- } from "./chunk-PM2ECWCL.js";
10
+ } from "./chunk-L5CDQ7QK.js";
11
11
 
12
12
  // src/pipeline/expert-access-mode.ts
13
13
  var logger = createLogger({ component: "expert-bridge" });
@@ -69,7 +69,7 @@ async function getMcpConfigPath() {
69
69
  if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;
70
70
  mcpConfigInitPromise ??= (async () => {
71
71
  try {
72
- const { generateMcpConfig } = await import("./child-mcp-config-SYKZPE4K.js");
72
+ const { generateMcpConfig } = await import("./child-mcp-config-DQGG7CTI.js");
73
73
  const config = await generateMcpConfig();
74
74
  cachedMcpConfigPath = config.configPath;
75
75
  cachedMcpConfigCleanup = config.cleanup;
@@ -163,8 +163,8 @@ async function getRouter() {
163
163
  }
164
164
  if (cachedRouter !== null) return cachedRouter;
165
165
  routerInitPromise ??= (async () => {
166
- const { createAllAdapters } = await import("./factory-T5Z4H7I4.js");
167
- const { createCompositeRouter } = await import("./composite-router-FMSFSUY4.js");
166
+ const { createAllAdapters } = await import("./factory-XS7U6MG5.js");
167
+ const { createCompositeRouter } = await import("./composite-router-4TSZUALA.js");
168
168
  const adapters = createAllAdapters();
169
169
  const superseded = generation !== routerGeneration;
170
170
  if (adapters.size === 0) {
@@ -175,7 +175,7 @@ async function getRouter() {
175
175
  if (superseded) return router;
176
176
  cachedRouter = router;
177
177
  try {
178
- const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-2NCL4BJG.js");
178
+ const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-RG4UF6FN.js");
179
179
  cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
180
180
  } catch (error) {
181
181
  const msg = error instanceof Error ? error.message : String(error);
@@ -323,4 +323,4 @@ export {
323
323
  tokenSplitFromUsage,
324
324
  executeExpert
325
325
  };
326
- //# sourceMappingURL=chunk-3XW3QNOW.js.map
326
+ //# sourceMappingURL=chunk-B3ALYUFL.js.map
@@ -7,7 +7,7 @@ import {
7
7
  createLogger,
8
8
  err,
9
9
  ok
10
- } from "./chunk-PM2ECWCL.js";
10
+ } from "./chunk-L5CDQ7QK.js";
11
11
 
12
12
  // src/adapters/gateway-redaction.ts
13
13
  var GATEWAY_REDACTED = "<redacted>";
@@ -341,4 +341,4 @@ export {
341
341
  validateCustomApiBaseUrl,
342
342
  assertCustomApiHostResolvesPublic
343
343
  };
344
- //# sourceMappingURL=chunk-MVFKTFMM.js.map
344
+ //# sourceMappingURL=chunk-BGQA53QQ.js.map
@@ -16,7 +16,7 @@ import {
16
16
  ok,
17
17
  recordUsageEvent,
18
18
  resolveRetryAfterMs
19
- } from "./chunk-PM2ECWCL.js";
19
+ } from "./chunk-L5CDQ7QK.js";
20
20
 
21
21
  // src/adapters/base-adapter.ts
22
22
  var AdapterModelError = class extends ModelError {
@@ -1113,4 +1113,4 @@ export {
1113
1113
  gatewayAiSdkOptions,
1114
1114
  withGatewayUsageRecording
1115
1115
  };
1116
- //# sourceMappingURL=chunk-DRNW3QRY.js.map
1116
+ //# sourceMappingURL=chunk-BKQ3ALKH.js.map
@@ -8,7 +8,7 @@ import {
8
8
  getAdaptiveBonus,
9
9
  getOutcomeStore,
10
10
  hasMeasuredCategory
11
- } from "./chunk-PM2ECWCL.js";
11
+ } from "./chunk-L5CDQ7QK.js";
12
12
 
13
13
  // src/cli/doctor-deep.ts
14
14
  var CLI_NAMES = ["claude", "gemini", "codex", "opencode"];
@@ -148,4 +148,4 @@ export {
148
148
  runDeepDiagnostics,
149
149
  formatDeepDiagnostics
150
150
  };
151
- //# sourceMappingURL=chunk-2FCB5UBG.js.map
151
+ //# sourceMappingURL=chunk-CDWHC2OZ.js.map
@@ -1,12 +1,10 @@
1
- import {
2
- resolveInsideRoot
3
- } from "./chunk-XEPZSDN5.js";
4
1
  import {
5
2
  SecurityError,
6
3
  ValidationError,
7
4
  createLogger,
8
- formatZodError
9
- } from "./chunk-PM2ECWCL.js";
5
+ formatZodError,
6
+ resolveInsideRoot
7
+ } from "./chunk-L5CDQ7QK.js";
10
8
 
11
9
  // src/security/ast-rule-runner.ts
12
10
  import { existsSync } from "node:fs";
@@ -243,4 +241,4 @@ export {
243
241
  collectAstQaFindings,
244
242
  runAstQaRules
245
243
  };
246
- //# sourceMappingURL=chunk-ELTV6L22.js.map
244
+ //# sourceMappingURL=chunk-DK5FPG6K.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/security/ast-rule-runner.ts"],"sourcesContent":["/**\n * nexus-agents/security - Polyglot (Python/Go) AST QA/Security Rule Runner (#4249 child C)\n *\n * Runs YAML-defined `@ast-grep/napi` rules against Python/Go source, detecting\n * common QA/security anti-patterns (dynamic `eval`/`exec`, shell injection,\n * unchecked external command execution). Same engine already used by\n * `search_usages` (indexer/usage-ast.ts, #4265) and the ast-fixer rewrites\n * (agents/collaboration/ast-rewrites.ts, #4243/#4249 child B) — no new AST\n * dependency, just new language grammars for it.\n *\n * **Language support gap.** `Lang` in `@ast-grep/napi@0.44.1` ships only\n * Html/JavaScript/Tsx/Css/TypeScript — no Python, no Go. This module closes\n * that gap via napi's `@experimental registerDynamicLanguage` API, backed by\n * the `@ast-grep/lang-python`/`@ast-grep/lang-go` prebuilt tree-sitter\n * grammars. Both are EXACT-pinned in package.json (no caret): these are\n * early/experimental packages and a caret range could silently swap in an\n * incompatible native `.so` grammar build underneath a \"safe\" semver-minor\n * bump. `registerDynamicLanguage` throws if called more than once per\n * process (napi-rs's own documented constraint) — {@link ensurePolyglotLangs}\n * is a lazy, module-level, once-only guard so repeated calls (tests, repeat\n * runner invocations within one process) never trip it twice.\n *\n * **Read-only.** Reads rule YAML and target source files, walks their ASTs,\n * performs NO writes. ast-grep YAML rule files support a `fix:` key for\n * autofixing, but napi's `SgNode.findAll` (used here) never applies it —\n * only ast-grep's separate rewrite/CLI machinery does — so even a rule\n * author who adds `fix:` cannot turn this runner into a writer by accident.\n * MCP exposure is deliberately deferred (see the follow-up issue referenced\n * in the #4249 child C PR) to keep this surface a plain function until a\n * named consumer needs it wired through a tool.\n *\n * @module security/ast-rule-runner\n * @see Issue #4249 - epic: ast-grep adoption (Child C: polyglot QA/security rules)\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { dirname, extname, join, relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { parse, registerDynamicLanguage } from '@ast-grep/napi';\nimport type { NapiConfig } from '@ast-grep/napi';\n// Both packages are CJS `export = <LanguageRegistration>` modules — the\n// default import is the whole registration object (`libraryPath` getter,\n// `extensions`, `languageSymbol`, `expandoChar`). See their `index.d.ts`.\nimport goLangRegistration from '@ast-grep/lang-go';\nimport pythonLangRegistration from '@ast-grep/lang-python';\nimport { parse as parseYaml } from 'yaml';\nimport { z } from 'zod';\nimport { createLogger, SecurityError, ValidationError, formatZodError } from '../core/index.js';\nimport { resolveInsideRoot } from './safe-path.js';\n\n// ============================================================================\n// Dynamic language registration (@experimental, call-once)\n// ============================================================================\n\nlet polyglotLangsRegistered = false;\n\n/**\n * Lazily register the Python/Go tree-sitter grammars with ast-grep's\n * `registerDynamicLanguage`. That API throws if called more than once in a\n * process; this guard makes every call after the first a no-op so repeated\n * runner invocations (or a test suite that constructs the runner many times)\n * never trip the constraint.\n */\nexport function ensurePolyglotLangs(): void {\n if (polyglotLangsRegistered) return;\n registerDynamicLanguage({ python: pythonLangRegistration, go: goLangRegistration });\n polyglotLangsRegistered = true;\n}\n\n// ============================================================================\n// Rule schema (fail-closed)\n// ============================================================================\n\n/** Languages a rule file may declare. Deliberately narrowed to the two this\n * runner actually SCANS (python/go): admitting `typescript`/`javascript` here\n * would let a TS/JS rule file validate at load time and then silently never\n * fire (there is no TS/JS extension in {@link POLYGLOT_EXT_TO_LANG}), which is\n * a fail-OPEN gap for a security scanner where \"no findings\" reads as \"clean\".\n * TS/JS structural analysis is already covered by `search_usages` (#4265) and\n * the ast-fixer rewrites (#4243); a TS/JS rule here would fail LOUD at load\n * (unknown-language Zod error) instead of loading dead. */\nexport const AST_RULE_LANGUAGES = ['python', 'go'] as const;\nexport type AstRuleLanguage = (typeof AST_RULE_LANGUAGES)[number];\n\nexport const AST_RULE_SEVERITIES = ['error', 'warning', 'info'] as const;\nexport type AstRuleSeverity = (typeof AST_RULE_SEVERITIES)[number];\n\n/** Schema for one `*.yml` rule file. `rule` is passed through as ast-grep's\n * own `Rule` object (napi already validates it structurally at match time);\n * Zod only pins down the envelope so an unknown `language` or a missing\n * field FAILS CLOSED instead of silently loading a partial/broken rule. */\nconst RuleFileSchema = z.object({\n id: z.string().min(1),\n language: z.enum(AST_RULE_LANGUAGES),\n severity: z.enum(AST_RULE_SEVERITIES),\n message: z.string().min(1),\n rule: z.record(z.string(), z.unknown()),\n});\n\nexport type AstQaRuleFile = z.infer<typeof RuleFileSchema>;\n\n/** Per-match snippet char cap (matches indexer/usage-ast.ts's discipline). */\nconst MAX_SNIPPET_CHARS = 200;\n\n/** Default cap on emitted findings. Excess is counted + reported, never silently dropped. */\nexport const DEFAULT_AST_QA_LIMIT = 200;\n/** Hard upper bound a caller may request for the finding cap. */\nexport const MAX_AST_QA_LIMIT = 2000;\n/** Directory walk depth for the target-dir scan (not caller-configurable — no\n * named consumer needs a deeper/shallower walk yet; YAGNI). */\nconst AST_QA_MAX_DEPTH = 24;\n/** Upper bound on files parsed in a single run, to bound worst-case cost.\n * Exceeding it makes the scan PARTIAL — surfaced via {@link AstQaCollectResult}'s\n * `filesTruncated`/`filesSkipped` + a warn, never silently dropped. */\nexport const MAX_FILES_SCANNED = 5000;\n\nconst logger = createLogger({ component: 'ast-rule-runner' });\n\n// ============================================================================\n// Rule loading\n// ============================================================================\n\n/**\n * Load and Zod-validate every `*.yml` rule file in `dir`. FAILS CLOSED: a\n * single malformed YAML file, or a file with an unrecognized `language` or\n * missing field, throws a {@link ValidationError} — there is no\n * \"load what parsed, skip the rest\" partial mode.\n */\nexport async function loadRules(dir: string): Promise<AstQaRuleFile[]> {\n let entries: string[];\n try {\n entries = (await readdir(dir)).filter((f) => f.endsWith('.yml') || f.endsWith('.yaml')).sort();\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read rules dir ${dir}: ${e.message}`, {\n cause: e,\n });\n }\n\n const rules: AstQaRuleFile[] = [];\n for (const file of entries) {\n const path = join(dir, file);\n const raw = await readFile(path, 'utf8');\n\n let parsed: unknown;\n try {\n parsed = parseYaml(raw);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: malformed YAML in ${path}: ${e.message}`, {\n cause: e,\n });\n }\n\n const result = RuleFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new ValidationError(\n `ast-rule-runner: invalid rule file ${path}: ${formatZodError(result.error)}`\n );\n }\n rules.push(result.data);\n }\n return rules;\n}\n\n// ============================================================================\n// Built-in rules dir resolution (mirrors workflows/template-loader.ts)\n// ============================================================================\n\n/**\n * Resolve the built-in `ast-rules/` directory, handling both dev (unbundled,\n * `src/security/ast-rule-runner.ts`) and published (bundled,\n * `dist/index.js` + `dist/security/ast-rules/*.yml` copied by tsup's\n * `onSuccess` step) layouts — the same two-layout problem\n * `getBuiltInTemplatesPath` solves for workflow templates.\n */\nexport function getBuiltInAstRulesPath(): string {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n\n if (currentFile.includes(`${sep}dist${sep}`) || currentFile.endsWith(`${sep}dist`)) {\n const distIndex = currentFile.lastIndexOf(`${sep}dist${sep}`);\n if (distIndex !== -1) {\n const distDir = currentFile.substring(0, distIndex + 5); // +5 for \"/dist\"\n const bundledPath = join(distDir, 'security', 'ast-rules');\n if (existsSync(bundledPath)) return bundledPath;\n }\n }\n\n const possiblePaths = [\n join(currentDir, 'ast-rules'), // Unbundled: sibling of this file in src/security/\n join(currentDir, 'security', 'ast-rules'), // Bundled chunk: dist/security sibling\n join(dirname(currentDir), 'security', 'ast-rules'),\n ];\n for (const path of possiblePaths) {\n if (existsSync(path)) return path;\n }\n return join(currentDir, 'ast-rules'); // Fallback (for error reporting)\n}\n\n// ============================================================================\n// Path-traversal guard (same shape as mcp/tools/search-usages-tool.ts)\n// ============================================================================\n\n/**\n * Resolve a caller path against a path-traversal guard (must stay within cwd).\n * Realpath-aware: a symlink inside cwd whose target is outside it is refused,\n * and the returned path is the canonical one the scan then walks.\n */\nfunction resolveWithinCwd(target: string): { resolved: string } | { error: string } {\n const resolved = resolveInsideRoot(target);\n if (resolved === null) {\n return { error: `Path traversal denied: scope must be within ${process.cwd()}` };\n }\n return { resolved };\n}\n\n// ============================================================================\n// File walk (LOCAL extension map — python/go only; does NOT reuse\n// indexer/usage-ast.ts's TS/JS inferLang or indexer/codebase-search.ts's\n// TS/JS-only findSourceFiles)\n// ============================================================================\n\nconst SKIP_DIRS = new Set(['node_modules', 'dist', '.git']);\n\n/** file-extension -> ast-rule language, for the two languages this runner scans. */\nconst POLYGLOT_EXT_TO_LANG: Readonly<Record<string, AstRuleLanguage>> = {\n '.py': 'python',\n '.go': 'go',\n};\n\n/** Infer the ast-rule language for a file from its extension, or `null` if unsupported. */\nfunction inferRuleLang(file: string): AstRuleLanguage | null {\n return POLYGLOT_EXT_TO_LANG[extname(file).toLowerCase()] ?? null;\n}\n\n/**\n * Recursively collect `.py`/`.go` files under `dir`, bounded by `maxDepth`.\n * A subdirectory whose `readdir` fails mid-walk (e.g. a `chmod 000` dir) is\n * WARNED about per-dir and skipped rather than silently swallowed — the scan\n * continues, but the partiality is surfaced in the log. The SCAN ROOT's own\n * readability is validated up front by {@link collectAstQaFindings} (fail\n * loud), so this soft-skip only ever applies to descendant dirs.\n */\nasync function findPolyglotFiles(dir: string, maxDepth: number): Promise<string[]> {\n if (maxDepth <= 0) return [];\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n logger.warn(`ast-rule-runner: skipped unreadable directory ${dir}: ${e.message}`);\n return out;\n }\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory() && !SKIP_DIRS.has(entry.name)) {\n out.push(...(await findPolyglotFiles(fullPath, maxDepth - 1)));\n } else if (entry.isFile() && inferRuleLang(entry.name) !== null) {\n out.push(fullPath);\n }\n }\n return out;\n}\n\n/** Map a rule's declared language to the `parse()` first argument, registering\n * the dynamic grammars on first use. Both supported languages (python/go) are\n * dynamically-registered CustomLangs, so the language name string IS the\n * `parse()` key set up in {@link ensurePolyglotLangs}. */\nfunction langToParseArg(lang: AstRuleLanguage): AstRuleLanguage {\n ensurePolyglotLangs();\n return lang; // the CustomLang string keys used in registerDynamicLanguage()\n}\n\n// ============================================================================\n// Findings\n// ============================================================================\n\n/** One ast-grep rule match against a source file. */\nexport interface AstRuleFinding {\n ruleId: string;\n severity: AstRuleSeverity;\n message: string;\n /** Path relative to the resolved `targetDir`. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number. */\n column: number;\n /** Trimmed, length-capped source line for the match. */\n snippet: string;\n}\n\nexport interface RunAstQaRulesOptions {\n /** Directory containing `*.yml` rule files (default: the built-in bundled rules). */\n rulesDir?: string;\n /** Directory to scan for `.py`/`.go` source files (must stay within cwd). */\n targetDir: string;\n /** Max findings emitted (default {@link DEFAULT_AST_QA_LIMIT}). Excess is counted + reported. */\n limit?: number;\n}\n\n/** {@link collectAstQaFindings}'s full result — findings plus the true total,\n * so overflow beyond `limit` is counted and reported, never silently dropped. */\nexport interface AstQaCollectResult {\n findings: AstRuleFinding[];\n /** True count of matches found, before the `limit` cap was applied. */\n total: number;\n limit: number;\n /** Number of `.py`/`.go` files actually scanned (after the file cap). */\n filesScanned: number;\n /** Number of discovered files DROPPED because the file cap ({@link MAX_FILES_SCANNED})\n * was exceeded. Non-zero means the scan was PARTIAL — a downstream consumer\n * must not treat empty/low findings as a clean bill of health. */\n filesSkipped: number;\n /** True iff `filesSkipped > 0` — the scan did not cover every candidate file. */\n filesTruncated: boolean;\n}\n\n/** Findings + true-match-count from scanning ONE already-read source file. */\ninterface FileScanResult {\n findings: AstRuleFinding[];\n total: number;\n}\n\n/** Bundles {@link scanFile}'s cap-tracking inputs (max-params discipline). */\ninterface FileScanBudget {\n /** Path emitted on each finding (relative to the resolved `targetDir`). */\n rel: string;\n /** Max TOTAL findings across the whole run. */\n limit: number;\n /** Findings already accepted by earlier files in this run. */\n alreadyFound: number;\n}\n\n/**\n * Scan one already-read source file against the rules applicable to its\n * language, pushing findings only while the running total (`budget.alreadyFound`\n * + findings pushed so far) stays under `budget.limit` — while still counting\n * every true match, so the caller can report overflow instead of silently\n * dropping it.\n */\nfunction scanFile(\n src: string,\n lang: AstRuleLanguage,\n applicable: readonly AstQaRuleFile[],\n budget: FileScanBudget\n): FileScanResult {\n const { rel, limit, alreadyFound } = budget;\n const root = parse(langToParseArg(lang), src).root();\n const lines = src.split('\\n');\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const rule of applicable) {\n const config: NapiConfig = { rule: rule.rule };\n for (const node of root.findAll(config)) {\n total += 1;\n if (alreadyFound + findings.length < limit) {\n const { start } = node.range();\n const rawLine = lines[start.line] ?? node.text();\n findings.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: rule.message,\n file: rel,\n line: start.line + 1,\n column: start.column + 1,\n snippet: rawLine.trim().slice(0, MAX_SNIPPET_CHARS),\n });\n }\n }\n }\n return { findings, total };\n}\n\n/**\n * Fail LOUD on an unreadable / non-directory scan root. `loadRules` already\n * throws on an unreadable RULES dir; the TARGET traversal must not fail OPEN —\n * a lone file path, a bad path, or a `000` root would otherwise return an empty\n * finding set that reads as \"clean\" for a security scanner.\n */\nasync function assertScanRootIsDirectory(resolved: string): Promise<void> {\n let rootStat;\n try {\n rootStat = await stat(resolved);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read targetDir ${resolved}: ${e.message}`, {\n cause: e,\n });\n }\n if (!rootStat.isDirectory()) {\n throw new ValidationError(\n `ast-rule-runner: targetDir must be a directory, got a non-directory path: ${resolved}`\n );\n }\n}\n\n/** Result of resolving the candidate file set under a scan root, with the\n * file-cap truncation signal surfaced (never a silent `.slice`). */\ninterface ScanFileSet {\n files: string[];\n filesSkipped: number;\n filesTruncated: boolean;\n}\n\n/** Discover candidate `.py`/`.go` files, applying + SURFACING the file cap. */\nasync function resolveScanFiles(root: string): Promise<ScanFileSet> {\n const discovered = await findPolyglotFiles(root, AST_QA_MAX_DEPTH);\n const files = discovered.slice(0, MAX_FILES_SCANNED);\n const filesSkipped = discovered.length - files.length;\n const filesTruncated = filesSkipped > 0;\n if (filesTruncated) {\n logger.warn(\n `ast-rule-runner: ${String(filesSkipped)} file(s) NOT scanned — file cap ` +\n `${String(MAX_FILES_SCANNED)} exceeded (discovered=${String(discovered.length)}). ` +\n `Scan is PARTIAL; do not treat findings as exhaustive.`\n );\n }\n return { files, filesSkipped, filesTruncated };\n}\n\n/**\n * Run every applicable rule in `rulesDir` against every `.py`/`.go` file under\n * `targetDir`, returning capped findings plus the true total (so callers that\n * need the overflow count — e.g. a future MCP tool wrapper — can report it).\n * {@link runAstQaRules} is the capped-array convenience wrapper over this.\n */\nexport async function collectAstQaFindings(\n opts: RunAstQaRulesOptions\n): Promise<AstQaCollectResult> {\n const guard = resolveWithinCwd(opts.targetDir);\n if ('error' in guard) {\n throw new SecurityError(guard.error);\n }\n await assertScanRootIsDirectory(guard.resolved);\n\n const rulesDir = opts.rulesDir ?? getBuiltInAstRulesPath();\n const rules = await loadRules(rulesDir);\n // Clamp into [1, MAX]: a limit <= 0 would report total > 0 with zero findings\n // (fail-open \"clean\" signal), so the floor is load-bearing, not cosmetic.\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_AST_QA_LIMIT, 1), MAX_AST_QA_LIMIT);\n\n const { files, filesSkipped, filesTruncated } = await resolveScanFiles(guard.resolved);\n\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const file of files) {\n const lang = inferRuleLang(file);\n if (lang === null) continue;\n const applicable = rules.filter((r) => r.language === lang);\n if (applicable.length === 0) continue;\n\n let src: string;\n try {\n src = await readFile(file, 'utf8');\n } catch {\n logger.warn(`ast-rule-runner: skipped unreadable file ${file}`);\n continue;\n }\n\n const rel = relative(guard.resolved, file) || file;\n const scanned = scanFile(src, lang, applicable, { rel, limit, alreadyFound: findings.length });\n findings.push(...scanned.findings);\n total += scanned.total;\n }\n\n if (total > findings.length) {\n logger.warn(\n `ast-rule-runner: ${String(total - findings.length)} finding(s) omitted beyond ` +\n `limit=${String(limit)} (total=${String(total)})`\n );\n }\n\n return { findings, total, limit, filesScanned: files.length, filesSkipped, filesTruncated };\n}\n\n/**\n * Run the polyglot QA/security ast-grep rules and return the capped findings\n * array. Overflow beyond `limit` is counted and logged (never silently\n * dropped) — use {@link collectAstQaFindings} directly when the caller needs\n * the true total/overflow count programmatically.\n */\nexport async function runAstQaRules(opts: RunAstQaRulesOptions): Promise<AstRuleFinding[]> {\n const { findings } = await collectAstQaFindings(opts);\n return findings;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/security/ast-rule-runner.ts"],"sourcesContent":["/**\n * nexus-agents/security - Polyglot (Python/Go) AST QA/Security Rule Runner (#4249 child C)\n *\n * Runs YAML-defined `@ast-grep/napi` rules against Python/Go source, detecting\n * common QA/security anti-patterns (dynamic `eval`/`exec`, shell injection,\n * unchecked external command execution). Same engine already used by\n * `search_usages` (indexer/usage-ast.ts, #4265) and the ast-fixer rewrites\n * (agents/collaboration/ast-rewrites.ts, #4243/#4249 child B) — no new AST\n * dependency, just new language grammars for it.\n *\n * **Language support gap.** `Lang` in `@ast-grep/napi@0.44.1` ships only\n * Html/JavaScript/Tsx/Css/TypeScript — no Python, no Go. This module closes\n * that gap via napi's `@experimental registerDynamicLanguage` API, backed by\n * the `@ast-grep/lang-python`/`@ast-grep/lang-go` prebuilt tree-sitter\n * grammars. Both are EXACT-pinned in package.json (no caret): these are\n * early/experimental packages and a caret range could silently swap in an\n * incompatible native `.so` grammar build underneath a \"safe\" semver-minor\n * bump. `registerDynamicLanguage` throws if called more than once per\n * process (napi-rs's own documented constraint) — {@link ensurePolyglotLangs}\n * is a lazy, module-level, once-only guard so repeated calls (tests, repeat\n * runner invocations within one process) never trip it twice.\n *\n * **Read-only.** Reads rule YAML and target source files, walks their ASTs,\n * performs NO writes. ast-grep YAML rule files support a `fix:` key for\n * autofixing, but napi's `SgNode.findAll` (used here) never applies it —\n * only ast-grep's separate rewrite/CLI machinery does — so even a rule\n * author who adds `fix:` cannot turn this runner into a writer by accident.\n * MCP exposure is deliberately deferred (see the follow-up issue referenced\n * in the #4249 child C PR) to keep this surface a plain function until a\n * named consumer needs it wired through a tool.\n *\n * @module security/ast-rule-runner\n * @see Issue #4249 - epic: ast-grep adoption (Child C: polyglot QA/security rules)\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { dirname, extname, join, relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { parse, registerDynamicLanguage } from '@ast-grep/napi';\nimport type { NapiConfig } from '@ast-grep/napi';\n// Both packages are CJS `export = <LanguageRegistration>` modules — the\n// default import is the whole registration object (`libraryPath` getter,\n// `extensions`, `languageSymbol`, `expandoChar`). See their `index.d.ts`.\nimport goLangRegistration from '@ast-grep/lang-go';\nimport pythonLangRegistration from '@ast-grep/lang-python';\nimport { parse as parseYaml } from 'yaml';\nimport { z } from 'zod';\nimport { createLogger, SecurityError, ValidationError, formatZodError } from '../core/index.js';\nimport { resolveInsideRoot } from './safe-path.js';\n\n// ============================================================================\n// Dynamic language registration (@experimental, call-once)\n// ============================================================================\n\nlet polyglotLangsRegistered = false;\n\n/**\n * Lazily register the Python/Go tree-sitter grammars with ast-grep's\n * `registerDynamicLanguage`. That API throws if called more than once in a\n * process; this guard makes every call after the first a no-op so repeated\n * runner invocations (or a test suite that constructs the runner many times)\n * never trip the constraint.\n */\nexport function ensurePolyglotLangs(): void {\n if (polyglotLangsRegistered) return;\n registerDynamicLanguage({ python: pythonLangRegistration, go: goLangRegistration });\n polyglotLangsRegistered = true;\n}\n\n// ============================================================================\n// Rule schema (fail-closed)\n// ============================================================================\n\n/** Languages a rule file may declare. Deliberately narrowed to the two this\n * runner actually SCANS (python/go): admitting `typescript`/`javascript` here\n * would let a TS/JS rule file validate at load time and then silently never\n * fire (there is no TS/JS extension in {@link POLYGLOT_EXT_TO_LANG}), which is\n * a fail-OPEN gap for a security scanner where \"no findings\" reads as \"clean\".\n * TS/JS structural analysis is already covered by `search_usages` (#4265) and\n * the ast-fixer rewrites (#4243); a TS/JS rule here would fail LOUD at load\n * (unknown-language Zod error) instead of loading dead. */\nexport const AST_RULE_LANGUAGES = ['python', 'go'] as const;\nexport type AstRuleLanguage = (typeof AST_RULE_LANGUAGES)[number];\n\nexport const AST_RULE_SEVERITIES = ['error', 'warning', 'info'] as const;\nexport type AstRuleSeverity = (typeof AST_RULE_SEVERITIES)[number];\n\n/** Schema for one `*.yml` rule file. `rule` is passed through as ast-grep's\n * own `Rule` object (napi already validates it structurally at match time);\n * Zod only pins down the envelope so an unknown `language` or a missing\n * field FAILS CLOSED instead of silently loading a partial/broken rule. */\nconst RuleFileSchema = z.object({\n id: z.string().min(1),\n language: z.enum(AST_RULE_LANGUAGES),\n severity: z.enum(AST_RULE_SEVERITIES),\n message: z.string().min(1),\n rule: z.record(z.string(), z.unknown()),\n});\n\nexport type AstQaRuleFile = z.infer<typeof RuleFileSchema>;\n\n/** Per-match snippet char cap (matches indexer/usage-ast.ts's discipline). */\nconst MAX_SNIPPET_CHARS = 200;\n\n/** Default cap on emitted findings. Excess is counted + reported, never silently dropped. */\nexport const DEFAULT_AST_QA_LIMIT = 200;\n/** Hard upper bound a caller may request for the finding cap. */\nexport const MAX_AST_QA_LIMIT = 2000;\n/** Directory walk depth for the target-dir scan (not caller-configurable — no\n * named consumer needs a deeper/shallower walk yet; YAGNI). */\nconst AST_QA_MAX_DEPTH = 24;\n/** Upper bound on files parsed in a single run, to bound worst-case cost.\n * Exceeding it makes the scan PARTIAL — surfaced via {@link AstQaCollectResult}'s\n * `filesTruncated`/`filesSkipped` + a warn, never silently dropped. */\nexport const MAX_FILES_SCANNED = 5000;\n\nconst logger = createLogger({ component: 'ast-rule-runner' });\n\n// ============================================================================\n// Rule loading\n// ============================================================================\n\n/**\n * Load and Zod-validate every `*.yml` rule file in `dir`. FAILS CLOSED: a\n * single malformed YAML file, or a file with an unrecognized `language` or\n * missing field, throws a {@link ValidationError} — there is no\n * \"load what parsed, skip the rest\" partial mode.\n */\nexport async function loadRules(dir: string): Promise<AstQaRuleFile[]> {\n let entries: string[];\n try {\n entries = (await readdir(dir)).filter((f) => f.endsWith('.yml') || f.endsWith('.yaml')).sort();\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read rules dir ${dir}: ${e.message}`, {\n cause: e,\n });\n }\n\n const rules: AstQaRuleFile[] = [];\n for (const file of entries) {\n const path = join(dir, file);\n const raw = await readFile(path, 'utf8');\n\n let parsed: unknown;\n try {\n parsed = parseYaml(raw);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: malformed YAML in ${path}: ${e.message}`, {\n cause: e,\n });\n }\n\n const result = RuleFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new ValidationError(\n `ast-rule-runner: invalid rule file ${path}: ${formatZodError(result.error)}`\n );\n }\n rules.push(result.data);\n }\n return rules;\n}\n\n// ============================================================================\n// Built-in rules dir resolution (mirrors workflows/template-loader.ts)\n// ============================================================================\n\n/**\n * Resolve the built-in `ast-rules/` directory, handling both dev (unbundled,\n * `src/security/ast-rule-runner.ts`) and published (bundled,\n * `dist/index.js` + `dist/security/ast-rules/*.yml` copied by tsup's\n * `onSuccess` step) layouts — the same two-layout problem\n * `getBuiltInTemplatesPath` solves for workflow templates.\n */\nexport function getBuiltInAstRulesPath(): string {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n\n if (currentFile.includes(`${sep}dist${sep}`) || currentFile.endsWith(`${sep}dist`)) {\n const distIndex = currentFile.lastIndexOf(`${sep}dist${sep}`);\n if (distIndex !== -1) {\n const distDir = currentFile.substring(0, distIndex + 5); // +5 for \"/dist\"\n const bundledPath = join(distDir, 'security', 'ast-rules');\n if (existsSync(bundledPath)) return bundledPath;\n }\n }\n\n const possiblePaths = [\n join(currentDir, 'ast-rules'), // Unbundled: sibling of this file in src/security/\n join(currentDir, 'security', 'ast-rules'), // Bundled chunk: dist/security sibling\n join(dirname(currentDir), 'security', 'ast-rules'),\n ];\n for (const path of possiblePaths) {\n if (existsSync(path)) return path;\n }\n return join(currentDir, 'ast-rules'); // Fallback (for error reporting)\n}\n\n// ============================================================================\n// Path-traversal guard (same shape as mcp/tools/search-usages-tool.ts)\n// ============================================================================\n\n/**\n * Resolve a caller path against a path-traversal guard (must stay within cwd).\n * Realpath-aware: a symlink inside cwd whose target is outside it is refused,\n * and the returned path is the canonical one the scan then walks.\n */\nfunction resolveWithinCwd(target: string): { resolved: string } | { error: string } {\n const resolved = resolveInsideRoot(target);\n if (resolved === null) {\n return { error: `Path traversal denied: scope must be within ${process.cwd()}` };\n }\n return { resolved };\n}\n\n// ============================================================================\n// File walk (LOCAL extension map — python/go only; does NOT reuse\n// indexer/usage-ast.ts's TS/JS inferLang or indexer/codebase-search.ts's\n// TS/JS-only findSourceFiles)\n// ============================================================================\n\nconst SKIP_DIRS = new Set(['node_modules', 'dist', '.git']);\n\n/** file-extension -> ast-rule language, for the two languages this runner scans. */\nconst POLYGLOT_EXT_TO_LANG: Readonly<Record<string, AstRuleLanguage>> = {\n '.py': 'python',\n '.go': 'go',\n};\n\n/** Infer the ast-rule language for a file from its extension, or `null` if unsupported. */\nfunction inferRuleLang(file: string): AstRuleLanguage | null {\n return POLYGLOT_EXT_TO_LANG[extname(file).toLowerCase()] ?? null;\n}\n\n/**\n * Recursively collect `.py`/`.go` files under `dir`, bounded by `maxDepth`.\n * A subdirectory whose `readdir` fails mid-walk (e.g. a `chmod 000` dir) is\n * WARNED about per-dir and skipped rather than silently swallowed — the scan\n * continues, but the partiality is surfaced in the log. The SCAN ROOT's own\n * readability is validated up front by {@link collectAstQaFindings} (fail\n * loud), so this soft-skip only ever applies to descendant dirs.\n */\nasync function findPolyglotFiles(dir: string, maxDepth: number): Promise<string[]> {\n if (maxDepth <= 0) return [];\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n logger.warn(`ast-rule-runner: skipped unreadable directory ${dir}: ${e.message}`);\n return out;\n }\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory() && !SKIP_DIRS.has(entry.name)) {\n out.push(...(await findPolyglotFiles(fullPath, maxDepth - 1)));\n } else if (entry.isFile() && inferRuleLang(entry.name) !== null) {\n out.push(fullPath);\n }\n }\n return out;\n}\n\n/** Map a rule's declared language to the `parse()` first argument, registering\n * the dynamic grammars on first use. Both supported languages (python/go) are\n * dynamically-registered CustomLangs, so the language name string IS the\n * `parse()` key set up in {@link ensurePolyglotLangs}. */\nfunction langToParseArg(lang: AstRuleLanguage): AstRuleLanguage {\n ensurePolyglotLangs();\n return lang; // the CustomLang string keys used in registerDynamicLanguage()\n}\n\n// ============================================================================\n// Findings\n// ============================================================================\n\n/** One ast-grep rule match against a source file. */\nexport interface AstRuleFinding {\n ruleId: string;\n severity: AstRuleSeverity;\n message: string;\n /** Path relative to the resolved `targetDir`. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number. */\n column: number;\n /** Trimmed, length-capped source line for the match. */\n snippet: string;\n}\n\nexport interface RunAstQaRulesOptions {\n /** Directory containing `*.yml` rule files (default: the built-in bundled rules). */\n rulesDir?: string;\n /** Directory to scan for `.py`/`.go` source files (must stay within cwd). */\n targetDir: string;\n /** Max findings emitted (default {@link DEFAULT_AST_QA_LIMIT}). Excess is counted + reported. */\n limit?: number;\n}\n\n/** {@link collectAstQaFindings}'s full result — findings plus the true total,\n * so overflow beyond `limit` is counted and reported, never silently dropped. */\nexport interface AstQaCollectResult {\n findings: AstRuleFinding[];\n /** True count of matches found, before the `limit` cap was applied. */\n total: number;\n limit: number;\n /** Number of `.py`/`.go` files actually scanned (after the file cap). */\n filesScanned: number;\n /** Number of discovered files DROPPED because the file cap ({@link MAX_FILES_SCANNED})\n * was exceeded. Non-zero means the scan was PARTIAL — a downstream consumer\n * must not treat empty/low findings as a clean bill of health. */\n filesSkipped: number;\n /** True iff `filesSkipped > 0` — the scan did not cover every candidate file. */\n filesTruncated: boolean;\n}\n\n/** Findings + true-match-count from scanning ONE already-read source file. */\ninterface FileScanResult {\n findings: AstRuleFinding[];\n total: number;\n}\n\n/** Bundles {@link scanFile}'s cap-tracking inputs (max-params discipline). */\ninterface FileScanBudget {\n /** Path emitted on each finding (relative to the resolved `targetDir`). */\n rel: string;\n /** Max TOTAL findings across the whole run. */\n limit: number;\n /** Findings already accepted by earlier files in this run. */\n alreadyFound: number;\n}\n\n/**\n * Scan one already-read source file against the rules applicable to its\n * language, pushing findings only while the running total (`budget.alreadyFound`\n * + findings pushed so far) stays under `budget.limit` — while still counting\n * every true match, so the caller can report overflow instead of silently\n * dropping it.\n */\nfunction scanFile(\n src: string,\n lang: AstRuleLanguage,\n applicable: readonly AstQaRuleFile[],\n budget: FileScanBudget\n): FileScanResult {\n const { rel, limit, alreadyFound } = budget;\n const root = parse(langToParseArg(lang), src).root();\n const lines = src.split('\\n');\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const rule of applicable) {\n const config: NapiConfig = { rule: rule.rule };\n for (const node of root.findAll(config)) {\n total += 1;\n if (alreadyFound + findings.length < limit) {\n const { start } = node.range();\n const rawLine = lines[start.line] ?? node.text();\n findings.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: rule.message,\n file: rel,\n line: start.line + 1,\n column: start.column + 1,\n snippet: rawLine.trim().slice(0, MAX_SNIPPET_CHARS),\n });\n }\n }\n }\n return { findings, total };\n}\n\n/**\n * Fail LOUD on an unreadable / non-directory scan root. `loadRules` already\n * throws on an unreadable RULES dir; the TARGET traversal must not fail OPEN —\n * a lone file path, a bad path, or a `000` root would otherwise return an empty\n * finding set that reads as \"clean\" for a security scanner.\n */\nasync function assertScanRootIsDirectory(resolved: string): Promise<void> {\n let rootStat;\n try {\n rootStat = await stat(resolved);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read targetDir ${resolved}: ${e.message}`, {\n cause: e,\n });\n }\n if (!rootStat.isDirectory()) {\n throw new ValidationError(\n `ast-rule-runner: targetDir must be a directory, got a non-directory path: ${resolved}`\n );\n }\n}\n\n/** Result of resolving the candidate file set under a scan root, with the\n * file-cap truncation signal surfaced (never a silent `.slice`). */\ninterface ScanFileSet {\n files: string[];\n filesSkipped: number;\n filesTruncated: boolean;\n}\n\n/** Discover candidate `.py`/`.go` files, applying + SURFACING the file cap. */\nasync function resolveScanFiles(root: string): Promise<ScanFileSet> {\n const discovered = await findPolyglotFiles(root, AST_QA_MAX_DEPTH);\n const files = discovered.slice(0, MAX_FILES_SCANNED);\n const filesSkipped = discovered.length - files.length;\n const filesTruncated = filesSkipped > 0;\n if (filesTruncated) {\n logger.warn(\n `ast-rule-runner: ${String(filesSkipped)} file(s) NOT scanned — file cap ` +\n `${String(MAX_FILES_SCANNED)} exceeded (discovered=${String(discovered.length)}). ` +\n `Scan is PARTIAL; do not treat findings as exhaustive.`\n );\n }\n return { files, filesSkipped, filesTruncated };\n}\n\n/**\n * Run every applicable rule in `rulesDir` against every `.py`/`.go` file under\n * `targetDir`, returning capped findings plus the true total (so callers that\n * need the overflow count — e.g. a future MCP tool wrapper — can report it).\n * {@link runAstQaRules} is the capped-array convenience wrapper over this.\n */\nexport async function collectAstQaFindings(\n opts: RunAstQaRulesOptions\n): Promise<AstQaCollectResult> {\n const guard = resolveWithinCwd(opts.targetDir);\n if ('error' in guard) {\n throw new SecurityError(guard.error);\n }\n await assertScanRootIsDirectory(guard.resolved);\n\n const rulesDir = opts.rulesDir ?? getBuiltInAstRulesPath();\n const rules = await loadRules(rulesDir);\n // Clamp into [1, MAX]: a limit <= 0 would report total > 0 with zero findings\n // (fail-open \"clean\" signal), so the floor is load-bearing, not cosmetic.\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_AST_QA_LIMIT, 1), MAX_AST_QA_LIMIT);\n\n const { files, filesSkipped, filesTruncated } = await resolveScanFiles(guard.resolved);\n\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const file of files) {\n const lang = inferRuleLang(file);\n if (lang === null) continue;\n const applicable = rules.filter((r) => r.language === lang);\n if (applicable.length === 0) continue;\n\n let src: string;\n try {\n src = await readFile(file, 'utf8');\n } catch {\n logger.warn(`ast-rule-runner: skipped unreadable file ${file}`);\n continue;\n }\n\n const rel = relative(guard.resolved, file) || file;\n const scanned = scanFile(src, lang, applicable, { rel, limit, alreadyFound: findings.length });\n findings.push(...scanned.findings);\n total += scanned.total;\n }\n\n if (total > findings.length) {\n logger.warn(\n `ast-rule-runner: ${String(total - findings.length)} finding(s) omitted beyond ` +\n `limit=${String(limit)} (total=${String(total)})`\n );\n }\n\n return { findings, total, limit, filesScanned: files.length, filesSkipped, filesTruncated };\n}\n\n/**\n * Run the polyglot QA/security ast-grep rules and return the capped findings\n * array. Overflow beyond `limit` is counted and logged (never silently\n * dropped) — use {@link collectAstQaFindings} directly when the caller needs\n * the true total/overflow count programmatically.\n */\nexport async function runAstQaRules(opts: RunAstQaRulesOptions): Promise<AstRuleFinding[]> {\n const { findings } = await collectAstQaFindings(opts);\n return findings;\n}\n"],"mappings":"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","names":[]}
@@ -4,16 +4,16 @@ import {
4
4
  createOpenAICompatAdapter,
5
5
  discoverGatewayCatalog,
6
6
  readOpenAICompatEnv
7
- } from "./chunk-V4GLPTHB.js";
7
+ } from "./chunk-AFYFKT6T.js";
8
8
  import {
9
9
  CUSTOM_API_DEFAULT_MODEL
10
- } from "./chunk-G6C4CB2P.js";
10
+ } from "./chunk-23FQPFI4.js";
11
11
  import {
12
12
  gatewayProxyUrl
13
- } from "./chunk-DRNW3QRY.js";
13
+ } from "./chunk-BKQ3ALKH.js";
14
14
  import {
15
15
  redactGatewaySecrets
16
- } from "./chunk-MVFKTFMM.js";
16
+ } from "./chunk-BGQA53QQ.js";
17
17
  import {
18
18
  DEFAULT_OPENAI_COMPAT_ENDPOINT,
19
19
  GATEWAY_COST_ENV,
@@ -31,7 +31,7 @@ import {
31
31
  isCliDisabled,
32
32
  symbols,
33
33
  writeLine
34
- } from "./chunk-PM2ECWCL.js";
34
+ } from "./chunk-L5CDQ7QK.js";
35
35
 
36
36
  // src/cli/doctor-gateway-slots.ts
37
37
  var FAMILY_SLOTS = [
@@ -398,4 +398,4 @@ export {
398
398
  formatGatewayReport,
399
399
  formatGatewaySlotWarnings
400
400
  };
401
- //# sourceMappingURL=chunk-TXXXWVPX.js.map
401
+ //# sourceMappingURL=chunk-EL6WVSX2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SERVES_PROBE_PROMPT
3
- } from "./chunk-WBIO7WHW.js";
3
+ } from "./chunk-I7WLZ3KF.js";
4
4
  import {
5
5
  checkGatewayHealth,
6
6
  cliFailsVerdict,
@@ -10,13 +10,13 @@ import {
10
10
  gatewaySlotServing,
11
11
  gatewayVerdict,
12
12
  printVoterTransportCheck
13
- } from "./chunk-TXXXWVPX.js";
13
+ } from "./chunk-EL6WVSX2.js";
14
14
  import {
15
15
  NODE_ENGINE_RANGE,
16
16
  VERSION,
17
17
  isNodeVersionSupported,
18
18
  recordServerTransport
19
- } from "./chunk-4SZQYMMO.js";
19
+ } from "./chunk-MBBQDXX6.js";
20
20
  import {
21
21
  allOf,
22
22
  anyOf
@@ -24,10 +24,10 @@ import {
24
24
  import {
25
25
  readOpenAICompatEndpoint,
26
26
  readOpenAICompatEnv
27
- } from "./chunk-V4GLPTHB.js";
27
+ } from "./chunk-AFYFKT6T.js";
28
28
  import {
29
29
  claimGlobalRegistry
30
- } from "./chunk-DKJITSJK.js";
30
+ } from "./chunk-3CBBUAZZ.js";
31
31
  import {
32
32
  capitalize
33
33
  } from "./chunk-SX5DB6UR.js";
@@ -41,13 +41,13 @@ import {
41
41
  createAllAdapters,
42
42
  isCliAdmitted,
43
43
  probeCli
44
- } from "./chunk-LTYFP4MJ.js";
44
+ } from "./chunk-RMLNW376.js";
45
45
  import {
46
46
  getNexusTmpDir
47
47
  } from "./chunk-OITVVSWO.js";
48
48
  import {
49
49
  resolveGatewayEnv
50
- } from "./chunk-MVFKTFMM.js";
50
+ } from "./chunk-BGQA53QQ.js";
51
51
  import {
52
52
  DEFAULT_CAPABILITIES,
53
53
  cliBinaryAdapterOf,
@@ -70,7 +70,7 @@ import {
70
70
  resolveGatewayCostDeclaration,
71
71
  symbols,
72
72
  writeLine
73
- } from "./chunk-PM2ECWCL.js";
73
+ } from "./chunk-L5CDQ7QK.js";
74
74
  import {
75
75
  getLearningDir,
76
76
  getOutcomesFile,
@@ -1499,7 +1499,7 @@ async function doctorCommand(options = {}) {
1499
1499
  options.onResult?.(result);
1500
1500
  printDoctorResults(result);
1501
1501
  if (options.gateway === true || options.probe === true) {
1502
- const { formatGatewayReport } = await import("./doctor-gateway-report-QQVWP3P5.js");
1502
+ const { formatGatewayReport } = await import("./doctor-gateway-report-A7MZPJWD.js");
1503
1503
  for (const line of formatGatewayReport(result.gateway, result.clis)) {
1504
1504
  process.stdout.write(line + "\n");
1505
1505
  }
@@ -1518,13 +1518,13 @@ async function runDoctorFix(result) {
1518
1518
  writeLine2("\u2500".repeat(40));
1519
1519
  let fixCount = 0;
1520
1520
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
1521
- const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-46AJGMKK.js");
1521
+ const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-DUDPUBXE.js");
1522
1522
  const outcome = describeDataDirFix2(initDataDirectories2());
1523
1523
  writeLine2(outcome.line);
1524
1524
  if (outcome.counted) fixCount++;
1525
1525
  }
1526
1526
  if (!result.configFile.found) {
1527
- const { runConfigInitSync } = await import("./setup-config-TLKV6TBJ.js");
1527
+ const { runConfigInitSync } = await import("./setup-config-TNAEREJ2.js");
1528
1528
  const configResult = runConfigInitSync(process.cwd(), false, false);
1529
1529
  if (configResult.success && configResult.created) {
1530
1530
  writeLine2(`\u2713 Generated config: ${configResult.path}`);
@@ -1620,4 +1620,4 @@ export {
1620
1620
  startStdioServer,
1621
1621
  closeServer
1622
1622
  };
1623
- //# sourceMappingURL=chunk-NGVBCGM6.js.map
1623
+ //# sourceMappingURL=chunk-FEOYDA6G.js.map
@@ -3,17 +3,14 @@ import {
3
3
  } from "./chunk-W654ME6B.js";
4
4
  import {
5
5
  resolveToken
6
- } from "./chunk-W4VWFQRC.js";
6
+ } from "./chunk-6WRH3LBP.js";
7
7
  import {
8
8
  REGISTRY_PATH,
9
9
  getProjectRoot,
10
10
  loadPapersRegistry,
11
11
  loadTechniquesRegistry,
12
12
  savePapersRegistry
13
- } from "./chunk-3NQVZQCT.js";
14
- import {
15
- resolveInsideRoot
16
- } from "./chunk-XEPZSDN5.js";
13
+ } from "./chunk-TGWRNNHQ.js";
17
14
  import {
18
15
  beliefTrustTier,
19
16
  getToolMemory,
@@ -21,7 +18,7 @@ import {
21
18
  rankedItemTrustTier,
22
19
  trustTierLabel,
23
20
  withoutUntrustedMemory
24
- } from "./chunk-YCTJNJKU.js";
21
+ } from "./chunk-T7ZKHG5T.js";
25
22
  import {
26
23
  capitalizeWords,
27
24
  tokenizeFiltered,
@@ -49,8 +46,9 @@ import {
49
46
  getTimeProvider,
50
47
  ok,
51
48
  registerPersistentDistillerFactory,
49
+ resolveInsideRoot,
52
50
  sigmoidConfidence
53
- } from "./chunk-PM2ECWCL.js";
51
+ } from "./chunk-L5CDQ7QK.js";
54
52
  import {
55
53
  ensureLearningDir,
56
54
  getRulesFile
@@ -4287,4 +4285,4 @@ export {
4287
4285
  DEFAULT_CONTEXT_BUDGET_TOKENS,
4288
4286
  getContextPromptPrefix
4289
4287
  };
4290
- //# sourceMappingURL=chunk-XJGVR65R.js.map
4288
+ //# sourceMappingURL=chunk-G3RQ3ECZ.js.map