@yasserkhanorg/e2e-agents 1.8.4 → 1.9.5

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 (259) 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/plan_crew.d.ts.map +1 -1
  63. package/dist/cli/commands/plan_crew.js +33 -21
  64. package/dist/cli/commands/train.d.ts.map +1 -1
  65. package/dist/cli/commands/train.js +16 -21
  66. package/dist/cli/defaults.d.ts +35 -0
  67. package/dist/cli/defaults.d.ts.map +1 -0
  68. package/dist/cli/defaults.js +125 -0
  69. package/dist/cli/errors.d.ts +27 -0
  70. package/dist/cli/errors.d.ts.map +1 -0
  71. package/dist/cli/errors.js +57 -0
  72. package/dist/cli/parse_args.d.ts.map +1 -1
  73. package/dist/cli/parse_args.js +24 -2
  74. package/dist/cli/types.d.ts +7 -1
  75. package/dist/cli/types.d.ts.map +1 -1
  76. package/dist/cli.js +47 -2
  77. package/dist/crew/context.d.ts +15 -0
  78. package/dist/crew/context.d.ts.map +1 -1
  79. package/dist/crew/orchestrator.d.ts +14 -0
  80. package/dist/crew/orchestrator.d.ts.map +1 -1
  81. package/dist/crew/orchestrator.js +162 -4
  82. package/dist/crew/protocol.d.ts +13 -0
  83. package/dist/crew/protocol.d.ts.map +1 -1
  84. package/dist/crew/provider.d.ts +15 -1
  85. package/dist/crew/provider.d.ts.map +1 -1
  86. package/dist/crew/provider.js +24 -4
  87. package/dist/custom_provider.d.ts.map +1 -1
  88. package/dist/custom_provider.js +1 -0
  89. package/dist/engine/diff_loader.d.ts.map +1 -1
  90. package/dist/engine/diff_loader.js +3 -14
  91. package/dist/engine/impact_engine.d.ts.map +1 -1
  92. package/dist/engine/impact_engine.js +9 -23
  93. package/dist/esm/adapters/cypress.js +49 -0
  94. package/dist/esm/adapters/framework_adapter.js +114 -0
  95. package/dist/esm/adapters/playwright.js +49 -0
  96. package/dist/esm/adapters/pytest.js +59 -0
  97. package/dist/esm/adapters/supertest.js +48 -0
  98. package/dist/esm/agent/git.js +3 -1
  99. package/dist/esm/agentic/fix_loop.js +5 -4
  100. package/dist/esm/agentic/runner.js +15 -12
  101. package/dist/esm/agents/cross-impact.js +6 -1
  102. package/dist/esm/agents/executor.js +6 -1
  103. package/dist/esm/agents/strategist.js +6 -1
  104. package/dist/esm/agents/test-designer.js +6 -1
  105. package/dist/esm/anthropic_provider.js +1 -0
  106. package/dist/esm/base_provider.js +121 -0
  107. package/dist/esm/budget_ledger.js +58 -0
  108. package/dist/esm/cache/cached_provider.js +82 -0
  109. package/dist/esm/cache/response_cache.js +140 -0
  110. package/dist/esm/cli/commands/bootstrap.js +106 -0
  111. package/dist/esm/cli/commands/cost_report.js +112 -0
  112. package/dist/esm/cli/commands/crew.js +118 -1
  113. package/dist/esm/cli/commands/gate.js +83 -0
  114. package/dist/esm/cli/commands/init.js +3 -58
  115. package/dist/esm/cli/commands/plan_crew.js +33 -21
  116. package/dist/esm/cli/commands/train.js +16 -21
  117. package/dist/esm/cli/defaults.js +118 -0
  118. package/dist/esm/cli/errors.js +52 -0
  119. package/dist/esm/cli/parse_args.js +24 -2
  120. package/dist/esm/cli.js +47 -2
  121. package/dist/esm/crew/orchestrator.js +162 -4
  122. package/dist/esm/crew/provider.js +24 -4
  123. package/dist/esm/custom_provider.js +1 -0
  124. package/dist/esm/engine/diff_loader.js +1 -12
  125. package/dist/esm/engine/impact_engine.js +9 -23
  126. package/dist/esm/index.js +21 -0
  127. package/dist/esm/knowledge/cluster_utils.js +60 -0
  128. package/dist/esm/knowledge/kg_bridge.js +381 -0
  129. package/dist/esm/knowledge/kg_types.js +3 -0
  130. package/dist/esm/knowledge/route_families.js +89 -0
  131. package/dist/esm/mcp-server.js +2 -4
  132. package/dist/esm/metrics/prometheus.js +149 -0
  133. package/dist/esm/model_router.js +59 -0
  134. package/dist/esm/ollama_provider.js +1 -0
  135. package/dist/esm/openai_provider.js +1 -0
  136. package/dist/esm/pipeline/orchestrator.js +6 -12
  137. package/dist/esm/pipeline/stage0_preprocess.js +12 -19
  138. package/dist/esm/pipeline/stage2_coverage.js +1 -0
  139. package/dist/esm/pipeline/stage3_generation.js +1 -0
  140. package/dist/esm/progress.js +112 -0
  141. package/dist/esm/prompts/coverage.js +7 -24
  142. package/dist/esm/prompts/cross-impact.js +3 -21
  143. package/dist/esm/prompts/generation.js +158 -36
  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/version.js +33 -0
  160. package/dist/index.d.ts +21 -1
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +45 -1
  163. package/dist/knowledge/cluster_utils.d.ts +28 -0
  164. package/dist/knowledge/cluster_utils.d.ts.map +1 -0
  165. package/dist/knowledge/cluster_utils.js +67 -0
  166. package/dist/knowledge/kg_bridge.d.ts +31 -0
  167. package/dist/knowledge/kg_bridge.d.ts.map +1 -0
  168. package/dist/knowledge/kg_bridge.js +388 -0
  169. package/dist/knowledge/kg_types.d.ts +75 -0
  170. package/dist/knowledge/kg_types.d.ts.map +1 -0
  171. package/dist/knowledge/kg_types.js +4 -0
  172. package/dist/knowledge/route_families.d.ts +18 -0
  173. package/dist/knowledge/route_families.d.ts.map +1 -1
  174. package/dist/knowledge/route_families.js +91 -0
  175. package/dist/mcp-server.d.ts.map +1 -1
  176. package/dist/mcp-server.js +2 -4
  177. package/dist/metrics/prometheus.d.ts +37 -0
  178. package/dist/metrics/prometheus.d.ts.map +1 -0
  179. package/dist/metrics/prometheus.js +153 -0
  180. package/dist/model_router.d.ts +28 -0
  181. package/dist/model_router.d.ts.map +1 -0
  182. package/dist/model_router.js +63 -0
  183. package/dist/ollama_provider.d.ts.map +1 -1
  184. package/dist/ollama_provider.js +1 -0
  185. package/dist/openai_provider.d.ts.map +1 -1
  186. package/dist/openai_provider.js +1 -0
  187. package/dist/pipeline/orchestrator.d.ts +2 -0
  188. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  189. package/dist/pipeline/orchestrator.js +6 -12
  190. package/dist/pipeline/stage0_preprocess.d.ts.map +1 -1
  191. package/dist/pipeline/stage0_preprocess.js +11 -18
  192. package/dist/pipeline/stage2_coverage.d.ts +2 -0
  193. package/dist/pipeline/stage2_coverage.d.ts.map +1 -1
  194. package/dist/pipeline/stage2_coverage.js +1 -0
  195. package/dist/pipeline/stage3_generation.d.ts +2 -0
  196. package/dist/pipeline/stage3_generation.d.ts.map +1 -1
  197. package/dist/pipeline/stage3_generation.js +1 -0
  198. package/dist/pipeline/stage4_heal.d.ts +2 -0
  199. package/dist/pipeline/stage4_heal.d.ts.map +1 -1
  200. package/dist/progress.d.ts +22 -0
  201. package/dist/progress.d.ts.map +1 -0
  202. package/dist/progress.js +116 -0
  203. package/dist/prompts/coverage.d.ts +2 -0
  204. package/dist/prompts/coverage.d.ts.map +1 -1
  205. package/dist/prompts/coverage.js +7 -24
  206. package/dist/prompts/cross-impact.d.ts +1 -0
  207. package/dist/prompts/cross-impact.d.ts.map +1 -1
  208. package/dist/prompts/cross-impact.js +3 -21
  209. package/dist/prompts/generation.d.ts +3 -1
  210. package/dist/prompts/generation.d.ts.map +1 -1
  211. package/dist/prompts/generation.js +158 -36
  212. package/dist/prompts/generation_profile.d.ts +29 -0
  213. package/dist/prompts/generation_profile.d.ts.map +1 -0
  214. package/dist/prompts/generation_profile.js +151 -0
  215. package/dist/prompts/heal.d.ts +3 -1
  216. package/dist/prompts/heal.d.ts.map +1 -1
  217. package/dist/prompts/heal.js +33 -15
  218. package/dist/prompts/impact.d.ts +1 -0
  219. package/dist/prompts/impact.d.ts.map +1 -1
  220. package/dist/prompts/impact.js +3 -22
  221. package/dist/prompts/json_extract.d.ts +14 -0
  222. package/dist/prompts/json_extract.d.ts.map +1 -0
  223. package/dist/prompts/json_extract.js +39 -0
  224. package/dist/prompts/strategist.d.ts.map +1 -1
  225. package/dist/prompts/strategist.js +2 -20
  226. package/dist/prompts/test-designer.d.ts +2 -0
  227. package/dist/prompts/test-designer.d.ts.map +1 -1
  228. package/dist/prompts/test-designer.js +6 -21
  229. package/dist/provider_factory.d.ts.map +1 -1
  230. package/dist/provider_factory.js +6 -4
  231. package/dist/reporters/junit.d.ts +6 -0
  232. package/dist/reporters/junit.d.ts.map +1 -0
  233. package/dist/reporters/junit.js +89 -0
  234. package/dist/reporters/reporter.d.ts +42 -0
  235. package/dist/reporters/reporter.d.ts.map +1 -0
  236. package/dist/reporters/reporter.js +4 -0
  237. package/dist/reporters/sarif.d.ts +7 -0
  238. package/dist/reporters/sarif.d.ts.map +1 -0
  239. package/dist/reporters/sarif.js +134 -0
  240. package/dist/resilience/circuit_breaker.d.ts +36 -0
  241. package/dist/resilience/circuit_breaker.d.ts.map +1 -0
  242. package/dist/resilience/circuit_breaker.js +82 -0
  243. package/dist/resilience/retry.d.ts +11 -0
  244. package/dist/resilience/retry.d.ts.map +1 -0
  245. package/dist/resilience/retry.js +59 -0
  246. package/dist/sanitize.d.ts +15 -0
  247. package/dist/sanitize.d.ts.map +1 -0
  248. package/dist/sanitize.js +71 -0
  249. package/dist/training/kg_scanner.d.ts +13 -0
  250. package/dist/training/kg_scanner.d.ts.map +1 -0
  251. package/dist/training/kg_scanner.js +118 -0
  252. package/dist/training/scanner.d.ts +7 -2
  253. package/dist/training/scanner.d.ts.map +1 -1
  254. package/dist/training/scanner.js +27 -34
  255. package/dist/version.d.ts +6 -0
  256. package/dist/version.d.ts.map +1 -0
  257. package/dist/version.js +36 -0
  258. package/package.json +7 -2
  259. package/schemas/route-families.schema.json +31 -1
