@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,721 @@
1
+ /**
2
+ * Rich error analysis with remediation suggestions.
3
+ *
4
+ * This module provides enhanced error analysis capabilities:
5
+ * - HTTP status code parsing and categorization
6
+ * - Root cause inference from error messages
7
+ * - Remediation suggestion generation
8
+ * - Related parameter extraction
9
+ * - Transient error detection
10
+ * - Error trend analysis across baselines
11
+ */
12
+ // ==================== Analysis Functions ====================
13
+ /**
14
+ * Analyze an error message for enhanced information.
15
+ *
16
+ * @param errorMessage - The error message to analyze
17
+ * @param context - Optional context about the test that generated the error
18
+ * @returns Enhanced error analysis with root cause and remediation
19
+ */
20
+ export function analyzeError(errorMessage, context) {
21
+ const httpStatus = extractHttpStatus(errorMessage);
22
+ let statusCategory = categorizeHttpStatus(httpStatus);
23
+ const wasExpected = context?.wasExpected ?? context?.expectedOutcome === 'error';
24
+ // If the error was expected (validation test), recategorize it
25
+ if (wasExpected && (statusCategory === 'client_error_validation' || statusCategory === 'unknown')) {
26
+ statusCategory = 'validation_expected';
27
+ }
28
+ const rootCause = wasExpected
29
+ ? 'Expected validation error from intentional test'
30
+ : inferRootCause(errorMessage, statusCategory);
31
+ const remediation = wasExpected
32
+ ? 'No action needed - this error was intentional to verify input validation'
33
+ : generateRemediation(statusCategory, errorMessage);
34
+ const relatedParameters = extractRelatedParameters(errorMessage);
35
+ const transient = isTransientError(statusCategory, errorMessage);
36
+ // Expected errors have 'info' severity - they're not problems
37
+ const severity = wasExpected ? 'info' : assessErrorSeverity(statusCategory, errorMessage);
38
+ return {
39
+ pattern: {
40
+ category: mapStatusToErrorCategory(statusCategory),
41
+ patternHash: '',
42
+ example: errorMessage,
43
+ count: 1,
44
+ },
45
+ httpStatus,
46
+ statusCategory,
47
+ rootCause,
48
+ remediation,
49
+ relatedParameters,
50
+ transient,
51
+ severity,
52
+ wasExpected,
53
+ };
54
+ }
55
+ /**
56
+ * Analyze multiple error patterns and return enhanced analyses.
57
+ *
58
+ * @param patterns - Array of error patterns to analyze
59
+ * @param defaultContext - Default context to apply to all patterns without individual context
60
+ * @returns Array of enhanced error analyses
61
+ */
62
+ export function analyzeErrorPatterns(patterns, defaultContext) {
63
+ return patterns.map((item) => {
64
+ // Support both plain patterns and patterns with context
65
+ const pattern = 'pattern' in item ? item.pattern : item;
66
+ const context = 'context' in item ? (item.context ?? defaultContext) : defaultContext;
67
+ const analysis = analyzeError(pattern.example, context);
68
+ return {
69
+ ...analysis,
70
+ pattern,
71
+ };
72
+ });
73
+ }
74
+ /**
75
+ * Generate an error analysis summary for a tool.
76
+ *
77
+ * @param toolName - Name of the tool
78
+ * @param patterns - Error patterns for the tool
79
+ * @returns Error analysis summary
80
+ */
81
+ export function generateErrorSummary(toolName, patterns) {
82
+ const analyses = analyzeErrorPatterns(patterns);
83
+ const totalErrors = patterns.reduce((sum, p) => sum + p.count, 0);
84
+ // Find dominant category and build category counts
85
+ const categoryCounts = new Map();
86
+ for (const analysis of analyses) {
87
+ const count = categoryCounts.get(analysis.statusCategory) ?? 0;
88
+ categoryCounts.set(analysis.statusCategory, count + analysis.pattern.count);
89
+ }
90
+ let dominantCategory = 'unknown';
91
+ let maxCount = 0;
92
+ for (const [category, count] of categoryCounts) {
93
+ if (count > maxCount) {
94
+ maxCount = count;
95
+ dominantCategory = category;
96
+ }
97
+ }
98
+ // Count transient and actionable errors
99
+ const transientErrors = analyses.filter((a) => a.transient).reduce((sum, a) => sum + a.pattern.count, 0);
100
+ const actionableCount = analyses.filter((a) => a.remediation && !a.remediation.includes('Review')).length;
101
+ // Collect unique remediations with frequency
102
+ const remediationCounts = new Map();
103
+ for (const analysis of analyses) {
104
+ if (analysis.remediation) {
105
+ const count = remediationCounts.get(analysis.remediation) ?? 0;
106
+ remediationCounts.set(analysis.remediation, count + analysis.pattern.count);
107
+ }
108
+ }
109
+ // Get top remediations sorted by frequency
110
+ const topRemediations = Array.from(remediationCounts.entries())
111
+ .sort((a, b) => b[1] - a[1])
112
+ .slice(0, 5)
113
+ .map(([remediation]) => remediation);
114
+ // Collect root causes with frequency
115
+ const rootCauseCounts = new Map();
116
+ for (const analysis of analyses) {
117
+ if (analysis.rootCause) {
118
+ const count = rootCauseCounts.get(analysis.rootCause) ?? 0;
119
+ rootCauseCounts.set(analysis.rootCause, count + analysis.pattern.count);
120
+ }
121
+ }
122
+ // Get top root causes sorted by frequency
123
+ const topRootCauses = Array.from(rootCauseCounts.entries())
124
+ .sort((a, b) => b[1] - a[1])
125
+ .slice(0, 5)
126
+ .map(([cause]) => cause);
127
+ // Collect all related parameters
128
+ const relatedParamsSet = new Set();
129
+ for (const analysis of analyses) {
130
+ for (const param of analysis.relatedParameters) {
131
+ relatedParamsSet.add(param);
132
+ }
133
+ }
134
+ return {
135
+ tool: toolName,
136
+ totalErrors,
137
+ analyses,
138
+ dominantCategory,
139
+ transientErrors,
140
+ actionableCount,
141
+ remediations: Array.from(remediationCounts.keys()),
142
+ categoryCounts,
143
+ topRootCauses,
144
+ topRemediations,
145
+ relatedParameters: Array.from(relatedParamsSet).slice(0, 10),
146
+ };
147
+ }
148
+ /**
149
+ * Compare error patterns and identify trends.
150
+ *
151
+ * @param previous - Error patterns from previous baseline
152
+ * @param current - Error patterns from current baseline
153
+ * @returns Error trend report
154
+ */
155
+ export function analyzeErrorTrends(previous, current) {
156
+ const trends = [];
157
+ const prevByCategory = new Map();
158
+ const currByCategory = new Map();
159
+ for (const p of previous) {
160
+ prevByCategory.set(p.category, (prevByCategory.get(p.category) ?? 0) + p.count);
161
+ }
162
+ for (const c of current) {
163
+ currByCategory.set(c.category, (currByCategory.get(c.category) ?? 0) + c.count);
164
+ }
165
+ const allCategories = new Set([...prevByCategory.keys(), ...currByCategory.keys()]);
166
+ const increasingCategories = [];
167
+ const decreasingCategories = [];
168
+ const newCategories = [];
169
+ const resolvedCategories = [];
170
+ for (const category of allCategories) {
171
+ const prevCount = prevByCategory.get(category) ?? 0;
172
+ const currCount = currByCategory.get(category) ?? 0;
173
+ let trend;
174
+ let significance;
175
+ let changePercent = 0;
176
+ if (prevCount === 0 && currCount > 0) {
177
+ trend = 'new';
178
+ significance = 'high';
179
+ changePercent = 100;
180
+ newCategories.push(category);
181
+ }
182
+ else if (currCount === 0 && prevCount > 0) {
183
+ trend = 'resolved';
184
+ significance = 'medium';
185
+ changePercent = -100;
186
+ resolvedCategories.push(category);
187
+ }
188
+ else if (prevCount > 0) {
189
+ changePercent = ((currCount - prevCount) / prevCount) * 100;
190
+ if (currCount > prevCount * 1.5) {
191
+ trend = 'increasing';
192
+ significance = 'high';
193
+ increasingCategories.push(category);
194
+ }
195
+ else if (currCount < prevCount * 0.5) {
196
+ trend = 'decreasing';
197
+ significance = 'low';
198
+ decreasingCategories.push(category);
199
+ }
200
+ else {
201
+ trend = 'stable';
202
+ significance = 'low';
203
+ }
204
+ }
205
+ else {
206
+ trend = 'stable';
207
+ significance = 'low';
208
+ }
209
+ trends.push({
210
+ category,
211
+ previousCount: prevCount,
212
+ currentCount: currCount,
213
+ trend,
214
+ significance,
215
+ changePercent: Math.round(changePercent),
216
+ });
217
+ }
218
+ // Filter out stable trends with zero counts
219
+ const significantTrends = trends.filter((t) => t.trend !== 'stable' || t.currentCount > 0);
220
+ // Determine if there's a significant change
221
+ const significantChange = newCategories.length > 0 ||
222
+ increasingCategories.length > 0 ||
223
+ trends.some((t) => t.significance === 'high');
224
+ // Generate summary
225
+ const summary = generateTrendSummary(newCategories, resolvedCategories, increasingCategories, decreasingCategories);
226
+ return {
227
+ trends: significantTrends,
228
+ significantChange,
229
+ summary,
230
+ increasingCategories,
231
+ decreasingCategories,
232
+ newCategories,
233
+ resolvedCategories,
234
+ };
235
+ }
236
+ // ==================== HTTP Status Parsing ====================
237
+ /**
238
+ * Extract HTTP status code from error message.
239
+ *
240
+ * @param message - Error message to parse
241
+ * @returns HTTP status code if found, undefined otherwise
242
+ */
243
+ export function extractHttpStatus(message) {
244
+ // Match patterns like "status code 400", "HTTP 404", "Error 500", "(404)", "[500]"
245
+ const patterns = [
246
+ /status\s*(?:code)?\s*[:\s]?\s*(\d{3})/i,
247
+ /HTTP\s*(?:\/\d\.\d)?\s*(\d{3})/i,
248
+ /Error\s*(\d{3})/i,
249
+ /\[(\d{3})\]/,
250
+ /\((\d{3})\)/,
251
+ /\b([45]\d{2})\b(?:\s+(?:error|bad|not|forbidden|unauthorized|internal))/i,
252
+ ];
253
+ for (const pattern of patterns) {
254
+ const match = message.match(pattern);
255
+ if (match) {
256
+ const status = parseInt(match[1], 10);
257
+ // Validate it's a reasonable HTTP status
258
+ if (status >= 100 && status < 600) {
259
+ return status;
260
+ }
261
+ }
262
+ }
263
+ return undefined;
264
+ }
265
+ /**
266
+ * Categorize HTTP status code into a category.
267
+ *
268
+ * @param status - HTTP status code
269
+ * @returns HTTP status category
270
+ */
271
+ export function categorizeHttpStatus(status) {
272
+ if (!status)
273
+ return 'unknown';
274
+ if (status === 400)
275
+ return 'client_error_validation';
276
+ if (status === 401 || status === 403)
277
+ return 'client_error_auth';
278
+ if (status === 404)
279
+ return 'client_error_not_found';
280
+ if (status === 409)
281
+ return 'client_error_conflict';
282
+ if (status === 429)
283
+ return 'client_error_rate_limit';
284
+ if (status >= 500)
285
+ return 'server_error';
286
+ if (status >= 400)
287
+ return 'client_error_validation';
288
+ return 'unknown';
289
+ }
290
+ // ==================== Root Cause Analysis ====================
291
+ /**
292
+ * Infer root cause from error message and category.
293
+ *
294
+ * @param message - Error message
295
+ * @param category - HTTP status category
296
+ * @returns Root cause description
297
+ */
298
+ export function inferRootCause(message, category) {
299
+ const lower = message.toLowerCase();
300
+ // Check for specific patterns first (most specific)
301
+ if (lower.includes('required') && lower.includes('missing')) {
302
+ return 'Missing required parameter or field';
303
+ }
304
+ if (lower.includes('required')) {
305
+ const paramMatch = message.match(/['"`](\w+)['"`].*(?:is )?required/i);
306
+ if (paramMatch) {
307
+ return `Required parameter "${paramMatch[1]}" is missing`;
308
+ }
309
+ return 'Missing required parameter or field';
310
+ }
311
+ if (lower.includes('missing')) {
312
+ const fieldMatch = message.match(/missing\s+(?:required\s+)?(?:field|parameter|property)?\s*['"`]?(\w+)['"`]?/i);
313
+ if (fieldMatch) {
314
+ return `Missing required field "${fieldMatch[1]}"`;
315
+ }
316
+ return 'Missing required parameter or field';
317
+ }
318
+ if (lower.includes('invalid') && lower.includes('format')) {
319
+ return 'Invalid input format - value does not match expected format';
320
+ }
321
+ if (lower.includes('invalid') && lower.includes('type')) {
322
+ return 'Invalid input type - value type does not match expected type';
323
+ }
324
+ if (lower.includes('invalid') || lower.includes('malformed')) {
325
+ return 'Invalid input format or value';
326
+ }
327
+ if (lower.includes('not found') || lower.includes('does not exist') || lower.includes("doesn't exist")) {
328
+ return 'Referenced resource does not exist';
329
+ }
330
+ if (lower.includes('already exists') || lower.includes('duplicate')) {
331
+ return 'Resource already exists - duplicate creation attempted';
332
+ }
333
+ if (lower.includes('unauthorized') || lower.includes('authentication')) {
334
+ return 'Authentication credentials missing or invalid';
335
+ }
336
+ if (lower.includes('forbidden') || lower.includes('permission') || lower.includes('access denied')) {
337
+ return 'Insufficient permissions for this operation';
338
+ }
339
+ if (lower.includes('rate') || lower.includes('throttl') || lower.includes('too many')) {
340
+ return 'Request rate limit exceeded';
341
+ }
342
+ if (lower.includes('timeout') || lower.includes('timed out')) {
343
+ return 'Operation timed out';
344
+ }
345
+ if (lower.includes('conflict') || lower.includes('concurrent')) {
346
+ return 'Resource state conflict (concurrent modification)';
347
+ }
348
+ if (lower.includes('connection') && (lower.includes('refused') || lower.includes('failed'))) {
349
+ return 'Connection to external service failed';
350
+ }
351
+ if (lower.includes('network') || lower.includes('dns')) {
352
+ return 'Network connectivity issue';
353
+ }
354
+ if (lower.includes('internal') && lower.includes('error')) {
355
+ return 'Internal server error occurred';
356
+ }
357
+ if (lower.includes('unavailable') || lower.includes('maintenance')) {
358
+ return 'Service temporarily unavailable';
359
+ }
360
+ // Fall back to category-based inference
361
+ switch (category) {
362
+ case 'client_error_validation':
363
+ return 'Client request validation failed';
364
+ case 'client_error_auth':
365
+ return 'Authentication or authorization failure';
366
+ case 'client_error_not_found':
367
+ return 'Requested resource not found';
368
+ case 'client_error_conflict':
369
+ return 'Resource conflict detected';
370
+ case 'client_error_rate_limit':
371
+ return 'Rate limit exceeded';
372
+ case 'server_error':
373
+ return 'Server-side error occurred';
374
+ default:
375
+ return 'Unknown error cause';
376
+ }
377
+ }
378
+ // ==================== Remediation Generation ====================
379
+ /**
380
+ * Generate remediation suggestion based on category and message.
381
+ *
382
+ * @param category - HTTP status category
383
+ * @param message - Error message
384
+ * @returns Remediation suggestion
385
+ */
386
+ export function generateRemediation(category, message) {
387
+ const lower = message.toLowerCase();
388
+ // Specific remediations based on message content
389
+ if (lower.includes('required')) {
390
+ const paramMatch = message.match(/['"`](\w+)['"`]/);
391
+ if (paramMatch) {
392
+ return `Ensure the "${paramMatch[1]}" parameter is provided with a valid value`;
393
+ }
394
+ return 'Ensure all required parameters are provided';
395
+ }
396
+ if (lower.includes('invalid') && lower.includes('format')) {
397
+ return 'Verify input format matches the expected pattern (check documentation for format requirements)';
398
+ }
399
+ if (lower.includes('invalid') && lower.includes('type')) {
400
+ return 'Check that parameter types match the schema (string, number, boolean, etc.)';
401
+ }
402
+ if (lower.includes('not found')) {
403
+ const resourceMatch = message.match(/['"`]?(\w+)['"`]?\s+(?:not found|does not exist)/i);
404
+ if (resourceMatch) {
405
+ return `Verify the ${resourceMatch[1]} exists before accessing it`;
406
+ }
407
+ return 'Verify the resource exists before accessing';
408
+ }
409
+ if (lower.includes('already exists')) {
410
+ return 'Check if resource exists before creation, or use upsert if available';
411
+ }
412
+ if (lower.includes('timeout')) {
413
+ return 'Consider increasing timeout or breaking operation into smaller chunks';
414
+ }
415
+ if (lower.includes('rate') || lower.includes('throttl')) {
416
+ return 'Implement exponential backoff and respect rate limits (Retry-After header)';
417
+ }
418
+ // Category-based remediations
419
+ switch (category) {
420
+ case 'client_error_validation':
421
+ return 'Check input parameters against the schema requirements';
422
+ case 'client_error_auth':
423
+ return 'Verify authentication credentials and ensure proper permissions are granted';
424
+ case 'client_error_not_found':
425
+ return 'Verify the resource exists before accessing (check IDs and paths)';
426
+ case 'client_error_conflict':
427
+ return 'Implement optimistic locking or retry with conflict resolution';
428
+ case 'client_error_rate_limit':
429
+ return 'Implement exponential backoff and rate limiting';
430
+ case 'server_error':
431
+ return 'Retry with exponential backoff; contact server administrator if persistent';
432
+ default:
433
+ return 'Review error message and API documentation';
434
+ }
435
+ }
436
+ // ==================== Parameter Extraction ====================
437
+ /**
438
+ * Extract parameter names mentioned in error message.
439
+ *
440
+ * @param message - Error message
441
+ * @returns Array of parameter names
442
+ */
443
+ export function extractRelatedParameters(message) {
444
+ const params = [];
445
+ const seen = new Set();
446
+ // Match quoted strings that look like parameter names
447
+ const quotedMatches = message.matchAll(/['"`](\w+)['"`]/g);
448
+ for (const match of quotedMatches) {
449
+ const param = match[1];
450
+ if (param.length > 1 && param.length < 30 && !seen.has(param)) {
451
+ // Filter out common non-parameter words
452
+ if (!isCommonWord(param)) {
453
+ params.push(param);
454
+ seen.add(param);
455
+ }
456
+ }
457
+ }
458
+ // Match "parameter X" or "field X" patterns
459
+ const paramMatches = message.matchAll(/(?:parameter|field|property|argument|key)\s+['"`]?(\w+)['"`]?/gi);
460
+ for (const match of paramMatches) {
461
+ const param = match[1];
462
+ if (!seen.has(param) && !isCommonWord(param)) {
463
+ params.push(param);
464
+ seen.add(param);
465
+ }
466
+ }
467
+ // Match "X is required" or "missing X" patterns
468
+ const requiredMatches = message.matchAll(/(\w+)\s+(?:is\s+)?(?:required|missing|invalid)/gi);
469
+ for (const match of requiredMatches) {
470
+ const param = match[1].toLowerCase();
471
+ if (param.length > 2 && !seen.has(param) && !isCommonWord(param)) {
472
+ params.push(param);
473
+ seen.add(param);
474
+ }
475
+ }
476
+ return params;
477
+ }
478
+ /**
479
+ * Check if a word is a common English word (not a parameter).
480
+ */
481
+ function isCommonWord(word) {
482
+ const commonWords = new Set([
483
+ 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
484
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
485
+ 'could', 'should', 'may', 'might', 'must', 'shall', 'can',
486
+ 'need', 'not', 'and', 'but', 'or', 'if', 'then', 'else',
487
+ 'for', 'with', 'from', 'this', 'that', 'these', 'those',
488
+ 'error', 'message', 'failed', 'invalid', 'missing', 'required',
489
+ 'found', 'exist', 'exists', 'value', 'input', 'output', 'type',
490
+ 'string', 'number', 'boolean', 'object', 'array', 'null', 'undefined',
491
+ 'field', 'parameter', 'property', 'argument', 'key',
492
+ ]);
493
+ return commonWords.has(word.toLowerCase());
494
+ }
495
+ // ==================== Transient Error Detection ====================
496
+ /**
497
+ * Determine if error is likely transient (temporary).
498
+ *
499
+ * @param category - HTTP status category
500
+ * @param message - Error message
501
+ * @returns Whether the error is likely transient
502
+ */
503
+ export function isTransientError(category, message) {
504
+ const lower = message.toLowerCase();
505
+ // Rate limiting is always transient
506
+ if (category === 'client_error_rate_limit')
507
+ return true;
508
+ // Server errors are usually transient
509
+ if (category === 'server_error')
510
+ return true;
511
+ // Check for transient keywords
512
+ const transientKeywords = [
513
+ 'timeout', 'timed out', 'temporarily', 'retry', 'unavailable',
514
+ 'connection', 'network', 'service unavailable', 'too many requests',
515
+ 'try again', 'overloaded', 'busy', 'maintenance',
516
+ ];
517
+ return transientKeywords.some((keyword) => lower.includes(keyword));
518
+ }
519
+ // ==================== Severity Assessment ====================
520
+ /**
521
+ * Assess error severity based on category and message.
522
+ *
523
+ * @param category - HTTP status category
524
+ * @param message - Error message
525
+ * @returns Error severity level
526
+ */
527
+ export function assessErrorSeverity(category, message) {
528
+ const lower = message.toLowerCase();
529
+ // Critical severity indicators
530
+ if (lower.includes('fatal') || lower.includes('crash') || lower.includes('corrupt')) {
531
+ return 'critical';
532
+ }
533
+ // High severity
534
+ if (category === 'server_error') {
535
+ return 'high';
536
+ }
537
+ if (category === 'client_error_auth') {
538
+ return 'high';
539
+ }
540
+ // Medium severity
541
+ if (category === 'client_error_validation') {
542
+ return 'medium';
543
+ }
544
+ if (category === 'client_error_conflict') {
545
+ return 'medium';
546
+ }
547
+ // Low severity
548
+ if (category === 'client_error_not_found') {
549
+ return 'low';
550
+ }
551
+ if (category === 'client_error_rate_limit') {
552
+ return 'low';
553
+ }
554
+ // Default
555
+ return 'info';
556
+ }
557
+ // ==================== Helper Functions ====================
558
+ /**
559
+ * Map HTTP status category to ErrorPattern category.
560
+ */
561
+ export function mapStatusToErrorCategory(category) {
562
+ switch (category) {
563
+ case 'client_error_validation':
564
+ case 'client_error_conflict':
565
+ case 'client_error_rate_limit':
566
+ return 'validation';
567
+ case 'client_error_not_found':
568
+ return 'not_found';
569
+ case 'client_error_auth':
570
+ return 'permission';
571
+ case 'server_error':
572
+ return 'internal';
573
+ default:
574
+ return 'unknown';
575
+ }
576
+ }
577
+ /**
578
+ * Generate a summary of error trends.
579
+ */
580
+ function generateTrendSummary(newCategories, resolvedCategories, increasingCategories, decreasingCategories) {
581
+ const parts = [];
582
+ if (newCategories.length > 0) {
583
+ parts.push(`${newCategories.length} new error type(s): ${newCategories.join(', ')}`);
584
+ }
585
+ if (resolvedCategories.length > 0) {
586
+ parts.push(`${resolvedCategories.length} resolved: ${resolvedCategories.join(', ')}`);
587
+ }
588
+ if (increasingCategories.length > 0) {
589
+ parts.push(`${increasingCategories.length} increasing: ${increasingCategories.join(', ')}`);
590
+ }
591
+ if (decreasingCategories.length > 0) {
592
+ parts.push(`${decreasingCategories.length} decreasing: ${decreasingCategories.join(', ')}`);
593
+ }
594
+ if (parts.length === 0) {
595
+ return 'Error patterns stable';
596
+ }
597
+ return parts.join('; ');
598
+ }
599
+ // ==================== Formatting Functions ====================
600
+ /**
601
+ * Format enhanced error analysis for display.
602
+ *
603
+ * @param analysis - Enhanced error analysis
604
+ * @param useColors - Whether to use ANSI colors
605
+ * @returns Formatted string
606
+ */
607
+ export function formatEnhancedError(analysis, useColors = false) {
608
+ const lines = [];
609
+ const { yellow, cyan, dim } = useColors ? getColors() : getNoColors();
610
+ // Category and status
611
+ const statusText = analysis.httpStatus ? `HTTP ${analysis.httpStatus}` : 'Unknown status';
612
+ lines.push(`${cyan(formatCategoryName(analysis.statusCategory))} (${statusText})`);
613
+ // Root cause
614
+ lines.push(` ${dim('Cause:')} ${analysis.rootCause}`);
615
+ // Remediation
616
+ lines.push(` ${dim('Fix:')} ${analysis.remediation}`);
617
+ // Related parameters
618
+ if (analysis.relatedParameters.length > 0) {
619
+ lines.push(` ${dim('Parameters:')} ${analysis.relatedParameters.join(', ')}`);
620
+ }
621
+ // Transient indicator
622
+ if (analysis.transient) {
623
+ lines.push(` ${yellow('Transient - may resolve with retry')}`);
624
+ }
625
+ return lines.join('\n');
626
+ }
627
+ /**
628
+ * Format error trend report for display.
629
+ *
630
+ * @param report - Error trend report
631
+ * @param useColors - Whether to use ANSI colors
632
+ * @returns Formatted string
633
+ */
634
+ export function formatErrorTrendReport(report, useColors = false) {
635
+ const lines = [];
636
+ const { red, green, yellow, cyan, dim } = useColors ? getColors() : getNoColors();
637
+ lines.push(cyan('Error Trend Analysis'));
638
+ lines.push('');
639
+ if (!report.significantChange) {
640
+ lines.push(green(' No significant changes in error patterns'));
641
+ return lines.join('\n');
642
+ }
643
+ // New errors (high priority)
644
+ if (report.newCategories.length > 0) {
645
+ lines.push(red(` New error types: ${report.newCategories.join(', ')}`));
646
+ }
647
+ // Resolved errors
648
+ if (report.resolvedCategories.length > 0) {
649
+ lines.push(green(` Resolved: ${report.resolvedCategories.join(', ')}`));
650
+ }
651
+ // Increasing errors
652
+ if (report.increasingCategories.length > 0) {
653
+ lines.push(yellow(` Increasing: ${report.increasingCategories.join(', ')}`));
654
+ }
655
+ // Decreasing errors
656
+ if (report.decreasingCategories.length > 0) {
657
+ lines.push(dim(` Decreasing: ${report.decreasingCategories.join(', ')}`));
658
+ }
659
+ // Trend details
660
+ lines.push('');
661
+ lines.push(' Trend details:');
662
+ for (const trend of report.trends.filter((t) => t.trend !== 'stable')) {
663
+ const arrow = getTrendArrow(trend.trend);
664
+ const changeText = trend.changePercent !== 0 ? ` (${trend.changePercent > 0 ? '+' : ''}${trend.changePercent}%)` : '';
665
+ lines.push(` ${arrow} ${trend.category}: ${trend.previousCount} → ${trend.currentCount}${changeText}`);
666
+ }
667
+ return lines.join('\n');
668
+ }
669
+ /**
670
+ * Format category name for display.
671
+ */
672
+ export function formatCategoryName(category) {
673
+ const names = {
674
+ client_error_validation: 'Validation Error',
675
+ client_error_auth: 'Authentication Error',
676
+ client_error_not_found: 'Not Found',
677
+ client_error_conflict: 'Conflict',
678
+ client_error_rate_limit: 'Rate Limited',
679
+ server_error: 'Server Error',
680
+ validation_expected: 'Expected Validation (Test)',
681
+ unknown: 'Unknown Error',
682
+ };
683
+ return names[category] ?? category;
684
+ }
685
+ /**
686
+ * Get trend arrow for display.
687
+ */
688
+ function getTrendArrow(trend) {
689
+ switch (trend) {
690
+ case 'increasing':
691
+ return '↑';
692
+ case 'decreasing':
693
+ return '↓';
694
+ case 'new':
695
+ return '+';
696
+ case 'resolved':
697
+ return '✓';
698
+ case 'stable':
699
+ return '→';
700
+ }
701
+ }
702
+ function getColors() {
703
+ return {
704
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
705
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
706
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
707
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
708
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
709
+ };
710
+ }
711
+ function getNoColors() {
712
+ const identity = (s) => s;
713
+ return {
714
+ red: identity,
715
+ green: identity,
716
+ yellow: identity,
717
+ cyan: identity,
718
+ dim: identity,
719
+ };
720
+ }
721
+ //# sourceMappingURL=error-analyzer.js.map