@yasserkhanorg/e2e-agents 1.7.7 → 1.8.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 (100) hide show
  1. package/dist/agent/git.d.ts +5 -0
  2. package/dist/agent/git.d.ts.map +1 -1
  3. package/dist/agent/git.js +13 -0
  4. package/dist/agents/coverage-evaluator.d.ts +8 -0
  5. package/dist/agents/coverage-evaluator.d.ts.map +1 -0
  6. package/dist/agents/coverage-evaluator.js +41 -0
  7. package/dist/agents/cross-impact.d.ts +13 -0
  8. package/dist/agents/cross-impact.d.ts.map +1 -0
  9. package/dist/agents/cross-impact.js +135 -0
  10. package/dist/agents/executor.d.ts +8 -0
  11. package/dist/agents/executor.d.ts.map +1 -0
  12. package/dist/agents/executor.js +70 -0
  13. package/dist/agents/explorer.d.ts +12 -0
  14. package/dist/agents/explorer.d.ts.map +1 -0
  15. package/dist/agents/explorer.js +43 -0
  16. package/dist/agents/generator.d.ts +8 -0
  17. package/dist/agents/generator.d.ts.map +1 -0
  18. package/dist/agents/generator.js +77 -0
  19. package/dist/agents/healer.d.ts +8 -0
  20. package/dist/agents/healer.d.ts.map +1 -0
  21. package/dist/agents/healer.js +31 -0
  22. package/dist/agents/impact-analyst.d.ts +8 -0
  23. package/dist/agents/impact-analyst.d.ts.map +1 -0
  24. package/dist/agents/impact-analyst.js +38 -0
  25. package/dist/agents/regression-advisor.d.ts +8 -0
  26. package/dist/agents/regression-advisor.d.ts.map +1 -0
  27. package/dist/agents/regression-advisor.js +116 -0
  28. package/dist/agents/strategist.d.ts +9 -0
  29. package/dist/agents/strategist.d.ts.map +1 -0
  30. package/dist/agents/strategist.js +87 -0
  31. package/dist/agents/test-designer.d.ts +8 -0
  32. package/dist/agents/test-designer.d.ts.map +1 -0
  33. package/dist/agents/test-designer.js +106 -0
  34. package/dist/cli/commands/crew.d.ts +3 -0
  35. package/dist/cli/commands/crew.d.ts.map +1 -0
  36. package/dist/cli/commands/crew.js +137 -0
  37. package/dist/cli/parse_args.d.ts.map +1 -1
  38. package/dist/cli/parse_args.js +2 -1
  39. package/dist/cli/types.d.ts +2 -1
  40. package/dist/cli/types.d.ts.map +1 -1
  41. package/dist/cli.js +5 -0
  42. package/dist/crew/context.d.ts +40 -0
  43. package/dist/crew/context.d.ts.map +1 -0
  44. package/dist/crew/context.js +36 -0
  45. package/dist/crew/orchestrator.d.ts +36 -0
  46. package/dist/crew/orchestrator.d.ts.map +1 -0
  47. package/dist/crew/orchestrator.js +171 -0
  48. package/dist/crew/protocol.d.ts +33 -0
  49. package/dist/crew/protocol.d.ts.map +1 -0
  50. package/dist/crew/protocol.js +4 -0
  51. package/dist/crew/provider.d.ts +3 -0
  52. package/dist/crew/provider.d.ts.map +1 -0
  53. package/dist/crew/provider.js +16 -0
  54. package/dist/crew/sanitize.d.ts +3 -0
  55. package/dist/crew/sanitize.d.ts.map +1 -0
  56. package/dist/crew/sanitize.js +31 -0
  57. package/dist/crew/types.d.ts +52 -0
  58. package/dist/crew/types.d.ts.map +1 -0
  59. package/dist/crew/types.js +4 -0
  60. package/dist/crew/workflows.d.ts +52 -0
  61. package/dist/crew/workflows.d.ts.map +1 -0
  62. package/dist/crew/workflows.js +36 -0
  63. package/dist/esm/agent/git.js +12 -0
  64. package/dist/esm/agents/coverage-evaluator.js +37 -0
  65. package/dist/esm/agents/cross-impact.js +131 -0
  66. package/dist/esm/agents/executor.js +66 -0
  67. package/dist/esm/agents/explorer.js +39 -0
  68. package/dist/esm/agents/generator.js +73 -0
  69. package/dist/esm/agents/healer.js +27 -0
  70. package/dist/esm/agents/impact-analyst.js +34 -0
  71. package/dist/esm/agents/regression-advisor.js +112 -0
  72. package/dist/esm/agents/strategist.js +83 -0
  73. package/dist/esm/agents/test-designer.js +102 -0
  74. package/dist/esm/cli/commands/crew.js +134 -0
  75. package/dist/esm/cli/parse_args.js +2 -1
  76. package/dist/esm/cli.js +5 -0
  77. package/dist/esm/crew/context.js +32 -0
  78. package/dist/esm/crew/orchestrator.js +167 -0
  79. package/dist/esm/crew/protocol.js +3 -0
  80. package/dist/esm/crew/provider.js +13 -0
  81. package/dist/esm/crew/sanitize.js +27 -0
  82. package/dist/esm/crew/types.js +3 -0
  83. package/dist/esm/crew/workflows.js +33 -0
  84. package/dist/esm/index.js +14 -0
  85. package/dist/esm/prompts/cross-impact.js +71 -0
  86. package/dist/esm/prompts/strategist.js +79 -0
  87. package/dist/esm/prompts/test-designer.js +107 -0
  88. package/dist/index.d.ts +17 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +27 -1
  91. package/dist/prompts/cross-impact.d.ts +22 -0
  92. package/dist/prompts/cross-impact.d.ts.map +1 -0
  93. package/dist/prompts/cross-impact.js +75 -0
  94. package/dist/prompts/strategist.d.ts +25 -0
  95. package/dist/prompts/strategist.d.ts.map +1 -0
  96. package/dist/prompts/strategist.js +83 -0
  97. package/dist/prompts/test-designer.d.ts +33 -0
  98. package/dist/prompts/test-designer.d.ts.map +1 -0
  99. package/dist/prompts/test-designer.js +111 -0
  100. package/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { formatApiSurfaceForPrompt } from '../knowledge/api_surface.js';
