@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.
- package/README.md +95 -8
- package/dist/adapters/cypress.d.ts +10 -0
- package/dist/adapters/cypress.d.ts.map +1 -0
- package/dist/adapters/cypress.js +86 -0
- package/dist/adapters/framework_adapter.d.ts +41 -0
- package/dist/adapters/framework_adapter.d.ts.map +1 -0
- package/dist/adapters/framework_adapter.js +152 -0
- package/dist/adapters/playwright.d.ts +10 -0
- package/dist/adapters/playwright.d.ts.map +1 -0
- package/dist/adapters/playwright.js +86 -0
- package/dist/adapters/pytest.d.ts +10 -0
- package/dist/adapters/pytest.d.ts.map +1 -0
- package/dist/adapters/pytest.js +96 -0
- package/dist/adapters/supertest.d.ts +12 -0
- package/dist/adapters/supertest.d.ts.map +1 -0
- package/dist/adapters/supertest.js +85 -0
- package/dist/agent/config.d.ts +1 -1
- package/dist/agent/config.d.ts.map +1 -1
- package/dist/agent/git.d.ts +1 -0
- package/dist/agent/git.d.ts.map +1 -1
- package/dist/agent/git.js +3 -0
- package/dist/agentic/fix_loop.d.ts.map +1 -1
- package/dist/agentic/fix_loop.js +5 -4
- package/dist/agentic/runner.d.ts +2 -0
- package/dist/agentic/runner.d.ts.map +1 -1
- package/dist/agentic/runner.js +15 -12
- package/dist/agents/cross-impact.d.ts.map +1 -1
- package/dist/agents/cross-impact.js +6 -1
- package/dist/agents/executor.d.ts.map +1 -1
- package/dist/agents/executor.js +6 -1
- package/dist/agents/strategist.d.ts.map +1 -1
- package/dist/agents/strategist.js +6 -1
- package/dist/agents/test-designer.d.ts.map +1 -1
- package/dist/agents/test-designer.js +6 -1
- package/dist/anthropic_provider.d.ts.map +1 -1
- package/dist/anthropic_provider.js +1 -0
- package/dist/base_provider.d.ts +56 -0
- package/dist/base_provider.d.ts.map +1 -1
- package/dist/base_provider.js +123 -1
- package/dist/budget_ledger.d.ts +28 -0
- package/dist/budget_ledger.d.ts.map +1 -0
- package/dist/budget_ledger.js +62 -0
- package/dist/cache/cached_provider.d.ts +45 -0
- package/dist/cache/cached_provider.d.ts.map +1 -0
- package/dist/cache/cached_provider.js +88 -0
- package/dist/cache/response_cache.d.ts +79 -0
- package/dist/cache/response_cache.d.ts.map +1 -0
- package/dist/cache/response_cache.js +177 -0
- package/dist/cli/commands/bootstrap.d.ts +3 -0
- package/dist/cli/commands/bootstrap.d.ts.map +1 -0
- package/dist/cli/commands/bootstrap.js +109 -0
- package/dist/cli/commands/cost_report.d.ts +3 -0
- package/dist/cli/commands/cost_report.d.ts.map +1 -0
- package/dist/cli/commands/cost_report.js +115 -0
- package/dist/cli/commands/crew.d.ts.map +1 -1
- package/dist/cli/commands/crew.js +118 -1
- package/dist/cli/commands/gate.d.ts +3 -0
- package/dist/cli/commands/gate.d.ts.map +1 -0
- package/dist/cli/commands/gate.js +86 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -62
- package/dist/cli/commands/plan_crew.d.ts.map +1 -1
- package/dist/cli/commands/plan_crew.js +33 -21
- package/dist/cli/commands/train.d.ts.map +1 -1
- package/dist/cli/commands/train.js +16 -21
- package/dist/cli/defaults.d.ts +35 -0
- package/dist/cli/defaults.d.ts.map +1 -0
- package/dist/cli/defaults.js +125 -0
- package/dist/cli/errors.d.ts +27 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +57 -0
- package/dist/cli/parse_args.d.ts.map +1 -1
- package/dist/cli/parse_args.js +24 -2
- package/dist/cli/types.d.ts +7 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli.js +47 -2
- package/dist/crew/context.d.ts +15 -0
- package/dist/crew/context.d.ts.map +1 -1
- package/dist/crew/orchestrator.d.ts +14 -0
- package/dist/crew/orchestrator.d.ts.map +1 -1
- package/dist/crew/orchestrator.js +162 -4
- package/dist/crew/protocol.d.ts +13 -0
- package/dist/crew/protocol.d.ts.map +1 -1
- package/dist/crew/provider.d.ts +15 -1
- package/dist/crew/provider.d.ts.map +1 -1
- package/dist/crew/provider.js +24 -4
- package/dist/custom_provider.d.ts.map +1 -1
- package/dist/custom_provider.js +1 -0
- package/dist/engine/diff_loader.d.ts.map +1 -1
- package/dist/engine/diff_loader.js +3 -14
- package/dist/engine/impact_engine.d.ts.map +1 -1
- package/dist/engine/impact_engine.js +9 -23
- package/dist/esm/adapters/cypress.js +49 -0
- package/dist/esm/adapters/framework_adapter.js +114 -0
- package/dist/esm/adapters/playwright.js +49 -0
- package/dist/esm/adapters/pytest.js +59 -0
- package/dist/esm/adapters/supertest.js +48 -0
- package/dist/esm/agent/git.js +3 -1
- package/dist/esm/agentic/fix_loop.js +5 -4
- package/dist/esm/agentic/runner.js +15 -12
- package/dist/esm/agents/cross-impact.js +6 -1
- package/dist/esm/agents/executor.js +6 -1
- package/dist/esm/agents/strategist.js +6 -1
- package/dist/esm/agents/test-designer.js +6 -1
- package/dist/esm/anthropic_provider.js +1 -0
- package/dist/esm/base_provider.js +121 -0
- package/dist/esm/budget_ledger.js +58 -0
- package/dist/esm/cache/cached_provider.js +82 -0
- package/dist/esm/cache/response_cache.js +140 -0
- package/dist/esm/cli/commands/bootstrap.js +106 -0
- package/dist/esm/cli/commands/cost_report.js +112 -0
- package/dist/esm/cli/commands/crew.js +118 -1
- package/dist/esm/cli/commands/gate.js +83 -0
- package/dist/esm/cli/commands/init.js +3 -58
- package/dist/esm/cli/commands/plan_crew.js +33 -21
- package/dist/esm/cli/commands/train.js +16 -21
- package/dist/esm/cli/defaults.js +118 -0
- package/dist/esm/cli/errors.js +52 -0
- package/dist/esm/cli/parse_args.js +24 -2
- package/dist/esm/cli.js +47 -2
- package/dist/esm/crew/orchestrator.js +162 -4
- package/dist/esm/crew/provider.js +24 -4
- package/dist/esm/custom_provider.js +1 -0
- package/dist/esm/engine/diff_loader.js +1 -12
- package/dist/esm/engine/impact_engine.js +9 -23
- package/dist/esm/index.js +21 -0
- package/dist/esm/knowledge/cluster_utils.js +60 -0
- package/dist/esm/knowledge/kg_bridge.js +381 -0
- package/dist/esm/knowledge/kg_types.js +3 -0
- package/dist/esm/knowledge/route_families.js +89 -0
- package/dist/esm/mcp-server.js +2 -4
- package/dist/esm/metrics/prometheus.js +149 -0
- package/dist/esm/model_router.js +59 -0
- package/dist/esm/ollama_provider.js +1 -0
- package/dist/esm/openai_provider.js +1 -0
- package/dist/esm/pipeline/orchestrator.js +6 -12
- package/dist/esm/pipeline/stage0_preprocess.js +12 -19
- package/dist/esm/pipeline/stage2_coverage.js +1 -0
- package/dist/esm/pipeline/stage3_generation.js +1 -0
- package/dist/esm/progress.js +112 -0
- package/dist/esm/prompts/coverage.js +7 -24
- package/dist/esm/prompts/cross-impact.js +3 -21
- package/dist/esm/prompts/generation.js +158 -36
- package/dist/esm/prompts/generation_profile.js +147 -0
- package/dist/esm/prompts/heal.js +33 -15
- package/dist/esm/prompts/impact.js +3 -22
- package/dist/esm/prompts/json_extract.js +36 -0
- package/dist/esm/prompts/strategist.js +2 -20
- package/dist/esm/prompts/test-designer.js +6 -21
- package/dist/esm/provider_factory.js +6 -4
- package/dist/esm/reporters/junit.js +86 -0
- package/dist/esm/reporters/reporter.js +3 -0
- package/dist/esm/reporters/sarif.js +131 -0
- package/dist/esm/resilience/circuit_breaker.js +78 -0
- package/dist/esm/resilience/retry.js +56 -0
- package/dist/esm/sanitize.js +66 -0
- package/dist/esm/training/kg_scanner.js +115 -0
- package/dist/esm/training/scanner.js +27 -34
- package/dist/esm/version.js +33 -0
- package/dist/index.d.ts +21 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -1
- package/dist/knowledge/cluster_utils.d.ts +28 -0
- package/dist/knowledge/cluster_utils.d.ts.map +1 -0
- package/dist/knowledge/cluster_utils.js +67 -0
- package/dist/knowledge/kg_bridge.d.ts +31 -0
- package/dist/knowledge/kg_bridge.d.ts.map +1 -0
- package/dist/knowledge/kg_bridge.js +388 -0
- package/dist/knowledge/kg_types.d.ts +75 -0
- package/dist/knowledge/kg_types.d.ts.map +1 -0
- package/dist/knowledge/kg_types.js +4 -0
- package/dist/knowledge/route_families.d.ts +18 -0
- package/dist/knowledge/route_families.d.ts.map +1 -1
- package/dist/knowledge/route_families.js +91 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +2 -4
- package/dist/metrics/prometheus.d.ts +37 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/prometheus.js +153 -0
- package/dist/model_router.d.ts +28 -0
- package/dist/model_router.d.ts.map +1 -0
- package/dist/model_router.js +63 -0
- package/dist/ollama_provider.d.ts.map +1 -1
- package/dist/ollama_provider.js +1 -0
- package/dist/openai_provider.d.ts.map +1 -1
- package/dist/openai_provider.js +1 -0
- package/dist/pipeline/orchestrator.d.ts +2 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +6 -12
- package/dist/pipeline/stage0_preprocess.d.ts.map +1 -1
- package/dist/pipeline/stage0_preprocess.js +11 -18
- package/dist/pipeline/stage2_coverage.d.ts +2 -0
- package/dist/pipeline/stage2_coverage.d.ts.map +1 -1
- package/dist/pipeline/stage2_coverage.js +1 -0
- package/dist/pipeline/stage3_generation.d.ts +2 -0
- package/dist/pipeline/stage3_generation.d.ts.map +1 -1
- package/dist/pipeline/stage3_generation.js +1 -0
- package/dist/pipeline/stage4_heal.d.ts +2 -0
- package/dist/pipeline/stage4_heal.d.ts.map +1 -1
- package/dist/progress.d.ts +22 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +116 -0
- package/dist/prompts/coverage.d.ts +2 -0
- package/dist/prompts/coverage.d.ts.map +1 -1
- package/dist/prompts/coverage.js +7 -24
- package/dist/prompts/cross-impact.d.ts +1 -0
- package/dist/prompts/cross-impact.d.ts.map +1 -1
- package/dist/prompts/cross-impact.js +3 -21
- package/dist/prompts/generation.d.ts +3 -1
- package/dist/prompts/generation.d.ts.map +1 -1
- package/dist/prompts/generation.js +158 -36
- package/dist/prompts/generation_profile.d.ts +29 -0
- package/dist/prompts/generation_profile.d.ts.map +1 -0
- package/dist/prompts/generation_profile.js +151 -0
- package/dist/prompts/heal.d.ts +3 -1
- package/dist/prompts/heal.d.ts.map +1 -1
- package/dist/prompts/heal.js +33 -15
- package/dist/prompts/impact.d.ts +1 -0
- package/dist/prompts/impact.d.ts.map +1 -1
- package/dist/prompts/impact.js +3 -22
- package/dist/prompts/json_extract.d.ts +14 -0
- package/dist/prompts/json_extract.d.ts.map +1 -0
- package/dist/prompts/json_extract.js +39 -0
- package/dist/prompts/strategist.d.ts.map +1 -1
- package/dist/prompts/strategist.js +2 -20
- package/dist/prompts/test-designer.d.ts +2 -0
- package/dist/prompts/test-designer.d.ts.map +1 -1
- package/dist/prompts/test-designer.js +6 -21
- package/dist/provider_factory.d.ts.map +1 -1
- package/dist/provider_factory.js +6 -4
- package/dist/reporters/junit.d.ts +6 -0
- package/dist/reporters/junit.d.ts.map +1 -0
- package/dist/reporters/junit.js +89 -0
- package/dist/reporters/reporter.d.ts +42 -0
- package/dist/reporters/reporter.d.ts.map +1 -0
- package/dist/reporters/reporter.js +4 -0
- package/dist/reporters/sarif.d.ts +7 -0
- package/dist/reporters/sarif.d.ts.map +1 -0
- package/dist/reporters/sarif.js +134 -0
- package/dist/resilience/circuit_breaker.d.ts +36 -0
- package/dist/resilience/circuit_breaker.d.ts.map +1 -0
- package/dist/resilience/circuit_breaker.js +82 -0
- package/dist/resilience/retry.d.ts +11 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +59 -0
- package/dist/sanitize.d.ts +15 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +71 -0
- package/dist/training/kg_scanner.d.ts +13 -0
- package/dist/training/kg_scanner.d.ts.map +1 -0
- package/dist/training/kg_scanner.js +118 -0
- package/dist/training/scanner.d.ts +7 -2
- package/dist/training/scanner.d.ts.map +1 -1
- package/dist/training/scanner.js +27 -34
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +36 -0
- package/package.json +7 -2
- package/schemas/route-families.schema.json +31 -1
|
@@ -95,11 +95,11 @@ function buildCrewMarkdown(crew, plan) {
|
|
|
95
95
|
const totalCases = crew.testDesigns.reduce((n, td) => n + td.testCases.length, 0);
|
|
96
96
|
const gapFamilies = new Set((plan?.gapDetails ?? []).map((g) => g.id));
|
|
97
97
|
const lines = [
|
|
98
|
-
'### Crew
|
|
98
|
+
'### Crew Analysis — What to Test',
|
|
99
99
|
'',
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
`Strategy entries: **${crew.summary.strategyEntries}**`,
|
|
100
|
+
`Crew analyzed the diff and recommends what to verify before merging.`,
|
|
101
|
+
'',
|
|
102
|
+
`Impacted flows: **${crew.summary.impactedFlows}** | Strategy entries: **${crew.summary.strategyEntries}**`,
|
|
103
103
|
];
|
|
104
104
|
if (totalCases > 0) {
|
|
105
105
|
const gapDesigns = gapFamilies.size > 0
|
|
@@ -184,37 +184,48 @@ function buildCrewTestPlan(crew, plan) {
|
|
|
184
184
|
const gapCases = gapDesigns.reduce((n, td) => n + td.testCases.length, 0);
|
|
185
185
|
const coveredCases = coveredDesigns.reduce((n, td) => n + td.testCases.length, 0);
|
|
186
186
|
const lines = [
|
|
187
|
-
'# Crew Test Plan',
|
|
187
|
+
'# Crew Test Plan — What to Verify',
|
|
188
|
+
'',
|
|
189
|
+
'> **This is a test recommendation, not a test execution report.**',
|
|
190
|
+
'> Crew analyzed the code diff and identified what needs to be tested.',
|
|
191
|
+
'> Use this plan to guide manual QA or write automated E2E tests.',
|
|
188
192
|
'',
|
|
189
|
-
|
|
193
|
+
`_Auto-generated by e2e-agents crew (\`${crew.workflow}\` workflow)_`,
|
|
190
194
|
'',
|
|
191
195
|
'## Summary',
|
|
192
196
|
'',
|
|
193
197
|
`| Metric | Count |`,
|
|
194
198
|
`|--------|-------|`,
|
|
195
|
-
`| Gap flows
|
|
196
|
-
`| Covered flows
|
|
197
|
-
`| Total
|
|
199
|
+
`| Gap flows — **no existing tests, must verify** | ${gapStrategies.length} flows${hasTestDesigns ? `, **${gapCases} test cases**` : ''} |`,
|
|
200
|
+
`| Covered flows — **has tests, verify no regressions** | ${coveredStrategies.length} flows${hasTestDesigns ? `, ${coveredCases} test cases` : ''} |`,
|
|
201
|
+
`| Total | ${crew.strategyEntries.length} flows${hasTestDesigns ? `, ${totalCases} test cases` : ''} |`,
|
|
198
202
|
`| High-risk cross-impacts | ${crew.summary.highRiskCrossImpacts} |`,
|
|
199
203
|
`| AI cost | $${crew.summary.totalCostUSD.toFixed(4)} |`,
|
|
200
204
|
'',
|
|
201
205
|
];
|
|
202
206
|
// ── Gap flows ──
|
|
203
207
|
if (gapStrategies.length > 0) {
|
|
204
|
-
lines.push('##
|
|
208
|
+
lines.push('## Action Required: Gap Flows (No Existing Tests)');
|
|
205
209
|
lines.push('');
|
|
206
|
-
lines.push('These flows have **no
|
|
210
|
+
lines.push('These flows have **no automated E2E coverage**. Before merging, either:');
|
|
211
|
+
lines.push('1. **Write E2E tests** for the critical scenarios below, or');
|
|
212
|
+
lines.push('2. **Manually verify** each flow works as expected');
|
|
207
213
|
lines.push('');
|
|
208
214
|
for (const strategy of gapStrategies) {
|
|
209
215
|
const td = crew.testDesigns.find((d) => d.flowId === strategy.flowId);
|
|
210
216
|
lines.push(`### ${strategy.flowName}`);
|
|
211
217
|
lines.push('');
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
const actionVerb = strategy.approach === 'full-test' ? 'Write full E2E test or verify manually'
|
|
219
|
+
: strategy.approach === 'smoke-test' ? 'Smoke-test manually or add basic E2E coverage'
|
|
220
|
+
: strategy.approach === 'manual-review' ? 'Manual review required'
|
|
221
|
+
: 'Can skip — low risk';
|
|
222
|
+
lines.push(`**${strategy.priority}** | Recommended: **${strategy.approach}** | Cross-impact risk: **${strategy.crossImpactRisk}**`);
|
|
223
|
+
lines.push(`> ${actionVerb}`);
|
|
224
|
+
if (strategy.rationale && !strategy.rationale.includes('Default strategy')) {
|
|
225
|
+
lines.push(`> Rationale: ${strategy.rationale}`);
|
|
215
226
|
}
|
|
216
227
|
if (strategy.testCategories.length > 0) {
|
|
217
|
-
lines.push(
|
|
228
|
+
lines.push(`> Test types to cover: ${strategy.testCategories.join(', ')}`);
|
|
218
229
|
}
|
|
219
230
|
lines.push('');
|
|
220
231
|
// If test designs exist, show P0/P1 cases
|
|
@@ -249,9 +260,10 @@ function buildCrewTestPlan(crew, plan) {
|
|
|
249
260
|
}
|
|
250
261
|
// ── Covered flows ──
|
|
251
262
|
if (coveredStrategies.length > 0) {
|
|
252
|
-
lines.push('## Covered Flows (
|
|
263
|
+
lines.push('## Regression Check: Covered Flows (Already Have Tests)');
|
|
253
264
|
lines.push('');
|
|
254
|
-
lines.push('These flows
|
|
265
|
+
lines.push('These flows have existing E2E specs. The existing tests should catch regressions automatically.');
|
|
266
|
+
lines.push('**No manual action required** unless CI tests fail on these flows.');
|
|
255
267
|
lines.push('');
|
|
256
268
|
for (const strategy of coveredStrategies) {
|
|
257
269
|
const td = crew.testDesigns.find((d) => d.flowId === strategy.flowId);
|
|
@@ -259,8 +271,8 @@ function buildCrewTestPlan(crew, plan) {
|
|
|
259
271
|
const detail = caseCount > 0 ? ` | ${caseCount} cases` : '';
|
|
260
272
|
lines.push(`<details><summary><strong>${strategy.flowName}</strong> — ${strategy.approach}${detail} (${strategy.priority})</summary>`);
|
|
261
273
|
lines.push('');
|
|
262
|
-
lines.push(`Cross-impact risk: ${strategy.crossImpactRisk}`);
|
|
263
|
-
if (strategy.rationale) {
|
|
274
|
+
lines.push(`Existing tests should cover this. Cross-impact risk: ${strategy.crossImpactRisk}`);
|
|
275
|
+
if (strategy.rationale && !strategy.rationale.includes('Default strategy')) {
|
|
264
276
|
lines.push(`> ${strategy.rationale}`);
|
|
265
277
|
}
|
|
266
278
|
if (strategy.testCategories.length > 0) {
|
|
@@ -280,9 +292,9 @@ function buildCrewTestPlan(crew, plan) {
|
|
|
280
292
|
// ── Cross-impacts ──
|
|
281
293
|
const highRisk = crew.crossImpacts.filter((ci) => ci.riskLevel === 'high');
|
|
282
294
|
if (highRisk.length > 0) {
|
|
283
|
-
lines.push('## High-Risk Cross-Impacts');
|
|
295
|
+
lines.push('## High-Risk Cross-Impacts — Verify Before Release');
|
|
284
296
|
lines.push('');
|
|
285
|
-
lines.push('
|
|
297
|
+
lines.push('Changes in one area may break these related areas. Manually verify or ensure E2E tests cover both sides:');
|
|
286
298
|
lines.push('');
|
|
287
299
|
for (const ci of highRisk) {
|
|
288
300
|
lines.push(`- **${ci.sourceFamily}** → **${ci.affectedFamily}**: ${ci.sharedDependency}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/train.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/train.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAqI5C,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgQ1F"}
|
|
@@ -44,10 +44,13 @@ const config_js_1 = require("../../agent/config.js");
|
|
|
44
44
|
const route_families_js_1 = require("../../knowledge/route_families.js");
|
|
45
45
|
const provider_factory_js_1 = require("../../provider_factory.js");
|
|
46
46
|
const logger_js_1 = require("../../logger.js");
|
|
47
|
+
const version_js_1 = require("../../version.js");
|
|
47
48
|
const scanner_js_1 = require("../../training/scanner.js");
|
|
49
|
+
const kg_scanner_js_1 = require("../../training/kg_scanner.js");
|
|
48
50
|
const merger_js_1 = require("../../training/merger.js");
|
|
49
51
|
const enricher_js_1 = require("../../training/enricher.js");
|
|
50
52
|
const validator_js_1 = require("../../training/validator.js");
|
|
53
|
+
const kg_bridge_js_1 = require("../../knowledge/kg_bridge.js");
|
|
51
54
|
class TrainError extends Error {
|
|
52
55
|
constructor(message) {
|
|
53
56
|
super(message);
|
|
@@ -157,24 +160,6 @@ function ask(rl, question, defaultValue) {
|
|
|
157
160
|
});
|
|
158
161
|
});
|
|
159
162
|
}
|
|
160
|
-
function serializeManifest(manifest) {
|
|
161
|
-
const output = {
|
|
162
|
-
families: manifest.families.map((f) => {
|
|
163
|
-
// Remove undefined/empty optional fields for clean JSON
|
|
164
|
-
const cleaned = { ...f };
|
|
165
|
-
const optionalArrays = ['pageObjects', 'components', 'webappPaths', 'serverPaths', 'specDirs', 'cypressSpecDirs', 'tags', 'userFlows', 'features'];
|
|
166
|
-
for (const key of optionalArrays) {
|
|
167
|
-
if (!cleaned[key] || (Array.isArray(cleaned[key]) && cleaned[key].length === 0)) {
|
|
168
|
-
delete cleaned[key];
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (!cleaned.priority)
|
|
172
|
-
delete cleaned.priority;
|
|
173
|
-
return cleaned;
|
|
174
|
-
}),
|
|
175
|
-
};
|
|
176
|
-
return JSON.stringify(output, null, 2) + '\n';
|
|
177
|
-
}
|
|
178
163
|
async function runTrainCommand(args, autoConfig) {
|
|
179
164
|
const opts = resolveTrainOptions(args, autoConfig);
|
|
180
165
|
const totalTimer = logger_js_1.logger.timer('train-total');
|
|
@@ -187,12 +172,22 @@ async function runTrainCommand(args, autoConfig) {
|
|
|
187
172
|
logger_js_1.logger.info('e2e-ai-agents train');
|
|
188
173
|
logger_js_1.logger.info('===================');
|
|
189
174
|
// ---------- Phase 1: Deterministic scan ----------
|
|
175
|
+
// Prefer knowledge graph when available
|
|
176
|
+
const kg = (0, kg_bridge_js_1.loadKnowledgeGraph)(opts.appPath);
|
|
190
177
|
logger_js_1.logger.info('Scanning project structure...');
|
|
191
178
|
if (opts.serverRoot) {
|
|
192
179
|
logger_js_1.logger.info(`Server root: ${opts.serverRoot}`);
|
|
193
180
|
}
|
|
194
181
|
const scanTimer = logger_js_1.logger.timer('scan');
|
|
195
|
-
|
|
182
|
+
let scanResult;
|
|
183
|
+
if (kg) {
|
|
184
|
+
logger_js_1.logger.info('Using knowledge graph for scanning (found .understand-anything/knowledge-graph.json)');
|
|
185
|
+
scanResult = (0, kg_scanner_js_1.scanFromKnowledgeGraph)(kg);
|
|
186
|
+
logger_js_1.logger.info(`KG: ${kg.nodes.length} nodes, ${kg.edges.length} edges`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
scanResult = (0, scanner_js_1.scanProject)(opts.appPath, opts.testsRoot !== opts.appPath ? opts.testsRoot : undefined, opts.serverRoot, opts.gitRepoRoot);
|
|
190
|
+
}
|
|
196
191
|
timings.scan = scanTimer.end();
|
|
197
192
|
logger_js_1.logger.info(`Found ${scanResult.stats.totalSourceFiles} source files, ${scanResult.stats.totalTestFiles} test files`);
|
|
198
193
|
logger_js_1.logger.info(`Discovered ${scanResult.families.length} candidate families`);
|
|
@@ -269,7 +264,7 @@ async function runTrainCommand(args, autoConfig) {
|
|
|
269
264
|
timings.enrich = enrichTimer.end();
|
|
270
265
|
}
|
|
271
266
|
// ---------- Phase 5: Write manifest ----------
|
|
272
|
-
const json = serializeManifest(mergeResult.manifest);
|
|
267
|
+
const json = (0, route_families_js_1.serializeManifest)(mergeResult.manifest);
|
|
273
268
|
if (opts.dryRun) {
|
|
274
269
|
logger_js_1.logger.info('Dry run — proposed manifest:');
|
|
275
270
|
console.log(json);
|
|
@@ -368,7 +363,7 @@ async function runTrainCommand(args, autoConfig) {
|
|
|
368
363
|
const reportDir = (0, path_1.dirname)(opts.outputPath);
|
|
369
364
|
const trainReport = {
|
|
370
365
|
timestamp: new Date().toISOString(),
|
|
371
|
-
version:
|
|
366
|
+
version: (0, version_js_1.getVersion)(),
|
|
372
367
|
timings,
|
|
373
368
|
families: {
|
|
374
369
|
total: mergeResult.manifest.families.length,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { FrameworkType } from '../agent/config.js';
|
|
2
|
+
export interface ResolvedDefaults {
|
|
3
|
+
path: string;
|
|
4
|
+
testsRoot: string;
|
|
5
|
+
framework: FrameworkType;
|
|
6
|
+
since: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Detect the test framework from package.json dependencies.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectFramework(appPath: string): FrameworkType;
|
|
12
|
+
/**
|
|
13
|
+
* Detect the tests root directory by scanning common conventions.
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectTestsRoot(appPath: string): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Detect the git default branch for diffing.
|
|
18
|
+
* Returns origin/<branch> format.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectGitDefaultBranch(appPath: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Detect the project root by walking up to find package.json or .git.
|
|
23
|
+
*/
|
|
24
|
+
export declare function detectProjectRoot(startDir: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve defaults for CLI commands that need path/testsRoot/framework/since.
|
|
27
|
+
* Explicit values from CLI flags take precedence over detected values.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveDefaults(explicit: {
|
|
30
|
+
path?: string;
|
|
31
|
+
testsRoot?: string;
|
|
32
|
+
framework?: FrameworkType;
|
|
33
|
+
gitSince?: string;
|
|
34
|
+
}): ResolvedDefaults;
|
|
35
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/cli/defaults.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAsB9D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoBnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4B9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAa1D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,gBAAgB,CAOnB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
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.detectFramework = detectFramework;
|
|
6
|
+
exports.detectTestsRoot = detectTestsRoot;
|
|
7
|
+
exports.detectGitDefaultBranch = detectGitDefaultBranch;
|
|
8
|
+
exports.detectProjectRoot = detectProjectRoot;
|
|
9
|
+
exports.resolveDefaults = resolveDefaults;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
/**
|
|
14
|
+
* Detect the test framework from package.json dependencies.
|
|
15
|
+
*/
|
|
16
|
+
function detectFramework(appPath) {
|
|
17
|
+
const resolvedPath = (0, path_1.resolve)(appPath);
|
|
18
|
+
const pkgPath = (0, path_1.join)(resolvedPath, 'package.json');
|
|
19
|
+
if (!(0, fs_1.existsSync)(pkgPath)) {
|
|
20
|
+
return 'auto';
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
24
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
25
|
+
if (allDeps['@playwright/test'] || allDeps.playwright) {
|
|
26
|
+
return 'playwright';
|
|
27
|
+
}
|
|
28
|
+
if (allDeps.cypress) {
|
|
29
|
+
return 'cypress';
|
|
30
|
+
}
|
|
31
|
+
if (allDeps['selenium-webdriver'] || allDeps.webdriverio) {
|
|
32
|
+
return 'selenium';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore malformed package.json
|
|
37
|
+
}
|
|
38
|
+
return 'auto';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Detect the tests root directory by scanning common conventions.
|
|
42
|
+
*/
|
|
43
|
+
function detectTestsRoot(appPath) {
|
|
44
|
+
const resolvedPath = (0, path_1.resolve)(appPath);
|
|
45
|
+
const candidates = [
|
|
46
|
+
'e2e-tests/playwright',
|
|
47
|
+
'e2e-tests',
|
|
48
|
+
'e2e',
|
|
49
|
+
'tests/e2e',
|
|
50
|
+
'test/e2e',
|
|
51
|
+
'tests',
|
|
52
|
+
'test',
|
|
53
|
+
'specs',
|
|
54
|
+
'playwright',
|
|
55
|
+
'cypress',
|
|
56
|
+
];
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(resolvedPath, candidate))) {
|
|
59
|
+
return candidate;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Detect the git default branch for diffing.
|
|
66
|
+
* Returns origin/<branch> format.
|
|
67
|
+
*/
|
|
68
|
+
function detectGitDefaultBranch(appPath) {
|
|
69
|
+
try {
|
|
70
|
+
// Try to find the remote HEAD branch first
|
|
71
|
+
const remoteInfo = (0, child_process_1.execFileSync)('git', ['remote', 'show', 'origin'], {
|
|
72
|
+
cwd: (0, path_1.resolve)(appPath),
|
|
73
|
+
encoding: 'utf-8',
|
|
74
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
75
|
+
timeout: 5000,
|
|
76
|
+
});
|
|
77
|
+
const headMatch = remoteInfo.match(/HEAD branch:\s*(.+)/);
|
|
78
|
+
if (headMatch) {
|
|
79
|
+
return `origin/${headMatch[1].trim()}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// fallback to current branch
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const result = (0, child_process_1.execFileSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
87
|
+
cwd: (0, path_1.resolve)(appPath),
|
|
88
|
+
encoding: 'utf-8',
|
|
89
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
90
|
+
timeout: 5000,
|
|
91
|
+
}).trim();
|
|
92
|
+
return `origin/${result}`;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return 'origin/main';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Detect the project root by walking up to find package.json or .git.
|
|
100
|
+
*/
|
|
101
|
+
function detectProjectRoot(startDir) {
|
|
102
|
+
let current = (0, path_1.resolve)(startDir);
|
|
103
|
+
while (true) {
|
|
104
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(current, 'package.json')) || (0, fs_1.existsSync)((0, path_1.join)(current, '.git'))) {
|
|
105
|
+
return current;
|
|
106
|
+
}
|
|
107
|
+
const parent = (0, path_1.resolve)(current, '..');
|
|
108
|
+
if (parent === current) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
current = parent;
|
|
112
|
+
}
|
|
113
|
+
return startDir;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolve defaults for CLI commands that need path/testsRoot/framework/since.
|
|
117
|
+
* Explicit values from CLI flags take precedence over detected values.
|
|
118
|
+
*/
|
|
119
|
+
function resolveDefaults(explicit) {
|
|
120
|
+
const path = explicit.path || detectProjectRoot(process.cwd());
|
|
121
|
+
const testsRoot = explicit.testsRoot || detectTestsRoot(path) || '.';
|
|
122
|
+
const framework = explicit.framework || detectFramework(path);
|
|
123
|
+
const since = explicit.gitSince || detectGitDefaultBranch(path);
|
|
124
|
+
return { path, testsRoot, framework, since };
|
|
125
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Error types with structured exit codes.
|
|
3
|
+
*
|
|
4
|
+
* Exit codes:
|
|
5
|
+
* 0 = success
|
|
6
|
+
* 1 = general/user error (bad args, missing config, invalid input)
|
|
7
|
+
* 2 = budget exceeded
|
|
8
|
+
* 3 = LLM provider unavailable (API down, auth failure)
|
|
9
|
+
* 4 = invalid manifest or config file
|
|
10
|
+
*/
|
|
11
|
+
export declare const EXIT_CODES: {
|
|
12
|
+
readonly SUCCESS: 0;
|
|
13
|
+
readonly GENERAL_ERROR: 1;
|
|
14
|
+
readonly BUDGET_EXCEEDED: 2;
|
|
15
|
+
readonly PROVIDER_UNAVAILABLE: 3;
|
|
16
|
+
readonly INVALID_CONFIG: 4;
|
|
17
|
+
};
|
|
18
|
+
export type ExitCode = typeof EXIT_CODES[keyof typeof EXIT_CODES];
|
|
19
|
+
export declare class CliError extends Error {
|
|
20
|
+
readonly exitCode: ExitCode;
|
|
21
|
+
constructor(message: string, exitCode?: ExitCode);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Classify an unknown error into the appropriate exit code.
|
|
25
|
+
*/
|
|
26
|
+
export declare function classifyError(error: unknown): ExitCode;
|
|
27
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,eAAO,MAAM,UAAU;;;;;;CAMb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAElE,qBAAa,QAAS,SAAQ,KAAK;aAGX,QAAQ,EAAE,QAAQ;gBADlC,OAAO,EAAE,MAAM,EACC,QAAQ,GAAE,QAAmC;CAKpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CA0BtD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
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.CliError = exports.EXIT_CODES = void 0;
|
|
6
|
+
exports.classifyError = classifyError;
|
|
7
|
+
/**
|
|
8
|
+
* CLI Error types with structured exit codes.
|
|
9
|
+
*
|
|
10
|
+
* Exit codes:
|
|
11
|
+
* 0 = success
|
|
12
|
+
* 1 = general/user error (bad args, missing config, invalid input)
|
|
13
|
+
* 2 = budget exceeded
|
|
14
|
+
* 3 = LLM provider unavailable (API down, auth failure)
|
|
15
|
+
* 4 = invalid manifest or config file
|
|
16
|
+
*/
|
|
17
|
+
exports.EXIT_CODES = {
|
|
18
|
+
SUCCESS: 0,
|
|
19
|
+
GENERAL_ERROR: 1,
|
|
20
|
+
BUDGET_EXCEEDED: 2,
|
|
21
|
+
PROVIDER_UNAVAILABLE: 3,
|
|
22
|
+
INVALID_CONFIG: 4,
|
|
23
|
+
};
|
|
24
|
+
class CliError extends Error {
|
|
25
|
+
constructor(message, exitCode = exports.EXIT_CODES.GENERAL_ERROR) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.exitCode = exitCode;
|
|
28
|
+
this.name = 'CliError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.CliError = CliError;
|
|
32
|
+
/**
|
|
33
|
+
* Classify an unknown error into the appropriate exit code.
|
|
34
|
+
*/
|
|
35
|
+
function classifyError(error) {
|
|
36
|
+
if (error instanceof CliError)
|
|
37
|
+
return error.exitCode;
|
|
38
|
+
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
39
|
+
// Budget errors
|
|
40
|
+
if (msg.includes('budget exceeded') || msg.includes('budget limit')) {
|
|
41
|
+
return exports.EXIT_CODES.BUDGET_EXCEEDED;
|
|
42
|
+
}
|
|
43
|
+
// Provider/auth errors
|
|
44
|
+
if (msg.includes('api key') || msg.includes('authentication') ||
|
|
45
|
+
msg.includes('unauthorized') || msg.includes('403') ||
|
|
46
|
+
(msg.includes('provider') && msg.includes('unavailable')) ||
|
|
47
|
+
msg.includes('econnrefused') || msg.includes('econnreset')) {
|
|
48
|
+
return exports.EXIT_CODES.PROVIDER_UNAVAILABLE;
|
|
49
|
+
}
|
|
50
|
+
// Config/manifest errors
|
|
51
|
+
if ((msg.includes('manifest') && (msg.includes('invalid') || msg.includes('not found') || msg.includes('parse'))) ||
|
|
52
|
+
(msg.includes('config') && msg.includes('invalid')) ||
|
|
53
|
+
(msg.includes('route-families') && msg.includes('invalid'))) {
|
|
54
|
+
return exports.EXIT_CODES.INVALID_CONFIG;
|
|
55
|
+
}
|
|
56
|
+
return exports.EXIT_CODES.GENERAL_ERROR;
|
|
57
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse_args.d.ts","sourceRoot":"","sources":["../../src/cli/parse_args.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parse_args.d.ts","sourceRoot":"","sources":["../../src/cli/parse_args.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAU,UAAU,EAAC,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,iBAAiB,UAA8D,CAAC;AAE7F,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAmBlF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAmBtE;AA4JD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuFpD"}
|
package/dist/cli/parse_args.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.resolveAutoConfig = resolveAutoConfig;
|
|
|
8
8
|
exports.parseArgs = parseArgs;
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
10
|
const path_1 = require("path");
|
|
11
|
+
const logger_js_1 = require("../logger.js");
|
|
11
12
|
exports.CONFIG_CANDIDATES = ['e2e-ai-agents.config.json', '.e2e-ai-agents.config.json'];
|
|
12
13
|
function findConfigUpwards(startDir) {
|
|
13
14
|
if (!startDir) {
|
|
@@ -68,6 +69,7 @@ const FLAGS = {
|
|
|
68
69
|
'--generate': { key: 'analyzeGenerate', type: 'boolean' },
|
|
69
70
|
'--heal': { key: 'analyzeHeal', type: 'boolean' },
|
|
70
71
|
'--no-ai': { key: 'noAi', type: 'boolean' },
|
|
72
|
+
'--degraded-mode': { key: 'degradedMode', type: 'boolean' },
|
|
71
73
|
'--enrich': { key: 'trainEnrich', type: 'boolean' },
|
|
72
74
|
'--no-enrich': { key: 'trainEnrich', type: 'boolean-false' },
|
|
73
75
|
'--validate': { key: 'trainValidate', type: 'boolean' },
|
|
@@ -137,6 +139,13 @@ const FLAGS = {
|
|
|
137
139
|
type: 'csv',
|
|
138
140
|
transform: (v) => csvSplit(v).filter((s) => s === 'run-now' || s === 'must-add-tests' || s === 'safe-to-merge'),
|
|
139
141
|
},
|
|
142
|
+
// -- gate command --
|
|
143
|
+
'--threshold': { key: 'gateThreshold', type: 'number' },
|
|
144
|
+
// -- bootstrap command --
|
|
145
|
+
'--kg-path': { key: 'bootstrapKgPath', type: 'string' },
|
|
146
|
+
'--scaffold-framework': { key: 'bootstrapScaffoldFramework', type: 'boolean' },
|
|
147
|
+
'--test-mode': { key: 'bootstrapTestMode', type: 'enum', enumValues: ['ui', 'api', 'both'] },
|
|
148
|
+
'--max-families': { key: 'bootstrapMaxFamilies', type: 'number' },
|
|
140
149
|
};
|
|
141
150
|
// Build a lookup from alias -> canonical flag name
|
|
142
151
|
const ALIAS_MAP = {};
|
|
@@ -152,7 +161,8 @@ const COMMANDS = new Set([
|
|
|
152
161
|
'init', 'impact', 'plan', 'heal', 'suggest', 'generate',
|
|
153
162
|
'finalize-generated-tests', 'feedback',
|
|
154
163
|
'traceability-capture', 'traceability-ingest',
|
|
155
|
-
'analyze', 'llm-health', 'train', 'crew',
|
|
164
|
+
'analyze', 'llm-health', 'train', 'crew', 'cost-report', 'gate',
|
|
165
|
+
'bootstrap',
|
|
156
166
|
]);
|
|
157
167
|
// ---------------------------------------------------------------------------
|
|
158
168
|
// Parser
|
|
@@ -174,6 +184,9 @@ function parseArgs(argv) {
|
|
|
174
184
|
const arg = argv[i];
|
|
175
185
|
const canonical = ALIAS_MAP[arg];
|
|
176
186
|
if (!canonical) {
|
|
187
|
+
if (arg.startsWith('--')) {
|
|
188
|
+
logger_js_1.logger.warn(`Unknown flag "${arg}" (ignored)`);
|
|
189
|
+
}
|
|
177
190
|
continue;
|
|
178
191
|
}
|
|
179
192
|
const def = FLAGS[canonical];
|
|
@@ -202,7 +215,16 @@ function parseArgs(argv) {
|
|
|
202
215
|
break;
|
|
203
216
|
case 'number-raw':
|
|
204
217
|
if (next) {
|
|
205
|
-
|
|
218
|
+
const rawValue = def.transform ? def.transform(next) : Number(next);
|
|
219
|
+
// Allow non-number transforms through; reject NaN/Infinity for numbers
|
|
220
|
+
if (typeof rawValue === 'number') {
|
|
221
|
+
if (Number.isFinite(rawValue)) {
|
|
222
|
+
setField(parsed, def.key, rawValue);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
setField(parsed, def.key, rawValue);
|
|
227
|
+
}
|
|
206
228
|
i += 1;
|
|
207
229
|
}
|
|
208
230
|
break;
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AnalysisProfile, FrameworkType } from '../agent/config.js';
|
|
2
|
-
export type Command = 'init' | 'impact' | 'plan' | 'heal' | 'suggest' | 'generate' | 'finalize-generated-tests' | 'feedback' | 'traceability-capture' | 'traceability-ingest' | 'analyze' | 'llm-health' | 'train' | 'crew';
|
|
2
|
+
export type Command = 'init' | 'impact' | 'plan' | 'heal' | 'suggest' | 'generate' | 'finalize-generated-tests' | 'feedback' | 'traceability-capture' | 'traceability-ingest' | 'analyze' | 'llm-health' | 'train' | 'crew' | 'cost-report' | 'gate' | 'bootstrap';
|
|
3
3
|
export interface ParsedArgs {
|
|
4
4
|
command?: Command;
|
|
5
5
|
configPath?: string;
|
|
@@ -74,6 +74,12 @@ export interface ParsedArgs {
|
|
|
74
74
|
trainYes?: boolean;
|
|
75
75
|
serverPath?: string;
|
|
76
76
|
crewWorkflow?: string;
|
|
77
|
+
gateThreshold?: number;
|
|
78
|
+
bootstrapKgPath?: string;
|
|
79
|
+
bootstrapScaffoldFramework?: boolean;
|
|
80
|
+
bootstrapTestMode?: 'ui' | 'api' | 'both';
|
|
81
|
+
bootstrapMaxFamilies?: number;
|
|
82
|
+
degradedMode?: boolean;
|
|
77
83
|
verbose?: boolean;
|
|
78
84
|
jsonOutput?: boolean;
|
|
79
85
|
}
|
package/dist/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,eAAe,EAAE,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAEvE,MAAM,MAAM,OAAO,GACf,MAAM,GACJ,QAAQ,GACR,MAAM,GACN,MAAM,GACN,SAAS,GACT,UAAU,GACV,0BAA0B,GAC1B,UAAU,GACV,sBAAsB,GACtB,qBAAqB,GACrB,SAAS,GACT,YAAY,GACZ,OAAO,GACP,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const config_js_1 = require("./agent/config.js");
|
|
7
7
|
const parse_args_js_1 = require("./cli/parse_args.js");
|
|
8
|
+
const defaults_js_1 = require("./cli/defaults.js");
|
|
8
9
|
const usage_js_1 = require("./cli/usage.js");
|
|
9
10
|
const llm_health_js_1 = require("./cli/commands/llm_health.js");
|
|
10
11
|
const analyze_js_1 = require("./cli/commands/analyze.js");
|
|
@@ -18,14 +19,42 @@ const generate_js_1 = require("./cli/commands/generate.js");
|
|
|
18
19
|
const init_js_1 = require("./cli/commands/init.js");
|
|
19
20
|
const train_js_1 = require("./cli/commands/train.js");
|
|
20
21
|
const crew_js_1 = require("./cli/commands/crew.js");
|
|
22
|
+
const cost_report_js_1 = require("./cli/commands/cost_report.js");
|
|
23
|
+
const gate_js_1 = require("./cli/commands/gate.js");
|
|
24
|
+
const bootstrap_js_1 = require("./cli/commands/bootstrap.js");
|
|
25
|
+
const errors_js_1 = require("./cli/errors.js");
|
|
26
|
+
// Commands that skip default resolution (they handle their own setup)
|
|
27
|
+
const SKIP_DEFAULTS_COMMANDS = new Set(['init', 'llm-health', 'cost-report', 'bootstrap']);
|
|
28
|
+
// Commands that need path/testsRoot/framework/since
|
|
29
|
+
const NEEDS_DEFAULTS_COMMANDS = new Set([
|
|
30
|
+
'impact', 'plan', 'suggest', 'crew', 'generate', 'heal', 'analyze', 'train',
|
|
31
|
+
'feedback', 'traceability-capture', 'traceability-ingest', 'finalize-generated-tests',
|
|
32
|
+
]);
|
|
21
33
|
async function main() {
|
|
22
34
|
const args = (0, parse_args_js_1.parseArgs)(process.argv.slice(2));
|
|
23
35
|
const autoConfig = (0, parse_args_js_1.resolveAutoConfig)(args);
|
|
36
|
+
// Auto-detect defaults for commands that need them (when no config file found)
|
|
37
|
+
if (args.command && NEEDS_DEFAULTS_COMMANDS.has(args.command) && !SKIP_DEFAULTS_COMMANDS.has(args.command)) {
|
|
38
|
+
const defaults = (0, defaults_js_1.resolveDefaults)({
|
|
39
|
+
path: args.path,
|
|
40
|
+
testsRoot: args.testsRoot,
|
|
41
|
+
framework: args.framework,
|
|
42
|
+
gitSince: args.gitSince,
|
|
43
|
+
});
|
|
44
|
+
args.path = args.path || defaults.path;
|
|
45
|
+
args.testsRoot = args.testsRoot || defaults.testsRoot;
|
|
46
|
+
args.framework = args.framework || defaults.framework;
|
|
47
|
+
args.gitSince = args.gitSince || defaults.since;
|
|
48
|
+
}
|
|
24
49
|
if (args.command === 'init') {
|
|
25
50
|
const hasYes = process.argv.includes('--yes') || process.argv.includes('-y');
|
|
26
51
|
await (0, init_js_1.runInitCommand)(hasYes);
|
|
27
52
|
return;
|
|
28
53
|
}
|
|
54
|
+
if (args.command === 'bootstrap') {
|
|
55
|
+
await (0, bootstrap_js_1.runBootstrapCommand)(args);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
29
58
|
if (args.command === 'train') {
|
|
30
59
|
await (0, train_js_1.runTrainCommand)(args, autoConfig);
|
|
31
60
|
return;
|
|
@@ -66,6 +95,14 @@ async function main() {
|
|
|
66
95
|
await (0, crew_js_1.runCrewCommand)(args, autoConfig);
|
|
67
96
|
return;
|
|
68
97
|
}
|
|
98
|
+
if (args.command === 'cost-report') {
|
|
99
|
+
(0, cost_report_js_1.runCostReportCommand)(args);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (args.command === 'gate') {
|
|
103
|
+
await (0, gate_js_1.runGateCommand)(args, autoConfig);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
69
106
|
if (!args.path && !autoConfig) {
|
|
70
107
|
console.error('Error: --path is required (or provide a config file with path set)');
|
|
71
108
|
(0, usage_js_1.printUsage)();
|
|
@@ -140,6 +177,14 @@ async function main() {
|
|
|
140
177
|
process.exit(1);
|
|
141
178
|
}
|
|
142
179
|
main().catch((error) => {
|
|
143
|
-
|
|
144
|
-
|
|
180
|
+
const exitCode = (0, errors_js_1.classifyError)(error);
|
|
181
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
182
|
+
console.error(message);
|
|
183
|
+
if (exitCode === errors_js_1.EXIT_CODES.BUDGET_EXCEEDED) {
|
|
184
|
+
console.error('Hint: Increase --budget or use --degraded-mode to skip AI features.');
|
|
185
|
+
}
|
|
186
|
+
else if (exitCode === errors_js_1.EXIT_CODES.PROVIDER_UNAVAILABLE) {
|
|
187
|
+
console.error('Hint: Check API key or use --degraded-mode for deterministic analysis only.');
|
|
188
|
+
}
|
|
189
|
+
process.exit(exitCode);
|
|
145
190
|
});
|