@tmhs/mobile-mcp 0.6.0 → 0.9.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.
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/addMap.d.ts +3 -0
- package/dist/tools/addMap.d.ts.map +1 -0
- package/dist/tools/addMap.js +223 -0
- package/dist/tools/addMap.js.map +1 -0
- package/dist/tools/analyzeBundle.d.ts +3 -0
- package/dist/tools/analyzeBundle.d.ts.map +1 -0
- package/dist/tools/analyzeBundle.js +122 -0
- package/dist/tools/analyzeBundle.js.map +1 -0
- package/dist/tools/checkDevEnvironment.js +1 -1
- package/dist/tools/checkDevEnvironment.js.map +1 -1
- package/dist/tools/configureOTA.d.ts +3 -0
- package/dist/tools/configureOTA.d.ts.map +1 -0
- package/dist/tools/configureOTA.js +118 -0
- package/dist/tools/configureOTA.js.map +1 -0
- package/dist/tools/generateForm.d.ts +3 -0
- package/dist/tools/generateForm.d.ts.map +1 -0
- package/dist/tools/generateForm.js +337 -0
- package/dist/tools/generateForm.js.map +1 -0
- package/dist/tools/generateScreenshots.d.ts +3 -0
- package/dist/tools/generateScreenshots.d.ts.map +1 -0
- package/dist/tools/generateScreenshots.js +128 -0
- package/dist/tools/generateScreenshots.js.map +1 -0
- package/dist/tools/generateTestFile.d.ts +3 -0
- package/dist/tools/generateTestFile.d.ts.map +1 -0
- package/dist/tools/generateTestFile.js +184 -0
- package/dist/tools/generateTestFile.js.map +1 -0
- package/dist/tools/runOnDevice.d.ts.map +1 -1
- package/dist/tools/runOnDevice.js +45 -40
- package/dist/tools/runOnDevice.js.map +1 -1
- package/dist/tools/runTests.d.ts +3 -0
- package/dist/tools/runTests.d.ts.map +1 -0
- package/dist/tools/runTests.js +165 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/tools/scaffoldProject.js +1 -1
- package/dist/tools/scaffoldProject.js.map +1 -1
- package/dist/tools/setupCI.d.ts +3 -0
- package/dist/tools/setupCI.d.ts.map +1 -0
- package/dist/tools/setupCI.js +202 -0
- package/dist/tools/setupCI.js.map +1 -0
- package/dist/tools/setupI18n.d.ts +3 -0
- package/dist/tools/setupI18n.d.ts.map +1 -0
- package/dist/tools/setupI18n.js +155 -0
- package/dist/tools/setupI18n.js.map +1 -0
- package/dist/tools/setupRealtime.d.ts +3 -0
- package/dist/tools/setupRealtime.d.ts.map +1 -0
- package/dist/tools/setupRealtime.js +311 -0
- package/dist/tools/setupRealtime.js.map +1 -0
- package/dist/tools/submitToAppStore.js +1 -1
- package/dist/tools/submitToAppStore.js.map +1 -1
- package/dist/tools/submitToPlayStore.d.ts +3 -0
- package/dist/tools/submitToPlayStore.d.ts.map +1 -0
- package/dist/tools/submitToPlayStore.js +92 -0
- package/dist/tools/submitToPlayStore.js.map +1 -0
- package/dist/tools/validateStoreMetadata.js +1 -1
- package/dist/tools/validateStoreMetadata.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3
|
+
import { join, dirname, basename, extname } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
source_file: z
|
|
7
|
+
.string()
|
|
8
|
+
.describe("Path to the source file to generate a test for (relative to project root or absolute)."),
|
|
9
|
+
project_path: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
13
|
+
framework: z
|
|
14
|
+
.enum(["expo", "flutter"])
|
|
15
|
+
.optional()
|
|
16
|
+
.default("expo")
|
|
17
|
+
.describe("Project framework (default: expo). Determines test file conventions."),
|
|
18
|
+
test_location: z
|
|
19
|
+
.enum(["__tests__", "colocated"])
|
|
20
|
+
.optional()
|
|
21
|
+
.default("__tests__")
|
|
22
|
+
.describe("Where to place test files. __tests__: sibling directory. colocated: same directory as source."),
|
|
23
|
+
};
|
|
24
|
+
function extractExports(content) {
|
|
25
|
+
const exports = [];
|
|
26
|
+
const patterns = [
|
|
27
|
+
/export\s+(?:default\s+)?function\s+(\w+)/g,
|
|
28
|
+
/export\s+(?:default\s+)?class\s+(\w+)/g,
|
|
29
|
+
/export\s+const\s+(\w+)/g,
|
|
30
|
+
];
|
|
31
|
+
for (const pattern of patterns) {
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
34
|
+
exports.push(match[1]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return exports;
|
|
38
|
+
}
|
|
39
|
+
function isComponent(content) {
|
|
40
|
+
return (content.includes("from \"react-native\"") ||
|
|
41
|
+
content.includes("from 'react-native'") ||
|
|
42
|
+
content.includes("from \"react\"") ||
|
|
43
|
+
content.includes("from 'react'") ||
|
|
44
|
+
/<\w+/.test(content));
|
|
45
|
+
}
|
|
46
|
+
function generateExpoTest(sourceName, exports, isReactComponent, importPath) {
|
|
47
|
+
const lines = [];
|
|
48
|
+
if (isReactComponent) {
|
|
49
|
+
lines.push(`import { render, screen } from "@testing-library/react-native";`);
|
|
50
|
+
const named = exports.filter((e) => e !== "default");
|
|
51
|
+
if (named.length > 0) {
|
|
52
|
+
lines.push(`import { ${named.join(", ")} } from "${importPath}";`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
lines.push(`import ${sourceName} from "${importPath}";`);
|
|
56
|
+
}
|
|
57
|
+
lines.push("");
|
|
58
|
+
const componentName = exports[0] || sourceName;
|
|
59
|
+
lines.push(`describe("${componentName}", () => {`);
|
|
60
|
+
lines.push(` it("renders without crashing", () => {`);
|
|
61
|
+
lines.push(` render(<${componentName} />);`);
|
|
62
|
+
lines.push(` });`);
|
|
63
|
+
lines.push("");
|
|
64
|
+
lines.push(` it.todo("handles user interaction");`);
|
|
65
|
+
lines.push(`});`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (exports.length > 0) {
|
|
69
|
+
lines.push(`import { ${exports.join(", ")} } from "${importPath}";`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lines.push(`import "${importPath}";`);
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push(`describe("${sourceName}", () => {`);
|
|
76
|
+
for (const exp of exports) {
|
|
77
|
+
lines.push(` describe("${exp}", () => {`);
|
|
78
|
+
lines.push(` it.todo("works correctly");`);
|
|
79
|
+
lines.push(` });`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
if (exports.length === 0) {
|
|
83
|
+
lines.push(` it.todo("works correctly");`);
|
|
84
|
+
}
|
|
85
|
+
lines.push(`});`);
|
|
86
|
+
}
|
|
87
|
+
lines.push("");
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
function generateFlutterTest(sourceName, importPath) {
|
|
91
|
+
return `import 'package:flutter_test/flutter_test.dart';
|
|
92
|
+
import '${importPath}';
|
|
93
|
+
|
|
94
|
+
void main() {
|
|
95
|
+
group('${sourceName}', () {
|
|
96
|
+
test('exists', () {
|
|
97
|
+
// Placeholder: replace with real assertions
|
|
98
|
+
expect(true, isTrue);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// TODO: add widget tests with testWidgets() if this is a widget
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
export function register(server) {
|
|
107
|
+
server.tool("mobile_generateTestFile", "Scaffold a test file for an existing component or module. Reads exports from the source file and generates matching test boilerplate.", inputSchema, async (args) => {
|
|
108
|
+
try {
|
|
109
|
+
const root = args.project_path || process.cwd();
|
|
110
|
+
const sourceAbsolute = args.source_file.startsWith("/") || args.source_file.match(/^[A-Z]:\\/)
|
|
111
|
+
? args.source_file
|
|
112
|
+
: join(root, args.source_file);
|
|
113
|
+
if (!existsSync(sourceAbsolute)) {
|
|
114
|
+
return errorResponse(new Error(`Source file not found: ${sourceAbsolute}`));
|
|
115
|
+
}
|
|
116
|
+
const content = readFileSync(sourceAbsolute, "utf-8");
|
|
117
|
+
const ext = extname(sourceAbsolute);
|
|
118
|
+
const nameWithoutExt = basename(sourceAbsolute, ext);
|
|
119
|
+
const sourceDir = dirname(sourceAbsolute);
|
|
120
|
+
if (args.framework === "flutter") {
|
|
121
|
+
const testDir = join(root, "test");
|
|
122
|
+
const relativePath = sourceAbsolute.replace(join(root, "lib"), "").replace(/\\/g, "/");
|
|
123
|
+
const testFile = join(testDir, relativePath.replace(ext, "_test.dart"));
|
|
124
|
+
if (existsSync(testFile)) {
|
|
125
|
+
return errorResponse(new Error(`Test file already exists: ${testFile}`));
|
|
126
|
+
}
|
|
127
|
+
const packageName = basename(root);
|
|
128
|
+
const importPath = `package:${packageName}${relativePath.replace(/\\/g, "/")}`;
|
|
129
|
+
mkdirSync(dirname(testFile), { recursive: true });
|
|
130
|
+
writeFileSync(testFile, generateFlutterTest(nameWithoutExt, importPath), "utf-8");
|
|
131
|
+
return textResponse(JSON.stringify({
|
|
132
|
+
success: true,
|
|
133
|
+
file_created: testFile,
|
|
134
|
+
source_file: sourceAbsolute,
|
|
135
|
+
framework: "flutter",
|
|
136
|
+
next_steps: [
|
|
137
|
+
"Replace placeholder assertions with real tests",
|
|
138
|
+
"Add testWidgets() calls for widget tests",
|
|
139
|
+
"Run: flutter test " + testFile,
|
|
140
|
+
],
|
|
141
|
+
}, null, 2));
|
|
142
|
+
}
|
|
143
|
+
const exports = extractExports(content);
|
|
144
|
+
const isComp = isComponent(content);
|
|
145
|
+
let testFile;
|
|
146
|
+
let importPath;
|
|
147
|
+
if (args.test_location === "colocated") {
|
|
148
|
+
testFile = join(sourceDir, `${nameWithoutExt}.test${ext}`);
|
|
149
|
+
importPath = `./${nameWithoutExt}`;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const testDir = join(sourceDir, "__tests__");
|
|
153
|
+
testFile = join(testDir, `${nameWithoutExt}.test${ext}`);
|
|
154
|
+
importPath = `../${nameWithoutExt}`;
|
|
155
|
+
mkdirSync(testDir, { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
if (existsSync(testFile)) {
|
|
158
|
+
return errorResponse(new Error(`Test file already exists: ${testFile}`));
|
|
159
|
+
}
|
|
160
|
+
const testContent = generateExpoTest(nameWithoutExt, exports, isComp, importPath);
|
|
161
|
+
writeFileSync(testFile, testContent, "utf-8");
|
|
162
|
+
return textResponse(JSON.stringify({
|
|
163
|
+
success: true,
|
|
164
|
+
file_created: testFile,
|
|
165
|
+
source_file: sourceAbsolute,
|
|
166
|
+
framework: "expo",
|
|
167
|
+
detected_exports: exports,
|
|
168
|
+
is_component: isComp,
|
|
169
|
+
test_location: args.test_location,
|
|
170
|
+
next_steps: [
|
|
171
|
+
"Fill in the placeholder test cases",
|
|
172
|
+
isComp
|
|
173
|
+
? "Add interaction tests with fireEvent/userEvent"
|
|
174
|
+
: "Add assertions for each exported function",
|
|
175
|
+
"Run: npx jest " + testFile,
|
|
176
|
+
],
|
|
177
|
+
}, null, 2));
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
return errorResponse(err);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=generateTestFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTestFile.js","sourceRoot":"","sources":["../../src/tools/generateTestFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runOnDevice.d.ts","sourceRoot":"","sources":["../../src/tools/runOnDevice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"runOnDevice.d.ts","sourceRoot":"","sources":["../../src/tools/runOnDevice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqGhD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { platform } from "node:os";
|
|
3
|
-
import { textResponse } from "../types.js";
|
|
3
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
4
4
|
const inputSchema = {
|
|
5
5
|
project_path: z
|
|
6
6
|
.string()
|
|
@@ -17,48 +17,53 @@ const inputSchema = {
|
|
|
17
17
|
.describe("Connection method between dev server and device"),
|
|
18
18
|
};
|
|
19
19
|
export function register(server) {
|
|
20
|
-
server.tool("mobile_runOnDevice", "
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (!targetPlatform || targetPlatform === "ios") {
|
|
41
|
-
instructions.push(`### iOS Device`, `1. Install **Expo Go** from the App Store`, `2. Open the **Camera** app on your iPhone/iPad`, `3. Point it at the QR code shown in the terminal`, `4. Tap the notification to open in Expo Go`, ``);
|
|
42
|
-
if (os !== "darwin") {
|
|
43
|
-
instructions.push(`> Note: You are not on macOS. You can test via Expo Go but cannot create native iOS builds locally. Use EAS Build for cloud-based iOS builds.`, ``);
|
|
20
|
+
server.tool("mobile_runOnDevice", "Provide step-by-step instructions for connecting a physical device to the Expo dev server via LAN, tunnel, or USB.", inputSchema, async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
const os = platform();
|
|
23
|
+
const connection = args.connection;
|
|
24
|
+
const targetPlatform = args.target_platform;
|
|
25
|
+
const startCommand = connection === "tunnel"
|
|
26
|
+
? "npx expo start --tunnel"
|
|
27
|
+
: "npx expo start";
|
|
28
|
+
const instructions = [
|
|
29
|
+
`## Run on Device`,
|
|
30
|
+
``,
|
|
31
|
+
`**Start the dev server:**`,
|
|
32
|
+
`\`\`\`bash`,
|
|
33
|
+
`cd ${args.project_path || "."}`,
|
|
34
|
+
startCommand,
|
|
35
|
+
`\`\`\``,
|
|
36
|
+
``,
|
|
37
|
+
];
|
|
38
|
+
if (connection === "tunnel") {
|
|
39
|
+
instructions.push(`**Tunnel mode** routes through Expo's servers. Slower but works across different networks and through firewalls.`, ``);
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
if (!targetPlatform || targetPlatform === "ios") {
|
|
42
|
+
instructions.push(`### iOS Device`, `1. Install **Expo Go** from the App Store`, `2. Open the **Camera** app on your iPhone/iPad`, `3. Point it at the QR code shown in the terminal`, `4. Tap the notification to open in Expo Go`, ``);
|
|
43
|
+
if (os !== "darwin") {
|
|
44
|
+
instructions.push(`> Note: You are not on macOS. You can test via Expo Go but cannot create native iOS builds locally. Use EAS Build for cloud-based iOS builds.`, ``);
|
|
45
|
+
}
|
|
50
46
|
}
|
|
47
|
+
if (!targetPlatform || targetPlatform === "android") {
|
|
48
|
+
instructions.push(`### Android Device`, `1. Install **Expo Go** from the Play Store`, `2. Open Expo Go and tap **Scan QR Code**`, `3. Scan the QR code from the terminal`, ``);
|
|
49
|
+
if (connection === "usb") {
|
|
50
|
+
instructions.push(`### USB Debugging (Android)`, `1. Enable Developer Options: Settings > About phone > tap "Build number" 7 times`, `2. Enable USB Debugging: Settings > Developer options > USB debugging`, `3. Connect USB cable`, `4. Accept "Allow USB debugging" prompt on the phone`, `5. Run: \`npx expo run:android\``, ``);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
instructions.push(`### Troubleshooting`, ``, `| Problem | Fix |`, `|---------|-----|`, `| QR code won't scan | Type the URL manually in Expo Go |`, `| "Network response timed out" | Use \`npx expo start --tunnel\` |`, `| Red error screen | Read the error. Usually a missing dependency or syntax error |`, `| Hot reload not working | Shake device > enable Fast Refresh |`, `| "Untrusted Developer" (iOS) | Settings > General > VPN & Device Management > trust certificate |`);
|
|
54
|
+
const result = {
|
|
55
|
+
start_command: startCommand,
|
|
56
|
+
project_path: args.project_path || ".",
|
|
57
|
+
connection_method: connection,
|
|
58
|
+
target_platform: targetPlatform || "both",
|
|
59
|
+
host_os: os,
|
|
60
|
+
instructions: instructions.join("\n"),
|
|
61
|
+
};
|
|
62
|
+
return textResponse(JSON.stringify(result, null, 2));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return errorResponse(err);
|
|
51
66
|
}
|
|
52
|
-
instructions.push(`### Troubleshooting`, ``, `| Problem | Fix |`, `|---------|-----|`, `| QR code won't scan | Type the URL manually in Expo Go |`, `| "Network response timed out" | Use \`npx expo start --tunnel\` |`, `| Red error screen | Read the error. Usually a missing dependency or syntax error |`, `| Hot reload not working | Shake device > enable Fast Refresh |`, `| "Untrusted Developer" (iOS) | Settings > General > VPN & Device Management > trust certificate |`);
|
|
53
|
-
const result = {
|
|
54
|
-
start_command: startCommand,
|
|
55
|
-
project_path: args.project_path || ".",
|
|
56
|
-
connection_method: connection,
|
|
57
|
-
target_platform: targetPlatform || "both",
|
|
58
|
-
host_os: os,
|
|
59
|
-
instructions: instructions.join("\n"),
|
|
60
|
-
};
|
|
61
|
-
return textResponse(JSON.stringify(result, null, 2));
|
|
62
67
|
});
|
|
63
68
|
}
|
|
64
69
|
//# sourceMappingURL=runOnDevice.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runOnDevice.js","sourceRoot":"","sources":["../../src/tools/runOnDevice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runOnDevice.js","sourceRoot":"","sources":["../../src/tools/runOnDevice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTests.d.ts","sourceRoot":"","sources":["../../src/tools/runTests.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAuFzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiHhD"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
6
|
+
const inputSchema = {
|
|
7
|
+
project_path: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
11
|
+
framework: z
|
|
12
|
+
.enum(["expo", "flutter"])
|
|
13
|
+
.optional()
|
|
14
|
+
.default("expo")
|
|
15
|
+
.describe("Project framework (default: expo). Determines which test runner to invoke."),
|
|
16
|
+
test_path: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Specific test file or directory to run. Omit to run the full suite."),
|
|
20
|
+
coverage: z
|
|
21
|
+
.boolean()
|
|
22
|
+
.optional()
|
|
23
|
+
.default(false)
|
|
24
|
+
.describe("Collect code coverage (default: false)."),
|
|
25
|
+
};
|
|
26
|
+
function parseJestJson(raw) {
|
|
27
|
+
try {
|
|
28
|
+
const result = JSON.parse(raw);
|
|
29
|
+
const summary = {
|
|
30
|
+
passed: result.numPassedTests ?? 0,
|
|
31
|
+
failed: result.numFailedTests ?? 0,
|
|
32
|
+
skipped: result.numPendingTests ?? 0,
|
|
33
|
+
total: result.numTotalTests ?? 0,
|
|
34
|
+
};
|
|
35
|
+
const failures = [];
|
|
36
|
+
for (const suite of result.testResults ?? []) {
|
|
37
|
+
for (const test of suite.assertionResults ?? []) {
|
|
38
|
+
if (test.status === "failed") {
|
|
39
|
+
const msg = (test.failureMessages ?? []).join("\n").slice(0, 500);
|
|
40
|
+
failures.push(`${test.ancestorTitles?.join(" > ")} > ${test.title}\n${msg}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { summary, failures };
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return {
|
|
48
|
+
summary: { passed: 0, failed: 0, skipped: 0, total: 0 },
|
|
49
|
+
failures: ["Could not parse Jest JSON output."],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function parseFlutterOutput(raw) {
|
|
54
|
+
const lines = raw.split("\n");
|
|
55
|
+
let passed = 0;
|
|
56
|
+
let failed = 0;
|
|
57
|
+
let skipped = 0;
|
|
58
|
+
const failures = [];
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
if (/^\+\d+/.test(line)) {
|
|
61
|
+
const passMatch = line.match(/\+(\d+)/);
|
|
62
|
+
const failMatch = line.match(/-(\d+)/);
|
|
63
|
+
const skipMatch = line.match(/~(\d+)/);
|
|
64
|
+
if (passMatch)
|
|
65
|
+
passed = parseInt(passMatch[1], 10);
|
|
66
|
+
if (failMatch)
|
|
67
|
+
failed = parseInt(failMatch[1], 10);
|
|
68
|
+
if (skipMatch)
|
|
69
|
+
skipped = parseInt(skipMatch[1], 10);
|
|
70
|
+
}
|
|
71
|
+
if (line.includes("FAILED") || line.includes("Expected:") || line.includes("Actual:")) {
|
|
72
|
+
failures.push(line.trim());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
summary: { passed, failed, skipped, total: passed + failed + skipped },
|
|
77
|
+
failures: failures.slice(0, 20),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function register(server) {
|
|
81
|
+
server.tool("mobile_runTests", "Execute the project test suite (Jest for Expo, flutter test for Flutter) and return a structured pass/fail summary with failure details.", inputSchema, async (args) => {
|
|
82
|
+
try {
|
|
83
|
+
const root = args.project_path || process.cwd();
|
|
84
|
+
if (args.framework === "flutter") {
|
|
85
|
+
const pubspecPath = join(root, "pubspec.yaml");
|
|
86
|
+
if (!existsSync(pubspecPath)) {
|
|
87
|
+
return errorResponse(new Error(`No pubspec.yaml at ${root}. Is this a Flutter project?`));
|
|
88
|
+
}
|
|
89
|
+
const cmd = ["flutter", "test"];
|
|
90
|
+
if (args.test_path)
|
|
91
|
+
cmd.push(args.test_path);
|
|
92
|
+
if (args.coverage)
|
|
93
|
+
cmd.push("--coverage");
|
|
94
|
+
let output;
|
|
95
|
+
let exitCode = 0;
|
|
96
|
+
try {
|
|
97
|
+
output = execSync(cmd.join(" "), { cwd: root, encoding: "utf-8", timeout: 300_000 });
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
output = err.stdout || err.message;
|
|
101
|
+
exitCode = err.status ?? 1;
|
|
102
|
+
}
|
|
103
|
+
const { summary, failures } = parseFlutterOutput(output);
|
|
104
|
+
return textResponse(JSON.stringify({
|
|
105
|
+
success: exitCode === 0,
|
|
106
|
+
framework: "flutter",
|
|
107
|
+
summary,
|
|
108
|
+
failures: failures.length > 0 ? failures : undefined,
|
|
109
|
+
coverage_collected: args.coverage,
|
|
110
|
+
raw_output_tail: output.split("\n").slice(-15).join("\n"),
|
|
111
|
+
}, null, 2));
|
|
112
|
+
}
|
|
113
|
+
const pkgPath = join(root, "package.json");
|
|
114
|
+
if (!existsSync(pkgPath)) {
|
|
115
|
+
return errorResponse(new Error(`No package.json at ${root}. Is this a Node.js project?`));
|
|
116
|
+
}
|
|
117
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
118
|
+
const hasJest = pkg.devDependencies?.jest ||
|
|
119
|
+
pkg.dependencies?.jest ||
|
|
120
|
+
pkg.devDependencies?.["@jest/core"];
|
|
121
|
+
if (!hasJest) {
|
|
122
|
+
return textResponse(JSON.stringify({
|
|
123
|
+
success: false,
|
|
124
|
+
message: "Jest is not installed. Run: npx expo install jest @testing-library/react-native",
|
|
125
|
+
next_steps: [
|
|
126
|
+
"Install Jest: npx expo install jest jest-expo @testing-library/react-native",
|
|
127
|
+
'Add to package.json: "jest": { "preset": "jest-expo" }',
|
|
128
|
+
"Create your first test in __tests__/",
|
|
129
|
+
],
|
|
130
|
+
}, null, 2));
|
|
131
|
+
}
|
|
132
|
+
const cmd = ["npx", "jest", "--json"];
|
|
133
|
+
if (args.test_path)
|
|
134
|
+
cmd.push(args.test_path);
|
|
135
|
+
if (args.coverage)
|
|
136
|
+
cmd.push("--coverage");
|
|
137
|
+
let output;
|
|
138
|
+
let exitCode = 0;
|
|
139
|
+
try {
|
|
140
|
+
output = execSync(cmd.join(" "), { cwd: root, encoding: "utf-8", timeout: 300_000 });
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
output = err.stdout || err.message;
|
|
144
|
+
exitCode = err.status ?? 1;
|
|
145
|
+
}
|
|
146
|
+
const jsonStart = output.indexOf("{");
|
|
147
|
+
const jsonStr = jsonStart >= 0 ? output.slice(jsonStart) : output;
|
|
148
|
+
const { summary, failures } = parseJestJson(jsonStr);
|
|
149
|
+
return textResponse(JSON.stringify({
|
|
150
|
+
success: exitCode === 0,
|
|
151
|
+
framework: "expo",
|
|
152
|
+
summary,
|
|
153
|
+
failures: failures.length > 0 ? failures : undefined,
|
|
154
|
+
coverage_collected: args.coverage,
|
|
155
|
+
next_steps: exitCode !== 0
|
|
156
|
+
? ["Fix the failing tests above", "Run again with mobile_runTests"]
|
|
157
|
+
: ["All tests passed"],
|
|
158
|
+
}, null, 2));
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
return errorResponse(err);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=runTests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTests.js","sourceRoot":"","sources":["../../src/tools/runTests.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ const inputSchema = {
|
|
|
16
16
|
.describe("Parent directory to create the project in (defaults to current directory)"),
|
|
17
17
|
};
|
|
18
18
|
export function register(server) {
|
|
19
|
-
server.tool("mobile_scaffoldProject", "Generate a new Expo project with
|
|
19
|
+
server.tool("mobile_scaffoldProject", "Generate a new Expo project using create-expo-app with the default or specified template.", inputSchema, async (args) => {
|
|
20
20
|
try {
|
|
21
21
|
const cwd = args.directory || process.cwd();
|
|
22
22
|
const templateArg = args.template === "blank"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffoldProject.js","sourceRoot":"","sources":["../../src/tools/scaffoldProject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,6DAA6D,CAAC;IAC1E,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;SAClC,QAAQ,EAAE;SACV,OAAO,CAAC,SAAS,CAAC;SAClB,QAAQ,CAAC,sBAAsB,CAAC;IACnC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,2EAA2E,CAAC;CACzF,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,
|
|
1
|
+
{"version":3,"file":"scaffoldProject.js","sourceRoot":"","sources":["../../src/tools/scaffoldProject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,6DAA6D,CAAC;IAC1E,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;SAClC,QAAQ,EAAE;SACV,OAAO,CAAC,SAAS,CAAC;SAClB,QAAQ,CAAC,sBAAsB,CAAC;IACnC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,2EAA2E,CAAC;CACzF,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,2FAA2F,EAC3F,WAAW,EACX,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAC5C,MAAM,WAAW,GACf,IAAI,CAAC,QAAQ,KAAK,OAAO;gBACvB,CAAC,CAAC,kBAAkB;gBACpB,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM;oBACxB,CAAC,CAAC,iBAAiB;oBACnB,CAAC,CAAC,EAAE,CAAC;YAEX,MAAM,OAAO,GAAG,8BAA8B,IAAI,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;YAEhF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;gBAC/B,GAAG;gBACH,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,MAAM;gBACf,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,IAAI,CAAC,IAAI;gBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE;gBAC3B,YAAY,EAAE,OAAO;gBACrB,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;gBACrB,UAAU,EAAE;oBACV,MAAM,IAAI,CAAC,IAAI,EAAE;oBACjB,gBAAgB;oBAChB,uEAAuE;iBACxE;aACF,CAAC;YAEF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupCI.d.ts","sourceRoot":"","sources":["../../src/tools/setupCI.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqKzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiEhD"}
|