@yasserkhanorg/e2e-agents 0.3.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 (221) hide show
  1. package/LICENSE +168 -0
  2. package/README.md +620 -0
  3. package/dist/agent/analysis.d.ts +62 -0
  4. package/dist/agent/analysis.d.ts.map +1 -0
  5. package/dist/agent/analysis.js +292 -0
  6. package/dist/agent/blast_radius.d.ts +4 -0
  7. package/dist/agent/blast_radius.d.ts.map +1 -0
  8. package/dist/agent/blast_radius.js +37 -0
  9. package/dist/agent/cache_utils.d.ts +38 -0
  10. package/dist/agent/cache_utils.d.ts.map +1 -0
  11. package/dist/agent/cache_utils.js +67 -0
  12. package/dist/agent/config.d.ts +148 -0
  13. package/dist/agent/config.d.ts.map +1 -0
  14. package/dist/agent/config.js +640 -0
  15. package/dist/agent/dependency_graph.d.ts +14 -0
  16. package/dist/agent/dependency_graph.d.ts.map +1 -0
  17. package/dist/agent/dependency_graph.js +227 -0
  18. package/dist/agent/feedback.d.ts +55 -0
  19. package/dist/agent/feedback.d.ts.map +1 -0
  20. package/dist/agent/feedback.js +257 -0
  21. package/dist/agent/flags.d.ts +23 -0
  22. package/dist/agent/flags.d.ts.map +1 -0
  23. package/dist/agent/flags.js +171 -0
  24. package/dist/agent/flow_catalog.d.ts +25 -0
  25. package/dist/agent/flow_catalog.d.ts.map +1 -0
  26. package/dist/agent/flow_catalog.js +106 -0
  27. package/dist/agent/flow_mapping.d.ts +10 -0
  28. package/dist/agent/flow_mapping.d.ts.map +1 -0
  29. package/dist/agent/flow_mapping.js +84 -0
  30. package/dist/agent/framework.d.ts +13 -0
  31. package/dist/agent/framework.d.ts.map +1 -0
  32. package/dist/agent/framework.js +149 -0
  33. package/dist/agent/gap_suggestions.d.ts +14 -0
  34. package/dist/agent/gap_suggestions.d.ts.map +1 -0
  35. package/dist/agent/gap_suggestions.js +101 -0
  36. package/dist/agent/generator.d.ts +10 -0
  37. package/dist/agent/generator.d.ts.map +1 -0
  38. package/dist/agent/generator.js +115 -0
  39. package/dist/agent/git.d.ts +11 -0
  40. package/dist/agent/git.d.ts.map +1 -0
  41. package/dist/agent/git.js +90 -0
  42. package/dist/agent/handoff.d.ts +22 -0
  43. package/dist/agent/handoff.d.ts.map +1 -0
  44. package/dist/agent/handoff.js +180 -0
  45. package/dist/agent/impact-analyzer.d.ts +114 -0
  46. package/dist/agent/impact-analyzer.d.ts.map +1 -0
  47. package/dist/agent/impact-analyzer.js +557 -0
  48. package/dist/agent/index.d.ts +21 -0
  49. package/dist/agent/index.d.ts.map +1 -0
  50. package/dist/agent/index.js +38 -0
  51. package/dist/agent/model-router.d.ts +57 -0
  52. package/dist/agent/model-router.d.ts.map +1 -0
  53. package/dist/agent/model-router.js +154 -0
  54. package/dist/agent/operational_insights.d.ts +41 -0
  55. package/dist/agent/operational_insights.d.ts.map +1 -0
  56. package/dist/agent/operational_insights.js +126 -0
  57. package/dist/agent/pipeline.d.ts +23 -0
  58. package/dist/agent/pipeline.d.ts.map +1 -0
  59. package/dist/agent/pipeline.js +609 -0
  60. package/dist/agent/plan.d.ts +91 -0
  61. package/dist/agent/plan.d.ts.map +1 -0
  62. package/dist/agent/plan.js +331 -0
  63. package/dist/agent/playwright_report.d.ts +8 -0
  64. package/dist/agent/playwright_report.d.ts.map +1 -0
  65. package/dist/agent/playwright_report.js +126 -0
  66. package/dist/agent/report-generator.d.ts +24 -0
  67. package/dist/agent/report-generator.d.ts.map +1 -0
  68. package/dist/agent/report-generator.js +250 -0
  69. package/dist/agent/report.d.ts +81 -0
  70. package/dist/agent/report.d.ts.map +1 -0
  71. package/dist/agent/report.js +147 -0
  72. package/dist/agent/runner.d.ts +7 -0
  73. package/dist/agent/runner.d.ts.map +1 -0
  74. package/dist/agent/runner.js +576 -0
  75. package/dist/agent/selectors.d.ts +10 -0
  76. package/dist/agent/selectors.d.ts.map +1 -0
  77. package/dist/agent/selectors.js +75 -0
  78. package/dist/agent/spec-bridge.d.ts +101 -0
  79. package/dist/agent/spec-bridge.d.ts.map +1 -0
  80. package/dist/agent/spec-bridge.js +273 -0
  81. package/dist/agent/spec-builder.d.ts +102 -0
  82. package/dist/agent/spec-builder.d.ts.map +1 -0
  83. package/dist/agent/spec-builder.js +273 -0
  84. package/dist/agent/subsystem_risk.d.ts +23 -0
  85. package/dist/agent/subsystem_risk.d.ts.map +1 -0
  86. package/dist/agent/subsystem_risk.js +207 -0
  87. package/dist/agent/telemetry.d.ts +84 -0
  88. package/dist/agent/telemetry.d.ts.map +1 -0
  89. package/dist/agent/telemetry.js +220 -0
  90. package/dist/agent/test_path.d.ts +2 -0
  91. package/dist/agent/test_path.d.ts.map +1 -0
  92. package/dist/agent/test_path.js +23 -0
  93. package/dist/agent/tests.d.ts +18 -0
  94. package/dist/agent/tests.d.ts.map +1 -0
  95. package/dist/agent/tests.js +106 -0
  96. package/dist/agent/traceability.d.ts +22 -0
  97. package/dist/agent/traceability.d.ts.map +1 -0
  98. package/dist/agent/traceability.js +183 -0
  99. package/dist/agent/traceability_capture.d.ts +18 -0
  100. package/dist/agent/traceability_capture.d.ts.map +1 -0
  101. package/dist/agent/traceability_capture.js +313 -0
  102. package/dist/agent/traceability_ingest.d.ts +21 -0
  103. package/dist/agent/traceability_ingest.d.ts.map +1 -0
  104. package/dist/agent/traceability_ingest.js +237 -0
  105. package/dist/agent/utils.d.ts +13 -0
  106. package/dist/agent/utils.d.ts.map +1 -0
  107. package/dist/agent/utils.js +152 -0
  108. package/dist/agent/validators/selector-validator.d.ts +74 -0
  109. package/dist/agent/validators/selector-validator.d.ts.map +1 -0
  110. package/dist/agent/validators/selector-validator.js +165 -0
  111. package/dist/anthropic_provider.d.ts +65 -0
  112. package/dist/anthropic_provider.d.ts.map +1 -0
  113. package/dist/anthropic_provider.js +332 -0
  114. package/dist/api.d.ts +48 -0
  115. package/dist/api.d.ts.map +1 -0
  116. package/dist/api.js +113 -0
  117. package/dist/base_provider.d.ts +53 -0
  118. package/dist/base_provider.d.ts.map +1 -0
  119. package/dist/base_provider.js +81 -0
  120. package/dist/cli.d.ts +3 -0
  121. package/dist/cli.d.ts.map +1 -0
  122. package/dist/cli.js +843 -0
  123. package/dist/custom_provider.d.ts +20 -0
  124. package/dist/custom_provider.d.ts.map +1 -0
  125. package/dist/custom_provider.js +276 -0
  126. package/dist/e2e-test-gen/index.d.ts +51 -0
  127. package/dist/e2e-test-gen/index.d.ts.map +1 -0
  128. package/dist/e2e-test-gen/index.js +57 -0
  129. package/dist/e2e-test-gen/spec_parser.d.ts +142 -0
  130. package/dist/e2e-test-gen/spec_parser.d.ts.map +1 -0
  131. package/dist/e2e-test-gen/spec_parser.js +786 -0
  132. package/dist/e2e-test-gen/types.d.ts +185 -0
  133. package/dist/e2e-test-gen/types.d.ts.map +1 -0
  134. package/dist/e2e-test-gen/types.js +4 -0
  135. package/dist/esm/agent/analysis.js +287 -0
  136. package/dist/esm/agent/blast_radius.js +34 -0
  137. package/dist/esm/agent/cache_utils.js +63 -0
  138. package/dist/esm/agent/config.js +637 -0
  139. package/dist/esm/agent/dependency_graph.js +224 -0
  140. package/dist/esm/agent/feedback.js +253 -0
  141. package/dist/esm/agent/flags.js +160 -0
  142. package/dist/esm/agent/flow_catalog.js +103 -0
  143. package/dist/esm/agent/flow_mapping.js +81 -0
  144. package/dist/esm/agent/framework.js +145 -0
  145. package/dist/esm/agent/gap_suggestions.js +98 -0
  146. package/dist/esm/agent/generator.js +112 -0
  147. package/dist/esm/agent/git.js +87 -0
  148. package/dist/esm/agent/handoff.js +177 -0
  149. package/dist/esm/agent/impact-analyzer.js +548 -0
  150. package/dist/esm/agent/index.js +22 -0
  151. package/dist/esm/agent/model-router.js +150 -0
  152. package/dist/esm/agent/operational_insights.js +123 -0
  153. package/dist/esm/agent/pipeline.js +605 -0
  154. package/dist/esm/agent/plan.js +324 -0
  155. package/dist/esm/agent/playwright_report.js +123 -0
  156. package/dist/esm/agent/report-generator.js +247 -0
  157. package/dist/esm/agent/report.js +144 -0
  158. package/dist/esm/agent/runner.js +572 -0
  159. package/dist/esm/agent/selectors.js +71 -0
  160. package/dist/esm/agent/spec-bridge.js +267 -0
  161. package/dist/esm/agent/spec-builder.js +267 -0
  162. package/dist/esm/agent/subsystem_risk.js +204 -0
  163. package/dist/esm/agent/telemetry.js +216 -0
  164. package/dist/esm/agent/test_path.js +20 -0
  165. package/dist/esm/agent/tests.js +101 -0
  166. package/dist/esm/agent/traceability.js +180 -0
  167. package/dist/esm/agent/traceability_capture.js +310 -0
  168. package/dist/esm/agent/traceability_ingest.js +234 -0
  169. package/dist/esm/agent/utils.js +138 -0
  170. package/dist/esm/agent/validators/selector-validator.js +160 -0
  171. package/dist/esm/anthropic_provider.js +324 -0
  172. package/dist/esm/api.js +105 -0
  173. package/dist/esm/base_provider.js +77 -0
  174. package/dist/esm/cli.js +841 -0
  175. package/dist/esm/custom_provider.js +272 -0
  176. package/dist/esm/e2e-test-gen/index.js +50 -0
  177. package/dist/esm/e2e-test-gen/spec_parser.js +782 -0
  178. package/dist/esm/e2e-test-gen/types.js +3 -0
  179. package/dist/esm/index.js +16 -0
  180. package/dist/esm/logger.js +89 -0
  181. package/dist/esm/mcp-server.js +465 -0
  182. package/dist/esm/ollama_provider.js +300 -0
  183. package/dist/esm/openai_provider.js +242 -0
  184. package/dist/esm/package.json +3 -0
  185. package/dist/esm/plan-and-test-constants.js +126 -0
  186. package/dist/esm/provider_factory.js +336 -0
  187. package/dist/esm/provider_interface.js +23 -0
  188. package/dist/esm/provider_utils.js +96 -0
  189. package/dist/index.d.ts +31 -0
  190. package/dist/index.d.ts.map +1 -0
  191. package/dist/index.js +41 -0
  192. package/dist/logger.d.ts +23 -0
  193. package/dist/logger.d.ts.map +1 -0
  194. package/dist/logger.js +93 -0
  195. package/dist/mcp-server.d.ts +35 -0
  196. package/dist/mcp-server.d.ts.map +1 -0
  197. package/dist/mcp-server.js +469 -0
  198. package/dist/ollama_provider.d.ts +65 -0
  199. package/dist/ollama_provider.d.ts.map +1 -0
  200. package/dist/ollama_provider.js +308 -0
  201. package/dist/openai_provider.d.ts +23 -0
  202. package/dist/openai_provider.d.ts.map +1 -0
  203. package/dist/openai_provider.js +250 -0
  204. package/dist/plan-and-test-constants.d.ts +110 -0
  205. package/dist/plan-and-test-constants.d.ts.map +1 -0
  206. package/dist/plan-and-test-constants.js +132 -0
  207. package/dist/provider_factory.d.ts +99 -0
  208. package/dist/provider_factory.d.ts.map +1 -0
  209. package/dist/provider_factory.js +341 -0
  210. package/dist/provider_interface.d.ts +358 -0
  211. package/dist/provider_interface.d.ts.map +1 -0
  212. package/dist/provider_interface.js +28 -0
  213. package/dist/provider_utils.d.ts +39 -0
  214. package/dist/provider_utils.d.ts.map +1 -0
  215. package/dist/provider_utils.js +103 -0
  216. package/package.json +101 -0
  217. package/schemas/gap.schema.json +18 -0
  218. package/schemas/impact.schema.json +418 -0
  219. package/schemas/plan.schema.json +285 -0
  220. package/schemas/subsystem-risk-map.schema.json +62 -0
  221. package/schemas/traceability-input.schema.json +122 -0
