@yasserkhanorg/e2e-agents 1.10.1 → 1.10.2

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 (48) hide show
  1. package/README.md +116 -99
  2. package/dist/agent/config.d.ts +1 -1
  3. package/dist/agent/config.d.ts.map +1 -1
  4. package/dist/agent/config.js +6 -1
  5. package/dist/cache/cached_provider.d.ts +4 -0
  6. package/dist/cache/cached_provider.d.ts.map +1 -1
  7. package/dist/cache/cached_provider.js +3 -0
  8. package/dist/cli/commands/crew.d.ts.map +1 -1
  9. package/dist/cli/commands/crew.js +1 -0
  10. package/dist/cli/commands/init.js +5 -5
  11. package/dist/cli/commands/llm_health.d.ts.map +1 -1
  12. package/dist/cli/commands/llm_health.js +11 -67
  13. package/dist/cli/defaults.d.ts.map +1 -1
  14. package/dist/cli/defaults.js +47 -0
  15. package/dist/cli/parse_args.d.ts.map +1 -1
  16. package/dist/cli/parse_args.js +3 -1
  17. package/dist/cli/types.d.ts +1 -0
  18. package/dist/cli/types.d.ts.map +1 -1
  19. package/dist/cli/usage.d.ts.map +1 -1
  20. package/dist/cli/usage.js +28 -18
  21. package/dist/cli.js +5 -1
  22. package/dist/esm/agent/config.js +6 -1
  23. package/dist/esm/cache/cached_provider.js +3 -0
  24. package/dist/esm/cli/commands/crew.js +1 -0
  25. package/dist/esm/cli/commands/init.js +5 -5
  26. package/dist/esm/cli/commands/llm_health.js +11 -67
  27. package/dist/esm/cli/defaults.js +47 -0
  28. package/dist/esm/cli/parse_args.js +3 -1
  29. package/dist/esm/cli/usage.js +28 -18
  30. package/dist/esm/cli.js +5 -1
  31. package/dist/esm/prompts/coverage.js +2 -2
  32. package/dist/esm/prompts/cross-impact.js +1 -1
  33. package/dist/esm/prompts/generation.js +4 -4
  34. package/dist/esm/prompts/heal.js +4 -4
  35. package/dist/esm/prompts/impact.js +1 -1
  36. package/dist/esm/prompts/test-designer.js +1 -1
  37. package/dist/esm/provider_factory.js +17 -0
  38. package/dist/prompts/coverage.js +2 -2
  39. package/dist/prompts/cross-impact.js +1 -1
  40. package/dist/prompts/generation.js +4 -4
  41. package/dist/prompts/heal.js +4 -4
  42. package/dist/prompts/impact.js +1 -1
  43. package/dist/prompts/test-designer.js +1 -1
  44. package/dist/provider_factory.d.ts.map +1 -1
  45. package/dist/provider_factory.js +17 -0
  46. package/dist/provider_interface.d.ts +7 -0
  47. package/dist/provider_interface.d.ts.map +1 -1
  48. package/package.json +2 -2
@@ -10,6 +10,42 @@ exports.resolveDefaults = resolveDefaults;
10
10
  const fs_1 = require("fs");
11
11
  const child_process_1 = require("child_process");
12
12
  const path_1 = require("path");
13
+ function detectPytestFramework(appPath) {
14
+ const resolvedPath = (0, path_1.resolve)(appPath);
15
+ const pytestIni = (0, path_1.join)(resolvedPath, 'pytest.ini');
16
+ if ((0, fs_1.existsSync)(pytestIni)) {
17
+ return 'pytest';
18
+ }
19
+ const conftest = (0, path_1.join)(resolvedPath, 'conftest.py');
20
+ if ((0, fs_1.existsSync)(conftest)) {
21
+ return 'pytest';
22
+ }
23
+ const pyproject = (0, path_1.join)(resolvedPath, 'pyproject.toml');
24
+ if ((0, fs_1.existsSync)(pyproject)) {
25
+ try {
26
+ const content = (0, fs_1.readFileSync)(pyproject, 'utf-8');
27
+ if (content.includes('pytest')) {
28
+ return 'pytest';
29
+ }
30
+ }
31
+ catch {
32
+ // ignore malformed or unreadable file
33
+ }
34
+ }
35
+ const setupCfg = (0, path_1.join)(resolvedPath, 'setup.cfg');
36
+ if ((0, fs_1.existsSync)(setupCfg)) {
37
+ try {
38
+ const content = (0, fs_1.readFileSync)(setupCfg, 'utf-8');
39
+ if (content.includes('[tool:pytest]') || content.includes('[pytest]')) {
40
+ return 'pytest';
41
+ }
42
+ }
43
+ catch {
44
+ // ignore malformed or unreadable file
45
+ }
46
+ }
47
+ return undefined;
48
+ }
13
49
  /**
14
50
  * Detect the test framework from package.json dependencies.
15
51
  */
