nexus-agents 9.4.1 → 10.1.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 (152) hide show
  1. package/dist/{ast-rule-runner-5U6TE6YJ.js → ast-rule-runner-AAOBENF2.js} +3 -3
  2. package/dist/{child-mcp-config-IR7LRMIK.js → child-mcp-config-FRWGQIHP.js} +2 -2
  3. package/dist/{chunk-DG2UY5QU.js → chunk-2VD5OQQR.js} +2 -2
  4. package/dist/{chunk-72IBCL2X.js → chunk-33C22IY4.js} +3 -3
  5. package/dist/{chunk-FTUBCD52.js → chunk-52Q72CPP.js} +3 -3
  6. package/dist/{chunk-L34WFGDZ.js → chunk-AMK4BTAV.js} +3 -3
  7. package/dist/{chunk-L34WFGDZ.js.map → chunk-AMK4BTAV.js.map} +1 -1
  8. package/dist/{chunk-Q7RFJSR5.js → chunk-BJLP4E6Q.js} +3 -3
  9. package/dist/{chunk-Q5F4OBOK.js → chunk-BK6Q3VQK.js} +6 -42
  10. package/dist/chunk-BK6Q3VQK.js.map +1 -0
  11. package/dist/{chunk-OCKU3I4A.js → chunk-C6MM6Z65.js} +728 -54
  12. package/dist/chunk-C6MM6Z65.js.map +1 -0
  13. package/dist/{chunk-FWSAYHGV.js → chunk-EGUISJBB.js} +4 -4
  14. package/dist/{chunk-IU7CN5UQ.js → chunk-HQWQ7MR5.js} +5 -5
  15. package/dist/{chunk-XJ65J3O5.js → chunk-HVZVVDFN.js} +10 -6
  16. package/dist/chunk-HVZVVDFN.js.map +1 -0
  17. package/dist/{chunk-2AW2VHMK.js → chunk-IRFKJ2KR.js} +2 -2
  18. package/dist/{chunk-B5YROFD2.js → chunk-IYEZVAJT.js} +2506 -3219
  19. package/dist/chunk-IYEZVAJT.js.map +1 -0
  20. package/dist/{chunk-HK4LBUYY.js → chunk-K6M2ZWX5.js} +2 -2
  21. package/dist/{chunk-RI4IXOZT.js → chunk-KPGWNBDA.js} +2 -2
  22. package/dist/{chunk-6WPXQTQY.js → chunk-L4P4A7Z2.js} +2 -2
  23. package/dist/{chunk-P7327767.js → chunk-M4IJ3H6M.js} +2 -2
  24. package/dist/{chunk-FKMBZ53Y.js → chunk-MCWIMVG2.js} +2 -2
  25. package/dist/{chunk-JNRDNE26.js → chunk-MYM2TPNL.js} +2 -2
  26. package/dist/{chunk-TMHCN5EY.js → chunk-NUXSGWDS.js} +5 -5
  27. package/dist/{chunk-ONYCBTOH.js → chunk-O3VPGING.js} +11 -15
  28. package/dist/chunk-O3VPGING.js.map +1 -0
  29. package/dist/{chunk-AFAM6GK3.js → chunk-O46IOND3.js} +7 -7
  30. package/dist/{chunk-DYTB2XW2.js → chunk-O5OUJ3PX.js} +5 -5
  31. package/dist/{chunk-VQGHQVD2.js → chunk-QPU7QKPT.js} +3 -3
  32. package/dist/{chunk-DEQRRCHK.js → chunk-RBFHY2LF.js} +2 -2
  33. package/dist/{chunk-H4ACPMJS.js → chunk-SCQ5YAYO.js} +4 -4
  34. package/dist/{chunk-PFGLZZ7E.js → chunk-TLITBKMZ.js} +13 -13
  35. package/dist/{chunk-ECJ52NSK.js → chunk-TYLE7Z2S.js} +5 -3
  36. package/dist/{chunk-ECJ52NSK.js.map → chunk-TYLE7Z2S.js.map} +1 -1
  37. package/dist/{chunk-TFQMVUWQ.js → chunk-V5FGXVSX.js} +5 -7
  38. package/dist/{chunk-TFQMVUWQ.js.map → chunk-V5FGXVSX.js.map} +1 -1
  39. package/dist/{chunk-2AN5NGCQ.js → chunk-VGCRYAEH.js} +4 -4
  40. package/dist/{chunk-AYBOQE2Y.js → chunk-VHOOJ4FG.js} +3 -3
  41. package/dist/{chunk-AYBOQE2Y.js.map → chunk-VHOOJ4FG.js.map} +1 -1
  42. package/dist/{chunk-6H4NUU7G.js → chunk-WCHN7B2Q.js} +6 -20
  43. package/dist/{chunk-6H4NUU7G.js.map → chunk-WCHN7B2Q.js.map} +1 -1
  44. package/dist/{chunk-7XJZTSHW.js → chunk-WI73OZAU.js} +22 -125
  45. package/dist/chunk-WI73OZAU.js.map +1 -0
  46. package/dist/{chunk-EPCR2GOE.js → chunk-XFTTKOHK.js} +2 -2
  47. package/dist/{chunk-C5WECFBR.js → chunk-XQMQGUJT.js} +5 -5
  48. package/dist/{chunk-PRX4ERTK.js → chunk-XSAUVC6D.js} +2 -2
  49. package/dist/{chunk-6Z3MAHAC.js → chunk-XYYXVJSO.js} +2 -2
  50. package/dist/{chunk-HESQ746B.js → chunk-YHY7GMAL.js} +2 -2
  51. package/dist/{cli-circuit-breaker-AZHN2TMH.js → cli-circuit-breaker-AM425BRL.js} +3 -3
  52. package/dist/{cli-readiness-H4JTTKKU.js → cli-readiness-LWOMHZ34.js} +7 -7
  53. package/dist/cli.d.ts +1 -1
  54. package/dist/cli.js +55 -57
  55. package/dist/cli.js.map +1 -1
  56. package/dist/{composite-router-WCTNVMSX.js → composite-router-VXQFXNET.js} +2 -2
  57. package/dist/{consensus-vote-5PNCR3FT.js → consensus-vote-V2JQHILD.js} +19 -19
  58. package/dist/{consensus-vote-types-G7Lnj3B3.d.ts → consensus-vote-types-DexdhOdB.d.ts} +9 -15
  59. package/dist/{context-retriever-YM2PPNSY.js → context-retriever-GEQIPCVL.js} +8 -8
  60. package/dist/{doctor-deep-6P23G7PN.js → doctor-deep-DSOZGB5J.js} +3 -3
  61. package/dist/doctor-gateway-report-RJOSOHGA.js +21 -0
  62. package/dist/{doctor-live-MYXZCBSP.js → doctor-live-7LVRGOS5.js} +13 -13
  63. package/dist/{expert-bridge-CXHYMQRL.js → expert-bridge-5A4ADUBO.js} +4 -4
  64. package/dist/{factory-KH2MJQ5U.js → factory-4RZLP7QV.js} +5 -5
  65. package/dist/{factory-3Z46455N.js → factory-UBAUIA2M.js} +12 -12
  66. package/dist/{improvement-review-SRQQBAGG.js → improvement-review-UIYSAI36.js} +7 -7
  67. package/dist/index.d.ts +40 -559
  68. package/dist/index.js +44 -92
  69. package/dist/index.js.map +1 -1
  70. package/dist/{init-opencode-WXRTDPFP.js → init-opencode-WUN3CTBM.js} +6 -6
  71. package/dist/{issue-triage-KF47ZHU7.js → issue-triage-VKEHVHO4.js} +6 -6
  72. package/dist/{model-config-helpers-ZH2QAFVR.js → model-config-helpers-GYPIIXOP.js} +2 -2
  73. package/dist/{openai-compat-adapter-PQ3JKWPZ.js → openai-compat-adapter-GSDOJ7TQ.js} +6 -6
  74. package/dist/{outcome-store-adapter-NTYEZXLH.js → outcome-store-adapter-PXT7AL6T.js} +2 -2
  75. package/dist/{pr-reviewer-helpers-AQNGDRQT.js → pr-reviewer-helpers-GUUT7G43.js} +4 -4
  76. package/dist/{registry-command-6EHIJ3PJ.js → registry-command-4G3WGKS5.js} +2 -2
  77. package/dist/{repo-security-plan-AP3QEWJ5.js → repo-security-plan-QO6ACTPZ.js} +3 -3
  78. package/dist/{research-helpers-synthesize-XE3RMFQT.js → research-helpers-synthesize-MPEJHPYR.js} +4 -4
  79. package/dist/{routing-memory-PBZIE5NX.js → routing-memory-VHQDJ6XZ.js} +2 -2
  80. package/dist/{session-memory-6NUK6ZAG.js → session-memory-M3CQFFL6.js} +3 -3
  81. package/dist/{setup-config-KEPU4NTT.js → setup-config-VGEBCEKX.js} +3 -3
  82. package/dist/{setup-custom-api-XY455LVS.js → setup-custom-api-DX7CNYKT.js} +5 -5
  83. package/dist/{setup-custom-api-XY455LVS.js.map → setup-custom-api-DX7CNYKT.js.map} +1 -1
  84. package/dist/setup-data-dir-75Z5PSSB.js +36 -0
  85. package/dist/{tool-memory-MO2KOJJ7.js → tool-memory-7QUPGCWV.js} +5 -5
  86. package/dist/{unified-registry-JE22THXP.js → unified-registry-CLZK3H64.js} +13 -13
  87. package/dist/{weather-report-TQ6KM2F2.js → weather-report-OKMXF73V.js} +2 -2
  88. package/package.json +3 -2
  89. package/dist/chunk-7XJZTSHW.js.map +0 -1
  90. package/dist/chunk-B5YROFD2.js.map +0 -1
  91. package/dist/chunk-OCKU3I4A.js.map +0 -1
  92. package/dist/chunk-ONYCBTOH.js.map +0 -1
  93. package/dist/chunk-Q5F4OBOK.js.map +0 -1
  94. package/dist/chunk-XJ65J3O5.js.map +0 -1
  95. package/dist/doctor-gateway-report-4TXHTWUM.js +0 -21
  96. package/dist/setup-data-dir-B6URVYUD.js +0 -36
  97. /package/dist/{ast-rule-runner-5U6TE6YJ.js.map → ast-rule-runner-AAOBENF2.js.map} +0 -0
  98. /package/dist/{child-mcp-config-IR7LRMIK.js.map → child-mcp-config-FRWGQIHP.js.map} +0 -0
  99. /package/dist/{chunk-DG2UY5QU.js.map → chunk-2VD5OQQR.js.map} +0 -0
  100. /package/dist/{chunk-72IBCL2X.js.map → chunk-33C22IY4.js.map} +0 -0
  101. /package/dist/{chunk-FTUBCD52.js.map → chunk-52Q72CPP.js.map} +0 -0
  102. /package/dist/{chunk-Q7RFJSR5.js.map → chunk-BJLP4E6Q.js.map} +0 -0
  103. /package/dist/{chunk-FWSAYHGV.js.map → chunk-EGUISJBB.js.map} +0 -0
  104. /package/dist/{chunk-IU7CN5UQ.js.map → chunk-HQWQ7MR5.js.map} +0 -0
  105. /package/dist/{chunk-2AW2VHMK.js.map → chunk-IRFKJ2KR.js.map} +0 -0
  106. /package/dist/{chunk-HK4LBUYY.js.map → chunk-K6M2ZWX5.js.map} +0 -0
  107. /package/dist/{chunk-RI4IXOZT.js.map → chunk-KPGWNBDA.js.map} +0 -0
  108. /package/dist/{chunk-6WPXQTQY.js.map → chunk-L4P4A7Z2.js.map} +0 -0
  109. /package/dist/{chunk-P7327767.js.map → chunk-M4IJ3H6M.js.map} +0 -0
  110. /package/dist/{chunk-FKMBZ53Y.js.map → chunk-MCWIMVG2.js.map} +0 -0
  111. /package/dist/{chunk-JNRDNE26.js.map → chunk-MYM2TPNL.js.map} +0 -0
  112. /package/dist/{chunk-TMHCN5EY.js.map → chunk-NUXSGWDS.js.map} +0 -0
  113. /package/dist/{chunk-AFAM6GK3.js.map → chunk-O46IOND3.js.map} +0 -0
  114. /package/dist/{chunk-DYTB2XW2.js.map → chunk-O5OUJ3PX.js.map} +0 -0
  115. /package/dist/{chunk-VQGHQVD2.js.map → chunk-QPU7QKPT.js.map} +0 -0
  116. /package/dist/{chunk-DEQRRCHK.js.map → chunk-RBFHY2LF.js.map} +0 -0
  117. /package/dist/{chunk-H4ACPMJS.js.map → chunk-SCQ5YAYO.js.map} +0 -0
  118. /package/dist/{chunk-PFGLZZ7E.js.map → chunk-TLITBKMZ.js.map} +0 -0
  119. /package/dist/{chunk-2AN5NGCQ.js.map → chunk-VGCRYAEH.js.map} +0 -0
  120. /package/dist/{chunk-EPCR2GOE.js.map → chunk-XFTTKOHK.js.map} +0 -0
  121. /package/dist/{chunk-C5WECFBR.js.map → chunk-XQMQGUJT.js.map} +0 -0
  122. /package/dist/{chunk-PRX4ERTK.js.map → chunk-XSAUVC6D.js.map} +0 -0
  123. /package/dist/{chunk-6Z3MAHAC.js.map → chunk-XYYXVJSO.js.map} +0 -0
  124. /package/dist/{chunk-HESQ746B.js.map → chunk-YHY7GMAL.js.map} +0 -0
  125. /package/dist/{cli-circuit-breaker-AZHN2TMH.js.map → cli-circuit-breaker-AM425BRL.js.map} +0 -0
  126. /package/dist/{cli-readiness-H4JTTKKU.js.map → cli-readiness-LWOMHZ34.js.map} +0 -0
  127. /package/dist/{composite-router-WCTNVMSX.js.map → composite-router-VXQFXNET.js.map} +0 -0
  128. /package/dist/{consensus-vote-5PNCR3FT.js.map → consensus-vote-V2JQHILD.js.map} +0 -0
  129. /package/dist/{context-retriever-YM2PPNSY.js.map → context-retriever-GEQIPCVL.js.map} +0 -0
  130. /package/dist/{doctor-deep-6P23G7PN.js.map → doctor-deep-DSOZGB5J.js.map} +0 -0
  131. /package/dist/{doctor-gateway-report-4TXHTWUM.js.map → doctor-gateway-report-RJOSOHGA.js.map} +0 -0
  132. /package/dist/{doctor-live-MYXZCBSP.js.map → doctor-live-7LVRGOS5.js.map} +0 -0
  133. /package/dist/{expert-bridge-CXHYMQRL.js.map → expert-bridge-5A4ADUBO.js.map} +0 -0
  134. /package/dist/{factory-3Z46455N.js.map → factory-4RZLP7QV.js.map} +0 -0
  135. /package/dist/{factory-KH2MJQ5U.js.map → factory-UBAUIA2M.js.map} +0 -0
  136. /package/dist/{improvement-review-SRQQBAGG.js.map → improvement-review-UIYSAI36.js.map} +0 -0
  137. /package/dist/{init-opencode-WXRTDPFP.js.map → init-opencode-WUN3CTBM.js.map} +0 -0
  138. /package/dist/{issue-triage-KF47ZHU7.js.map → issue-triage-VKEHVHO4.js.map} +0 -0
  139. /package/dist/{model-config-helpers-ZH2QAFVR.js.map → model-config-helpers-GYPIIXOP.js.map} +0 -0
  140. /package/dist/{openai-compat-adapter-PQ3JKWPZ.js.map → openai-compat-adapter-GSDOJ7TQ.js.map} +0 -0
  141. /package/dist/{outcome-store-adapter-NTYEZXLH.js.map → outcome-store-adapter-PXT7AL6T.js.map} +0 -0
  142. /package/dist/{pr-reviewer-helpers-AQNGDRQT.js.map → pr-reviewer-helpers-GUUT7G43.js.map} +0 -0
  143. /package/dist/{registry-command-6EHIJ3PJ.js.map → registry-command-4G3WGKS5.js.map} +0 -0
  144. /package/dist/{repo-security-plan-AP3QEWJ5.js.map → repo-security-plan-QO6ACTPZ.js.map} +0 -0
  145. /package/dist/{research-helpers-synthesize-XE3RMFQT.js.map → research-helpers-synthesize-MPEJHPYR.js.map} +0 -0
  146. /package/dist/{routing-memory-PBZIE5NX.js.map → routing-memory-VHQDJ6XZ.js.map} +0 -0
  147. /package/dist/{session-memory-6NUK6ZAG.js.map → session-memory-M3CQFFL6.js.map} +0 -0
  148. /package/dist/{setup-config-KEPU4NTT.js.map → setup-config-VGEBCEKX.js.map} +0 -0
  149. /package/dist/{setup-data-dir-B6URVYUD.js.map → setup-data-dir-75Z5PSSB.js.map} +0 -0
  150. /package/dist/{tool-memory-MO2KOJJ7.js.map → tool-memory-7QUPGCWV.js.map} +0 -0
  151. /package/dist/{unified-registry-JE22THXP.js.map → unified-registry-CLZK3H64.js.map} +0 -0
  152. /package/dist/{weather-report-TQ6KM2F2.js.map → weather-report-OKMXF73V.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  VERSION,
8
8
  isNodeVersionSupported,
9
9
  recordServerTransport
10
- } from "./chunk-L34WFGDZ.js";
10
+ } from "./chunk-AMK4BTAV.js";
11
11
  import {
12
12
  checkGatewayHealth,
13
13
  cliFailsVerdict,
@@ -17,14 +17,14 @@ import {
17
17
  gatewaySlotServing,
18
18
  gatewayVerdict,
19
19
  printVoterTransportCheck
20
- } from "./chunk-6H4NUU7G.js";
20
+ } from "./chunk-WCHN7B2Q.js";
21
21
  import {
22
22
  readOpenAICompatEndpoint,
23
23
  readOpenAICompatEnv
24
- } from "./chunk-C5WECFBR.js";
24
+ } from "./chunk-XQMQGUJT.js";
25
25
  import {
26
26
  claimGlobalRegistry
27
- } from "./chunk-TFQMVUWQ.js";
27
+ } from "./chunk-V5FGXVSX.js";
28
28
  import {
29
29
  CODEX_LEGACY_LANDLOCK_CONFIG,
30
30
  CODEX_MCP_SERVER_UNAVAILABLE_REASON,
@@ -32,23 +32,24 @@ import {
32
32
  codexSandboxPreflight,
33
33
  createAllAdapters,
34
34
  createCliAdapter
35
- } from "./chunk-ONYCBTOH.js";
35
+ } from "./chunk-O3VPGING.js";
36
+ import {
37
+ DEFAULT_EXECUTION_MODE,
38
+ SecurityConfigSchema
39
+ } from "./chunk-TYLE7Z2S.js";
36
40
  import {
37
41
  getNexusTmpDir
38
42
  } from "./chunk-JPFRRNRR.js";