@@ -0,0 +1,35 @@
1
+ interface Tool {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: Record<string, unknown>;
5
+ }
6
+ /**
7
+ * MCP Server for autonomous test discovery, generation, and healing
8
+ * Provides tools for Claude to interact with test framework
9
+ */
10
+ export declare class E2EAgentsMCPServer {
11
+ private repoRoot;
12
+ private tools;
13
+ private rateLimiter;
14
+ constructor(repoRoot?: string);
15
+ private defineTools;
16
+ /**
17
+ * Handle tool calls from Claude/Playwright agents
18
+ * SECURITY: Rate limiting enforced
19
+ */
20
+ callTool(name: string, args: Record<string, unknown>): Promise<string>;
21
+ private discoverTests;
22
+ private readFile;
23
+ private writeFile;
24
+ private runTests;
25
+ private getGitChanges;
26
+ private getRepositoryContext;
27
+ private getChangedFiles;
28
+ private analyzeChangesForTests;
29
+ /**
30
+ * Get all available tools
31
+ */
32
+ getTools(): Tool[];
33
+ }
34
+ export default E2EAgentsMCPServer;
35
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAaA,UAAU,IAAI;IACV,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AA4GD;;;GAGG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAAc;gBAErB,QAAQ,GAAE,MAAsB;IAM5C,OAAO,CAAC,WAAW;IAmGnB;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB5E,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,QAAQ;IAyDhB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,oBAAoB;IAqD5B,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,QAAQ,IAAI,IAAI,EAAE;CAGrB;AAYD,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,469 @@
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.E2EAgentsMCPServer = void 0;
6
+ /**
7
+ * MCP Server for E2E Agents - SECURITY HARDENED
8
+ * Exposes tools for Claude and Playwright agents to discover, generate, and heal tests
9
+ */
10
+ const child_process_1 = require("child_process");
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
13
+ const glob_1 = require("glob");
14
+ /**
15
+ * SECURITY: Path validation helper
16
+ * Prevents directory traversal attacks
17
+ */
18
+ function validatePathIsWithinRoot(filePath, rootPath) {
19
+ try {
20
+ const normalized = (0, path_1.resolve)(filePath);
21
+ const normalizedRoot = (0, path_1.resolve)(rootPath);
22
+ return normalized.startsWith(normalizedRoot + '/') || normalized === normalizedRoot;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ /**
29
+ * SECURITY: Input validation for shell arguments
30
+ * Prevents command injection attacks
31
+ */
32
+ function validatePlaywrightPattern(pattern) {
33
+ // Allow alphanumeric, dots, dashes, slashes, asterisks, underscores only
34
+ return /^[a-zA-Z0-9_\-.*\/]+$/.test(pattern) && !pattern.includes('..') && pattern.length < 512;
35
+ }
36
+ /**
37
+ * SECURITY: Validate git refs to prevent argument injection
38
+ */
39
+ function validateGitRef(ref) {
40
+ // Allow standard git ref patterns: branches, tags, commit hashes
41
+ // Blocks patterns that start with -- (options) or contain spaces
42
+ return (/^[a-zA-Z0-9_\-./~^]+$/.test(ref) &&
43
+ !ref.startsWith('--') &&
44
+ ref.length < 256 &&
45
+ !ref.includes('\n') &&
46
+ !ref.includes('\0'));
47
+ }
48
+ /**
49
+ * SECURITY: Validate browser names against allowlist
50
+ */
51
+ function validateBrowsers(browsers) {
52
+ const allowedBrowsers = new Set(['chromium', 'firefox', 'webkit']);
53
+ return browsers.length > 0 && browsers.length <= 3 && browsers.every((b) => allowedBrowsers.has(b));
54
+ }
55
+ /**
56
+ * SECURITY: Glob pattern validation
57
+ * Restricts to test-related patterns to prevent enumeration of sensitive files
58
+ */
59
+ function validateGlobPattern(pattern) {
60
+ // Block attempts to enumerate sensitive patterns
61
+ const blockedPatterns = [/\*\*\/\*\*/, /\.env/, /\.pem/, /\.key/, /aws|credentials|secret|password/i];
62
+ if (pattern.length > 256)
63
+ return false;
64
+ if (blockedPatterns.some((p) => p.test(pattern)))
65
+ return false;
66
+ if (pattern.includes('..'))
67
+ return false;
68
+ return /^[a-zA-Z0-9_\-.*\/]+$/.test(pattern);
69
+ }
70
+ /**
71
+ * SECURITY: Sanitize error messages to prevent information leakage
72
+ */
73
+ function sanitizeError(error, operation) {
74
+ if (error instanceof Error) {
75
+ // Only return safe error message, hide internal details
76
+ if (error.message.includes('ENOENT')) {
77
+ return `File not found (${operation})`;
78
+ }
79
+ if (error.message.includes('EACCES')) {
80
+ return `Permission denied (${operation})`;
81
+ }
82
+ if (error.message.includes('EISDIR')) {
83
+ return `Is a directory (${operation})`;
84
+ }
85
+ return `Operation failed: ${operation}`;
86
+ }
87
+ return 'An unexpected error occurred';
88
+ }
89
+ /**
90
+ * SECURITY: Rate limiter helper
91
+ */
92
+ class RateLimiter {
93
+ constructor(maxRequests = 100, windowMs = 60000) {
94
+ this.requests = [];
95
+ this.maxRequests = maxRequests;
96
+ this.windowMs = windowMs;
97
+ }
98
+ isAllowed() {
99
+ const now = Date.now();
100
+ this.requests = this.requests.filter((time) => now - time < this.windowMs);
101
+ if (this.requests.length >= this.maxRequests) {
102
+ return false;
103
+ }
104
+ this.requests.push(now);
105
+ return true;
106
+ }
107
+ }
108
+ /**
109
+ * MCP Server for autonomous test discovery, generation, and healing
110
+ * Provides tools for Claude to interact with test framework
111
+ */
112
+ class E2EAgentsMCPServer {
113
+ constructor(repoRoot = process.cwd()) {
114
+ this.repoRoot = repoRoot;
115
+ this.tools = this.defineTools();
116
+ this.rateLimiter = new RateLimiter(100, 60000); // 100 requests per minute
117
+ }
118
+ defineTools() {
119
+ return [
120
+ {
121
+ name: 'discover_tests',
122
+ description: 'Discover tests that need to be written based on code changes',
123
+ inputSchema: {
124
+ type: 'object',
125
+ properties: {
126
+ since: {
127
+ type: 'string',
128
+ description: 'Git ref to compare against (e.g., HEAD~5, main)',
129
+ },
130
+ pattern: {
131
+ type: 'string',
132
+ description: "Test file pattern to search (e.g., '**/*.spec.ts')",
133
+ },
134
+ },
135
+ },
136
+ },
137
+ {
138
+ name: 'read_file',
139
+ description: 'Read a file from the repository',
140
+ inputSchema: {
141
+ type: 'object',
142
+ properties: {
143
+ path: {
144
+ type: 'string',
145
+ description: 'File path relative to repo root',
146
+ },
147
+ },
148
+ required: ['path'],
149
+ },
150
+ },
151
+ {
152
+ name: 'write_file',
153
+ description: 'Write or create a file in the repository',
154
+ inputSchema: {
155
+ type: 'object',
156
+ properties: {
157
+ path: {
158
+ type: 'string',
159
+ description: 'File path relative to repo root',
160
+ },
161
+ content: {
162
+ type: 'string',
163
+ description: 'File content to write',
164
+ },
165
+ },
166
+ required: ['path', 'content'],
167
+ },
168
+ },
169
+ {
170
+ name: 'run_tests',
171
+ description: 'Run Playwright tests matching a pattern',
172
+ inputSchema: {
173
+ type: 'object',
174
+ properties: {
175
+ pattern: {
176
+ type: 'string',
177
+ description: "Test file pattern (e.g., 'tests/**/*.spec.ts')",
178
+ },
179
+ browsers: {
180
+ type: 'array',
181
+ items: { type: 'string' },
182
+ description: 'Browsers to test (chromium, firefox, webkit)',
183
+ },
184
+ },
185
+ },
186
+ },
187
+ {
188
+ name: 'get_git_changes',
189
+ description: 'Get files changed since a git reference',
190
+ inputSchema: {
191
+ type: 'object',
192
+ properties: {
193
+ since: {
194
+ type: 'string',
195
+ description: 'Git ref to compare against (e.g., HEAD~5, main)',
196
+ },
197
+ },
198
+ },
199
+ },
200
+ {
201
+ name: 'get_repository_context',
202
+ description: 'Get repository structure and project metadata',
203
+ inputSchema: {
204
+ type: 'object',
205
+ properties: {
206
+ include: {
207
+ type: 'array',
208
+ items: { type: 'string' },
209
+ description: 'What to include (package.json, tsconfig, playwright.config, tests)',
210
+ },
211
+ },
212
+ },
213
+ },
214
+ ];
215
+ }
216
+ /**
217
+ * Handle tool calls from Claude/Playwright agents
218
+ * SECURITY: Rate limiting enforced
219
+ */
220
+ async callTool(name, args) {
221
+ // SECURITY: Rate limiting
222
+ if (!this.rateLimiter.isAllowed()) {
223
+ return JSON.stringify({ error: 'Rate limit exceeded. Too many requests.' });
224
+ }
225
+ switch (name) {
226
+ case 'discover_tests':
227
+ return this.discoverTests(args);
228
+ case 'read_file':
229
+ return this.readFile(args);
230
+ case 'write_file':
231
+ return this.writeFile(args);
232
+ case 'run_tests':
233
+ return this.runTests(args);
234
+ case 'get_git_changes':
235
+ return this.getGitChanges(args);
236
+ case 'get_repository_context':
237
+ return this.getRepositoryContext(args);
238
+ default:
239
+ return JSON.stringify({ error: 'Unknown tool' });
240
+ }
241
+ }
242
+ discoverTests(args) {
243
+ try {
244
+ const since = args.since || 'HEAD~5';
245
+ const pattern = args.pattern || '**/*.spec.ts';
246
+ // SECURITY: Validate inputs
247
+ if (!validateGitRef(since)) {
248
+ return JSON.stringify({ error: 'Invalid git reference format' });
249
+ }
250
+ if (!validateGlobPattern(pattern)) {
251
+ return JSON.stringify({ error: 'Invalid pattern format' });
252
+ }
253
+ // Get changed files
254
+ const changedFiles = this.getChangedFiles(since);
255
+ // Find test files that might need updating
256
+ const testFiles = (0, glob_1.globSync)(pattern, { cwd: this.repoRoot });
257
+ return JSON.stringify({
258
+ changedFiles,
259
+ existingTests: testFiles,
260
+ recommendedTests: this.analyzeChangesForTests(changedFiles, testFiles),
261
+ });
262
+ }
263
+ catch (error) {
264
+ return JSON.stringify({ error: sanitizeError(error, 'discover_tests') });
265
+ }
266
+ }
267
+ readFile(args) {
268
+ try {
269
+ // SECURITY: Path traversal prevention
270
+ const filePath = (0, path_1.resolve)(this.repoRoot, args.path);
271
+ if (!validatePathIsWithinRoot(filePath, this.repoRoot)) {
272
+ return JSON.stringify({ error: 'Access denied' });
273
+ }
274
+ if (!(0, fs_1.existsSync)(filePath)) {
275
+ return JSON.stringify({ error: 'File not found' });
276
+ }
277
+ const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
278
+ return JSON.stringify({ path: args.path, content });
279
+ }
280
+ catch (error) {
281
+ return JSON.stringify({ error: sanitizeError(error, 'read_file') });
282
+ }
283
+ }
284
+ writeFile(args) {
285
+ try {
286
+ // SECURITY: Path traversal prevention
287
+ const filePath = (0, path_1.resolve)(this.repoRoot, args.path);
288
+ if (!validatePathIsWithinRoot(filePath, this.repoRoot)) {
289
+ return JSON.stringify({ error: 'Access denied' });
290
+ }
291
+ // SECURITY: Size limit to prevent resource exhaustion
292
+ if (args.content.length > 10 * 1024 * 1024) {
293
+ // 10MB limit
294
+ return JSON.stringify({ error: 'File too large' });
295
+ }
296
+ (0, fs_1.writeFileSync)(filePath, args.content, 'utf-8');
297
+ return JSON.stringify({ success: true, path: args.path });
298
+ }
299
+ catch (error) {
300
+ return JSON.stringify({ error: sanitizeError(error, 'write_file') });
301
+ }
302
+ }
303
+ runTests(args) {
304
+ try {
305
+ const pattern = args.pattern || '**/*.spec.ts';
306
+ const browsers = args.browsers || ['chromium'];
307
+ // SECURITY: Validate inputs
308
+ if (!validatePlaywrightPattern(pattern)) {
309
+ return JSON.stringify({ error: 'Invalid test pattern' });
310
+ }
311
+ if (!validateBrowsers(browsers)) {
312
+ return JSON.stringify({ error: 'Invalid browser specification' });
313
+ }
314
+ const projectArgs = browsers.flatMap((browser) => ['--project', browser]);
315
+ // SECURITY: Use -- to separate playwright options from test args
316
+ const result = (0, child_process_1.spawnSync)('npx', [
317
+ 'playwright',
318
+ 'test',
319
+ ...projectArgs,
320
+ '--',
321
+ pattern,
322
+ ], {
323
+ cwd: this.repoRoot,
324
+ encoding: 'utf-8',
325
+ timeout: 300000, // 5 minute timeout
326
+ maxBuffer: 1024 * 1024, // 1MB output limit
327
+ });
328
+ if (result.error) {
329
+ return JSON.stringify({
330
+ success: false,
331
+ error: 'Test execution failed',
332
+ });
333
+ }
334
+ // SECURITY: Don't leak full stdout/stderr, summarize instead
335
+ const stdout = result.stdout ? result.stdout.substring(0, 5000) : '';
336
+ const stderr = result.stderr ? result.stderr.substring(0, 5000) : '';
337
+ return JSON.stringify({
338
+ success: result.status === 0,
339
+ summary: `Exit code: ${result.status}`,
340
+ testsPassed: stdout.includes('passed'),
341
+ testsFailed: stdout.includes('failed'),
342
+ });
343
+ }
344
+ catch (error) {
345
+ return JSON.stringify({
346
+ success: false,
347
+ error: 'Test execution error',
348
+ });
349
+ }
350
+ }
351
+ getGitChanges(args) {
352
+ try {
353
+ const since = args.since || 'HEAD~5';
354
+ // SECURITY: Validate git ref
355
+ if (!validateGitRef(since)) {
356
+ return JSON.stringify({ error: 'Invalid git reference format' });
357
+ }
358
+ // SECURITY: Use -- to separate git options from refs
359
+ const result = (0, child_process_1.spawnSync)('git', ['diff', '--name-only', '--', `${since}..HEAD`], {
360
+ cwd: this.repoRoot,
361
+ encoding: 'utf-8',
362
+ timeout: 30000,
363
+ });
364
+ if (result.error) {
365
+ return JSON.stringify({ error: 'Git operation failed' });
366
+ }
367
+ const changedFiles = result.stdout.trim().split('\n').filter((f) => f);
368
+ return JSON.stringify({ changedFiles });
369
+ }
370
+ catch (error) {
371
+ return JSON.stringify({ error: 'Git operation error' });
372
+ }
373
+ }
374
+ getRepositoryContext(args) {
375
+ try {
376
+ const defaultInclude = ['package.json', 'tsconfig.json', 'playwright.config.ts', 'playwright.config.js'];
377
+ const include = args.include || defaultInclude;
378
+ // SECURITY: Limit to allowed filenames
379
+ const allowedFiles = new Set([
380
+ 'package.json',
381
+ 'tsconfig.json',
382
+ 'tsconfig.base.json',
383
+ 'playwright.config.ts',
384
+ 'playwright.config.js',
385
+ 'jest.config.js',
386
+ '.npmrc',
387
+ 'README.md',
388
+ ]);
389
+ const context = {};
390
+ for (const file of include) {
391
+ // SECURITY: Validate each path
392
+ if (!allowedFiles.has(file)) {
393
+ continue; // Skip non-allowed files
394
+ }
395
+ const filePath = (0, path_1.resolve)(this.repoRoot, file);
396
+ if (!validatePathIsWithinRoot(filePath, this.repoRoot)) {
397
+ continue;
398
+ }
399
+ if ((0, fs_1.existsSync)(filePath)) {
400
+ try {
401
+ context[file] = (0, fs_1.readFileSync)(filePath, 'utf-8');
402
+ }
403
+ catch {
404
+ // Ignore read errors for individual files
405
+ }
406
+ }
407
+ }
408
+ // Add test structure with safe globbing
409
+ const testFiles = (0, glob_1.globSync)('**/*.spec.ts', {
410
+ cwd: this.repoRoot,
411
+ ignore: 'node_modules/**',
412
+ maxDepth: 5,
413
+ });
414
+ context.testFiles = testFiles.slice(0, 100); // Limit to 100 files
415
+ return JSON.stringify(context);
416
+ }
417
+ catch (error) {
418
+ return JSON.stringify({ error: sanitizeError(error, 'get_repository_context') });
419
+ }
420
+ }
421
+ getChangedFiles(since) {
422
+ try {
423
+ // SECURITY: Validate git ref before use
424
+ if (!validateGitRef(since)) {
425
+ return [];
426
+ }
427
+ // SECURITY: Use -- separator
428
+ const result = (0, child_process_1.spawnSync)('git', ['diff', '--name-only', '--', `${since}..HEAD`], {
429
+ cwd: this.repoRoot,
430
+ encoding: 'utf-8',
431
+ timeout: 30000,
432
+ });
433
+ if (result.error) {
434
+ return [];
435
+ }
436
+ return result.stdout.trim().split('\n').filter((f) => f);
437
+ }
438
+ catch {
439
+ return [];
440
+ }
441
+ }
442
+ analyzeChangesForTests(changedFiles, existingTests) {
443
+ // Simple heuristic: if a source file changed, suggest a test for it
444
+ return changedFiles
445
+ .filter((f) => !f.endsWith('.spec.ts') && !f.endsWith('.test.ts'))
446
+ .slice(0, 10) // Limit results
447
+ .map((f) => {
448
+ const testFile = f.replace(/\.(ts|js)$/, '.spec.ts');
449
+ return testFile;
450
+ });
451
+ }
452
+ /**
453
+ * Get all available tools
454
+ */
455
+ getTools() {
456
+ return this.tools;
457
+ }
458
+ }
459
+ exports.E2EAgentsMCPServer = E2EAgentsMCPServer;
460
+ /**
461
+ * Start MCP server
462
+ * Usage: node dist/mcp-server.js
463
+ */
464
+ if (require.main === module) {
465
+ const server = new E2EAgentsMCPServer();
466
+ console.log('E2E Agents MCP Server started');
467
+ console.log('Tools:', server.getTools().map((t) => t.name).join(', '));
468
+ }
469
+ exports.default = E2EAgentsMCPServer;
@@ -0,0 +1,65 @@
1
+ import type { GenerateOptions, ImageInput, LLMResponse, OllamaConfig, ProviderCapabilities } from './provider_interface.js';
2
+ import { BaseProvider } from './base_provider.js';
3
+ /**
4
+ * Ollama Provider - Free, local LLM execution
5
+ *
6
+ * Features:
7
+ * - Zero cost (runs locally)
8
+ * - Full privacy (no data leaves your machine)
9
+ * - OpenAI-compatible API
10
+ * - Supports DeepSeek-R1, Llama 4, and other open models
11
+ *
12
+ * Limitations:
13
+ * - No vision support (most models)
14
+ * - Slower inference than cloud APIs (~2-5 sec vs <1 sec)
15
+ * - Requires local installation and model downloads
16
+ *
17
+ * Recommended models:
18
+ * - deepseek-r1:7b - Fast, good quality, low memory (4GB)
19
+ * - deepseek-r1:14b - Better quality, medium memory (8GB)
20
+ * - llama4:13b - High quality, medium memory (8GB)
21
+ * - deepseek-r1:7b-q4 - Quantized for speed, lower quality
22
+ *
23
+ * Setup:
24
+ * 1. Install Ollama: curl -fsSL https://ollama.com/install.sh | sh
25
+ * 2. Pull model: ollama pull deepseek-r1:7b
26
+ * 3. Start: ollama serve (runs on localhost:11434)
27
+ */
28
+ export declare class OllamaProvider extends BaseProvider {
29
+ name: string;
30
+ private client;
31
+ private model;
32
+ capabilities: ProviderCapabilities;
33
+ constructor(config: OllamaConfig);
34
+ generateText(prompt: string, options?: GenerateOptions): Promise<LLMResponse>;
35
+ /**
36
+ * Ollama does not support vision by default
37
+ * This method throws an error to help users understand the limitation
38
+ */
39
+ analyzeImage(images: ImageInput[], prompt: string, options?: GenerateOptions): Promise<LLMResponse>;
40
+ /**
41
+ * Stream text generation for real-time feedback
42
+ */
43
+ streamText(prompt: string, options?: GenerateOptions): AsyncGenerator<string, void, unknown>;
44
+ /**
45
+ * Check if Ollama is running and accessible
46
+ */
47
+ checkHealth(): Promise<{
48
+ healthy: boolean;
49
+ message: string;
50
+ }>;
51
+ /**
52
+ * List available models in Ollama
53
+ */
54
+ listModels(): Promise<string[]>;
55
+ }
56
+ /**
57
+ * Helper function to check if Ollama is installed and suggest setup
58
+ */
59
+ export declare function checkOllamaSetup(): Promise<{
60
+ installed: boolean;
61
+ running: boolean;
62
+ modelAvailable: boolean;
63
+ setupInstructions: string;
64
+ }>;
65
+ //# sourceMappingURL=ollama_provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama_provider.d.ts","sourceRoot":"","sources":["../src/ollama_provider.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACR,eAAe,EACf,UAAU,EACV,WAAW,EACX,YAAY,EACZ,oBAAoB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAiEhD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC5C,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IAEtB,YAAY,EAAE,oBAAoB,CAShC;gBAEU,MAAM,EAAE,YAAY;IA8B1B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAkEnF;;;OAGG;IAEG,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzG;;OAEG;IACI,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IAqDnG;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IAgBjE;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAaxC;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC7B,CAAC,CAoCD"}