4
+ import { sanitizeForPrompt } from '../crew/sanitize.js';
5
+ export function buildTestDesignerPrompt(ctx) {
6
+ const relevantClasses = ctx.apiSurface.pageObjects
7
+ .map((po) => po.className)
8
+ .filter((name) => {
9
+ const lower = name.toLowerCase();
10
+ const hints = [ctx.flow.routeFamily, ctx.flow.featureId, ...ctx.flow.userActions.join(' ').split(/\s+/)]
11
+ .filter(Boolean)
12
+ .map((s) => s.toLowerCase().replace(/[^a-z]/g, ''));
13
+ return lower.includes('page') || hints.some((h) => h.length > 3 && lower.includes(h));
14
+ })
15
+ .slice(0, 10);
16
+ const apiBlock = relevantClasses.length > 0
17
+ ? formatApiSurfaceForPrompt(ctx.apiSurface, relevantClasses)
18
+ : 'No page objects available.';
19
+ const existingSpecsBlock = ctx.existingSpecs.length > 0
20
+ ? ctx.existingSpecs.map((s) => `- ${s.relativePath}: ${s.testTitles.join(', ')}`).join('\n')
21
+ : 'No existing specs.';
22
+ const crossImpactBlock = ctx.crossImpacts.length > 0
23
+ ? ctx.crossImpacts.map((ci) => `- ${ci.sourceFamily} → ${ci.affectedFamily}: ${ci.sharedDependency} (${ci.riskLevel})`).join('\n')
24
+ : 'None detected.';
25
+ const categories = ctx.strategy.testCategories.join(', ');
26
+ return [
27
+ 'You are a senior QA engineer designing comprehensive test cases for a Mattermost user flow.',
28
+ '',
29
+ `FLOW: ${ctx.flow.flowName}`,
30
+ `Flow ID: ${ctx.flow.flowId}`,
31
+ `Route Family: ${ctx.flow.routeFamily}${ctx.flow.featureId ? ` / ${ctx.flow.featureId}` : ''}`,
32
+ `Route: ${ctx.flow.specificRoute || '(not specified)'}`,
33
+ `Priority: ${ctx.strategy.priority}`,
34
+ `Approach: ${ctx.strategy.approach}`,
35
+ `User Actions: ${sanitizeForPrompt(ctx.flow.userActions.join('; ') || 'unknown')}`,
36
+ `Evidence: ${sanitizeForPrompt(ctx.flow.evidence)}`,
37
+ '',
38
+ `REQUIRED TEST CATEGORIES: ${categories}`,
39
+ '',
40
+ 'AVAILABLE PAGE OBJECTS:',
41
+ apiBlock,
42
+ '',
43
+ 'EXISTING SPECS (avoid duplicating these):',
44
+ existingSpecsBlock,
45
+ '',
46
+ 'CROSS-FAMILY IMPACTS:',
47
+ crossImpactBlock,
48
+ '',
49
+ 'TASK: Design structured test cases for this flow.',
50
+ '',
51
+ 'Return strict JSON only with this shape:',
52
+ '{"testDesign":{"flowId":"<id>","flowName":"<name>","testCases":[{"name":"<descriptive name>","type":"<category>","preconditions":["<state required>"],"steps":["<user action>"],"expectedOutcome":"<what should happen>","priority":"P0|P1|P2","rationale":"<why this test matters>"}]}}',
53
+ '',
54
+ 'TYPE VALUES: happy-path, edge-case, boundary, negative, state-transition, race-condition, permission, accessibility, performance',
55
+ '',
56
+ 'Rules:',
57
+ '- Every test must describe a specific USER ACTION, not an implementation detail.',
58
+ '- Steps must be concrete: "click Create Channel button" not "test channel creation".',
59
+ '- Include preconditions (logged-in role, existing data state, etc.).',
60
+ '- Reference only page objects and methods listed above.',
61
+ '- Include a mandatory rationale explaining why this specific test case matters.',
62
+ '- Do NOT duplicate tests already covered by existing specs.',
63
+ '- Maximum 15 test cases per flow.',
64
+ '- For accessibility: test keyboard navigation, screen reader support, ARIA labels.',
65
+ '- For performance: test with realistic data volumes, measure load times.',
66
+ '- For edge cases: test unicode input, max-length fields, empty states, concurrent edits.',
67
+ '',
68
+ 'FEW-SHOT EXAMPLES:',
69
+ '',
70
+ 'Edge case example:',
71
+ '```json',
72
+ '{"name":"channel creation with unicode characters and max-length name","type":"edge-case","preconditions":["logged in as team member","team has < 1000 channels"],"steps":["open create channel dialog","enter 64-character name with emoji and CJK characters","click Create"],"expectedOutcome":"channel created successfully, name renders correctly in sidebar and header","priority":"P1","rationale":"catches encoding issues in channel name storage and rendering"}',
73
+ '```',
74
+ '',
75
+ 'Permission example:',
76
+ '```json',
77
+ '{"name":"guest user cannot archive a public channel","type":"permission","preconditions":["logged in as guest user","guest has access to public channel"],"steps":["open channel header menu","look for Archive Channel option"],"expectedOutcome":"Archive Channel option is not visible in the menu","priority":"P0","rationale":"permission escalation bug — guests archiving channels could disrupt entire teams"}',
78
+ '```',
79
+ '',
80
+ 'Accessibility example:',
81
+ '```json',
82
+ '{"name":"keyboard navigation through channel switcher results","type":"accessibility","preconditions":["logged in","channel switcher open via Ctrl+K"],"steps":["type partial channel name","press ArrowDown to navigate results","press Enter to select"],"expectedOutcome":"focus moves visually and via aria-activedescendant, selected channel opens","priority":"P1","rationale":"screen reader users rely on keyboard navigation — broken focus management makes the app unusable"}',
83
+ '```',
84
+ ].join('\n');
85
+ }
86
+ export function parseTestDesignerResponse(text) {
87
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
88
+ const candidates = fenced ? [fenced[1], text] : [text];
89
+ for (const candidate of candidates) {
90
+ const start = candidate.indexOf('{');
91
+ const end = candidate.lastIndexOf('}');
92
+ if (start < 0 || end <= start) {
93
+ continue;
94
+ }
95
+ const raw = candidate.slice(start, end + 1);
96
+ try {
97
+ const parsed = JSON.parse(raw);
98
+ if (parsed?.testDesign?.testCases && Array.isArray(parsed.testDesign.testCases)) {
99
+ return parsed;
100
+ }
101
+ }
102
+ catch {
103
+ continue;
104
+ }
105
+ }
106
+ return null;
107
+ }
package/dist/index.d.ts CHANGED
@@ -54,6 +54,23 @@ export type { PlanReport } from './agent/plan.js';
54
54
  export { runAgenticGeneration } from './agentic/runner.js';
