nexus-agents 2.160.0 → 2.160.2

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 (121) hide show
  1. package/dist/{child-mcp-config-XEXFG3LA.js → child-mcp-config-JHX6JCF5.js} +2 -2
  2. package/dist/{chunk-HBLVOFLL.js → chunk-24ALAT2O.js} +2 -2
  3. package/dist/{chunk-AMY4S4VD.js → chunk-2CGJSTYK.js} +2 -2
  4. package/dist/{chunk-I2DK3KSH.js → chunk-2QDZ2L2C.js} +2 -2
  5. package/dist/{chunk-ZO54JW4V.js → chunk-32ZVVATK.js} +3 -3
  6. package/dist/{chunk-OQUELE4L.js → chunk-3CPGLNSD.js} +38 -35
  7. package/dist/{chunk-OQUELE4L.js.map → chunk-3CPGLNSD.js.map} +1 -1
  8. package/dist/{chunk-VWX75FKD.js → chunk-3QHURPW4.js} +5 -5
  9. package/dist/{chunk-RU336IEH.js → chunk-3XMAIPFB.js} +2 -2
  10. package/dist/{chunk-5NVU25BA.js → chunk-3Y44T42S.js} +4 -4
  11. package/dist/{chunk-QD653D5O.js → chunk-4JKJEEMP.js} +7 -7
  12. package/dist/{chunk-I6NTUVGW.js → chunk-4KRO6NTX.js} +2 -2
  13. package/dist/{chunk-ICYEG7T4.js → chunk-4TLU7JJA.js} +7 -7
  14. package/dist/{chunk-SHFCJJTY.js → chunk-6DJ7WISU.js} +6 -6
  15. package/dist/{chunk-SHFCJJTY.js.map → chunk-6DJ7WISU.js.map} +1 -1
  16. package/dist/{chunk-RNCBSF6I.js → chunk-6EUEK2T5.js} +2 -2
  17. package/dist/{chunk-E7LG7L4O.js → chunk-7NOWAN4D.js} +9 -7
  18. package/dist/{chunk-E7LG7L4O.js.map → chunk-7NOWAN4D.js.map} +1 -1
  19. package/dist/{chunk-O27ZG7BL.js → chunk-AL3PRVJG.js} +3 -3
  20. package/dist/{chunk-VKUP2PG5.js → chunk-AMU753KU.js} +14 -10
  21. package/dist/chunk-AMU753KU.js.map +1 -0
  22. package/dist/{chunk-SNKSSSAR.js → chunk-BKPBAXWH.js} +4 -4
  23. package/dist/{chunk-ZBEJITR6.js → chunk-CDJJ3CL2.js} +5 -5
  24. package/dist/{chunk-XLEZBTQG.js → chunk-DDAYKDEB.js} +2 -2
  25. package/dist/{chunk-ED6B55WK.js → chunk-H2HAB3EW.js} +3 -3
  26. package/dist/{chunk-WRISLYLK.js → chunk-INQLVBAM.js} +2 -2
  27. package/dist/{chunk-JYV5MZC6.js → chunk-J2SLPVMA.js} +4 -4
  28. package/dist/{chunk-WP6UBBNJ.js → chunk-JRQSJ2L7.js} +4 -4
  29. package/dist/{chunk-7XISTLQP.js → chunk-LB5AD6JX.js} +8 -8
  30. package/dist/{chunk-FYQSTNG6.js → chunk-LPFOSO5W.js} +5 -5
  31. package/dist/{chunk-4AXOISAP.js → chunk-NSPJHKKJ.js} +3 -3
  32. package/dist/{chunk-QVIQAIOK.js → chunk-PRERQSR2.js} +2 -2
  33. package/dist/{chunk-MXNIOTDY.js → chunk-PXIGNQWU.js} +3 -3
  34. package/dist/{chunk-IG2SIC2E.js → chunk-RHY46PYV.js} +2 -2
  35. package/dist/{chunk-B23GFISN.js → chunk-TID366GJ.js} +3 -3
  36. package/dist/{chunk-HT3B6ZWV.js → chunk-URIRSUQQ.js} +2 -2
  37. package/dist/{chunk-Q6EGZKLE.js → chunk-W75MNLLK.js} +2 -2
  38. package/dist/{chunk-SN4Q7TZT.js → chunk-WFGGF6RQ.js} +2 -2
  39. package/dist/{chunk-3QIXGEY7.js → chunk-WZJK5ZK3.js} +2 -2
  40. package/dist/{cli-circuit-breaker-SAHRY3BI.js → cli-circuit-breaker-3MA2YHO4.js} +4 -4
  41. package/dist/cli.js +41 -41
  42. package/dist/{composite-router-MFJNLR3O.js → composite-router-XNE5Q3YF.js} +2 -2
  43. package/dist/{consensus-vote-Z55357CP.js → consensus-vote-4CU3EY7H.js} +15 -15
  44. package/dist/{context-retriever-Z474PNZ4.js → context-retriever-VOPNSCRI.js} +8 -8
  45. package/dist/{doctor-deep-IESAJDVW.js → doctor-deep-LPZ7X4MY.js} +3 -3
  46. package/dist/{expert-bridge-JW4DJPH3.js → expert-bridge-WDVNKIO3.js} +4 -4
  47. package/dist/{factory-Z7GGTUK2.js → factory-3KFIWW2N.js} +5 -5
  48. package/dist/{factory-6JIXPGRH.js → factory-Q4FUNYFK.js} +8 -8
  49. package/dist/{improvement-review-5DRIOL5K.js → improvement-review-SUVEFV7C.js} +5 -5
  50. package/dist/index.d.ts +7 -0
  51. package/dist/index.js +30 -30
  52. package/dist/{init-opencode-T2F5WSLT.js → init-opencode-IU3SEIHV.js} +6 -6
  53. package/dist/{issue-triage-RC5VVUAV.js → issue-triage-PF2WKXHL.js} +6 -6
  54. package/dist/{pr-reviewer-helpers-G35TGA7R.js → pr-reviewer-helpers-UR7WCAGK.js} +4 -4
  55. package/dist/{registry-command-47UO65SV.js → registry-command-IHDL7SMW.js} +2 -2
  56. package/dist/{repo-security-plan-CGXT5CIP.js → repo-security-plan-YNCJQ2YC.js} +3 -3
  57. package/dist/{research-helpers-synthesize-37WHCE5I.js → research-helpers-synthesize-FUY4WVHY.js} +4 -4
  58. package/dist/{routing-memory-YWPM45FH.js → routing-memory-CRRV6C4D.js} +2 -2
  59. package/dist/{session-memory-ENUULCNK.js → session-memory-JLWKMKZI.js} +3 -3
  60. package/dist/{setup-command-T6I5TRFR.js → setup-command-Q23UB7WS.js} +11 -11
  61. package/dist/{setup-config-AMGGWQHX.js → setup-config-DXN6CAOG.js} +3 -3
  62. package/dist/{setup-custom-api-UNAPYLEX.js → setup-custom-api-NKK2CNLH.js} +3 -3
  63. package/dist/{tool-memory-QH3DN2SU.js → tool-memory-JUZW6R3I.js} +5 -5
  64. package/dist/{unified-registry-YXQGTU3P.js → unified-registry-3ROGZFAX.js} +9 -9
  65. package/dist/{weather-report-BUKQ7YPV.js → weather-report-5MYASHFK.js} +2 -2
  66. package/package.json +1 -1
  67. package/dist/chunk-VKUP2PG5.js.map +0 -1
  68. /package/dist/{child-mcp-config-XEXFG3LA.js.map → child-mcp-config-JHX6JCF5.js.map} +0 -0
  69. /package/dist/{chunk-HBLVOFLL.js.map → chunk-24ALAT2O.js.map} +0 -0
  70. /package/dist/{chunk-AMY4S4VD.js.map → chunk-2CGJSTYK.js.map} +0 -0
  71. /package/dist/{chunk-I2DK3KSH.js.map → chunk-2QDZ2L2C.js.map} +0 -0
  72. /package/dist/{chunk-ZO54JW4V.js.map → chunk-32ZVVATK.js.map} +0 -0
  73. /package/dist/{chunk-VWX75FKD.js.map → chunk-3QHURPW4.js.map} +0 -0
  74. /package/dist/{chunk-RU336IEH.js.map → chunk-3XMAIPFB.js.map} +0 -0
  75. /package/dist/{chunk-5NVU25BA.js.map → chunk-3Y44T42S.js.map} +0 -0
  76. /package/dist/{chunk-QD653D5O.js.map → chunk-4JKJEEMP.js.map} +0 -0
  77. /package/dist/{chunk-I6NTUVGW.js.map → chunk-4KRO6NTX.js.map} +0 -0
  78. /package/dist/{chunk-ICYEG7T4.js.map → chunk-4TLU7JJA.js.map} +0 -0
  79. /package/dist/{chunk-RNCBSF6I.js.map → chunk-6EUEK2T5.js.map} +0 -0
  80. /package/dist/{chunk-O27ZG7BL.js.map → chunk-AL3PRVJG.js.map} +0 -0
  81. /package/dist/{chunk-SNKSSSAR.js.map → chunk-BKPBAXWH.js.map} +0 -0
  82. /package/dist/{chunk-ZBEJITR6.js.map → chunk-CDJJ3CL2.js.map} +0 -0
  83. /package/dist/{chunk-XLEZBTQG.js.map → chunk-DDAYKDEB.js.map} +0 -0
  84. /package/dist/{chunk-ED6B55WK.js.map → chunk-H2HAB3EW.js.map} +0 -0
  85. /package/dist/{chunk-WRISLYLK.js.map → chunk-INQLVBAM.js.map} +0 -0
  86. /package/dist/{chunk-JYV5MZC6.js.map → chunk-J2SLPVMA.js.map} +0 -0
  87. /package/dist/{chunk-WP6UBBNJ.js.map → chunk-JRQSJ2L7.js.map} +0 -0
  88. /package/dist/{chunk-7XISTLQP.js.map → chunk-LB5AD6JX.js.map} +0 -0
  89. /package/dist/{chunk-FYQSTNG6.js.map → chunk-LPFOSO5W.js.map} +0 -0
  90. /package/dist/{chunk-4AXOISAP.js.map → chunk-NSPJHKKJ.js.map} +0 -0
  91. /package/dist/{chunk-QVIQAIOK.js.map → chunk-PRERQSR2.js.map} +0 -0
  92. /package/dist/{chunk-MXNIOTDY.js.map → chunk-PXIGNQWU.js.map} +0 -0
  93. /package/dist/{chunk-IG2SIC2E.js.map → chunk-RHY46PYV.js.map} +0 -0
  94. /package/dist/{chunk-B23GFISN.js.map → chunk-TID366GJ.js.map} +0 -0
  95. /package/dist/{chunk-HT3B6ZWV.js.map → chunk-URIRSUQQ.js.map} +0 -0
  96. /package/dist/{chunk-Q6EGZKLE.js.map → chunk-W75MNLLK.js.map} +0 -0
  97. /package/dist/{chunk-SN4Q7TZT.js.map → chunk-WFGGF6RQ.js.map} +0 -0
  98. /package/dist/{chunk-3QIXGEY7.js.map → chunk-WZJK5ZK3.js.map} +0 -0
  99. /package/dist/{cli-circuit-breaker-SAHRY3BI.js.map → cli-circuit-breaker-3MA2YHO4.js.map} +0 -0
  100. /package/dist/{composite-router-MFJNLR3O.js.map → composite-router-XNE5Q3YF.js.map} +0 -0
  101. /package/dist/{consensus-vote-Z55357CP.js.map → consensus-vote-4CU3EY7H.js.map} +0 -0
  102. /package/dist/{context-retriever-Z474PNZ4.js.map → context-retriever-VOPNSCRI.js.map} +0 -0
  103. /package/dist/{doctor-deep-IESAJDVW.js.map → doctor-deep-LPZ7X4MY.js.map} +0 -0
  104. /package/dist/{expert-bridge-JW4DJPH3.js.map → expert-bridge-WDVNKIO3.js.map} +0 -0
  105. /package/dist/{factory-6JIXPGRH.js.map → factory-3KFIWW2N.js.map} +0 -0
  106. /package/dist/{factory-Z7GGTUK2.js.map → factory-Q4FUNYFK.js.map} +0 -0
  107. /package/dist/{improvement-review-5DRIOL5K.js.map → improvement-review-SUVEFV7C.js.map} +0 -0
  108. /package/dist/{init-opencode-T2F5WSLT.js.map → init-opencode-IU3SEIHV.js.map} +0 -0
  109. /package/dist/{issue-triage-RC5VVUAV.js.map → issue-triage-PF2WKXHL.js.map} +0 -0
  110. /package/dist/{pr-reviewer-helpers-G35TGA7R.js.map → pr-reviewer-helpers-UR7WCAGK.js.map} +0 -0
  111. /package/dist/{registry-command-47UO65SV.js.map → registry-command-IHDL7SMW.js.map} +0 -0
  112. /package/dist/{repo-security-plan-CGXT5CIP.js.map → repo-security-plan-YNCJQ2YC.js.map} +0 -0
  113. /package/dist/{research-helpers-synthesize-37WHCE5I.js.map → research-helpers-synthesize-FUY4WVHY.js.map} +0 -0
  114. /package/dist/{routing-memory-YWPM45FH.js.map → routing-memory-CRRV6C4D.js.map} +0 -0
  115. /package/dist/{session-memory-ENUULCNK.js.map → session-memory-JLWKMKZI.js.map} +0 -0
  116. /package/dist/{setup-command-T6I5TRFR.js.map → setup-command-Q23UB7WS.js.map} +0 -0
  117. /package/dist/{setup-config-AMGGWQHX.js.map → setup-config-DXN6CAOG.js.map} +0 -0
  118. /package/dist/{setup-custom-api-UNAPYLEX.js.map → setup-custom-api-NKK2CNLH.js.map} +0 -0
  119. /package/dist/{tool-memory-QH3DN2SU.js.map → tool-memory-JUZW6R3I.js.map} +0 -0
  120. /package/dist/{unified-registry-YXQGTU3P.js.map → unified-registry-3ROGZFAX.js.map} +0 -0
  121. /package/dist/{weather-report-BUKQ7YPV.js.map → weather-report-5MYASHFK.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-HT3B6ZWV.js";
4
+ } from "./chunk-URIRSUQQ.js";
5
5
  import {
6
6
  ROLE_DEFAULT_TRUST,
7
7
  ReputationCache,
@@ -11,17 +11,17 @@ import {
11
11
  gateWithReputation,
12
12
  resolveReputationGatingMode,
13
13
  sanitizeInput
14
- } from "./chunk-HBLVOFLL.js";
14
+ } from "./chunk-24ALAT2O.js";
15
15
  import {
16
16
  emitPolicyEvent
17
- } from "./chunk-QVIQAIOK.js";
17
+ } from "./chunk-PRERQSR2.js";
18
18
  import {
19
19
  CLI_SUBPROCESS_TIMEOUTS,
20
20
  createLogger,
21
21
  err,
22
22
  getTimeProvider,
23
23
  ok
24
- } from "./chunk-E7LG7L4O.js";
24
+ } from "./chunk-7NOWAN4D.js";
25
25
 
