@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
|
@@ -0,0 +1,109 @@
|
|
|
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.runBootstrapCommand = runBootstrapCommand;
|
|
6
|
+
/**
|
|
7
|
+
* Bootstrap command — takes a project with an Understand-Anything knowledge graph
|
|
8
|
+
* and generates route-families.json + initial test stubs.
|
|
9
|
+
*/
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const logger_js_1 = require("../../logger.js");
|
|
13
|
+
const kg_bridge_js_1 = require("../../knowledge/kg_bridge.js");
|
|
14
|
+
const route_families_js_1 = require("../../knowledge/route_families.js");
|
|
15
|
+
const framework_adapter_js_1 = require("../../adapters/framework_adapter.js");
|
|
16
|
+
const generation_profile_js_1 = require("../../prompts/generation_profile.js");
|
|
17
|
+
class BootstrapError extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'BootstrapError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function runBootstrapCommand(args) {
|
|
24
|
+
const projectRoot = (0, path_1.resolve)(args.path || '.');
|
|
25
|
+
if (args.verbose)
|
|
26
|
+
logger_js_1.logger.setLevel(logger_js_1.LogLevel.DEBUG);
|
|
27
|
+
if (args.jsonOutput)
|
|
28
|
+
logger_js_1.logger.setJsonMode(true);
|
|
29
|
+
logger_js_1.logger.info('e2e-ai-agents bootstrap');
|
|
30
|
+
logger_js_1.logger.info('=======================');
|
|
31
|
+
// ---------- Step 1: Check for knowledge graph ----------
|
|
32
|
+
const kgPath = args.bootstrapKgPath
|
|
33
|
+
? (0, path_1.resolve)(args.bootstrapKgPath)
|
|
34
|
+
: (0, path_1.join)(projectRoot, '.understand-anything', 'knowledge-graph.json');
|
|
35
|
+
if (!(0, fs_1.existsSync)(kgPath)) {
|
|
36
|
+
throw new BootstrapError(`Knowledge graph not found at: ${kgPath}\n\n` +
|
|
37
|
+
'To bootstrap, first generate a knowledge graph for your project:\n' +
|
|
38
|
+
' 1. Install Understand-Anything: npm install -g understand-anything\n' +
|
|
39
|
+
' 2. Run: understand-anything analyze .\n' +
|
|
40
|
+
' 3. Then run: e2e-ai-agents bootstrap\n\n' +
|
|
41
|
+
'Or provide a path: e2e-ai-agents bootstrap --kg-path /path/to/knowledge-graph.json');
|
|
42
|
+
}
|
|
43
|
+
// ---------- Step 2: Load KG and classify ----------
|
|
44
|
+
logger_js_1.logger.info('Loading knowledge graph...');
|
|
45
|
+
const kg = (0, kg_bridge_js_1.loadKnowledgeGraph)(projectRoot, args.bootstrapKgPath ? kgPath : undefined);
|
|
46
|
+
if (!kg) {
|
|
47
|
+
throw new BootstrapError('Failed to load knowledge graph. Ensure it is valid JSON with nodes and edges arrays.');
|
|
48
|
+
}
|
|
49
|
+
const projectType = (0, kg_bridge_js_1.classifyProjectType)(kg);
|
|
50
|
+
logger_js_1.logger.info(`Project: ${kg.project.name || '(unnamed)'}`);
|
|
51
|
+
logger_js_1.logger.info(`Type: ${projectType}`);
|
|
52
|
+
logger_js_1.logger.info(`Frameworks: ${kg.project.frameworks.join(', ')}`);
|
|
53
|
+
logger_js_1.logger.info(`Languages: ${kg.project.languages.join(', ')}`);
|
|
54
|
+
logger_js_1.logger.info(`Nodes: ${kg.nodes.length}, Edges: ${kg.edges.length}`);
|
|
55
|
+
// ---------- Step 3: Transform KG to route families ----------
|
|
56
|
+
logger_js_1.logger.info('');
|
|
57
|
+
logger_js_1.logger.info('Generating route families from knowledge graph...');
|
|
58
|
+
const manifest = (0, kg_bridge_js_1.transformKGToFamilies)(kg);
|
|
59
|
+
const maxFamilies = args.bootstrapMaxFamilies || 50;
|
|
60
|
+
if (manifest.families.length > maxFamilies) {
|
|
61
|
+
logger_js_1.logger.info(`Limiting to top ${maxFamilies} families (of ${manifest.families.length} discovered). Use --max-families to adjust.`);
|
|
62
|
+
manifest.families = manifest.families.slice(0, maxFamilies);
|
|
63
|
+
}
|
|
64
|
+
const p0Count = manifest.families.filter((f) => f.priority === 'P0').length;
|
|
65
|
+
const p1Count = manifest.families.filter((f) => f.priority === 'P1').length;
|
|
66
|
+
const p2Count = manifest.families.filter((f) => f.priority === 'P2').length;
|
|
67
|
+
logger_js_1.logger.info(`Discovered ${manifest.families.length} families: ${p0Count} P0, ${p1Count} P1, ${p2Count} P2`);
|
|
68
|
+
// ---------- Step 4: Detect/scaffold test framework ----------
|
|
69
|
+
const framework = (0, framework_adapter_js_1.detectFramework)(projectRoot);
|
|
70
|
+
const testMode = args.bootstrapTestMode || (0, framework_adapter_js_1.detectTestMode)(projectRoot, kg);
|
|
71
|
+
const profile = (0, generation_profile_js_1.resolveGenerationProfile)({ profile: args.profile, testMode }, kg);
|
|
72
|
+
logger_js_1.logger.info(`Test framework: ${framework.name}`);
|
|
73
|
+
logger_js_1.logger.info(`Test mode: ${testMode}`);
|
|
74
|
+
logger_js_1.logger.info(`Generation profile: ${profile.projectName} (${profile.testFramework})`);
|
|
75
|
+
// ---------- Step 5: Write route-families.json ----------
|
|
76
|
+
const outputDir = (0, path_1.join)(projectRoot, '.e2e-ai-agents');
|
|
77
|
+
const outputPath = (0, path_1.join)(outputDir, 'route-families.json');
|
|
78
|
+
if (args.dryRun) {
|
|
79
|
+
logger_js_1.logger.info('');
|
|
80
|
+
logger_js_1.logger.info('Dry run — proposed manifest:');
|
|
81
|
+
console.log((0, route_families_js_1.serializeManifest)(manifest));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (!(0, fs_1.existsSync)(outputDir)) {
|
|
85
|
+
(0, fs_1.mkdirSync)(outputDir, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
(0, fs_1.writeFileSync)(outputPath, (0, route_families_js_1.serializeManifest)(manifest), 'utf-8');
|
|
88
|
+
logger_js_1.logger.info(`Wrote ${outputPath}`);
|
|
89
|
+
}
|
|
90
|
+
// ---------- Step 6: Summary and next steps ----------
|
|
91
|
+
logger_js_1.logger.info('');
|
|
92
|
+
logger_js_1.logger.info('Bootstrap complete!');
|
|
93
|
+
logger_js_1.logger.info('');
|
|
94
|
+
logger_js_1.logger.info('Route families summary:');
|
|
95
|
+
for (const family of manifest.families.slice(0, 15)) {
|
|
96
|
+
const endpoints = family.apiEndpoints?.length || 0;
|
|
97
|
+
const endpointSuffix = endpoints > 0 ? ` (${endpoints} API endpoints)` : '';
|
|
98
|
+
logger_js_1.logger.info(` ${family.priority || 'P2'} ${family.id}: ${family.routes.join(', ')}${endpointSuffix}`);
|
|
99
|
+
}
|
|
100
|
+
if (manifest.families.length > 15) {
|
|
101
|
+
logger_js_1.logger.info(` ... and ${manifest.families.length - 15} more`);
|
|
102
|
+
}
|
|
103
|
+
logger_js_1.logger.info('');
|
|
104
|
+
logger_js_1.logger.info('Next steps:');
|
|
105
|
+
logger_js_1.logger.info(' 1. Review and refine .e2e-ai-agents/route-families.json');
|
|
106
|
+
logger_js_1.logger.info(' 2. Run `e2e-ai-agents train --enrich` to add LLM-enriched metadata');
|
|
107
|
+
logger_js_1.logger.info(' 3. Run `e2e-ai-agents plan` to see what tests are needed');
|
|
108
|
+
logger_js_1.logger.info(' 4. Run `e2e-ai-agents generate` to create test stubs');
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost_report.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cost_report.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AA8C5C,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAgE3D"}
|
|
@@ -0,0 +1,115 @@
|
|
|
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.runCostReportCommand = runCostReportCommand;
|
|
6
|
+
/**
|
|
7
|
+
* CLI command: cost-report — displays LLM cost breakdown from metrics.
|
|
8
|
+
*/
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
function parseMetricsFile(filePath) {
|
|
12
|
+
if (!(0, fs_1.existsSync)(filePath)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const lines = (0, fs_1.readFileSync)(filePath, 'utf-8').split('\n');
|
|
16
|
+
const events = [];
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
continue;
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(trimmed);
|
|
23
|
+
if (parsed.type === 'crew-run') {
|
|
24
|
+
events.push(parsed);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return events;
|
|
32
|
+
}
|
|
33
|
+
function filterByDays(events, days) {
|
|
34
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
35
|
+
return events.filter((e) => new Date(e.timestamp).getTime() >= cutoff);
|
|
36
|
+
}
|
|
37
|
+
function runCostReportCommand(args) {
|
|
38
|
+
const reportRoot = args.path || args.testsRoot || process.cwd();
|
|
39
|
+
const metricsPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents', 'metrics.jsonl');
|
|
40
|
+
const days = 30; // Default; could be added as a CLI flag later
|
|
41
|
+
const allEvents = parseMetricsFile(metricsPath);
|
|
42
|
+
const events = filterByDays(allEvents, days);
|
|
43
|
+
if (events.length === 0) {
|
|
44
|
+
console.log('No crew metrics found.');
|
|
45
|
+
if (!(0, fs_1.existsSync)(metricsPath)) {
|
|
46
|
+
console.log(`Metrics file not found at: ${metricsPath}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log('Run `e2e-ai-agents crew` to generate cost data.');
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// JSON output
|
|
54
|
+
if (args.jsonOutput) {
|
|
55
|
+
const report = buildReport(events, days);
|
|
56
|
+
console.log(JSON.stringify(report, null, 2));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Human-readable output
|
|
60
|
+
const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0);
|
|
61
|
+
const totalRuns = events.length;
|
|
62
|
+
console.log(`E2E Agents Cost Report (last ${days} days)`);
|
|
63
|
+
console.log('='.repeat(45));
|
|
64
|
+
console.log(`\nTotal: $${totalCost.toFixed(2)} across ${totalRuns} runs\n`);
|
|
65
|
+
// By workflow
|
|
66
|
+
const byWorkflow = new Map();
|
|
67
|
+
for (const e of events) {
|
|
68
|
+
const entry = byWorkflow.get(e.workflow) || { runs: 0, cost: 0 };
|
|
69
|
+
entry.runs++;
|
|
70
|
+
entry.cost += e.totalCost;
|
|
71
|
+
byWorkflow.set(e.workflow, entry);
|
|
72
|
+
}
|
|
73
|
+
console.log('By workflow:');
|
|
74
|
+
for (const [workflow, data] of [...byWorkflow.entries()].sort((a, b) => b[1].cost - a[1].cost)) {
|
|
75
|
+
const avg = data.cost / data.runs;
|
|
76
|
+
console.log(` ${workflow.padEnd(14)} | ${String(data.runs).padStart(3)} runs | $${data.cost.toFixed(2).padStart(6)} | avg $${avg.toFixed(2)}/run`);
|
|
77
|
+
}
|
|
78
|
+
// By agent (top 5)
|
|
79
|
+
const byAgent = new Map();
|
|
80
|
+
for (const e of events) {
|
|
81
|
+
for (const au of e.agentUsage) {
|
|
82
|
+
byAgent.set(au.agent, (byAgent.get(au.agent) || 0) + au.cost);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const sortedAgents = [...byAgent.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
86
|
+
if (sortedAgents.length > 0) {
|
|
87
|
+
console.log('\nBy agent (top 5):');
|
|
88
|
+
for (const [agent, cost] of sortedAgents) {
|
|
89
|
+
const pct = totalCost > 0 ? ((cost / totalCost) * 100).toFixed(0) : '0';
|
|
90
|
+
console.log(` ${agent.padEnd(20)} | $${cost.toFixed(2).padStart(6)} | ${pct.padStart(3)}%`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function buildReport(events, days) {
|
|
95
|
+
const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0);
|
|
96
|
+
const byWorkflow = {};
|
|
97
|
+
const byAgent = {};
|
|
98
|
+
for (const e of events) {
|
|
99
|
+
if (!byWorkflow[e.workflow]) {
|
|
100
|
+
byWorkflow[e.workflow] = { runs: 0, cost: 0 };
|
|
101
|
+
}
|
|
102
|
+
byWorkflow[e.workflow].runs++;
|
|
103
|
+
byWorkflow[e.workflow].cost += e.totalCost;
|
|
104
|
+
for (const au of e.agentUsage) {
|
|
105
|
+
byAgent[au.agent] = (byAgent[au.agent] || 0) + au.cost;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
days,
|
|
110
|
+
totalRuns: events.length,
|
|
111
|
+
totalCost,
|
|
112
|
+
byWorkflow,
|
|
113
|
+
byAgent,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crew.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crew.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAI5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA8KpG"}
|
|
@@ -6,8 +6,12 @@ exports.runCrewCommand = runCrewCommand;
|
|
|
6
6
|
/**
|
|
7
7
|
* CLI command: crew — runs multi-agent QA analysis workflows.
|
|
8
8
|
*/
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = require("path");
|
|
9
11
|
const config_js_1 = require("../../agent/config.js");
|
|
10
12
|
const orchestrator_js_1 = require("../../crew/orchestrator.js");
|
|
13
|
+
const response_cache_js_1 = require("../../cache/response_cache.js");
|
|
14
|
+
const workflows_js_1 = require("../../crew/workflows.js");
|
|
11
15
|
const impact_analyst_js_1 = require("../../agents/impact-analyst.js");
|
|
12
16
|
const generator_js_1 = require("../../agents/generator.js");
|
|
13
17
|
const executor_js_1 = require("../../agents/executor.js");
|
|
@@ -37,6 +41,23 @@ async function runCrewCommand(args, autoConfig) {
|
|
|
37
41
|
process.exit(1);
|
|
38
42
|
}
|
|
39
43
|
const workflowName = rawWorkflow;
|
|
44
|
+
// Degraded mode: skip all AI features, deterministic analysis only
|
|
45
|
+
const degraded = args.degradedMode || process.env.E2E_AGENTS_DEGRADED === 'true';
|
|
46
|
+
if (degraded) {
|
|
47
|
+
console.log('Running in degraded mode — deterministic analysis only, no LLM calls.');
|
|
48
|
+
}
|
|
49
|
+
// Prune expired cache entries to prevent unbounded growth on CI
|
|
50
|
+
try {
|
|
51
|
+
const cache = new response_cache_js_1.ResponseCache(testsRoot);
|
|
52
|
+
const pruned = cache.prune();
|
|
53
|
+
if (pruned > 0) {
|
|
54
|
+
console.log(`Cache: pruned ${pruned} expired entries.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
+
console.error(`Cache prune warning: ${msg}`);
|
|
60
|
+
}
|
|
40
61
|
const crewConfig = {
|
|
41
62
|
appPath: config.path,
|
|
42
63
|
testsRoot,
|
|
@@ -46,7 +67,7 @@ async function runCrewCommand(args, autoConfig) {
|
|
|
46
67
|
workflow: workflowName,
|
|
47
68
|
providerOverride: args.llmProvider,
|
|
48
69
|
budgetUSD: args.budgetUSD,
|
|
49
|
-
dryRun: args.dryRun,
|
|
70
|
+
dryRun: degraded || args.dryRun,
|
|
50
71
|
};
|
|
51
72
|
// Create orchestrator and register all agents
|
|
52
73
|
const orchestrator = new orchestrator_js_1.CrewOrchestrator();
|
|
@@ -68,6 +89,33 @@ async function runCrewCommand(args, autoConfig) {
|
|
|
68
89
|
process.exit(1);
|
|
69
90
|
}
|
|
70
91
|
const ctx = result.context;
|
|
92
|
+
// Dry-run output
|
|
93
|
+
if (result.dryRun) {
|
|
94
|
+
printDryRunOutput(result, workflowName, args.jsonOutput);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Write crew metrics to metrics.jsonl for cost-report
|
|
98
|
+
if (ctx.usage.requestCount > 0) {
|
|
99
|
+
try {
|
|
100
|
+
const baseDir = (0, path_1.join)(testsRoot, '.e2e-ai-agents');
|
|
101
|
+
(0, fs_1.mkdirSync)(baseDir, { recursive: true });
|
|
102
|
+
const metricsPath = (0, path_1.join)(baseDir, 'metrics.jsonl');
|
|
103
|
+
const crewMetric = {
|
|
104
|
+
type: 'crew-run',
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
workflow: workflowName,
|
|
107
|
+
totalCost: ctx.usage.totalCost,
|
|
108
|
+
totalTokens: ctx.usage.totalTokens,
|
|
109
|
+
totalInputTokens: ctx.usage.totalInputTokens,
|
|
110
|
+
totalOutputTokens: ctx.usage.totalOutputTokens,
|
|
111
|
+
agentUsage: ctx.agentUsage,
|
|
112
|
+
};
|
|
113
|
+
(0, fs_1.appendFileSync)(metricsPath, `${JSON.stringify(crewMetric)}\n`, 'utf-8');
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Non-fatal: metrics writing should not break the workflow
|
|
117
|
+
}
|
|
118
|
+
}
|
|
71
119
|
// JSON output mode
|
|
72
120
|
if (args.jsonOutput) {
|
|
73
121
|
const jsonReport = {
|
|
@@ -135,3 +183,72 @@ async function runCrewCommand(args, autoConfig) {
|
|
|
135
183
|
}
|
|
136
184
|
}
|
|
137
185
|
}
|
|
186
|
+
function printDryRunOutput(result, workflowName, jsonOutput) {
|
|
187
|
+
const ctx = result.context;
|
|
188
|
+
const workflow = workflows_js_1.WORKFLOWS[workflowName];
|
|
189
|
+
if (jsonOutput) {
|
|
190
|
+
console.log(JSON.stringify({
|
|
191
|
+
dryRun: true,
|
|
192
|
+
workflow: workflowName,
|
|
193
|
+
changedFiles: ctx.changedFiles,
|
|
194
|
+
familyGroups: ctx.familyGroups.map((fg) => ({
|
|
195
|
+
familyId: fg.familyId,
|
|
196
|
+
featureId: fg.featureId,
|
|
197
|
+
files: fg.files,
|
|
198
|
+
})),
|
|
199
|
+
phases: workflow.phases.map((p) => ({
|
|
200
|
+
name: p.name,
|
|
201
|
+
agents: p.parallel || p.sequential || [],
|
|
202
|
+
})),
|
|
203
|
+
manifestSource: ctx.manifest?.source || 'none',
|
|
204
|
+
warnings: result.warnings,
|
|
205
|
+
}, null, 2));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
console.log('Dry run — no LLM calls will be made.\n');
|
|
209
|
+
console.log(`Changed files (${ctx.changedFiles.length}):`);
|
|
210
|
+
for (const f of ctx.changedFiles.slice(0, 20)) {
|
|
211
|
+
console.log(` ${f}`);
|
|
212
|
+
}
|
|
213
|
+
if (ctx.changedFiles.length > 20) {
|
|
214
|
+
console.log(` ... and ${ctx.changedFiles.length - 20} more`);
|
|
215
|
+
}
|
|
216
|
+
console.log(`\nAffected families (${ctx.familyGroups.length}):`);
|
|
217
|
+
for (const fg of ctx.familyGroups) {
|
|
218
|
+
const label = fg.featureId ? `${fg.familyId}/${fg.featureId}` : fg.familyId;
|
|
219
|
+
console.log(` ${label} (${fg.files.length} files)`);
|
|
220
|
+
}
|
|
221
|
+
if (ctx.manifest?.source === 'heuristic') {
|
|
222
|
+
console.log('\n Note: Using directory-based heuristics. Run `e2e-ai-agents train` for better accuracy.');
|
|
223
|
+
}
|
|
224
|
+
console.log(`\nWorkflow: ${workflowName}`);
|
|
225
|
+
const phaseNames = workflow.phases
|
|
226
|
+
.map((p) => {
|
|
227
|
+
const agents = p.parallel || p.sequential || [];
|
|
228
|
+
return agents.length > 0 ? `${p.name} (${agents.join(', ')})` : p.name;
|
|
229
|
+
})
|
|
230
|
+
.join(' → ');
|
|
231
|
+
console.log(`Phases: ${phaseNames}`);
|
|
232
|
+
// Cost estimation based on workflow and family count
|
|
233
|
+
const familyCount = Math.max(ctx.familyGroups.length, 1);
|
|
234
|
+
const agentCount = workflow.phases.reduce((sum, p) => sum + (p.parallel?.length || 0) + (p.sequential?.length || 0), 0);
|
|
235
|
+
const costEstimate = estimateCost(workflowName, familyCount, agentCount);
|
|
236
|
+
console.log(`\nEstimated cost: $${costEstimate.low.toFixed(2)}-$${costEstimate.high.toFixed(2)}`);
|
|
237
|
+
if (ctx.modelRoutingProviderType) {
|
|
238
|
+
console.log(` With model routing: $${(costEstimate.low * 0.5).toFixed(2)}-$${(costEstimate.high * 0.5).toFixed(2)} (Haiku for classification)`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Rough cost estimation based on observed averages per workflow type */
|
|
242
|
+
function estimateCost(workflow, families, _agents) {
|
|
243
|
+
// Per-family cost ranges by workflow (based on typical Sonnet pricing)
|
|
244
|
+
const ranges = {
|
|
245
|
+
'quick-check': { low: 0.03, high: 0.10 },
|
|
246
|
+
'design-only': { low: 0.10, high: 0.40 },
|
|
247
|
+
'full-qa': { low: 0.30, high: 1.00 },
|
|
248
|
+
};
|
|
249
|
+
const range = ranges[workflow] || ranges['full-qa'];
|
|
250
|
+
return {
|
|
251
|
+
low: range.low * families,
|
|
252
|
+
high: range.high * families,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/gate.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAE5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA6EpG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
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.runGateCommand = runGateCommand;
|
|
6
|
+
/**
|
|
7
|
+
* CLI command: gate — CI coverage gate that exits 1 if coverage is below threshold.
|
|
8
|
+
*
|
|
9
|
+
* Runs deterministic impact analysis (no LLM required) and checks what
|
|
10
|
+
* percentage of impacted features have test coverage.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* e2e-ai-agents gate --threshold 80 --path . --since origin/main
|
|
14
|
+
*/
|
|
15
|
+
const config_js_1 = require("../../agent/config.js");
|
|
16
|
+
const git_js_1 = require("../../agent/git.js");
|
|
17
|
+
const impact_engine_js_1 = require("../../engine/impact_engine.js");
|
|
18
|
+
async function runGateCommand(args, autoConfig) {
|
|
19
|
+
if (!args.path && !autoConfig) {
|
|
20
|
+
console.error('Error: --path is required for gate command');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const threshold = args.gateThreshold ?? 80;
|
|
24
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
25
|
+
path: args.path,
|
|
26
|
+
profile: args.profile,
|
|
27
|
+
testsRoot: args.testsRoot,
|
|
28
|
+
mode: 'impact',
|
|
29
|
+
gitSince: args.gitSince,
|
|
30
|
+
});
|
|
31
|
+
const testsRoot = config.testsRoot || config.path;
|
|
32
|
+
const gitSince = args.gitSince || config.git.since;
|
|
33
|
+
// Get changed files
|
|
34
|
+
const result = await (0, git_js_1.getChangedFiles)(config.path, gitSince);
|
|
35
|
+
const changedFiles = result.files;
|
|
36
|
+
if (changedFiles.length === 0) {
|
|
37
|
+
console.log('No changed files detected. Gate passes.');
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
// Run deterministic impact analysis
|
|
41
|
+
const impact = (0, impact_engine_js_1.analyzeImpact)(changedFiles, {
|
|
42
|
+
testsRoot,
|
|
43
|
+
routeFamilies: config.routeFamilies,
|
|
44
|
+
});
|
|
45
|
+
const totalFeatures = impact.impactedFeatures.length;
|
|
46
|
+
if (totalFeatures === 0) {
|
|
47
|
+
console.log('No impacted features detected. Gate passes.');
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
const coveredFeatures = impact.impactedFeatures.filter((f) => f.coverageStatus === 'covered' || f.coverageStatus === 'partial').length;
|
|
51
|
+
const coveragePercent = Math.round((coveredFeatures / totalFeatures) * 100);
|
|
52
|
+
// Output
|
|
53
|
+
if (args.jsonOutput) {
|
|
54
|
+
console.log(JSON.stringify({
|
|
55
|
+
threshold,
|
|
56
|
+
coveragePercent,
|
|
57
|
+
totalFeatures,
|
|
58
|
+
coveredFeatures,
|
|
59
|
+
passed: coveragePercent >= threshold,
|
|
60
|
+
uncoveredFeatures: impact.impactedFeatures
|
|
61
|
+
.filter((f) => f.coverageStatus === 'uncovered')
|
|
62
|
+
.map((f) => ({ id: f.featureId || f.familyId, priority: f.priority })),
|
|
63
|
+
}, null, 2));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(`Coverage gate: ${coveragePercent}% (${coveredFeatures}/${totalFeatures} features covered)`);
|
|
67
|
+
console.log(`Threshold: ${threshold}%`);
|
|
68
|
+
if (coveragePercent < threshold) {
|
|
69
|
+
console.log(`\nFAILED — coverage ${coveragePercent}% is below ${threshold}% threshold`);
|
|
70
|
+
const uncovered = impact.impactedFeatures.filter((f) => f.coverageStatus === 'uncovered');
|
|
71
|
+
if (uncovered.length > 0) {
|
|
72
|
+
console.log('\nUncovered features:');
|
|
73
|
+
for (const f of uncovered.slice(0, 10)) {
|
|
74
|
+
console.log(` ${f.priority || 'P2'} ${f.featureId || f.familyId}`);
|
|
75
|
+
}
|
|
76
|
+
if (uncovered.length > 10) {
|
|
77
|
+
console.log(` ... and ${uncovered.length - 10} more`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.log('\nPASSED');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
process.exit(coveragePercent >= threshold ? 0 : 1);
|
|
86
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAyEA,wBAAsB,cAAc,CAAC,GAAG,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F/D"}
|
|
@@ -37,9 +37,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
38
|
exports.runInitCommand = runInitCommand;
|
|
39
39
|
const fs_1 = require("fs");
|
|
40
|
-
const child_process_1 = require("child_process");
|
|
41
40
|
const path_1 = require("path");
|
|
42
41
|
const readline = __importStar(require("readline"));
|
|
42
|
+
const defaults_js_1 = require("../defaults.js");
|
|
43
43
|
const CONFIG_FILENAME = 'e2e-ai-agents.config.json';
|
|
44
44
|
function createInterface() {
|
|
45
45
|
return readline.createInterface({
|
|
@@ -55,61 +55,6 @@ function ask(rl, question, defaultValue) {
|
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
function detectFramework(appPath) {
|
|
59
|
-
const resolvedPath = (0, path_1.resolve)(appPath);
|
|
60
|
-
const pkgPath = (0, path_1.join)(resolvedPath, 'package.json');
|
|
61
|
-
if (!(0, fs_1.existsSync)(pkgPath)) {
|
|
62
|
-
return 'auto';
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
66
|
-
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
67
|
-
if (allDeps['@playwright/test'] || allDeps.playwright) {
|
|
68
|
-
return 'playwright';
|
|
69
|
-
}
|
|
70
|
-
if (allDeps.cypress) {
|
|
71
|
-
return 'cypress';
|
|
72
|
-
}
|
|
73
|
-
if (allDeps['selenium-webdriver'] || allDeps.webdriverio) {
|
|
74
|
-
return 'selenium';
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
// ignore
|
|
79
|
-
}
|
|
80
|
-
return 'auto';
|
|
81
|
-
}
|
|
82
|
-
function detectGitDefaultBranch(appPath) {
|
|
83
|
-
try {
|
|
84
|
-
const result = (0, child_process_1.execFileSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
85
|
-
cwd: (0, path_1.resolve)(appPath),
|
|
86
|
-
encoding: 'utf-8',
|
|
87
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
88
|
-
}).trim();
|
|
89
|
-
return `origin/${result}`;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return 'origin/main';
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function detectTestsRoot(appPath) {
|
|
96
|
-
const resolvedPath = (0, path_1.resolve)(appPath);
|
|
97
|
-
const candidates = [
|
|
98
|
-
'e2e-tests/playwright',
|
|
99
|
-
'e2e-tests',
|
|
100
|
-
'e2e',
|
|
101
|
-
'tests/e2e',
|
|
102
|
-
'test/e2e',
|
|
103
|
-
'tests',
|
|
104
|
-
'test',
|
|
105
|
-
];
|
|
106
|
-
for (const candidate of candidates) {
|
|
107
|
-
if ((0, fs_1.existsSync)((0, path_1.join)(resolvedPath, candidate))) {
|
|
108
|
-
return candidate;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
58
|
function buildConfig(answers) {
|
|
114
59
|
const config = {
|
|
115
60
|
path: answers.path,
|
|
@@ -155,9 +100,9 @@ async function runInitCommand(yes = false) {
|
|
|
155
100
|
const appPath = '.';
|
|
156
101
|
const answers = {
|
|
157
102
|
path: appPath,
|
|
158
|
-
testsRoot: detectTestsRoot(appPath) || '.',
|
|
159
|
-
framework: detectFramework(appPath),
|
|
160
|
-
gitSince: detectGitDefaultBranch(appPath),
|
|
103
|
+
testsRoot: (0, defaults_js_1.detectTestsRoot)(appPath) || '.',
|
|
104
|
+
framework: (0, defaults_js_1.detectFramework)(appPath),
|
|
105
|
+
gitSince: (0, defaults_js_1.detectGitDefaultBranch)(appPath),
|
|
161
106
|
provider: 'auto',
|
|
162
107
|
enableAi: true,
|
|
163
108
|
enforcementMode: 'advisory',
|
|
@@ -178,11 +123,11 @@ async function runInitCommand(yes = false) {
|
|
|
178
123
|
const rl = createInterface();
|
|
179
124
|
try {
|
|
180
125
|
const appPath = await ask(rl, ' Path to your web app root', '.');
|
|
181
|
-
const detectedFramework = detectFramework(appPath);
|
|
126
|
+
const detectedFramework = (0, defaults_js_1.detectFramework)(appPath);
|
|
182
127
|
const framework = await ask(rl, ' Test framework (auto | playwright | cypress | selenium)', detectedFramework);
|
|
183
|
-
const detectedTestsRoot = detectTestsRoot(appPath);
|
|
128
|
+
const detectedTestsRoot = (0, defaults_js_1.detectTestsRoot)(appPath);
|
|
184
129
|
const testsRoot = await ask(rl, ' Path to tests root (relative to app root, "." if same)', detectedTestsRoot || '.');
|
|
185
|
-
const detectedBranch = detectGitDefaultBranch(appPath);
|
|
130
|
+
const detectedBranch = (0, defaults_js_1.detectGitDefaultBranch)(appPath);
|
|
186
131
|
const gitSince = await ask(rl, ' Git ref to diff against', detectedBranch);
|
|
187
132
|
const providerAnswer = await ask(rl, ' LLM provider for AI features (anthropic | openai | ollama | auto)', 'auto');
|
|
188
133
|
const enableAi = providerAnswer !== 'none';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan_crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plan_crew.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAUtE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAgC5C,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkD5H;AAWD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAwEnF;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAE3G;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"plan_crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plan_crew.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAUtE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAgC5C,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkD5H;AAWD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAwEnF;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAE3G;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAsJnF;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAC,CAa/K"}
|