@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,374 @@
1
+ /**
2
+ * Authentication module for Bellwether Cloud.
3
+ *
4
+ * Handles session storage, retrieval, and management.
5
+ * Sessions are stored in ~/.bellwether/session.json with restricted permissions.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, statSync, chmodSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir, platform } from 'os';
10
+ import { URLS, PATHS, PATTERNS, CLI_SECURITY } from '../constants.js';
11
+ import { isLocalhost } from '../utils/index.js';
12
+ import * as output from '../cli/output.js';
13
+ /**
14
+ * Directory for bellwether configuration.
15
+ */
16
+ export const CONFIG_DIR = join(homedir(), PATHS.CONFIG_DIR);
17
+ /**
18
+ * Path to session file.
19
+ */
20
+ export const SESSION_FILE = join(CONFIG_DIR, PATHS.SESSION_FILE);
21
+ /**
22
+ * Environment variable name for session token.
23
+ */
24
+ export const SESSION_ENV_VAR = 'BELLWETHER_SESSION';
25
+ /**
26
+ * Environment variable name for API base URL.
27
+ */
28
+ export const BASE_URL_ENV_VAR = 'BELLWETHER_API_URL';
29
+ /**
30
+ * Environment variable name for team ID override.
31
+ */
32
+ export const TEAM_ID_ENV_VAR = 'BELLWETHER_TEAM_ID';
33
+ /**
34
+ * Session token prefix for validation.
35
+ */
36
+ export const SESSION_PREFIX = CLI_SECURITY.SESSION_PREFIX;
37
+ /**
38
+ * Mock session prefix for development.
39
+ */
40
+ export const MOCK_SESSION_PREFIX = CLI_SECURITY.MOCK_SESSION_PREFIX;
41
+ /**
42
+ * Session token pattern: sess_ followed by 64 hex characters.
43
+ * Mock sessions use sess_mock_ prefix with username and hex characters.
44
+ * Format: sess_mock_<username>_<hex>
45
+ */
46
+ const SESSION_TOKEN_PATTERN = PATTERNS.SESSION_TOKEN;
47
+ const MOCK_SESSION_TOKEN_PATTERN = PATTERNS.MOCK_SESSION_TOKEN;
48
+ /**
49
+ * Ensure the config directory exists.
50
+ */
51
+ export function ensureConfigDir() {
52
+ if (!existsSync(CONFIG_DIR)) {
53
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
54
+ }
55
+ }
56
+ /**
57
+ * Verify and fix session file permissions.
58
+ * On Unix systems, ensures file is only readable by owner (0600).
59
+ * Returns false if permissions could not be verified/fixed.
60
+ */
61
+ function verifySessionPermissions() {
62
+ // Skip permission checks on Windows (Windows has different ACL system)
63
+ if (platform() === 'win32') {
64
+ return true;
65
+ }
66
+ try {
67
+ if (!existsSync(SESSION_FILE)) {
68
+ return true; // No file to check
69
+ }
70
+ const stats = statSync(SESSION_FILE);
71
+ const mode = stats.mode & 0o777;
72
+ // Check if permissions are too permissive (anyone other than owner can read)
73
+ if (mode & 0o077) {
74
+ // Try to fix permissions
75
+ try {
76
+ chmodSync(SESSION_FILE, 0o600);
77
+ return true;
78
+ }
79
+ catch {
80
+ // Could not fix permissions
81
+ return false;
82
+ }
83
+ }
84
+ return true;
85
+ }
86
+ catch (error) {
87
+ // If we can't stat the file, there's a real problem
88
+ output.warn(`Warning: Could not verify session file permissions: ${error instanceof Error ? error.message : error}`);
89
+ return false;
90
+ }
91
+ }
92
+ /**
93
+ * Get the stored session.
94
+ * Returns null if no session exists, session is expired, or file is corrupted.
95
+ */
96
+ export function getStoredSession() {
97
+ if (!existsSync(SESSION_FILE)) {
98
+ return null;
99
+ }
100
+ // Verify file permissions before reading sensitive data
101
+ const permissionsOk = verifySessionPermissions();
102
+ if (!permissionsOk) {
103
+ // Permissions are insecure and couldn't be fixed - refuse to use session
104
+ output.error('Error: Session file has insecure permissions. Please fix with:');
105
+ output.error(` chmod 600 ${SESSION_FILE}`);
106
+ return null;
107
+ }
108
+ try {
109
+ const content = readFileSync(SESSION_FILE, 'utf-8');
110
+ const session = JSON.parse(content);
111
+ // Validate and check if session is expired
112
+ if (!session.expiresAt) {
113
+ output.warn('Warning: Session file missing expiration date, clearing it.');
114
+ clearSession();
115
+ return null;
116
+ }
117
+ const expirationDate = new Date(session.expiresAt);
118
+ if (isNaN(expirationDate.getTime())) {
119
+ output.warn('Warning: Session file has invalid expiration date, clearing it.');
120
+ clearSession();
121
+ return null;
122
+ }
123
+ if (expirationDate <= new Date()) {
124
+ // Session expired, clear it
125
+ clearSession();
126
+ return null;
127
+ }
128
+ return session;
129
+ }
130
+ catch {
131
+ // If file is corrupted, log and return null
132
+ output.warn('Warning: Session file is corrupted, clearing it.');
133
+ clearSession();
134
+ return null;
135
+ }
136
+ }
137
+ /**
138
+ * Save session to disk.
139
+ * File is created with 0600 permissions (owner read/write only).
140
+ */
141
+ export function saveSession(session) {
142
+ ensureConfigDir();
143
+ writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2), { mode: 0o600 });
144
+ }
145
+ /**
146
+ * Clear the stored session.
147
+ */
148
+ export function clearSession() {
149
+ if (existsSync(SESSION_FILE)) {
150
+ try {
151
+ unlinkSync(SESSION_FILE);
152
+ }
153
+ catch {
154
+ // Ignore errors
155
+ }
156
+ }
157
+ }
158
+ /**
159
+ * Get the session token.
160
+ *
161
+ * Priority:
162
+ * 1. BELLWETHER_SESSION environment variable
163
+ * 2. Stored session in ~/.bellwether/session.json
164
+ */
165
+ export function getSessionToken() {
166
+ // Check environment variable first
167
+ const envSession = process.env[SESSION_ENV_VAR];
168
+ if (envSession) {
169
+ return envSession;
170
+ }
171
+ // Fall back to stored session
172
+ const session = getStoredSession();
173
+ return session?.sessionToken;
174
+ }
175
+ /**
176
+ * Get the API base URL.
177
+ *
178
+ * Priority:
179
+ * 1. BELLWETHER_API_URL environment variable
180
+ * 2. Default: https://api.bellwether.sh
181
+ *
182
+ * Security: Validates that custom URLs use HTTPS (except localhost for development).
183
+ */
184
+ export function getBaseUrl() {
185
+ // Check environment variable first
186
+ const envUrl = process.env[BASE_URL_ENV_VAR];
187
+ if (envUrl) {
188
+ // Validate URL format and security
189
+ try {
190
+ const url = new URL(envUrl);
191
+ // Allow HTTP only for localhost (development)
192
+ if (url.protocol !== 'https:' && !isLocalhost(url.hostname)) {
193
+ output.warn(`Warning: ${BASE_URL_ENV_VAR} uses insecure HTTP protocol.`);
194
+ output.warn('HTTPS is required for production use to protect authentication tokens.');
195
+ output.warn('Use HTTPS or localhost for secure communication.\n');
196
+ }
197
+ return envUrl;
198
+ }
199
+ catch {
200
+ output.warn(`Warning: Invalid URL in ${BASE_URL_ENV_VAR}: ${envUrl}`);
201
+ output.warn('Falling back to default API URL.\n');
202
+ return URLS.CLOUD_API;
203
+ }
204
+ }
205
+ // Return default
206
+ return URLS.CLOUD_API;
207
+ }
208
+ /**
209
+ * Check if a session token appears valid (strict format check).
210
+ * Validates against exact patterns to prevent injection.
211
+ */
212
+ export function isValidSessionFormat(token) {
213
+ return SESSION_TOKEN_PATTERN.test(token) || MOCK_SESSION_TOKEN_PATTERN.test(token);
214
+ }
215
+ /**
216
+ * Check if a session token is a mock session (for development).
217
+ */
218
+ export function isMockSession(token) {
219
+ return token.startsWith(MOCK_SESSION_PREFIX);
220
+ }
221
+ /**
222
+ * Check if currently authenticated.
223
+ */
224
+ export function isAuthenticated() {
225
+ const token = getSessionToken();
226
+ return token !== undefined && isValidSessionFormat(token);
227
+ }
228
+ /**
229
+ * Get the active team ID.
230
+ *
231
+ * Priority:
232
+ * 1. BELLWETHER_TEAM_ID environment variable
233
+ * 2. Team ID from project link (if in a linked project directory)
234
+ * 3. Active team ID from stored session
235
+ */
236
+ export function getTeamId(projectDir = process.cwd()) {
237
+ // Check environment variable first (for CI/CD)
238
+ const envTeamId = process.env[TEAM_ID_ENV_VAR];
239
+ if (envTeamId) {
240
+ return envTeamId;
241
+ }
242
+ // Check project link for project-specific team
243
+ const projectLink = getLinkedProject(projectDir);
244
+ if (projectLink?.teamId) {
245
+ return projectLink.teamId;
246
+ }
247
+ // Fall back to session's active team
248
+ const session = getStoredSession();
249
+ return session?.activeTeamId;
250
+ }
251
+ /**
252
+ * Get the active team details.
253
+ * Returns the full team object if available.
254
+ */
255
+ export function getActiveTeam(projectDir = process.cwd()) {
256
+ const teamId = getTeamId(projectDir);
257
+ if (!teamId) {
258
+ return undefined;
259
+ }
260
+ const session = getStoredSession();
261
+ return session?.teams?.find(t => t.id === teamId);
262
+ }
263
+ /**
264
+ * Get all teams from the stored session.
265
+ */
266
+ export function getSessionTeams() {
267
+ const session = getStoredSession();
268
+ return session?.teams ?? [];
269
+ }
270
+ /**
271
+ * Set the active team in the stored session.
272
+ * Returns true if successful, false if team not found in session.
273
+ */
274
+ export function setActiveTeam(teamId) {
275
+ const session = getStoredSession();
276
+ if (!session) {
277
+ return false;
278
+ }
279
+ // Verify the team exists in the session
280
+ const teamExists = session.teams?.some(t => t.id === teamId);
281
+ if (!teamExists) {
282
+ return false;
283
+ }
284
+ // Update the active team
285
+ session.activeTeamId = teamId;
286
+ saveSession(session);
287
+ return true;
288
+ }
289
+ /**
290
+ * Update the session token in the stored session.
291
+ * Called when the server rotates the token and returns a new one.
292
+ *
293
+ * @param newToken - The new session token from the server
294
+ * @returns Promise that resolves when the session is updated
295
+ */
296
+ export async function updateSessionToken(newToken) {
297
+ const session = getStoredSession();
298
+ if (!session) {
299
+ // No session to update - this shouldn't happen in normal flow
300
+ return;
301
+ }
302
+ // Validate the new token format
303
+ if (!isValidSessionFormat(newToken)) {
304
+ throw new Error('Invalid session token format received from server');
305
+ }
306
+ // Update the token and record when it was rotated
307
+ session.sessionToken = newToken;
308
+ session.tokenRotatedAt = new Date().toISOString();
309
+ saveSession(session);
310
+ }
311
+ /**
312
+ * Directory name for per-project bellwether config.
313
+ */
314
+ export const PROJECT_CONFIG_DIR = '.bellwether';
315
+ /**
316
+ * File name for project link configuration.
317
+ */
318
+ export const LINK_FILE = 'link.json';
319
+ /**
320
+ * Get the project link file path for a given directory.
321
+ */
322
+ export function getLinkFilePath(projectDir = process.cwd()) {
323
+ return join(projectDir, PROJECT_CONFIG_DIR, LINK_FILE);
324
+ }
325
+ /**
326
+ * Get the linked project for the current directory.
327
+ */
328
+ export function getLinkedProject(projectDir = process.cwd()) {
329
+ const linkFile = getLinkFilePath(projectDir);
330
+ if (!existsSync(linkFile)) {
331
+ return null;
332
+ }
333
+ try {
334
+ const content = readFileSync(linkFile, 'utf-8');
335
+ return JSON.parse(content);
336
+ }
337
+ catch {
338
+ return null;
339
+ }
340
+ }
341
+ /**
342
+ * Save a project link for the current directory.
343
+ */
344
+ export function saveProjectLink(link, projectDir = process.cwd()) {
345
+ const configDir = join(projectDir, PROJECT_CONFIG_DIR);
346
+ if (!existsSync(configDir)) {
347
+ mkdirSync(configDir, { recursive: true });
348
+ }
349
+ const linkFile = getLinkFilePath(projectDir);
350
+ writeFileSync(linkFile, JSON.stringify(link, null, 2));
351
+ }
352
+ /**
353
+ * Remove the project link for the current directory.
354
+ */
355
+ export function removeProjectLink(projectDir = process.cwd()) {
356
+ const linkFile = getLinkFilePath(projectDir);
357
+ if (!existsSync(linkFile)) {
358
+ return false;
359
+ }
360
+ try {
361
+ unlinkSync(linkFile);
362
+ return true;
363
+ }
364
+ catch {
365
+ return false;
366
+ }
367
+ }
368
+ /**
369
+ * Check if the current directory is linked to a project.
370
+ */
371
+ export function isLinked(projectDir = process.cwd()) {
372
+ return getLinkedProject(projectDir) !== null;
373
+ }
374
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Cloud client factory.
3
+ *
4
+ * Creates the appropriate cloud client implementation based on configuration.
5
+ * Supports:
6
+ * - MockCloudClient (local development/testing)
7
+ * - HttpCloudClient (production API)
8
+ */
9
+ import type { BellwetherCloudClient, CloudConfig } from './types.js';
10
+ /**
11
+ * Create a cloud client with the given configuration.
12
+ *
13
+ * If no session token is provided, attempts to get one from environment/storage.
14
+ * Automatically selects mock client for development or HTTP client for production.
15
+ */
16
+ export declare function createCloudClient(config?: Partial<CloudConfig>): BellwetherCloudClient;
17
+ /**
18
+ * Create a cloud client with explicit session token.
19
+ *
20
+ * Convenience function for when you already have a session token.
21
+ */
22
+ export declare function createCloudClientWithSession(sessionToken: string): BellwetherCloudClient;
23
+ export type { BellwetherCloudClient, CloudConfig } from './types.js';
24
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Cloud client factory.
3
+ *
4
+ * Creates the appropriate cloud client implementation based on configuration.
5
+ * Supports:
6
+ * - MockCloudClient (local development/testing)
7
+ * - HttpCloudClient (production API)
8
+ */
9
+ import { MockCloudClient } from './mock-client.js';
10
+ import { HttpCloudClient } from './http-client.js';
11
+ import { getSessionToken, getBaseUrl, isMockSession, getTeamId } from './auth.js';
12
+ import { TIMEOUTS } from '../constants.js';
13
+ /**
14
+ * Create a cloud client with the given configuration.
15
+ *
16
+ * If no session token is provided, attempts to get one from environment/storage.
17
+ * Automatically selects mock client for development or HTTP client for production.
18
+ */
19
+ export function createCloudClient(config) {
20
+ const sessionToken = config?.sessionToken ?? getSessionToken();
21
+ const baseUrl = config?.baseUrl ?? getBaseUrl();
22
+ const timeout = config?.timeout ?? TIMEOUTS.CLOUD_API;
23
+ // Determine which client to use
24
+ const useMock = shouldUseMockClient(sessionToken);
25
+ if (useMock) {
26
+ return new MockCloudClient(sessionToken);
27
+ }
28
+ // Use HTTP client for production
29
+ if (!sessionToken) {
30
+ throw new Error('Session required for HTTP client. Run `bellwether login` first.');
31
+ }
32
+ const teamId = getTeamId();
33
+ return new HttpCloudClient(baseUrl, sessionToken, timeout, teamId);
34
+ }
35
+ /**
36
+ * Determine if we should use the mock client.
37
+ *
38
+ * Uses mock client when:
39
+ * - Session is a mock session (sess_mock_*)
40
+ * - No session is provided (unauthenticated mode)
41
+ *
42
+ * Uses HTTP client when:
43
+ * - A real session is provided (even for localhost - allows local server testing)
44
+ */
45
+ function shouldUseMockClient(sessionToken) {
46
+ // Use mock if session is a mock session
47
+ if (sessionToken && isMockSession(sessionToken)) {
48
+ return true;
49
+ }
50
+ // Use mock if no session (unauthenticated mock mode)
51
+ if (!sessionToken) {
52
+ return true;
53
+ }
54
+ // Use HTTP client for real sessions (works with localhost or production)
55
+ return false;
56
+ }
57
+ /**
58
+ * Create a cloud client with explicit session token.
59
+ *
60
+ * Convenience function for when you already have a session token.
61
+ */
62
+ export function createCloudClientWithSession(sessionToken) {
63
+ return createCloudClient({ sessionToken });
64
+ }
65
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * HTTP cloud client for production API.
3
+ *
4
+ * Makes real HTTP requests to the Bellwether Cloud API.
5
+ * Handles automatic session token rotation when the server returns
6
+ * a new token via the X-Rotated-Session-Token header.
7
+ */
8
+ import type { BellwetherCloudClient, CloudUser, Project, BaselineVersion, UploadResult, DiffSummary, BellwetherBaseline, BadgeInfo, CloudVerificationResult, VerificationSubmissionResult } from './types.js';
9
+ /**
10
+ * HTTP cloud client implementation.
11
+ */
12
+ export declare class HttpCloudClient implements BellwetherCloudClient {
13
+ private baseUrl;
14
+ private sessionToken;
15
+ private teamId?;
16
+ private timeout;
17
+ constructor(baseUrl: string, sessionToken: string, timeout?: number, teamId?: string);
18
+ /**
19
+ * Make an authenticated request.
20
+ * Handles automatic session token rotation when the server returns
21
+ * a new token via the X-Rotated-Session-Token header.
22
+ */
23
+ private request;
24
+ isAuthenticated(): boolean;
25
+ whoami(): Promise<CloudUser | null>;
26
+ listProjects(): Promise<Project[]>;
27
+ createProject(name: string, serverCommand: string): Promise<Project>;
28
+ getProject(projectId: string): Promise<Project | null>;
29
+ deleteProject(projectId: string): Promise<void>;
30
+ uploadBaseline(projectId: string, baseline: BellwetherBaseline): Promise<UploadResult>;
31
+ getHistory(projectId: string, limit?: number): Promise<BaselineVersion[]>;
32
+ getBaseline(baselineId: string): Promise<BellwetherBaseline | null>;
33
+ getDiff(projectId: string, fromVersion: number, toVersion: number): Promise<DiffSummary>;
34
+ getLatestDiff(projectId: string): Promise<DiffSummary | null>;
35
+ getBadgeInfo(projectId: string): Promise<BadgeInfo | null>;
36
+ submitVerification(projectId: string, result: CloudVerificationResult, report?: Record<string, unknown>): Promise<VerificationSubmissionResult>;
37
+ }
38
+ //# sourceMappingURL=http-client.d.ts.map