39
- import {
40
- resolveGatewayEnv
41
- } from "./chunk-Q5F4OBOK.js";
42
43
  import {
43
44
  probeCli
44
45
  } from "./chunk-TW6PJYTP.js";
45
46
  import {
46
47
  SERVES_PROBE_PROMPT
47
- } from "./chunk-FWSAYHGV.js";
48
+ } from "./chunk-EGUISJBB.js";
48
49
  import {
49
50
  ClaudeCliAdapter,
50
51
  IN_FAMILY_FALLBACK_OPTION
51
- } from "./chunk-TMHCN5EY.js";
52
+ } from "./chunk-NUXSGWDS.js";
52
53
  import {
53
54
  DEFAULT_CAPABILITIES,
54
55
  capitalize,
@@ -58,6 +59,7 @@ import {
58
59
  countRoutedOutcomesInFile,
59
60
  createLogger,
60
61
  err,
62
+ formatZodIssuesAsArray,
61
63
  gatewayCostStatus,
62
64
  getCliModelName,
63
65
  getDefaultModelForCli,
@@ -71,9 +73,10 @@ import {
71
73
  ok,
72
74
  resolveAuthEvidence,
73
75
  resolveGatewayCostDeclaration,
76
+ resolveInsideRoot,
74
77
  symbols,
75
78
  writeLine
76
- } from "./chunk-7XJZTSHW.js";
79
+ } from "./chunk-WI73OZAU.js";
77
80
  import {
78
81
  getLearningDir,
79
82
  getOutcomesFile,
@@ -90,21 +93,683 @@ import {
90
93
  parseBoolEnv
91
94
  } from "./chunk-LWOX65CP.js";
92
95
  import {
96
+ CliNameSchema,
97
+ TaskCategorySchema,
93
98
  resolveClassGuardMs
94
99
  } from "./chunk-4PN3UVZV.js";
95
100
 
96
101
  // src/cli/setup-data-dir.ts
97
- import { mkdirSync, existsSync as existsSync3 } from "node:fs";
102
+ import { mkdirSync, existsSync as existsSync4 } from "node:fs";
98
103
 
99
104
  // src/cli/doctor.ts
100
105
  import {
101
- existsSync as existsSync2,
102
- readFileSync as readFileSync2,
106
+ existsSync as existsSync3,
107
+ readFileSync as readFileSync3,
103
108
  readdirSync,
104
109
  accessSync,
105
110
  constants as fsConstants
106
111
  } from "node:fs";
107
112
 
113
+ // src/config/config-loader.ts
114
+ import { readFileSync, existsSync } from "node:fs";
115
+ import { resolve, join } from "node:path";
116
+ import * as yaml from "yaml";
117
+
118
+ // src/config/schemas.ts
119
+ import { z as z9 } from "zod";
120
+
121
+ // src/config/schemas-core.ts
122
+ import { z } from "zod";
123
+ var LoggingConfigSchema = z.object({
124
+ level: z.enum(["debug", "info", "warn", "error"]).default("info"),
125
+ format: z.enum(["json", "pretty"]).default("json"),
126
+ // Default to stderr: MCP stdio transport reserves stdout for JSON-RPC frames.
127
+ destination: z.enum(["stdout", "stderr", "file"]).default("stderr"),
128
+ filePath: z.string().optional()
129
+ });
130
+ var ProviderConfigSchema = z.object({
131
+ apiKey: z.string().optional(),
132
+ baseUrl: z.url().optional(),
133
+ timeout: z.number().positive().default(3e4),
134
+ maxRetries: z.number().nonnegative().default(3)
135
+ });
136
+ var ModelTiersSchema = z.object({
137
+ fast: z.array(z.string()).min(1),
138
+ balanced: z.array(z.string()).min(1),
139
+ powerful: z.array(z.string()).min(1)
140
+ });
141
+ var ModelConfigSchema = z.object({
142
+ default: z.string(),
143
+ tiers: ModelTiersSchema,
144
+ providers: z.record(z.string(), ProviderConfigSchema).optional()
145
+ });
146
+ var WorkflowConfigSchema = z.object({
147
+ templatesDir: z.string().default("./workflows"),
148
+ timeout: z.number().positive().default(3e5),
149
+ maxParallel: z.number().positive().default(5)
150
+ });
151
+
152
+ // src/config/schemas-expert.ts
153
+ import { z as z2 } from "zod";
154
+ var VALID_EXPERT_TIERS = ["fast", "balanced", "powerful"];
155
+ var VALID_EXPERT_DOMAINS = [
156
+ "code",
157
+ "security",
158
+ "architecture",
159
+ "documentation",
160
+ "testing",
161
+ "general"
162
+ ];
163
+ var MAX_SYSTEM_PROMPT_LENGTH = 4e3;
164
+ var CustomExpertDefinitionSchema = z2.object({
165
+ /** System prompt defining the expert's persona (max 4000 characters) */
166
+ systemPrompt: z2.string().min(1, "System prompt is required").max(
167
+ MAX_SYSTEM_PROMPT_LENGTH,
168
+ `System prompt must be at most ${String(MAX_SYSTEM_PROMPT_LENGTH)} characters`
169
+ ),
170
+ /** Model tier for routing */
171
+ tier: z2.enum(VALID_EXPERT_TIERS, {
172
+ error: `Invalid tier. Valid options: ${VALID_EXPERT_TIERS.join(", ")}`
173
+ }).default("balanced"),
174
+ /** Primary domain of expertise */
175
+ domain: z2.enum(VALID_EXPERT_DOMAINS, {
176
+ error: `Invalid domain. Valid options: ${VALID_EXPERT_DOMAINS.join(", ")}`
177
+ }).default("general"),
178
+ /** Secondary domains (optional) */
179
+ secondaryDomains: z2.array(z2.enum(VALID_EXPERT_DOMAINS)).optional(),
180
+ /** Expert capabilities */
181
+ capabilities: z2.array(z2.string().min(1)).min(1, "At least one capability is required").default(["task_execution"]),
182
+ /** Model temperature (0-1) */
183
+ temperature: z2.number().min(0).max(1).default(0.3),
184
+ /** Allowed tools (optional, unrestricted if not specified) */
185
+ tools: z2.array(z2.string()).optional(),
186
+ /** Human-readable description */
187
+ description: z2.string().optional(),
188
+ /** Weight for expert selection scoring (0-1) */
189
+ weight: z2.number().min(0).max(1).default(1),
190
+ /** Whether this expert is currently available */
191
+ available: z2.boolean().default(true)
192
+ });
193
+ var ExpertDefinitionSchema = z2.object({
194
+ prompt: z2.string().min(1),
195
+ tier: z2.enum(["fast", "balanced", "powerful"]).default("balanced"),
196
+ temperature: z2.number().min(0).max(1).default(0.3),
197
+ tools: z2.array(z2.string()).optional()
198
+ });
199
+ var ExpertConfigSchema = z2.object({
200
+ /** Enable built-in experts */
201
+ builtin: z2.boolean().default(true),
202
+ /** Custom expert definitions keyed by expert ID */
203
+ custom: z2.record(
204
+ z2.string().regex(/^[a-z][a-z0-9_]*$/, {
205
+ message: "Expert ID must start with a letter and contain only lowercase letters, numbers, and underscores"
206
+ }),
207
+ CustomExpertDefinitionSchema
208
+ ).optional()
209
+ });
210
+
211
+ // src/config/schemas-observability.ts
212
+ import { z as z3 } from "zod";
213
+ var EventBusConfigSchema = z3.object({
214
+ /** Enable EventBus integration (default: true) */
215
+ enabled: z3.boolean().default(true),
216
+ /** Maximum events to retain in history (default: 1000) */
217
+ maxHistorySize: z3.number().positive().default(1e3),
218
+ /** Event patterns to subscribe to (default: all major patterns) */
219
+ subscriptions: z3.object({
220
+ /** Subscribe to consensus events (consensus.*) */
221
+ consensus: z3.boolean().default(true),
222
+ /** Subscribe to agent events (agent.*) */
223
+ agent: z3.boolean().default(true),
224
+ /** Subscribe to protocol events (protocol.*) */
225
+ protocol: z3.boolean().default(true),
226
+ /** Subscribe to session events (session.*) */
227
+ session: z3.boolean().default(true),
228
+ /** Subscribe to message events (message.*) */
229
+ message: z3.boolean().default(false),
230
+ // Off by default (high volume)
231
+ /** Subscribe to byzantine detection events (byzantine.*) */
232
+ byzantine: z3.boolean().default(true)
233
+ }).default(() => ({
234
+ consensus: true,
235
+ agent: true,
236
+ protocol: true,
237
+ session: true,
238
+ message: false,
239
+ byzantine: true
240
+ })),
241
+ /** Logging configuration for events */
242
+ logging: z3.object({
243
+ /** Log level for frequent events (default: debug) */
244
+ frequentEventLevel: z3.enum(["debug", "info"]).default("debug"),
245
+ /** Log level for important events (default: info) */
246
+ importantEventLevel: z3.enum(["debug", "info"]).default("info")
247
+ }).default(() => ({
248
+ frequentEventLevel: "debug",
249
+ importantEventLevel: "info"
250
+ }))
251
+ });
252
+ var ObservabilityConfigSchema = z3.object({
253
+ /** EventBus configuration */
254
+ eventBus: EventBusConfigSchema.optional(),
255
+ /** SwarmObserver maximum events (default: 10000) */
256
+ swarmObserverMaxEvents: z3.number().positive().default(1e4)
257
+ });
258
+
259
+ // src/config/schemas-skills.ts
260
+ import { z as z4 } from "zod";
261
+ var ExternalPackSourceSchema = z4.object({
262
+ /** Pack name for identification */
263
+ name: z4.string().min(1),
264
+ /** Source: npm package name or local file path */
265
+ source: z4.string().min(1),
266
+ /** Whether the pack is enabled (default: true) */
267
+ enabled: z4.boolean().default(true)
268
+ });
269
+ var SkillLibraryConfigSchema = z4.object({
270
+ /** Whether skill library is enabled (default: true) */
271
+ enabled: z4.boolean().default(true),
272
+ /** Maximum skills to store (default: 1000) */
273
+ maxSkills: z4.number().int().positive().default(1e3),
274
+ /** Minimum success rate to keep skill (0-1, default: 0.3) */
275
+ minSuccessRateForRetention: z4.number().min(0).max(1).default(0.3),
276
+ /** Number of executions before evaluating retention (default: 5) */
277
+ executionsBeforeEvaluation: z4.number().int().nonnegative().default(5),
278
+ /** Enable automatic skill pruning (default: true) */
279
+ enablePruning: z4.boolean().default(true),
280
+ /** Whether to track detailed execution history (default: true) */
281
+ trackExecutionHistory: z4.boolean().default(true),
282
+ /** Maximum execution history entries per skill (default: 100) */
283
+ maxHistoryPerSkill: z4.number().int().positive().default(100),
284
+ /** External skill pack sources (Issue #654) */
285
+ externalPacks: z4.array(ExternalPackSourceSchema).optional()
286
+ });
287
+
288
+ // src/config/schemas-sica.ts
289
+ import { z as z5 } from "zod";
290
+ var SicaConfigSchema = z5.object({
291
+ /** Whether SICA wrapping is enabled (default: false) */
292
+ enabled: z5.boolean().default(false),
293
+ /** Minimum executions before considering improvement (default: 10) */
294
+ minExecutionsForImprovement: z5.number().int().positive().default(10),
295
+ /** Success rate threshold to trigger improvement (0-1, default: 0.7) */
296
+ improvementThreshold: z5.number().min(0).max(1).default(0.7),
297
+ /** Maximum concurrent versions to evaluate (default: 3) */
298
+ maxActiveVersions: z5.number().int().positive().max(10).default(3),
299
+ /** Whether to auto-select best version (default: true) */
300
+ autoSelectBest: z5.boolean().default(true),
301
+ /** Improvement cooldown in milliseconds (default: 60000) */
302
+ improvementCooldownMs: z5.number().int().nonnegative().default(6e4),
303
+ /** Enable observability logging for SICA events (default: true) */
304
+ enableObservability: z5.boolean().default(true)
305
+ });
306
+
307
+ // src/config/schemas-gateway.ts
308
+ import { z as z6 } from "zod";
309
+ var TierNameSchema = z6.enum(["DIRECT", "ANALYZED", "ORCHESTRATED"]);
310
+ var ALLOWED_COMMANDS = ["node", "npx", "python", "python3", "uvx", "docker"];
311
+ var UpstreamServerSchema = z6.object({
312
+ /** Unique name for this upstream server (used as tool prefix). */
313
+ name: z6.string().min(1).max(50).regex(/^[a-z0-9_-]+$/),
314
+ /** Command to spawn the server. Must be in allowlist. */
315
+ command: z6.enum(ALLOWED_COMMANDS),
316
+ /** Arguments to pass to the command. */
317
+ args: z6.array(z6.string().max(500)).default([]),
318
+ /** Environment variables (use {env:VAR} references, not plaintext secrets). */
319
+ env: z6.record(z6.string(), z6.string()).optional(),
320
+ /** Whether to connect lazily on first tool call (default: true). */
321
+ lazy: z6.boolean().default(true),
322
+ /** Connection timeout in ms (default: 10000). */
323
+ timeoutMs: z6.number().int().min(1e3).max(6e4).default(1e4)
324
+ });
325
+ var MAX_UPSTREAM_SERVERS = 5;
326
+ var GatewayConfigSchema = z6.object({
327
+ /** Enable gateway tier dispatch logging (default: true). */
328
+ enabled: z6.boolean().default(true),
329
+ /**
330
+ * Per-tool tier overrides.
331
+ * Keys are tool names (e.g., 'delegate_to_model'), values are tier names.
332
+ * Overrides the default tier from TOOL_TIER_MAP in tier-classifier.ts.
333
+ */
334
+ tierOverrides: z6.record(z6.string(), TierNameSchema).optional(),
335
+ /**
336
+ * Upstream MCP servers to compose with (#1498).
337
+ * Tools from upstream servers are available as prefixed tools (e.g., tavily.search).
338
+ */
339
+ upstreamServers: z6.array(UpstreamServerSchema).max(MAX_UPSTREAM_SERVERS).optional()
340
+ });
341
+
342
+ // src/config/schemas-routing.ts
343
+ import { z as z7 } from "zod";
344
+ var BudgetConstraintsSchema = z7.object({
345
+ /** Maximum tokens per request */
346
+ maxTokens: z7.number().positive().optional(),
347
+ /** Maximum cost per request in USD */
348
+ maxCostUsd: z7.number().positive().optional(),
349
+ /** Maximum latency per request in milliseconds */
350
+ maxLatencyMs: z7.number().positive().optional(),
351
+ /**
352
+ * Per-task-class cost ceilings in USD, keyed by `TaskCategory`
353
+ * (#4196, #4214). Keys are validated against the enum so a typo'd
354
+ * class fails config parsing instead of silently configuring nothing.
355
+ * Absent → no ceiling (OFF/unlimited). Enforced only under
356
+ * `NEXUS_BILLING_MODE=api`; a candidate with missing registry pricing
357
+ * fails a configured ceiling (fail-closed).
358
+ */
359
+ taskClassMaxCostUsd: z7.partialRecord(TaskCategorySchema, z7.number().positive()).optional()
360
+ }).optional();
361
+ var TopsisCriterionSchema = z7.object({
362
+ /** Criterion name (e.g., 'quality', 'cost', 'latency') */
363
+ name: z7.string().min(1),
364
+ /** Weight for this criterion (0-1, should sum to 1 across all criteria) */
365
+ weight: z7.number().min(0).max(1),
366
+ /** Whether higher values are better (true) or lower is better (false) */
367
+ beneficial: z7.boolean()
368
+ });
369
+ var TopsisConfigSchema = z7.object({
370
+ /** Criteria with weights (must sum to 1.0) */
371
+ criteria: z7.array(TopsisCriterionSchema).optional(),
372
+ /** Minimum acceptable quality score (0-10) */
373
+ minQualityThreshold: z7.number().min(0).max(10).default(5),
374
+ /** Maximum acceptable latency in milliseconds (optional) */
375
+ maxLatencyMs: z7.number().positive().optional(),
376
+ /** Maximum acceptable cost per request in USD (optional) */
377
+ maxCostPerRequest: z7.number().positive().optional(),
378
+ /** Whether to log detailed scoring info */
379
+ verbose: z7.boolean().default(false)
380
+ }).optional();
381
+ var DifficultyWeightsConfigSchema = z7.object({
382
+ /** Weight for reasoning difficulty (0-1) */
383
+ reasoning: z7.number().min(0).max(1).default(0.3),
384
+ /** Weight for knowledge difficulty (0-1) */
385
+ knowledge: z7.number().min(0).max(1).default(0.15),
386
+ /** Weight for creativity difficulty (0-1) */
387
+ creativity: z7.number().min(0).max(1).default(0.15),
388
+ /** Weight for precision difficulty (0-1) */
389
+ precision: z7.number().min(0).max(1).default(0.25),
390
+ /** Weight for context length difficulty (0-1) */
391
+ context_length: z7.number().min(0).max(1).default(0.15)
392
+ });
393
+ var DifficultyThresholdsSchema = z7.object({
394
+ /** Upper bound for 'easy' classification (0-1) */
395
+ easyUpperBound: z7.number().min(0).max(1).default(0.3),
396
+ /** Lower bound for 'hard' classification (0-1) */
397
+ hardLowerBound: z7.number().min(0).max(1).default(0.7)
398
+ });
399
+ var DifficultyLevelSchema = z7.enum(["easy", "medium", "hard"]);
400
+ var ModelTierSchema = z7.enum(["fast", "balanced", "powerful"]);
401
+ var ZeroRouterConfigSchema = z7.object({
402
+ /** Difficulty thresholds for level classification */
403
+ thresholds: DifficultyThresholdsSchema.optional(),
404
+ /** Weights for difficulty aggregation */
405
+ weights: DifficultyWeightsConfigSchema.optional(),
406
+ /** Mapping from difficulty level to model tier */
407
+ difficultyToTier: z7.record(DifficultyLevelSchema, ModelTierSchema).optional(),
408
+ /** Mapping from model tier to CLI preference order */
409
+ tierToClis: z7.record(ModelTierSchema, z7.array(CliNameSchema)).optional(),
410
+ /** Enable adaptive calibration from outcomes */
411
+ enableCalibration: z7.boolean().default(true),
412
+ /** Maximum outcomes to store for calibration */
413
+ maxCalibrationOutcomes: z7.number().int().positive().default(1e3),
414
+ /** Minimum outcomes before applying calibration adjustments */
415
+ minCalibrationOutcomes: z7.number().int().positive().default(50),
416
+ /** Verbose logging */
417
+ verbose: z7.boolean().default(false)
418
+ }).optional();
419
+ var LatencyTrackerConfigSchema = z7.object({
420
+ /** Maximum number of samples to keep per CLI */
421
+ windowSize: z7.number().int().positive().default(100),
422
+ /** Time-weighted decay factor (0-1, higher = more weight to recent) */
423
+ decayFactor: z7.number().min(0).max(1).default(0.95),
424
+ /** Maximum age of samples in milliseconds before forced eviction */
425
+ maxSampleAgeMs: z7.number().int().positive().default(36e5),
426
+ /** Percentiles to calculate */
427
+ percentiles: z7.array(z7.number().min(0).max(100)).max(20).default([50, 95, 99])
428
+ }).optional();
429
+ var RoutingMemoryConfigSchema = z7.object({
430
+ /** Minimum observations before using learned routing */
431
+ minObservations: z7.number().int().positive().default(5),
432
+ /** Confidence threshold for using cached decisions */
433
+ confidenceThreshold: z7.number().min(0).max(1).default(0.6),
434
+ /** Success rate threshold for trusting a routing pattern */
435
+ successRateThreshold: z7.number().min(0).max(1).default(0.7),
436
+ /** Maximum age of cached actions in milliseconds */
437
+ actionCacheMaxAgeMs: z7.number().int().positive().default(36e5)
438
+ }).optional();
439
+ var RoutingConfigSchema = z7.object({
440
+ /**
441
+ * Pipeline stage toggles.
442
+ * Enable or disable individual routing stages.
443
+ */
444
+ stages: z7.object({
445
+ /** Enable budget filtering stage */
446
+ budgetFilter: z7.boolean().default(true),
447
+ /** Enable ZeroRouter difficulty-based routing */
448
+ zeroRouter: z7.boolean().default(true),
449
+ /** Enable preference-trained routing */
450
+ preferenceRouting: z7.boolean().default(false),
451
+ /** Enable TOPSIS ranking */
452
+ topsisRanking: z7.boolean().default(true),
453
+ /** Enable LinUCB selection */
454
+ linucbSelection: z7.boolean().default(true),
455
+ /** Enable latency tracking */
456
+ latencyTracking: z7.boolean().default(true),
457
+ /** Enable routing memory for learned routing */
458
+ routingMemory: z7.boolean().default(false),
459
+ /** Enable confidence cascade stage (Issue #755, ADR-0005) */
460
+ confidenceCascade: z7.boolean().default(false),
461
+ /** Enable capability match stage (Issue #755, ADR-0005) */
462
+ capabilityMatch: z7.boolean().default(false),
463
+ /** Enable quality constraint stage (Issue #755, ADR-0005) */
464
+ qualityConstraint: z7.boolean().default(false),
465
+ /** Enable resource strategy stage for budget-aware oscillation (Issue #998) */
466
+ resourceStrategy: z7.boolean().default(true),
467
+ /** Enable strategy distillation for learned routing rules (Issue #999) */
468
+ strategyDistillation: z7.boolean().default(false)
469
+ }).optional(),
470
+ /**
471
+ * Budget constraints for routing decisions.
472
+ */
473
+ budget: BudgetConstraintsSchema,
474
+ /**
475
+ * TOPSIS multi-criteria decision making configuration.
476
+ */
477
+ topsis: TopsisConfigSchema,
478
+ /**
479
+ * ZeroRouter difficulty-based routing configuration.
480
+ */
481
+ zeroRouter: ZeroRouterConfigSchema,
482
+ /**
483
+ * Latency tracker configuration.
484
+ */
485
+ latencyTracker: LatencyTrackerConfigSchema,
486
+ /**
487
+ * Routing memory configuration.
488
+ */
489
+ routingMemory: RoutingMemoryConfigSchema,
490
+ /**
491
+ * LinUCB bandit parameters.
492
+ */
493
+ linucb: z7.object({
494
+ /** Exploration parameter (higher = more exploration) */
495
+ alpha: z7.number().positive().default(1)
496
+ }).optional(),
497
+ /**
498
+ * Preference router parameters.
499
+ */
500
+ preference: z7.object({
501
+ /** Minimum data points before using learned preferences */
502
+ minDataPoints: z7.number().int().positive().default(10)
503
+ }).optional(),
504
+ /**
505
+ * Weight for latency score in final routing (0-1).
506
+ */
507
+ latencyScoreWeight: z7.number().min(0).max(1).default(0.2)
508
+ });
509
+
510
+ // src/config/schemas-memory.ts
511
+ import { z as z8 } from "zod";
512
+ var unitInterval = z8.number().min(0).max(1);
513
+ var MIN_DECAY_INTERVAL_MS = 1e3;
514
+ var MemoryDecayConfigSchema = z8.object({
515
+ /** Whether decay runs at all (default: true) */
516
+ enabled: z8.boolean().optional(),
517
+ /**
518
+ * Interval between automatic decay runs in ms (default: 1 hour).
519
+ * Floor: {@link MIN_DECAY_INTERVAL_MS}. `runDecay` has no re-entrancy
520
+ * guard, so a sub-second cadence invites overlapping sweeps over the same
521
+ * stores; 1000 ms is the smallest value at which that is implausible.
522
+ */
523
+ decayIntervalMs: z8.number().int().min(MIN_DECAY_INTERVAL_MS).optional(),
524
+ /** Age in days before superseded beliefs are pruned (default: 30) */
525
+ beliefMaxAgeDays: z8.number().int().positive().optional(),
526
+ /** Agentic entries before importance-based eviction starts (default: 10000) */
527
+ agenticMaxEntries: z8.number().int().positive().optional(),
528
+ /** Importance below which agentic entries are evicted, 0-1 (default: 0.3) */
529
+ agenticImportanceThreshold: unitInterval.optional(),
530
+ /** Priority score below which adaptive entries are evicted, 0-1 (default: 0.2) */
531
+ adaptivePriorityThreshold: unitInterval.optional(),
532
+ /** Run MobiMem TTL eviction on each coordinated decay (default: true) */
533
+ mobimemEvictOnDecay: z8.boolean().optional(),
534
+ /** Check cross-references before evicting (default: true) */
535
+ checkCrossReferences: z8.boolean().optional(),
536
+ /** Grace period in ms before removing cross-referenced items (default: 7 days) */
537
+ crossReferenceGracePeriodMs: z8.number().int().nonnegative().optional()
538
+ });
539
+ var MemoryConfigSchema = z8.object({
540
+ /** Coordinated decay knobs (#5097) */
541
+ decay: MemoryDecayConfigSchema.optional()
542
+ });
543
+
544
+ // src/config/schemas.ts
545
+ var AppConfigSchema = z9.object({
546
+ models: ModelConfigSchema,
547
+ experts: ExpertConfigSchema.optional(),
548
+ workflows: WorkflowConfigSchema.optional(),
549
+ security: SecurityConfigSchema.optional(),
550
+ logging: LoggingConfigSchema.optional(),
551
+ /** Observability configuration (Issue #307) */
552
+ observability: ObservabilityConfigSchema.optional(),
553
+ /** Routing configuration (Issue #475) - used in orchestrator mode */
554
+ routing: RoutingConfigSchema.optional(),
555
+ /** Skill library configuration (Issue #491) */
556
+ skills: SkillLibraryConfigSchema.optional(),
557
+ /** SICA self-improvement configuration (Issue #492) */
558
+ sica: SicaConfigSchema.optional(),
559
+ /** Gateway middleware configuration (Issue #897) */
560
+ gateway: GatewayConfigSchema.optional(),
561
+ /** Memory configuration — today only `decay` reaches runtime (Issue #5097) */
562
+ memory: MemoryConfigSchema.optional()
563
+ });
564
+ var defaultConfig = {
565
+ models: {
566
+ default: "claude-sonnet",
567
+ tiers: {
568
+ fast: ["claude-haiku", "gemini-flash"],
569
+ balanced: ["claude-sonnet", "gemini-pro"],
570
+ powerful: ["claude-opus", "codex-5.3"]
571
+ }
572
+ },
573
+ logging: {
574
+ level: "info",
575
+ format: "json",
576
+ // stderr is the safe default: MCP stdio transport reserves stdout for
577
+ // JSON-RPC frames. Any log written to stdout corrupts the transport.
578
+ destination: "stderr"
579
+ },
580
+ security: {
581
+ allowedPaths: ["./"],
582
+ blockedPatterns: [],
583
+ rateLimit: {
584
+ enabled: true,
585
+ requestsPerMinute: 60
586
+ },
587
+ policy: {
588
+ defaultMode: DEFAULT_EXECUTION_MODE,
589
+ policyMode: "enforce"
590
+ },
591
+ timeout: {
592
+ defaultTimeoutMs: 3e4,
593
+ maxTimeoutMs: 3e5,
594
+ enableLogging: true,
595
+ uriValidation: true
596
+ }
597
+ }
598
+ };
599
+
600
+ // src/config/config-loader.ts
601
+ var DEFAULT_CONFIG_FILE = "nexus-agents.yaml";
602
+ var ALTERNATE_CONFIG_FILE = "nexus-agents.yml";
603
+ var CONFIG_LOOKUP_PATHS = [
604
+ `.nexus-agents/${DEFAULT_CONFIG_FILE}`,
605
+ `.nexus-agents/${ALTERNATE_CONFIG_FILE}`,
606
+ DEFAULT_CONFIG_FILE,
607
+ ALTERNATE_CONFIG_FILE
608
+ ];
609
+ var ConfigLoadError = class extends Error {
610
+ code;
611
+ constructor(message, code, cause) {
612
+ super(message, { cause });
613
+ this.name = "ConfigLoadError";
614
+ this.code = code;
615
+ }
616
+ };
617
+ function validatePath(userPath, root) {
618
+ const resolved = resolveInsideRoot(userPath, root);
619
+ if (resolved === null) {
620
+ return err(
621
+ new ConfigLoadError(
622
+ `Config path traversal detected: ${userPath} escapes ${root}`,
623
+ "PATH_TRAVERSAL"
624
+ )
625
+ );
626
+ }
627
+ return ok(resolved);
628
+ }
629
+ function findConfigPath(cwd) {
630
+ const envPath = process.env["NEXUS_CONFIG_PATH"];
631
+ if (envPath !== void 0 && envPath !== "") {
632
+ const validation = validatePath(envPath, cwd);
633
+ if (validation.ok && existsSync(validation.value)) {
634
+ return validation.value;
635
+ }
636
+ }
637
+ for (const rel of CONFIG_LOOKUP_PATHS) {
638
+ const abs = resolve(cwd, rel);
639
+ if (existsSync(abs)) {
640
+ return abs;
641
+ }
642
+ }
643
+ const globalDir = getNexusDataDir();
644
+ const globalYamlPath = join(globalDir, DEFAULT_CONFIG_FILE);
645
+ if (existsSync(globalYamlPath)) {
646
+ return globalYamlPath;
647
+ }
648
+ const globalYmlPath = join(globalDir, ALTERNATE_CONFIG_FILE);
649
+ if (existsSync(globalYmlPath)) {
650
+ return globalYmlPath;
651
+ }
652
+ return void 0;
653
+ }
654
+ function parseYaml(content) {
655
+ try {
656
+ const parsed = yaml.parse(content);
657
+ return ok(parsed);
658
+ } catch (error) {
659
+ const message = error instanceof Error ? error.message : "Unknown YAML parse error";
660
+ return err(
661
+ new ConfigLoadError(`YAML parse error: ${message}`, "YAML_PARSE_ERROR", error)
662
+ );
663
+ }
664
+ }
665
+ var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
666
+ "__proto__",
667
+ "constructor",
668
+ "prototype"
669
+ ]);
670
+ function isMergeableObject(value) {
671
+ return typeof value === "object" && value !== null && !Array.isArray(value);
672
+ }
673
+ function deepMerge(target, source) {
674
+ const result = { ...target };
675
+ for (const key of Object.keys(source)) {
676
+ if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
677
+ const sourceValue = source[key];
678
+ if (sourceValue === void 0) continue;
679
+ const targetValue = target[key];
680
+ if (isMergeableObject(sourceValue) && isMergeableObject(targetValue)) {
681
+ result[key] = deepMerge(targetValue, sourceValue);
682
+ } else {
683
+ result[key] = sourceValue;
684
+ }
685
+ }
686
+ return result;
687
+ }
688
+ function loadDefaultConfig(logger2) {
689
+ logger2.debug("No config file found, using defaults");
690
+ const validated = AppConfigSchema.safeParse(defaultConfig);
691
+ if (!validated.success) {
692
+ return err(
693
+ new ConfigLoadError(
694
+ `Default config validation failed: ${validated.error.message}`,
695
+ "VALIDATION_ERROR"
696
+ )
697
+ );
698
+ }
699
+ return ok({
700
+ config: validated.data,
701
+ usingDefaults: true,
702
+ warnings: ["No config file found, using default configuration"]
703
+ });
704
+ }
705
+ function readAndParseConfig(configPath, mergeDefaults, logger2) {
706
+ let content;
707
+ try {
708
+ content = readFileSync(configPath, "utf-8");
709
+ } catch (error) {
710
+ const message = error instanceof Error ? error.message : "Unknown error";
711
+ return err(
712
+ new ConfigLoadError(
713
+ `Failed to read config file: ${message}`,
714
+ "FILE_READ_ERROR",
715
+ error
716
+ )
717
+ );
718
+ }
719
+ const parseResult = parseYaml(content);
720
+ if (!parseResult.ok) return err(parseResult.error);
721
+ if (mergeDefaults && typeof parseResult.value === "object" && parseResult.value !== null) {
722
+ logger2.debug("Merged config with defaults");
723
+ return ok(
724
+ deepMerge(
725
+ defaultConfig,
726
+ parseResult.value
727
+ )
728
+ );
729
+ }
730
+ return ok(parseResult.value);
731
+ }
732
+ function validateConfig(configData, configPath, logger2) {
733
+ const validation = AppConfigSchema.safeParse(configData);
734
+ if (!validation.success) {
735
+ const issues = formatZodIssuesAsArray(validation.error);
736
+ return err(
737
+ new ConfigLoadError(`Config validation failed:
738
+ ${issues.join("\n")}`, "VALIDATION_ERROR")
739
+ );
740
+ }
741
+ logger2.info("Configuration loaded successfully", { configPath });
742
+ return ok({ config: validation.data, configPath, usingDefaults: false, warnings: [] });
743
+ }
744
+ function loadConfig(options = {}) {
745
+ const { configPath: explicitPath, cwd = process.cwd(), mergeDefaults = true } = options;
746
+ const logger2 = options.logger ?? createLogger({ component: "ConfigLoader" });
747
+ let configPath;
748
+ if (explicitPath !== void 0) {
749
+ const validation = validatePath(explicitPath, cwd);
750
+ if (!validation.ok) return err(validation.error);
751
+ configPath = validation.value;
752
+ } else {
753
+ configPath = findConfigPath(cwd);
754
+ }
755
+ if (configPath === void 0) return loadDefaultConfig(logger2);
756
+ const parseResult = readAndParseConfig(configPath, mergeDefaults, logger2);
757
+ if (!parseResult.ok) return err(parseResult.error);
758
+ return validateConfig(parseResult.value, configPath, logger2);
759
+ }
760
+ var loadedConfig;
761
+ function getConfig(options) {
762
+ if (loadedConfig !== void 0) {
763
+ return loadedConfig;
764
+ }
765
+ const result = loadConfig(options);
766
+ if (!result.ok) {
767
+ throw result.error;
768
+ }
769
+ loadedConfig = result.value;
770
+ return loadedConfig;
771
+ }
772
+
108
773
  // src/cli/doctor-scratch-space.ts