55
55
  export type { ScenarioInput, AgenticRunOptions } from './agentic/runner.js';
56
56
  export type { AgenticConfig, AgenticResult, AgenticSummary, PlaywrightRunResult, TestFailure } from './agentic/types.js';
57
+ export { CrewOrchestrator } from './crew/orchestrator.js';
58
+ export type { CrewConfig, CrewResult } from './crew/orchestrator.js';
59
+ export type { CrewContext } from './crew/context.js';
60
+ export type { Agent, AgentTask, AgentResult, AgentMessage } from './crew/protocol.js';
61
+ export type { AgentRole, TestCaseType, TestCase, TestDesign, CrossImpact, Finding, RegressionRisk, StrategyEntry, } from './crew/types.js';
62
+ export type { WorkflowDef, WorkflowName } from './crew/workflows.js';
63
+ export { WORKFLOWS } from './crew/workflows.js';
64
+ export { ImpactAnalystAgent } from './agents/impact-analyst.js';
65
+ export { CoverageEvaluatorAgent } from './agents/coverage-evaluator.js';
66
+ export { GeneratorAgent } from './agents/generator.js';
67
+ export { ExecutorAgent } from './agents/executor.js';
68
+ export { HealerAgent } from './agents/healer.js';
69
+ export { ExplorerAgent } from './agents/explorer.js';
70
+ export { StrategistAgent } from './agents/strategist.js';
71
+ export { TestDesignerAgent } from './agents/test-designer.js';
72
+ export { CrossImpactAgent } from './agents/cross-impact.js';
73
+ export { RegressionAdvisorAgent } from './agents/regression-advisor.js';
57
74
  export { scanProject } from './training/scanner.js';
58
75
  export { mergeFamilies, detectStaleFamilies } from './training/merger.js';
59
76
  export { enrichFamilies } from './training/enricher.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // See LICENSE.txt for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.runAgenticGeneration = exports.getSpecsForFamily = exports.buildSpecIndex = exports.loadOrBuildApiSurface = exports.buildApiSurface = exports.getUserFlowsForBinding = exports.getPriorityForBinding = exports.getCypressSpecDirsForBinding = exports.bindFilesToFamilies = exports.loadRouteFamilyManifest = exports.buildQualityFixPrompt = exports.buildHealPrompt = exports.renderHealMarkdown = exports.resolveHealTargets = exports.healFromReport = exports.runHealStage = exports.detectHallucinatedMethods = exports.parseGenerationResponse = exports.buildGenerationPrompt = exports.runGenerationStage = exports.runPipeline = exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.getAdaptiveThresholds = exports.readFlakyTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.buildPlanFromImpact = exports.extractScenarios = exports.getPartialGaps = exports.getGapsWithSuppressed = exports.getGaps = exports.analyzeImpactV2 = exports.captureTraceability = exports.ingestTraceability = exports.handoffGeneratedTests = exports.recommendTestsDeterministic = exports.analyzeImpactDeterministic = exports.validateProviderSetup = exports.LLMProviderFactory = exports.CustomProvider = exports.checkOpenAISetup = exports.OpenAIProvider = exports.checkOllamaSetup = exports.OllamaProvider = exports.checkAnthropicSetup = exports.AnthropicProvider = exports.UnsupportedCapabilityError = exports.LLMProviderError = void 0;