26
26
  // src/security/trust-classifier.ts
27
27
  function mapAuthorAssociation(association) {
@@ -1211,4 +1211,4 @@ export {
1211
1211
  IssueTriage,
1212
1212
  createIssueTriage
1213
1213
  };
1214
- //# sourceMappingURL=chunk-VWX75FKD.js.map
1214
+ //# sourceMappingURL=chunk-3QHURPW4.js.map
@@ -3,7 +3,7 @@ import {
3
3
  MODEL_IDS,
4
4
  getTimeProvider,
5
5
  resolveModelIdentitySync
6
- } from "./chunk-E7LG7L4O.js";
6
+ } from "./chunk-7NOWAN4D.js";
7
7
 
8
8
  // src/config/model-availability.ts
9
9
  var DEFAULT_TTL_MS = 6e4;
@@ -150,4 +150,4 @@ export {
150
150
  resetAvailabilityCache,
151
151
  filterAvailableModels
152
152
  };
153
- //# sourceMappingURL=chunk-RU336IEH.js.map
153
+ //# sourceMappingURL=chunk-3XMAIPFB.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-HT3B6ZWV.js";
4
+ } from "./chunk-URIRSUQQ.js";
5
5
  import {
6
6
  resolveToken
7
- } from "./chunk-Q6EGZKLE.js";
7
+ } from "./chunk-W75MNLLK.js";
8
8
  import {
9
9
  err,
10
10
  ok
11
- } from "./chunk-E7LG7L4O.js";
11
+ } from "./chunk-7NOWAN4D.js";
12
12
 
13
13
  // src/scm/factory.ts
14
14
  async function createScmProvider(config) {
@@ -41,4 +41,4 @@ export {
41
41
  createScmProvider,
42
42
  createGitHubProvider
43
43
  };
44
- //# sourceMappingURL=chunk-5NVU25BA.js.map
44
+ //# sourceMappingURL=chunk-3Y44T42S.js.map
@@ -5,24 +5,24 @@ import {
5
5
  planOptionalParams,
6
6
  requireApiKey,
7
7
  validateApiKeyPresence
8
- } from "./chunk-I6NTUVGW.js";
8
+ } from "./chunk-4KRO6NTX.js";
9
9
  import {
10
10
  CUSTOM_API_BASE_URL_ENV,
11
11
  CUSTOM_API_DEFAULT_MODEL,
12
12
  PROVIDER_ENV_KEYS,
13
13
  assertCustomApiHostResolvesPublic,
14
14
  validateCustomApiBaseUrl
15
- } from "./chunk-SHFCJJTY.js";
15
+ } from "./chunk-6DJ7WISU.js";
16
16
  import {
17
17
  CliCircuitBreaker,
18
18
  DEFAULT_CIRCUIT_BREAKER_CONFIG
19
- } from "./chunk-3QIXGEY7.js";
19
+ } from "./chunk-WZJK5ZK3.js";
20
20
  import {
21
21
  getAvailabilityCache
22
- } from "./chunk-RU336IEH.js";
22
+ } from "./chunk-3XMAIPFB.js";
23
23
  import {
24
24
  generateHyphenId
25
- } from "./chunk-WRISLYLK.js";
25
+ } from "./chunk-INQLVBAM.js";
26
26
  import {
27
27
  CLI_SUBPROCESS_TIMEOUTS,
28
28
  CLI_TIMEOUTS,
@@ -58,7 +58,7 @@ import {
58
58
  loadModelsDevSnapshot,
59
59
  ok,
60
60
  resolveCliAlias
61
- } from "./chunk-E7LG7L4O.js";
61
+ } from "./chunk-7NOWAN4D.js";
62
62
 
63
63
  // src/cli-adapters/cli-to-model-adapter.ts
64
64
  var CliToModelAdapter = class {
@@ -4867,4 +4867,4 @@ export {
4867
4867
  SdkAdapter,
4868
4868
  createAutoAdapter
4869
4869
  };
4870
- //# sourceMappingURL=chunk-QD653D5O.js.map
4870
+ //# sourceMappingURL=chunk-4JKJEEMP.js.map
@@ -11,7 +11,7 @@ import {
11
11
  isRateLimitLikeError,
12
12
  lookupInTreeCapability,
13
13
  ok
14
- } from "./chunk-E7LG7L4O.js";
14
+ } from "./chunk-7NOWAN4D.js";
15
15
 
16
16
  // src/config/model-parameter-support.ts
17
17
  function parseClaudeMajorMinor(bareId) {
@@ -828,4 +828,4 @@ export {
828
828
  DEFAULT_COLLECT_STREAM_MAX_CHUNKS,
829
829
  collectStream
830
830
  };
831
- //# sourceMappingURL=chunk-I6NTUVGW.js.map
831
+ //# sourceMappingURL=chunk-4KRO6NTX.js.map
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  resolveCliSlot
3
- } from "./chunk-RU336IEH.js";
3
+ } from "./chunk-3XMAIPFB.js";
4
4
  import {
5
5
  createLogger,
6
6
  getTimeProvider,
7
7
  isRateLimitText
8
- } from "./chunk-E7LG7L4O.js";
8
+ } from "./chunk-7NOWAN4D.js";
9
9
 
10
10
  // src/pipeline/expert-bridge.ts
