@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,253 @@
1
+ /**
2
+ * Watch command - watch for file changes and auto-check.
3
+ *
4
+ * Uses bellwether.yaml for configuration.
5
+ * Only watch-specific options are available as flags.
6
+ *
7
+ * Note: Watch mode only runs schema validation (check mode).
8
+ * For LLM-powered exploration, use 'bellwether explore' directly.
9
+ */
10
+ import { Command } from 'commander';
11
+ import { existsSync, readdirSync, statSync } from 'fs';
12
+ import { resolve, join } from 'path';
13
+ import { MCPClient } from '../../transport/mcp-client.js';
14
+ import { discover } from '../../discovery/discovery.js';
15
+ import { Interviewer } from '../../interview/interviewer.js';
16
+ import { loadConfig, ConfigNotFoundError } from '../../config/loader.js';
17
+ import { validateConfigForCheck } from '../../config/validator.js';
18
+ import { createBaseline, saveBaseline, loadBaseline, compareBaselines, formatDiffText, } from '../../baseline/index.js';
19
+ import { EXIT_CODES, CHECK_SAMPLING } from '../../constants.js';
20
+ import * as output from '../output.js';
21
+ export const watchCommand = new Command('watch')
22
+ .description('Watch for file changes and auto-check (uses bellwether.yaml)')
23
+ .argument('[server-command]', 'Server command (overrides config)')
24
+ .argument('[args...]', 'Server arguments')
25
+ .option('-c, --config <path>', 'Path to config file')
26
+ .action(async (serverCommandArg, serverArgs, options) => {
27
+ // Load configuration (required)
28
+ let config;
29
+ try {
30
+ config = loadConfig(options.config);
31
+ }
32
+ catch (error) {
33
+ if (error instanceof ConfigNotFoundError) {
34
+ output.error(error.message);
35
+ process.exit(EXIT_CODES.ERROR);
36
+ }
37
+ throw error;
38
+ }
39
+ // Determine server command (CLI arg overrides config)
40
+ const serverCommand = serverCommandArg || config.server.command;
41
+ const args = serverArgs.length > 0 ? serverArgs : config.server.args;
42
+ // Validate config for check mode (watch only does check, not explore)
43
+ try {
44
+ validateConfigForCheck(config, serverCommand);
45
+ }
46
+ catch (error) {
47
+ output.error(error instanceof Error ? error.message : String(error));
48
+ process.exit(EXIT_CODES.ERROR);
49
+ }
50
+ // Get watch settings from config
51
+ const watchPath = resolve(config.watch.path);
52
+ const interval = config.watch.interval;
53
+ const extensions = config.watch.extensions;
54
+ const onDriftCommand = config.watch.onDrift;
55
+ const minSamplesForConfidence = CHECK_SAMPLING.SAMPLES_FOR_CONFIDENCE[config.check.sampling.targetConfidence];
56
+ const minSamples = Math.max(config.check.sampling.minSamples, minSamplesForConfidence);
57
+ // Baseline path for watch mode (use savePath or baseline default)
58
+ const baselinePathValue = config.baseline.savePath ?? config.baseline.path;
59
+ const baselinePath = baselinePathValue.startsWith('/')
60
+ ? baselinePathValue
61
+ : resolve(join(config.output.dir, baselinePathValue));
62
+ // Extract settings from config
63
+ const timeout = config.server.timeout;
64
+ const verbose = config.logging.verbose;
65
+ output.info('Bellwether Watch Mode\n');
66
+ output.info(`Server: ${serverCommand} ${args.join(' ')}`);
67
+ output.info(`Mode: check (schema validation)`);
68
+ output.info(`Watching: ${watchPath}`);
69
+ output.info(`Baseline: ${baselinePath}`);
70
+ output.info(`Poll interval: ${interval}ms`);
71
+ output.info('');
72
+ output.info('Note: Watch mode runs schema validation only. Use "bellwether explore" for LLM analysis.');
73
+ output.info('');
74
+ // Track last baseline hash to detect changes
75
+ let lastBaselineHash = null;
76
+ if (existsSync(baselinePath)) {
77
+ const baseline = loadBaseline(baselinePath);
78
+ lastBaselineHash = baseline.integrityHash;
79
+ output.info(`Loaded existing baseline: ${lastBaselineHash.slice(0, 8)}`);
80
+ }
81
+ // Track watched file modification times
82
+ const fileModTimes = new Map();
83
+ async function runTest() {
84
+ const mcpClient = new MCPClient({ timeout });
85
+ try {
86
+ output.info('\n--- Running Test ---');
87
+ output.info(`[${new Date().toLocaleTimeString()}] Starting test...`);
88
+ await mcpClient.connect(serverCommand, args, config.server.env);
89
+ const discovery = await discover(mcpClient, serverCommand, args);
90
+ output.info(`Found ${discovery.tools.length} tools`);
91
+ if (discovery.tools.length === 0) {
92
+ output.info('No tools found. Skipping.');
93
+ await mcpClient.disconnect();
94
+ return;
95
+ }
96
+ const fullServerCommand = `${serverCommand} ${args.join(' ')}`.trim();
97
+ // Watch mode uses check (no LLM) for fast, deterministic drift detection
98
+ const interviewer = new Interviewer(null, {
99
+ maxQuestionsPerTool: minSamples,
100
+ timeout,
101
+ skipErrorTests: false,
102
+ model: 'check',
103
+ personas: [],
104
+ checkMode: true, // Required when passing null for LLM
105
+ parallelTools: config.check.parallel,
106
+ toolConcurrency: config.check.parallelWorkers,
107
+ serverCommand: fullServerCommand,
108
+ });
109
+ const progressCallback = (progress) => {
110
+ process.stdout.write(`\rChecking: ${progress.toolsCompleted + 1}/${progress.totalTools} tools`.padEnd(60));
111
+ };
112
+ const result = await interviewer.interview(mcpClient, discovery, progressCallback);
113
+ output.info('\n');
114
+ // Create and compare baseline
115
+ const newBaseline = createBaseline(result, fullServerCommand);
116
+ if (lastBaselineHash && existsSync(baselinePath)) {
117
+ const previousBaseline = loadBaseline(baselinePath);
118
+ const diff = compareBaselines(previousBaseline, newBaseline, {});
119
+ if (diff.severity !== 'none') {
120
+ output.info('\n--- Behavioral Drift Detected ---');
121
+ output.info(formatDiffText(diff));
122
+ // Run on-drift command if configured
123
+ if (onDriftCommand) {
124
+ output.info(`\nRunning: ${onDriftCommand}`);
125
+ const { spawnSync } = await import('child_process');
126
+ try {
127
+ // Parse command safely - split on spaces but respect quoted strings
128
+ const parts = onDriftCommand.match(/(?:[^\s"]+|"[^"]*")+/g);
129
+ if (!parts || parts.length === 0) {
130
+ throw new Error('Empty on-drift command');
131
+ }
132
+ const [cmd, ...rest] = parts;
133
+ const cmdArgs = rest.map((arg) => arg.replace(/^"|"$/g, ''));
134
+ // Use spawnSync without shell to prevent command injection
135
+ const cmdResult = spawnSync(cmd, cmdArgs, { stdio: 'inherit' });
136
+ if (cmdResult.error) {
137
+ throw cmdResult.error;
138
+ }
139
+ if (cmdResult.status !== 0) {
140
+ output.error(`On-drift command exited with code ${cmdResult.status}`);
141
+ }
142
+ }
143
+ catch (e) {
144
+ output.error('On-drift command failed: ' + (e instanceof Error ? e.message : String(e)));
145
+ }
146
+ }
147
+ }
148
+ else {
149
+ output.info('No drift detected.');
150
+ }
151
+ }
152
+ // Save new baseline
153
+ saveBaseline(newBaseline, baselinePath);
154
+ lastBaselineHash = newBaseline.integrityHash;
155
+ output.info(`Baseline updated: ${newBaseline.integrityHash.slice(0, 8)}`);
156
+ }
157
+ catch (error) {
158
+ output.error('Test failed: ' + (error instanceof Error ? error.message : String(error)));
159
+ }
160
+ finally {
161
+ await mcpClient.disconnect();
162
+ }
163
+ }
164
+ function checkForChanges() {
165
+ // Simple file watcher - check if any source files changed
166
+ let changed = false;
167
+ function walkDir(dir) {
168
+ try {
169
+ const entries = readdirSync(dir, { withFileTypes: true });
170
+ for (const entry of entries) {
171
+ const fullPath = join(dir, entry.name);
172
+ // Skip common directories
173
+ if (entry.isDirectory()) {
174
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist') {
175
+ continue;
176
+ }
177
+ walkDir(fullPath);
178
+ }
179
+ else if (entry.isFile()) {
180
+ if (extensions.some(ext => entry.name.endsWith(ext))) {
181
+ const stat = statSync(fullPath);
182
+ const modTime = stat.mtimeMs;
183
+ const lastMod = fileModTimes.get(fullPath);
184
+ if (lastMod === undefined) {
185
+ fileModTimes.set(fullPath, modTime);
186
+ }
187
+ else if (modTime > lastMod) {
188
+ fileModTimes.set(fullPath, modTime);
189
+ output.info(`\nFile changed: ${fullPath}`);
190
+ changed = true;
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ catch (error) {
197
+ if (verbose) {
198
+ output.error(`Warning: Error scanning ${dir}: ` + (error instanceof Error ? error.message : String(error)));
199
+ }
200
+ }
201
+ }
202
+ walkDir(watchPath);
203
+ return changed;
204
+ }
205
+ // Initial test run
206
+ await runTest();
207
+ output.info('\nWatching for changes... (Press Ctrl+C to exit)\n');
208
+ // Track current interval for proper cleanup
209
+ let currentInterval = null;
210
+ let isRunningInterview = false;
211
+ /**
212
+ * Poll for file changes and run test when changes detected.
213
+ */
214
+ async function pollForChanges() {
215
+ if (isRunningInterview) {
216
+ return;
217
+ }
218
+ try {
219
+ if (checkForChanges()) {
220
+ isRunningInterview = true;
221
+ await runTest();
222
+ output.info('\nWatching for changes... (Press Ctrl+C to exit)\n');
223
+ }
224
+ }
225
+ catch (error) {
226
+ output.error('Watch polling error: ' + (error instanceof Error ? error.message : String(error)));
227
+ }
228
+ finally {
229
+ isRunningInterview = false;
230
+ }
231
+ }
232
+ // Start polling interval
233
+ currentInterval = setInterval(() => {
234
+ pollForChanges().catch((error) => {
235
+ output.error('Unexpected polling error: ' + (error instanceof Error ? error.message : String(error)));
236
+ });
237
+ }, interval);
238
+ // Handle exit
239
+ const cleanup = () => {
240
+ output.info('\n\nExiting watch mode.');
241
+ if (currentInterval) {
242
+ clearInterval(currentInterval);
243
+ currentInterval = null;
244
+ }
245
+ // Remove signal handlers to prevent accumulation
246
+ process.removeListener('SIGINT', cleanup);
247
+ process.removeListener('SIGTERM', cleanup);
248
+ process.exit(EXIT_CODES.CLEAN);
249
+ };
250
+ process.on('SIGINT', cleanup);
251
+ process.on('SIGTERM', cleanup);
252
+ });
253
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ import { config } from 'dotenv';
3
+ import { existsSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { homedir } from 'os';
6
+ // Load global ~/.bellwether/.env first (if exists)
7
+ const globalEnvPath = join(homedir(), '.bellwether', '.env');
8
+ if (existsSync(globalEnvPath)) {
9
+ config({ path: globalEnvPath });
10
+ }
11
+ // Then load project .env (overrides global settings)
12
+ config();
13
+ // Load credentials from keychain if not already in env
14
+ // This is done async but we await it before parsing commands
15
+ async function loadKeychainCredentials() {
16
+ // Only load from keychain if env vars aren't already set
17
+ if (!process.env.OPENAI_API_KEY || !process.env.ANTHROPIC_API_KEY) {
18
+ try {
19
+ const { getKeychainService } = await import('../auth/keychain.js');
20
+ const keychain = getKeychainService();
21
+ // Load OpenAI key if not in env
22
+ if (!process.env.OPENAI_API_KEY) {
23
+ const key = await keychain.getApiKey('openai');
24
+ if (key) {
25
+ process.env.OPENAI_API_KEY = key;
26
+ }
27
+ }
28
+ // Load Anthropic key if not in env
29
+ if (!process.env.ANTHROPIC_API_KEY) {
30
+ const key = await keychain.getApiKey('anthropic');
31
+ if (key) {
32
+ process.env.ANTHROPIC_API_KEY = key;
33
+ }
34
+ }
35
+ }
36
+ catch {
37
+ // Keychain not available - continue without it
38
+ }
39
+ }
40
+ }
41
+ import { Command } from 'commander';
42
+ import { checkCommand } from './commands/check.js';
43
+ import { exploreCommand } from './commands/explore.js';
44
+ import { discoverCommand } from './commands/discover.js';
45
+ import { watchCommand } from './commands/watch.js';
46
+ import { initCommand } from './commands/init.js';
47
+ import { authCommand } from './commands/auth.js';
48
+ import { baselineCommand } from './commands/baseline.js';
49
+ import { goldenCommand } from './commands/golden.js';
50
+ import { registryCommand } from './commands/registry.js';
51
+ import { verifyCommand } from './commands/verify.js';
52
+ import { contractCommand } from './commands/contract.js';
53
+ import { validateConfigCommand } from './commands/validate-config.js';
54
+ import { badgeCommand } from './commands/cloud/badge.js';
55
+ import { diffCommand } from './commands/cloud/diff.js';
56
+ import { historyCommand } from './commands/cloud/history.js';
57
+ import { linkCommand } from './commands/cloud/link.js';
58
+ import { loginCommand } from './commands/cloud/login.js';
59
+ import { projectsCommand } from './commands/cloud/projects.js';
60
+ import { teamsCommand } from './commands/cloud/teams.js';
61
+ import { uploadCommand } from './commands/cloud/upload.js';
62
+ import { configureLogger } from '../logging/logger.js';
63
+ import { VERSION } from '../version.js';
64
+ import { findConfigFile } from '../config/validator.js';
65
+ import { ConfigNotFoundError } from '../config/loader.js';
66
+ import { EXIT_CODES, PATHS } from '../constants.js';
67
+ const program = new Command();
68
+ // ASCII art banner for help
69
+ const banner = `
70
+ Bellwether - MCP Server Validation & Documentation
71
+ `;
72
+ // Extended help with examples
73
+ const examples = `
74
+ Examples:
75
+
76
+ Initialize configuration:
77
+ $ bellwether init # Create bellwether.yaml
78
+ $ bellwether init --preset ci # Optimized for CI/CD
79
+ $ bellwether init --preset local # Local LLM with Ollama
80
+
81
+ Check for drift (free, fast, deterministic):
82
+ $ bellwether check npx @mcp/my-server # Validate schemas
83
+ $ bellwether baseline save # Save baseline
84
+ $ bellwether baseline compare ./bellwether-baseline.json # Detect drift
85
+
86
+ Explore behavior (LLM-powered):
87
+ $ bellwether explore npx @mcp/my-server # Generate AGENTS.md documentation
88
+
89
+ Discover server capabilities:
90
+ $ bellwether discover npx @mcp/server-postgres
91
+
92
+ Search MCP Registry:
93
+ $ bellwether registry filesystem
94
+
95
+ Cloud workflow:
96
+ $ bellwether login # Authenticate with Bellwether Cloud
97
+ $ bellwether teams # List your teams
98
+ $ bellwether link my-project # Link to cloud project
99
+ $ bellwether upload # Upload baseline
100
+ $ bellwether history # View version history
101
+
102
+ Documentation: https://docs.bellwether.sh
103
+ `;
104
+ program
105
+ .name('bellwether')
106
+ .description(`${banner}
107
+ Check MCP servers for drift. Explore behavior. Generate documentation.
108
+
109
+ Commands:
110
+ check - Schema validation and drift detection (free, fast, deterministic)
111
+ explore - LLM-powered behavioral exploration and documentation
112
+
113
+ For more information on a specific command, use:
114
+ bellwether <command> --help`)
115
+ .version(VERSION)
116
+ .option('--log-level <level>', 'Log level: debug, info, warn, error, silent')
117
+ .option('--log-file <path>', 'Write logs to file instead of stderr')
118
+ .hook('preAction', (thisCommand, actionCommand) => {
119
+ const activeCommand = actionCommand ?? thisCommand;
120
+ const commandName = activeCommand.name();
121
+ const opts = activeCommand.opts();
122
+ if (commandName !== 'init' && commandName !== 'validate-config') {
123
+ const configPath = opts.config;
124
+ const found = findConfigFile(configPath);
125
+ if (!found) {
126
+ const searchedPaths = configPath
127
+ ? [configPath]
128
+ : PATHS.CONFIG_FILENAMES.map((name) => join(process.cwd(), name));
129
+ console.error(new ConfigNotFoundError(searchedPaths).message);
130
+ process.exit(EXIT_CODES.ERROR);
131
+ }
132
+ }
133
+ if (opts.logLevel || opts.logFile) {
134
+ process.env.BELLWETHER_LOG_OVERRIDE = '1';
135
+ configureLogger({
136
+ level: opts.logLevel,
137
+ file: opts.logFile,
138
+ });
139
+ }
140
+ })
141
+ .addHelpText('after', examples);
142
+ // Add command groups for better organization
143
+ program.addHelpText('beforeAll', '\nCore Commands:');
144
+ // Core commands - check and explore
145
+ program.addCommand(checkCommand.description('Check MCP server schema and detect drift (free, fast, deterministic)'));
146
+ program.addCommand(exploreCommand.description('Explore MCP server behavior with LLM-powered testing'));
147
+ program.addCommand(watchCommand.description('Watch for MCP server changes and auto-check'));
148
+ program.addCommand(discoverCommand.description('Discover MCP server capabilities (tools, prompts, resources)'));
149
+ program.addCommand(initCommand.description('Create a new bellwether.yaml configuration file'));
150
+ program.addCommand(authCommand.description('Manage LLM provider API keys (keychain storage)'));
151
+ program.addCommand(baselineCommand.description('Manage baselines for drift detection (save, compare, show, diff)'));
152
+ program.addCommand(goldenCommand.description('Manage golden outputs for tool validation (save, compare, list, delete)'));
153
+ program.addCommand(registryCommand.description('Search the MCP Registry for servers'));
154
+ program.addCommand(verifyCommand.description('Generate verification report for Verified by Bellwether program'));
155
+ program.addCommand(contractCommand.description('Validate MCP servers against contract definitions (validate, generate, show)'));
156
+ program.addCommand(validateConfigCommand.description('Validate bellwether.yaml configuration (no tests)'));
157
+ // Cloud commands - sync with Bellwether Cloud
158
+ program.addCommand(loginCommand.description('Authenticate with Bellwether Cloud'));
159
+ program.addCommand(teamsCommand.description('Manage team selection for cloud operations'));
160
+ program.addCommand(linkCommand.description('Link local project to Bellwether Cloud project'));
161
+ program.addCommand(projectsCommand.description('List your Bellwether Cloud projects'));
162
+ program.addCommand(uploadCommand.description('Upload baseline to Bellwether Cloud'));
163
+ program.addCommand(historyCommand.description('View baseline version history'));
164
+ program.addCommand(diffCommand.description('Compare two baseline versions'));
165
+ program.addCommand(badgeCommand.description('Get embeddable verification badge for your project'));
166
+ // Custom help formatting
167
+ program.configureHelp({
168
+ sortSubcommands: false, // Keep our custom order
169
+ subcommandTerm: (cmd) => cmd.name() + ' ' + cmd.usage(),
170
+ });
171
+ // Load keychain credentials, then parse commands
172
+ loadKeychainCredentials().then(() => {
173
+ program.parse();
174
+ }).catch(() => {
175
+ // If keychain loading fails, still parse commands
176
+ program.parse();
177
+ });
178
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Interactive mode utilities for CLI commands.
3
+ *
4
+ * Provides user prompts for server command, persona selection,
5
+ * output format, and test control.
6
+ */
7
+ import type { BellwetherConfig } from '../config/loader.js';
8
+ /**
9
+ * Interactive configuration gathered from prompts.
10
+ */
11
+ export interface InteractiveConfig {
12
+ serverCommand: string;
13
+ serverArgs: string[];
14
+ selectedPersonas: string[];
15
+ outputFormat: 'markdown' | 'json' | 'both';
16
+ outputDir: string;
17
+ saveBaseline: boolean;
18
+ baselinePath?: string;
19
+ compareBaseline?: string;
20
+ maxQuestions?: number;
21
+ }
22
+ /**
23
+ * Prompt user for interactive configuration.
24
+ */
25
+ export declare function promptForConfig(existingConfig: BellwetherConfig, providedCommand?: string, providedArgs?: string[]): Promise<InteractiveConfig>;
26
+ /**
27
+ * Pause controller for mid-test pause/resume.
28
+ */
29
+ export interface PauseController {
30
+ isPaused: boolean;
31
+ pause(): void;
32
+ resume(): void;
33
+ waitIfPaused(): Promise<void>;
34
+ }
35
+ /**
36
+ * Create a pause controller for test control.
37
+ */
38
+ export declare function createPauseController(): PauseController;
39
+ /**
40
+ * Setup keyboard listener for pause/resume during test.
41
+ */
42
+ export declare function setupInteractiveKeyboard(controller: PauseController): () => void;
43
+ /**
44
+ * Display a summary of the interactive configuration.
45
+ */
46
+ export declare function displayConfigSummary(config: InteractiveConfig): void;
47
+ //# sourceMappingURL=interactive.d.ts.map