@yasserkhanorg/e2e-agents 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +112 -584
  2. package/dist/agent/api_catalog.d.ts +11 -0
  3. package/dist/agent/api_catalog.d.ts.map +1 -0
  4. package/dist/agent/api_catalog.js +210 -0
  5. package/dist/agent/llm_agents_flow.d.ts +15 -0
  6. package/dist/agent/llm_agents_flow.d.ts.map +1 -0
  7. package/dist/agent/llm_agents_flow.js +434 -0
  8. package/dist/agent/native_flow.d.ts +6 -0
  9. package/dist/agent/native_flow.d.ts.map +1 -0
  10. package/dist/agent/native_flow.js +179 -0
  11. package/dist/agent/pipeline.d.ts +2 -25
  12. package/dist/agent/pipeline.d.ts.map +1 -1
  13. package/dist/agent/pipeline.js +30 -1329
  14. package/dist/agent/pipeline_types.d.ts +54 -0
  15. package/dist/agent/pipeline_types.d.ts.map +1 -0
  16. package/dist/agent/pipeline_types.js +4 -0
  17. package/dist/agent/pipeline_utils.d.ts +12 -0
  18. package/dist/agent/pipeline_utils.d.ts.map +1 -0
  19. package/dist/agent/pipeline_utils.js +156 -0
  20. package/dist/agent/process_runner.d.ts +10 -0
  21. package/dist/agent/process_runner.d.ts.map +1 -0
  22. package/dist/agent/process_runner.js +92 -0
  23. package/dist/agent/spec_generator.d.ts +5 -0
  24. package/dist/agent/spec_generator.d.ts.map +1 -0
  25. package/dist/agent/spec_generator.js +253 -0
  26. package/dist/agent/validation_runner.d.ts +5 -0
  27. package/dist/agent/validation_runner.d.ts.map +1 -0
  28. package/dist/agent/validation_runner.js +77 -0
  29. package/dist/agentic/playwright_runner.js +1 -1
  30. package/dist/cli/commands/analyze.d.ts +3 -0
  31. package/dist/cli/commands/analyze.d.ts.map +1 -0
  32. package/dist/cli/commands/analyze.js +77 -0
  33. package/dist/cli/commands/feedback.d.ts +3 -0
  34. package/dist/cli/commands/feedback.d.ts.map +1 -0
  35. package/dist/cli/commands/feedback.js +39 -0
  36. package/dist/cli/commands/finalize.d.ts +3 -0
  37. package/dist/cli/commands/finalize.d.ts.map +1 -0
  38. package/dist/cli/commands/finalize.js +41 -0
  39. package/dist/cli/commands/generate.d.ts +4 -0
  40. package/dist/cli/commands/generate.d.ts.map +1 -0
  41. package/dist/cli/commands/generate.js +108 -0
  42. package/dist/cli/commands/heal.d.ts +3 -0
  43. package/dist/cli/commands/heal.d.ts.map +1 -0
  44. package/dist/cli/commands/heal.js +60 -0
  45. package/dist/cli/commands/impact.d.ts +4 -0
  46. package/dist/cli/commands/impact.d.ts.map +1 -0
  47. package/dist/cli/commands/impact.js +26 -0
  48. package/dist/cli/commands/llm_health.d.ts +2 -0
  49. package/dist/cli/commands/llm_health.d.ts.map +1 -0
  50. package/dist/cli/commands/llm_health.js +38 -0
  51. package/dist/cli/commands/plan.d.ts +4 -0
  52. package/dist/cli/commands/plan.d.ts.map +1 -0
  53. package/dist/cli/commands/plan.js +83 -0
  54. package/dist/cli/commands/traceability.d.ts +4 -0
  55. package/dist/cli/commands/traceability.d.ts.map +1 -0
  56. package/dist/cli/commands/traceability.js +77 -0
  57. package/dist/cli/parse_args.d.ts +6 -0
  58. package/dist/cli/parse_args.d.ts.map +1 -0
  59. package/dist/cli/parse_args.js +216 -0
  60. package/dist/cli/types.d.ts +70 -0
  61. package/dist/cli/types.d.ts.map +1 -0
  62. package/dist/cli/types.js +4 -0
  63. package/dist/cli/usage.d.ts +2 -0
  64. package/dist/cli/usage.d.ts.map +1 -0
  65. package/dist/cli/usage.js +86 -0
  66. package/dist/cli.js +26 -1060
  67. package/dist/esm/agent/api_catalog.js +199 -0
  68. package/dist/esm/agent/llm_agents_flow.js +421 -0
  69. package/dist/esm/agent/native_flow.js +175 -0
  70. package/dist/esm/agent/pipeline.js +8 -1307
  71. package/dist/esm/agent/pipeline_types.js +3 -0
  72. package/dist/esm/agent/pipeline_utils.js +146 -0
  73. package/dist/esm/agent/process_runner.js +83 -0
  74. package/dist/esm/agent/spec_generator.js +249 -0
  75. package/dist/esm/agent/validation_runner.js +73 -0
  76. package/dist/esm/agentic/playwright_runner.js +1 -1
  77. package/dist/esm/cli/commands/analyze.js +74 -0
  78. package/dist/esm/cli/commands/feedback.js +36 -0
  79. package/dist/esm/cli/commands/finalize.js +38 -0
  80. package/dist/esm/cli/commands/generate.js +105 -0
  81. package/dist/esm/cli/commands/heal.js +57 -0
  82. package/dist/esm/cli/commands/impact.js +23 -0
  83. package/dist/esm/cli/commands/llm_health.js +35 -0
  84. package/dist/esm/cli/commands/plan.js +80 -0
  85. package/dist/esm/cli/commands/traceability.js +73 -0
  86. package/dist/esm/cli/parse_args.js +210 -0
  87. package/dist/esm/cli/types.js +3 -0
  88. package/dist/esm/cli/usage.js +83 -0
  89. package/dist/esm/cli.js +20 -1054
  90. package/dist/esm/mcp-server.js +18 -1
  91. package/dist/mcp-server.d.ts.map +1 -1
  92. package/dist/mcp-server.js +17 -0
  93. package/package.json +2 -4
