@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,64 @@
1
+ /**
2
+ * Credential resolution - unified API key retrieval from multiple sources.
3
+ *
4
+ * Resolution order (highest to lowest priority):
5
+ * 1. Direct config (apiKey in config)
6
+ * 2. Custom environment variable (apiKeyEnvVar in config)
7
+ * 3. Standard environment variable (OPENAI_API_KEY, ANTHROPIC_API_KEY)
8
+ * 4. Project .env file (./env in current working directory)
9
+ * 5. Global .env file (~/.bellwether/.env)
10
+ * 6. System keychain (via bellwether auth)
11
+ */
12
+ import type { LLMProviderId, LLMConfig } from '../llm/client.js';
13
+ /**
14
+ * Default environment variable names for each provider.
15
+ */
16
+ export declare const DEFAULT_ENV_VARS: Record<LLMProviderId, string>;
17
+ /**
18
+ * Result of credential resolution.
19
+ */
20
+ export interface CredentialResult {
21
+ apiKey: string | undefined;
22
+ source: 'config' | 'env' | 'project-env' | 'global-env' | 'keychain' | 'none';
23
+ envVar?: string;
24
+ envFile?: string;
25
+ }
26
+ /**
27
+ * Resolve API key from all available sources.
28
+ *
29
+ * Resolution order (highest to lowest priority):
30
+ * 1. Direct config (apiKey in config)
31
+ * 2. Custom environment variable (apiKeyEnvVar in config)
32
+ * 3. Standard environment variable (OPENAI_API_KEY, ANTHROPIC_API_KEY)
33
+ * 4. Project .env file (./env in current working directory)
34
+ * 5. Global .env file (~/.bellwether/.env)
35
+ * 6. System keychain (via bellwether auth)
36
+ *
37
+ * @param config - LLM configuration
38
+ * @returns The resolved API key and its source
39
+ */
40
+ export declare function resolveCredentials(config: Pick<LLMConfig, 'provider' | 'apiKey' | 'apiKeyEnvVar'>): Promise<CredentialResult>;
41
+ /**
42
+ * Synchronous API key resolution (for backward compatibility).
43
+ * Does NOT check keychain - use resolveCredentials for full resolution.
44
+ */
45
+ export declare function resolveApiKeySync(config: Pick<LLMConfig, 'provider' | 'apiKey' | 'apiKeyEnvVar'>): string | undefined;
46
+ /**
47
+ * Check if credentials are available for a provider.
48
+ */
49
+ export declare function hasCredentials(provider: LLMProviderId): Promise<boolean>;
50
+ /**
51
+ * Get a description of where credentials are configured.
52
+ */
53
+ export declare function describeCredentialSource(provider: LLMProviderId): Promise<string>;
54
+ /**
55
+ * Get authentication status for all providers.
56
+ */
57
+ export interface AuthStatus {
58
+ provider: LLMProviderId;
59
+ configured: boolean;
60
+ source: CredentialResult['source'];
61
+ envVar?: string;
62
+ }
63
+ export declare function getAuthStatus(): Promise<AuthStatus[]>;
64
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Credential resolution - unified API key retrieval from multiple sources.
3
+ *
4
+ * Resolution order (highest to lowest priority):
5
+ * 1. Direct config (apiKey in config)
6
+ * 2. Custom environment variable (apiKeyEnvVar in config)
7
+ * 3. Standard environment variable (OPENAI_API_KEY, ANTHROPIC_API_KEY)
8
+ * 4. Project .env file (./env in current working directory)
9
+ * 5. Global .env file (~/.bellwether/.env)
10
+ * 6. System keychain (via bellwether auth)
11
+ */
12
+ import { existsSync, readFileSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { homedir } from 'os';
15
+ import { getKeychainService } from './keychain.js';
16
+ /**
17
+ * Default environment variable names for each provider.
18
+ */
19
+ export const DEFAULT_ENV_VARS = {
20
+ openai: 'OPENAI_API_KEY',
21
+ anthropic: 'ANTHROPIC_API_KEY',
22
+ ollama: '', // Ollama doesn't need an API key
23
+ };
24
+ /**
25
+ * Read a specific environment variable from a .env file.
26
+ * Returns undefined if the file doesn't exist or the variable isn't found.
27
+ */
28
+ function readEnvFile(filePath, envVar) {
29
+ try {
30
+ if (!existsSync(filePath)) {
31
+ return undefined;
32
+ }
33
+ const content = readFileSync(filePath, 'utf-8');
34
+ const lines = content.split('\n');
35
+ for (const line of lines) {
36
+ const trimmed = line.trim();
37
+ // Skip empty lines and comments
38
+ if (!trimmed || trimmed.startsWith('#')) {
39
+ continue;
40
+ }
41
+ // Parse KEY=VALUE format
42
+ const eqIndex = trimmed.indexOf('=');
43
+ if (eqIndex === -1) {
44
+ continue;
45
+ }
46
+ const key = trimmed.substring(0, eqIndex).trim();
47
+ if (key !== envVar) {
48
+ continue;
49
+ }
50
+ let value = trimmed.substring(eqIndex + 1).trim();
51
+ // Remove surrounding quotes if present
52
+ if ((value.startsWith('"') && value.endsWith('"')) ||
53
+ (value.startsWith("'") && value.endsWith("'"))) {
54
+ value = value.slice(1, -1);
55
+ }
56
+ if (value) {
57
+ return value;
58
+ }
59
+ }
60
+ return undefined;
61
+ }
62
+ catch {
63
+ // File read error - return undefined
64
+ return undefined;
65
+ }
66
+ }
67
+ /**
68
+ * Get the path to the global Bellwether .env file.
69
+ */
70
+ function getGlobalEnvPath() {
71
+ return join(homedir(), '.bellwether', '.env');
72
+ }
73
+ /**
74
+ * Get the path to the project .env file.
75
+ */
76
+ function getProjectEnvPath() {
77
+ return join(process.cwd(), '.env');
78
+ }
79
+ /**
80
+ * Resolve API key from all available sources.
81
+ *
82
+ * Resolution order (highest to lowest priority):
83
+ * 1. Direct config (apiKey in config)
84
+ * 2. Custom environment variable (apiKeyEnvVar in config)
85
+ * 3. Standard environment variable (OPENAI_API_KEY, ANTHROPIC_API_KEY)
86
+ * 4. Project .env file (./env in current working directory)
87
+ * 5. Global .env file (~/.bellwether/.env)
88
+ * 6. System keychain (via bellwether auth)
89
+ *
90
+ * @param config - LLM configuration
91
+ * @returns The resolved API key and its source
92
+ */
93
+ export async function resolveCredentials(config) {
94
+ // 1. Direct config
95
+ if (config.apiKey) {
96
+ return { apiKey: config.apiKey, source: 'config' };
97
+ }
98
+ // 2. Custom environment variable
99
+ if (config.apiKeyEnvVar) {
100
+ const key = process.env[config.apiKeyEnvVar];
101
+ if (key) {
102
+ return { apiKey: key, source: 'env', envVar: config.apiKeyEnvVar };
103
+ }
104
+ }
105
+ // 3. Standard environment variable (already in process.env)
106
+ const defaultEnvVar = DEFAULT_ENV_VARS[config.provider];
107
+ if (defaultEnvVar) {
108
+ const key = process.env[defaultEnvVar];
109
+ if (key) {
110
+ return { apiKey: key, source: 'env', envVar: defaultEnvVar };
111
+ }
112
+ }
113
+ // 4. Project .env file
114
+ if (defaultEnvVar) {
115
+ const projectEnvPath = getProjectEnvPath();
116
+ const key = readEnvFile(projectEnvPath, defaultEnvVar);
117
+ if (key) {
118
+ return { apiKey: key, source: 'project-env', envVar: defaultEnvVar, envFile: projectEnvPath };
119
+ }
120
+ }
121
+ // 5. Global .env file (~/.bellwether/.env)
122
+ if (defaultEnvVar) {
123
+ const globalEnvPath = getGlobalEnvPath();
124
+ const key = readEnvFile(globalEnvPath, defaultEnvVar);
125
+ if (key) {
126
+ return { apiKey: key, source: 'global-env', envVar: defaultEnvVar, envFile: globalEnvPath };
127
+ }
128
+ }
129
+ // 6. System keychain
130
+ if (config.provider !== 'ollama') {
131
+ try {
132
+ const keychain = getKeychainService();
133
+ const key = await keychain.getApiKey(config.provider);
134
+ if (key) {
135
+ return { apiKey: key, source: 'keychain' };
136
+ }
137
+ }
138
+ catch {
139
+ // Keychain not available
140
+ }
141
+ }
142
+ return { apiKey: undefined, source: 'none' };
143
+ }
144
+ /**
145
+ * Synchronous API key resolution (for backward compatibility).
146
+ * Does NOT check keychain - use resolveCredentials for full resolution.
147
+ */
148
+ export function resolveApiKeySync(config) {
149
+ if (config.apiKey) {
150
+ return config.apiKey;
151
+ }
152
+ if (config.apiKeyEnvVar) {
153
+ const key = process.env[config.apiKeyEnvVar];
154
+ if (key)
155
+ return key;
156
+ }
157
+ const defaultEnvVar = DEFAULT_ENV_VARS[config.provider];
158
+ if (defaultEnvVar) {
159
+ return process.env[defaultEnvVar];
160
+ }
161
+ return undefined;
162
+ }
163
+ /**
164
+ * Check if credentials are available for a provider.
165
+ */
166
+ export async function hasCredentials(provider) {
167
+ if (provider === 'ollama') {
168
+ return true; // Ollama doesn't need credentials
169
+ }
170
+ const result = await resolveCredentials({ provider });
171
+ return result.source !== 'none';
172
+ }
173
+ /**
174
+ * Get a description of where credentials are configured.
175
+ */
176
+ export async function describeCredentialSource(provider) {
177
+ if (provider === 'ollama') {
178
+ return 'Ollama (no API key required)';
179
+ }
180
+ const result = await resolveCredentials({ provider });
181
+ switch (result.source) {
182
+ case 'config':
183
+ return 'Provided in configuration';
184
+ case 'env':
185
+ return `Environment variable: ${result.envVar}`;
186
+ case 'project-env':
187
+ return `Project .env file: ${result.envFile}`;
188
+ case 'global-env':
189
+ return `Global .env file: ${result.envFile}`;
190
+ case 'keychain':
191
+ return 'System keychain';
192
+ case 'none':
193
+ return 'Not configured';
194
+ }
195
+ }
196
+ export async function getAuthStatus() {
197
+ const providers = ['openai', 'anthropic', 'ollama'];
198
+ const results = [];
199
+ for (const provider of providers) {
200
+ if (provider === 'ollama') {
201
+ results.push({
202
+ provider,
203
+ configured: true,
204
+ source: 'none', // Ollama doesn't use credentials
205
+ });
206
+ continue;
207
+ }
208
+ const creds = await resolveCredentials({ provider });
209
+ results.push({
210
+ provider,
211
+ configured: creds.source !== 'none',
212
+ source: creds.source,
213
+ envVar: creds.envVar,
214
+ });
215
+ }
216
+ return results;
217
+ }
218
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Authentication module - secure credential management.
3
+ */
4
+ export { KeychainService, getKeychainService, type KeychainBackend, } from './keychain.js';
5
+ export { resolveCredentials, resolveApiKeySync, hasCredentials, describeCredentialSource, getAuthStatus, DEFAULT_ENV_VARS, type CredentialResult, type AuthStatus, } from './credentials.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Authentication module - secure credential management.
3
+ */
4
+ export { KeychainService, getKeychainService, } from './keychain.js';
5
+ export { resolveCredentials, resolveApiKeySync, hasCredentials, describeCredentialSource, getAuthStatus, DEFAULT_ENV_VARS, } from './credentials.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Cross-platform keychain service for secure credential storage.
3
+ *
4
+ * Uses the system keychain:
5
+ * - macOS: Keychain
6
+ * - Windows: Credential Manager
7
+ * - Linux: Secret Service (libsecret)
8
+ *
9
+ * Gracefully degrades if keychain is unavailable (e.g., CI environments).
10
+ */
11
+ import type { LLMProviderId } from '../llm/client.js';
12
+ /**
13
+ * Keychain interface - can be implemented by different backends.
14
+ */
15
+ export interface KeychainBackend {
16
+ getPassword(service: string, account: string): Promise<string | null>;
17
+ setPassword(service: string, account: string, password: string): Promise<void>;
18
+ deletePassword(service: string, account: string): Promise<boolean>;
19
+ }
20
+ /**
21
+ * Keychain service - manages API key storage.
22
+ */
23
+ export declare class KeychainService {
24
+ private backend;
25
+ private useFileBackend;
26
+ constructor();
27
+ /**
28
+ * Check if secure keychain (keytar) is available.
29
+ */
30
+ isSecureKeychainAvailable(): Promise<boolean>;
31
+ /**
32
+ * Get the backend being used.
33
+ */
34
+ getBackendType(): Promise<'keychain' | 'file'>;
35
+ /**
36
+ * Enable file-based fallback explicitly.
37
+ */
38
+ enableFileBackend(): void;
39
+ /**
40
+ * Get API key for a provider from keychain.
41
+ */
42
+ getApiKey(provider: LLMProviderId): Promise<string | null>;
43
+ /**
44
+ * Store API key for a provider in keychain.
45
+ */
46
+ setApiKey(provider: LLMProviderId, apiKey: string): Promise<void>;
47
+ /**
48
+ * Delete API key for a provider from keychain.
49
+ */
50
+ deleteApiKey(provider: LLMProviderId): Promise<boolean>;
51
+ /**
52
+ * Get all stored credentials (without values, just which providers have keys).
53
+ */
54
+ getStoredProviders(): Promise<LLMProviderId[]>;
55
+ /**
56
+ * Clear all stored credentials.
57
+ */
58
+ clearAll(): Promise<void>;
59
+ }
60
+ /**
61
+ * Get the keychain service instance.
62
+ */
63
+ export declare function getKeychainService(): KeychainService;
64
+ //# sourceMappingURL=keychain.d.ts.map
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Cross-platform keychain service for secure credential storage.
3
+ *
4
+ * Uses the system keychain:
5
+ * - macOS: Keychain
6
+ * - Windows: Credential Manager
7
+ * - Linux: Secret Service (libsecret)
8
+ *
9
+ * Gracefully degrades if keychain is unavailable (e.g., CI environments).
10
+ */
11
+ import { homedir } from 'os';
12
+ import { join } from 'path';
13
+ import { createRequire } from 'module';
14
+ // Create require function for loading CommonJS optional dependencies in ESM
15
+ const require = createRequire(import.meta.url);
16
+ // Service name for keychain entries
17
+ const SERVICE_NAME = 'bellwether';
18
+ // Account names for each provider
19
+ const PROVIDER_ACCOUNTS = {
20
+ openai: 'openai-api-key',
21
+ anthropic: 'anthropic-api-key',
22
+ ollama: 'ollama', // Ollama doesn't use API keys, but included for completeness
23
+ };
24
+ /**
25
+ * Keytar-based keychain backend (requires keytar package).
26
+ */
27
+ class KeytarBackend {
28
+ keytar = null;
29
+ initPromise = null;
30
+ async init() {
31
+ if (this.initPromise) {
32
+ return this.initPromise;
33
+ }
34
+ this.initPromise = (async () => {
35
+ try {
36
+ // Dynamic import to avoid requiring keytar if not installed
37
+ // Using require() for optional dependency
38
+ this.keytar = require('keytar');
39
+ }
40
+ catch {
41
+ // keytar not available - will use fallback
42
+ this.keytar = null;
43
+ }
44
+ })();
45
+ return this.initPromise;
46
+ }
47
+ async getPassword(service, account) {
48
+ await this.init();
49
+ if (!this.keytar)
50
+ return null;
51
+ return this.keytar.getPassword(service, account);
52
+ }
53
+ async setPassword(service, account, password) {
54
+ await this.init();
55
+ if (!this.keytar) {
56
+ throw new Error('Keychain not available. Install keytar: npm install keytar\n' +
57
+ 'Or use environment variables instead.');
58
+ }
59
+ await this.keytar.setPassword(service, account, password);
60
+ }
61
+ async deletePassword(service, account) {
62
+ await this.init();
63
+ if (!this.keytar)
64
+ return false;
65
+ return this.keytar.deletePassword(service, account);
66
+ }
67
+ }
68
+ /**
69
+ * File-based fallback for environments without keychain access.
70
+ * Stores credentials in ~/.bellwether/credentials (with restrictive permissions).
71
+ *
72
+ * NOTE: This is less secure than system keychain but better than nothing.
73
+ * Credentials are stored in plain text but with 0600 permissions.
74
+ */
75
+ class FileBackend {
76
+ credentialsPath;
77
+ credentials = null;
78
+ constructor() {
79
+ this.credentialsPath = join(homedir(), '.bellwether', 'credentials.json');
80
+ }
81
+ async load() {
82
+ if (this.credentials)
83
+ return this.credentials;
84
+ const fs = await import('fs');
85
+ try {
86
+ if (fs.existsSync(this.credentialsPath)) {
87
+ const content = fs.readFileSync(this.credentialsPath, 'utf-8');
88
+ this.credentials = JSON.parse(content);
89
+ }
90
+ else {
91
+ this.credentials = {};
92
+ }
93
+ }
94
+ catch {
95
+ this.credentials = {};
96
+ }
97
+ return this.credentials;
98
+ }
99
+ async save() {
100
+ const fs = await import('fs');
101
+ const path = await import('path');
102
+ const os = await import('os');
103
+ const dir = path.join(os.homedir(), '.bellwether');
104
+ if (!fs.existsSync(dir)) {
105
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
106
+ }
107
+ fs.writeFileSync(this.credentialsPath, JSON.stringify(this.credentials, null, 2), { mode: 0o600 });
108
+ }
109
+ async getPassword(service, account) {
110
+ const creds = await this.load();
111
+ return creds[service]?.[account] ?? null;
112
+ }
113
+ async setPassword(service, account, password) {
114
+ const creds = await this.load();
115
+ if (!creds[service]) {
116
+ creds[service] = {};
117
+ }
118
+ creds[service][account] = password;
119
+ await this.save();
120
+ }
121
+ async deletePassword(service, account) {
122
+ const creds = await this.load();
123
+ if (creds[service]?.[account]) {
124
+ delete creds[service][account];
125
+ if (Object.keys(creds[service]).length === 0) {
126
+ delete creds[service];
127
+ }
128
+ await this.save();
129
+ return true;
130
+ }
131
+ return false;
132
+ }
133
+ }
134
+ /**
135
+ * Keychain service - manages API key storage.
136
+ */
137
+ export class KeychainService {
138
+ backend;
139
+ useFileBackend = false;
140
+ constructor() {
141
+ // Try keytar first, fall back to file-based storage
142
+ this.backend = new KeytarBackend();
143
+ }
144
+ /**
145
+ * Check if secure keychain (keytar) is available.
146
+ */
147
+ async isSecureKeychainAvailable() {
148
+ try {
149
+ // Try to access keytar using require
150
+ require('keytar');
151
+ return true;
152
+ }
153
+ catch {
154
+ return false;
155
+ }
156
+ }
157
+ /**
158
+ * Get the backend being used.
159
+ */
160
+ async getBackendType() {
161
+ if (await this.isSecureKeychainAvailable()) {
162
+ return 'keychain';
163
+ }
164
+ return 'file';
165
+ }
166
+ /**
167
+ * Enable file-based fallback explicitly.
168
+ */
169
+ enableFileBackend() {
170
+ this.backend = new FileBackend();
171
+ this.useFileBackend = true;
172
+ }
173
+ /**
174
+ * Get API key for a provider from keychain.
175
+ */
176
+ async getApiKey(provider) {
177
+ const account = PROVIDER_ACCOUNTS[provider];
178
+ if (!account || provider === 'ollama') {
179
+ return null;
180
+ }
181
+ try {
182
+ return await this.backend.getPassword(SERVICE_NAME, account);
183
+ }
184
+ catch {
185
+ // If keytar fails, try file backend
186
+ if (!this.useFileBackend) {
187
+ this.enableFileBackend();
188
+ return await this.backend.getPassword(SERVICE_NAME, account);
189
+ }
190
+ return null;
191
+ }
192
+ }
193
+ /**
194
+ * Store API key for a provider in keychain.
195
+ */
196
+ async setApiKey(provider, apiKey) {
197
+ const account = PROVIDER_ACCOUNTS[provider];
198
+ if (!account || provider === 'ollama') {
199
+ throw new Error(`Provider ${provider} does not use API keys`);
200
+ }
201
+ try {
202
+ await this.backend.setPassword(SERVICE_NAME, account, apiKey);
203
+ }
204
+ catch (error) {
205
+ // If keytar fails, try file backend
206
+ if (!this.useFileBackend) {
207
+ this.enableFileBackend();
208
+ await this.backend.setPassword(SERVICE_NAME, account, apiKey);
209
+ }
210
+ else {
211
+ throw error;
212
+ }
213
+ }
214
+ }
215
+ /**
216
+ * Delete API key for a provider from keychain.
217
+ */
218
+ async deleteApiKey(provider) {
219
+ const account = PROVIDER_ACCOUNTS[provider];
220
+ if (!account || provider === 'ollama') {
221
+ return false;
222
+ }
223
+ try {
224
+ return await this.backend.deletePassword(SERVICE_NAME, account);
225
+ }
226
+ catch {
227
+ // If keytar fails, try file backend
228
+ if (!this.useFileBackend) {
229
+ this.enableFileBackend();
230
+ return await this.backend.deletePassword(SERVICE_NAME, account);
231
+ }
232
+ return false;
233
+ }
234
+ }
235
+ /**
236
+ * Get all stored credentials (without values, just which providers have keys).
237
+ */
238
+ async getStoredProviders() {
239
+ const providers = [];
240
+ for (const provider of ['openai', 'anthropic']) {
241
+ const key = await this.getApiKey(provider);
242
+ if (key) {
243
+ providers.push(provider);
244
+ }
245
+ }
246
+ return providers;
247
+ }
248
+ /**
249
+ * Clear all stored credentials.
250
+ */
251
+ async clearAll() {
252
+ for (const provider of ['openai', 'anthropic']) {
253
+ await this.deleteApiKey(provider);
254
+ }
255
+ }
256
+ }
257
+ // Singleton instance
258
+ let keychainService = null;
259
+ /**
260
+ * Get the keychain service instance.
261
+ */
262
+ export function getKeychainService() {
263
+ if (!keychainService) {
264
+ keychainService = new KeychainService();
265
+ }
266
+ return keychainService;
267
+ }
268
+ //# sourceMappingURL=keychain.js.map