@muuktest/maintenance-mcp 0.1.3
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.
- package/LICENSE +21 -0
- package/README.md +926 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +146 -0
- package/build/index.js.map +1 -0
- package/build/server.d.ts +26 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +220 -0
- package/build/server.js.map +1 -0
- package/build/utils.d.ts +23 -0
- package/build/utils.d.ts.map +1 -0
- package/build/utils.js +117 -0
- package/build/utils.js.map +1 -0
- package/package.json +53 -0
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MuukTest Maintenance MCP Server
|
|
4
|
+
* Analyzes E2E test failures and provides repair suggestions.
|
|
5
|
+
*/
|
|
6
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { analyzeImpl, } from "./server.js";
|
|
10
|
+
const API_URL = process.env.MUUK_API_URL ||
|
|
11
|
+
"https://oztodz5qove7dnpts5yln3ccl40bitlo.lambda-url.us-east-2.on.aws/";
|
|
12
|
+
const MUUK_KEY = process.env.MUUK_KEY || "";
|
|
13
|
+
const REQUEST_TIMEOUT_SECS = parseInt(process.env.MUUK_TIMEOUT_SECS || "300", 10);
|
|
14
|
+
const SIGNED_URL_ENDPOINT = process.env.MUUK_SIGNED_URL_ENDPOINT ||
|
|
15
|
+
"https://bm5s428g6e.execute-api.us-east-2.amazonaws.com/v1/mcp/getSignedUrl";
|
|
16
|
+
// Create server instance
|
|
17
|
+
const server = new Server({
|
|
18
|
+
name: "muuk-maintenance",
|
|
19
|
+
version: "0.1.3",
|
|
20
|
+
}, {
|
|
21
|
+
capabilities: {
|
|
22
|
+
tools: {},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
// Define input schema for tools
|
|
26
|
+
const INPUT_SCHEMA = {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
workspace_path: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "REQUIRED: The absolute path to the current workspace/project root. You must always provide this - get it from the current working directory.",
|
|
32
|
+
},
|
|
33
|
+
test_files_path: {
|
|
34
|
+
type: "array",
|
|
35
|
+
items: { type: "string" },
|
|
36
|
+
description: "Array of test file paths, relative to workspace (e.g., [./tests/a.spec.ts, ./foo/bar.json]). Allowed: .ts/.tsx/.js/.jsx, .spec.* variants, .json, .mjs/.cjs/.mts/.cts, .feature, .yaml/.yml, .txt/.csv, .xml, .env, .graphql/.gql",
|
|
37
|
+
},
|
|
38
|
+
failure_data_path: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Path to failure data directory, relative to workspace (e.g., ./failure-data/)",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ["workspace_path", "test_files_path", "failure_data_path"],
|
|
44
|
+
};
|
|
45
|
+
// List available tools
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
47
|
+
return {
|
|
48
|
+
tools: [
|
|
49
|
+
{
|
|
50
|
+
name: "fix_selectors",
|
|
51
|
+
description: "Fixing selector issues in E2E tests. Returns suggested fixes by generating an updated selector.",
|
|
52
|
+
inputSchema: INPUT_SCHEMA,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "fix_ui_flow",
|
|
56
|
+
description: "Fixing UI/flow issues in E2E tests. Returns suggested fixes by removing unnecessary steps or adding missing ones.",
|
|
57
|
+
inputSchema: INPUT_SCHEMA,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "fix_data_dependence",
|
|
61
|
+
description: "Fixing data dependence issues in E2E tests. Returns suggested fixes by updating test data used in a step.",
|
|
62
|
+
inputSchema: INPUT_SCHEMA,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
// Handle tool calls
|
|
68
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
69
|
+
const { name, arguments: args } = request.params;
|
|
70
|
+
if (!["fix_selectors", "fix_ui_flow", "fix_data_dependence"].includes(name)) {
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: JSON.stringify({ error: `Unknown tool: ${name}` }),
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (!args) {
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: JSON.stringify({ error: "Missing arguments" }, null, 2),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const scenario = name;
|
|
91
|
+
const required = ["workspace_path", "test_files_path", "failure_data_path"];
|
|
92
|
+
const missing = required.filter((k) => !args[k]);
|
|
93
|
+
if (missing.length > 0) {
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: JSON.stringify({
|
|
99
|
+
error: "Missing required arguments",
|
|
100
|
+
missing,
|
|
101
|
+
hint: "workspace_path must be the absolute path to your project root",
|
|
102
|
+
}, null, 2),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const result = await analyzeImpl(scenario, args.test_files_path, args.failure_data_path, args.workspace_path, {
|
|
109
|
+
apiUrl: API_URL,
|
|
110
|
+
muukKey: MUUK_KEY,
|
|
111
|
+
signedUrlEndpoint: SIGNED_URL_ENDPOINT,
|
|
112
|
+
timeoutSecs: REQUEST_TIMEOUT_SECS,
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: result,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: "text",
|
|
128
|
+
text: JSON.stringify({
|
|
129
|
+
error: "Execution failed",
|
|
130
|
+
details: error instanceof Error ? error.message : String(error),
|
|
131
|
+
}, null, 2),
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// Start the server
|
|
138
|
+
async function main() {
|
|
139
|
+
const transport = new StdioServerTransport();
|
|
140
|
+
await server.connect(transport);
|
|
141
|
+
}
|
|
142
|
+
main().catch((error) => {
|
|
143
|
+
console.error("Server error:", error);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core server logic for analyzing test failures
|
|
3
|
+
*/
|
|
4
|
+
interface AnalyzeConfig {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
muukKey: string;
|
|
7
|
+
signedUrlEndpoint: string;
|
|
8
|
+
timeoutSecs: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Validate and normalize input paths
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateInputs(testFilesPaths: string[], failureDataPath: string, workspace?: string): Promise<{
|
|
14
|
+
testPaths: string[];
|
|
15
|
+
failurePath: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Authenticate using Muuk Key
|
|
19
|
+
*/
|
|
20
|
+
export declare function authenticateMuukKey(muukKey: string): Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Execute test failure analysis
|
|
23
|
+
*/
|
|
24
|
+
export declare function analyzeImpl(scenario: string, testFilesPath: string[], failureDataPath: string, workspacePath: string, config: AnalyzeConfig): Promise<string>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AA8CD;;GAEG;AACH,wBAAsB,cAAc,CAClC,cAAc,EAAE,MAAM,EAAE,EACxB,eAAe,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA8CvD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc3E;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EAAE,EACvB,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAgJjB"}
|
package/build/server.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core server logic for analyzing test failures
|
|
3
|
+
*/
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import * as fs from "fs/promises";
|
|
6
|
+
import axios from "axios";
|
|
7
|
+
import { createTempZip, requestSignedUrl, uploadZipToS3, buildS3Path } from "./utils.js";
|
|
8
|
+
const MUUK_AUTH_URL = "https://portal.muuktest.com:8081/generate_token_executer?=";
|
|
9
|
+
/**
|
|
10
|
+
* Normalize path to absolute, using workspace as base for relative paths
|
|
11
|
+
*/
|
|
12
|
+
function normPath(p, workspace) {
|
|
13
|
+
const expanded = p.replace(/^~/, process.env.HOME || "");
|
|
14
|
+
if (path.isAbsolute(expanded)) {
|
|
15
|
+
return path.resolve(expanded);
|
|
16
|
+
}
|
|
17
|
+
const base = workspace || process.cwd();
|
|
18
|
+
return path.resolve(base, expanded);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if file is an allowed test file type
|
|
22
|
+
*/
|
|
23
|
+
function isAllowedTestFile(filePath) {
|
|
24
|
+
const name = path.basename(filePath).toLowerCase();
|
|
25
|
+
const allowedExtensions = [
|
|
26
|
+
".spec.ts",
|
|
27
|
+
".spec.tsx",
|
|
28
|
+
".spec.js",
|
|
29
|
+
".spec.jsx",
|
|
30
|
+
".ts",
|
|
31
|
+
".tsx",
|
|
32
|
+
".js",
|
|
33
|
+
".jsx",
|
|
34
|
+
".json",
|
|
35
|
+
".mjs",
|
|
36
|
+
".cjs",
|
|
37
|
+
".mts",
|
|
38
|
+
".cts",
|
|
39
|
+
".feature",
|
|
40
|
+
".yaml",
|
|
41
|
+
".yml",
|
|
42
|
+
".txt",
|
|
43
|
+
".csv",
|
|
44
|
+
".xml",
|
|
45
|
+
".env",
|
|
46
|
+
".graphql",
|
|
47
|
+
".gql",
|
|
48
|
+
];
|
|
49
|
+
return allowedExtensions.some((ext) => name.endsWith(ext));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validate and normalize input paths
|
|
53
|
+
*/
|
|
54
|
+
export async function validateInputs(testFilesPaths, failureDataPath, workspace) {
|
|
55
|
+
if (!Array.isArray(testFilesPaths)) {
|
|
56
|
+
throw new Error("test_files_path must be an array of file paths");
|
|
57
|
+
}
|
|
58
|
+
const testPaths = testFilesPaths.map((p) => normPath(p, workspace));
|
|
59
|
+
const failurePath = normPath(failureDataPath, workspace);
|
|
60
|
+
// Check if files exist
|
|
61
|
+
const missing = [];
|
|
62
|
+
for (const p of testPaths) {
|
|
63
|
+
try {
|
|
64
|
+
const stat = await fs.stat(p);
|
|
65
|
+
if (!stat.isFile()) {
|
|
66
|
+
throw new Error(`test-files path must be a file: ${p}`);
|
|
67
|
+
}
|
|
68
|
+
if (!isAllowedTestFile(p)) {
|
|
69
|
+
throw new Error(`Unsupported test file type: ${p}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error.code === "ENOENT") {
|
|
74
|
+
missing.push(p);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const stat = await fs.stat(failurePath);
|
|
83
|
+
if (!stat.isDirectory()) {
|
|
84
|
+
throw new Error(`failure-data path must be a directory: ${failurePath}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === "ENOENT") {
|
|
89
|
+
missing.push(failurePath);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (missing.length > 0) {
|
|
96
|
+
throw new Error(`Missing file(s): ${missing.join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
return { testPaths, failurePath };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Authenticate using Muuk Key
|
|
102
|
+
*/
|
|
103
|
+
export async function authenticateMuukKey(muukKey) {
|
|
104
|
+
try {
|
|
105
|
+
const response = await axios.post(MUUK_AUTH_URL, { key: muukKey }, {
|
|
106
|
+
headers: { "Content-Type": "application/json" },
|
|
107
|
+
timeout: 30000,
|
|
108
|
+
});
|
|
109
|
+
return response.status !== 500;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Execute test failure analysis
|
|
117
|
+
*/
|
|
118
|
+
export async function analyzeImpl(scenario, testFilesPath, failureDataPath, workspacePath, config) {
|
|
119
|
+
if (!config.muukKey) {
|
|
120
|
+
return JSON.stringify({
|
|
121
|
+
error: "Muuk Key not configured",
|
|
122
|
+
hint: "Set MUUK_KEY environment variable",
|
|
123
|
+
}, null, 2);
|
|
124
|
+
}
|
|
125
|
+
// Authenticate
|
|
126
|
+
const isAuthenticated = await authenticateMuukKey(config.muukKey);
|
|
127
|
+
if (!isAuthenticated) {
|
|
128
|
+
return JSON.stringify({
|
|
129
|
+
error: "Invalid Muuk Key or authentication failed",
|
|
130
|
+
hint: "Verify your MUUK_KEY environment variable",
|
|
131
|
+
}, null, 2);
|
|
132
|
+
}
|
|
133
|
+
// Validate inputs
|
|
134
|
+
let testPaths;
|
|
135
|
+
let failurePath;
|
|
136
|
+
try {
|
|
137
|
+
const validated = await validateInputs(testFilesPath, failureDataPath, workspacePath);
|
|
138
|
+
testPaths = validated.testPaths;
|
|
139
|
+
failurePath = validated.failurePath;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
return JSON.stringify({
|
|
143
|
+
error: "Invalid input paths",
|
|
144
|
+
details: error instanceof Error ? error.message : String(error),
|
|
145
|
+
}, null, 2);
|
|
146
|
+
}
|
|
147
|
+
// Upload to S3
|
|
148
|
+
let zipPath = null;
|
|
149
|
+
let sourcePath;
|
|
150
|
+
let signedUrl;
|
|
151
|
+
try {
|
|
152
|
+
const signedUrlData = await requestSignedUrl(config.muukKey, config.signedUrlEndpoint);
|
|
153
|
+
sourcePath = signedUrlData.sourcePath;
|
|
154
|
+
signedUrl = signedUrlData.signedUrl;
|
|
155
|
+
zipPath = await createTempZip(testPaths, failurePath);
|
|
156
|
+
await uploadZipToS3(zipPath, signedUrl);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (axios.isAxiosError(error)) {
|
|
160
|
+
return JSON.stringify({
|
|
161
|
+
error: "S3 upload failed",
|
|
162
|
+
details: error.message,
|
|
163
|
+
}, null, 2);
|
|
164
|
+
}
|
|
165
|
+
return JSON.stringify({
|
|
166
|
+
error: "Upload preparation failed",
|
|
167
|
+
details: error instanceof Error ? error.message : String(error),
|
|
168
|
+
}, null, 2);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
if (zipPath) {
|
|
172
|
+
try {
|
|
173
|
+
await fs.unlink(zipPath);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Ignore cleanup errors
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Call API
|
|
181
|
+
const payload = {
|
|
182
|
+
config: {
|
|
183
|
+
muuk_key: config.muukKey,
|
|
184
|
+
},
|
|
185
|
+
s3_path: buildS3Path(sourcePath, signedUrl),
|
|
186
|
+
scenario: scenario,
|
|
187
|
+
};
|
|
188
|
+
try {
|
|
189
|
+
const response = await axios.post(config.apiUrl, payload, {
|
|
190
|
+
headers: { "Content-Type": "application/json" },
|
|
191
|
+
timeout: config.timeoutSecs * 1000,
|
|
192
|
+
});
|
|
193
|
+
if (response.status === 200) {
|
|
194
|
+
const data = response.data;
|
|
195
|
+
const report = data.report || data;
|
|
196
|
+
return typeof report === "string" ? report : JSON.stringify(report, null, 2);
|
|
197
|
+
}
|
|
198
|
+
return JSON.stringify({
|
|
199
|
+
error: `API error (${response.status})`,
|
|
200
|
+
details: JSON.stringify(response.data).substring(0, 2000),
|
|
201
|
+
payload_sent: payload,
|
|
202
|
+
}, null, 2);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (axios.isAxiosError(error)) {
|
|
206
|
+
if (error.code === "ECONNABORTED") {
|
|
207
|
+
return JSON.stringify({ error: "Request timed out" }, null, 2);
|
|
208
|
+
}
|
|
209
|
+
return JSON.stringify({
|
|
210
|
+
error: "Connection error",
|
|
211
|
+
details: error.message,
|
|
212
|
+
}, null, 2);
|
|
213
|
+
}
|
|
214
|
+
return JSON.stringify({
|
|
215
|
+
error: "Unexpected error",
|
|
216
|
+
details: error instanceof Error ? error.message : String(error),
|
|
217
|
+
}, null, 2);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/build/utils.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for file handling and S3 operations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create a temporary zip file containing test files and failure data
|
|
6
|
+
*/
|
|
7
|
+
export declare function createTempZip(testFiles: string[], failureDataDir: string, testRootName?: string, failureRootName?: string): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Request a signed URL for S3 upload
|
|
10
|
+
*/
|
|
11
|
+
export declare function requestSignedUrl(muukKey: string, endpoint: string): Promise<{
|
|
12
|
+
sourcePath: string;
|
|
13
|
+
signedUrl: string;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Upload a zip file to S3 using a signed URL
|
|
17
|
+
*/
|
|
18
|
+
export declare function uploadZipToS3(zipPath: string, signedUrl: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Build a full HTTPS path for the uploaded zip directory
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildS3Path(sourcePath: string, signedUrl: string): string;
|
|
23
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6BH;;GAEG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EAAE,EACnB,cAAc,EAAE,MAAM,EACtB,YAAY,GAAE,MAAqB,EACnC,eAAe,GAAE,MAAuB,GACvC,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBpD;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBzE"}
|
package/build/utils.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for file handling and S3 operations
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "fs/promises";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import * as os from "os";
|
|
7
|
+
import archiver from "archiver";
|
|
8
|
+
import axios from "axios";
|
|
9
|
+
import { createWriteStream, createReadStream } from "fs";
|
|
10
|
+
import { URL } from "url";
|
|
11
|
+
/**
|
|
12
|
+
* Create a unique filename if name already exists
|
|
13
|
+
*/
|
|
14
|
+
function uniqueName(name, seen) {
|
|
15
|
+
const count = seen.get(name) || 0;
|
|
16
|
+
if (count === 0) {
|
|
17
|
+
seen.set(name, 1);
|
|
18
|
+
return name;
|
|
19
|
+
}
|
|
20
|
+
seen.set(name, count + 1);
|
|
21
|
+
const lastDot = name.lastIndexOf(".");
|
|
22
|
+
if (lastDot > 0) {
|
|
23
|
+
const base = name.substring(0, lastDot);
|
|
24
|
+
const ext = name.substring(lastDot);
|
|
25
|
+
return `${base}_${count + 1}${ext}`;
|
|
26
|
+
}
|
|
27
|
+
return `${name}_${count + 1}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a temporary zip file containing test files and failure data
|
|
31
|
+
*/
|
|
32
|
+
export async function createTempZip(testFiles, failureDataDir, testRootName = "test-files", failureRootName = "failure-data") {
|
|
33
|
+
const tmpDir = os.tmpdir();
|
|
34
|
+
const zipPath = path.join(tmpDir, `muuk-${Date.now()}.zip`);
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const output = createWriteStream(zipPath);
|
|
37
|
+
const archive = archiver("zip", {
|
|
38
|
+
zlib: { level: 9 },
|
|
39
|
+
});
|
|
40
|
+
output.on("close", () => {
|
|
41
|
+
resolve(zipPath);
|
|
42
|
+
});
|
|
43
|
+
archive.on("error", (err) => {
|
|
44
|
+
reject(err);
|
|
45
|
+
});
|
|
46
|
+
archive.pipe(output);
|
|
47
|
+
// Add test files
|
|
48
|
+
const nameCounts = new Map();
|
|
49
|
+
for (const testFile of testFiles) {
|
|
50
|
+
const name = uniqueName(path.basename(testFile), nameCounts);
|
|
51
|
+
archive.file(testFile, { name: `${testRootName}/${name}` });
|
|
52
|
+
}
|
|
53
|
+
// Add failure data directory
|
|
54
|
+
archive.directory(failureDataDir, failureRootName);
|
|
55
|
+
archive.finalize();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Request a signed URL for S3 upload
|
|
60
|
+
*/
|
|
61
|
+
export async function requestSignedUrl(muukKey, endpoint) {
|
|
62
|
+
const response = await axios.post(endpoint, { key: muukKey }, {
|
|
63
|
+
headers: { "Content-Type": "application/json" },
|
|
64
|
+
timeout: 30000,
|
|
65
|
+
});
|
|
66
|
+
const data = response.data;
|
|
67
|
+
if (!data.sourcePath || !data.signedUrl) {
|
|
68
|
+
throw new Error("Signed URL response missing sourcePath or signedUrl");
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
sourcePath: data.sourcePath,
|
|
72
|
+
signedUrl: data.signedUrl,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Upload a zip file to S3 using a signed URL
|
|
77
|
+
*/
|
|
78
|
+
export async function uploadZipToS3(zipPath, signedUrl) {
|
|
79
|
+
const fileStream = createReadStream(zipPath);
|
|
80
|
+
const stats = await fs.stat(zipPath);
|
|
81
|
+
await axios.put(signedUrl, fileStream, {
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/zip",
|
|
84
|
+
"Content-Length": stats.size,
|
|
85
|
+
"x-amz-meta-purpose": "muukmcp",
|
|
86
|
+
"x-amz-server-side-encryption": "AES256",
|
|
87
|
+
},
|
|
88
|
+
timeout: 300000,
|
|
89
|
+
maxContentLength: Infinity,
|
|
90
|
+
maxBodyLength: Infinity,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build a full HTTPS path for the uploaded zip directory
|
|
95
|
+
*/
|
|
96
|
+
export function buildS3Path(sourcePath, signedUrl) {
|
|
97
|
+
try {
|
|
98
|
+
const parsed = new URL(signedUrl);
|
|
99
|
+
const base = `${parsed.protocol}//${parsed.hostname}`;
|
|
100
|
+
const signedPath = parsed.pathname;
|
|
101
|
+
const normalizedSource = sourcePath.replace(/^\/+|\/+$/g, "");
|
|
102
|
+
if (normalizedSource && signedPath.includes(normalizedSource)) {
|
|
103
|
+
const [prefix] = signedPath.split(normalizedSource);
|
|
104
|
+
return `${base}${prefix}${normalizedSource}/`;
|
|
105
|
+
}
|
|
106
|
+
const lastSlash = signedPath.lastIndexOf("/");
|
|
107
|
+
if (lastSlash > 0) {
|
|
108
|
+
const dirPath = signedPath.substring(0, lastSlash);
|
|
109
|
+
return `${base}${dirPath}/`;
|
|
110
|
+
}
|
|
111
|
+
return `${base}/`;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return sourcePath;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@muuktest/maintenance-mcp",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "MCP server for analyzing and repairing E2E test failures",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"maintenance-mcp": "./build/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"build/**/*",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"watch": "tsc --watch"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"testing",
|
|
22
|
+
"playwright",
|
|
23
|
+
"e2e",
|
|
24
|
+
"test-repair",
|
|
25
|
+
"ai",
|
|
26
|
+
"automation",
|
|
27
|
+
"muuktest",
|
|
28
|
+
"maintenance"
|
|
29
|
+
],
|
|
30
|
+
"author": "MuukTest <support@muuktest.com>",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"homepage": "https://muuktest.com",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/muuklabs/muukAgents-mcp.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/muuklabs/muukAgents-mcp/issues"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^0.5.0",
|
|
42
|
+
"archiver": "^7.0.1",
|
|
43
|
+
"axios": "^1.6.5"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/archiver": "^6.0.2",
|
|
47
|
+
"@types/node": "^24.0.0",
|
|
48
|
+
"typescript": "^5.3.3"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=24"
|
|
52
|
+
}
|
|
53
|
+
}
|