@@ -0,0 +1,175 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs';
4
+ import { join, resolve } from 'path';
5
+ import { isPathWithinRoot, normalizePath } from './utils.js';
6
+ import { createMcpStatus, toSafeSlug, buildNativeStrategyOrder } from './pipeline_utils.js';
7
+ import { validateGeneratedSpecContent, createNativePlaywrightSpec } from './spec_generator.js';
8
+ import { resolvePlaywrightBinary } from './process_runner.js';
9
+ import { runPlaywrightListValidation } from './validation_runner.js';
10
+ import { buildApiSurfaceCatalog } from './api_catalog.js';
11
+ import { resolveAgentSeedSpec } from './llm_agents_flow.js';
12
+ export function runPackageNativeFlow(testsRoot, flow, pipeline, outputDir, testFile, playwrightBinary, apiSurface) {
13
+ const flowId = flow.id;
14
+ const flowName = flow.name;
15
+ const existingFile = existsSync(testFile);
16
+ const originalContent = existingFile ? readFileSync(testFile, 'utf-8') : null;
17
+ if (existingFile && !pipeline.heal) {
18
+ return {
19
+ flowId,
20
+ flowName,
21
+ generatedDir: outputDir,
22
+ generateStatus: 'skipped',
23
+ };
24
+ }
25
+ const slug = toSafeSlug(flow.id);
26
+ const strategies = buildNativeStrategyOrder(flow);
27
+ const attempts = [];
28
+ const candidates = [];
29
+ if (pipeline.heal && originalContent !== null) {
30
+ candidates.push({
31
+ label: 'existing',
32
+ content: originalContent,
33
+ write: false,
34
+ });
35
+ }
36
+ for (const strategy of strategies) {
37
+ candidates.push({
38
+ label: strategy,
39
+ strategy,
40
+ content: createNativePlaywrightSpec(flow, slug, strategy),
41
+ write: true,
42
+ });
43
+ }
44
+ mkdirSync(outputDir, { recursive: true });
45
+ let wroteNewFile = false;
46
+ for (let i = 0; i < candidates.length; i += 1) {
47
+ const candidate = candidates[i];
48
+ if (candidate.write) {
49
+ writeFileSync(testFile, candidate.content, 'utf-8');
50
+ wroteNewFile = true;
51
+ }
52
+ const currentContent = candidate.write ? candidate.content : (originalContent || '');
53
+ const qualityIssues = validateGeneratedSpecContent(currentContent, apiSurface);
54
+ if (qualityIssues.length > 0) {
55
+ attempts.push(`${candidate.label}: ${qualityIssues.map((issue) => issue.message).join(' ')}`);
56
+ if (pipeline.heal && i < candidates.length - 1) {
57
+ continue;
58
+ }
59
+ if (originalContent !== null) {
60
+ writeFileSync(testFile, originalContent, 'utf-8');
61
+ }
62
+ else if (wroteNewFile && existsSync(testFile)) {
63
+ rmSync(testFile, { force: true });
64
+ }
65
+ return {
66
+ flowId,
67
+ flowName,
68
+ generatedDir: outputDir,
69
+ generateStatus: 'failed',
70
+ healStatus: pipeline.heal ? 'failed' : undefined,
71
+ error: `Quality checks failed. Attempts: ${attempts.join(' | ')}`,
72
+ };
73
+ }
74
+ if (pipeline.heal) {
75
+ const validation = runPlaywrightListValidation(testsRoot, testFile, pipeline, playwrightBinary);
76
+ if (validation.status === 'failed') {
77
+ attempts.push(`${candidate.label}: ${validation.detail || 'playwright validation failed'}`);
78
+ if (i < candidates.length - 1) {
79
+ continue;
80
+ }
81
+ if (originalContent !== null) {
82
+ writeFileSync(testFile, originalContent, 'utf-8');
83
+ }
84
+ else if (wroteNewFile && existsSync(testFile)) {
85
+ rmSync(testFile, { force: true });
86
+ }
87
+ return {
88
+ flowId,
89
+ flowName,
90
+ generatedDir: outputDir,
91
+ generateStatus: 'failed',
92
+ healStatus: 'failed',
93
+ error: `Heal validation failed. Attempts: ${attempts.join(' | ')}`,
94
+ };
95
+ }
96
+ }
97
+ return {
98
+ flowId,
99
+ flowName,
100
+ generatedDir: outputDir,
101
+ generateStatus: candidate.write ? 'success' : 'skipped',
102
+ healStatus: pipeline.heal ? 'success' : undefined,
103
+ };
104
+ }
105
+ if (originalContent !== null) {
106
+ writeFileSync(testFile, originalContent, 'utf-8');
107
+ }
108
+ else if (wroteNewFile && existsSync(testFile)) {
109
+ rmSync(testFile, { force: true });
110
+ }
111
+ return {
112
+ flowId,
113
+ flowName,
114
+ generatedDir: outputDir,
115
+ generateStatus: 'failed',
116
+ healStatus: pipeline.heal ? 'failed' : undefined,
117
+ error: attempts.length > 0 ? attempts.join(' | ') : 'No generation candidates were available.',
118
+ };
119
+ }
120
+ export function runPackageNativePipeline(testsRoot, flows, pipeline, baseWarnings = []) {
121
+ const warningSet = new Set(baseWarnings);
122
+ const mcp = createMcpStatus('package-native', Boolean(pipeline.mcp));
123
+ const playwrightBinary = pipeline.heal ? resolvePlaywrightBinary(testsRoot) : null;
124
+ const seedFile = resolveAgentSeedSpec(testsRoot) || 'specs/seed.spec.ts';
125
+ const apiSurface = buildApiSurfaceCatalog(testsRoot, seedFile);
126
+ if (pipeline.heal && !playwrightBinary) {
127
+ warningSet.add('Playwright binary was not found. Heal uses static quality checks without runtime compile validation.');
128
+ }
129
+ const results = [];
130
+ const outputBase = resolve(testsRoot, pipeline.outputDir || 'specs/functional/ai-assisted');
131
+ if (!isPathWithinRoot(testsRoot, outputBase)) {
132
+ warningSet.add(`Pipeline outputDir resolves outside testsRoot and was blocked: ${pipeline.outputDir}`);
133
+ return { runner: 'unknown', results, warnings: Array.from(warningSet), mcp: createMcpStatus('unknown', Boolean(pipeline.mcp)) };
134
+ }
135
+ for (const flow of flows) {
136
+ if (flow.priority !== 'P0' && flow.priority !== 'P1') {
137
+ continue;
138
+ }
139
+ const slug = toSafeSlug(flow.id);
140
+ const outputDir = normalizePath(join(outputBase, slug));
141
+ if (!isPathWithinRoot(testsRoot, outputDir)) {
142
+ results.push({
143
+ flowId: flow.id,
144
+ flowName: flow.name,
145
+ generatedDir: outputDir,
146
+ generateStatus: 'failed',
147
+ error: 'output directory resolves outside testsRoot',
148
+ });
149
+ continue;
150
+ }
151
+ if (pipeline.dryRun) {
152
+ results.push({
153
+ flowId: flow.id,
154
+ flowName: flow.name,
155
+ generatedDir: outputDir,
156
+ generateStatus: 'skipped',
157
+ healStatus: pipeline.heal ? 'skipped' : undefined,
158
+ });
159
+ continue;
160
+ }
161
+ const testFile = normalizePath(join(outputDir, `${slug}.spec.ts`));
162
+ if (!isPathWithinRoot(testsRoot, testFile)) {
163
+ results.push({
164
+ flowId: flow.id,
165
+ flowName: flow.name,
166
+ generatedDir: outputDir,
167
+ generateStatus: 'failed',
168
+ error: 'generated test path resolves outside testsRoot',
169
+ });
170
+ continue;
171
+ }
172
+ results.push(runPackageNativeFlow(testsRoot, flow, pipeline, outputDir, testFile, playwrightBinary, apiSurface));
173
+ }
174
+ return { runner: 'package-native', results, warnings: Array.from(warningSet), mcp };
175
+ }