11
11
  function resolveCliFromModelString(model) {
@@ -21,7 +21,7 @@ async function getMcpConfigPath() {
21
21
  if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;
22
22
  mcpConfigInitPromise ??= (async () => {
23
23
  try {
24
- const { generateMcpConfig } = await import("./child-mcp-config-XEXFG3LA.js");
24
+ const { generateMcpConfig } = await import("./child-mcp-config-JHX6JCF5.js");
25
25
  const config = await generateMcpConfig();
26
26
  cachedMcpConfigPath = config.configPath;
27
27
  cachedMcpConfigCleanup = config.cleanup;
@@ -93,8 +93,8 @@ var routerInitPromise = null;
93
93
  async function getRouter() {
94
94
  if (cachedRouter !== null) return cachedRouter;
95
95
  routerInitPromise ??= (async () => {
96
- const { createAllAdapters } = await import("./factory-6JIXPGRH.js");
97
- const { createCompositeRouter } = await import("./composite-router-MFJNLR3O.js");
96
+ const { createAllAdapters } = await import("./factory-Q4FUNYFK.js");
97
+ const { createCompositeRouter } = await import("./composite-router-XNE5Q3YF.js");
98
98
  const adapters = createAllAdapters();
99
99
  if (adapters.size === 0) {
100
100
  routerInitPromise = null;
@@ -102,7 +102,7 @@ async function getRouter() {
102
102
  }
103
103
  cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));
104
104
  try {
105
- const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-SAHRY3BI.js");
105
+ const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-3MA2YHO4.js");
106
106
  cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
107
107
  } catch (error) {
108
108
  const msg = error instanceof Error ? error.message : String(error);
@@ -213,4 +213,4 @@ export {
213
213
  tokenSplitFromUsage,
214
214
  executeExpert
215
215
  };
216
- //# sourceMappingURL=chunk-ICYEG7T4.js.map
216
+ //# sourceMappingURL=chunk-4TLU7JJA.js.map
@@ -15,7 +15,7 @@ import {
15
15
  createLogger,
16
16
  err,
17
17
  ok
18
- } from "./chunk-E7LG7L4O.js";
18
+ } from "./chunk-7NOWAN4D.js";
19
19
 
20
20
  // src/adapters/sdk/types.ts
21
21
  var PROVIDER_ENV_KEYS = {
@@ -184,10 +184,10 @@ var DEFAULTS = {
184
184
  TIMEOUT_DEFAULTS: {
185
185
  /** CLI tool execution timeout in milliseconds. */
186
186
  cliMs: CLI_TIMEOUTS.default.standard,
187
- /** Simple CLI task timeout (single function, quick query). */
188
- cliSimpleMs: CLI_TIMEOUTS.default.simple,
189
- /** Complex CLI task timeout (codebase-wide, deep analysis). */
190
- cliComplexMs: CLI_TIMEOUTS.default.complex,
187
+ // cliSimpleMs / cliComplexMs removed in #4180 never read by any production
188
+ // code (the matching NEXUS_TIMEOUT_CLISIMPLE/CLICOMPLEX env vars were silent
189
+ // no-ops, #2977 class). Per-complexity CLI timeouts come from
190
+ // getTimeoutForCli/TIMEOUT_PROFILES (CLI_TIMEOUTS in config/timeouts.ts).
191
191
  /** API request timeout in milliseconds. */
192
192
  apiMs: API_TIMEOUTS.defaultMs,
193
193
  /** Maximum API timeout in milliseconds. */
@@ -396,4 +396,4 @@ export {
396
396
  CUSTOM_API_DEFAULT_MODEL,
397
397
  DEFAULTS
398
398
  };
399
- //# sourceMappingURL=chunk-SHFCJJTY.js.map
399
+ //# sourceMappingURL=chunk-6DJ7WISU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/sdk/types.ts","../src/adapters/sdk/custom-api-validation.ts","../src/config/defaults.ts"],"sourcesContent":["/**\n * nexus-agents/adapters/sdk - Shared Types\n *\n * Type definitions for AI SDK adapter layer.\n *\n * @module adapters/sdk/types\n * (Source: Issue #1123 — AI SDK provider layer)\n */\n\n/**\n * Supported AI SDK provider identifiers.\n *\n * `custom-openai` is for OpenAI-compatible gateways (multi-vendor proxies,\n * self-hosted LLM servers, corporate model gateways) — uses the same\n * @ai-sdk/openai package but with a configurable `baseURL`.\n */\nexport type SdkProviderId = 'anthropic' | 'openai' | 'google' | 'custom-openai';\n\n/**\n * Configuration for creating an AI SDK adapter.\n */\nexport interface SdkAdapterConfig {\n /** Provider identifier */\n providerId: SdkProviderId;\n /** Model to use (e.g., 'claude-sonnet-4-6', 'gpt-4o') */\n modelId: string;\n /** API key (falls back to environment variable) */\n apiKey?: string;\n /**\n * Base URL for OpenAI-compatible gateways. Required when\n * `providerId === 'custom-openai'`, ignored otherwise. Falls back to\n * the `NEXUS_CUSTOM_API_BASE_URL` environment variable.\n */\n baseUrl?: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Maximum retries on transient failures */\n maxRetries?: number;\n}\n\n/**\n * Maps provider IDs to their environment variable names.\n */\nexport const PROVIDER_ENV_KEYS: Record<SdkProviderId, string> = {\n anthropic: 'ANTHROPIC_API_KEY',\n openai: 'OPENAI_API_KEY',\n google: 'GOOGLE_AI_API_KEY',\n 'custom-openai': 'NEXUS_CUSTOM_API_KEY',\n};\n\n/**\n * Environment variable name for the custom gateway base URL.\n * Keep in sync with `SdkAdapterConfig.baseUrl`.\n */\nexport const CUSTOM_API_BASE_URL_ENV = 'NEXUS_CUSTOM_API_BASE_URL';\n\n/**\n * Escape hatch: set to `1`/`true` to allow the custom gateway base URL to\n * resolve to a loopback or RFC 1918 private address. Default is DENY —\n * SSRF defense. Only disable this when you know the gateway runs on a\n * trusted internal host and you accept the risk.\n */\nexport const CUSTOM_API_ALLOW_PRIVATE_ENV = 'NEXUS_CUSTOM_API_ALLOW_PRIVATE';\n","/**\n * Validation for the `custom-openai` SDK adapter's gateway URL.\n *\n * The base URL is user-provided, so without validation the adapter becomes\n * an SSRF vector: a malicious prompt that reshaped env vars, or a typo in\n * the config, could point nexus-agents at `http://169.254.169.254/` (AWS\n * metadata) or `http://localhost:5432/` (internal services). This module\n * rejects such URLs unless the user explicitly opts in via\n * `NEXUS_CUSTOM_API_ALLOW_PRIVATE=1`.\n *\n * Called out in the #2119 consensus vote by the Security Engineer role.\n *\n * @module adapters/sdk/custom-api-validation\n */\n\nimport { isIPv4, isIPv6 } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\nimport { ConfigError, ok, err, createLogger, type Result } from '../../core/index.js';\nimport { CUSTOM_API_ALLOW_PRIVATE_ENV } from './types.js';\n\nconst logger = createLogger({ module: 'custom-api-validation' });\n\n/**\n * Why a given URL was rejected. Machine-readable so error messages can\n * distinguish root causes in downstream tooling.\n */\nexport type BaseUrlRejectionReason =\n | 'empty'\n | 'not_a_url'\n | 'not_http_https'\n | 'loopback'\n | 'link_local'\n | 'private_range'\n | 'reserved';\n\ninterface RejectionDetail {\n readonly reason: BaseUrlRejectionReason;\n readonly message: string;\n}\n\n/**\n * Validates a user-provided custom-gateway base URL. Returns the URL as an\n * `ok` Result if it passes, or a `ConfigError` with a machine-readable\n * reason if it fails.\n *\n * Pass `{ allowPrivate: true }` (or set the env var) to bypass the SSRF\n * checks — use this only when the gateway is on a trusted internal host\n * and you accept the risk.\n */\nexport function validateCustomApiBaseUrl(\n raw: string | undefined,\n opts: { readonly allowPrivate?: boolean } = {}\n): Result<URL, ConfigError> {\n if (raw === undefined || raw.trim() === '') {\n return err(\n new ConfigError(\n 'Custom API base URL is required but missing. Set NEXUS_CUSTOM_API_BASE_URL or pass `baseUrl` in config.'\n )\n );\n }\n\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return err(new ConfigError(`Custom API base URL is not a valid URL: ${raw}`));\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n return err(\n new ConfigError(`Custom API base URL must use http or https, got \"${url.protocol}\" in ${raw}`)\n );\n }\n\n const allowPrivate = opts.allowPrivate === true || resolveAllowPrivateFromEnv();\n if (!allowPrivate) {\n const rejection = classifyPrivateHost(url.hostname);\n if (rejection !== null) {\n return err(\n new ConfigError(\n `Custom API base URL rejected (SSRF guard, reason=\"${rejection.reason}\"): ${rejection.message}. ` +\n `Set ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 to bypass if the gateway runs on a trusted internal host.`\n )\n );\n }\n }\n\n return ok(url);\n}\n\nfunction resolveAllowPrivateFromEnv(): boolean {\n // Deliberately strict (case-sensitive, not parseBoolEnv): this disables an\n // SSRF guard, so we don't want extra case variants (e.g. `TRUE`) to loosen\n // the control. Fail-closed on anything but exact `1`/`true` (#3297).\n const v = process.env[CUSTOM_API_ALLOW_PRIVATE_ENV];\n return v === '1' || v === 'true';\n}\n\n/**\n * Returns a rejection reason if the hostname resolves (by string form) to\n * a loopback, link-local, or RFC 1918 private address; `null` otherwise.\n *\n * Note: this is a string-level check. It does NOT perform DNS resolution,\n * so a public DNS name that secretly resolves to a private IP will pass.\n * For that level of defense, callers should additionally run\n * {@link assertCustomApiHostResolvesPublic}, which performs a DNS lookup\n * and classifies each resolved address with the same range tables below.\n */\nfunction classifyPrivateHost(hostname: string): RejectionDetail | null {\n const normalized = normalizeHost(hostname);\n\n // Literal IP addresses — classify directly against the range tables.\n const literal = classifyIpAddress(normalized);\n if (literal !== 'not_an_ip') {\n return literal;\n }\n\n // Hostname literals that resolve to loopback without needing DNS\n if (\n normalized === 'localhost' ||\n normalized.endsWith('.localhost') ||\n normalized.endsWith('.local') // mDNS\n ) {\n return {\n reason: 'loopback',\n message: `hostname \"${hostname}\" resolves to loopback/mDNS`,\n };\n }\n\n return null;\n}\n\n/**\n * Strips IPv6 bracket wrapping (URL.hostname yields \"[::1]\") and lowercases,\n * giving the bare form the `node:net` checks expect. Shared by the sync and\n * async guards so the normalization rule lives in one place.\n */\nfunction normalizeHost(hostname: string): string {\n const stripped =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n return stripped.toLowerCase();\n}\n\n/**\n * Classifies a single (already normalized, bracket-stripped) address string.\n * Returns:\n * - a {@link RejectionDetail} if it is a private/loopback/link-local/reserved IP,\n * - `null` if it is a public IP literal (safe),\n * - the sentinel `'not_an_ip'` if the string is not an IP literal at all.\n *\n * This is the shared per-address classifier reused by both the sync\n * string-level guard ({@link classifyPrivateHost}) and the async\n * DNS-resolve-time guard ({@link assertCustomApiHostResolvesPublic}), so the\n * IPv4/IPv6 range tables live in exactly one place.\n */\nfunction classifyIpAddress(normalized: string): RejectionDetail | null | 'not_an_ip' {\n if (isIPv4(normalized)) {\n return classifyIPv4(normalized);\n }\n if (isIPv6(normalized)) {\n return classifyIPv6(normalized);\n }\n return 'not_an_ip';\n}\n\n/**\n * DNS-resolve-time SSRF guard for the custom-openai gateway.\n *\n * The sync {@link validateCustomApiBaseUrl} only inspects the hostname as a\n * string, so a PUBLIC DNS name that resolves to a PRIVATE/loopback/link-local\n * IP (e.g. an attacker-controlled `gateway.evil.test` pointing at\n * `169.254.169.254`) slips past it. This function closes that gap: it resolves\n * the hostname and runs the EXISTING IP classification against every returned\n * address, failing closed if ANY of them is private.\n *\n * Behaviour:\n * - `allowPrivate` (opt or env) → bypass, returns `ok` (matches the sync guard).\n * - hostname is already an IP literal → no DNS needed; the sync guard already\n * classified literals at construction, so return `ok`.\n * - otherwise `dns.lookup(hostname, { all: true })` and classify each address.\n * If ANY resolves private → `err(ConfigError)`.\n * - on a `dns.lookup` THROW (transient/NXDOMAIN/network error) → log debug and\n * return `ok`. Failing closed here is too aggressive: it would break legit\n * gateways on a flaky resolver, and this is additive defense-in-depth layered\n * on top of the sync string guard that already ran at construction. We only\n * REJECT on a SUCCESSFUL resolution to a private address.\n *\n * Residual risk (TOCTOU): this is RESOLVE-time, not socket-connect-time. A name\n * that passes here could rebind to a private IP before the actual connect\n * (DNS rebinding). A full fix needs a custom `fetch` `lookup` hook validating\n * the peer address at the socket layer — out of scope for this LOW\n * defense-in-depth pass (#3426).\n */\nexport async function assertCustomApiHostResolvesPublic(\n hostname: string,\n opts: { readonly allowPrivate?: boolean } = {}\n): Promise<Result<void, ConfigError>> {\n const allowPrivate = opts.allowPrivate === true || resolveAllowPrivateFromEnv();\n if (allowPrivate) {\n return ok(undefined);\n }\n\n const normalized = normalizeHost(hostname);\n\n // IP literals are already handled by the sync guard at construction; no DNS.\n if (isIPv4(normalized) || isIPv6(normalized)) {\n return ok(undefined);\n }\n\n // Only `address` is read; the resolver's `family` is intentionally NOT\n // trusted — `classifyIpAddress` re-derives v4/v6 from the address string, so\n // a mislabeled family in the lookup result cannot let a private IP slip past.\n let addresses: ReadonlyArray<{ readonly address: string }>;\n try {\n addresses = await dnsLookup(hostname, { all: true });\n } catch (error) {\n // Fail OPEN: transient/NXDOMAIN/network errors must not break legit\n // gateways. The sync string guard already ran; this is additive only.\n logger.debug('custom-api SSRF resolve check: DNS lookup failed, skipping (fail-open)', {\n hostname,\n error: error instanceof Error ? error.message : String(error),\n });\n return ok(undefined);\n }\n\n const rejection = firstPrivateAddress(addresses);\n if (rejection !== null) {\n return err(\n new ConfigError(\n `Custom API base URL rejected (SSRF resolve guard, reason=\"${rejection.reason}\"): ` +\n `hostname \"${hostname}\" resolved to ${rejection.message}. ` +\n `Set ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 to bypass if the gateway runs on a trusted internal host.`\n )\n );\n }\n\n return ok(undefined);\n}\n\n/**\n * Returns the {@link RejectionDetail} for the first resolved address that\n * classifies as private/loopback/link-local/reserved, or `null` if every\n * address is public. Fail-closed: any single private hit trips the guard.\n */\nfunction firstPrivateAddress(\n addresses: ReadonlyArray<{ readonly address: string }>\n): RejectionDetail | null {\n for (const { address } of addresses) {\n const rejection = classifyIpAddress(address.toLowerCase());\n if (rejection !== null && rejection !== 'not_an_ip') {\n return rejection;\n }\n }\n return null;\n}\n\n/** IPv4 ranges the SSRF guard rejects, in order of specificity. */\nconst IPV4_RULES: ReadonlyArray<{\n readonly match: (a: number, b: number) => boolean;\n readonly reason: BaseUrlRejectionReason;\n readonly label: string;\n}> = [\n { match: (a) => a === 127, reason: 'loopback', label: 'IPv4 loopback' },\n { match: (a) => a === 10, reason: 'private_range', label: 'IPv4 private (10/8)' },\n {\n match: (a, b) => a === 172 && b >= 16 && b <= 31,\n reason: 'private_range',\n label: 'IPv4 private (172.16/12)',\n },\n {\n match: (a, b) => a === 192 && b === 168,\n reason: 'private_range',\n label: 'IPv4 private (192.168/16)',\n },\n {\n match: (a, b) => a === 169 && b === 254,\n reason: 'link_local',\n label: 'IPv4 link-local (169.254/16 — AWS IMDS)',\n },\n { match: (a) => a === 0, reason: 'reserved', label: 'IPv4 reserved (0/8)' },\n];\n\nfunction classifyIPv4(ip: string): RejectionDetail | null {\n const parts = ip.split('.').map((p) => Number.parseInt(p, 10));\n if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) return null;\n const [a, b] = parts as [number, number, number, number];\n for (const rule of IPV4_RULES) {\n if (rule.match(a, b)) {\n return { reason: rule.reason, message: `${rule.label} (${ip})` };\n }\n }\n return null;\n}\n\nfunction classifyIPv6(ip: string): RejectionDetail | null {\n const lower = ip.toLowerCase();\n if (lower === '::1') return { reason: 'loopback', message: `IPv6 loopback (${ip})` };\n if (lower.startsWith('fe80:'))\n return { reason: 'link_local', message: `IPv6 link-local (${ip})` };\n // Unique-local: fc00::/7 → first byte has high bit set and second-high bit set\n if (/^fc|^fd/.test(lower)) {\n return { reason: 'private_range', message: `IPv6 unique-local (${ip}, fc00::/7)` };\n }\n return null;\n}\n","/**\n * Central Configuration Defaults\n *\n * Consolidates common default values used across the codebase.\n * This prevents scattered magic numbers and ensures consistency.\n *\n * Usage:\n * import { DEFAULTS, getTimeout, TIMEOUT_PROFILES } from '../config/defaults.js';\n * const timeout = options.timeout ?? DEFAULTS.TIMEOUT_DEFAULTS.cliMs;\n * const cliTimeout = getTimeoutForCli('claude', 'complex');\n *\n * Environment overrides can be added via NEXUS_* environment variables.\n *\n * @module config/defaults\n * (Source: Central config consolidation initiative)\n */\n\n// Re-export types from defaults-types\nexport type {\n TaskComplexity,\n TimeoutProfile,\n KnownCliName,\n TimeoutDefaults,\n RateLimitDefaults,\n ToolRateLimitConfig,\n RetryDefaults,\n CircuitBreakerDefaults,\n} from './defaults-types.js';\n\nexport { isTaskComplexity, isKnownCliName } from './defaults-types.js';\n\n// Re-export timeout profiles (delegates to config/timeouts.ts)\nexport {\n TIMEOUT_PROFILES,\n getTimeoutProfile,\n getTimeoutForCli,\n} from './defaults-timeout-profiles.js';\n\n// Re-export canonical timeout modules (Issue #984)\nexport {\n CLI_TIMEOUTS,\n VOTE_TIMEOUTS,\n MCP_TIMEOUTS,\n WORKFLOW_TIMEOUTS,\n GRAPH_TIMEOUTS,\n PER_CLI_TASK_TIMEOUTS,\n API_TIMEOUTS,\n INTERNAL_TIMEOUTS,\n TEST_TIMEOUTS,\n TIMEOUT_ENV_VARS,\n getCliTimeoutProfile,\n getCliTimeout,\n resolveVoteTimeout,\n resolveEnvTimeout,\n validateTimeout,\n BACKOFF_CONFIG,\n AGENT_ROUTER_TIMEOUTS,\n CODEX_MCP_TIMEOUTS,\n} from './timeouts.js';\n\n// Re-export env helpers (internal use)\nexport { parseIntEnv, parseFloatEnv, parseBoolEnv } from './defaults-env.js';\n\nimport {\n createGetTimeout,\n createGetRetryConfig,\n createGetRateLimitConfig,\n createGetCircuitBreakerConfig,\n createGetToolRateLimit,\n createGetEnvVarDocumentation,\n} from './defaults-env.js';\nimport {\n API_TIMEOUTS as _API,\n WORKFLOW_TIMEOUTS as _WF,\n MCP_TIMEOUTS as _MCP,\n INTERNAL_TIMEOUTS as _INT,\n TEST_TIMEOUTS as _TEST,\n CLI_TIMEOUTS as _CLI,\n} from './timeouts.js';\n\n// ============================================================================\n// Default Model IDs (#2200 Child 4)\n// ============================================================================\n\n/**\n * Default model identifier for the custom OpenAI-compatible API gateway.\n *\n * Used by both `cli/setup-custom-api.ts` (write to nexus-agents.yaml) and\n * `adapters/auto-adapter.ts` (NEXUS_CUSTOM_MODEL env-var fallback). Single\n * source of truth so changes flow through all consumers.\n *\n * `gpt-4o` is widely supported across OpenAI-compatible gateways (vLLM,\n * LiteLLM, Together AI, etc.) — a pragmatic baseline rather than the\n * cheapest or most capable. Operators are expected to override.\n */\nexport const CUSTOM_API_DEFAULT_MODEL = 'gpt-4o';\n\n// ============================================================================\n// Central Defaults Object\n// ============================================================================\n\n/**\n * Central defaults object containing all configuration categories.\n */\nexport const DEFAULTS = {\n /**\n * Default timeout settings in milliseconds.\n * Values sourced from config/timeouts.ts (Issue #984).\n */\n TIMEOUT_DEFAULTS: {\n /** CLI tool execution timeout in milliseconds. */\n cliMs: _CLI.default.standard,\n /** Simple CLI task timeout (single function, quick query). */\n cliSimpleMs: _CLI.default.simple,\n /** Complex CLI task timeout (codebase-wide, deep analysis). */\n cliComplexMs: _CLI.default.complex,\n /** API request timeout in milliseconds. */\n apiMs: _API.defaultMs,\n /** Maximum API timeout in milliseconds. */\n apiMaxMs: _API.maxMs,\n /** Workflow-level timeout in milliseconds (5 minutes). */\n workflowMs: _WF.workflowMs,\n /** Maximum workflow timeout in milliseconds (30 minutes). */\n workflowMaxMs: _WF.workflowMaxMs,\n /** Step-level timeout in milliseconds. */\n stepMs: _INT.selfEvalMs,\n /** MCP operation default timeout in milliseconds (generic, not per-tool). */\n mcpMs: _API.defaultMs,\n /** MCP operation maximum timeout in milliseconds. */\n mcpMaxMs: _MCP.maxMs,\n /** Health check timeout in milliseconds. */\n healthCheckMs: _INT.healthCheckMs,\n /** Global test run timeout in milliseconds (10 minutes). */\n testGlobalMs: _TEST.globalMs,\n /** Per-task test timeout in milliseconds. */\n testTaskMs: _TEST.taskMs,\n /** Circuit breaker reset timeout in milliseconds. */\n circuitBreakerResetMs: _INT.circuitBreakerResetMs,\n },\n\n /**\n * Default rate limit settings for outbound operations.\n */\n RATE_LIMIT_DEFAULTS: {\n /** Global requests per minute. */\n requestsPerMinute: 60,\n /** Whether rate limiting is enabled by default. */\n enabled: true,\n /** Maximum number of concurrent requests. */\n maxConcurrent: 4,\n /** Token bucket capacity. */\n capacity: 100,\n /** Token bucket refill rate per second. */\n refillRate: 10,\n /** Refill interval in milliseconds. */\n refillIntervalMs: 100,\n },\n\n /**\n * Per-tool rate limit defaults for MCP tools.\n * (Source: Issue #274 Phase 2 - per-tool rate limits)\n */\n TOOL_RATE_LIMITS: {\n orchestrate: { capacity: 10, refillRate: 10, refillIntervalMs: 60_000 },\n delegate: { capacity: 20, refillRate: 20, refillIntervalMs: 60_000 },\n workflow: { capacity: 5, refillRate: 5, refillIntervalMs: 60_000 },\n expert: { capacity: 30, refillRate: 30, refillIntervalMs: 60_000 },\n },\n\n /**\n * Default retry strategy settings for transient failures.\n */\n RETRY_DEFAULTS: {\n /** Maximum retry attempts before failing. */\n maxRetries: 3,\n /** Base delay between retries in milliseconds. */\n baseDelayMs: 1_000,\n /** Maximum delay between retries in milliseconds. */\n maxDelayMs: 30_000,\n /** Jitter factor (0-1) to randomize retry delays. */\n jitterFactor: 0.1,\n },\n\n /**\n * Workflow-specific retry defaults.\n */\n WORKFLOW_RETRY_DEFAULTS: {\n /** Maximum retry attempts for workflow steps. */\n maxRetries: 2,\n /** Base delay for workflow retries in milliseconds. */\n baseDelayMs: 2_000,\n /** Maximum delay for workflow retries in milliseconds. */\n maxDelayMs: 60_000,\n /** Jitter factor for workflow retries. */\n jitterFactor: 0.15,\n },\n\n /**\n * CLI-specific retry defaults.\n */\n CLI_RETRY_DEFAULTS: {\n /** Maximum retry attempts for CLI operations. */\n maxRetries: 2,\n /** Base delay for CLI retries in milliseconds. */\n baseDelayMs: 5_000,\n /** Maximum delay for CLI retries in milliseconds. */\n maxDelayMs: 60_000,\n /** Jitter factor for CLI retries. */\n jitterFactor: 0.2,\n },\n\n /**\n * Test framework retry defaults.\n */\n TEST_RETRY_DEFAULTS: {\n /** Maximum retries per test task. */\n maxRetries: 2,\n /** Whether to retry failed tasks by default. */\n retryFailedTasks: true,\n },\n\n /**\n * Default buffer sizing for batching and chunked processing.\n */\n BUFFER_DEFAULTS: {\n /** Preferred batch size for bulk operations. */\n batchSize: 100,\n /** Chunk size for streaming or segmented processing. */\n chunkSize: 256,\n /** Maximum items allowed in a buffer. */\n maxItems: 1_000,\n /** Maximum memory size in bytes (10 MB). */\n maxMemoryBytes: 10 * 1024 * 1024,\n /** Log buffer flush interval in milliseconds. */\n logFlushIntervalMs: 5_000,\n },\n\n // WORKER_DEFAULTS removed in #2977 — the eight settings under this category\n // (maxWorkers, poolSize, idleTimeoutMs, workflowMaxParallel, testParallelism,\n // evaluationMaxWorkers, eventBusMaxHistory, swarmObserverMaxEvents) had zero\n // production consumers. `getWorkerConfig()` was never called from anywhere\n // in src/, and the matching NEXUS_WORKERS_* env vars were silent no-ops.\n // Silent config rot is worse than missing knobs; re-add when a concrete\n // consumer exists.\n\n /**\n * Default circuit breaker settings.\n * (Source: Issue #81 - Circuit breaker for CLI failures)\n */\n CIRCUIT_BREAKER_DEFAULTS: {\n /** Failure threshold to open circuit. */\n failureThreshold: 5,\n /** Reset timeout in milliseconds. */\n resetTimeoutMs: 30_000,\n /** Success threshold to close circuit in half-open state. */\n halfOpenSuccessThreshold: 2,\n /** Whether to count timeouts as failures. */\n countTimeoutsAsFailures: true,\n /** Whether to count auth failures as failures. */\n countAuthFailuresAsFailures: false,\n /** Whether to count rate limit errors as failures (#1529). */\n countRateLimitsAsFailures: true,\n /** Maximum requests allowed in half-open state. */\n halfOpenMaxRequests: 3,\n },\n\n /**\n * Default context/memory settings.\n */\n CONTEXT_DEFAULTS: {\n /** Maximum context tokens. */\n maxTokens: 100_000,\n /** Token budget warning threshold (80%). */\n warningThreshold: 0.8,\n /** Token budget critical threshold (95%). */\n criticalThreshold: 0.95,\n /** Maximum history entries to retain. */\n maxHistoryEntries: 1_000,\n },\n\n /**\n * Default provider/model settings.\n */\n PROVIDER_DEFAULTS: {\n /** Default timeout for provider API calls in ms. */\n timeout: 30_000,\n /** Maximum retries for provider requests. */\n maxRetries: 3,\n /** Default model tier. */\n defaultTier: 'balanced' as const,\n /** Default temperature. */\n temperatureDefault: 0.3,\n /** Minimum temperature. */\n temperatureMin: 0,\n /** Maximum temperature. */\n temperatureMax: 1,\n /** Billing mode: 'plan' (monthly subscription) or 'api' (pay-per-token). Env: NEXUS_BILLING_MODE */\n billingMode: 'plan' as const,\n },\n\n /**\n * Security-related defaults.\n */\n SECURITY_DEFAULTS: {\n /** Maximum system prompt length in characters. */\n maxSystemPromptLength: 4_000,\n /** Default policy execution mode. */\n policyDefaultMode: 'read-only' as const,\n /** Default policy mode. */\n policyMode: 'enforce' as const,\n /** Default sandbox mode. */\n sandboxMode: 'policy' as const,\n /** Whether to fall back to policy mode if container unavailable. */\n sandboxFallbackToPolicy: true,\n /** Whether network is enabled in container mode. */\n sandboxNetworkEnabled: false,\n },\n} as const;\n\n// ============================================================================\n// Type Exports for DEFAULTS\n// ============================================================================\n\n/** Type for the DEFAULTS object (readonly/const). */\nexport type DefaultsConfig = typeof DEFAULTS;\n\n/** Type for timeout defaults (readonly/const). */\nexport type TimeoutDefaultsConst = typeof DEFAULTS.TIMEOUT_DEFAULTS;\n\n/** Type for rate limit defaults (readonly/const). */\nexport type RateLimitDefaultsConst = typeof DEFAULTS.RATE_LIMIT_DEFAULTS;\n\n/** Type for retry defaults (readonly/const). */\nexport type RetryDefaultsConst = typeof DEFAULTS.RETRY_DEFAULTS;\n\n/** Type for buffer defaults (readonly/const). */\nexport type BufferDefaults = typeof DEFAULTS.BUFFER_DEFAULTS;\n\n/** Type for circuit breaker defaults (readonly/const). */\nexport type CircuitBreakerDefaultsConst = typeof DEFAULTS.CIRCUIT_BREAKER_DEFAULTS;\n\n/** Type for context defaults (readonly/const). */\nexport type ContextDefaults = typeof DEFAULTS.CONTEXT_DEFAULTS;\n\n/** Type for provider defaults (readonly/const). */\nexport type ProviderDefaults = typeof DEFAULTS.PROVIDER_DEFAULTS;\n\n/** Type for security defaults (readonly/const). */\nexport type SecurityDefaults = typeof DEFAULTS.SECURITY_DEFAULTS;\n\n// ============================================================================\n// Environment Override Functions (bound to DEFAULTS)\n// ============================================================================\n\n/**\n * Get timeout with environment override support.\n *\n * @param key - Timeout key (e.g., 'cliMs', 'apiMs')\n * @returns Timeout value in milliseconds\n */\nexport const getTimeout = createGetTimeout(DEFAULTS.TIMEOUT_DEFAULTS);\n\n/**\n * Get retry config with environment override support.\n *\n * @returns Retry configuration\n */\nexport const getRetryConfig = createGetRetryConfig(DEFAULTS.RETRY_DEFAULTS);\n\n/**\n * Get rate limit config with environment override support.\n *\n * @returns Rate limit configuration\n */\nexport const getRateLimitConfig = createGetRateLimitConfig(DEFAULTS.RATE_LIMIT_DEFAULTS);\n\n/**\n * Gets the circuit breaker configuration.\n *\n * @returns Circuit breaker configuration\n */\nexport const getCircuitBreakerConfig = createGetCircuitBreakerConfig(\n DEFAULTS.CIRCUIT_BREAKER_DEFAULTS\n);\n\n/**\n * Gets the tool rate limit configuration for a specific tool category.\n *\n * @param tool - Tool category (orchestrate, delegate, workflow, expert)\n * @returns Rate limit configuration\n */\nexport const getToolRateLimit = createGetToolRateLimit(DEFAULTS.TOOL_RATE_LIMITS);\n\n// ============================================================================\n// Documentation Helper\n// ============================================================================\n\n/**\n * Returns documentation for all environment variable overrides.\n *\n * @returns Markdown documentation string\n */\nexport const getEnvVarDocumentation = createGetEnvVarDocumentation(DEFAULTS);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/adapters/sdk/types.ts","../src/adapters/sdk/custom-api-validation.ts","../src/config/defaults.ts"],"sourcesContent":["/**\n * nexus-agents/adapters/sdk - Shared Types\n *\n * Type definitions for AI SDK adapter layer.\n *\n * @module adapters/sdk/types\n * (Source: Issue #1123 — AI SDK provider layer)\n */\n\n/**\n * Supported AI SDK provider identifiers.\n *\n * `custom-openai` is for OpenAI-compatible gateways (multi-vendor proxies,\n * self-hosted LLM servers, corporate model gateways) — uses the same\n * @ai-sdk/openai package but with a configurable `baseURL`.\n */\nexport type SdkProviderId = 'anthropic' | 'openai' | 'google' | 'custom-openai';\n\n/**\n * Configuration for creating an AI SDK adapter.\n */\nexport interface SdkAdapterConfig {\n /** Provider identifier */\n providerId: SdkProviderId;\n /** Model to use (e.g., 'claude-sonnet-4-6', 'gpt-4o') */\n modelId: string;\n /** API key (falls back to environment variable) */\n apiKey?: string;\n /**\n * Base URL for OpenAI-compatible gateways. Required when\n * `providerId === 'custom-openai'`, ignored otherwise. Falls back to\n * the `NEXUS_CUSTOM_API_BASE_URL` environment variable.\n */\n baseUrl?: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Maximum retries on transient failures */\n maxRetries?: number;\n}\n\n/**\n * Maps provider IDs to their environment variable names.\n */\nexport const PROVIDER_ENV_KEYS: Record<SdkProviderId, string> = {\n anthropic: 'ANTHROPIC_API_KEY',\n openai: 'OPENAI_API_KEY',\n google: 'GOOGLE_AI_API_KEY',\n 'custom-openai': 'NEXUS_CUSTOM_API_KEY',\n};\n\n/**\n * Environment variable name for the custom gateway base URL.\n * Keep in sync with `SdkAdapterConfig.baseUrl`.\n */\nexport const CUSTOM_API_BASE_URL_ENV = 'NEXUS_CUSTOM_API_BASE_URL';\n\n/**\n * Escape hatch: set to `1`/`true` to allow the custom gateway base URL to\n * resolve to a loopback or RFC 1918 private address. Default is DENY —\n * SSRF defense. Only disable this when you know the gateway runs on a\n * trusted internal host and you accept the risk.\n */\nexport const CUSTOM_API_ALLOW_PRIVATE_ENV = 'NEXUS_CUSTOM_API_ALLOW_PRIVATE';\n","/**\n * Validation for the `custom-openai` SDK adapter's gateway URL.\n *\n * The base URL is user-provided, so without validation the adapter becomes\n * an SSRF vector: a malicious prompt that reshaped env vars, or a typo in\n * the config, could point nexus-agents at `http://169.254.169.254/` (AWS\n * metadata) or `http://localhost:5432/` (internal services). This module\n * rejects such URLs unless the user explicitly opts in via\n * `NEXUS_CUSTOM_API_ALLOW_PRIVATE=1`.\n *\n * Called out in the #2119 consensus vote by the Security Engineer role.\n *\n * @module adapters/sdk/custom-api-validation\n */\n\nimport { isIPv4, isIPv6 } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\nimport { ConfigError, ok, err, createLogger, type Result } from '../../core/index.js';\nimport { CUSTOM_API_ALLOW_PRIVATE_ENV } from './types.js';\n\nconst logger = createLogger({ module: 'custom-api-validation' });\n\n/**\n * Why a given URL was rejected. Machine-readable so error messages can\n * distinguish root causes in downstream tooling.\n */\nexport type BaseUrlRejectionReason =\n | 'empty'\n | 'not_a_url'\n | 'not_http_https'\n | 'loopback'\n | 'link_local'\n | 'private_range'\n | 'reserved';\n\ninterface RejectionDetail {\n readonly reason: BaseUrlRejectionReason;\n readonly message: string;\n}\n\n/**\n * Validates a user-provided custom-gateway base URL. Returns the URL as an\n * `ok` Result if it passes, or a `ConfigError` with a machine-readable\n * reason if it fails.\n *\n * Pass `{ allowPrivate: true }` (or set the env var) to bypass the SSRF\n * checks — use this only when the gateway is on a trusted internal host\n * and you accept the risk.\n */\nexport function validateCustomApiBaseUrl(\n raw: string | undefined,\n opts: { readonly allowPrivate?: boolean } = {}\n): Result<URL, ConfigError> {\n if (raw === undefined || raw.trim() === '') {\n return err(\n new ConfigError(\n 'Custom API base URL is required but missing. Set NEXUS_CUSTOM_API_BASE_URL or pass `baseUrl` in config.'\n )\n );\n }\n\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return err(new ConfigError(`Custom API base URL is not a valid URL: ${raw}`));\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n return err(\n new ConfigError(`Custom API base URL must use http or https, got \"${url.protocol}\" in ${raw}`)\n );\n }\n\n const allowPrivate = opts.allowPrivate === true || resolveAllowPrivateFromEnv();\n if (!allowPrivate) {\n const rejection = classifyPrivateHost(url.hostname);\n if (rejection !== null) {\n return err(\n new ConfigError(\n `Custom API base URL rejected (SSRF guard, reason=\"${rejection.reason}\"): ${rejection.message}. ` +\n `Set ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 to bypass if the gateway runs on a trusted internal host.`\n )\n );\n }\n }\n\n return ok(url);\n}\n\nfunction resolveAllowPrivateFromEnv(): boolean {\n // Deliberately strict (case-sensitive, not parseBoolEnv): this disables an\n // SSRF guard, so we don't want extra case variants (e.g. `TRUE`) to loosen\n // the control. Fail-closed on anything but exact `1`/`true` (#3297).\n const v = process.env[CUSTOM_API_ALLOW_PRIVATE_ENV];\n return v === '1' || v === 'true';\n}\n\n/**\n * Returns a rejection reason if the hostname resolves (by string form) to\n * a loopback, link-local, or RFC 1918 private address; `null` otherwise.\n *\n * Note: this is a string-level check. It does NOT perform DNS resolution,\n * so a public DNS name that secretly resolves to a private IP will pass.\n * For that level of defense, callers should additionally run\n * {@link assertCustomApiHostResolvesPublic}, which performs a DNS lookup\n * and classifies each resolved address with the same range tables below.\n */\nfunction classifyPrivateHost(hostname: string): RejectionDetail | null {\n const normalized = normalizeHost(hostname);\n\n // Literal IP addresses — classify directly against the range tables.\n const literal = classifyIpAddress(normalized);\n if (literal !== 'not_an_ip') {\n return literal;\n }\n\n // Hostname literals that resolve to loopback without needing DNS\n if (\n normalized === 'localhost' ||\n normalized.endsWith('.localhost') ||\n normalized.endsWith('.local') // mDNS\n ) {\n return {\n reason: 'loopback',\n message: `hostname \"${hostname}\" resolves to loopback/mDNS`,\n };\n }\n\n return null;\n}\n\n/**\n * Strips IPv6 bracket wrapping (URL.hostname yields \"[::1]\") and lowercases,\n * giving the bare form the `node:net` checks expect. Shared by the sync and\n * async guards so the normalization rule lives in one place.\n */\nfunction normalizeHost(hostname: string): string {\n const stripped =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n return stripped.toLowerCase();\n}\n\n/**\n * Classifies a single (already normalized, bracket-stripped) address string.\n * Returns:\n * - a {@link RejectionDetail} if it is a private/loopback/link-local/reserved IP,\n * - `null` if it is a public IP literal (safe),\n * - the sentinel `'not_an_ip'` if the string is not an IP literal at all.\n *\n * This is the shared per-address classifier reused by both the sync\n * string-level guard ({@link classifyPrivateHost}) and the async\n * DNS-resolve-time guard ({@link assertCustomApiHostResolvesPublic}), so the\n * IPv4/IPv6 range tables live in exactly one place.\n */\nfunction classifyIpAddress(normalized: string): RejectionDetail | null | 'not_an_ip' {\n if (isIPv4(normalized)) {\n return classifyIPv4(normalized);\n }\n if (isIPv6(normalized)) {\n return classifyIPv6(normalized);\n }\n return 'not_an_ip';\n}\n\n/**\n * DNS-resolve-time SSRF guard for the custom-openai gateway.\n *\n * The sync {@link validateCustomApiBaseUrl} only inspects the hostname as a\n * string, so a PUBLIC DNS name that resolves to a PRIVATE/loopback/link-local\n * IP (e.g. an attacker-controlled `gateway.evil.test` pointing at\n * `169.254.169.254`) slips past it. This function closes that gap: it resolves\n * the hostname and runs the EXISTING IP classification against every returned\n * address, failing closed if ANY of them is private.\n *\n * Behaviour:\n * - `allowPrivate` (opt or env) → bypass, returns `ok` (matches the sync guard).\n * - hostname is already an IP literal → no DNS needed; the sync guard already\n * classified literals at construction, so return `ok`.\n * - otherwise `dns.lookup(hostname, { all: true })` and classify each address.\n * If ANY resolves private → `err(ConfigError)`.\n * - on a `dns.lookup` THROW (transient/NXDOMAIN/network error) → log debug and\n * return `ok`. Failing closed here is too aggressive: it would break legit\n * gateways on a flaky resolver, and this is additive defense-in-depth layered\n * on top of the sync string guard that already ran at construction. We only\n * REJECT on a SUCCESSFUL resolution to a private address.\n *\n * Residual risk (TOCTOU): this is RESOLVE-time, not socket-connect-time. A name\n * that passes here could rebind to a private IP before the actual connect\n * (DNS rebinding). A full fix needs a custom `fetch` `lookup` hook validating\n * the peer address at the socket layer — out of scope for this LOW\n * defense-in-depth pass (#3426).\n */\nexport async function assertCustomApiHostResolvesPublic(\n hostname: string,\n opts: { readonly allowPrivate?: boolean } = {}\n): Promise<Result<void, ConfigError>> {\n const allowPrivate = opts.allowPrivate === true || resolveAllowPrivateFromEnv();\n if (allowPrivate) {\n return ok(undefined);\n }\n\n const normalized = normalizeHost(hostname);\n\n // IP literals are already handled by the sync guard at construction; no DNS.\n if (isIPv4(normalized) || isIPv6(normalized)) {\n return ok(undefined);\n }\n\n // Only `address` is read; the resolver's `family` is intentionally NOT\n // trusted — `classifyIpAddress` re-derives v4/v6 from the address string, so\n // a mislabeled family in the lookup result cannot let a private IP slip past.\n let addresses: ReadonlyArray<{ readonly address: string }>;\n try {\n addresses = await dnsLookup(hostname, { all: true });\n } catch (error) {\n // Fail OPEN: transient/NXDOMAIN/network errors must not break legit\n // gateways. The sync string guard already ran; this is additive only.\n logger.debug('custom-api SSRF resolve check: DNS lookup failed, skipping (fail-open)', {\n hostname,\n error: error instanceof Error ? error.message : String(error),\n });\n return ok(undefined);\n }\n\n const rejection = firstPrivateAddress(addresses);\n if (rejection !== null) {\n return err(\n new ConfigError(\n `Custom API base URL rejected (SSRF resolve guard, reason=\"${rejection.reason}\"): ` +\n `hostname \"${hostname}\" resolved to ${rejection.message}. ` +\n `Set ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 to bypass if the gateway runs on a trusted internal host.`\n )\n );\n }\n\n return ok(undefined);\n}\n\n/**\n * Returns the {@link RejectionDetail} for the first resolved address that\n * classifies as private/loopback/link-local/reserved, or `null` if every\n * address is public. Fail-closed: any single private hit trips the guard.\n */\nfunction firstPrivateAddress(\n addresses: ReadonlyArray<{ readonly address: string }>\n): RejectionDetail | null {\n for (const { address } of addresses) {\n const rejection = classifyIpAddress(address.toLowerCase());\n if (rejection !== null && rejection !== 'not_an_ip') {\n return rejection;\n }\n }\n return null;\n}\n\n/** IPv4 ranges the SSRF guard rejects, in order of specificity. */\nconst IPV4_RULES: ReadonlyArray<{\n readonly match: (a: number, b: number) => boolean;\n readonly reason: BaseUrlRejectionReason;\n readonly label: string;\n}> = [\n { match: (a) => a === 127, reason: 'loopback', label: 'IPv4 loopback' },\n { match: (a) => a === 10, reason: 'private_range', label: 'IPv4 private (10/8)' },\n {\n match: (a, b) => a === 172 && b >= 16 && b <= 31,\n reason: 'private_range',\n label: 'IPv4 private (172.16/12)',\n },\n {\n match: (a, b) => a === 192 && b === 168,\n reason: 'private_range',\n label: 'IPv4 private (192.168/16)',\n },\n {\n match: (a, b) => a === 169 && b === 254,\n reason: 'link_local',\n label: 'IPv4 link-local (169.254/16 — AWS IMDS)',\n },\n { match: (a) => a === 0, reason: 'reserved', label: 'IPv4 reserved (0/8)' },\n];\n\nfunction classifyIPv4(ip: string): RejectionDetail | null {\n const parts = ip.split('.').map((p) => Number.parseInt(p, 10));\n if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) return null;\n const [a, b] = parts as [number, number, number, number];\n for (const rule of IPV4_RULES) {\n if (rule.match(a, b)) {\n return { reason: rule.reason, message: `${rule.label} (${ip})` };\n }\n }\n return null;\n}\n\nfunction classifyIPv6(ip: string): RejectionDetail | null {\n const lower = ip.toLowerCase();\n if (lower === '::1') return { reason: 'loopback', message: `IPv6 loopback (${ip})` };\n if (lower.startsWith('fe80:'))\n return { reason: 'link_local', message: `IPv6 link-local (${ip})` };\n // Unique-local: fc00::/7 → first byte has high bit set and second-high bit set\n if (/^fc|^fd/.test(lower)) {\n return { reason: 'private_range', message: `IPv6 unique-local (${ip}, fc00::/7)` };\n }\n return null;\n}\n","/**\n * Central Configuration Defaults\n *\n * Consolidates common default values used across the codebase.\n * This prevents scattered magic numbers and ensures consistency.\n *\n * Usage:\n * import { DEFAULTS, getTimeout, TIMEOUT_PROFILES } from '../config/defaults.js';\n * const timeout = options.timeout ?? DEFAULTS.TIMEOUT_DEFAULTS.cliMs;\n * const cliTimeout = getTimeoutForCli('claude', 'complex');\n *\n * Environment overrides can be added via NEXUS_* environment variables.\n *\n * @module config/defaults\n * (Source: Central config consolidation initiative)\n */\n\n// Re-export types from defaults-types\nexport type {\n TaskComplexity,\n TimeoutProfile,\n KnownCliName,\n TimeoutDefaults,\n RateLimitDefaults,\n ToolRateLimitConfig,\n RetryDefaults,\n CircuitBreakerDefaults,\n} from './defaults-types.js';\n\nexport { isTaskComplexity, isKnownCliName } from './defaults-types.js';\n\n// Re-export timeout profiles (delegates to config/timeouts.ts)\nexport {\n TIMEOUT_PROFILES,\n getTimeoutProfile,\n getTimeoutForCli,\n} from './defaults-timeout-profiles.js';\n\n// Re-export canonical timeout modules (Issue #984)\nexport {\n CLI_TIMEOUTS,\n VOTE_TIMEOUTS,\n MCP_TIMEOUTS,\n WORKFLOW_TIMEOUTS,\n GRAPH_TIMEOUTS,\n PER_CLI_TASK_TIMEOUTS,\n API_TIMEOUTS,\n INTERNAL_TIMEOUTS,\n TEST_TIMEOUTS,\n TIMEOUT_ENV_VARS,\n getCliTimeoutProfile,\n getCliTimeout,\n resolveVoteTimeout,\n resolveEnvTimeout,\n validateTimeout,\n BACKOFF_CONFIG,\n AGENT_ROUTER_TIMEOUTS,\n CODEX_MCP_TIMEOUTS,\n} from './timeouts.js';\n\n// Re-export env helpers (internal use)\nexport { parseIntEnv, parseFloatEnv, parseBoolEnv } from './defaults-env.js';\n\nimport {\n createGetTimeout,\n createGetRetryConfig,\n createGetRateLimitConfig,\n createGetCircuitBreakerConfig,\n createGetToolRateLimit,\n createGetEnvVarDocumentation,\n} from './defaults-env.js';\nimport {\n API_TIMEOUTS as _API,\n WORKFLOW_TIMEOUTS as _WF,\n MCP_TIMEOUTS as _MCP,\n INTERNAL_TIMEOUTS as _INT,\n TEST_TIMEOUTS as _TEST,\n CLI_TIMEOUTS as _CLI,\n} from './timeouts.js';\n\n// ============================================================================\n// Default Model IDs (#2200 Child 4)\n// ============================================================================\n\n/**\n * Default model identifier for the custom OpenAI-compatible API gateway.\n *\n * Used by both `cli/setup-custom-api.ts` (write to nexus-agents.yaml) and\n * `adapters/auto-adapter.ts` (NEXUS_CUSTOM_MODEL env-var fallback). Single\n * source of truth so changes flow through all consumers.\n *\n * `gpt-4o` is widely supported across OpenAI-compatible gateways (vLLM,\n * LiteLLM, Together AI, etc.) — a pragmatic baseline rather than the\n * cheapest or most capable. Operators are expected to override.\n */\nexport const CUSTOM_API_DEFAULT_MODEL = 'gpt-4o';\n\n// ============================================================================\n// Central Defaults Object\n// ============================================================================\n\n/**\n * Central defaults object containing all configuration categories.\n */\nexport const DEFAULTS = {\n /**\n * Default timeout settings in milliseconds.\n * Values sourced from config/timeouts.ts (Issue #984).\n */\n TIMEOUT_DEFAULTS: {\n /** CLI tool execution timeout in milliseconds. */\n cliMs: _CLI.default.standard,\n // cliSimpleMs / cliComplexMs removed in #4180 — never read by any production\n // code (the matching NEXUS_TIMEOUT_CLISIMPLE/CLICOMPLEX env vars were silent\n // no-ops, #2977 class). Per-complexity CLI timeouts come from\n // getTimeoutForCli/TIMEOUT_PROFILES (CLI_TIMEOUTS in config/timeouts.ts).\n /** API request timeout in milliseconds. */\n apiMs: _API.defaultMs,\n /** Maximum API timeout in milliseconds. */\n apiMaxMs: _API.maxMs,\n /** Workflow-level timeout in milliseconds (5 minutes). */\n workflowMs: _WF.workflowMs,\n /** Maximum workflow timeout in milliseconds (30 minutes). */\n workflowMaxMs: _WF.workflowMaxMs,\n /** Step-level timeout in milliseconds. */\n stepMs: _INT.selfEvalMs,\n /** MCP operation default timeout in milliseconds (generic, not per-tool). */\n mcpMs: _API.defaultMs,\n /** MCP operation maximum timeout in milliseconds. */\n mcpMaxMs: _MCP.maxMs,\n /** Health check timeout in milliseconds. */\n healthCheckMs: _INT.healthCheckMs,\n /** Global test run timeout in milliseconds (10 minutes). */\n testGlobalMs: _TEST.globalMs,\n /** Per-task test timeout in milliseconds. */\n testTaskMs: _TEST.taskMs,\n /** Circuit breaker reset timeout in milliseconds. */\n circuitBreakerResetMs: _INT.circuitBreakerResetMs,\n },\n\n /**\n * Default rate limit settings for outbound operations.\n */\n RATE_LIMIT_DEFAULTS: {\n /** Global requests per minute. */\n requestsPerMinute: 60,\n /** Whether rate limiting is enabled by default. */\n enabled: true,\n /** Maximum number of concurrent requests. */\n maxConcurrent: 4,\n /** Token bucket capacity. */\n capacity: 100,\n /** Token bucket refill rate per second. */\n refillRate: 10,\n /** Refill interval in milliseconds. */\n refillIntervalMs: 100,\n },\n\n /**\n * Per-tool rate limit defaults for MCP tools.\n * (Source: Issue #274 Phase 2 - per-tool rate limits)\n */\n TOOL_RATE_LIMITS: {\n orchestrate: { capacity: 10, refillRate: 10, refillIntervalMs: 60_000 },\n delegate: { capacity: 20, refillRate: 20, refillIntervalMs: 60_000 },\n workflow: { capacity: 5, refillRate: 5, refillIntervalMs: 60_000 },\n expert: { capacity: 30, refillRate: 30, refillIntervalMs: 60_000 },\n },\n\n /**\n * Default retry strategy settings for transient failures.\n */\n RETRY_DEFAULTS: {\n /** Maximum retry attempts before failing. */\n maxRetries: 3,\n /** Base delay between retries in milliseconds. */\n baseDelayMs: 1_000,\n /** Maximum delay between retries in milliseconds. */\n maxDelayMs: 30_000,\n /** Jitter factor (0-1) to randomize retry delays. */\n jitterFactor: 0.1,\n },\n\n /**\n * Workflow-specific retry defaults.\n */\n WORKFLOW_RETRY_DEFAULTS: {\n /** Maximum retry attempts for workflow steps. */\n maxRetries: 2,\n /** Base delay for workflow retries in milliseconds. */\n baseDelayMs: 2_000,\n /** Maximum delay for workflow retries in milliseconds. */\n maxDelayMs: 60_000,\n /** Jitter factor for workflow retries. */\n jitterFactor: 0.15,\n },\n\n /**\n * CLI-specific retry defaults.\n */\n CLI_RETRY_DEFAULTS: {\n /** Maximum retry attempts for CLI operations. */\n maxRetries: 2,\n /** Base delay for CLI retries in milliseconds. */\n baseDelayMs: 5_000,\n /** Maximum delay for CLI retries in milliseconds. */\n maxDelayMs: 60_000,\n /** Jitter factor for CLI retries. */\n jitterFactor: 0.2,\n },\n\n /**\n * Test framework retry defaults.\n */\n TEST_RETRY_DEFAULTS: {\n /** Maximum retries per test task. */\n maxRetries: 2,\n /** Whether to retry failed tasks by default. */\n retryFailedTasks: true,\n },\n\n /**\n * Default buffer sizing for batching and chunked processing.\n */\n BUFFER_DEFAULTS: {\n /** Preferred batch size for bulk operations. */\n batchSize: 100,\n /** Chunk size for streaming or segmented processing. */\n chunkSize: 256,\n /** Maximum items allowed in a buffer. */\n maxItems: 1_000,\n /** Maximum memory size in bytes (10 MB). */\n maxMemoryBytes: 10 * 1024 * 1024,\n /** Log buffer flush interval in milliseconds. */\n logFlushIntervalMs: 5_000,\n },\n\n // WORKER_DEFAULTS removed in #2977 — the eight settings under this category\n // (maxWorkers, poolSize, idleTimeoutMs, workflowMaxParallel, testParallelism,\n // evaluationMaxWorkers, eventBusMaxHistory, swarmObserverMaxEvents) had zero\n // production consumers. `getWorkerConfig()` was never called from anywhere\n // in src/, and the matching NEXUS_WORKERS_* env vars were silent no-ops.\n // Silent config rot is worse than missing knobs; re-add when a concrete\n // consumer exists.\n\n /**\n * Default circuit breaker settings.\n * (Source: Issue #81 - Circuit breaker for CLI failures)\n */\n CIRCUIT_BREAKER_DEFAULTS: {\n /** Failure threshold to open circuit. */\n failureThreshold: 5,\n /** Reset timeout in milliseconds. */\n resetTimeoutMs: 30_000,\n /** Success threshold to close circuit in half-open state. */\n halfOpenSuccessThreshold: 2,\n /** Whether to count timeouts as failures. */\n countTimeoutsAsFailures: true,\n /** Whether to count auth failures as failures. */\n countAuthFailuresAsFailures: false,\n /** Whether to count rate limit errors as failures (#1529). */\n countRateLimitsAsFailures: true,\n /** Maximum requests allowed in half-open state. */\n halfOpenMaxRequests: 3,\n },\n\n /**\n * Default context/memory settings.\n */\n CONTEXT_DEFAULTS: {\n /** Maximum context tokens. */\n maxTokens: 100_000,\n /** Token budget warning threshold (80%). */\n warningThreshold: 0.8,\n /** Token budget critical threshold (95%). */\n criticalThreshold: 0.95,\n /** Maximum history entries to retain. */\n maxHistoryEntries: 1_000,\n },\n\n /**\n * Default provider/model settings.\n */\n PROVIDER_DEFAULTS: {\n /** Default timeout for provider API calls in ms. */\n timeout: 30_000,\n /** Maximum retries for provider requests. */\n maxRetries: 3,\n /** Default model tier. */\n defaultTier: 'balanced' as const,\n /** Default temperature. */\n temperatureDefault: 0.3,\n /** Minimum temperature. */\n temperatureMin: 0,\n /** Maximum temperature. */\n temperatureMax: 1,\n /** Billing mode: 'plan' (monthly subscription) or 'api' (pay-per-token). Env: NEXUS_BILLING_MODE */\n billingMode: 'plan' as const,\n },\n\n /**\n * Security-related defaults.\n */\n SECURITY_DEFAULTS: {\n /** Maximum system prompt length in characters. */\n maxSystemPromptLength: 4_000,\n /** Default policy execution mode. */\n policyDefaultMode: 'read-only' as const,\n /** Default policy mode. */\n policyMode: 'enforce' as const,\n /** Default sandbox mode. */\n sandboxMode: 'policy' as const,\n /** Whether to fall back to policy mode if container unavailable. */\n sandboxFallbackToPolicy: true,\n /** Whether network is enabled in container mode. */\n sandboxNetworkEnabled: false,\n },\n} as const;\n\n// ============================================================================\n// Type Exports for DEFAULTS\n// ============================================================================\n\n/** Type for the DEFAULTS object (readonly/const). */\nexport type DefaultsConfig = typeof DEFAULTS;\n\n/** Type for timeout defaults (readonly/const). */\nexport type TimeoutDefaultsConst = typeof DEFAULTS.TIMEOUT_DEFAULTS;\n\n/** Type for rate limit defaults (readonly/const). */\nexport type RateLimitDefaultsConst = typeof DEFAULTS.RATE_LIMIT_DEFAULTS;\n\n/** Type for retry defaults (readonly/const). */\nexport type RetryDefaultsConst = typeof DEFAULTS.RETRY_DEFAULTS;\n\n/** Type for buffer defaults (readonly/const). */\nexport type BufferDefaults = typeof DEFAULTS.BUFFER_DEFAULTS;\n\n/** Type for circuit breaker defaults (readonly/const). */\nexport type CircuitBreakerDefaultsConst = typeof DEFAULTS.CIRCUIT_BREAKER_DEFAULTS;\n\n/** Type for context defaults (readonly/const). */\nexport type ContextDefaults = typeof DEFAULTS.CONTEXT_DEFAULTS;\n\n/** Type for provider defaults (readonly/const). */\nexport type ProviderDefaults = typeof DEFAULTS.PROVIDER_DEFAULTS;\n\n/** Type for security defaults (readonly/const). */\nexport type SecurityDefaults = typeof DEFAULTS.SECURITY_DEFAULTS;\n\n// ============================================================================\n// Environment Override Functions (bound to DEFAULTS)\n// ============================================================================\n\n/**\n * Get timeout with environment override support.\n *\n * @param key - Timeout key (e.g., 'cliMs', 'apiMs')\n * @returns Timeout value in milliseconds\n */\nexport const getTimeout = createGetTimeout(DEFAULTS.TIMEOUT_DEFAULTS);\n\n/**\n * Get retry config with environment override support.\n *\n * @returns Retry configuration\n */\nexport const getRetryConfig = createGetRetryConfig(DEFAULTS.RETRY_DEFAULTS);\n\n/**\n * Get rate limit config with environment override support.\n *\n * @returns Rate limit configuration\n */\nexport const getRateLimitConfig = createGetRateLimitConfig(DEFAULTS.RATE_LIMIT_DEFAULTS);\n\n/**\n * Gets the circuit breaker configuration.\n *\n * @returns Circuit breaker configuration\n */\nexport const getCircuitBreakerConfig = createGetCircuitBreakerConfig(\n DEFAULTS.CIRCUIT_BREAKER_DEFAULTS\n);\n\n/**\n * Gets the tool rate limit configuration for a specific tool category.\n *\n * @param tool - Tool category (orchestrate, delegate, workflow, expert)\n * @returns Rate limit configuration\n */\nexport const getToolRateLimit = createGetToolRateLimit(DEFAULTS.TOOL_RATE_LIMITS);\n\n// ============================================================================\n// Documentation Helper\n// ============================================================================\n\n/**\n * Returns documentation for all environment variable overrides.\n *\n * @returns Markdown documentation string\n */\nexport const getEnvVarDocumentation = createGetEnvVarDocumentation(DEFAULTS);\n"],"mappings":"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","names":[]}
@@ -8,7 +8,7 @@ import {
8
8
  getErrorMessage,
9
9
  ok,
10
10
  parseBoolEnv
11
- } from "./chunk-E7LG7L4O.js";
11
+ } from "./chunk-7NOWAN4D.js";
12
12
 
13
13
  // src/cli/research-helpers-io.ts
14
14
  import * as fs2 from "fs/promises";
@@ -146,4 +146,4 @@ export {
146
146
  loadPapersRegistry,
147
147
  savePapersRegistry
148
148
  };
149
- //# sourceMappingURL=chunk-RNCBSF6I.js.map
149
+ //# sourceMappingURL=chunk-6EUEK2T5.js.map
@@ -2534,7 +2534,7 @@ function setDefaultRegistry(registry) {
2534
2534
  }
2535
2535
  async function reloadDefaultRegistry() {
2536
2536
  globalRegistry = buildDefaultRegistry();
2537
- const { resetGlobalRegistry } = await import("./unified-registry-YXQGTU3P.js");
2537
+ const { resetGlobalRegistry } = await import("./unified-registry-3ROGZFAX.js");
2538
2538
  resetGlobalRegistry();
2539
2539
  return globalRegistry;
2540
2540
  }
@@ -10737,8 +10737,7 @@ var ToolRateLimitConfigSchema = z13.object({
10737
10737
  });
10738
10738
  var TimeoutDefaultsSchema = z13.object({
10739
10739
  cliMs: durationMs.describe("Default CLI timeout"),
10740
- cliSimpleMs: durationMs.describe("Simple CLI task timeout"),
10741
- cliComplexMs: durationMs.describe("Complex CLI task timeout"),
10740
+ // cliSimpleMs / cliComplexMs removed in #4180 — see config/defaults.ts.
10742
10741
  apiMs: durationMs.describe("Default API timeout"),
10743
10742
  apiMaxMs: durationMs.describe("Maximum API timeout"),
10744
10743
  workflowMs: durationMs.describe("Default workflow timeout"),
@@ -12088,8 +12087,11 @@ function buildOptionalSections(input, cfg) {
12088
12087
  triageStats: buildTriageStats(input),
12089
12088
  recentWindow: buildRecentWindow(cfg),
12090
12089
  // Per-model telemetry lens (#4194) — additive optional section; the
12091
- // routing-visible adaptiveBonuses above stay CLI×category.
12092
- modelWeather: getModelWeatherSummary(input, cfg)
12090
+ // routing-visible adaptiveBonuses above stay CLI×category. Gated off by
12091
+ // default (#4202): the lens costs a full-store scan per distinct model,
12092
+ // and the routing-bonus path (weather-bonus-stage) reads only
12093
+ // adaptiveBonuses — only the MCP tool opts in.
12094
+ modelWeather: input.includeModelWeather === true ? getModelWeatherSummary(input, cfg) : void 0
12093
12095
  });
12094
12096
  }
12095
12097
  function generateWeatherReport(input, config, deps) {
@@ -13914,7 +13916,7 @@ var CompositeRouter = class _CompositeRouter {
13914
13916
  */
13915
13917
  async consultUnifiedContext(task) {
13916
13918
  try {
13917
- const { getContextForTask, inferTaskCategory } = await import("./context-retriever-Z474PNZ4.js");
13919
+ const { getContextForTask, inferTaskCategory } = await import("./context-retriever-VOPNSCRI.js");
13918
13920
  const ctx = await getContextForTask({
13919
13921
  task: task.content,
13920
13922
  category: inferTaskCategory(task.content),
@@ -15419,4 +15421,4 @@ export {
15419
15421
  AgentCapability,
15420
15422
  OrchestratorError
15421
15423
  };
15422
- //# sourceMappingURL=chunk-E7LG7L4O.js.map
15424
+ //# sourceMappingURL=chunk-7NOWAN4D.js.map