@yasserkhanorg/e2e-agents 1.7.6 → 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 +49 -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 +48 -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,36 @@
1
+ import type { RouteFamilyConfig } from '../knowledge/route_families.js';
2
+ import type { ApiSurfaceConfig } from '../knowledge/api_surface.js';
3
+ import type { Agent, AgentMessage, AgentResult } from './protocol.js';
4
+ import type { CrewContext } from './context.js';
5
+ import type { AgentRole } from './types.js';
6
+ import type { WorkflowName } from './workflows.js';
7
+ export interface CrewConfig {
8
+ appPath: string;
9
+ testsRoot: string;
10
+ gitSince: string;
11
+ gitIncludeUncommitted?: boolean;
12
+ routeFamilies?: RouteFamilyConfig;
13
+ apiSurface?: ApiSurfaceConfig;
14
+ workflow?: WorkflowName;
15
+ providerOverride?: string;
16
+ budgetUSD?: number;
17
+ dryRun?: boolean;
18
+ }
19
+ export interface CrewResult {
20
+ context: CrewContext;
21
+ warnings: string[];
22
+ timings: Record<string, number>;
23
+ }
24
+ export declare class CrewOrchestrator {
25
+ private agents;
26
+ registerAgent(agent: Agent): void;
27
+ run(config: CrewConfig): Promise<CrewResult>;
28
+ dispatch(role: AgentRole, action: string, ctx: CrewContext): Promise<AgentResult>;
29
+ parallel(roles: AgentRole[], action: string, ctx: CrewContext): Promise<AgentResult[]>;
30
+ broadcast(msg: AgentMessage, ctx: CrewContext): Promise<void>;
31
+ private runBuiltInPhase;
32
+ private runParallel;
33
+ private runSequential;
34
+ private checkPhaseResults;
35
+ }
36
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/crew/orchestrator.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAC,KAAK,EAAE,YAAY,EAAE,WAAW,EAAY,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAA6B,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAG7E,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAA+B;IAE7C,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI3B,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAwE5C,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BjF,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtF,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;YAerD,eAAe;YAwBf,WAAW;YAMX,aAAa;IAS3B,OAAO,CAAC,iBAAiB;CAM5B"}
@@ -0,0 +1,171 @@
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.CrewOrchestrator = void 0;
6
+ /**
7
+ * Crew Orchestrator — executes workflow definitions by dispatching to agents.
8
+ */
9
+ const git_js_1 = require("../agent/git.js");
10
+ const stage0_preprocess_js_1 = require("../pipeline/stage0_preprocess.js");
11
+ const logger_js_1 = require("../logger.js");
12
+ const context_js_1 = require("./context.js");
13
+ const workflows_js_1 = require("./workflows.js");
14
+ class CrewOrchestrator {
15
+ constructor() {
16
+ this.agents = new Map();
17
+ }
18
+ registerAgent(agent) {
19
+ this.agents.set(agent.role, agent);
20
+ }
21
+ async run(config) {
22
+ const workflow = workflows_js_1.WORKFLOWS[config.workflow || 'full-qa'];
23
+ const timings = {};
24
+ const warnings = [];
25
+ // Step 1: Get changed files
26
+ const gitResult = (0, git_js_1.getChangedFiles)(config.appPath, config.gitSince, {
27
+ includeUncommitted: config.gitIncludeUncommitted,
28
+ });
29
+ if (gitResult.error) {
30
+ warnings.push(`Git diff warning: ${gitResult.error}`);
31
+ }
32
+ const changedFiles = gitResult.files
33
+ .map((f) => f.replace(/\\/g, '/'))
34
+ .filter((f) => !(0, git_js_1.isTestFile)(f));
35
+ if (changedFiles.length === 0) {
36
+ warnings.push('No changed application files detected.');
37
+ }
38
+ // Initialize context (will be populated during preprocess phase)
39
+ const ctx = {
40
+ changedFiles,
41
+ routeFamilies: [],
42
+ manifest: null,
43
+ apiSurface: { pageObjects: [], generatedAt: '' },
44
+ specIndex: { specs: [], indexedAt: '' },
45
+ context: { documents: [], warnings: [] },
46
+ familyGroups: [],
47
+ preprocessResult: null,
48
+ appPath: config.appPath,
49
+ testsRoot: config.testsRoot,
50
+ gitSince: config.gitSince,
51
+ providerOverride: config.providerOverride,
52
+ impactedFlows: [],
53
+ strategyEntries: [],
54
+ testDesigns: [],
55
+ crossImpacts: [],
56
+ regressionRisks: [],
57
+ findings: [],
58
+ generatedSpecs: [],
59
+ usage: (0, context_js_1.createEmptyUsageStats)(),
60
+ messages: [],
61
+ warnings,
62
+ };
63
+ // Execute each phase
64
+ for (const phase of workflow.phases) {
65
+ const timer = logger_js_1.logger.timer(`crew:${phase.name}`);
66
+ if (phase.handler === 'built-in') {
67
+ await this.runBuiltInPhase(phase.name, ctx, config);
68
+ }
69
+ else if (phase.parallel && phase.parallel.length > 0) {
70
+ await this.runParallel(phase.parallel, phase.name, ctx);
71
+ }
72
+ else if (phase.sequential && phase.sequential.length > 0) {
73
+ await this.runSequential(phase.sequential, phase.name, ctx);
74
+ }
75
+ else {
76
+ warnings.push(`Phase '${phase.name}' has no handler, parallel, or sequential agents — skipped.`);
77
+ }
78
+ timings[phase.name] = timer.end();
79
+ // Budget check
80
+ if (config.budgetUSD && ctx.usage.totalCost >= config.budgetUSD) {
81
+ warnings.push(`Budget limit reached ($${ctx.usage.totalCost.toFixed(4)} >= $${config.budgetUSD}). Stopping workflow.`);
82
+ break;
83
+ }
84
+ }
85
+ return { context: ctx, warnings, timings };
86
+ }
87
+ async dispatch(role, action, ctx) {
88
+ const agent = this.agents.get(role);
89
+ if (!agent) {
90
+ return {
91
+ role,
92
+ status: 'failed',
93
+ output: null,
94
+ warnings: [`Agent '${role}' is not registered.`],
95
+ };
96
+ }
97
+ const task = { role, action, input: null };
98
+ try {
99
+ const result = await agent.execute(task, ctx);
100
+ if (result.usage) {
101
+ (0, context_js_1.mergeUsageStats)(ctx.usage, result.usage);
102
+ }
103
+ if (result.warnings && result.warnings.length > 0) {
104
+ ctx.warnings.push(...result.warnings);
105
+ }
106
+ return result;
107
+ }
108
+ catch (error) {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ ctx.warnings.push(`Agent '${role}' failed: ${message}`);
111
+ return { role, status: 'failed', output: null, warnings: [message] };
112
+ }
113
+ }
114
+ async parallel(roles, action, ctx) {
115
+ const promises = roles.map((role) => this.dispatch(role, action, ctx));
116
+ return Promise.all(promises);
117
+ }
118
+ async broadcast(msg, ctx) {
119
+ ctx.messages.push(msg);
120
+ const promises = [];
121
+ for (const agent of this.agents.values()) {
122
+ if (agent.onMessage && agent.role !== msg.from) {
123
+ promises.push(agent.onMessage(msg).catch((err) => {
124
+ ctx.warnings.push(`Broadcast to ${agent.role} failed: ${err instanceof Error ? err.message : String(err)}`);
125
+ }));
126
+ }
127
+ }
128
+ await Promise.all(promises);
129
+ }
130
+ async runBuiltInPhase(name, ctx, config) {
131
+ if (name === 'preprocess') {
132
+ if (ctx.changedFiles.length === 0) {
133
+ return;
134
+ }
135
+ const result = (0, stage0_preprocess_js_1.preprocess)(ctx.changedFiles, {
136
+ appPath: config.appPath,
137
+ testsRoot: config.testsRoot,
138
+ routeFamilies: config.routeFamilies,
139
+ apiSurface: config.apiSurface,
140
+ });
141
+ ctx.preprocessResult = result;
142
+ ctx.manifest = result.manifest;
143
+ ctx.routeFamilies = result.manifest?.families || [];
144
+ ctx.apiSurface = result.apiSurface;
145
+ ctx.specIndex = result.specIndex;
146
+ ctx.context = result.context;
147
+ ctx.familyGroups = result.familyGroups;
148
+ ctx.warnings.push(...result.warnings);
149
+ }
150
+ }
151
+ async runParallel(roles, phaseName, ctx) {
152
+ logger_js_1.logger.info(`Crew phase '${phaseName}': running ${roles.join(', ')} in parallel`);
153
+ const results = await this.parallel(roles, phaseName, ctx);
154
+ this.checkPhaseResults(phaseName, results, ctx);
155
+ }
156
+ async runSequential(roles, phaseName, ctx) {
157
+ logger_js_1.logger.info(`Crew phase '${phaseName}': running ${roles.join(' → ')} sequentially`);
158
+ const results = [];
159
+ for (const role of roles) {
160
+ results.push(await this.dispatch(role, phaseName, ctx));
161
+ }
162
+ this.checkPhaseResults(phaseName, results, ctx);
163
+ }
164
+ checkPhaseResults(phaseName, results, ctx) {
165
+ const allFailed = results.length > 0 && results.every((r) => r.status === 'failed');
166
+ if (allFailed) {
167
+ ctx.warnings.push(`Phase '${phaseName}': all ${results.length} agent(s) failed. Downstream phases may produce empty results.`);
168
+ }
169
+ }
170
+ }
171
+ exports.CrewOrchestrator = CrewOrchestrator;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Agent Crew Protocol — core interfaces for inter-agent communication and execution.
3
+ */
4
+ import type { ProviderUsageStats } from '../provider_interface.js';
5
+ import type { AgentRole } from './types.js';
6
+ import type { CrewContext } from './context.js';
7
+ export interface AgentMessage {
8
+ id: string;
9
+ from: AgentRole;
10
+ to: AgentRole | 'broadcast';
11
+ type: 'task' | 'result' | 'escalation' | 'finding';
12
+ payload: unknown;
13
+ correlationId: string;
14
+ timestamp: number;
15
+ }
16
+ export interface AgentTask {
17
+ role: AgentRole;
18
+ action: string;
19
+ input: unknown;
20
+ }
21
+ export interface AgentResult {
22
+ role: AgentRole;
23
+ status: 'success' | 'partial' | 'failed';
24
+ output: unknown;
25
+ usage?: ProviderUsageStats;
26
+ warnings: string[];
27
+ }
28
+ export interface Agent {
29
+ role: AgentRole;
30
+ execute(task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
31
+ onMessage?(msg: AgentMessage): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/crew/protocol.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,GAAG,WAAW,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"}
@@ -0,0 +1,4 @@
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 });
@@ -0,0 +1,3 @@
1
+ import type { LLMProvider } from '../provider_interface.js';
2
+ export declare function getCrewProvider(providerOverride?: string): Promise<LLMProvider>;
3
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/crew/provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAE1D,wBAAsB,eAAe,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAKrF"}
@@ -0,0 +1,16 @@
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.getCrewProvider = getCrewProvider;
6
+ /**
7
+ * Shared provider creation for crew agents — ensures consistent provider
8
+ * instantiation and prevents usage stats fragmentation.
9
+ */
10
+ const provider_factory_js_1 = require("../provider_factory.js");
11
+ async function getCrewProvider(providerOverride) {
12
+ if (providerOverride) {
13
+ return provider_factory_js_1.LLMProviderFactory.createFromString(providerOverride);
14
+ }
15
+ return provider_factory_js_1.LLMProviderFactory.createFromEnv();
16
+ }
@@ -0,0 +1,3 @@
1
+ export declare function sanitizeForPrompt(value: string): string;
2
+ export declare function sanitizeArray(values: string[]): string[];
3
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/crew/sanitize.ts"],"names":[],"mappings":"AAqBA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAExD"}
@@ -0,0 +1,31 @@
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.sanitizeForPrompt = sanitizeForPrompt;
6
+ exports.sanitizeArray = sanitizeArray;
7
+ /**
8
+ * Sanitize strings before interpolating into LLM prompts.
9
+ * Strips common prompt injection patterns while preserving useful content.
10
+ */
11
+ const INJECTION_PATTERNS = [
12
+ /ignore\s+(all\s+)?previous\s+instructions/gi,
13
+ /disregard\s+(all\s+)?(above|prior|previous)/gi,
14
+ /system\s*:\s*/gi,
15
+ /\[INST\]/gi,
16
+ /<<SYS>>/gi,
17
+ /<\|im_start\|>/gi,
18
+ /\bHuman\s*:\s*/gi,
19
+ /\bAssistant\s*:\s*/gi,
20
+ ];
21
+ const MAX_FIELD_LENGTH = 2000;
22
+ function sanitizeForPrompt(value) {
23
+ let sanitized = value.slice(0, MAX_FIELD_LENGTH);
24
+ for (const pattern of INJECTION_PATTERNS) {
25
+ sanitized = sanitized.replace(pattern, '[filtered]');
26
+ }
27
+ return sanitized;
28
+ }
29
+ function sanitizeArray(values) {
30
+ return values.map((v) => sanitizeForPrompt(v));
31
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Crew data types — structured test design, cross-impact analysis, and findings.
3
+ */
4
+ export type TestCaseType = 'happy-path' | 'edge-case' | 'boundary' | 'negative' | 'state-transition' | 'race-condition' | 'permission' | 'accessibility' | 'performance';
5
+ export interface TestCase {
6
+ name: string;
7
+ type: TestCaseType;
8
+ preconditions: string[];
9
+ steps: string[];
10
+ expectedOutcome: string;
11
+ priority: 'P0' | 'P1' | 'P2';
12
+ rationale: string;
13
+ }
14
+ export interface TestDesign {
15
+ flowId: string;
16
+ flowName: string;
17
+ testCases: TestCase[];
18
+ }
19
+ export interface CrossImpact {
20
+ sourceFamily: string;
21
+ affectedFamily: string;
22
+ sharedDependency: string;
23
+ riskLevel: 'high' | 'medium' | 'low';
24
+ evidence: string;
25
+ }
26
+ export interface Finding {
27
+ id: string;
28
+ type: 'bug' | 'gap' | 'risk' | 'flaky';
29
+ severity: 'critical' | 'high' | 'medium' | 'low';
30
+ source: AgentRole;
31
+ summary: string;
32
+ details: string;
33
+ relatedFlows: string[];
34
+ }
35
+ export interface RegressionRisk {
36
+ familyId: string;
37
+ filePattern: string;
38
+ riskScore: number;
39
+ reason: string;
40
+ historicalFailures: number;
41
+ }
42
+ export interface StrategyEntry {
43
+ flowId: string;
44
+ flowName: string;
45
+ priority: 'P0' | 'P1' | 'P2';
46
+ approach: 'full-test' | 'smoke-test' | 'skip' | 'manual-review';
47
+ rationale: string;
48
+ testCategories: TestCaseType[];
49
+ crossImpactRisk: 'high' | 'medium' | 'low' | 'none';
50
+ }
51
+ export type AgentRole = 'strategist' | 'test-designer' | 'cross-impact' | 'regression-advisor' | 'impact-analyst' | 'coverage-evaluator' | 'generator' | 'executor' | 'healer' | 'explorer';
52
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crew/types.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAClB,YAAY,GACZ,WAAW,GACX,UAAU,GACV,UAAU,GACV,kBAAkB,GAClB,gBAAgB,GAChB,YAAY,GACZ,eAAe,GACf,aAAa,CAAC;AAEpB,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IACvC,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,eAAe,CAAC;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACvD;AAED,MAAM,MAAM,SAAS,GACf,YAAY,GACZ,eAAe,GACf,cAAc,GACd,oBAAoB,GACpB,gBAAgB,GAChB,oBAAoB,GACpB,WAAW,GACX,UAAU,GACV,QAAQ,GACR,UAAU,CAAC"}
@@ -0,0 +1,4 @@
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 });
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Predefined workflow definitions — playbooks that compose agents into phases.
3
+ *
4
+ * Data flow through full-qa workflow:
5
+ *
6
+ * preprocess (built-in)
7
+ * → populates: familyGroups, routeFamilies, manifest, apiSurface, specIndex, context
8
+ *
9
+ * understand (parallel):
10
+ * impact-analyst → writes: impactedFlows
11
+ * cross-impact → writes: crossImpacts
12
+ * regression-advisor → writes: regressionRisks
13
+ *
14
+ * strategize (sequential):
15
+ * strategist → reads: impactedFlows, crossImpacts, regressionRisks
16
+ * → writes: strategyEntries
17
+ * test-designer → reads: strategyEntries, impactedFlows, crossImpacts, apiSurface, specIndex
18
+ * → writes: testDesigns
19
+ *
20
+ * execute (parallel):
21
+ * generator → reads: impactedFlows, testDesigns, apiSurface
22
+ * → writes: generatedSpecs
23
+ *
24
+ * validate (sequential):
25
+ * executor → reads: generatedSpecs, impactedFlows
26
+ * healer → reads: generatedSpecs, impactedFlows
27
+ */
28
+ import type { AgentRole } from './types.js';
29
+ export type WorkflowPhase = {
30
+ name: string;
31
+ handler: 'built-in';
32
+ parallel?: never;
33
+ sequential?: never;
34
+ } | {
35
+ name: string;
36
+ handler?: never;
37
+ parallel: AgentRole[];
38
+ sequential?: never;
39
+ } | {
40
+ name: string;
41
+ handler?: never;
42
+ parallel?: never;
43
+ sequential: AgentRole[];
44
+ };
45
+ export interface WorkflowDef {
46
+ name: string;
47
+ description: string;
48
+ phases: WorkflowPhase[];
49
+ }
50
+ export type WorkflowName = 'full-qa' | 'quick-check' | 'design-only';
51
+ export declare const WORKFLOWS: Record<WorkflowName, WorkflowDef>;
52
+ //# sourceMappingURL=workflows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/crew/workflows.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,MAAM,MAAM,aAAa,GACnB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAC,GACzE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAC,GAC1E;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,SAAS,EAAE,CAAA;CAAC,CAAC;AAEjF,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CAAC;AAErE,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE,WAAW,CA8BvD,CAAC"}
@@ -0,0 +1,36 @@
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.WORKFLOWS = void 0;
6
+ exports.WORKFLOWS = {
7
+ 'full-qa': {
8
+ name: 'full-qa',
9
+ description: 'Full multi-agent QA analysis: understand → strategize → execute → validate',
10
+ phases: [
11
+ { name: 'preprocess', handler: 'built-in' },
12
+ { name: 'understand', parallel: ['impact-analyst', 'cross-impact', 'regression-advisor'] },
13
+ { name: 'strategize', sequential: ['strategist', 'test-designer'] },
14
+ { name: 'execute', parallel: ['generator'] },
15
+ { name: 'validate', sequential: ['executor', 'healer'] },
16
+ ],
17
+ },
18
+ 'quick-check': {
19
+ name: 'quick-check',
20
+ description: 'Quick impact analysis with strategy recommendations',
21
+ phases: [
22
+ { name: 'preprocess', handler: 'built-in' },
23
+ { name: 'understand', parallel: ['impact-analyst'] },
24
+ { name: 'strategize', sequential: ['strategist'] },
25
+ ],
26
+ },
27
+ 'design-only': {
28
+ name: 'design-only',
29
+ description: 'Impact analysis through test design — no generation or execution',
30
+ phases: [
31
+ { name: 'preprocess', handler: 'built-in' },
32
+ { name: 'understand', parallel: ['impact-analyst', 'cross-impact'] },
33
+ { name: 'strategize', sequential: ['strategist', 'test-designer'] },
34
+ ],
35
+ },
36
+ };
@@ -143,6 +143,50 @@ function parseStatusLines(lines) {
143
143
  }