6
- exports.formatValidationReport = exports.buildValidationReport = exports.validateCommit = exports.getCommitFiles = exports.enrichFamilies = exports.detectStaleFamilies = exports.mergeFamilies = exports.scanProject = void 0;
6
+ exports.formatValidationReport = exports.buildValidationReport = exports.validateCommit = exports.getCommitFiles = exports.enrichFamilies = exports.detectStaleFamilies = exports.mergeFamilies = exports.scanProject = exports.RegressionAdvisorAgent = exports.CrossImpactAgent = exports.TestDesignerAgent = exports.StrategistAgent = exports.ExplorerAgent = exports.HealerAgent = exports.ExecutorAgent = exports.GeneratorAgent = exports.CoverageEvaluatorAgent = exports.ImpactAnalystAgent = exports.WORKFLOWS = exports.CrewOrchestrator = void 0;
7
7
  var provider_interface_js_1 = require("./provider_interface.js");
8
8
  Object.defineProperty(exports, "LLMProviderError", { enumerable: true, get: function () { return provider_interface_js_1.LLMProviderError; } });
9
9
  Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return provider_interface_js_1.UnsupportedCapabilityError; } });
@@ -84,6 +84,32 @@ Object.defineProperty(exports, "getSpecsForFamily", { enumerable: true, get: fun
84
84
  // Agentic generation
85
85
  var runner_js_1 = require("./agentic/runner.js");
86
86
  Object.defineProperty(exports, "runAgenticGeneration", { enumerable: true, get: function () { return runner_js_1.runAgenticGeneration; } });
87
+ // Crew (multi-agent QA workflows)
88
+ var orchestrator_js_2 = require("./crew/orchestrator.js");
89
+ Object.defineProperty(exports, "CrewOrchestrator", { enumerable: true, get: function () { return orchestrator_js_2.CrewOrchestrator; } });
90
+ var workflows_js_1 = require("./crew/workflows.js");
91
+ Object.defineProperty(exports, "WORKFLOWS", { enumerable: true, get: function () { return workflows_js_1.WORKFLOWS; } });
92
+ // Crew agents
93
+ var impact_analyst_js_1 = require("./agents/impact-analyst.js");
94
+ Object.defineProperty(exports, "ImpactAnalystAgent", { enumerable: true, get: function () { return impact_analyst_js_1.ImpactAnalystAgent; } });
95
+ var coverage_evaluator_js_1 = require("./agents/coverage-evaluator.js");
96
+ Object.defineProperty(exports, "CoverageEvaluatorAgent", { enumerable: true, get: function () { return coverage_evaluator_js_1.CoverageEvaluatorAgent; } });
97
+ var generator_js_1 = require("./agents/generator.js");
98
+ Object.defineProperty(exports, "GeneratorAgent", { enumerable: true, get: function () { return generator_js_1.GeneratorAgent; } });
99
+ var executor_js_1 = require("./agents/executor.js");
100
+ Object.defineProperty(exports, "ExecutorAgent", { enumerable: true, get: function () { return executor_js_1.ExecutorAgent; } });
101
+ var healer_js_1 = require("./agents/healer.js");
102
+ Object.defineProperty(exports, "HealerAgent", { enumerable: true, get: function () { return healer_js_1.HealerAgent; } });
103
+ var explorer_js_1 = require("./agents/explorer.js");
104
+ Object.defineProperty(exports, "ExplorerAgent", { enumerable: true, get: function () { return explorer_js_1.ExplorerAgent; } });
105
+ var strategist_js_1 = require("./agents/strategist.js");
106
+ Object.defineProperty(exports, "StrategistAgent", { enumerable: true, get: function () { return strategist_js_1.StrategistAgent; } });
107
+ var test_designer_js_1 = require("./agents/test-designer.js");
108
+ Object.defineProperty(exports, "TestDesignerAgent", { enumerable: true, get: function () { return test_designer_js_1.TestDesignerAgent; } });
109
+ var cross_impact_js_1 = require("./agents/cross-impact.js");
110
+ Object.defineProperty(exports, "CrossImpactAgent", { enumerable: true, get: function () { return cross_impact_js_1.CrossImpactAgent; } });
111
+ var regression_advisor_js_1 = require("./agents/regression-advisor.js");
112
+ Object.defineProperty(exports, "RegressionAdvisorAgent", { enumerable: true, get: function () { return regression_advisor_js_1.RegressionAdvisorAgent; } });
87
113
  // Training (route-families bootstrap and maintenance)
88
114
  var scanner_js_1 = require("./training/scanner.js");
89
115
  Object.defineProperty(exports, "scanProject", { enumerable: true, get: function () { return scanner_js_1.scanProject; } });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cross-Impact Analyst prompt — finds ripple effects across route families.
3
+ */
4
+ import type { RouteFamily } from '../knowledge/route_families.js';
5
+ export interface CrossImpactPromptContext {
6
+ changedFiles: string[];
7
+ families: RouteFamily[];
8
+ /** The families directly impacted by changed files */
9
+ directlyImpactedFamilyIds: string[];
10
+ }
11
+ export declare function buildCrossImpactPrompt(ctx: CrossImpactPromptContext): string;
12
+ export interface CrossImpactAgentResponse {
13
+ crossImpacts: Array<{
14
+ sourceFamily: string;
15
+ affectedFamily: string;
16
+ sharedDependency: string;
17
+ riskLevel: 'high' | 'medium' | 'low' | string;
18
+ evidence: string;
19
+ }>;
20
+ }
21
+ export declare function parseCrossImpactResponse(text: string): CrossImpactAgentResponse | null;
22
+ //# sourceMappingURL=cross-impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-impact.d.ts","sourceRoot":"","sources":["../../src/prompts/cross-impact.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAIhE,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,EAAE,CAAC;CACvC;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CA+C5E;AAED,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,KAAK,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QAC9C,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAqBtF"}
@@ -0,0 +1,75 @@
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.buildCrossImpactPrompt = buildCrossImpactPrompt;
6
+ exports.parseCrossImpactResponse = parseCrossImpactResponse;
7
+ const sanitize_js_1 = require("../crew/sanitize.js");
8
+ function buildCrossImpactPrompt(ctx) {
9
+ const familiesBlock = ctx.families
10
+ .map((f) => {
11
+ const paths = [
12
+ ...(f.webappPaths || []),
13
+ ...(f.serverPaths || []),
14
+ ...(f.components || []),
15
+ ];
16
+ return `- ${f.id}: routes=[${f.routes.join(', ')}] paths=[${paths.join(', ')}] pageObjects=[${(f.pageObjects || []).join(', ')}]`;
17
+ })
18
+ .join('\n');
19
+ const changedBlock = ctx.changedFiles.map((f) => (0, sanitize_js_1.sanitizeForPrompt)(f)).join('\n');
20
+ return [
21
+ 'You are analyzing code changes in Mattermost to identify cross-family ripple effects.',
22
+ 'When a change in one route family could affect another family through shared dependencies,',
23
+ 'that is a cross-impact.',
24
+ '',
25
+ `CHANGED FILES (${ctx.changedFiles.length}):`,
26
+ changedBlock,
27
+ '',
28
+ `DIRECTLY IMPACTED FAMILIES: ${ctx.directlyImpactedFamilyIds.join(', ')}`,
29
+ '',
30
+ `ALL ROUTE FAMILIES (${ctx.families.length}):`,
31
+ familiesBlock,
32
+ '',
33
+ 'TASK: Identify cross-family impacts. For each pair, explain the shared dependency.',
34
+ '',
35
+ 'Look for:',
36
+ '1. Shared webapp paths (same component used by multiple families)',
37
+ '2. Shared page objects (same PO class referenced by multiple families)',
38
+ '3. Shared API endpoints (changes affecting data used by multiple families)',
39
+ '4. Shared components (React components imported across family boundaries)',
40
+ '5. Shared state management (Redux stores, contexts used across families)',
41
+ '',
42
+ 'Return strict JSON only with this shape:',
43
+ '{"crossImpacts":[{"sourceFamily":"<directly impacted family>","affectedFamily":"<indirectly affected family>","sharedDependency":"<what connects them>","riskLevel":"high|medium|low","evidence":"<specific file/component/API that creates the dependency>"}]}',
44
+ '',
45
+ 'Rules:',
46
+ '- Only report cross-impacts where both families are in the manifest.',
47
+ '- sourceFamily must be one of the directly impacted families.',
48
+ '- affectedFamily must be DIFFERENT from sourceFamily.',
49
+ '- Risk levels: high = shared data model/state, medium = shared UI component, low = shared utility.',
50
+ '- Evidence must cite specific files, components, or API paths.',
51
+ '- Return empty array if no cross-impacts are found.',
52
+ ].join('\n');
53
+ }
54
+ function parseCrossImpactResponse(text) {
55
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
56
+ const candidates = fenced ? [fenced[1], text] : [text];
57
+ for (const candidate of candidates) {
58
+ const start = candidate.indexOf('{');
59
+ const end = candidate.lastIndexOf('}');
60
+ if (start < 0 || end <= start) {
61
+ continue;
62
+ }
63
+ const raw = candidate.slice(start, end + 1);
64
+ try {
65
+ const parsed = JSON.parse(raw);
66
+ if (parsed && Array.isArray(parsed.crossImpacts)) {
67
+ return parsed;
68
+ }
69
+ }
70
+ catch {
71
+ continue;
72
+ }
73
+ }
74
+ return null;
75
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Strategist prompt — designs overall test strategy from impact analysis,
3
+ * cross-impact data, and regression risk.
4
+ */
5
+ import type { FlowDecision } from '../validation/output_schema.js';
6
+ import type { CrossImpact, RegressionRisk } from '../crew/types.js';
7
+ export interface StrategistPromptContext {
8
+ impactedFlows: FlowDecision[];
9
+ crossImpacts: CrossImpact[];
10
+ regressionRisks: RegressionRisk[];
11
+ }
12
+ export declare function buildStrategistPrompt(ctx: StrategistPromptContext): string;
13
+ export interface StrategistAgentResponse {
14
+ strategy: Array<{
15
+ flowId: string;
16
+ flowName: string;
17
+ priority: 'P0' | 'P1' | 'P2' | string;
18
+ approach: 'full-test' | 'smoke-test' | 'skip' | 'manual-review' | string;
19
+ rationale: string;
20
+ testCategories: string[];
21
+ crossImpactRisk: 'high' | 'medium' | 'low' | 'none' | string;
22
+ }>;
23
+ }
24
+ export declare function parseStrategistResponse(text: string): StrategistAgentResponse | null;
25
+ //# sourceMappingURL=strategist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategist.d.ts","sourceRoot":"","sources":["../../src/prompts/strategist.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,WAAW,EAAE,cAAc,EAAgB,MAAM,kBAAkB,CAAC;AAGjF,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,cAAc,EAAE,CAAC;CACrC;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CA4D1E;AAED,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,KAAK,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;QACtC,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC;QACzE,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;KAChE,CAAC,CAAC;CACN;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAqBpF"}
@@ -0,0 +1,83 @@
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.buildStrategistPrompt = buildStrategistPrompt;
6
+ exports.parseStrategistResponse = parseStrategistResponse;
7
+ const sanitize_js_1 = require("../crew/sanitize.js");
8
+ function buildStrategistPrompt(ctx) {
9
+ const flowsBlock = ctx.impactedFlows
10
+ .map((f) => {
11
+ const specs = f.existingSpecs.map((s) => `${s.path} (${s.coverageLevel})`).join(', ') || 'none';
12
+ return [
13
+ `- ${f.flowId} (${f.priority}): ${f.flowName}`,
14
+ ` Route Family: ${f.routeFamily}`,
15
+ ` Action: ${f.action}`,
16
+ ` Confidence: ${f.confidence}%`,
17
+ ` Existing Coverage: ${specs}`,
18
+ ` User Actions: ${(0, sanitize_js_1.sanitizeForPrompt)(f.userActions.join('; ') || 'unknown')}`,
19
+ ` Changed Files: ${f.changedFiles.join(', ')}`,
20
+ ].join('\n');
21
+ })
22
+ .join('\n\n');
23
+ const crossImpactBlock = ctx.crossImpacts.length > 0
24
+ ? ctx.crossImpacts.map((ci) => `- ${ci.sourceFamily} → ${ci.affectedFamily} (${ci.riskLevel}): ${ci.sharedDependency} — ${ci.evidence}`).join('\n')
25
+ : 'No cross-family impacts detected.';
26
+ const regressionBlock = ctx.regressionRisks.length > 0
27
+ ? ctx.regressionRisks.map((r) => `- ${r.familyId} (risk=${r.riskScore}): ${r.reason}`).join('\n')
28
+ : 'No regression risk data available.';
29
+ return [
30
+ 'You are a senior QA strategist designing the overall test strategy for a code change.',
31
+ '',
32
+ `IMPACTED FLOWS (${ctx.impactedFlows.length}):`,
33
+ flowsBlock,
34
+ '',
35
+ 'CROSS-FAMILY IMPACTS:',
36
+ crossImpactBlock,
37
+ '',
38
+ 'REGRESSION RISK:',
39
+ regressionBlock,
40
+ '',
41
+ 'TASK: Design a prioritized test strategy for each impacted flow.',
42
+ '',
43
+ 'For each flow, decide:',
44
+ '1. Approach: full-test (comprehensive), smoke-test (critical path only), skip, or manual-review',
45
+ '2. Priority: P0 (critical path), P1 (important), P2 (nice to have)',
46
+ '3. Test categories to cover (from: happy-path, edge-case, boundary, negative, state-transition, race-condition, permission, accessibility, performance)',
47
+ '4. Cross-impact risk level based on shared dependencies',
48
+ '',
49
+ 'Return strict JSON only with this shape:',
50
+ '{"strategy":[{"flowId":"<id>","flowName":"<name>","priority":"P0|P1|P2","approach":"full-test|smoke-test|skip|manual-review","rationale":"<why this approach>","testCategories":["happy-path","edge-case",...],"crossImpactRisk":"high|medium|low|none"}]}',
51
+ '',
52
+ 'Rules:',
53
+ '- P0 flows with create_spec or add_scenarios action should always get full-test.',
54
+ '- Flows with high cross-impact risk should be promoted to at least P1.',
55
+ '- Flows with high regression risk should include edge-case and boundary categories.',
56
+ '- Skip flows only if confidence < 30 AND no cross-impact risk.',
57
+ '- Include accessibility category for any flow involving interactive UI elements.',
58
+ '- Include permission category for any flow involving role-based features.',
59
+ '- Keep rationale concise (1-2 sentences) explaining why this approach was chosen.',
60
+ ].join('\n');
61
+ }
62
+ function parseStrategistResponse(text) {
63
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
64
+ const candidates = fenced ? [fenced[1], text] : [text];
65
+ for (const candidate of candidates) {
66
+ const start = candidate.indexOf('{');
67
+ const end = candidate.lastIndexOf('}');
68
+ if (start < 0 || end <= start) {
69
+ continue;
70
+ }
71
+ const raw = candidate.slice(start, end + 1);
72
+ try {
73
+ const parsed = JSON.parse(raw);
74
+ if (parsed && Array.isArray(parsed.strategy)) {
75
+ return parsed;
76
+ }
77
+ }
78
+ catch {
79
+ continue;
80
+ }
81
+ }
82
+ return null;
83
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Test Designer prompt — designs structured test cases across 9 categories.
3
+ * Replaces flat scenariosToAdd with rich TestCase[] that feed the Generator.
4
+ */
5
+ import type { FlowDecision } from '../validation/output_schema.js';
6
+ import { type ApiSurfaceCatalog } from '../knowledge/api_surface.js';
7
+ import type { SpecEntry } from '../knowledge/spec_index.js';
8
+ import type { StrategyEntry, CrossImpact } from '../crew/types.js';
9
+ export interface TestDesignerPromptContext {
10
+ flow: FlowDecision;
11
+ strategy: StrategyEntry;
12
+ apiSurface: ApiSurfaceCatalog;
13
+ existingSpecs: SpecEntry[];
14
+ crossImpacts: CrossImpact[];
15
+ }
16
+ export declare function buildTestDesignerPrompt(ctx: TestDesignerPromptContext): string;
17
+ export interface TestDesignerAgentResponse {
18
+ testDesign: {
19
+ flowId: string;
20
+ flowName: string;
21
+ testCases: Array<{
22
+ name: string;
23
+ type: 'happy-path' | 'edge-case' | 'boundary' | 'negative' | 'state-transition' | 'race-condition' | 'permission' | 'accessibility' | 'performance' | string;
24
+ preconditions: string[];
25
+ steps: string[];
26
+ expectedOutcome: string;
27
+ priority: 'P0' | 'P1' | 'P2' | string;
28
+ rationale: string;
29
+ }>;
30
+ };
31
+ }
32
+ export declare function parseTestDesignerResponse(text: string): TestDesignerAgentResponse | null;
33
+ //# sourceMappingURL=test-designer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-designer.d.ts","sourceRoot":"","sources":["../../src/prompts/test-designer.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAA4B,KAAK,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAC9F,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAC,aAAa,EAAE,WAAW,EAAa,MAAM,kBAAkB,CAAC;AAG7E,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,aAAa,EAAE,SAAS,EAAE,CAAC;IAC3B,YAAY,EAAE,WAAW,EAAE,CAAC;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,yBAAyB,GAAG,MAAM,CAuF9E;AAED,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,KAAK,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,YAAY,GAAG,eAAe,GAAG,aAAa,GAAG,MAAM,CAAC;YAC7J,aAAa,EAAE,MAAM,EAAE,CAAC;YACxB,KAAK,EAAE,MAAM,EAAE,CAAC;YAChB,eAAe,EAAE,MAAM,CAAC;YACxB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;YACtC,SAAS,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACN,CAAC;CACL;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,GAAG,IAAI,CAqBxF"}
@@ -0,0 +1,111 @@
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.buildTestDesignerPrompt = buildTestDesignerPrompt;
6
+ exports.parseTestDesignerResponse = parseTestDesignerResponse;
7
+ const api_surface_js_1 = require("../knowledge/api_surface.js");
8
+ const sanitize_js_1 = require("../crew/sanitize.js");
9
+ function buildTestDesignerPrompt(ctx) {
10
+ const relevantClasses = ctx.apiSurface.pageObjects
11
+ .map((po) => po.className)
12
+ .filter((name) => {
13
+ const lower = name.toLowerCase();
14
+ const hints = [ctx.flow.routeFamily, ctx.flow.featureId, ...ctx.flow.userActions.join(' ').split(/\s+/)]
15
+ .filter(Boolean)
16
+ .map((s) => s.toLowerCase().replace(/[^a-z]/g, ''));
17
+ return lower.includes('page') || hints.some((h) => h.length > 3 && lower.includes(h));
18
+ })
19
+ .slice(0, 10);
20
+ const apiBlock = relevantClasses.length > 0
21
+ ? (0, api_surface_js_1.formatApiSurfaceForPrompt)(ctx.apiSurface, relevantClasses)
22
+ : 'No page objects available.';
23
+ const existingSpecsBlock = ctx.existingSpecs.length > 0
24
+ ? ctx.existingSpecs.map((s) => `- ${s.relativePath}: ${s.testTitles.join(', ')}`).join('\n')
25
+ : 'No existing specs.';
26
+ const crossImpactBlock = ctx.crossImpacts.length > 0
27
+ ? ctx.crossImpacts.map((ci) => `- ${ci.sourceFamily} → ${ci.affectedFamily}: ${ci.sharedDependency} (${ci.riskLevel})`).join('\n')
28
+ : 'None detected.';
29
+ const categories = ctx.strategy.testCategories.join(', ');
30
+ return [
31
+ 'You are a senior QA engineer designing comprehensive test cases for a Mattermost user flow.',
32
+ '',
33
+ `FLOW: ${ctx.flow.flowName}`,
34
+ `Flow ID: ${ctx.flow.flowId}`,
35
+ `Route Family: ${ctx.flow.routeFamily}${ctx.flow.featureId ? ` / ${ctx.flow.featureId}` : ''}`,
36
+ `Route: ${ctx.flow.specificRoute || '(not specified)'}`,
37
+ `Priority: ${ctx.strategy.priority}`,
38
+ `Approach: ${ctx.strategy.approach}`,
39
+ `User Actions: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.flow.userActions.join('; ') || 'unknown')}`,
40
+ `Evidence: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.flow.evidence)}`,
41
+ '',
42
+ `REQUIRED TEST CATEGORIES: ${categories}`,
43
+ '',
44
+ 'AVAILABLE PAGE OBJECTS:',
45
+ apiBlock,
46
+ '',
47
+ 'EXISTING SPECS (avoid duplicating these):',
48
+ existingSpecsBlock,
49
+ '',
50
+ 'CROSS-FAMILY IMPACTS:',
51
+ crossImpactBlock,
52
+ '',
53
+ 'TASK: Design structured test cases for this flow.',
54
+ '',
55
+ 'Return strict JSON only with this shape:',
56
+ '{"testDesign":{"flowId":"<id>","flowName":"<name>","testCases":[{"name":"<descriptive name>","type":"<category>","preconditions":["<state required>"],"steps":["<user action>"],"expectedOutcome":"<what should happen>","priority":"P0|P1|P2","rationale":"<why this test matters>"}]}}',
57
+ '',
58
+ 'TYPE VALUES: happy-path, edge-case, boundary, negative, state-transition, race-condition, permission, accessibility, performance',
59
+ '',
60
+ 'Rules:',
61
+ '- Every test must describe a specific USER ACTION, not an implementation detail.',
62
+ '- Steps must be concrete: "click Create Channel button" not "test channel creation".',
63
+ '- Include preconditions (logged-in role, existing data state, etc.).',
64
+ '- Reference only page objects and methods listed above.',
65
+ '- Include a mandatory rationale explaining why this specific test case matters.',
66
+ '- Do NOT duplicate tests already covered by existing specs.',
67
+ '- Maximum 15 test cases per flow.',
68
+ '- For accessibility: test keyboard navigation, screen reader support, ARIA labels.',
69
+ '- For performance: test with realistic data volumes, measure load times.',
70
+ '- For edge cases: test unicode input, max-length fields, empty states, concurrent edits.',
71
+ '',
72
+ 'FEW-SHOT EXAMPLES:',
73
+ '',
74
+ 'Edge case example:',
75
+ '```json',
76
+ '{"name":"channel creation with unicode characters and max-length name","type":"edge-case","preconditions":["logged in as team member","team has < 1000 channels"],"steps":["open create channel dialog","enter 64-character name with emoji and CJK characters","click Create"],"expectedOutcome":"channel created successfully, name renders correctly in sidebar and header","priority":"P1","rationale":"catches encoding issues in channel name storage and rendering"}',
77
+ '```',
78
+ '',
79
+ 'Permission example:',
80
+ '```json',
81
+ '{"name":"guest user cannot archive a public channel","type":"permission","preconditions":["logged in as guest user","guest has access to public channel"],"steps":["open channel header menu","look for Archive Channel option"],"expectedOutcome":"Archive Channel option is not visible in the menu","priority":"P0","rationale":"permission escalation bug — guests archiving channels could disrupt entire teams"}',
82
+ '```',
83
+ '',
84
+ 'Accessibility example:',
85
+ '```json',
86
+ '{"name":"keyboard navigation through channel switcher results","type":"accessibility","preconditions":["logged in","channel switcher open via Ctrl+K"],"steps":["type partial channel name","press ArrowDown to navigate results","press Enter to select"],"expectedOutcome":"focus moves visually and via aria-activedescendant, selected channel opens","priority":"P1","rationale":"screen reader users rely on keyboard navigation — broken focus management makes the app unusable"}',
87
+ '```',
88
+ ].join('\n');
89
+ }
90
+ function parseTestDesignerResponse(text) {
91
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
92
+ const candidates = fenced ? [fenced[1], text] : [text];
93
+ for (const candidate of candidates) {
94
+ const start = candidate.indexOf('{');
95
+ const end = candidate.lastIndexOf('}');
96
+ if (start < 0 || end <= start) {
97
+ continue;
98
+ }
99
+ const raw = candidate.slice(start, end + 1);
100
+ try {
101
+ const parsed = JSON.parse(raw);
102
+ if (parsed?.testDesign?.testCases && Array.isArray(parsed.testDesign.testCases)) {
103
+ return parsed;
104
+ }
105
+ }
106
+ catch {
107
+ continue;
108
+ }
109
+ }
110
+ return null;
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yasserkhanorg/e2e-agents",
3
- "version": "1.7.7",
3
+ "version": "1.8.0",
4
4
  "description": "AI-powered E2E test impact analysis, generation, and healing. Analyzes code changes to identify affected Playwright tests, detects coverage gaps, and generates or repairs specs using pluggable LLM providers (Claude, OpenAI, Ollama). Includes MCP server, traceability, and CI/CD integration.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",