@dotsetlabs/bellwether 0.10.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 (403) hide show
  1. package/CHANGELOG.md +291 -0
  2. package/LICENSE +21 -0
  3. package/README.md +739 -0
  4. package/dist/auth/credentials.d.ts +64 -0
  5. package/dist/auth/credentials.js +218 -0
  6. package/dist/auth/index.d.ts +6 -0
  7. package/dist/auth/index.js +6 -0
  8. package/dist/auth/keychain.d.ts +64 -0
  9. package/dist/auth/keychain.js +268 -0
  10. package/dist/baseline/ab-testing.d.ts +80 -0
  11. package/dist/baseline/ab-testing.js +236 -0
  12. package/dist/baseline/ai-compatibility-scorer.d.ts +95 -0
  13. package/dist/baseline/ai-compatibility-scorer.js +606 -0
  14. package/dist/baseline/calibration.d.ts +77 -0
  15. package/dist/baseline/calibration.js +136 -0
  16. package/dist/baseline/category-matching.d.ts +85 -0
  17. package/dist/baseline/category-matching.js +289 -0
  18. package/dist/baseline/change-impact-analyzer.d.ts +98 -0
  19. package/dist/baseline/change-impact-analyzer.js +592 -0
  20. package/dist/baseline/comparator.d.ts +64 -0
  21. package/dist/baseline/comparator.js +916 -0
  22. package/dist/baseline/confidence.d.ts +55 -0
  23. package/dist/baseline/confidence.js +122 -0
  24. package/dist/baseline/converter.d.ts +61 -0
  25. package/dist/baseline/converter.js +585 -0
  26. package/dist/baseline/dependency-analyzer.d.ts +89 -0
  27. package/dist/baseline/dependency-analyzer.js +567 -0
  28. package/dist/baseline/deprecation-tracker.d.ts +133 -0
  29. package/dist/baseline/deprecation-tracker.js +322 -0
  30. package/dist/baseline/diff.d.ts +55 -0
  31. package/dist/baseline/diff.js +1584 -0
  32. package/dist/baseline/documentation-scorer.d.ts +205 -0
  33. package/dist/baseline/documentation-scorer.js +466 -0
  34. package/dist/baseline/embeddings.d.ts +118 -0
  35. package/dist/baseline/embeddings.js +251 -0
  36. package/dist/baseline/error-analyzer.d.ts +198 -0
  37. package/dist/baseline/error-analyzer.js +721 -0
  38. package/dist/baseline/evaluation/evaluator.d.ts +42 -0
  39. package/dist/baseline/evaluation/evaluator.js +323 -0
  40. package/dist/baseline/evaluation/expanded-dataset.d.ts +45 -0
  41. package/dist/baseline/evaluation/expanded-dataset.js +1164 -0
  42. package/dist/baseline/evaluation/golden-dataset.d.ts +58 -0
  43. package/dist/baseline/evaluation/golden-dataset.js +717 -0
  44. package/dist/baseline/evaluation/index.d.ts +15 -0
  45. package/dist/baseline/evaluation/index.js +15 -0
  46. package/dist/baseline/evaluation/types.d.ts +186 -0
  47. package/dist/baseline/evaluation/types.js +8 -0
  48. package/dist/baseline/external-dependency-detector.d.ts +181 -0
  49. package/dist/baseline/external-dependency-detector.js +524 -0
  50. package/dist/baseline/golden-output.d.ts +162 -0
  51. package/dist/baseline/golden-output.js +636 -0
  52. package/dist/baseline/health-scorer.d.ts +174 -0
  53. package/dist/baseline/health-scorer.js +451 -0
  54. package/dist/baseline/incremental-checker.d.ts +97 -0
  55. package/dist/baseline/incremental-checker.js +174 -0
  56. package/dist/baseline/index.d.ts +31 -0
  57. package/dist/baseline/index.js +42 -0
  58. package/dist/baseline/migration-generator.d.ts +137 -0
  59. package/dist/baseline/migration-generator.js +554 -0
  60. package/dist/baseline/migrations.d.ts +60 -0
  61. package/dist/baseline/migrations.js +197 -0
  62. package/dist/baseline/performance-tracker.d.ts +214 -0
  63. package/dist/baseline/performance-tracker.js +577 -0
  64. package/dist/baseline/pr-comment-generator.d.ts +117 -0
  65. package/dist/baseline/pr-comment-generator.js +546 -0
  66. package/dist/baseline/response-fingerprint.d.ts +127 -0
  67. package/dist/baseline/response-fingerprint.js +728 -0
  68. package/dist/baseline/response-schema-tracker.d.ts +129 -0
  69. package/dist/baseline/response-schema-tracker.js +420 -0
  70. package/dist/baseline/risk-scorer.d.ts +54 -0
  71. package/dist/baseline/risk-scorer.js +434 -0
  72. package/dist/baseline/saver.d.ts +89 -0
  73. package/dist/baseline/saver.js +554 -0
  74. package/dist/baseline/scenario-generator.d.ts +151 -0
  75. package/dist/baseline/scenario-generator.js +905 -0
  76. package/dist/baseline/schema-compare.d.ts +86 -0
  77. package/dist/baseline/schema-compare.js +557 -0
  78. package/dist/baseline/schema-evolution.d.ts +189 -0
  79. package/dist/baseline/schema-evolution.js +467 -0
  80. package/dist/baseline/semantic.d.ts +203 -0
  81. package/dist/baseline/semantic.js +908 -0
  82. package/dist/baseline/synonyms.d.ts +60 -0
  83. package/dist/baseline/synonyms.js +386 -0
  84. package/dist/baseline/telemetry.d.ts +165 -0
  85. package/dist/baseline/telemetry.js +294 -0
  86. package/dist/baseline/test-pruner.d.ts +120 -0
  87. package/dist/baseline/test-pruner.js +387 -0
  88. package/dist/baseline/types.d.ts +449 -0
  89. package/dist/baseline/types.js +5 -0
  90. package/dist/baseline/version.d.ts +138 -0
  91. package/dist/baseline/version.js +206 -0
  92. package/dist/cache/index.d.ts +5 -0
  93. package/dist/cache/index.js +5 -0
  94. package/dist/cache/response-cache.d.ts +151 -0
  95. package/dist/cache/response-cache.js +287 -0
  96. package/dist/ci/index.d.ts +60 -0
  97. package/dist/ci/index.js +342 -0
  98. package/dist/cli/commands/auth.d.ts +12 -0
  99. package/dist/cli/commands/auth.js +352 -0
  100. package/dist/cli/commands/badge.d.ts +3 -0
  101. package/dist/cli/commands/badge.js +74 -0
  102. package/dist/cli/commands/baseline-accept.d.ts +15 -0
  103. package/dist/cli/commands/baseline-accept.js +178 -0
  104. package/dist/cli/commands/baseline-migrate.d.ts +12 -0
  105. package/dist/cli/commands/baseline-migrate.js +164 -0
  106. package/dist/cli/commands/baseline.d.ts +14 -0
  107. package/dist/cli/commands/baseline.js +449 -0
  108. package/dist/cli/commands/beta.d.ts +10 -0
  109. package/dist/cli/commands/beta.js +231 -0
  110. package/dist/cli/commands/check.d.ts +11 -0
  111. package/dist/cli/commands/check.js +820 -0
  112. package/dist/cli/commands/cloud/badge.d.ts +3 -0
  113. package/dist/cli/commands/cloud/badge.js +74 -0
  114. package/dist/cli/commands/cloud/diff.d.ts +6 -0
  115. package/dist/cli/commands/cloud/diff.js +79 -0
  116. package/dist/cli/commands/cloud/history.d.ts +6 -0
  117. package/dist/cli/commands/cloud/history.js +102 -0
  118. package/dist/cli/commands/cloud/link.d.ts +9 -0
  119. package/dist/cli/commands/cloud/link.js +119 -0
  120. package/dist/cli/commands/cloud/login.d.ts +7 -0
  121. package/dist/cli/commands/cloud/login.js +499 -0
  122. package/dist/cli/commands/cloud/projects.d.ts +6 -0
  123. package/dist/cli/commands/cloud/projects.js +44 -0
  124. package/dist/cli/commands/cloud/shared.d.ts +7 -0
  125. package/dist/cli/commands/cloud/shared.js +42 -0
  126. package/dist/cli/commands/cloud/teams.d.ts +8 -0
  127. package/dist/cli/commands/cloud/teams.js +169 -0
  128. package/dist/cli/commands/cloud/upload.d.ts +8 -0
  129. package/dist/cli/commands/cloud/upload.js +181 -0
  130. package/dist/cli/commands/contract.d.ts +11 -0
  131. package/dist/cli/commands/contract.js +280 -0
  132. package/dist/cli/commands/discover.d.ts +3 -0
  133. package/dist/cli/commands/discover.js +82 -0
  134. package/dist/cli/commands/eval.d.ts +9 -0
  135. package/dist/cli/commands/eval.js +187 -0
  136. package/dist/cli/commands/explore.d.ts +11 -0
  137. package/dist/cli/commands/explore.js +437 -0
  138. package/dist/cli/commands/feedback.d.ts +9 -0
  139. package/dist/cli/commands/feedback.js +174 -0
  140. package/dist/cli/commands/golden.d.ts +12 -0
  141. package/dist/cli/commands/golden.js +407 -0
  142. package/dist/cli/commands/history.d.ts +10 -0
  143. package/dist/cli/commands/history.js +202 -0
  144. package/dist/cli/commands/init.d.ts +9 -0
  145. package/dist/cli/commands/init.js +219 -0
  146. package/dist/cli/commands/interview.d.ts +3 -0
  147. package/dist/cli/commands/interview.js +903 -0
  148. package/dist/cli/commands/link.d.ts +10 -0
  149. package/dist/cli/commands/link.js +169 -0
  150. package/dist/cli/commands/login.d.ts +7 -0
  151. package/dist/cli/commands/login.js +499 -0
  152. package/dist/cli/commands/preset.d.ts +33 -0
  153. package/dist/cli/commands/preset.js +297 -0
  154. package/dist/cli/commands/profile.d.ts +33 -0
  155. package/dist/cli/commands/profile.js +286 -0
  156. package/dist/cli/commands/registry.d.ts +11 -0
  157. package/dist/cli/commands/registry.js +146 -0
  158. package/dist/cli/commands/shared.d.ts +79 -0
  159. package/dist/cli/commands/shared.js +196 -0
  160. package/dist/cli/commands/teams.d.ts +8 -0
  161. package/dist/cli/commands/teams.js +169 -0
  162. package/dist/cli/commands/test.d.ts +9 -0
  163. package/dist/cli/commands/test.js +500 -0
  164. package/dist/cli/commands/upload.d.ts +8 -0
  165. package/dist/cli/commands/upload.js +223 -0
  166. package/dist/cli/commands/validate-config.d.ts +6 -0
  167. package/dist/cli/commands/validate-config.js +35 -0
  168. package/dist/cli/commands/verify.d.ts +11 -0
  169. package/dist/cli/commands/verify.js +283 -0
  170. package/dist/cli/commands/watch.d.ts +12 -0
  171. package/dist/cli/commands/watch.js +253 -0
  172. package/dist/cli/index.d.ts +3 -0
  173. package/dist/cli/index.js +178 -0
  174. package/dist/cli/interactive.d.ts +47 -0
  175. package/dist/cli/interactive.js +216 -0
  176. package/dist/cli/output/terminal-reporter.d.ts +19 -0
  177. package/dist/cli/output/terminal-reporter.js +104 -0
  178. package/dist/cli/output.d.ts +226 -0
  179. package/dist/cli/output.js +438 -0
  180. package/dist/cli/utils/env.d.ts +5 -0
  181. package/dist/cli/utils/env.js +14 -0
  182. package/dist/cli/utils/progress.d.ts +59 -0
  183. package/dist/cli/utils/progress.js +206 -0
  184. package/dist/cli/utils/server-context.d.ts +10 -0
  185. package/dist/cli/utils/server-context.js +36 -0
  186. package/dist/cloud/auth.d.ts +144 -0
  187. package/dist/cloud/auth.js +374 -0
  188. package/dist/cloud/client.d.ts +24 -0
  189. package/dist/cloud/client.js +65 -0
  190. package/dist/cloud/http-client.d.ts +38 -0
  191. package/dist/cloud/http-client.js +215 -0
  192. package/dist/cloud/index.d.ts +23 -0
  193. package/dist/cloud/index.js +25 -0
  194. package/dist/cloud/mock-client.d.ts +107 -0
  195. package/dist/cloud/mock-client.js +545 -0
  196. package/dist/cloud/types.d.ts +515 -0
  197. package/dist/cloud/types.js +15 -0
  198. package/dist/config/defaults.d.ts +160 -0
  199. package/dist/config/defaults.js +169 -0
  200. package/dist/config/loader.d.ts +24 -0
  201. package/dist/config/loader.js +122 -0
  202. package/dist/config/template.d.ts +42 -0
  203. package/dist/config/template.js +647 -0
  204. package/dist/config/validator.d.ts +2112 -0
  205. package/dist/config/validator.js +658 -0
  206. package/dist/constants/cloud.d.ts +107 -0
  207. package/dist/constants/cloud.js +110 -0
  208. package/dist/constants/core.d.ts +521 -0
  209. package/dist/constants/core.js +556 -0
  210. package/dist/constants/testing.d.ts +1283 -0
  211. package/dist/constants/testing.js +1568 -0
  212. package/dist/constants.d.ts +10 -0
  213. package/dist/constants.js +10 -0
  214. package/dist/contract/index.d.ts +6 -0
  215. package/dist/contract/index.js +5 -0
  216. package/dist/contract/validator.d.ts +177 -0
  217. package/dist/contract/validator.js +574 -0
  218. package/dist/cost/index.d.ts +6 -0
  219. package/dist/cost/index.js +5 -0
  220. package/dist/cost/tracker.d.ts +134 -0
  221. package/dist/cost/tracker.js +313 -0
  222. package/dist/discovery/discovery.d.ts +16 -0
  223. package/dist/discovery/discovery.js +173 -0
  224. package/dist/discovery/types.d.ts +51 -0
  225. package/dist/discovery/types.js +2 -0
  226. package/dist/docs/agents.d.ts +3 -0
  227. package/dist/docs/agents.js +995 -0
  228. package/dist/docs/contract.d.ts +51 -0
  229. package/dist/docs/contract.js +1681 -0
  230. package/dist/docs/generator.d.ts +4 -0
  231. package/dist/docs/generator.js +4 -0
  232. package/dist/docs/html-reporter.d.ts +9 -0
  233. package/dist/docs/html-reporter.js +757 -0
  234. package/dist/docs/index.d.ts +10 -0
  235. package/dist/docs/index.js +11 -0
  236. package/dist/docs/junit-reporter.d.ts +18 -0
  237. package/dist/docs/junit-reporter.js +210 -0
  238. package/dist/docs/report.d.ts +14 -0
  239. package/dist/docs/report.js +44 -0
  240. package/dist/docs/sarif-reporter.d.ts +19 -0
  241. package/dist/docs/sarif-reporter.js +335 -0
  242. package/dist/docs/shared.d.ts +35 -0
  243. package/dist/docs/shared.js +162 -0
  244. package/dist/docs/templates.d.ts +12 -0
  245. package/dist/docs/templates.js +76 -0
  246. package/dist/errors/index.d.ts +6 -0
  247. package/dist/errors/index.js +6 -0
  248. package/dist/errors/retry.d.ts +92 -0
  249. package/dist/errors/retry.js +323 -0
  250. package/dist/errors/types.d.ts +321 -0
  251. package/dist/errors/types.js +584 -0
  252. package/dist/index.d.ts +32 -0
  253. package/dist/index.js +32 -0
  254. package/dist/interview/dependency-resolver.d.ts +11 -0
  255. package/dist/interview/dependency-resolver.js +32 -0
  256. package/dist/interview/interviewer.d.ts +232 -0
  257. package/dist/interview/interviewer.js +1939 -0
  258. package/dist/interview/mock-response-generator.d.ts +7 -0
  259. package/dist/interview/mock-response-generator.js +102 -0
  260. package/dist/interview/orchestrator.d.ts +237 -0
  261. package/dist/interview/orchestrator.js +1296 -0
  262. package/dist/interview/rate-limiter.d.ts +15 -0
  263. package/dist/interview/rate-limiter.js +55 -0
  264. package/dist/interview/response-validator.d.ts +10 -0
  265. package/dist/interview/response-validator.js +132 -0
  266. package/dist/interview/schema-inferrer.d.ts +8 -0
  267. package/dist/interview/schema-inferrer.js +71 -0
  268. package/dist/interview/schema-test-generator.d.ts +71 -0
  269. package/dist/interview/schema-test-generator.js +834 -0
  270. package/dist/interview/smart-value-generator.d.ts +155 -0
  271. package/dist/interview/smart-value-generator.js +554 -0
  272. package/dist/interview/stateful-test-runner.d.ts +19 -0
  273. package/dist/interview/stateful-test-runner.js +106 -0
  274. package/dist/interview/types.d.ts +561 -0
  275. package/dist/interview/types.js +2 -0
  276. package/dist/llm/anthropic.d.ts +41 -0
  277. package/dist/llm/anthropic.js +355 -0
  278. package/dist/llm/client.d.ts +123 -0
  279. package/dist/llm/client.js +42 -0
  280. package/dist/llm/factory.d.ts +38 -0
  281. package/dist/llm/factory.js +145 -0
  282. package/dist/llm/fallback.d.ts +140 -0
  283. package/dist/llm/fallback.js +379 -0
  284. package/dist/llm/index.d.ts +18 -0
  285. package/dist/llm/index.js +15 -0
  286. package/dist/llm/ollama.d.ts +37 -0
  287. package/dist/llm/ollama.js +330 -0
  288. package/dist/llm/openai.d.ts +25 -0
  289. package/dist/llm/openai.js +320 -0
  290. package/dist/llm/token-budget.d.ts +161 -0
  291. package/dist/llm/token-budget.js +395 -0
  292. package/dist/logging/logger.d.ts +70 -0
  293. package/dist/logging/logger.js +130 -0
  294. package/dist/metrics/collector.d.ts +106 -0
  295. package/dist/metrics/collector.js +547 -0
  296. package/dist/metrics/index.d.ts +7 -0
  297. package/dist/metrics/index.js +7 -0
  298. package/dist/metrics/prometheus.d.ts +20 -0
  299. package/dist/metrics/prometheus.js +241 -0
  300. package/dist/metrics/types.d.ts +209 -0
  301. package/dist/metrics/types.js +5 -0
  302. package/dist/persona/builtins.d.ts +54 -0
  303. package/dist/persona/builtins.js +219 -0
  304. package/dist/persona/index.d.ts +8 -0
  305. package/dist/persona/index.js +8 -0
  306. package/dist/persona/loader.d.ts +30 -0
  307. package/dist/persona/loader.js +190 -0
  308. package/dist/persona/types.d.ts +144 -0
  309. package/dist/persona/types.js +5 -0
  310. package/dist/persona/validation.d.ts +94 -0
  311. package/dist/persona/validation.js +332 -0
  312. package/dist/prompts/index.d.ts +5 -0
  313. package/dist/prompts/index.js +5 -0
  314. package/dist/prompts/templates.d.ts +180 -0
  315. package/dist/prompts/templates.js +431 -0
  316. package/dist/registry/client.d.ts +49 -0
  317. package/dist/registry/client.js +191 -0
  318. package/dist/registry/index.d.ts +7 -0
  319. package/dist/registry/index.js +6 -0
  320. package/dist/registry/types.d.ts +140 -0
  321. package/dist/registry/types.js +6 -0
  322. package/dist/scenarios/evaluator.d.ts +43 -0
  323. package/dist/scenarios/evaluator.js +206 -0
  324. package/dist/scenarios/index.d.ts +10 -0
  325. package/dist/scenarios/index.js +9 -0
  326. package/dist/scenarios/loader.d.ts +20 -0
  327. package/dist/scenarios/loader.js +285 -0
  328. package/dist/scenarios/types.d.ts +153 -0
  329. package/dist/scenarios/types.js +8 -0
  330. package/dist/security/index.d.ts +17 -0
  331. package/dist/security/index.js +18 -0
  332. package/dist/security/payloads.d.ts +61 -0
  333. package/dist/security/payloads.js +268 -0
  334. package/dist/security/security-tester.d.ts +42 -0
  335. package/dist/security/security-tester.js +582 -0
  336. package/dist/security/types.d.ts +166 -0
  337. package/dist/security/types.js +8 -0
  338. package/dist/transport/base-transport.d.ts +59 -0
  339. package/dist/transport/base-transport.js +38 -0
  340. package/dist/transport/http-transport.d.ts +67 -0
  341. package/dist/transport/http-transport.js +238 -0
  342. package/dist/transport/mcp-client.d.ts +141 -0
  343. package/dist/transport/mcp-client.js +496 -0
  344. package/dist/transport/sse-transport.d.ts +88 -0
  345. package/dist/transport/sse-transport.js +316 -0
  346. package/dist/transport/stdio-transport.d.ts +43 -0
  347. package/dist/transport/stdio-transport.js +238 -0
  348. package/dist/transport/types.d.ts +125 -0
  349. package/dist/transport/types.js +16 -0
  350. package/dist/utils/concurrency.d.ts +123 -0
  351. package/dist/utils/concurrency.js +213 -0
  352. package/dist/utils/formatters.d.ts +16 -0
  353. package/dist/utils/formatters.js +37 -0
  354. package/dist/utils/index.d.ts +8 -0
  355. package/dist/utils/index.js +8 -0
  356. package/dist/utils/jsonpath.d.ts +87 -0
  357. package/dist/utils/jsonpath.js +326 -0
  358. package/dist/utils/markdown.d.ts +113 -0
  359. package/dist/utils/markdown.js +265 -0
  360. package/dist/utils/network.d.ts +14 -0
  361. package/dist/utils/network.js +17 -0
  362. package/dist/utils/sanitize.d.ts +92 -0
  363. package/dist/utils/sanitize.js +191 -0
  364. package/dist/utils/semantic.d.ts +194 -0
  365. package/dist/utils/semantic.js +1051 -0
  366. package/dist/utils/smart-truncate.d.ts +94 -0
  367. package/dist/utils/smart-truncate.js +361 -0
  368. package/dist/utils/timeout.d.ts +153 -0
  369. package/dist/utils/timeout.js +205 -0
  370. package/dist/utils/yaml-parser.d.ts +58 -0
  371. package/dist/utils/yaml-parser.js +86 -0
  372. package/dist/validation/index.d.ts +32 -0
  373. package/dist/validation/index.js +32 -0
  374. package/dist/validation/semantic-test-generator.d.ts +50 -0
  375. package/dist/validation/semantic-test-generator.js +176 -0
  376. package/dist/validation/semantic-types.d.ts +66 -0
  377. package/dist/validation/semantic-types.js +94 -0
  378. package/dist/validation/semantic-validator.d.ts +38 -0
  379. package/dist/validation/semantic-validator.js +340 -0
  380. package/dist/verification/index.d.ts +6 -0
  381. package/dist/verification/index.js +5 -0
  382. package/dist/verification/types.d.ts +133 -0
  383. package/dist/verification/types.js +5 -0
  384. package/dist/verification/verifier.d.ts +30 -0
  385. package/dist/verification/verifier.js +309 -0
  386. package/dist/version.d.ts +19 -0
  387. package/dist/version.js +48 -0
  388. package/dist/workflow/auto-generator.d.ts +27 -0
  389. package/dist/workflow/auto-generator.js +513 -0
  390. package/dist/workflow/discovery.d.ts +40 -0
  391. package/dist/workflow/discovery.js +195 -0
  392. package/dist/workflow/executor.d.ts +82 -0
  393. package/dist/workflow/executor.js +611 -0
  394. package/dist/workflow/index.d.ts +10 -0
  395. package/dist/workflow/index.js +10 -0
  396. package/dist/workflow/loader.d.ts +24 -0
  397. package/dist/workflow/loader.js +194 -0
  398. package/dist/workflow/state-tracker.d.ts +98 -0
  399. package/dist/workflow/state-tracker.js +424 -0
  400. package/dist/workflow/types.d.ts +337 -0
  401. package/dist/workflow/types.js +5 -0
  402. package/package.json +94 -0
  403. package/schemas/bellwether-check.schema.json +651 -0
