@yasserkhanorg/e2e-agents 1.8.5 → 1.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 (274) hide show
  1. package/README.md +95 -8
  2. package/dist/adapters/cypress.d.ts +10 -0
  3. package/dist/adapters/cypress.d.ts.map +1 -0
  4. package/dist/adapters/cypress.js +86 -0
  5. package/dist/adapters/framework_adapter.d.ts +41 -0
  6. package/dist/adapters/framework_adapter.d.ts.map +1 -0
  7. package/dist/adapters/framework_adapter.js +152 -0
  8. package/dist/adapters/playwright.d.ts +10 -0
  9. package/dist/adapters/playwright.d.ts.map +1 -0
  10. package/dist/adapters/playwright.js +86 -0
  11. package/dist/adapters/pytest.d.ts +10 -0
  12. package/dist/adapters/pytest.d.ts.map +1 -0
  13. package/dist/adapters/pytest.js +96 -0
  14. package/dist/adapters/supertest.d.ts +12 -0
  15. package/dist/adapters/supertest.d.ts.map +1 -0
  16. package/dist/adapters/supertest.js +85 -0
  17. package/dist/agent/config.d.ts +1 -1
  18. package/dist/agent/config.d.ts.map +1 -1
  19. package/dist/agent/git.d.ts +1 -0
  20. package/dist/agent/git.d.ts.map +1 -1
  21. package/dist/agent/git.js +3 -0
  22. package/dist/agentic/fix_loop.d.ts.map +1 -1
  23. package/dist/agentic/fix_loop.js +5 -4
  24. package/dist/agentic/runner.d.ts +2 -0
  25. package/dist/agentic/runner.d.ts.map +1 -1
  26. package/dist/agentic/runner.js +15 -12
  27. package/dist/agents/cross-impact.d.ts.map +1 -1
  28. package/dist/agents/cross-impact.js +6 -1
  29. package/dist/agents/executor.d.ts.map +1 -1
  30. package/dist/agents/executor.js +6 -1
  31. package/dist/agents/strategist.d.ts.map +1 -1
  32. package/dist/agents/strategist.js +6 -1
  33. package/dist/agents/test-designer.d.ts.map +1 -1
  34. package/dist/agents/test-designer.js +6 -1
  35. package/dist/anthropic_provider.d.ts.map +1 -1
  36. package/dist/anthropic_provider.js +1 -0
  37. package/dist/base_provider.d.ts +56 -0
  38. package/dist/base_provider.d.ts.map +1 -1
  39. package/dist/base_provider.js +123 -1
  40. package/dist/budget_ledger.d.ts +28 -0
  41. package/dist/budget_ledger.d.ts.map +1 -0
  42. package/dist/budget_ledger.js +62 -0
  43. package/dist/cache/cached_provider.d.ts +45 -0
  44. package/dist/cache/cached_provider.d.ts.map +1 -0
  45. package/dist/cache/cached_provider.js +88 -0
  46. package/dist/cache/response_cache.d.ts +79 -0
  47. package/dist/cache/response_cache.d.ts.map +1 -0
  48. package/dist/cache/response_cache.js +177 -0
  49. package/dist/cli/commands/bootstrap.d.ts +3 -0
  50. package/dist/cli/commands/bootstrap.d.ts.map +1 -0
  51. package/dist/cli/commands/bootstrap.js +109 -0
  52. package/dist/cli/commands/cost_report.d.ts +3 -0
  53. package/dist/cli/commands/cost_report.d.ts.map +1 -0
  54. package/dist/cli/commands/cost_report.js +115 -0
  55. package/dist/cli/commands/crew.d.ts.map +1 -1
  56. package/dist/cli/commands/crew.js +118 -1
  57. package/dist/cli/commands/gate.d.ts +3 -0
  58. package/dist/cli/commands/gate.d.ts.map +1 -0
  59. package/dist/cli/commands/gate.js +86 -0
  60. package/dist/cli/commands/init.d.ts.map +1 -1
  61. package/dist/cli/commands/init.js +7 -62
  62. package/dist/cli/commands/train.d.ts.map +1 -1
  63. package/dist/cli/commands/train.js +16 -21
  64. package/dist/cli/defaults.d.ts +35 -0
  65. package/dist/cli/defaults.d.ts.map +1 -0
  66. package/dist/cli/defaults.js +125 -0
  67. package/dist/cli/errors.d.ts +27 -0
  68. package/dist/cli/errors.d.ts.map +1 -0
  69. package/dist/cli/errors.js +57 -0
  70. package/dist/cli/parse_args.d.ts.map +1 -1
  71. package/dist/cli/parse_args.js +24 -2
  72. package/dist/cli/types.d.ts +7 -1
  73. package/dist/cli/types.d.ts.map +1 -1
  74. package/dist/cli.js +47 -2
  75. package/dist/crew/context.d.ts +15 -0
  76. package/dist/crew/context.d.ts.map +1 -1
  77. package/dist/crew/orchestrator.d.ts +14 -0
  78. package/dist/crew/orchestrator.d.ts.map +1 -1
  79. package/dist/crew/orchestrator.js +162 -4
  80. package/dist/crew/protocol.d.ts +13 -0
  81. package/dist/crew/protocol.d.ts.map +1 -1
  82. package/dist/crew/provider.d.ts +15 -1
  83. package/dist/crew/provider.d.ts.map +1 -1
  84. package/dist/crew/provider.js +24 -4
  85. package/dist/custom_provider.d.ts.map +1 -1
  86. package/dist/custom_provider.js +1 -0
  87. package/dist/engine/diff_loader.d.ts.map +1 -1
  88. package/dist/engine/diff_loader.js +3 -14
  89. package/dist/engine/impact_engine.d.ts.map +1 -1
  90. package/dist/engine/impact_engine.js +9 -23
  91. package/dist/esm/adapters/cypress.js +49 -0
  92. package/dist/esm/adapters/framework_adapter.js +114 -0
  93. package/dist/esm/adapters/playwright.js +49 -0
  94. package/dist/esm/adapters/pytest.js +59 -0
  95. package/dist/esm/adapters/supertest.js +48 -0
  96. package/dist/esm/agent/git.js +3 -1
  97. package/dist/esm/agentic/fix_loop.js +5 -4
  98. package/dist/esm/agentic/runner.js +15 -12
  99. package/dist/esm/agents/cross-impact.js +6 -1
  100. package/dist/esm/agents/executor.js +6 -1
  101. package/dist/esm/agents/strategist.js +6 -1
  102. package/dist/esm/agents/test-designer.js +6 -1
  103. package/dist/esm/anthropic_provider.js +1 -0
  104. package/dist/esm/base_provider.js +121 -0
  105. package/dist/esm/budget_ledger.js +58 -0
  106. package/dist/esm/cache/cached_provider.js +82 -0
  107. package/dist/esm/cache/response_cache.js +140 -0
  108. package/dist/esm/cli/commands/bootstrap.js +106 -0
  109. package/dist/esm/cli/commands/cost_report.js +112 -0
  110. package/dist/esm/cli/commands/crew.js +118 -1
  111. package/dist/esm/cli/commands/gate.js +83 -0
  112. package/dist/esm/cli/commands/init.js +3 -58
  113. package/dist/esm/cli/commands/train.js +16 -21
  114. package/dist/esm/cli/defaults.js +118 -0
  115. package/dist/esm/cli/errors.js +52 -0
  116. package/dist/esm/cli/parse_args.js +24 -2
  117. package/dist/esm/cli.js +47 -2
  118. package/dist/esm/crew/orchestrator.js +162 -4
  119. package/dist/esm/crew/provider.js +24 -4
  120. package/dist/esm/custom_provider.js +1 -0
  121. package/dist/esm/engine/diff_loader.js +1 -12
  122. package/dist/esm/engine/impact_engine.js +9 -23
  123. package/dist/esm/index.js +21 -0
  124. package/dist/esm/knowledge/api_surface.js +265 -34
  125. package/dist/esm/knowledge/cluster_utils.js +60 -0
  126. package/dist/esm/knowledge/failure_history.js +121 -0
  127. package/dist/esm/knowledge/kg_bridge.js +381 -0
  128. package/dist/esm/knowledge/kg_types.js +3 -0
  129. package/dist/esm/knowledge/route_families.js +119 -0
  130. package/dist/esm/mcp-server.js +2 -4
  131. package/dist/esm/metrics/prometheus.js +149 -0
  132. package/dist/esm/model_router.js +59 -0
  133. package/dist/esm/ollama_provider.js +1 -0
  134. package/dist/esm/openai_provider.js +1 -0
  135. package/dist/esm/pipeline/orchestrator.js +6 -12
  136. package/dist/esm/pipeline/stage0_preprocess.js +12 -19
  137. package/dist/esm/pipeline/stage1_impact.js +19 -3
  138. package/dist/esm/pipeline/stage2_coverage.js +29 -7
  139. package/dist/esm/pipeline/stage3_generation.js +21 -1
  140. package/dist/esm/progress.js +112 -0
  141. package/dist/esm/prompts/coverage.js +17 -24
  142. package/dist/esm/prompts/cross-impact.js +3 -21
  143. package/dist/esm/prompts/generation.js +201 -45
  144. package/dist/esm/prompts/generation_profile.js +147 -0
  145. package/dist/esm/prompts/heal.js +33 -15
  146. package/dist/esm/prompts/impact.js +3 -22
  147. package/dist/esm/prompts/json_extract.js +36 -0
  148. package/dist/esm/prompts/strategist.js +2 -20
  149. package/dist/esm/prompts/test-designer.js +6 -21
  150. package/dist/esm/provider_factory.js +6 -4
  151. package/dist/esm/reporters/junit.js +86 -0
  152. package/dist/esm/reporters/reporter.js +3 -0
  153. package/dist/esm/reporters/sarif.js +131 -0
  154. package/dist/esm/resilience/circuit_breaker.js +78 -0
  155. package/dist/esm/resilience/retry.js +56 -0
  156. package/dist/esm/sanitize.js +66 -0
  157. package/dist/esm/training/kg_scanner.js +115 -0
  158. package/dist/esm/training/scanner.js +27 -34
  159. package/dist/esm/validation/guardrails.js +5 -0
  160. package/dist/esm/version.js +33 -0
  161. package/dist/index.d.ts +21 -1
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +45 -1
  164. package/dist/knowledge/api_surface.d.ts +12 -0
  165. package/dist/knowledge/api_surface.d.ts.map +1 -1
  166. package/dist/knowledge/api_surface.js +268 -34
  167. package/dist/knowledge/cluster_utils.d.ts +28 -0
  168. package/dist/knowledge/cluster_utils.d.ts.map +1 -0
  169. package/dist/knowledge/cluster_utils.js +67 -0
  170. package/dist/knowledge/failure_history.d.ts +39 -0
  171. package/dist/knowledge/failure_history.d.ts.map +1 -0
  172. package/dist/knowledge/failure_history.js +128 -0
  173. package/dist/knowledge/kg_bridge.d.ts +31 -0
  174. package/dist/knowledge/kg_bridge.d.ts.map +1 -0
  175. package/dist/knowledge/kg_bridge.js +388 -0
  176. package/dist/knowledge/kg_types.d.ts +75 -0
  177. package/dist/knowledge/kg_types.d.ts.map +1 -0
  178. package/dist/knowledge/kg_types.js +4 -0
  179. package/dist/knowledge/route_families.d.ts +29 -0
  180. package/dist/knowledge/route_families.d.ts.map +1 -1
  181. package/dist/knowledge/route_families.js +122 -0
  182. package/dist/mcp-server.d.ts.map +1 -1
  183. package/dist/mcp-server.js +2 -4
  184. package/dist/metrics/prometheus.d.ts +37 -0
  185. package/dist/metrics/prometheus.d.ts.map +1 -0
  186. package/dist/metrics/prometheus.js +153 -0
  187. package/dist/model_router.d.ts +28 -0
  188. package/dist/model_router.d.ts.map +1 -0
  189. package/dist/model_router.js +63 -0
  190. package/dist/ollama_provider.d.ts.map +1 -1
  191. package/dist/ollama_provider.js +1 -0
  192. package/dist/openai_provider.d.ts.map +1 -1
  193. package/dist/openai_provider.js +1 -0
  194. package/dist/pipeline/orchestrator.d.ts +2 -0
  195. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  196. package/dist/pipeline/orchestrator.js +6 -12
  197. package/dist/pipeline/stage0_preprocess.d.ts.map +1 -1
  198. package/dist/pipeline/stage0_preprocess.js +11 -18
  199. package/dist/pipeline/stage1_impact.d.ts +1 -1
  200. package/dist/pipeline/stage1_impact.d.ts.map +1 -1
  201. package/dist/pipeline/stage1_impact.js +18 -2
  202. package/dist/pipeline/stage2_coverage.d.ts +2 -0
  203. package/dist/pipeline/stage2_coverage.d.ts.map +1 -1
  204. package/dist/pipeline/stage2_coverage.js +29 -7
  205. package/dist/pipeline/stage3_generation.d.ts +2 -0
  206. package/dist/pipeline/stage3_generation.d.ts.map +1 -1
  207. package/dist/pipeline/stage3_generation.js +21 -1
  208. package/dist/pipeline/stage4_heal.d.ts +2 -0
  209. package/dist/pipeline/stage4_heal.d.ts.map +1 -1
  210. package/dist/progress.d.ts +22 -0
  211. package/dist/progress.d.ts.map +1 -0
  212. package/dist/progress.js +116 -0
  213. package/dist/prompts/coverage.d.ts +2 -0
  214. package/dist/prompts/coverage.d.ts.map +1 -1
  215. package/dist/prompts/coverage.js +17 -24
  216. package/dist/prompts/cross-impact.d.ts +1 -0
  217. package/dist/prompts/cross-impact.d.ts.map +1 -1
  218. package/dist/prompts/cross-impact.js +3 -21
  219. package/dist/prompts/generation.d.ts +4 -2
  220. package/dist/prompts/generation.d.ts.map +1 -1
  221. package/dist/prompts/generation.js +201 -45
  222. package/dist/prompts/generation_profile.d.ts +29 -0
  223. package/dist/prompts/generation_profile.d.ts.map +1 -0
  224. package/dist/prompts/generation_profile.js +151 -0
  225. package/dist/prompts/heal.d.ts +3 -1
  226. package/dist/prompts/heal.d.ts.map +1 -1
  227. package/dist/prompts/heal.js +33 -15
  228. package/dist/prompts/impact.d.ts +1 -0
  229. package/dist/prompts/impact.d.ts.map +1 -1
  230. package/dist/prompts/impact.js +3 -22
  231. package/dist/prompts/json_extract.d.ts +14 -0
  232. package/dist/prompts/json_extract.d.ts.map +1 -0
  233. package/dist/prompts/json_extract.js +39 -0
  234. package/dist/prompts/strategist.d.ts.map +1 -1
  235. package/dist/prompts/strategist.js +2 -20
  236. package/dist/prompts/test-designer.d.ts +2 -0
  237. package/dist/prompts/test-designer.d.ts.map +1 -1
  238. package/dist/prompts/test-designer.js +6 -21
  239. package/dist/provider_factory.d.ts.map +1 -1
  240. package/dist/provider_factory.js +6 -4
  241. package/dist/reporters/junit.d.ts +6 -0
  242. package/dist/reporters/junit.d.ts.map +1 -0
  243. package/dist/reporters/junit.js +89 -0
  244. package/dist/reporters/reporter.d.ts +42 -0
  245. package/dist/reporters/reporter.d.ts.map +1 -0
  246. package/dist/reporters/reporter.js +4 -0
  247. package/dist/reporters/sarif.d.ts +7 -0
  248. package/dist/reporters/sarif.d.ts.map +1 -0
  249. package/dist/reporters/sarif.js +134 -0
  250. package/dist/resilience/circuit_breaker.d.ts +36 -0
  251. package/dist/resilience/circuit_breaker.d.ts.map +1 -0
  252. package/dist/resilience/circuit_breaker.js +82 -0
  253. package/dist/resilience/retry.d.ts +11 -0
  254. package/dist/resilience/retry.d.ts.map +1 -0
  255. package/dist/resilience/retry.js +59 -0
  256. package/dist/sanitize.d.ts +15 -0
  257. package/dist/sanitize.d.ts.map +1 -0
  258. package/dist/sanitize.js +71 -0
  259. package/dist/training/kg_scanner.d.ts +13 -0
  260. package/dist/training/kg_scanner.d.ts.map +1 -0
  261. package/dist/training/kg_scanner.js +118 -0
  262. package/dist/training/scanner.d.ts +7 -2
  263. package/dist/training/scanner.d.ts.map +1 -1
  264. package/dist/training/scanner.js +27 -34
  265. package/dist/validation/guardrails.d.ts +2 -0
  266. package/dist/validation/guardrails.d.ts.map +1 -1
  267. package/dist/validation/guardrails.js +5 -0
  268. package/dist/validation/output_schema.d.ts +3 -0
  269. package/dist/validation/output_schema.d.ts.map +1 -1
  270. package/dist/version.d.ts +6 -0
  271. package/dist/version.d.ts.map +1 -0
  272. package/dist/version.js +36 -0
  273. package/package.json +7 -2
  274. package/schemas/route-families.schema.json +31 -1
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.CircuitBreaker = void 0;
6
+ const DEFAULT_CONFIG = {
7
+ failureThreshold: 3,
8
+ cooldownMs: 60000,
9
+ };
10
+ class CircuitBreaker {
11
+ constructor(config = {}) {
12
+ this.state = 'closed';
13
+ this.failures = 0;
14
+ this.lastFailureTime = 0;
15
+ this.config = { ...DEFAULT_CONFIG, ...config };
16
+ }
17
+ /** Returns the derived state without mutating internal state. */
18
+ get currentState() {
19
+ if (this.state === 'open' && Date.now() - this.lastFailureTime >= this.config.cooldownMs) {
20
+ return 'half-open';
21
+ }
22
+ return this.state;
23
+ }
24
+ get isOpen() {
25
+ return this.currentState === 'open';
26
+ }
27
+ /**
28
+ * Execute a function with circuit breaker protection.
29
+ * If the circuit is open, the fallback is called instead.
30
+ */
31
+ async call(fn, fallback) {
32
+ // Transition from open to half-open if cooldown has elapsed
33
+ if (this.state === 'open') {
34
+ if (Date.now() - this.lastFailureTime >= this.config.cooldownMs) {
35
+ this.state = 'half-open';
36
+ }
37
+ else {
38
+ return fallback();
39
+ }
40
+ }
41
+ // At this point state is 'closed' or 'half-open'
42
+ const stateBeforeCall = this.state;
43
+ try {
44
+ const result = await fn();
45
+ this.onSuccess();
46
+ return result;
47
+ }
48
+ catch (error) {
49
+ const shouldCount = !this.config.shouldCount || this.config.shouldCount(error);
50
+ if (shouldCount) {
51
+ this.onFailure();
52
+ }
53
+ // In half-open state, a failure re-opens the circuit
54
+ if (stateBeforeCall === 'half-open') {
55
+ throw error;
56
+ }
57
+ // In closed state, if failures hit threshold the circuit opened
58
+ if (shouldCount && this.failures >= this.config.failureThreshold) {
59
+ return fallback();
60
+ }
61
+ throw error;
62
+ }
63
+ }
64
+ onSuccess() {
65
+ this.failures = 0;
66
+ this.state = 'closed';
67
+ }
68
+ onFailure() {
69
+ this.failures++;
70
+ this.lastFailureTime = Date.now();
71
+ if (this.failures >= this.config.failureThreshold) {
72
+ this.state = 'open';
73
+ }
74
+ }
75
+ /** Reset the circuit breaker to closed state */
76
+ reset() {
77
+ this.state = 'closed';
78
+ this.failures = 0;
79
+ this.lastFailureTime = 0;
80
+ }
81
+ }
82
+ exports.CircuitBreaker = CircuitBreaker;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Retry with exponential backoff and jitter for LLM provider calls.
3
+ */
4
+ export interface RetryConfig {
5
+ maxRetries: number;
6
+ baseDelayMs: number;
7
+ maxDelayMs: number;
8
+ jitter: boolean;
9
+ }
10
+ export declare function withRetry<T>(fn: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
11
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/resilience/retry.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,MAAM,WAAW,WAAW;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACnB;AAsCD,wBAAsB,SAAS,CAAC,CAAC,EAC7B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAClC,OAAO,CAAC,CAAC,CAAC,CAkBZ"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.withRetry = withRetry;
6
+ const DEFAULT_RETRY_CONFIG = {
7
+ maxRetries: 2,
8
+ baseDelayMs: 1000,
9
+ maxDelayMs: 10000,
10
+ jitter: true,
11
+ };
12
+ /** Errors that should be retried (transient failures) */
13
+ function isRetryable(error) {
14
+ if (!(error instanceof Error))
15
+ return false;
16
+ const msg = error.message.toLowerCase();
17
+ // Rate limits
18
+ if (msg.includes('rate limit') || msg.includes('429') || msg.includes('too many requests'))
19
+ return true;
20
+ // Server errors
21
+ if (msg.includes('500') || msg.includes('502') || msg.includes('503') || msg.includes('504'))
22
+ return true;
23
+ if (msg.includes('internal server error') || msg.includes('bad gateway') || msg.includes('service unavailable'))
24
+ return true;
25
+ // Network errors
26
+ if (msg.includes('econnreset') || msg.includes('econnrefused') || msg.includes('etimedout'))
27
+ return true;
28
+ if (msg.includes('socket hang up') || msg.includes('network error'))
29
+ return true;
30
+ // Overloaded
31
+ if (msg.includes('overloaded') || msg.includes('capacity'))
32
+ return true;
33
+ return false;
34
+ }
35
+ function computeDelay(attempt, config) {
36
+ const exponential = Math.min(config.baseDelayMs * Math.pow(2, attempt), config.maxDelayMs);
37
+ if (!config.jitter)
38
+ return exponential;
39
+ // Full jitter: random between 0 and exponential
40
+ return Math.floor(Math.random() * exponential);
41
+ }
42
+ async function withRetry(fn, config = {}) {
43
+ const cfg = { ...DEFAULT_RETRY_CONFIG, ...config };
44
+ let lastError;
45
+ for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {
46
+ try {
47
+ return await fn();
48
+ }
49
+ catch (error) {
50
+ lastError = error;
51
+ if (attempt >= cfg.maxRetries || !isRetryable(error)) {
52
+ throw error;
53
+ }
54
+ const delay = computeDelay(attempt, cfg);
55
+ await new Promise((resolve) => setTimeout(resolve, delay));
56
+ }
57
+ }
58
+ throw lastError;
59
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Sanitize a string by replacing detected secrets with [REDACTED].
3
+ */
4
+ export declare function sanitizeSecrets(text: string): string;
5
+ /**
6
+ * Check if a string contains any detectable secrets.
7
+ */
8
+ export declare function containsSecrets(text: string): boolean;
9
+ /**
10
+ * Deep-sanitize a JSON-serializable object.
11
+ * Recursively walks all string values and sanitizes them.
12
+ * Tracks seen objects to prevent stack overflow on circular references.
13
+ */
14
+ export declare function sanitizeObject<T>(obj: T, _seen?: WeakSet<object>): T;
15
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AA2BA;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKrD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAepE"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.sanitizeSecrets = sanitizeSecrets;
6
+ exports.containsSecrets = containsSecrets;
7
+ exports.sanitizeObject = sanitizeObject;
8
+ /**
9
+ * Secret scanning and sanitization utilities.
10
+ * Prevents API keys and credentials from leaking into artifacts, logs, and output.
11
+ *
12
+ * Patterns are stored WITHOUT the global flag to avoid shared mutable lastIndex state.
13
+ * New RegExp instances with /g are created per call for safe concurrent usage.
14
+ */
15
+ const SECRET_PATTERNS = [
16
+ // Anthropic API keys (must be checked before generic sk- pattern)
17
+ /sk-ant-[a-zA-Z0-9_-]{20,}/,
18
+ // OpenAI API keys (negative lookahead to avoid matching Anthropic keys)
19
+ /sk-(?!ant-)[a-zA-Z0-9]{20,}/,
20
+ // Generic API key patterns
21
+ /(?:api[_-]?key|api[_-]?secret|access[_-]?token|auth[_-]?token)['":\s=]+['"]?([a-zA-Z0-9_\-./]{20,})['"]?/i,
22
+ // Bearer tokens
23
+ /Bearer\s+[a-zA-Z0-9_\-./]{20,}/,
24
+ // AWS keys
25
+ /AKIA[0-9A-Z]{16}/,
26
+ // GitHub tokens
27
+ /gh[ps]_[a-zA-Z0-9]{36,}/,
28
+ /github_pat_[a-zA-Z0-9_]{22,}/,
29
+ ];
30
+ /**
31
+ * Sanitize a string by replacing detected secrets with [REDACTED].
32
+ */
33
+ function sanitizeSecrets(text) {
34
+ let result = text;
35
+ for (const pattern of SECRET_PATTERNS) {
36
+ result = result.replace(new RegExp(pattern, 'gi'), '[REDACTED]');
37
+ }
38
+ return result;
39
+ }
40
+ /**
41
+ * Check if a string contains any detectable secrets.
42
+ */
43
+ function containsSecrets(text) {
44
+ for (const pattern of SECRET_PATTERNS) {
45
+ if (new RegExp(pattern, 'i').test(text))
46
+ return true;
47
+ }
48
+ return false;
49
+ }
50
+ /**
51
+ * Deep-sanitize a JSON-serializable object.
52
+ * Recursively walks all string values and sanitizes them.
53
+ * Tracks seen objects to prevent stack overflow on circular references.
54
+ */
55
+ function sanitizeObject(obj, _seen) {
56
+ if (typeof obj === 'string')
57
+ return sanitizeSecrets(obj);
58
+ if (obj === null || typeof obj !== 'object')
59
+ return obj;
60
+ const seen = _seen ?? new WeakSet();
61
+ if (seen.has(obj))
62
+ return '[Circular]';
63
+ seen.add(obj);
64
+ if (Array.isArray(obj))
65
+ return obj.map((item) => sanitizeObject(item, seen));
66
+ const result = {};
67
+ for (const [key, value] of Object.entries(obj)) {
68
+ result[key] = sanitizeObject(value, seen);
69
+ }
70
+ return result;
71
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Converts an Understand-Anything knowledge graph into the same ScanResult
3
+ * format produced by the filesystem scanner. This allows the existing
4
+ * merge/enrich/validate pipeline to work unchanged with KG input.
5
+ */
6
+ import type { KnowledgeGraph } from '../knowledge/kg_types.js';
7
+ import type { ScanResult } from './types.js';
8
+ /**
9
+ * Converts KG nodes/edges into a ScanResult compatible with the filesystem scanner output.
10
+ * Groups nodes by their containing module/directory to form families.
11
+ */
12
+ export declare function scanFromKnowledgeGraph(kg: KnowledgeGraph): ScanResult;
13
+ //# sourceMappingURL=kg_scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kg_scanner.d.ts","sourceRoot":"","sources":["../../src/training/kg_scanner.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAS,MAAM,0BAA0B,CAAC;AAErE,OAAO,KAAK,EAAC,UAAU,EAAgC,MAAM,YAAY,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,cAAc,GAAG,UAAU,CA4FrE"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.scanFromKnowledgeGraph = scanFromKnowledgeGraph;
6
+ const cluster_utils_js_1 = require("../knowledge/cluster_utils.js");
7
+ /**
8
+ * Converts KG nodes/edges into a ScanResult compatible with the filesystem scanner output.
9
+ * Groups nodes by their containing module/directory to form families.
10
+ */
11
+ function scanFromKnowledgeGraph(kg) {
12
+ const clusters = new Map();
13
+ // Group nodes into clusters by directory/module
14
+ for (const node of kg.nodes) {
15
+ if (node.layer === 'infra')
16
+ continue; // skip infrastructure nodes
17
+ const clusterId = (0, cluster_utils_js_1.deriveClusterId)(node, cluster_utils_js_1.SKIP_DIRS_WITH_TESTS);
18
+ if (!clusterId)
19
+ continue;
20
+ if (!clusters.has(clusterId)) {
21
+ clusters.set(clusterId, []);
22
+ }
23
+ clusters.get(clusterId).push(node);
24
+ }
25
+ let totalSourceFiles = 0;
26
+ let totalTestFiles = 0;
27
+ const families = [];
28
+ for (const [id, nodes] of clusters) {
29
+ const webappPaths = [];
30
+ const serverPaths = [];
31
+ const specDirs = [];
32
+ const tags = [];
33
+ const seenDirs = new Set();
34
+ for (const node of nodes) {
35
+ if (!node.filePath)
36
+ continue;
37
+ const normalized = node.filePath.replace(/\\/g, '/');
38
+ if (node.layer === 'test') {
39
+ totalTestFiles++;
40
+ const dir = normalized.split('/').slice(0, -1).join('/');
41
+ if (dir && !seenDirs.has(dir)) {
42
+ seenDirs.add(dir);
43
+ specDirs.push(dir + '/');
44
+ }
45
+ continue;
46
+ }
47
+ totalSourceFiles++;
48
+ const glob = buildGlobFromPath(normalized);
49
+ if (node.layer === 'api' || node.layer === 'service' || node.layer === 'data') {
50
+ serverPaths.push(glob);
51
+ }
52
+ else if (node.layer === 'ui') {
53
+ webappPaths.push(glob);
54
+ }
55
+ else {
56
+ // Default assignment based on file path heuristics
57
+ if (isLikelyServerPath(normalized)) {
58
+ serverPaths.push(glob);
59
+ }
60
+ else {
61
+ webappPaths.push(glob);
62
+ }
63
+ }
64
+ // Extract tags from node metadata
65
+ if (node.tags) {
66
+ tags.push(...node.tags);
67
+ }
68
+ }
69
+ if (webappPaths.length === 0 && serverPaths.length === 0 && specDirs.length === 0) {
70
+ continue;
71
+ }
72
+ families.push({
73
+ id,
74
+ routes: [`/${id}`],
75
+ webappPaths: [...new Set(webappPaths)],
76
+ serverPaths: [...new Set(serverPaths)],
77
+ specDirs: [...new Set(specDirs)],
78
+ cypressSpecDirs: [],
79
+ tags: [...new Set(tags)],
80
+ features: [],
81
+ routesGuessed: true,
82
+ });
83
+ }
84
+ return {
85
+ families,
86
+ unmatchedSourceDirs: [],
87
+ unmatchedTestDirs: [],
88
+ stats: {
89
+ totalSourceFiles,
90
+ totalTestFiles,
91
+ familyCount: families.length,
92
+ },
93
+ };
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // Internal helpers
97
+ // ---------------------------------------------------------------------------
98
+ // deriveClusterId and deriveClusterIdFromPath imported from cluster_utils.ts
99
+ function buildGlobFromPath(filePath) {
100
+ // Reject paths with traversal or null bytes
101
+ if (filePath.includes('..') || filePath.includes('\0')) {
102
+ return '';
103
+ }
104
+ // Convert a file path to a glob pattern matching the directory
105
+ const dir = filePath.split('/').slice(0, -1).join('/');
106
+ return dir ? `${dir}/*` : `${filePath}*`;
107
+ }
108
+ function isLikelyServerPath(filePath) {
109
+ const lower = filePath.toLowerCase();
110
+ return lower.includes('/server/') ||
111
+ lower.includes('/api/') ||
112
+ lower.includes('/routes/') ||
113
+ lower.includes('/controllers/') ||
114
+ lower.includes('/services/') ||
115
+ lower.includes('/models/') ||
116
+ lower.endsWith('.go') ||
117
+ lower.endsWith('.py');
118
+ }
@@ -1,4 +1,9 @@
1
1
  import type { DiscoveredDir, ScannedFamily, ScanResult } from './types.js';
2
+ /** Configurable scanner options. All fields optional — defaults to Mattermost conventions. */
3
+ export interface ScannerConfig {
4
+ serverInfraFiles?: Set<string>;
5
+ serverTiers?: readonly string[];
6
+ }
2
7
  export declare function discoverSourceDirs(projectRoot: string): DiscoveredDir[];
3
8
  export declare function discoverTestDirs(projectRoot: string): DiscoveredDir[];
4
9
  /**
@@ -12,7 +17,7 @@ export declare function discoverTestDirs(projectRoot: string): DiscoveredDir[];
12
17
  *
13
18
  * Each domain becomes a candidate family with precise serverPaths.
14
19
  */
15
- export declare function discoverServerDerivedFamilies(serverRoot: string): {
20
+ export declare function discoverServerDerivedFamilies(serverRoot: string, infraFiles?: Set<string>, tiers?: readonly string[]): {
16
21
  multiTierFamilies: ScannedFamily[];
17
22
  singleTierFamilies: ScannedFamily[];
18
23
  };
@@ -27,5 +32,5 @@ export declare function discoverTestLibPaths(testsRoot: string): Map<string, str
27
32
  * maps directly to a family ID.
28
33
  */
29
34
  export declare function discoverNameMatchedPaths(appPath: string, gitRepoRoot?: string): Map<string, string[]>;
30
- export declare function scanProject(projectRoot: string, testsRoot?: string, serverRoot?: string, gitRepoRoot?: string): ScanResult;
35
+ export declare function scanProject(projectRoot: string, testsRoot?: string, serverRoot?: string, gitRepoRoot?: string, config?: ScannerConfig): ScanResult;
31
36
  //# sourceMappingURL=scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/training/scanner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAkB,UAAU,EAAC,MAAM,YAAY,CAAC;AAgJzF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA+BvE;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA6DrE;AAuLD;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG;IAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;IAAC,kBAAkB,EAAE,aAAa,EAAE,CAAA;CAAC,CAgI3I;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAiG9E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA8C7E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACrB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAyDvB;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CA0L1H"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/training/scanner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAkB,UAAU,EAAC,MAAM,YAAY,CAAC;AAoEzF,8FAA8F;AAC9F,MAAM,WAAW,aAAa;IAC1B,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAqED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA+BvE;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA6DrE;AAuLD;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CACzC,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,GAAG,CAAC,MAAM,CAA8B,EACpD,KAAK,GAAE,SAAS,MAAM,EAAyB,GAChD;IAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;IAAC,kBAAkB,EAAE,aAAa,EAAE,CAAA;CAAC,CAgI3E;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAiG9E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA8C7E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACrB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAyDvB;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,UAAU,CA8LlJ"}
@@ -11,6 +11,7 @@ exports.discoverNameMatchedPaths = discoverNameMatchedPaths;
11
11
  exports.scanProject = scanProject;
12
12
  const fs_1 = require("fs");
13
13
  const path_1 = require("path");
14
+ const cluster_utils_js_1 = require("../knowledge/cluster_utils.js");
14
15
  const SOURCE_MAX_DEPTH = 3;
15
16
  // One deeper than source to account for test framework wrapper dirs (e2e/, integration/)
16
17
  const TEST_MAX_DEPTH = 5;
@@ -44,10 +45,11 @@ const STRUCTURAL_DIRS = new Set([
44
45
  'middleware', 'contexts', 'providers', 'layouts', 'templates',
45
46
  ]);
46
47
  /**
47
- * Server Go files that are infrastructure / cross-cutting concerns,
48
+ * Default server Go files that are infrastructure / cross-cutting concerns,
48
49
  * not feature-specific domains. Matched after stripping _local/_store suffixes.
50
+ * Override via ScannerConfig.serverInfraFiles.
49
51
  */
50
- const SERVER_INFRA_FILES = new Set([
52
+ const DEFAULT_SERVER_INFRA_FILES = new Set([
51
53
  'api', 'apitestlib', 'context', 'helpers', 'params', 'swagger',
52
54
  'app', 'server', 'enterprise', 'product_service', 'security_update_check',
53
55
  'store', 'adapters', 'errors', 'integrity', 'migrate', 'doc',
@@ -57,10 +59,11 @@ const SERVER_INFRA_FILES = new Set([
57
59
  'manifest', 'permission', 'log', 'utils',
58
60
  ]);
59
61
  /**
60
- * Server tier directories to scan for Go domain files.
62
+ * Default server tier directories to scan for Go domain files.
61
63
  * Each tier represents a layer of the backend architecture.
64
+ * Override via ScannerConfig.serverTiers.
62
65
  */
63
- const SERVER_TIERS = [
66
+ const DEFAULT_SERVER_TIERS = [
64
67
  'channels/api4',
65
68
  'channels/app',
66
69
  'channels/store/sqlstore',
@@ -73,13 +76,7 @@ const includes = (arr, v) => arr.includes(v);
73
76
  function isSkipped(name) {
74
77
  return name.startsWith('.') || SKIP_DIRS.has(name);
75
78
  }
76
- function normalizeId(name) {
77
- return name
78
- .replace(/[A-Z]/g, (c, idx) => (idx > 0 ? `_${c.toLowerCase()}` : c.toLowerCase()))
79
- .replace(/[^a-z0-9_]/g, '_')
80
- .replace(/_+/g, '_')
81
- .replace(/^_|_$/g, '');
82
- }
79
+ const normalizeId = cluster_utils_js_1.normalizeToClusterId;
83
80
  function extractFamilyHint(dirPath, projectRoot) {
84
81
  const rel = (0, path_1.relative)(projectRoot, dirPath).replace(/\\/g, '/');
85
82
  const parts = rel.split('/').filter(Boolean);
@@ -97,32 +94,25 @@ function walkDirs(root, projectRoot, category, maxDepth, results, depth = 0) {
97
94
  if (depth > maxDepth || !(0, fs_1.existsSync)(root)) {
98
95
  return;
99
96
  }
100
- let entries;
97
+ let dirents;
101
98
  try {
102
- entries = (0, fs_1.readdirSync)(root);
99
+ dirents = (0, fs_1.readdirSync)(root, { withFileTypes: true });
103
100
  }
104
101
  catch {
105
102
  // ENOENT or EACCES — skip inaccessible entries
106
103
  return;
107
104
  }
108
- const hasSourceFiles = entries.some((e) => {
109
- const ext = e.slice(e.lastIndexOf('.'));
105
+ const hasSourceFiles = dirents.some((d) => {
106
+ if (!d.isFile())
107
+ return false;
108
+ const ext = d.name.slice(d.name.lastIndexOf('.'));
110
109
  return ['.ts', '.tsx', '.js', '.jsx', '.go', '.py', '.rs'].includes(ext);
111
110
  });
112
- const subdirs = entries.filter((e) => {
113
- if (isSkipped(e))
111
+ const subdirs = dirents.filter((d) => {
112
+ if (!d.isDirectory() || d.isSymbolicLink())
114
113
  return false;
115
- try {
116
- const stat = (0, fs_1.lstatSync)((0, path_1.join)(root, e));
117
- if (stat.isSymbolicLink())
118
- return false;
119
- return stat.isDirectory();
120
- }
121
- catch {
122
- // ENOENT or EACCES — skip inaccessible entries
123
- return false;
124
- }
125
- });
114
+ return !isSkipped(d.name);
115
+ }).map((d) => d.name);
126
116
  if (hasSourceFiles && depth >= 1) {
127
117
  results.push({
128
118
  path: (0, path_1.resolve)(root),
@@ -419,7 +409,7 @@ function findParentDomain(name, allDomains) {
419
409
  *
420
410
  * Each domain becomes a candidate family with precise serverPaths.
421
411
  */
422
- function discoverServerDerivedFamilies(serverRoot) {
412
+ function discoverServerDerivedFamilies(serverRoot, infraFiles = DEFAULT_SERVER_INFRA_FILES, tiers = DEFAULT_SERVER_TIERS) {
423
413
  const resolved = (0, path_1.resolve)(serverRoot);
424
414
  // First pass: collect all raw domain names across tiers
425
415
  const allRawDomains = new Set();
@@ -430,7 +420,7 @@ function discoverServerDerivedFamilies(serverRoot) {
430
420
  return;
431
421
  const baseName = entry.replace('.go', '');
432
422
  const domain = normalizeServerDomain(baseName);
433
- if (!domain || SERVER_INFRA_FILES.has(domain))
423
+ if (!domain || infraFiles.has(domain))
434
424
  return;
435
425
  allRawDomains.add(domain);
436
426
  if (!domainTierFiles.has(domain))
@@ -440,7 +430,7 @@ function discoverServerDerivedFamilies(serverRoot) {
440
430
  tierMap.set(tierRelPath, new Set());
441
431
  tierMap.get(tierRelPath).add(baseName);
442
432
  }
443
- for (const tier of SERVER_TIERS) {
433
+ for (const tier of tiers) {
444
434
  const tierPath = (0, path_1.join)(resolved, tier);
445
435
  if (!(0, fs_1.existsSync)(tierPath))
446
436
  continue;
@@ -477,7 +467,7 @@ function discoverServerDerivedFamilies(serverRoot) {
477
467
  if (!(0, fs_1.lstatSync)(jobPath).isDirectory() || isSkipped(entry))
478
468
  continue;
479
469
  const domain = normalizeId(entry);
480
- if (SERVER_INFRA_FILES.has(domain))
470
+ if (infraFiles.has(domain))
481
471
  continue;
482
472
  allRawDomains.add(domain);
483
473
  const jobFiles = (0, fs_1.readdirSync)(jobPath);
@@ -764,7 +754,10 @@ function discoverNameMatchedPaths(appPath, gitRepoRoot) {
764
754
  }
765
755
  return result;
766
756
  }
767
- function scanProject(projectRoot, testsRoot, serverRoot, gitRepoRoot) {
757
+ function scanProject(projectRoot, testsRoot, serverRoot, gitRepoRoot, config) {
758
+ // Resolve scanner config for this run (passed to functions, no module-level mutation)
759
+ const resolvedInfraFiles = config?.serverInfraFiles || DEFAULT_SERVER_INFRA_FILES;
760
+ const resolvedTiers = config?.serverTiers || DEFAULT_SERVER_TIERS;
768
761
  const resolved = (0, path_1.resolve)(projectRoot);
769
762
  const resolvedTestsRoot = testsRoot ? (0, path_1.resolve)(testsRoot) : resolved;
770
763
  const sourceDirs = discoverSourceDirs(resolved);
@@ -827,7 +820,7 @@ function scanProject(projectRoot, testsRoot, serverRoot, gitRepoRoot) {
827
820
  // When a separate serverRoot is provided, discover families from Go source
828
821
  // filenames across the three-tier backend (api4, app, store).
829
822
  if (serverRoot) {
830
- const { multiTierFamilies: serverMulti, singleTierFamilies: serverSingle } = discoverServerDerivedFamilies((0, path_1.resolve)(serverRoot));
823
+ const { multiTierFamilies: serverMulti, singleTierFamilies: serverSingle } = discoverServerDerivedFamilies((0, path_1.resolve)(serverRoot), resolvedInfraFiles, resolvedTiers);
831
824
  const existingIds = new Set(families.map((f) => f.id));
832
825
  // Merge ALL server families (multi + single tier) into existing families,
833
826
  // but only add NEW families if they span ≥2 tiers.
@@ -5,6 +5,8 @@ export interface EvidenceCheck {
5
5
  hasPageObject: boolean;
6
6
  hasUserAction: boolean;
7
7
  hasExistingSpecCited: boolean;
8
+ /** Historical failure correlation boost (0-20) from failure_history */
9
+ historyBoost?: number;
8
10
  }
9
11
  export type ConfidenceClass = 'high' | 'medium' | 'low';
10
12
  export declare const EVIDENCE_THRESHOLDS: {
@@ -1 +1 @@
1
- {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../src/validation/guardrails.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAExE,MAAM,WAAW,aAAa;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAEX,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAkB9D;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAQtE;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,4BAA4B,CACxC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,mBAAmB,GAC9B,OAAO,CAwBT;AAeD,wBAAgB,2BAA2B,CACvC,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAC,GACnC,MAAM,CAMR;AAED,wBAAgB,wBAAwB,CACpC,SAAS,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAC,GACvD,eAAe,CAUjB;AAGD,YAAY,EAAC,kBAAkB,EAAE,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAC,gBAAgB,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../src/validation/guardrails.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAExE,MAAM,WAAW,aAAa;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAEX,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAuB9D;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAQtE;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,4BAA4B,CACxC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,mBAAmB,GAC9B,OAAO,CAwBT;AAeD,wBAAgB,2BAA2B,CACvC,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAC,GACnC,MAAM,CAMR;AAED,wBAAgB,wBAAwB,CACpC,SAAS,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAC,GACvD,eAAe,CAUjB;AAGD,YAAY,EAAC,kBAAkB,EAAE,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAC,gBAAgB,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC"}
@@ -32,6 +32,11 @@ function computeConfidence(check) {
32
32
  if (check.hasExistingSpecCited) {
33
33
  score += 15;
34
34
  }
35
+ // Historical failure correlation: if this file historically causes test failures,
36
+ // we're more confident it needs testing now
37
+ if (check.historyBoost) {
38
+ score += check.historyBoost;
39
+ }
35
40
  return Math.min(100, score);
36
41
  }
37
42
  function classifyConfidence(confidence) {
@@ -9,6 +9,8 @@ export interface ExistingSpecCoverage {
9
9
  coverageLevel: CoverageLevel;
10
10
  missingScenarios?: string[];
11
11
  }
12
+ export type { AssertionPattern } from '../knowledge/route_families.js';
13
+ import type { AssertionPattern } from '../knowledge/route_families.js';
12
14
  export interface FlowDecision {
13
15
  flowId: string;
14
16
  flowName: string;
@@ -27,6 +29,7 @@ export interface FlowDecision {
27
29
  blockingReason?: string;
28
30
  priority: FlowPriority;
29
31
  userActions: string[];
32
+ assertionPatterns?: AssertionPattern[];
30
33
  }
31
34
  export interface FlowDecisionSummary {
32
35
  changedFiles: number;
@@ -1 +1 @@
1
- {"version":3,"file":"output_schema.d.ts","sourceRoot":"","sources":["../../src/validation/output_schema.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,eAAe,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAC/F,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,GAAG,eAAe,CAAC;AACjF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,iBAAiB,EAAE,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACL;AAMD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAC,CA0C1F;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,mBAAmB,CAmC3E"}
1
+ {"version":3,"file":"output_schema.d.ts","sourceRoot":"","sources":["../../src/validation/output_schema.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,eAAe,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAC/F,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,GAAG,eAAe,CAAC;AACjF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,YAAY,EAAC,gBAAgB,EAAC,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,gCAAgC,CAAC;AAErE,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,iBAAiB,EAAE,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACL;AAMD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAC,CA0C1F;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,mBAAmB,CAmC3E"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns the package version by reading the nearest package.json.
3
+ * Cached after first call.
4
+ */
5
+ export declare function getVersion(): string;
6
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAoBnC"}