@@ -9,6 +9,7 @@ import type { ProviderUsageStats } from '../provider_interface.js';
9
9
  import type { GeneratedSpec } from '../pipeline/stage3_generation.js';
10
10
  import type { LoadedContext } from '../knowledge/context_loader.js';
11
11
  import type { FamilyGroup, PreprocessResult } from '../pipeline/stage0_preprocess.js';
12
+ import type { BudgetLedger } from '../budget_ledger.js';
12
13
  import type { AgentMessage } from './protocol.js';
13
14
  import type { TestDesign, CrossImpact, Finding, StrategyEntry, RegressionRisk } from './types.js';
14
15
  export interface CrewContext {
@@ -24,6 +25,11 @@ export interface CrewContext {
24
25
  testsRoot: string;
25
26
  gitSince: string;
26
27
  providerOverride?: string;
28
+ budgetUSD?: number;
29
+ modelRoutingProviderType?: string;
30
+ modelRoutingOverrides?: Record<string, string>;
31
+ /** @internal Shared budget enforcement — not part of the public API. */
32
+ budgetLedger?: BudgetLedger;
27
33
  impactedFlows: FlowDecision[];
28
34
  strategyEntries: StrategyEntry[];
29
35
  testDesigns: TestDesign[];
@@ -32,9 +38,18 @@ export interface CrewContext {
32
38
  findings: Finding[];
33
39
  generatedSpecs: GeneratedSpec[];
34
40
  usage: ProviderUsageStats;
41
+ agentUsage: AgentUsageEntry[];
35
42
  messages: AgentMessage[];
36
43
  warnings: string[];
37
44
  }
45
+ export interface AgentUsageEntry {
46
+ agent: string;
47
+ family?: string;
48
+ inputTokens: number;
49
+ outputTokens: number;
50
+ cost: number;
51
+ durationMs: number;
52
+ }
38
53
  export declare function createEmptyUsageStats(): ProviderUsageStats;
39
54
  export declare function mergeUsageStats(target: ProviderUsageStats, source: ProviderUsageStats): void;
40
55
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/crew/context.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAE,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,WAAW,EAAE,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACpF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AAEhG,MAAM,WAAW,WAAW;IAExB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAGhC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,CAa1D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAe5F"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/crew/context.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAE,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,WAAW,EAAE,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACpF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AAEhG,MAAM,WAAW,WAAW;IAExB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,wEAAwE;IACxE,YAAY,CAAC,EAAE,YAAY,CAAC;IAG5B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAGhC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,CAa1D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAe5F"}
@@ -15,15 +15,22 @@ export interface CrewConfig {
15
15
  providerOverride?: string;
16
16
  budgetUSD?: number;
17
17
  dryRun?: boolean;
18
+ plugins?: string[];
18
19
  }
19
20
  export interface CrewResult {
20
21
  context: CrewContext;
21
22
  warnings: string[];
22
23
  timings: Record<string, number>;
24
+ dryRun?: boolean;
23
25
  }
24
26
  export declare class CrewOrchestrator {
25
27
  private agents;
26
28
  registerAgent(agent: Agent): void;
29
+ /**
30
+ * Load and register plugins from file paths.
31
+ * Each module must default-export an object satisfying AgentPlugin.
32
+ */
33
+ loadPlugins(pluginPaths: string[]): Promise<string[]>;
27
34
  run(config: CrewConfig): Promise<CrewResult>;
28
35
  dispatch(role: AgentRole, action: string, ctx: CrewContext): Promise<AgentResult>;
29
36
  parallel(roles: AgentRole[], action: string, ctx: CrewContext): Promise<AgentResult[]>;
@@ -31,6 +38,13 @@ export declare class CrewOrchestrator {
31
38
  private runBuiltInPhase;
32
39
  private runParallel;
33
40
  private runSequential;
41
+ /**
42
+ * Inject loaded plugins into workflow phases based on their `phase` and `runAfter` fields.
43
+ * Plugins with `runAfter` dependencies are appended to the sequential list of the matching phase;
44
+ * plugins without `runAfter` are appended to the parallel list.
45
+ * Returns a new array of phases (does not mutate the original workflow definition).
46
+ */
47
+ private injectPluginsIntoPhases;
34
48
  private checkPhaseResults;
35
49
  }
36
50
  //# sourceMappingURL=orchestrator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/crew/orchestrator.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAC,KAAK,EAAE,YAAY,EAAE,WAAW,EAAY,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAA6B,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAG7E,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAA+B;IAE7C,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI3B,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAwE5C,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BjF,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtF,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;YAerD,eAAe;YAwBf,WAAW;YAMX,aAAa;IAS3B,OAAO,CAAC,iBAAiB;CAM5B"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/crew/orchestrator.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAC,KAAK,EAAE,YAAY,EAAe,WAAW,EAAY,MAAM,eAAe,CAAC;AAC5F,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAA6B,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAG7E,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAA+B;IAE7C,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIjC;;;OAGG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAqCrD,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAiG5C,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA0CjF,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtF,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;YAerD,eAAe;YAwBf,WAAW;YAMX,aAAa;IAS3B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IA2E/B,OAAO,CAAC,iBAAiB;CAM5B"}
@@ -9,6 +9,8 @@ exports.CrewOrchestrator = void 0;
9
9
  const git_js_1 = require("../agent/git.js");
10
10
  const stage0_preprocess_js_1 = require("../pipeline/stage0_preprocess.js");
11
11
  const logger_js_1 = require("../logger.js");
12
+ const base_provider_js_1 = require("../base_provider.js");
13
+ const budget_ledger_js_1 = require("../budget_ledger.js");
12
14
  const context_js_1 = require("./context.js");
13
15
  const workflows_js_1 = require("./workflows.js");
14
16
  class CrewOrchestrator {
@@ -18,10 +20,61 @@ class CrewOrchestrator {
18
20
  registerAgent(agent) {
19
21
  this.agents.set(agent.role, agent);
20
22
  }
23
+ /**
24
+ * Load and register plugins from file paths.
25
+ * Each module must default-export an object satisfying AgentPlugin.
26
+ */
27
+ async loadPlugins(pluginPaths) {
28
+ const loaded = [];
29
+ for (const pluginPath of pluginPaths) {
30
+ try {
31
+ // Security: Only allow relative paths (starting with . or ..) to prevent loading arbitrary modules.
32
+ // Absolute paths, URLs, and node_modules references are rejected.
33
+ if (!pluginPath.startsWith('.')) {
34
+ logger_js_1.logger.warn(`Plugin path must be relative (start with ./): ${pluginPath} — skipped`);
35
+ continue;
36
+ }
37
+ const resolved = new URL(pluginPath, `file://${process.cwd()}/`).href;
38
+ // Security: reject paths that resolve outside the workspace (e.g., ../../etc/evil.js)
39
+ const cwd = `file://${process.cwd()}/`;
40
+ if (!resolved.startsWith(cwd)) {
41
+ logger_js_1.logger.warn(`Plugin path '${pluginPath}' resolves outside workspace — skipped`);
42
+ continue;
43
+ }
44
+ const mod = await import(resolved);
45
+ const plugin = mod.default || mod;
46
+ if (!plugin.role || typeof plugin.execute !== 'function') {
47
+ logger_js_1.logger.warn(`Plugin at ${pluginPath} missing required role/execute — skipped`);
48
+ continue;
49
+ }
50
+ // Warn if plugin overrides a built-in agent
51
+ if (this.agents.has(plugin.role)) {
52
+ logger_js_1.logger.warn(`Plugin '${plugin.role}' overrides built-in agent — ensure this is intentional`);
53
+ }
54
+ this.agents.set(plugin.role, plugin);
55
+ loaded.push(plugin.role);
56
+ }
57
+ catch (error) {
58
+ const msg = error instanceof Error ? error.message : String(error);
59
+ logger_js_1.logger.warn(`Failed to load plugin ${pluginPath}: ${msg}`);
60
+ }
61
+ }
62
+ return loaded;
63
+ }
21
64
  async run(config) {
22
65
  const workflow = workflows_js_1.WORKFLOWS[config.workflow || 'full-qa'];
23
66
  const timings = {};
24
67
  const warnings = [];
68
+ // Load plugins if configured, then inject them into workflow phases
69
+ const pluginRoles = [];
70
+ if (config.plugins && config.plugins.length > 0) {
71
+ const loaded = await this.loadPlugins(config.plugins);
72
+ pluginRoles.push(...loaded);
73
+ if (loaded.length > 0) {
74
+ logger_js_1.logger.info(`Loaded ${loaded.length} plugins: ${loaded.join(', ')}`);
75
+ }
76
+ }
77
+ const effectivePhases = this.injectPluginsIntoPhases(workflow.phases, pluginRoles);
25
78
  // Step 1: Get changed files
26
79
  const gitResult = (0, git_js_1.getChangedFiles)(config.appPath, config.gitSince, {
27
80
  includeUncommitted: config.gitIncludeUncommitted,
@@ -35,6 +88,8 @@ class CrewOrchestrator {
35
88
  if (changedFiles.length === 0) {
36
89
  warnings.push('No changed application files detected.');
37
90
  }
91
+ // Create shared budget ledger for aggregate cost tracking across all agents
92
+ const budgetLedger = config.budgetUSD ? new budget_ledger_js_1.BudgetLedger(config.budgetUSD) : undefined;
38
93
  // Initialize context (will be populated during preprocess phase)
39
94
  const ctx = {
40
95
  changedFiles,
@@ -49,6 +104,8 @@ class CrewOrchestrator {
49
104
  testsRoot: config.testsRoot,
50
105
  gitSince: config.gitSince,
51
106
  providerOverride: config.providerOverride,
107
+ budgetUSD: config.budgetUSD,
108
+ budgetLedger,
52
109
  impactedFlows: [],
53
110
  strategyEntries: [],
54
111
  testDesigns: [],
@@ -57,14 +114,21 @@ class CrewOrchestrator {
57
114
  findings: [],
58
115
  generatedSpecs: [],
59
116
  usage: (0, context_js_1.createEmptyUsageStats)(),
117
+ agentUsage: [],
60
118
  messages: [],
61
119
  warnings,
62
120
  };
63
121
  // Execute each phase
64
- for (const phase of workflow.phases) {
122
+ for (const phase of effectivePhases) {
65
123
  const timer = logger_js_1.logger.timer(`crew:${phase.name}`);
66
124
  if (phase.handler === 'built-in') {
67
125
  await this.runBuiltInPhase(phase.name, ctx, config);
126
+ // Dry-run: after preprocess, return summary without running agents
127
+ if (config.dryRun && phase.name === 'preprocess') {
128
+ timings[phase.name] = timer.end();
129
+ ctx.warnings.push('Dry run — no LLM calls were made.');
130
+ return { context: ctx, warnings, timings, dryRun: true };
131
+ }
68
132
  }
69
133
  else if (phase.parallel && phase.parallel.length > 0) {
70
134
  await this.runParallel(phase.parallel, phase.name, ctx);
@@ -76,9 +140,10 @@ class CrewOrchestrator {
76
140
  warnings.push(`Phase '${phase.name}' has no handler, parallel, or sequential agents — skipped.`);
77
141
  }
78
142
  timings[phase.name] = timer.end();
79
- // Budget check
80
- if (config.budgetUSD && ctx.usage.totalCost >= config.budgetUSD) {
81
- warnings.push(`Budget limit reached ($${ctx.usage.totalCost.toFixed(4)} >= $${config.budgetUSD}). Stopping workflow.`);
143
+ // Budget check — prefer ledger (aggregate across all providers) over ctx.usage
144
+ const currentCost = budgetLedger ? budgetLedger.totalCost : ctx.usage.totalCost;
145
+ if (config.budgetUSD && currentCost >= config.budgetUSD) {
146
+ warnings.push(`Budget limit reached ($${currentCost.toFixed(4)} >= $${config.budgetUSD}). Stopping workflow.`);
82
147
  break;
83
148
  }
84
149
  }
@@ -95,10 +160,19 @@ class CrewOrchestrator {
95
160
  };
96
161
  }
97
162
  const task = { role, action, input: null };
163
+ const startMs = Date.now();
98
164
  try {
99
165
  const result = await agent.execute(task, ctx);
166
+ const durationMs = Date.now() - startMs;
100
167
  if (result.usage) {
101
168
  (0, context_js_1.mergeUsageStats)(ctx.usage, result.usage);
169
+ ctx.agentUsage.push({
170
+ agent: role,
171
+ inputTokens: result.usage.totalInputTokens,
172
+ outputTokens: result.usage.totalOutputTokens,
173
+ cost: result.usage.totalCost,
174
+ durationMs,
175
+ });
102
176
  }
103
177
  if (result.warnings && result.warnings.length > 0) {
104
178
  ctx.warnings.push(...result.warnings);
@@ -106,6 +180,10 @@ class CrewOrchestrator {
106
180
  return result;
107
181
  }
108
182
  catch (error) {
183
+ if (error instanceof base_provider_js_1.BudgetExceededError) {
184
+ ctx.warnings.push(`Budget exceeded ($${error.currentCost.toFixed(4)} >= $${error.budgetUSD}). Agent '${role}' skipped.`);
185
+ return { role, status: 'failed', output: null, warnings: [error.message] };
186
+ }
109
187
  const message = error instanceof Error ? error.message : String(error);
110
188
  ctx.warnings.push(`Agent '${role}' failed: ${message}`);
111
189
  return { role, status: 'failed', output: null, warnings: [message] };
@@ -161,6 +239,86 @@ class CrewOrchestrator {
161
239
  }
162
240
  this.checkPhaseResults(phaseName, results, ctx);
163
241
  }
242
+ /**
243
+ * Inject loaded plugins into workflow phases based on their `phase` and `runAfter` fields.
244
+ * Plugins with `runAfter` dependencies are appended to the sequential list of the matching phase;
245
+ * plugins without `runAfter` are appended to the parallel list.
246
+ * Returns a new array of phases (does not mutate the original workflow definition).
247
+ */
248
+ injectPluginsIntoPhases(phases, pluginRoles) {
249
+ if (pluginRoles.length === 0)
250
+ return phases;
251
+ // Build mutable copies keyed by phase name
252
+ const phaseMap = new Map();
253
+ const ordered = [];
254
+ for (const p of phases) {
255
+ ordered.push(p.name);
256
+ if (p.handler === 'built-in') {
257
+ phaseMap.set(p.name, { handler: 'built-in' });
258
+ }
259
+ else if (p.parallel) {
260
+ phaseMap.set(p.name, { parallel: [...p.parallel] });
261
+ }
262
+ else if (p.sequential) {
263
+ phaseMap.set(p.name, { sequential: [...p.sequential] });
264
+ }
265
+ }
266
+ for (const role of pluginRoles) {
267
+ const agent = this.agents.get(role);
268
+ if (!agent)
269
+ continue;
270
+ const plugin = agent;
271
+ if (!plugin.phase)
272
+ continue;
273
+ const target = phaseMap.get(plugin.phase);
274
+ if (!target) {
275
+ logger_js_1.logger.warn(`Plugin '${role}' targets phase '${plugin.phase}' which does not exist in workflow — skipped`);
276
+ continue;
277
+ }
278
+ if (target.handler === 'built-in') {
279
+ logger_js_1.logger.warn(`Plugin '${role}' targets built-in phase '${plugin.phase}' — not supported, skipped`);
280
+ continue;
281
+ }
282
+ const pluginRole = role;
283
+ if (plugin.runAfter && plugin.runAfter.length > 0) {
284
+ // Validate that runAfter dependencies are either in this phase or a prior phase
285
+ const phaseRoles = target.parallel || target.sequential || [];
286
+ const missingDeps = plugin.runAfter.filter((dep) => !phaseRoles.includes(dep) && !this.agents.has(dep));
287
+ if (missingDeps.length > 0) {
288
+ logger_js_1.logger.warn(`Plugin '${role}' has unresolved runAfter deps [${missingDeps.join(', ')}] — injecting anyway`);
289
+ }
290
+ // Plugin has dependencies — must run sequentially
291
+ if (target.sequential) {
292
+ target.sequential.push(pluginRole);
293
+ }
294
+ else if (target.parallel) {
295
+ // Convert to sequential to respect dependency ordering
296
+ target.sequential = [...target.parallel, pluginRole];
297
+ delete target.parallel;
298
+ }
299
+ }
300
+ else {
301
+ if (target.parallel) {
302
+ target.parallel.push(pluginRole);
303
+ }
304
+ else if (target.sequential) {
305
+ target.sequential.push(pluginRole);
306
+ }
307
+ }
308
+ logger_js_1.logger.info(`Plugin '${role}' injected into phase '${plugin.phase}'`);
309
+ }
310
+ // Rebuild WorkflowPhase array
311
+ return ordered.map((name) => {
312
+ const entry = phaseMap.get(name);
313
+ if (entry.handler === 'built-in')
314
+ return { name, handler: 'built-in' };
315
+ if (entry.parallel)
316
+ return { name, parallel: entry.parallel };
317
+ if (entry.sequential)
318
+ return { name, sequential: entry.sequential };
319
+ throw new Error(`Phase '${name}' has no handler, parallel, or sequential agents after plugin injection`);
320
+ });
321
+ }
164
322
  checkPhaseResults(phaseName, results, ctx) {
165
323
  const allFailed = results.length > 0 && results.every((r) => r.status === 'failed');
166
324
  if (allFailed) {
@@ -30,4 +30,17 @@ export interface Agent {
30
30
  execute(task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
31
31
  onMessage?(msg: AgentMessage): Promise<void>;
32
32
  }
33
+ /**
34
+ * AgentPlugin — interface for external agent plugins loaded from config.
35
+ *
36
+ * Plugins register into crew workflow phases alongside built-in agents.
37
+ * The CrewContext interface is a public API contract once plugins exist:
38
+ * field additions are non-breaking, field removals or type changes are breaking.
39
+ */
40
+ export interface AgentPlugin extends Agent {
41
+ /** Which workflow phase to run in (e.g., 'strategize', 'understand') */
42
+ phase: string;
43
+ /** Run after these agents complete (dependency ordering) */
44
+ runAfter?: AgentRole[];
45
+ }
33
46
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/crew/protocol.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,GAAG,WAAW,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/crew/protocol.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,GAAG,WAAW,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAY,SAAQ,KAAK;IACtC,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;CAC1B"}
@@ -1,3 +1,17 @@
1
1
  import type { LLMProvider } from '../provider_interface.js';
2
- export declare function getCrewProvider(providerOverride?: string): Promise<LLMProvider>;
2
+ import type { BudgetLedger } from '../budget_ledger.js';
3
+ import type { AgentRole } from './types.js';
4
+ export interface CrewProviderOptions {
5
+ providerOverride?: string;
6
+ budgetUSD?: number;
7
+ agentRole?: AgentRole;
8
+ modelRoutingProviderType?: string;
9
+ modelRoutingOverrides?: Record<string, string>;
10
+ }
11
+ export declare function getCrewProvider(providerOverride?: string, budgetUSD?: number, opts?: {
12
+ agentRole?: AgentRole;
13
+ modelRoutingProviderType?: string;
14
+ modelRoutingOverrides?: Record<string, string>;
15
+ budgetLedger?: BudgetLedger;
16
+ }): Promise<LLMProvider>;
3
17
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/crew/provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAE1D,wBAAsB,eAAe,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAKrF"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/crew/provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAG1D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAED,wBAAsB,eAAe,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IACxF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B,GAAG,OAAO,CAAC,WAAW,CAAC,CA0BvB"}
@@ -8,9 +8,29 @@ exports.getCrewProvider = getCrewProvider;
8
8
  * instantiation and prevents usage stats fragmentation.
9
9
  */
10
10
  const provider_factory_js_1 = require("../provider_factory.js");
11
- async function getCrewProvider(providerOverride) {
12
- if (providerOverride) {
13
- return provider_factory_js_1.LLMProviderFactory.createFromString(providerOverride);
11
+ const base_provider_js_1 = require("../base_provider.js");
12
+ const model_router_js_1 = require("../model_router.js");
13
+ async function getCrewProvider(providerOverride, budgetUSD, opts) {
14
+ let effectiveOverride = providerOverride;
15
+ // Apply model routing if configured and agent role is provided
16
+ if (opts?.agentRole && opts?.modelRoutingProviderType) {
17
+ const router = new model_router_js_1.ModelRouter(opts.modelRoutingProviderType, opts.modelRoutingOverrides);
18
+ const model = router.getModel(opts.agentRole);
19
+ if (model) {
20
+ // Override uses provider:model format (e.g., "anthropic:claude-haiku-4-5-20251001")
21
+ effectiveOverride = `${opts.modelRoutingProviderType}:${model}`;
22
+ }
14
23
  }
15
- return provider_factory_js_1.LLMProviderFactory.createFromEnv();
24
+ const provider = effectiveOverride
25
+ ? await provider_factory_js_1.LLMProviderFactory.createFromString(effectiveOverride)
26
+ : await provider_factory_js_1.LLMProviderFactory.createFromEnv();
27
+ if (provider instanceof base_provider_js_1.BaseProvider) {
28
+ if (opts?.budgetLedger) {
29
+ provider.setBudgetLedger(opts.budgetLedger);
30
+ }
31
+ else if (budgetUSD !== undefined) {
32
+ provider.setBudget(budgetUSD);
33
+ }
34
+ }
35
+ return provider;
16
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"custom_provider.d.ts","sourceRoot":"","sources":["../src/custom_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,oBAAoB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AA6DhD,qBAAa,cAAe,SAAQ,YAAY;IAC5C,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAe;IAE7B,YAAY,EAAE,oBAAoB,CAAC;gBAEvB,MAAM,EAAE,YAAY;IAyB1B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAkC7E,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;YAyC3F,eAAe;YAiBf,aAAa;YA8Eb,gBAAgB;YA6EhB,aAAa;IAqBpB,UAAU,IAAI,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IAKpD,WAAW,IAAI,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAOpE"}
1
+ {"version":3,"file":"custom_provider.d.ts","sourceRoot":"","sources":["../src/custom_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,oBAAoB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AA6DhD,qBAAa,cAAe,SAAQ,YAAY;IAC5C,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAe;IAE7B,YAAY,EAAE,oBAAoB,CAAC;gBAEvB,MAAM,EAAE,YAAY;IAyB1B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAmC7E,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;YAyC3F,eAAe;YAiBf,aAAa;YA8Eb,gBAAgB;YA6EhB,aAAa;IAqBpB,UAAU,IAAI,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IAKpD,WAAW,IAAI,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAOpE"}
@@ -68,6 +68,7 @@ class CustomProvider extends base_provider_js_1.BaseProvider {
68
68
  };
69
69
  }
70
70
  async generateText(prompt, options) {
71
+ this.checkBudget();
71
72
  const startTime = Date.now();
72
73
  try {
73
74
  if (prompt.length > 10 * 1024 * 1024) {
@@ -1 +1 @@
1
- {"version":3,"file":"diff_loader.d.ts","sourceRoot":"","sources":["../../src/engine/diff_loader.ts"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA0CrG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUvE"}
1
+ {"version":3,"file":"diff_loader.d.ts","sourceRoot":"","sources":["../../src/engine/diff_loader.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA0CrG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUvE"}
@@ -4,21 +4,10 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.loadDiffs = loadDiffs;
6
6
  exports.formatDiffsForPrompt = formatDiffsForPrompt;
7
- const child_process_1 = require("child_process");
7
+ const git_js_1 = require("../agent/git.js");
8
8
  const MAX_DIFF_CHARS = 8000;
9
9
  const MAX_TOTAL_CHARS = 60000;
10
10
  const TRUNCATION_NOTICE = '\n... (diff truncated)';
11
- function runGitRaw(args, cwd) {
12
- const result = (0, child_process_1.spawnSync)('git', args, {
13
- cwd,
14
- encoding: 'utf-8',
15
- timeout: 30000,
16
- });
17
- if (result.error || result.status !== 0) {
18
- return null;
19
- }
20
- return result.stdout;
21
- }
22
11
  /**
23
12
  * Loads git diffs for the given changed files relative to the given since ref.
24
13
  * Uses `git merge-base` to find the accurate base ref first.
@@ -31,7 +20,7 @@ function loadDiffs(appRoot, since, changedFiles) {
31
20
  }
32
21
  // Try to get accurate merge base
33
22
  let baseRef = since;
34
- const mergeBaseOutput = runGitRaw(['merge-base', since, 'HEAD'], appRoot);
23
+ const mergeBaseOutput = (0, git_js_1.runGitRaw)(['merge-base', since, 'HEAD'], appRoot);
35
24
  if (mergeBaseOutput) {
36
25
  const candidate = mergeBaseOutput
37
26
  .split('\n')
@@ -46,7 +35,7 @@ function loadDiffs(appRoot, since, changedFiles) {
46
35
  if (totalChars >= MAX_TOTAL_CHARS) {
47
36
  break;
48
37
  }
49
- const diffOutput = runGitRaw(['diff', `${baseRef}..HEAD`, '--', file], appRoot);
38
+ const diffOutput = (0, git_js_1.runGitRaw)(['diff', `${baseRef}..HEAD`, '--', file], appRoot);
50
39
  if (diffOutput === null) {
51
40
  continue;
52
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"impact_engine.d.ts","sourceRoot":"","sources":["../../src/engine/impact_engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGR,eAAe,EAClB,MAAM,gCAAgC,CAAC;AASxC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAE5D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,EAAE,iBAAiB,EAAE,CAAC;IAC3C,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5E,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oFAAoF;IACpF,mBAAmB,EAAE,UAAU,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,yHAAyH;IACzH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AA+CD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,EAAE,CAgBhG;AA0GD,wBAAgB,aAAa,CACzB,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,mBAAmB,GAC7B,YAAY,CAuFd;AAYD,MAAM,WAAW,SAAS;IACtB,oDAAoD;IACpD,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,0IAA0I;IAC1I,cAAc,EAAE,eAAe,EAAE,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CA2BrE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,EAAE,CAE/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,EAAE,CAItE"}
1
+ {"version":3,"file":"impact_engine.d.ts","sourceRoot":"","sources":["../../src/engine/impact_engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGR,eAAe,EAClB,MAAM,gCAAgC,CAAC;AAUxC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAG5D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,EAAE,iBAAiB,EAAE,CAAC;IAC3C,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5E,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oFAAoF;IACpF,mBAAmB,EAAE,UAAU,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,yHAAyH;IACzH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AA+CD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,EAAE,CAgBhG;AAgGD,wBAAgB,aAAa,CACzB,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,mBAAmB,GAC7B,YAAY,CAoFd;AAYD,MAAM,WAAW,SAAS;IACtB,oDAAoD;IACpD,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,0IAA0I;IAC1I,cAAc,EAAE,eAAe,EAAE,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CA2BrE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,EAAE,CAE/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,EAAE,CAItE"}
@@ -10,6 +10,7 @@ exports.getPartialGaps = getPartialGaps;
10
10
  const fs_1 = require("fs");
11
11
  const path_1 = require("path");
12
12
  const route_families_js_1 = require("../knowledge/route_families.js");
13
+ const git_js_1 = require("../agent/git.js");
13
14
  function scanDirForSpecs(baseDir, specDir, extension) {
14
15
  const fullDir = (0, path_1.join)(baseDir, specDir);
15
16
  if (!(0, fs_1.existsSync)(fullDir)) {
@@ -132,7 +133,8 @@ function groupBindings(fileBindings) {
132
133
  const key = binding.feature || binding.family;
133
134
  const existing = groups.get(key);
134
135
  if (existing) {
135
- if (!existing.files.includes(fb.file)) {
136
+ if (!existing._seen.has(fb.file)) {
137
+ existing._seen.add(fb.file);
136
138
  existing.files.push(fb.file);
137
139
  }
138
140
  }
@@ -141,23 +143,13 @@ function groupBindings(fileBindings) {
141
143
  familyId: binding.family,
142
144
  featureId: binding.feature,
143
145
  files: [fb.file],
146
+ _seen: new Set([fb.file]),
144
147
  });
145
148
  }
146
149
  }
147
150
  }
148
151
  return groups;
149
152
  }
150
- /** Filter out test files that should not be treated as application changes. */
151
- function isTestFile(file) {
152
- const normalized = file.replace(/\\/g, '/');
153
- return /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(normalized) ||
154
- /\.snap$/.test(normalized) ||
155
- /_test\.go$/.test(normalized) ||
156
- normalized.includes('__tests__/') ||
157
- normalized.includes('__snapshots__/') ||
158
- normalized.includes('/tests/') ||
159
- normalized.includes('/test/');
160
- }
161
153
  /** Classify filtered test files by type for downstream decision-making. */
162
154
  function classifyPrTestFiles(allFiles, sourceFiles) {
163
155
  const sourceSet = new Set(sourceFiles);
@@ -185,19 +177,13 @@ function analyzeImpact(changedFiles, options) {
185
177
  // (b) test files pre-filtered by the caller (filteredTestFiles from git.ts).
186
178
  const preFilteredTests = options.filteredTestFiles ?? [];
187
179
  const allOriginalFiles = [...new Set([...changedFiles, ...preFilteredTests])];
188
- changedFiles = changedFiles.filter((f) => !isTestFile(f));
180
+ changedFiles = changedFiles.filter((f) => !(0, git_js_1.isTestFile)(f));
189
181
  const prIncludedTestFiles = classifyPrTestFiles(allOriginalFiles, changedFiles);
190
- // Load manifest
191
- const manifest = (0, route_families_js_1.loadRouteFamilyManifest)(testsRoot, routeFamilies);
182
+ // Load manifest, fall back to heuristic families if not found
183
+ let manifest = (0, route_families_js_1.loadRouteFamilyManifest)(testsRoot, routeFamilies);
192
184
  if (!manifest) {
193
- return {
194
- changedFiles,
195
- expandedFiles: options.expandedFiles || [],
196
- impactedFeatures: [],
197
- unboundFiles: [...changedFiles],
198
- warnings: ['Route family manifest not found. All files are unbound.'],
199
- prIncludedTestFiles,
200
- };
185
+ manifest = (0, route_families_js_1.buildHeuristicFamilies)(changedFiles, testsRoot);
186
+ warnings.push('Route family manifest not found. Using directory-based heuristics (lower accuracy).', 'Tip: Run `e2e-ai-agents train` to generate a proper manifest.');
201
187
  }
202
188
  // Combine original + expanded files
203
189
  const allFiles = [...new Set([...changedFiles, ...(options.expandedFiles || [])])];
@@ -0,0 +1,49 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ /**
4
+ * Cypress Adapter — FrameworkAdapter implementation for Cypress.
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ export class CypressAdapter {
9
+ constructor() {
10
+ this.name = 'cypress';
11
+ this.specGlob = '**/*.cy.{ts,js,tsx,jsx}';
12
+ this.extractTestPattern = /\b(?:it|describe|context)\s*\(/g;
13
+ this.configFileNames = ['cypress.config.ts', 'cypress.config.js'];
14
+ }
15
+ detect(projectRoot) {
16
+ const pkgPath = path.join(projectRoot, 'package.json');
17
+ if (!fs.existsSync(pkgPath)) {
18
+ return false;
19
+ }
20
+ try {
21
+ const raw = fs.readFileSync(pkgPath, 'utf-8');
22
+ const pkg = JSON.parse(raw);
23
+ const allDeps = {
24
+ ...pkg.dependencies,
25
+ ...pkg.devDependencies,
26
+ };
27
+ return 'cypress' in allDeps;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ buildRunCommand(specPath, options) {
34
+ const args = ['cypress', 'run', '--spec', specPath];
35
+ if (options?.headed) {
36
+ args.push('--headed');
37
+ }
38
+ if (options?.browser) {
39
+ args.push('--browser', options.browser);
40
+ }
41
+ if (options?.project) {
42
+ args.push('--project', options.project);
43
+ }
44
+ if (options?.timeout != null) {
45
+ args.push('--config', `defaultCommandTimeout=${options.timeout}`);
46
+ }
47
+ return { executable: 'npx', args };
48
+ }
49
+ }