@@ -0,0 +1,658 @@
1
+ /**
2
+ * Configuration validation using Zod schemas.
3
+ *
4
+ * Provides comprehensive validation with helpful error messages
5
+ * for all bellwether.yaml configuration options.
6
+ */
7
+ import { z } from 'zod';
8
+ import { existsSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { PATHS, VALIDATION_BOUNDS, EXTERNAL_DEPENDENCIES } from '../constants.js';
11
+ import { CONFIG_DEFAULTS } from './defaults.js';
12
+ import { getExternalServiceStatus } from '../baseline/external-dependency-detector.js';
13
+ /**
14
+ * Server configuration schema.
15
+ */
16
+ export const serverConfigSchema = z.object({
17
+ /** Command to start the MCP server */
18
+ command: z.string().default(CONFIG_DEFAULTS.server.command),
19
+ /** Arguments to pass to the server command */
20
+ args: z.array(z.string()).default(CONFIG_DEFAULTS.server.args),
21
+ /** Timeout for server startup and tool calls (ms) */
22
+ timeout: z
23
+ .number()
24
+ .int()
25
+ .min(VALIDATION_BOUNDS.TIMEOUT.MIN_MS)
26
+ .max(VALIDATION_BOUNDS.TIMEOUT.MAX_MS)
27
+ .default(CONFIG_DEFAULTS.server.timeout),
28
+ /** Additional environment variables */
29
+ env: z.record(z.string()).optional(),
30
+ }).default(CONFIG_DEFAULTS.server);
31
+ /**
32
+ * LLM Ollama-specific settings.
33
+ */
34
+ export const ollamaConfigSchema = z.object({
35
+ /** Ollama server base URL */
36
+ baseUrl: z.string().url().default(CONFIG_DEFAULTS.llm.ollama.baseUrl),
37
+ }).default(CONFIG_DEFAULTS.llm.ollama);
38
+ /**
39
+ * LLM configuration schema.
40
+ */
41
+ export const llmConfigSchema = z.object({
42
+ /** LLM provider */
43
+ provider: z.enum(['ollama', 'openai', 'anthropic']).default(CONFIG_DEFAULTS.llm.provider),
44
+ /** Model to use (empty = provider default) */
45
+ model: z.string().default(CONFIG_DEFAULTS.llm.model),
46
+ /** Ollama-specific settings */
47
+ ollama: ollamaConfigSchema,
48
+ /** Environment variable for OpenAI API key */
49
+ openaiApiKeyEnvVar: z.string().optional(),
50
+ /** Environment variable for Anthropic API key */
51
+ anthropicApiKeyEnvVar: z.string().optional(),
52
+ }).default(CONFIG_DEFAULTS.llm);
53
+ /**
54
+ * Explore configuration schema (for bellwether explore command).
55
+ */
56
+ export const exploreConfigSchema = z.object({
57
+ /** Personas to use for exploration */
58
+ personas: z.array(z.enum([
59
+ 'technical_writer',
60
+ 'security_tester',
61
+ 'qa_engineer',
62
+ 'novice_user',
63
+ ])).default([...CONFIG_DEFAULTS.explore.personas]),
64
+ /** Maximum questions per tool */
65
+ maxQuestionsPerTool: z
66
+ .number()
67
+ .int()
68
+ .min(VALIDATION_BOUNDS.QUESTIONS_PER_TOOL.MIN)
69
+ .max(VALIDATION_BOUNDS.QUESTIONS_PER_TOOL.MAX)
70
+ .default(CONFIG_DEFAULTS.explore.maxQuestionsPerTool),
71
+ /** Run personas in parallel */
72
+ parallelPersonas: z.boolean().default(CONFIG_DEFAULTS.explore.parallelPersonas),
73
+ /** Maximum concurrent persona interviews */
74
+ personaConcurrency: z
75
+ .number()
76
+ .int()
77
+ .min(VALIDATION_BOUNDS.PERSONA_CONCURRENCY.MIN)
78
+ .max(VALIDATION_BOUNDS.PERSONA_CONCURRENCY.MAX)
79
+ .default(CONFIG_DEFAULTS.explore.personaConcurrency),
80
+ /** Skip error/edge case testing */
81
+ skipErrorTests: z.boolean().default(CONFIG_DEFAULTS.explore.skipErrorTests),
82
+ }).default(() => ({
83
+ personas: [...CONFIG_DEFAULTS.explore.personas],
84
+ maxQuestionsPerTool: CONFIG_DEFAULTS.explore.maxQuestionsPerTool,
85
+ parallelPersonas: CONFIG_DEFAULTS.explore.parallelPersonas,
86
+ personaConcurrency: CONFIG_DEFAULTS.explore.personaConcurrency,
87
+ skipErrorTests: CONFIG_DEFAULTS.explore.skipErrorTests,
88
+ }));
89
+ /**
90
+ * Scenarios configuration schema.
91
+ */
92
+ export const scenariosConfigSchema = z.object({
93
+ /** Path to scenarios YAML file */
94
+ path: z.string().optional(),
95
+ /** Run only scenarios (no LLM tests) */
96
+ only: z.boolean().default(CONFIG_DEFAULTS.scenarios.only),
97
+ }).default(CONFIG_DEFAULTS.scenarios);
98
+ /**
99
+ * Workflows configuration schema.
100
+ */
101
+ export const workflowsConfigSchema = z.object({
102
+ /** Path to workflows YAML file */
103
+ path: z.string().optional(),
104
+ /** Enable LLM-based workflow discovery */
105
+ discover: z.boolean().default(CONFIG_DEFAULTS.workflows.discover),
106
+ /** Track state between workflow steps */
107
+ trackState: z.boolean().default(CONFIG_DEFAULTS.workflows.trackState),
108
+ /** Auto-generate workflows from discovered tools */
109
+ autoGenerate: z.boolean().default(CONFIG_DEFAULTS.workflows.autoGenerate),
110
+ /** Skip steps whose dependencies (previous steps providing data) have failed */
111
+ requireSuccessfulDependencies: z.boolean().default(CONFIG_DEFAULTS.workflows.requireSuccessfulDependencies),
112
+ /** Timeout per workflow step in milliseconds */
113
+ stepTimeout: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.stepTimeout),
114
+ /** Timeout configuration for workflow operations */
115
+ timeouts: z.object({
116
+ toolCall: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.timeouts.toolCall),
117
+ stateSnapshot: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.timeouts.stateSnapshot),
118
+ probeTool: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.timeouts.probeTool),
119
+ llmAnalysis: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.timeouts.llmAnalysis),
120
+ llmSummary: z.number().int().min(1000).max(300000).default(CONFIG_DEFAULTS.workflows.timeouts.llmSummary),
121
+ }).default(CONFIG_DEFAULTS.workflows.timeouts),
122
+ }).default(CONFIG_DEFAULTS.workflows);
123
+ /**
124
+ * Example output configuration schema.
125
+ */
126
+ export const examplesConfigSchema = z.object({
127
+ /** Include full (non-truncated) examples */
128
+ full: z.boolean().default(CONFIG_DEFAULTS.output.examples.full),
129
+ /** Maximum example length in characters */
130
+ maxLength: z.number().int().min(100).max(50000).default(CONFIG_DEFAULTS.output.examples.maxLength),
131
+ /** Maximum examples per tool */
132
+ maxPerTool: z.number().int().min(1).max(20).default(CONFIG_DEFAULTS.output.examples.maxPerTool),
133
+ }).default(CONFIG_DEFAULTS.output.examples);
134
+ /**
135
+ * Output file name configuration schema.
136
+ */
137
+ export const outputFilesConfigSchema = z.object({
138
+ /** Check report JSON file name */
139
+ checkReport: z.string().default(CONFIG_DEFAULTS.output.files.checkReport),
140
+ /** Explore report JSON file name */
141
+ exploreReport: z.string().default(CONFIG_DEFAULTS.output.files.exploreReport),
142
+ /** Contract documentation file name */
143
+ contractDoc: z.string().default(CONFIG_DEFAULTS.output.files.contractDoc),
144
+ /** Agents documentation file name */
145
+ agentsDoc: z.string().default(CONFIG_DEFAULTS.output.files.agentsDoc),
146
+ /** Verification report JSON file name */
147
+ verificationReport: z.string().default(CONFIG_DEFAULTS.output.files.verificationReport),
148
+ }).default(CONFIG_DEFAULTS.output.files);
149
+ /**
150
+ * Output configuration schema.
151
+ */
152
+ export const outputConfigSchema = z.object({
153
+ /** Output directory for JSON files (bellwether-check.json, etc.) */
154
+ dir: z.string().default(CONFIG_DEFAULTS.output.dir),
155
+ /** Output directory for documentation files (CONTRACT.md, AGENTS.md) */
156
+ docsDir: z.string().default(CONFIG_DEFAULTS.output.docsDir),
157
+ /** Output format */
158
+ format: z.enum(['agents.md', 'json', 'both']).default(CONFIG_DEFAULTS.output.format),
159
+ /** Example output settings */
160
+ examples: examplesConfigSchema,
161
+ /** Output file names */
162
+ files: outputFilesConfigSchema,
163
+ }).default(CONFIG_DEFAULTS.output);
164
+ /**
165
+ * Severity levels for configuration.
166
+ */
167
+ const severityLevels = ['none', 'info', 'warning', 'breaking'];
168
+ /**
169
+ * Behavior aspects that can have severity overrides.
170
+ */
171
+ const behaviorAspects = [
172
+ 'response_format',
173
+ 'response_structure',
174
+ 'error_handling',
175
+ 'error_pattern',
176
+ 'security',
177
+ 'performance',
178
+ 'schema',
179
+ 'description',
180
+ ];
181
+ /**
182
+ * Severity configuration schema.
183
+ * Allows customizing how changes are classified and reported.
184
+ */
185
+ export const severityConfigSchema = z.object({
186
+ /** Minimum severity level to include in reports */
187
+ minimumSeverity: z.enum(severityLevels).default(CONFIG_DEFAULTS.baseline.severity.minimumSeverity),
188
+ /** Severity level at which to fail CI checks */
189
+ failOnSeverity: z.enum(severityLevels).default(CONFIG_DEFAULTS.baseline.severity.failOnSeverity),
190
+ /** Suppress warning-level changes from output */
191
+ suppressWarnings: z.boolean().default(CONFIG_DEFAULTS.baseline.severity.suppressWarnings),
192
+ /** Custom severity overrides per aspect */
193
+ aspectOverrides: z.record(z.enum(behaviorAspects), z.enum(severityLevels)).optional(),
194
+ }).default(CONFIG_DEFAULTS.baseline.severity);
195
+ /**
196
+ * Security testing configuration schema.
197
+ */
198
+ export const securityConfigSchema = z.object({
199
+ /** Enable security vulnerability testing */
200
+ enabled: z.boolean().default(CONFIG_DEFAULTS.check.security.enabled),
201
+ /** Security categories to test */
202
+ categories: z.array(z.enum([
203
+ 'sql_injection',
204
+ 'xss',
205
+ 'path_traversal',
206
+ 'command_injection',
207
+ 'ssrf',
208
+ 'error_disclosure',
209
+ ])).default([...CONFIG_DEFAULTS.check.security.categories]),
210
+ }).default(() => ({
211
+ enabled: CONFIG_DEFAULTS.check.security.enabled,
212
+ categories: [...CONFIG_DEFAULTS.check.security.categories],
213
+ }));
214
+ /**
215
+ * Statistical sampling configuration schema.
216
+ */
217
+ export const samplingConfigSchema = z.object({
218
+ /** Minimum samples per tool for statistical confidence */
219
+ minSamples: z.number().int().min(1).max(50).default(CONFIG_DEFAULTS.check.sampling.minSamples),
220
+ /** Target confidence level */
221
+ targetConfidence: z.enum(['low', 'medium', 'high']).default(CONFIG_DEFAULTS.check.sampling.targetConfidence),
222
+ /** Fail if confidence is below target */
223
+ failOnLowConfidence: z.boolean().default(CONFIG_DEFAULTS.check.sampling.failOnLowConfidence),
224
+ }).default(CONFIG_DEFAULTS.check.sampling);
225
+ /**
226
+ * Metrics configuration schema.
227
+ */
228
+ export const metricsConfigSchema = z.object({
229
+ /** Count validation rejections as success */
230
+ countValidationAsSuccess: z.boolean().default(CONFIG_DEFAULTS.check.metrics.countValidationAsSuccess),
231
+ /** Separate validation metrics from reliability metrics */
232
+ separateValidationMetrics: z.boolean().default(CONFIG_DEFAULTS.check.metrics.separateValidationMetrics),
233
+ }).default(CONFIG_DEFAULTS.check.metrics);
234
+ /**
235
+ * Stateful testing configuration schema.
236
+ */
237
+ export const statefulTestingConfigSchema = z.object({
238
+ /** Enable stateful tool testing */
239
+ enabled: z.boolean().default(CONFIG_DEFAULTS.check.statefulTesting.enabled),
240
+ /** Maximum dependency chain length */
241
+ maxChainLength: z
242
+ .number()
243
+ .int()
244
+ .min(VALIDATION_BOUNDS.STATEFUL_CHAIN.MIN)
245
+ .max(VALIDATION_BOUNDS.STATEFUL_CHAIN.MAX)
246
+ .default(CONFIG_DEFAULTS.check.statefulTesting.maxChainLength),
247
+ /** Share outputs between dependent tools */
248
+ shareOutputsBetweenTools: z.boolean().default(CONFIG_DEFAULTS.check.statefulTesting.shareOutputsBetweenTools),
249
+ }).default(CONFIG_DEFAULTS.check.statefulTesting);
250
+ /**
251
+ * External service configuration schema.
252
+ */
253
+ export const externalServiceConfigSchema = z.object({
254
+ /** Enable this external service */
255
+ enabled: z.boolean().optional(),
256
+ /** Sandbox credentials for this service */
257
+ sandboxCredentials: z.record(z.string()).optional(),
258
+ });
259
+ /**
260
+ * External services handling configuration schema.
261
+ */
262
+ export const externalServicesConfigSchema = z.object({
263
+ /** Mode for unconfigured services */
264
+ mode: z.enum(['skip', 'mock', 'fail']).default(CONFIG_DEFAULTS.check.externalServices.mode),
265
+ /** Per-service configuration overrides */
266
+ services: z.record(externalServiceConfigSchema).optional(),
267
+ }).default(CONFIG_DEFAULTS.check.externalServices);
268
+ /**
269
+ * Response assertion configuration schema.
270
+ */
271
+ export const assertionsConfigSchema = z.object({
272
+ /** Enable response assertions */
273
+ enabled: z.boolean().default(CONFIG_DEFAULTS.check.assertions.enabled),
274
+ /** Strict mode fails on assertion violations */
275
+ strict: z.boolean().default(CONFIG_DEFAULTS.check.assertions.strict),
276
+ /** Infer schemas from responses */
277
+ infer: z.boolean().default(CONFIG_DEFAULTS.check.assertions.infer),
278
+ }).default(CONFIG_DEFAULTS.check.assertions);
279
+ /**
280
+ * Rate limiting configuration schema.
281
+ */
282
+ export const rateLimitConfigSchema = z.object({
283
+ /** Enable rate limiting */
284
+ enabled: z.boolean().default(CONFIG_DEFAULTS.check.rateLimit.enabled),
285
+ /** Requests per second */
286
+ requestsPerSecond: z
287
+ .number()
288
+ .min(VALIDATION_BOUNDS.RATE_LIMIT.REQUESTS_PER_SECOND.MIN)
289
+ .max(VALIDATION_BOUNDS.RATE_LIMIT.REQUESTS_PER_SECOND.MAX)
290
+ .default(CONFIG_DEFAULTS.check.rateLimit.requestsPerSecond),
291
+ /** Burst limit */
292
+ burstLimit: z
293
+ .number()
294
+ .int()
295
+ .min(VALIDATION_BOUNDS.RATE_LIMIT.BURST_LIMIT.MIN)
296
+ .max(VALIDATION_BOUNDS.RATE_LIMIT.BURST_LIMIT.MAX)
297
+ .default(CONFIG_DEFAULTS.check.rateLimit.burstLimit),
298
+ /** Backoff strategy */
299
+ backoffStrategy: z.enum(['linear', 'exponential']).default(CONFIG_DEFAULTS.check.rateLimit.backoffStrategy),
300
+ /** Maximum retries on rate limit */
301
+ maxRetries: z
302
+ .number()
303
+ .int()
304
+ .min(VALIDATION_BOUNDS.RATE_LIMIT.MAX_RETRIES.MIN)
305
+ .max(VALIDATION_BOUNDS.RATE_LIMIT.MAX_RETRIES.MAX)
306
+ .default(CONFIG_DEFAULTS.check.rateLimit.maxRetries),
307
+ }).default(CONFIG_DEFAULTS.check.rateLimit);
308
+ /**
309
+ * Check command configuration schema.
310
+ * Controls behavior of `bellwether check`.
311
+ */
312
+ export const checkConfigSchema = z.object({
313
+ /** Enable incremental checking (only test tools with changed schemas) */
314
+ incremental: z.boolean().default(CONFIG_DEFAULTS.check.incremental),
315
+ /** Maximum age of cached results in hours (for incremental checking) */
316
+ incrementalCacheHours: z.number().int().min(1).max(720).default(CONFIG_DEFAULTS.check.incrementalCacheHours),
317
+ /** Enable parallel tool testing (faster checks) */
318
+ parallel: z.boolean().default(CONFIG_DEFAULTS.check.parallel),
319
+ /** Number of concurrent tool workers (1-10) */
320
+ parallelWorkers: z.number().int().min(1).max(10).default(CONFIG_DEFAULTS.check.parallelWorkers),
321
+ /** Performance regression threshold percentage (0-100, e.g., 25 = 25% slower triggers warning) */
322
+ performanceThreshold: z.number().min(0).max(100).default(CONFIG_DEFAULTS.check.performanceThreshold),
323
+ /** Default diff output format */
324
+ diffFormat: z.enum(['text', 'json', 'compact', 'github', 'markdown', 'junit', 'sarif']).default(CONFIG_DEFAULTS.check.diffFormat),
325
+ /** Number of warmup runs before timing samples (excluded from variance calculation) */
326
+ warmupRuns: z.number().int().min(0).max(5).default(CONFIG_DEFAULTS.check.warmupRuns),
327
+ /** Enable smart test value generation from schema descriptions (e.g., YYYY-MM-DD dates) */
328
+ smartTestValues: z.boolean().default(CONFIG_DEFAULTS.check.smartTestValues),
329
+ /** Stateful testing settings */
330
+ statefulTesting: statefulTestingConfigSchema,
331
+ /** External services handling */
332
+ externalServices: externalServicesConfigSchema,
333
+ /** Response assertions */
334
+ assertions: assertionsConfigSchema,
335
+ /** Rate limit settings */
336
+ rateLimit: rateLimitConfigSchema,
337
+ /** Metrics configuration */
338
+ metrics: metricsConfigSchema,
339
+ /** Security testing settings */
340
+ security: securityConfigSchema,
341
+ /** Statistical sampling settings */
342
+ sampling: samplingConfigSchema,
343
+ }).default(() => ({
344
+ incremental: CONFIG_DEFAULTS.check.incremental,
345
+ incrementalCacheHours: CONFIG_DEFAULTS.check.incrementalCacheHours,
346
+ parallel: CONFIG_DEFAULTS.check.parallel,
347
+ parallelWorkers: CONFIG_DEFAULTS.check.parallelWorkers,
348
+ performanceThreshold: CONFIG_DEFAULTS.check.performanceThreshold,
349
+ diffFormat: CONFIG_DEFAULTS.check.diffFormat,
350
+ warmupRuns: CONFIG_DEFAULTS.check.warmupRuns,
351
+ smartTestValues: CONFIG_DEFAULTS.check.smartTestValues,
352
+ statefulTesting: { ...CONFIG_DEFAULTS.check.statefulTesting },
353
+ externalServices: { ...CONFIG_DEFAULTS.check.externalServices },
354
+ assertions: { ...CONFIG_DEFAULTS.check.assertions },
355
+ rateLimit: { ...CONFIG_DEFAULTS.check.rateLimit },
356
+ metrics: { ...CONFIG_DEFAULTS.check.metrics },
357
+ security: {
358
+ enabled: CONFIG_DEFAULTS.check.security.enabled,
359
+ categories: [...CONFIG_DEFAULTS.check.security.categories],
360
+ },
361
+ sampling: { ...CONFIG_DEFAULTS.check.sampling },
362
+ }));
363
+ /**
364
+ * Baseline configuration schema.
365
+ */
366
+ export const baselineConfigSchema = z.object({
367
+ /** Default baseline file path (relative to output.dir or absolute) */
368
+ path: z.string().default(CONFIG_DEFAULTS.baseline.path),
369
+ /** Path to save baseline after check (enables auto-save) */
370
+ savePath: z.string().optional(),
371
+ /** Path to baseline for comparison (drift detection) */
372
+ comparePath: z.string().optional(),
373
+ /** Fail if drift is detected */
374
+ failOnDrift: z.boolean().default(CONFIG_DEFAULTS.baseline.failOnDrift),
375
+ /** Default output format for baseline comparisons */
376
+ outputFormat: z.enum(['text', 'json', 'markdown', 'compact']).default(CONFIG_DEFAULTS.baseline.outputFormat),
377
+ /** Severity thresholds for filtering and CI failure */
378
+ severity: severityConfigSchema,
379
+ }).default(CONFIG_DEFAULTS.baseline);
380
+ /**
381
+ * Cache configuration schema.
382
+ */
383
+ export const cacheConfigSchema = z.object({
384
+ /** Enable response caching */
385
+ enabled: z.boolean().default(CONFIG_DEFAULTS.cache.enabled),
386
+ /** Cache directory */
387
+ dir: z.string().default(CONFIG_DEFAULTS.cache.dir),
388
+ }).default(CONFIG_DEFAULTS.cache);
389
+ /**
390
+ * Logging configuration schema.
391
+ */
392
+ export const loggingConfigSchema = z.object({
393
+ /** Log level */
394
+ level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default(CONFIG_DEFAULTS.logging.level),
395
+ /** Verbose output */
396
+ verbose: z.boolean().default(CONFIG_DEFAULTS.logging.verbose),
397
+ }).default(CONFIG_DEFAULTS.logging);
398
+ /**
399
+ * Watch mode configuration schema.
400
+ */
401
+ export const watchConfigSchema = z.object({
402
+ /** Path to watch for changes */
403
+ path: z.string().default(CONFIG_DEFAULTS.watch.path),
404
+ /** Polling interval in milliseconds */
405
+ interval: z.number().int().min(1000).max(60000).default(CONFIG_DEFAULTS.watch.interval),
406
+ /** File extensions to watch */
407
+ extensions: z.array(z.string()).default([...CONFIG_DEFAULTS.watch.extensions]),
408
+ /** Command to run when drift is detected */
409
+ onDrift: z.string().optional(),
410
+ }).default(() => ({
411
+ path: CONFIG_DEFAULTS.watch.path,
412
+ interval: CONFIG_DEFAULTS.watch.interval,
413
+ extensions: [...CONFIG_DEFAULTS.watch.extensions],
414
+ }));
415
+ /**
416
+ * Discovery configuration schema.
417
+ */
418
+ export const discoveryConfigSchema = z.object({
419
+ /** Output as JSON */
420
+ json: z.boolean().default(CONFIG_DEFAULTS.discovery.json),
421
+ /** Connection timeout in ms */
422
+ timeout: z.number().int().min(VALIDATION_BOUNDS.TIMEOUT.MIN_MS).max(VALIDATION_BOUNDS.TIMEOUT.MAX_MS).default(CONFIG_DEFAULTS.discovery.timeout),
423
+ /** Transport type */
424
+ transport: z.enum(['stdio', 'sse', 'streamable-http']).default(CONFIG_DEFAULTS.discovery.transport),
425
+ /** Remote MCP server URL */
426
+ url: z.string().optional(),
427
+ /** Session ID for remote auth */
428
+ sessionId: z.string().optional(),
429
+ }).default(CONFIG_DEFAULTS.discovery);
430
+ /**
431
+ * Registry configuration schema.
432
+ */
433
+ export const registryConfigSchema = z.object({
434
+ /** Maximum results to show */
435
+ limit: z.number().int().min(1).max(1000).default(CONFIG_DEFAULTS.registry.limit),
436
+ /** Output as JSON */
437
+ json: z.boolean().default(CONFIG_DEFAULTS.registry.json),
438
+ }).default(CONFIG_DEFAULTS.registry);
439
+ /**
440
+ * History command configuration schema.
441
+ */
442
+ export const historyConfigSchema = z.object({
443
+ /** Number of versions to show */
444
+ limit: z.number().int().min(1).max(1000).default(CONFIG_DEFAULTS.history.limit),
445
+ /** Output as JSON */
446
+ json: z.boolean().default(CONFIG_DEFAULTS.history.json),
447
+ }).default(CONFIG_DEFAULTS.history);
448
+ /**
449
+ * Link command configuration schema.
450
+ */
451
+ export const linkConfigSchema = z.object({
452
+ /** Default server command when creating new projects */
453
+ defaultServerCommand: z.string().default(CONFIG_DEFAULTS.link.defaultServerCommand),
454
+ }).default(CONFIG_DEFAULTS.link);
455
+ /**
456
+ * Golden command configuration schema.
457
+ */
458
+ export const goldenConfigSchema = z.object({
459
+ /** Default JSON args for golden save */
460
+ defaultArgs: z.string().default(CONFIG_DEFAULTS.golden.defaultArgs),
461
+ /** Default comparison mode for golden save */
462
+ mode: z.enum(['exact', 'structural', 'semantic']).default(CONFIG_DEFAULTS.golden.mode),
463
+ /** Output format for compare */
464
+ compareFormat: z.enum(['text', 'json', 'markdown']).default(CONFIG_DEFAULTS.golden.compareFormat),
465
+ /** Output format for list */
466
+ listFormat: z.enum(['text', 'json']).default(CONFIG_DEFAULTS.golden.listFormat),
467
+ /** Normalize timestamps by default */
468
+ normalizeTimestamps: z.boolean().default(CONFIG_DEFAULTS.golden.normalizeTimestamps),
469
+ /** Normalize UUIDs by default */
470
+ normalizeUuids: z.boolean().default(CONFIG_DEFAULTS.golden.normalizeUuids),
471
+ }).default(CONFIG_DEFAULTS.golden);
472
+ /**
473
+ * Verify command configuration schema.
474
+ */
475
+ export const verifyConfigSchema = z.object({
476
+ /** Default verification tier */
477
+ tier: z.enum(['bronze', 'silver', 'gold', 'platinum']).default(CONFIG_DEFAULTS.verify.tier),
478
+ /** Include security testing by default */
479
+ security: z.boolean().default(CONFIG_DEFAULTS.verify.security),
480
+ /** Output as JSON */
481
+ json: z.boolean().default(CONFIG_DEFAULTS.verify.json),
482
+ /** Output badge URL only */
483
+ badgeOnly: z.boolean().default(CONFIG_DEFAULTS.verify.badgeOnly),
484
+ }).default(CONFIG_DEFAULTS.verify);
485
+ /**
486
+ * Contract command configuration schema.
487
+ */
488
+ export const contractConfigSchema = z.object({
489
+ /** Default contract file path */
490
+ path: z.string().optional(),
491
+ /** Validation mode */
492
+ mode: z.enum(['strict', 'lenient', 'report']).default(CONFIG_DEFAULTS.contract.mode),
493
+ /** Output format */
494
+ format: z.enum(['text', 'json', 'markdown']).default(CONFIG_DEFAULTS.contract.format),
495
+ /** Server startup timeout */
496
+ timeout: z.number().int().min(VALIDATION_BOUNDS.TIMEOUT.MIN_MS).max(VALIDATION_BOUNDS.TIMEOUT.MAX_MS).default(CONFIG_DEFAULTS.contract.timeout),
497
+ /** Exit with error when violations are found */
498
+ failOnViolation: z.boolean().default(CONFIG_DEFAULTS.contract.failOnViolation),
499
+ }).default(CONFIG_DEFAULTS.contract);
500
+ /**
501
+ * Complete bellwether.yaml configuration schema.
502
+ *
503
+ * This config is used by both 'bellwether check' and 'bellwether explore' commands.
504
+ * Each command uses the relevant sections.
505
+ */
506
+ export const bellwetherConfigSchema = z.object({
507
+ /** Server configuration (used by both commands) */
508
+ server: serverConfigSchema,
509
+ /** LLM configuration (used by explore command) */
510
+ llm: llmConfigSchema,
511
+ /** Explore settings (used by explore command) */
512
+ explore: exploreConfigSchema,
513
+ /** Check settings (used by check command) */
514
+ check: checkConfigSchema,
515
+ /** Custom scenarios (used by both commands) */
516
+ scenarios: scenariosConfigSchema,
517
+ /** Workflow testing (used by explore command) */
518
+ workflows: workflowsConfigSchema,
519
+ /** Output settings (used by both commands) */
520
+ output: outputConfigSchema,
521
+ /** Baseline comparison (used by check command) */
522
+ baseline: baselineConfigSchema,
523
+ /** Watch mode settings (used by watch command) */
524
+ watch: watchConfigSchema,
525
+ /** Caching (used by both commands) */
526
+ cache: cacheConfigSchema,
527
+ /** Logging (used by both commands) */
528
+ logging: loggingConfigSchema,
529
+ /** Discovery defaults (used by discover command) */
530
+ discovery: discoveryConfigSchema,
531
+ /** Registry defaults (used by registry command) */
532
+ registry: registryConfigSchema,
533
+ /** History defaults (used by history command) */
534
+ history: historyConfigSchema,
535
+ /** Link defaults (used by link command) */
536
+ link: linkConfigSchema,
537
+ /** Golden command defaults */
538
+ golden: goldenConfigSchema,
539
+ /** Verify command defaults */
540
+ verify: verifyConfigSchema,
541
+ /** Contract command defaults */
542
+ contract: contractConfigSchema,
543
+ });
544
+ /**
545
+ * Validate a configuration object.
546
+ * Returns the validated config with defaults applied, or throws with helpful errors.
547
+ */
548
+ export function validateConfig(config, filePath) {
549
+ const result = bellwetherConfigSchema.safeParse(config);
550
+ if (!result.success) {
551
+ const location = filePath ? ` in ${filePath}` : '';
552
+ const issues = result.error.issues.map((issue) => {
553
+ const path = issue.path.join('.');
554
+ return ` - ${path || 'root'}: ${issue.message}`;
555
+ });
556
+ throw new Error(`Invalid configuration${location}:\n${issues.join('\n')}`);
557
+ }
558
+ return result.data;
559
+ }
560
+ /**
561
+ * Generate configuration warnings for potentially problematic settings.
562
+ */
563
+ export function getConfigWarnings(config) {
564
+ const warnings = [];
565
+ if (config.check.sampling.minSamples < 5) {
566
+ warnings.push('check.sampling.minSamples < 5 may result in unreliable confidence metrics');
567
+ }
568
+ if (config.check.parallel && config.check.parallelWorkers > 4) {
569
+ warnings.push('check.parallelWorkers > 4 may trigger rate limits on some servers');
570
+ }
571
+ if (config.check.externalServices.mode === 'fail') {
572
+ const unconfigured = Object.keys(EXTERNAL_DEPENDENCIES.SERVICES).filter((service) => {
573
+ const status = getExternalServiceStatus(service, config.check.externalServices);
574
+ return !status.configured;
575
+ });
576
+ if (unconfigured.length === Object.keys(EXTERNAL_DEPENDENCIES.SERVICES).length) {
577
+ warnings.push('External services mode is set to "fail" but no credentials detected');
578
+ }
579
+ }
580
+ return warnings;
581
+ }
582
+ /**
583
+ * Validate that required fields are present for the check command.
584
+ */
585
+ export function validateConfigForCheck(config, serverCommand) {
586
+ // Server command must be provided either in config or as argument
587
+ const effectiveCommand = serverCommand || config.server.command;
588
+ if (!effectiveCommand) {
589
+ throw new Error('No server command specified.\n\n' +
590
+ 'Either add it to bellwether.yaml:\n' +
591
+ ' server:\n' +
592
+ ' command: "npx @your/mcp-server"\n\n' +
593
+ 'Or pass it as an argument:\n' +
594
+ ' bellwether check npx @your/mcp-server');
595
+ }
596
+ // Check command doesn't require LLM - it's free and deterministic
597
+ }
598
+ /**
599
+ * Validate that required fields are present for the explore command.
600
+ */
601
+ export function validateConfigForExplore(config, serverCommand) {
602
+ // Server command must be provided either in config or as argument
603
+ const effectiveCommand = serverCommand || config.server.command;
604
+ if (!effectiveCommand) {
605
+ throw new Error('No server command specified.\n\n' +
606
+ 'Either add it to bellwether.yaml:\n' +
607
+ ' server:\n' +
608
+ ' command: "npx @your/mcp-server"\n\n' +
609
+ 'Or pass it as an argument:\n' +
610
+ ' bellwether explore npx @your/mcp-server');
611
+ }
612
+ // Explore command requires LLM - check provider requirements
613
+ const provider = config.llm.provider;
614
+ if (provider === 'openai') {
615
+ const envVar = config.llm.openaiApiKeyEnvVar || 'OPENAI_API_KEY';
616
+ if (!process.env[envVar]) {
617
+ throw new Error(`OpenAI API key not found.\n\n` +
618
+ `Set the ${envVar} environment variable or run:\n` +
619
+ ` bellwether auth\n\n` +
620
+ `Or switch to local Ollama (free) by setting:\n` +
621
+ ` llm:\n` +
622
+ ` provider: ollama\n\n` +
623
+ `For drift detection without LLM, use:\n` +
624
+ ` bellwether check`);
625
+ }
626
+ }
627
+ else if (provider === 'anthropic') {
628
+ const envVar = config.llm.anthropicApiKeyEnvVar || 'ANTHROPIC_API_KEY';
629
+ if (!process.env[envVar]) {
630
+ throw new Error(`Anthropic API key not found.\n\n` +
631
+ `Set the ${envVar} environment variable or run:\n` +
632
+ ` bellwether auth\n\n` +
633
+ `Or switch to local Ollama (free) by setting:\n` +
634
+ ` llm:\n` +
635
+ ` provider: ollama\n\n` +
636
+ `For drift detection without LLM, use:\n` +
637
+ ` bellwether check`);
638
+ }
639
+ }
640
+ // Ollama doesn't require API keys
641
+ }
642
+ /**
643
+ * Check if a config file exists at the given path or in common locations.
644
+ */
645
+ export function findConfigFile(explicitPath) {
646
+ if (explicitPath) {
647
+ return existsSync(explicitPath) ? explicitPath : null;
648
+ }
649
+ const searchNames = PATHS.CONFIG_FILENAMES;
650
+ for (const name of searchNames) {
651
+ const path = join(process.cwd(), name);
652
+ if (existsSync(path)) {
653
+ return path;
654
+ }
655
+ }
656
+ return null;
657
+ }
658
+ //# sourceMappingURL=validator.js.map