109
774
  import { statSync, statfsSync } from "node:fs";
110
775
  import { tmpdir } from "node:os";
@@ -596,6 +1261,7 @@ function failingVerdictTerms(result, live) {
596
1261
  const terms = gatewayTerms(result.gateway, gateway);
597
1262
  if (!result.nodeVersion.supported) terms.push("node version");
598
1263
  if (!result.mcpServerReady) terms.push("MCP server");
1264
+ if (result.configFile.error !== void 0) terms.push("configuration");
599
1265
  if (installFreshnessFailsVerdict(result.installFreshness)) {
600
1266
  terms.push("install freshness");
601
1267
  }
@@ -769,7 +1435,9 @@ function printApiKeysCheck(keys) {
769
1435
  }
770
1436
  }
771
1437
  function printConfigFileCheck(check) {
772
- if (check.found && check.path !== null) {
1438
+ if (check.error !== void 0) {
1439
+ writeLine(`${formatStatus(false)} Configuration failed: ${check.error}`);
1440
+ } else if (check.found && check.path !== null) {
773
1441
  writeLine(`${formatStatus(true)} Configuration loaded: ${check.path}`);
774
1442
  } else {
775
1443
  writeLine(`${formatStatus(false, true)} Configuration file: Not found`);
@@ -1015,8 +1683,8 @@ function printHarnessAlignment(check) {
1015
1683
  }
1016
1684
 
1017
1685
  // src/cli/doctor-harness-alignment.ts
1018
- import { existsSync, readFileSync } from "node:fs";
1019
- import { dirname, join, resolve } from "node:path";
1686
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
1687
+ import { dirname, join as join2, resolve as resolve2 } from "node:path";
1020
1688
  var HARNESS_FILES = [
1021
1689
  { harness: "Cursor", path: ".cursor/rules/agents.mdc" },
1022
1690
  { harness: "Windsurf", path: ".windsurf/rules/agents.md" },
@@ -1031,9 +1699,9 @@ function checkHarnessAlignment(cwd = process.cwd()) {
1031
1699
  const projectRoot = findProjectRoot(cwd);
1032
1700
  const inProject = projectRoot !== null;
1033
1701
  const base = projectRoot ?? cwd;
1034
- const agentsMdExists = existsSync(join(base, "AGENTS.md"));
1702
+ const agentsMdExists = existsSync2(join2(base, "AGENTS.md"));
1035
1703
  const files = HARNESS_FILES.map(
1036
- ({ harness, path }) => inspectFile(harness, path, join(base, path))
1704
+ ({ harness, path }) => inspectFile(harness, path, join2(base, path))
1037
1705
  );
1038
1706
  const alignedCount = files.filter((f) => f.exists && f.redirectsToAgentsMd).length;
1039
1707
  const driftCount = files.filter((f) => f.exists && !f.redirectsToAgentsMd).length;
@@ -1051,16 +1719,16 @@ function findProjectRoot(start) {
1051
1719
  return findRepoRoot(start) ?? findPackageJsonAncestor(start);
1052
1720
  }
1053
1721
  function findPackageJsonAncestor(start) {
1054
- let current = resolve(start);
1722
+ let current = resolve2(start);
1055
1723
  for (; ; ) {
1056
- if (existsSync(join(current, "package.json"))) return current;
1724
+ if (existsSync2(join2(current, "package.json"))) return current;
1057
1725
  const parent = dirname(current);
1058
1726
  if (parent === current) return null;
1059
1727
  current = parent;
1060
1728
  }
1061
1729
  }
1062
1730
  function inspectFile(harness, relativePath, absolutePath) {
1063
- if (!existsSync(absolutePath)) {
1731
+ if (!existsSync2(absolutePath)) {
1064
1732
  return {
1065
1733
  harness,
1066
1734
  path: relativePath,
@@ -1070,7 +1738,7 @@ function inspectFile(harness, relativePath, absolutePath) {
1070
1738
  };
1071
1739
  }
1072
1740
  try {
1073
- const content = readFileSync(absolutePath, "utf-8");
1741
+ const content = readFileSync2(absolutePath, "utf-8");
1074
1742
  return {
1075
1743
  harness,
1076
1744
  path: relativePath,
@@ -1092,12 +1760,6 @@ function inspectFile(harness, relativePath, absolutePath) {
1092
1760
  // src/cli/doctor.ts
1093
1761
  import { execFileSync } from "node:child_process";
1094
1762
  var API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GOOGLE_AI_API_KEY"];
1095
- var CONFIG_FILE_PATHS = [
1096
- "./.nexus-agents/nexus-agents.yaml",
1097
- "./.nexus-agents/nexus-agents.yml",
1098
- "./nexus-agents.yaml",
1099
- "./nexus-agents.yml"
1100
- ];
1101
1763
  var DATA_SUBDIRECTORIES = [
1102
1764
  "memory",
1103
1765
  "memory/beliefs",
@@ -1231,12 +1893,11 @@ function checkApiKeys() {
1231
1893
  }));
1232
1894
  }
1233
1895
  function checkConfigFile() {
1234
- for (const configPath of CONFIG_FILE_PATHS) {
1235
- if (existsSync2(configPath)) {
1236
- return { found: true, path: configPath };
1237
- }
1896
+ const result = loadConfig();
1897
+ if (!result.ok) {
1898
+ return { found: true, path: null, error: result.error.message };
1238
1899
  }
1239
- return { found: false, path: null };
1900
+ return { found: !result.value.usingDefaults, path: result.value.configPath ?? null };
1240
1901
  }
1241
1902
  function checkMcpServerReady() {
1242
1903
  try {
@@ -1274,11 +1935,11 @@ function buildRegistryAdvisory(cliResults, disabledClis, gateway) {
1274
1935
  function hasPriorUsage() {
1275
1936
  try {
1276
1937
  const root = getNexusDataDir();
1277
- if (!existsSync2(root)) return false;
1938
+ if (!existsSync3(root)) return false;
1278
1939
  for (const sub of ["audit", "learning", "sessions", "voting"]) {
1279
1940
  const p = `${root}/${sub}`;
1280
1941
  try {
1281
- if (existsSync2(p) && readdirSync(p).length > 0) return true;
1942
+ if (existsSync3(p) && readdirSync(p).length > 0) return true;
1282
1943
  } catch {
1283
1944
  }
1284
1945
  }
@@ -1288,17 +1949,17 @@ function hasPriorUsage() {
1288
1949
  }
1289
1950
  }
1290
1951
  function countJsonlLines(filePath) {
1291
- if (!existsSync2(filePath)) return 0;
1292
- return readFileSync2(filePath, "utf-8").split("\n").filter((l) => l.trim().length > 0).length;
1952
+ if (!existsSync3(filePath)) return 0;
1953
+ return readFileSync3(filePath, "utf-8").split("\n").filter((l) => l.trim().length > 0).length;
1293
1954
  }
1294
1955
  var NO_RULES = { count: 0, activeCount: 0, eligibleOutcomes: null, savedAt: null };
1295
1956
  function isActiveRule(rule) {
1296
1957
  return typeof rule === "object" && rule !== null && rule["status"] === "active";
1297
1958
  }
1298
1959
  function readRulesMetadata(filePath) {
1299
- if (!existsSync2(filePath)) return NO_RULES;
1960
+ if (!existsSync3(filePath)) return NO_RULES;
1300
1961
  try {
1301
- const raw = JSON.parse(readFileSync2(filePath, "utf-8"));
1962
+ const raw = JSON.parse(readFileSync3(filePath, "utf-8"));
1302
1963
  const rules = Array.isArray(raw["rules"]) ? raw["rules"] : [];
1303
1964
  const saved = raw["savedAt"];
1304
1965
  const eligible = raw["eligibleOutcomes"];
@@ -1313,7 +1974,7 @@ function readRulesMetadata(filePath) {
1313
1974
  }
1314
1975
  }
1315
1976
  function checkDirAccess(dir) {
1316
- const exists = existsSync2(dir);
1977
+ const exists = existsSync3(dir);
1317
1978
  if (!exists) return { exists: false, writable: false };
1318
1979
  try {
1319
1980
  accessSync(dir, fsConstants.W_OK);
@@ -1387,13 +2048,13 @@ async function checkSqlite() {
1387
2048
  }
1388
2049
  function checkDataDirectory() {
1389
2050
  const rootPath = getNexusDataDir();
1390
- const rootExists = existsSync2(rootPath);
2051
+ const rootExists = existsSync3(rootPath);
1391
2052
  const repoRoot = getNexusRepoDir();
1392
2053
  const perRepoSet = getPerRepoSubdirs();
1393
2054
  const subdirectories = DATA_SUBDIRECTORIES.map((name) => {
1394
2055
  const segments = name.split("/");
1395
2056
  const fullPath = nexusDataPath(...segments);
1396
- const exists = existsSync2(fullPath);
2057
+ const exists = existsSync3(fullPath);
1397
2058
  const scope = perRepoSet.has(segments[0] ?? "") ? "per-repo" : "cross-repo";
1398
2059
  return { name, path: fullPath, scope, exists, writable: exists && isWritable(fullPath) };
1399
2060
  });
@@ -1448,13 +2109,10 @@ function collectEnvironmentChecks() {
1448
2109
  }
1449
2110
  function checkVoterTransport() {
1450
2111
  const gateway = readOpenAICompatEnv();
1451
- const { deprecated } = resolveGatewayEnv();
1452
- const deprecatedEnv = deprecated.length > 0 ? { deprecatedEnv: deprecated } : {};
1453
- if (gateway === null) return { configured: false, ...deprecatedEnv };
2112
+ if (gateway === null) return { configured: false };
1454
2113
  return {
1455
2114
  configured: true,
1456
- cost: voterGatewayCostDeclaration(gateway.endpoint ?? readOpenAICompatEndpoint()),
1457
- ...deprecatedEnv
2115
+ cost: voterGatewayCostDeclaration(gateway.endpoint ?? readOpenAICompatEndpoint())
1458
2116
  };
1459
2117
  }
1460
2118
  function voterGatewayCostDeclaration(endpoint) {
@@ -1463,7 +2121,7 @@ function voterGatewayCostDeclaration(endpoint) {
1463
2121
  return resolveGatewayCostDeclaration(`api:${endpoint}`) ?? "no-default";
1464
2122
  }
1465
2123
  function isAllHealthy(input) {
1466
- return input.gateway !== "fail" && input.nodeSupported && input.hasAuthMethod && input.mcpServerReady && !installFreshnessFailsVerdict(input.installFreshness) && scratchSeverityIsAcceptable(worstSeverity(input.scratchSpace)) && // whenEmpty: zero detected CLIs is not a healthy install (#4581) — unless
2124
+ return input.gateway !== "fail" && input.nodeSupported && input.hasAuthMethod && input.mcpServerReady && input.configFile.error === void 0 && !installFreshnessFailsVerdict(input.installFreshness) && scratchSeverityIsAcceptable(worstSeverity(input.scratchSpace)) && // whenEmpty: zero detected CLIs is not a healthy install (#4581) — unless
1467
2125
  // a passing gateway serves the slots (#6609), as on a gateway-only host.
1468
2126
  allOf(
1469
2127
  input.clis,
@@ -1521,6 +2179,7 @@ async function runDoctor(deps = {}) {
1521
2179
  nodeSupported: nodeVersion.supported,
1522
2180
  hasAuthMethod: hasAnyAuthMethod(apiKeys, clis, gatewayVerdict(gateway)),
1523
2181
  mcpServerReady,
2182
+ configFile,
1524
2183
  installFreshness: env.installFreshness,
1525
2184
  scratchSpace: env.scratchSpace,
1526
2185
  clis,
@@ -1556,7 +2215,7 @@ async function doctorCommand(options = {}) {
1556
2215
  options.onResult?.(result);
1557
2216
  printDoctorResults(result, void 0, options.deferSummary === true);
1558
2217
  if (options.gateway === true || options.probe === true) {
1559
- const { formatGatewayReport } = await import("./doctor-gateway-report-4TXHTWUM.js");
2218
+ const { formatGatewayReport } = await import("./doctor-gateway-report-RJOSOHGA.js");
1560
2219
  for (const line of formatGatewayReport(result.gateway, result.clis)) {
1561
2220
  process.stdout.write(line + "\n");
1562
2221
  }
@@ -1575,13 +2234,13 @@ async function runDoctorFix(result) {
1575
2234
  writeLine2("\u2500".repeat(40));
1576
2235
  let fixCount = 0;
1577
2236
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
1578
- const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-B6URVYUD.js");
2237
+ const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-75Z5PSSB.js");
1579
2238
  const outcome = describeDataDirFix2(initDataDirectories2());
1580
2239
  writeLine2(outcome.line);
1581
2240
  if (outcome.counted) fixCount++;
1582
2241
  }
1583
2242
  if (!result.configFile.found) {
1584
- const { runConfigInitSync } = await import("./setup-config-KEPU4NTT.js");
2243
+ const { runConfigInitSync } = await import("./setup-config-VGEBCEKX.js");
1585
2244
  const configResult = runConfigInitSync(process.cwd(), false, false);
1586
2245
  if (configResult.success && configResult.created) {
1587
2246
  writeLine2(`\u2713 Generated config: ${configResult.path}`);
@@ -1632,7 +2291,7 @@ function initDataDirectories(dryRun = false) {
1632
2291
  return { success: true, rootPath: NEXUS_DATA_DIR, created, alreadyExisted, error: null };
1633
2292
  }
1634
2293
  function ensureDir(dirPath, dryRun, created, alreadyExisted, mode) {
1635
- if (existsSync3(dirPath)) {
2294
+ if (existsSync4(dirPath)) {
1636
2295
  alreadyExisted.push(dirPath);
1637
2296
  return;
1638
2297
  }
@@ -1661,6 +2320,21 @@ function describeDataDirFix(result) {
1661
2320
  }
1662
2321
 
1663
2322
  export {
2323
+ LoggingConfigSchema,
2324
+ ProviderConfigSchema,
2325
+ ModelTiersSchema,
2326
+ ModelConfigSchema,
2327
+ WorkflowConfigSchema,
2328
+ VALID_EXPERT_TIERS,
2329
+ VALID_EXPERT_DOMAINS,
2330
+ MAX_SYSTEM_PROMPT_LENGTH,
2331
+ CustomExpertDefinitionSchema,
2332
+ ExpertDefinitionSchema,
2333
+ ExpertConfigSchema,
2334
+ AppConfigSchema,
2335
+ defaultConfig,
2336
+ loadConfig,
2337
+ getConfig,
1664
2338
  DEFAULT_TASK_TTL_MS,
1665
2339
  clampTaskTtl,
1666
2340
  getCliAdapterDiagnostics,
@@ -1680,4 +2354,4 @@ export {
1680
2354
  startStdioServer,
1681
2355
  closeServer
1682
2356
  };
1683
- //# sourceMappingURL=chunk-OCKU3I4A.js.map
2357
+ //# sourceMappingURL=chunk-C6MM6Z65.js.map