@@ -17,6 +53,10 @@ function detectFramework(appPath) {
17
53
  const resolvedPath = (0, path_1.resolve)(appPath);
18
54
  const pkgPath = (0, path_1.join)(resolvedPath, 'package.json');
19
55
  if (!(0, fs_1.existsSync)(pkgPath)) {
56
+ const pytestFramework = detectPytestFramework(resolvedPath);
57
+ if (pytestFramework) {
58
+ return pytestFramework;
59
+ }
20
60
  return 'auto';
21
61
  }
22
62
  try {
@@ -28,6 +68,9 @@ function detectFramework(appPath) {
28
68
  if (allDeps.cypress) {
29
69
  return 'cypress';
30
70
  }
71
+ if (allDeps.supertest) {
72
+ return 'supertest';
73
+ }
31
74
  if (allDeps['selenium-webdriver'] || allDeps.webdriverio) {
32
75
  return 'selenium';
33
76
  }
@@ -35,6 +78,10 @@ function detectFramework(appPath) {
35
78
  catch {
36
79
  // ignore malformed package.json
37
80
  }
81
+ const pytestFramework = detectPytestFramework(resolvedPath);
82
+ if (pytestFramework) {
83
+ return pytestFramework;
84
+ }
38
85
  return 'auto';
39
86
  }
40
87
  /**
@@ -1 +1 @@
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"}
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;AA6JD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAyFpD"}
@@ -133,6 +133,7 @@ const FLAGS = {
133
133
  '--patterns': { key: 'testPatterns', type: 'csv' },
134
134
  '--flow-patterns': { key: 'flowPatterns', type: 'csv' },
135
135
  '--flow-exclude': { key: 'flowExclude', type: 'csv' },
136
+ '--plugins': { key: 'plugins', type: 'csv' },
136
137
  '--policy-risky-patterns': { key: 'policyRiskyPatterns', type: 'csv' },
137
138
  '--policy-block-actions': {
138
139
  key: 'policyBlockActions',
@@ -180,7 +181,8 @@ function parseArgs(argv) {
180
181
  if (COMMANDS.has(command)) {
181
182
  parsed.command = command;
182
183
  }
183
- for (let i = 1; i < argv.length; i += 1) {
184
+ const startIndex = parsed.command ? 1 : 0;
185
+ for (let i = startIndex; i < argv.length; i += 1) {
184
186
  const arg = argv[i];
185
187
  const canonical = ALIAS_MAP[arg];
186
188
  if (!canonical) {
@@ -74,6 +74,7 @@ export interface ParsedArgs {
74
74
  trainYes?: boolean;
75
75
  serverPath?: string;
76
76
  crewWorkflow?: string;
77
+ plugins?: string[];
77
78
  gateThreshold?: number;
78
79
  bootstrapKgPath?: string;
79
80
  bootstrapScaffoldFramework?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,IAAI,IAAI,CA+FjC"}
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,IAAI,IAAI,CAyGjC"}
package/dist/cli/usage.js CHANGED
@@ -6,23 +6,32 @@ exports.printUsage = printUsage;
6
6
  function printUsage() {
7
7
  console.log([
8
8
  'Usage:',
9
- ' e2e-ai-agents init [--yes]',
10
- ' e2e-ai-agents impact --path <app-root> [options]',
11
- ' e2e-ai-agents plan --path <app-root> [options]',
12
- ' e2e-ai-agents suggest --path <app-root> [options]',
13
- ' e2e-ai-agents heal --path <app-root> --traceability-report <json> [options]',
14
- ' e2e-ai-agents finalize-generated-tests --path <app-root> [options]',
15
- ' e2e-ai-agents feedback --path <app-root> --feedback-input <json>',
16
- ' e2e-ai-agents traceability-capture --path <app-root> --traceability-report <json>',
17
- ' e2e-ai-agents traceability-ingest --path <app-root> --traceability-input <json>',
18
- ' e2e-ai-agents generate [--scenarios <path|json>] [--max-attempts <n>] [--dry-run]',
19
- ' e2e-ai-agents analyze --path <app-root> [--tests-root <path>] [--since <ref>] [--generate] [--generate-output <dir>] [--heal] [--heal-report <json>]',
20
- ' e2e-ai-agents train --path <project-root> [--no-enrich] [--validate] [--since <ref>] [--pr <num>]',
21
- ' e2e-ai-agents crew --path <app-root> [--crew-workflow <name>]',
22
- ' e2e-ai-agents gate --path <app-root> --threshold <n> [--since <ref>]',
23
- ' e2e-ai-agents cost-report [--path <app-root>]',
24
- ' e2e-ai-agents bootstrap --path <app-root> [options]',
25
- ' e2e-ai-agents llm-health',
9
+ ' e2e-ai-agents <command> [options]',
10
+ '',
11
+ 'Core CI workflow:',
12
+ ' impact --path <app-root> [options]',
13
+ ' plan --path <app-root> [options]',
14
+ ' suggest --path <app-root> [options]',
15
+ ' gate --path <app-root> --threshold <n> [--since <ref>]',
16
+ '',
17
+ 'Optional AI workflow:',
18
+ ' analyze --path <app-root> [--tests-root <path>] [--since <ref>] [--generate] [--generate-output <dir>] [--heal] [--heal-report <json>]',
19
+ ' generate [--scenarios <path|json>] [--max-attempts <n>] [--dry-run]',
20
+ ' heal --path <app-root> --traceability-report <json> [options]',
21
+ ' finalize-generated-tests --path <app-root> [options]',
22
+ '',
23
+ 'Setup and calibration:',
24
+ ' init [--yes]',
25
+ ' train --path <project-root> [--no-enrich] [--validate] [--since <ref>] [--pr <num>]',
26
+ ' bootstrap --path <app-root> [options]',
27
+ ' feedback --path <app-root> --feedback-input <json>',
28
+ ' traceability-capture --path <app-root> --traceability-report <json>',
29
+ ' traceability-ingest --path <app-root> --traceability-input <json>',
30
+ ' cost-report [--path <app-root>]',
31
+ ' llm-health',
32
+ '',
33
+ 'Advanced / experimental:',
34
+ ' crew --path <app-root> [--crew-workflow <name>] [--plugins <paths>]',
26
35
  '',
27
36
  'Options:',
28
37
  ' --config <path> Path to e2e-ai-agents.config.json (auto-discovered if present)',
@@ -30,10 +39,11 @@ function printUsage() {
30
39
  ' --profile <name> default | mattermost',
31
40
  ' --mattermost Shortcut for --profile mattermost',
32
41
  ' --tests-root <path> Path to tests root (optional)',
33
- ' --framework <name> auto | playwright | cypress | selenium',
42
+ ' --framework <name> auto | playwright | cypress | pytest | supertest | selenium',
34
43
  ' --patterns <globs> Comma-separated test patterns',
35
44
  ' --flow-patterns <g> Comma-separated flow discovery patterns',
36
45
  ' --flow-exclude <g> Comma-separated flow exclude patterns',
46
+ ' --plugins <paths> Comma-separated plugin module paths for crew workflows',
37
47
  ' --flow-catalog <path> Path to flow catalog JSON',
38
48
  ' --allow-fallback Allow impact analysis without diff',
39
49
  ' --pipeline Run Playwright AI pipeline for missing P0/P1 flows',
package/dist/cli.js CHANGED
@@ -59,10 +59,14 @@ async function main() {
59
59
  await (0, train_js_1.runTrainCommand)(args, autoConfig);
60
60
  return;
61
61
  }
62
- if (args.help || !args.command) {
62
+ if (args.help) {
63
63
  (0, usage_js_1.printUsage)();
64
64
  process.exit(0);
65
65
  }
66
+ if (!args.command) {
67
+ (0, usage_js_1.printUsage)();
68
+ process.exit(1);
69
+ }
66
70
  if (args.command === 'llm-health') {
67
71
  await (0, llm_health_js_1.runLlmHealth)();
68
72
  return;
@@ -335,7 +335,12 @@ function normalizeProfile(value) {
335
335
  return undefined;
336
336
  }
337
337
  function normalizeFramework(value) {
338
- if (value === 'auto' || value === 'playwright' || value === 'cypress' || value === 'selenium') {
338
+ if (value === 'auto' ||
339
+ value === 'playwright' ||
340
+ value === 'cypress' ||
341
+ value === 'pytest' ||
342
+ value === 'supertest' ||
343
+ value === 'selenium') {
339
344
  return value;
340
345
  }
341
346
  return undefined;
@@ -77,6 +77,9 @@ export class CachedProvider {
77
77
  resetUsageStats() {
78
78
  this.inner.resetUsageStats();
79
79
  }
80
+ async checkHealth() {
81
+ return this.inner.checkHealth();
82
+ }
80
83
  }
81
84
  // Re-export for convenience
82
85
  export { ResponseCache, TTL } from './response_cache.js';
@@ -65,6 +65,7 @@ export async function runCrewCommand(args, autoConfig) {
65
65
  providerOverride: args.llmProvider,
66
66
  budgetUSD: args.budgetUSD,
67
67
  dryRun: degraded || args.dryRun,
68
+ plugins: args.plugins,
68
69
  };
69
70
  // Create orchestrator and register all agents
70
71
  const orchestrator = new CrewOrchestrator();
@@ -45,10 +45,10 @@ function buildConfig(answers) {
45
45
  function printNextSteps() {
46
46
  console.log('');
47
47
  console.log(' Next steps:');
48
- console.log(' 1. Set your API key: export ANTHROPIC_API_KEY=sk-ant-...');
49
- console.log(' 2. Test connectivity: npx e2e-ai-agents llm-health');
50
- console.log(' 3. Run impact analysis: npx e2e-ai-agents impact');
51
- console.log(' 4. Add to CI: see examples/github-actions/pr-impact.yml');
48
+ console.log(' 1. Start with impact analysis: npx e2e-ai-agents impact --path .');
49
+ console.log(' 2. Build a coverage plan: npx e2e-ai-agents plan --path .');
50
+ console.log(' 3. Optional AI setup: export ANTHROPIC_API_KEY=sk-ant-...');
51
+ console.log(' 4. Verify provider health: npx e2e-ai-agents llm-health');
52
52
  console.log('');
53
53
  }
54
54
  export async function runInitCommand(yes = false) {
@@ -88,7 +88,7 @@ export async function runInitCommand(yes = false) {
88
88
  try {
89
89
  const appPath = await ask(rl, ' Path to your web app root', '.');
90
90
  const detectedFramework = detectFramework(appPath);
91
- const framework = await ask(rl, ' Test framework (auto | playwright | cypress | selenium)', detectedFramework);
91
+ const framework = await ask(rl, ' Test framework (auto | playwright | cypress | pytest | supertest | selenium)', detectedFramework);
92
92
  const detectedTestsRoot = detectTestsRoot(appPath);
93
93
  const testsRoot = await ask(rl, ' Path to tests root (relative to app root, "." if same)', detectedTestsRoot || '.');
94
94
  const detectedBranch = detectGitDefaultBranch(appPath);
@@ -1,75 +1,19 @@
1
1
  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
2
  // See LICENSE.txt for license information.
3
- import { AnthropicProvider } from '../../anthropic_provider.js';
4
- import { OpenAIProvider } from '../../openai_provider.js';
5
- import { OllamaProvider } from '../../ollama_provider.js';
6
- import { LLMProviderError } from '../../provider_interface.js';
7
- async function checkAnthropic() {
8
- if (!process.env.ANTHROPIC_API_KEY) {
9
- return null;
10
- }
11
- const model = process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-5-20250929';
12
- try {
13
- const provider = new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY, model });
14
- const response = await provider.generateText('Reply with OK.', { maxTokens: 8, timeout: 15000 });
15
- return { provider: 'Anthropic', model, ok: true, response: response.text.trim() };
16
- }
17
- catch (error) {
18
- const message = error instanceof LLMProviderError || error instanceof Error ? error.message : String(error);
19
- return { provider: 'Anthropic', model, ok: false, error: message };
20
- }
21
- }
22
- async function checkOpenAI() {
23
- if (!process.env.OPENAI_API_KEY) {
24
- return null;
25
- }
26
- const model = process.env.OPENAI_MODEL || 'gpt-4o';
27
- try {
28
- const provider = new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY, model });
29
- const response = await provider.generateText('Reply with OK.', { maxTokens: 8, timeout: 15000 });
30
- return { provider: 'OpenAI', model, ok: true, response: response.text.trim() };
31
- }
32
- catch (error) {
33
- const message = error instanceof LLMProviderError || error instanceof Error ? error.message : String(error);
34
- return { provider: 'OpenAI', model, ok: false, error: message };
35
- }
36
- }
37
- async function checkOllama() {
38
- const baseUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
39
- const model = process.env.OLLAMA_MODEL || 'llama3';
40
- try {
41
- const provider = new OllamaProvider({ baseUrl, model });
42
- const response = await provider.generateText('Reply with OK.', { maxTokens: 8, timeout: 15000 });
43
- return { provider: 'Ollama', model, ok: true, response: response.text.trim() };
44
- }
45
- catch (error) {
46
- const message = error instanceof LLMProviderError || error instanceof Error ? error.message : String(error);
47
- return { provider: 'Ollama', model, ok: false, error: message };
48
- }
49
- }
3
+ import { LLMProviderFactory } from '../../provider_factory.js';
50
4
  export async function runLlmHealth() {
51
- const checks = await Promise.allSettled([checkAnthropic(), checkOpenAI(), checkOllama()]);
52
- const results = [];
53
- for (const check of checks) {
54
- if (check.status === 'fulfilled' && check.value) {
55
- results.push(check.value);
56
- }
57
- }
58
- if (results.length === 0) {
59
- console.error('No LLM providers configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or OLLAMA_HOST.');
60
- process.exit(1);
61
- }
62
- let anyFailed = false;
63
- for (const r of results) {
64
- if (r.ok) {
65
- console.log(`${r.provider} OK (${r.model}) -> ${r.response}`);
66
- }
67
- else {
68
- console.error(`${r.provider} failed (${r.model}): ${r.error}`);
69
- anyFailed = true;
5
+ try {
6
+ const provider = await LLMProviderFactory.createFromEnv();
7
+ const health = await provider.checkHealth();
8
+ if (!health.healthy) {
9
+ console.error(`${provider.name} failed: ${health.message}`);
10
+ process.exit(1);
70
11
  }
12
+ console.log(`${provider.name} OK -> ${health.message}`);
71
13
  }
72
- if (anyFailed) {
14
+ catch (error) {
15
+ const message = error instanceof Error ? error.message : String(error);
16
+ console.error(`LLM health check failed: ${message}`);
73
17
  process.exit(1);
74
18
  }
75
19
  }
@@ -3,6 +3,42 @@
3
3
  import { existsSync, readFileSync } from 'fs';
4
4
  import { execFileSync } from 'child_process';
5
5
  import { join, resolve } from 'path';
6
+ function detectPytestFramework(appPath) {
7
+ const resolvedPath = resolve(appPath);
8
+ const pytestIni = join(resolvedPath, 'pytest.ini');
9
+ if (existsSync(pytestIni)) {
10
+ return 'pytest';
11
+ }
12
+ const conftest = join(resolvedPath, 'conftest.py');
13
+ if (existsSync(conftest)) {
14
+ return 'pytest';
15
+ }
16
+ const pyproject = join(resolvedPath, 'pyproject.toml');
17
+ if (existsSync(pyproject)) {
18
+ try {
19
+ const content = readFileSync(pyproject, 'utf-8');
20
+ if (content.includes('pytest')) {
21
+ return 'pytest';
22
+ }
23
+ }
24
+ catch {
25
+ // ignore malformed or unreadable file
26
+ }
27
+ }
28
+ const setupCfg = join(resolvedPath, 'setup.cfg');
29
+ if (existsSync(setupCfg)) {
30
+ try {
31
+ const content = readFileSync(setupCfg, 'utf-8');
32
+ if (content.includes('[tool:pytest]') || content.includes('[pytest]')) {
33
+ return 'pytest';
34
+ }
35
+ }
36
+ catch {
37
+ // ignore malformed or unreadable file
38
+ }
39
+ }
40
+ return undefined;
41
+ }
6
42
  /**
7
43
  * Detect the test framework from package.json dependencies.
8
44
  */
@@ -10,6 +46,10 @@ export function detectFramework(appPath) {
10
46
  const resolvedPath = resolve(appPath);
11
47
  const pkgPath = join(resolvedPath, 'package.json');
12
48
  if (!existsSync(pkgPath)) {
49
+ const pytestFramework = detectPytestFramework(resolvedPath);
50
+ if (pytestFramework) {
51
+ return pytestFramework;
52
+ }
13
53
  return 'auto';
14
54
  }
15
55
  try {
@@ -21,6 +61,9 @@ export function detectFramework(appPath) {
21
61
  if (allDeps.cypress) {
22
62
  return 'cypress';
23
63
  }
64
+ if (allDeps.supertest) {
65
+ return 'supertest';
66
+ }
24
67
  if (allDeps['selenium-webdriver'] || allDeps.webdriverio) {
25
68
  return 'selenium';
26
69
  }
@@ -28,6 +71,10 @@ export function detectFramework(appPath) {
28
71
  catch {
29
72
  // ignore malformed package.json
30
73
  }
74
+ const pytestFramework = detectPytestFramework(resolvedPath);
75
+ if (pytestFramework) {
76
+ return pytestFramework;
77
+ }
31
78
  return 'auto';
32
79
  }
33
80
  /**
@@ -127,6 +127,7 @@ const FLAGS = {
127
127
  '--patterns': { key: 'testPatterns', type: 'csv' },
128
128
  '--flow-patterns': { key: 'flowPatterns', type: 'csv' },
129
129
  '--flow-exclude': { key: 'flowExclude', type: 'csv' },
130
+ '--plugins': { key: 'plugins', type: 'csv' },
130
131
  '--policy-risky-patterns': { key: 'policyRiskyPatterns', type: 'csv' },
131
132
  '--policy-block-actions': {
132
133
  key: 'policyBlockActions',
@@ -174,7 +175,8 @@ export function parseArgs(argv) {
174
175
  if (COMMANDS.has(command)) {
175
176
  parsed.command = command;
176
177
  }
177
- for (let i = 1; i < argv.length; i += 1) {
178
+ const startIndex = parsed.command ? 1 : 0;
179
+ for (let i = startIndex; i < argv.length; i += 1) {
178
180
  const arg = argv[i];
179
181
  const canonical = ALIAS_MAP[arg];
180
182
  if (!canonical) {
@@ -3,23 +3,32 @@
3
3
  export function printUsage() {
4
4
  console.log([
5
5
  'Usage:',
6
- ' e2e-ai-agents init [--yes]',
7
- ' e2e-ai-agents impact --path <app-root> [options]',
8
- ' e2e-ai-agents plan --path <app-root> [options]',
9
- ' e2e-ai-agents suggest --path <app-root> [options]',
10
- ' e2e-ai-agents heal --path <app-root> --traceability-report <json> [options]',
11
- ' e2e-ai-agents finalize-generated-tests --path <app-root> [options]',
12
- ' e2e-ai-agents feedback --path <app-root> --feedback-input <json>',
13
- ' e2e-ai-agents traceability-capture --path <app-root> --traceability-report <json>',
14
- ' e2e-ai-agents traceability-ingest --path <app-root> --traceability-input <json>',
15
- ' e2e-ai-agents generate [--scenarios <path|json>] [--max-attempts <n>] [--dry-run]',
16
- ' e2e-ai-agents analyze --path <app-root> [--tests-root <path>] [--since <ref>] [--generate] [--generate-output <dir>] [--heal] [--heal-report <json>]',
17
- ' e2e-ai-agents train --path <project-root> [--no-enrich] [--validate] [--since <ref>] [--pr <num>]',
18
- ' e2e-ai-agents crew --path <app-root> [--crew-workflow <name>]',
19
- ' e2e-ai-agents gate --path <app-root> --threshold <n> [--since <ref>]',
20
- ' e2e-ai-agents cost-report [--path <app-root>]',
21
- ' e2e-ai-agents bootstrap --path <app-root> [options]',
22
- ' e2e-ai-agents llm-health',
6
+ ' e2e-ai-agents <command> [options]',
7
+ '',
8
+ 'Core CI workflow:',
9
+ ' impact --path <app-root> [options]',
10
+ ' plan --path <app-root> [options]',
11
+ ' suggest --path <app-root> [options]',
12
+ ' gate --path <app-root> --threshold <n> [--since <ref>]',
13
+ '',
14
+ 'Optional AI workflow:',
15
+ ' analyze --path <app-root> [--tests-root <path>] [--since <ref>] [--generate] [--generate-output <dir>] [--heal] [--heal-report <json>]',
16
+ ' generate [--scenarios <path|json>] [--max-attempts <n>] [--dry-run]',
17
+ ' heal --path <app-root> --traceability-report <json> [options]',
18
+ ' finalize-generated-tests --path <app-root> [options]',
19
+ '',
20
+ 'Setup and calibration:',
21
+ ' init [--yes]',
22
+ ' train --path <project-root> [--no-enrich] [--validate] [--since <ref>] [--pr <num>]',
23
+ ' bootstrap --path <app-root> [options]',
24
+ ' feedback --path <app-root> --feedback-input <json>',
25
+ ' traceability-capture --path <app-root> --traceability-report <json>',
26
+ ' traceability-ingest --path <app-root> --traceability-input <json>',
27
+ ' cost-report [--path <app-root>]',
28
+ ' llm-health',
29
+ '',
30
+ 'Advanced / experimental:',
31
+ ' crew --path <app-root> [--crew-workflow <name>] [--plugins <paths>]',
23
32
  '',
24
33
  'Options:',
25
34
  ' --config <path> Path to e2e-ai-agents.config.json (auto-discovered if present)',
@@ -27,10 +36,11 @@ export function printUsage() {
27
36
  ' --profile <name> default | mattermost',
28
37
  ' --mattermost Shortcut for --profile mattermost',
29
38
  ' --tests-root <path> Path to tests root (optional)',
30
- ' --framework <name> auto | playwright | cypress | selenium',
39
+ ' --framework <name> auto | playwright | cypress | pytest | supertest | selenium',
31
40
  ' --patterns <globs> Comma-separated test patterns',
32
41
  ' --flow-patterns <g> Comma-separated flow discovery patterns',
33
42
  ' --flow-exclude <g> Comma-separated flow exclude patterns',
43
+ ' --plugins <paths> Comma-separated plugin module paths for crew workflows',
34
44
  ' --flow-catalog <path> Path to flow catalog JSON',
35
45
  ' --allow-fallback Allow impact analysis without diff',
36
46
  ' --pipeline Run Playwright AI pipeline for missing P0/P1 flows',
package/dist/esm/cli.js CHANGED
@@ -57,10 +57,14 @@ async function main() {
57
57
  await runTrainCommand(args, autoConfig);
58
58
  return;
59
59
  }
60
- if (args.help || !args.command) {
60
+ if (args.help) {
61
61
  printUsage();
62
62
  process.exit(0);
63
63
  }
64
+ if (!args.command) {
65
+ printUsage();
66
+ process.exit(1);
67
+ }
64
68
  if (args.command === 'llm-health') {
65
69
  await runLlmHealth();
66
70
  return;
@@ -15,7 +15,7 @@ export function buildCoveragePrompt(ctx) {
15
15
  })
16
16
  .join('\n\n');
17
17
  return [
18
- `You are evaluating whether existing ${ctx.profile?.projectName || 'Mattermost'} ${ctx.profile?.testFramework || 'Playwright'} E2E tests cover the impacted flows.`,
18
+ `You are evaluating whether existing ${ctx.profile?.projectName || 'the project'} ${ctx.profile?.testFramework || 'Playwright'} E2E tests cover the impacted flows.`,
19
19
  '',
20
20
  `IMPACTED FLOWS (${ctx.flows.length}):`,
21
21
  flowsBlock,
@@ -38,7 +38,7 @@ export function buildCoveragePrompt(ctx) {
38
38
  ' Wrong: "test the new isEditing state"',
39
39
  ' Right: "test editing a scheduled message while it is in pending state"',
40
40
  '- For add_scenarios, specify which existing spec file to extend in targetSpec.',
41
- `- For create_spec, suggest a path following ${ctx.profile?.projectName || 'Mattermost'} conventions.`,
41
+ `- For create_spec, suggest a path following ${ctx.profile?.projectName || 'the project'} conventions.`,
42
42
  '- Prefer adding scenarios to existing specs over creating new spec files.',
43
43
  '',
44
44
  'SEMANTIC MATCHING RULES (critical for accuracy):',
@@ -15,7 +15,7 @@ export function buildCrossImpactPrompt(ctx) {
15
15
  .join('\n');
16
16
  const changedBlock = ctx.changedFiles.map((f) => sanitizeForPrompt(f)).join('\n');
17
17
  return [
18
- `You are analyzing code changes in ${ctx.projectName || 'Mattermost'} to identify cross-family ripple effects.`,
18
+ `You are analyzing code changes in ${ctx.projectName || 'the project'} to identify cross-family ripple effects.`,
19
19
  'When a change in one route family could affect another family through shared dependencies,',
20
20
  'that is a cross-impact.',
21
21
  '',
@@ -36,7 +36,7 @@ function buildAssertionPatternsBlock(patterns) {
36
36
  }
37
37
  export function buildGenerationPrompt(ctx) {
38
38
  const profile = ctx.profile;
39
- const isMM = profile ? isMattermostProfile(profile) : true;
39
+ const isMM = profile ? isMattermostProfile(profile) : false;
40
40
  const relevantClasses = resolveRelevantPageObjects(ctx.apiSurface, ctx.decision);
41
41
  const apiBlock = relevantClasses.length > 0
42
42
  ? formatApiSurfaceForPrompt(ctx.apiSurface, relevantClasses)
@@ -52,9 +52,9 @@ export function buildGenerationPrompt(ctx) {
52
52
  : `ADD scenarios to the EXISTING spec at: ${ctx.specPath}`;
53
53
  const routeFamilyTag = ctx.decision.routeFamily;
54
54
  // Build prompt based on profile
55
- const projectName = profile?.projectName || 'Mattermost';
55
+ const projectName = profile?.projectName || 'Project';
56
56
  const testFramework = profile?.testFramework || 'Playwright';
57
- const importStatement = profile?.importStatement || '@mattermost/playwright-lib';
57
+ const importStatement = profile?.importStatement || '@playwright/test';
58
58
  // API test mode prompt
59
59
  if (profile?.testMode === 'api') {
60
60
  return buildApiTestPrompt(ctx, profile, scenariosBlock, routeFamilyTag);
@@ -226,7 +226,7 @@ export function parseGenerationResponse(text, expectedPath, mode, flowId, profil
226
226
  if (!code.includes('test(') && !code.includes('it(') && !code.includes('describe(')) {
227
227
  return null;
228
228
  }
229
- const importStatement = profile?.importStatement || '@mattermost/playwright-lib';
229
+ const importStatement = profile?.importStatement || '@playwright/test';
230
230
  // Auto-add import if missing
231
231
  if (!code.includes(importStatement)) {
232
232
  if (profile?.testMode === 'api') {
@@ -28,9 +28,9 @@ export function buildHealPrompt(ctx) {
28
28
  const consoleBlock = ctx.consoleErrors && ctx.consoleErrors.length > 0
29
29
  ? `\nRecent console errors from test run:\n${ctx.consoleErrors.slice(-3).map((e) => ` - ${sanitizeForPrompt(e)}`).join('\n')}`
30
30
  : '';
31
- const importLib = ctx.profile?.importStatement || '@mattermost/playwright-lib';
32
- const isMM = ctx.profile ? isMattermostProfile(ctx.profile) : true;
33
- const projectLabel = ctx.profile?.projectName || 'Mattermost';
31
+ const importLib = ctx.profile?.importStatement || '@playwright/test';
32
+ const isMM = ctx.profile ? isMattermostProfile(ctx.profile) : false;
33
+ const projectLabel = ctx.profile?.projectName || 'Project';
34
34
  const frameworkLabel = ctx.profile?.testFramework || 'Playwright';
35
35
  const constraints = isMM
36
36
  ? [
@@ -71,7 +71,7 @@ export function buildHealPrompt(ctx) {
71
71
  * (e.g. contain test.describe, test.only, wrong imports).
72
72
  */
73
73
  export function buildQualityFixPrompt(specPath, qualityIssues, profile) {
74
- const importLib = profile?.importStatement || '@mattermost/playwright-lib';
74
+ const importLib = profile?.importStatement || '@playwright/test';
75
75
  const frameworkLabel = profile?.testFramework || 'Playwright';
76
76
  return [
77
77
  `Fix quality issues in this ${frameworkLabel} spec file. Make minimal edits only.`,
@@ -24,7 +24,7 @@ export function buildImpactPrompt(ctx) {
24
24
  })
25
25
  .join('\n\n');
26
26
  return [
27
- `You are analyzing code changes in ${ctx.projectName || 'Mattermost'} to identify impacted user-facing flows.`,
27
+ `You are analyzing code changes in ${ctx.projectName || 'the project'} to identify impacted user-facing flows.`,
28
28
  '',
29
29
  `ROUTE FAMILY: ${ctx.family.id}`,
30
30
  `ROUTES: ${familyRoutes}`,
@@ -25,7 +25,7 @@ export function buildTestDesignerPrompt(ctx) {
25
25
  : 'None detected.';
26
26
  const categories = ctx.strategy.testCategories.join(', ');
27
27
  return [
28
- `You are a senior QA engineer designing comprehensive test cases for a ${ctx.profile?.projectName || 'Mattermost'} user flow.`,
28
+ `You are a senior QA engineer designing comprehensive test cases for a ${ctx.profile?.projectName || 'project'} user flow.`,
29
29
  '',
30
30
  `FLOW: ${ctx.flow.flowName}`,
31
31
  `Flow ID: ${ctx.flow.flowId}`,