144
144
  return files;
145
145
  }
146
+ // Comment-line patterns by file extension.
147
+ // A diff that ONLY touches these lines is a comment-only change (typo fix, doc update).
148
+ const COMMENT_PATTERNS = [
149
+ { extensions: ['.go'], pattern: /^\s*(\/\/|\/\*|\*)/ },
150
+ { extensions: ['.ts', '.tsx', '.js', '.jsx'], pattern: /^\s*(\/\/|\/\*|\*|\*\/)/ },
151
+ { extensions: ['.py'], pattern: /^\s*#/ },
152
+ { extensions: ['.css', '.scss'], pattern: /^\s*(\/\*|\*|\*\/)/ },
153
+ ];
154
+ /**
155
+ * Check if a file's diff only changes comment lines (no code changes).
156
+ * Returns true if the diff is comment-only and can be safely excluded.
157
+ */
158
+ function isCommentOnlyDiff(file, repoRoot, baseRef) {
159
+ const diff = runGitRaw(['diff', `${baseRef}..HEAD`, '-U0', '--', file], repoRoot);
160
+ if (!diff)
161
+ return false;
162
+ const ext = file.slice(file.lastIndexOf('.'));
163
+ const commentEntry = COMMENT_PATTERNS.find((cp) => cp.extensions.includes(ext));
164
+ if (!commentEntry)
165
+ return false;
166
+ // Extract only added/removed content lines (skip diff headers)
167
+ const contentLines = diff
168
+ .split('\n')
169
+ .filter((line) => (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---'));
170
+ if (contentLines.length === 0)
171
+ return false;
172
+ // Every changed line must be a comment line
173
+ return contentLines.every((line) => {
174
+ const content = line.slice(1).trim(); // Remove +/- prefix
175
+ return content === '' || commentEntry.pattern.test(content);
176
+ });
177
+ }
178
+ /**
179
+ * Check if a file path is a test file (spec, test, or in test directories).
180
+ * Shared across pipeline and crew orchestrators.
181
+ */
182
+ export function isTestFile(file) {
183
+ const normalized = file.replace(/\\/g, '/');
184
+ return /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(normalized) ||
185
+ /_test\.go$/.test(normalized) ||
186
+ normalized.includes('__tests__/') ||
187
+ normalized.includes('/tests/') ||
188
+ normalized.includes('/test/');
189
+ }
146
190
  export function getChangedFiles(appRoot, since, options) {
147
191
  try {
148
192
  const files = new Set();
@@ -183,6 +227,10 @@ export function getChangedFiles(appRoot, since, options) {
183
227
  const filteredTestFiles = [];
184
228
  for (const f of allFiles) {
185
229
  if (isRelevantFile(f)) {
230
+ // Skip files where the diff only touches comments (typo fixes, doc updates)
231
+ if (isCommentOnlyDiff(f, repoRoot, baseRef)) {
232
+ continue;
233
+ }
186
234
  relevant.push(f);
187
235
  }
188
236
  else {
@@ -0,0 +1,37 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ /**
4
+ * Coverage Evaluator Agent — wraps pipeline stage2 (coverage evaluation) in the Agent interface.
5
+ */
6
+ import { runCoverageStage } from '../pipeline/stage2_coverage.js';
7
+ export class CoverageEvaluatorAgent {
8
+ constructor() {
9
+ this.role = 'coverage-evaluator';
10
+ }
11
+ async execute(_task, ctx) {
12
+ const warnings = [];
13
+ if (ctx.impactedFlows.length === 0) {
14
+ warnings.push('Coverage evaluator: no impacted flows to evaluate.');
15
+ return { role: this.role, status: 'partial', output: [], warnings };
16
+ }
17
+ try {
18
+ const result = await runCoverageStage(ctx.impactedFlows, ctx.specIndex, ctx.context, ctx.testsRoot, { provider: ctx.providerOverride });
19
+ // Replace impacted flows with coverage-enriched versions.
20
+ // This is intentionally a full replace (not push) because coverage evaluation
21
+ // returns the same flow IDs with updated coverage fields.
22
+ ctx.impactedFlows = result.decisions;
23
+ warnings.push(...result.warnings);
24
+ return {
25
+ role: this.role,
26
+ status: 'success',
27
+ output: result.decisions,
28
+ warnings,
29
+ };
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ warnings.push(`Coverage evaluator failed: ${message}`);
34
+ return { role: this.role, status: 'failed', output: null, warnings };
35
+ }
36
+ }
37
+ }