@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,337 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const fieldSchema = z.object({
|
|
6
|
+
name: z.string().describe("Field name in camelCase (e.g. 'email', 'firstName')."),
|
|
7
|
+
type: z
|
|
8
|
+
.enum(["text", "email", "password", "number", "phone", "textarea", "select"])
|
|
9
|
+
.describe("Field input type."),
|
|
10
|
+
label: z.string().describe("Display label for the field."),
|
|
11
|
+
required: z.boolean().optional().default(true).describe("Whether the field is required."),
|
|
12
|
+
placeholder: z.string().optional().describe("Placeholder text."),
|
|
13
|
+
});
|
|
14
|
+
const inputSchema = {
|
|
15
|
+
form_name: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("Form component name in PascalCase (e.g. 'LoginForm', 'ContactForm')."),
|
|
18
|
+
fields: z
|
|
19
|
+
.array(fieldSchema)
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe("Array of field definitions."),
|
|
22
|
+
project_path: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
26
|
+
framework: z
|
|
27
|
+
.enum(["expo", "flutter"])
|
|
28
|
+
.optional()
|
|
29
|
+
.default("expo")
|
|
30
|
+
.describe("Project framework (default: expo)."),
|
|
31
|
+
output_directory: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.default("components")
|
|
35
|
+
.describe("Output directory relative to project root (default: components)."),
|
|
36
|
+
};
|
|
37
|
+
function zodValidation(field) {
|
|
38
|
+
let chain = "z.string()";
|
|
39
|
+
if (field.required)
|
|
40
|
+
chain += '.min(1, "Required")';
|
|
41
|
+
if (field.type === "email")
|
|
42
|
+
chain += '.email("Invalid email")';
|
|
43
|
+
if (field.type === "number")
|
|
44
|
+
chain = "z.coerce.number()";
|
|
45
|
+
if (field.type === "phone")
|
|
46
|
+
chain += '.regex(/^\\+?[0-9\\s-()]+$/, "Invalid phone number")';
|
|
47
|
+
if (field.type === "password")
|
|
48
|
+
chain += '.min(8, "At least 8 characters")';
|
|
49
|
+
return chain;
|
|
50
|
+
}
|
|
51
|
+
function rnInputType(type) {
|
|
52
|
+
switch (type) {
|
|
53
|
+
case "email": return "email-address";
|
|
54
|
+
case "number": return "numeric";
|
|
55
|
+
case "phone": return "phone-pad";
|
|
56
|
+
default: return "default";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function generateExpoForm(name, fields) {
|
|
60
|
+
const schemaFields = fields
|
|
61
|
+
.map((f) => ` ${f.name}: ${zodValidation(f)},`)
|
|
62
|
+
.join("\n");
|
|
63
|
+
const formFields = fields
|
|
64
|
+
.map((f) => {
|
|
65
|
+
const secureEntry = f.type === "password" ? "\n secureTextEntry" : "";
|
|
66
|
+
const multiline = f.type === "textarea" ? "\n multiline\n numberOfLines={4}" : "";
|
|
67
|
+
const keyboard = f.type !== "text" && f.type !== "password" && f.type !== "textarea" && f.type !== "select"
|
|
68
|
+
? `\n keyboardType="${rnInputType(f.type)}"`
|
|
69
|
+
: "";
|
|
70
|
+
return ` <View style={styles.field}>
|
|
71
|
+
<Text style={styles.label}>${f.label}</Text>
|
|
72
|
+
<Controller
|
|
73
|
+
control={control}
|
|
74
|
+
name="${f.name}"
|
|
75
|
+
render={({ field: { onChange, onBlur, value } }) => (
|
|
76
|
+
<TextInput
|
|
77
|
+
style={[styles.input, errors.${f.name} && styles.inputError]}
|
|
78
|
+
onBlur={onBlur}
|
|
79
|
+
onChangeText={onChange}
|
|
80
|
+
value={value}
|
|
81
|
+
placeholder="${f.placeholder || f.label}"${secureEntry}${multiline}${keyboard}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
/>
|
|
85
|
+
{errors.${f.name} && (
|
|
86
|
+
<Text style={styles.error}>{errors.${f.name}?.message}</Text>
|
|
87
|
+
)}
|
|
88
|
+
</View>`;
|
|
89
|
+
})
|
|
90
|
+
.join("\n\n");
|
|
91
|
+
const defaultValues = fields
|
|
92
|
+
.map((f) => ` ${f.name}: "",`)
|
|
93
|
+
.join("\n");
|
|
94
|
+
return `import { View, Text, TextInput, Pressable, StyleSheet } from "react-native";
|
|
95
|
+
import { useForm, Controller } from "react-hook-form";
|
|
96
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
97
|
+
import { z } from "zod";
|
|
98
|
+
|
|
99
|
+
const schema = z.object({
|
|
100
|
+
${schemaFields}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
type FormData = z.infer<typeof schema>;
|
|
104
|
+
|
|
105
|
+
interface ${name}Props {
|
|
106
|
+
onSubmit: (data: FormData) => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function ${name}({ onSubmit }: ${name}Props) {
|
|
110
|
+
const {
|
|
111
|
+
control,
|
|
112
|
+
handleSubmit,
|
|
113
|
+
formState: { errors, isSubmitting },
|
|
114
|
+
} = useForm<FormData>({
|
|
115
|
+
resolver: zodResolver(schema),
|
|
116
|
+
defaultValues: {
|
|
117
|
+
${defaultValues}
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<View style={styles.container}>
|
|
123
|
+
${formFields}
|
|
124
|
+
|
|
125
|
+
<Pressable
|
|
126
|
+
style={[styles.button, isSubmitting && styles.buttonDisabled]}
|
|
127
|
+
onPress={handleSubmit(onSubmit)}
|
|
128
|
+
disabled={isSubmitting}
|
|
129
|
+
>
|
|
130
|
+
<Text style={styles.buttonText}>
|
|
131
|
+
{isSubmitting ? "Submitting..." : "Submit"}
|
|
132
|
+
</Text>
|
|
133
|
+
</Pressable>
|
|
134
|
+
</View>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const styles = StyleSheet.create({
|
|
139
|
+
container: {
|
|
140
|
+
padding: 16,
|
|
141
|
+
gap: 12,
|
|
142
|
+
},
|
|
143
|
+
field: {
|
|
144
|
+
gap: 4,
|
|
145
|
+
},
|
|
146
|
+
label: {
|
|
147
|
+
fontSize: 14,
|
|
148
|
+
fontWeight: "600",
|
|
149
|
+
},
|
|
150
|
+
input: {
|
|
151
|
+
borderWidth: 1,
|
|
152
|
+
borderColor: "#ccc",
|
|
153
|
+
borderRadius: 8,
|
|
154
|
+
padding: 12,
|
|
155
|
+
fontSize: 16,
|
|
156
|
+
},
|
|
157
|
+
inputError: {
|
|
158
|
+
borderColor: "#dc2626",
|
|
159
|
+
},
|
|
160
|
+
error: {
|
|
161
|
+
color: "#dc2626",
|
|
162
|
+
fontSize: 12,
|
|
163
|
+
},
|
|
164
|
+
button: {
|
|
165
|
+
backgroundColor: "#0A84FF",
|
|
166
|
+
padding: 16,
|
|
167
|
+
borderRadius: 8,
|
|
168
|
+
alignItems: "center",
|
|
169
|
+
marginTop: 8,
|
|
170
|
+
},
|
|
171
|
+
buttonDisabled: {
|
|
172
|
+
opacity: 0.6,
|
|
173
|
+
},
|
|
174
|
+
buttonText: {
|
|
175
|
+
color: "#fff",
|
|
176
|
+
fontSize: 16,
|
|
177
|
+
fontWeight: "600",
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
function generateFlutterForm(name, fields) {
|
|
183
|
+
const className = name.charAt(0).toUpperCase() + name.slice(1);
|
|
184
|
+
const controllers = fields
|
|
185
|
+
.map((f) => ` final _${f.name}Controller = TextEditingController();`)
|
|
186
|
+
.join("\n");
|
|
187
|
+
const disposeControllers = fields
|
|
188
|
+
.map((f) => ` _${f.name}Controller.dispose();`)
|
|
189
|
+
.join("\n");
|
|
190
|
+
const formFields = fields
|
|
191
|
+
.map((f) => {
|
|
192
|
+
const obscure = f.type === "password" ? "\n obscureText: true," : "";
|
|
193
|
+
const maxLines = f.type === "textarea" ? "\n maxLines: 4," : "";
|
|
194
|
+
const keyboard = f.type === "email"
|
|
195
|
+
? "\n keyboardType: TextInputType.emailAddress,"
|
|
196
|
+
: f.type === "number"
|
|
197
|
+
? "\n keyboardType: TextInputType.number,"
|
|
198
|
+
: f.type === "phone"
|
|
199
|
+
? "\n keyboardType: TextInputType.phone,"
|
|
200
|
+
: "";
|
|
201
|
+
const validator = f.required
|
|
202
|
+
? `\n validator: (value) {\n if (value == null || value.isEmpty) return '${f.label} is required';\n return null;\n },`
|
|
203
|
+
: "";
|
|
204
|
+
return ` TextFormField(
|
|
205
|
+
controller: _${f.name}Controller,
|
|
206
|
+
decoration: const InputDecoration(
|
|
207
|
+
labelText: '${f.label}',
|
|
208
|
+
hintText: '${f.placeholder || f.label}',
|
|
209
|
+
),${obscure}${maxLines}${keyboard}${validator}
|
|
210
|
+
),
|
|
211
|
+
const SizedBox(height: 16),`;
|
|
212
|
+
})
|
|
213
|
+
.join("\n");
|
|
214
|
+
return `import 'package:flutter/material.dart';
|
|
215
|
+
|
|
216
|
+
class ${className} extends StatefulWidget {
|
|
217
|
+
final void Function(Map<String, String> data) onSubmit;
|
|
218
|
+
|
|
219
|
+
const ${className}({super.key, required this.onSubmit});
|
|
220
|
+
|
|
221
|
+
@override
|
|
222
|
+
State<${className}> createState() => _${className}State();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
class _${className}State extends State<${className}> {
|
|
226
|
+
final _formKey = GlobalKey<FormState>();
|
|
227
|
+
bool _isSubmitting = false;
|
|
228
|
+
|
|
229
|
+
${controllers}
|
|
230
|
+
|
|
231
|
+
@override
|
|
232
|
+
void dispose() {
|
|
233
|
+
${disposeControllers}
|
|
234
|
+
super.dispose();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Future<void> _handleSubmit() async {
|
|
238
|
+
if (!_formKey.currentState!.validate()) return;
|
|
239
|
+
|
|
240
|
+
setState(() => _isSubmitting = true);
|
|
241
|
+
try {
|
|
242
|
+
widget.onSubmit({
|
|
243
|
+
${fields.map((f) => ` '${f.name}': _${f.name}Controller.text,`).join("\n")}
|
|
244
|
+
});
|
|
245
|
+
} finally {
|
|
246
|
+
if (mounted) setState(() => _isSubmitting = false);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@override
|
|
251
|
+
Widget build(BuildContext context) {
|
|
252
|
+
return Form(
|
|
253
|
+
key: _formKey,
|
|
254
|
+
child: Padding(
|
|
255
|
+
padding: const EdgeInsets.all(16),
|
|
256
|
+
child: Column(
|
|
257
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
258
|
+
children: [
|
|
259
|
+
${formFields}
|
|
260
|
+
ElevatedButton(
|
|
261
|
+
onPressed: _isSubmitting ? null : _handleSubmit,
|
|
262
|
+
child: Text(_isSubmitting ? 'Submitting...' : 'Submit'),
|
|
263
|
+
),
|
|
264
|
+
],
|
|
265
|
+
),
|
|
266
|
+
),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
export function register(server) {
|
|
273
|
+
server.tool("mobile_generateForm", "Scaffold a validated form component with typed fields, validation rules, and error handling. Uses React Hook Form + Zod for Expo or Form + TextFormField for Flutter.", inputSchema, async (args) => {
|
|
274
|
+
try {
|
|
275
|
+
const root = args.project_path || process.cwd();
|
|
276
|
+
const outDir = join(root, args.output_directory);
|
|
277
|
+
mkdirSync(outDir, { recursive: true });
|
|
278
|
+
const fields = args.fields.map((f) => ({
|
|
279
|
+
name: f.name,
|
|
280
|
+
type: f.type,
|
|
281
|
+
label: f.label,
|
|
282
|
+
required: f.required,
|
|
283
|
+
placeholder: f.placeholder,
|
|
284
|
+
}));
|
|
285
|
+
if (args.framework === "flutter") {
|
|
286
|
+
const fileName = args.form_name
|
|
287
|
+
.replace(/([A-Z])/g, "_$1")
|
|
288
|
+
.toLowerCase()
|
|
289
|
+
.replace(/^_/, "");
|
|
290
|
+
const filePath = join(outDir, `${fileName}.dart`);
|
|
291
|
+
if (existsSync(filePath)) {
|
|
292
|
+
return errorResponse(new Error(`File already exists: ${filePath}`));
|
|
293
|
+
}
|
|
294
|
+
writeFileSync(filePath, generateFlutterForm(args.form_name, fields), "utf-8");
|
|
295
|
+
return textResponse(JSON.stringify({
|
|
296
|
+
success: true,
|
|
297
|
+
framework: "flutter",
|
|
298
|
+
file_created: filePath,
|
|
299
|
+
form_name: args.form_name,
|
|
300
|
+
fields: fields.map((f) => f.name),
|
|
301
|
+
next_steps: [
|
|
302
|
+
"Import and use the form widget in your screen",
|
|
303
|
+
"Add email/phone validators if needed",
|
|
304
|
+
"Add keyboard avoidance with SingleChildScrollView",
|
|
305
|
+
],
|
|
306
|
+
}, null, 2));
|
|
307
|
+
}
|
|
308
|
+
const filePath = join(outDir, `${args.form_name}.tsx`);
|
|
309
|
+
if (existsSync(filePath)) {
|
|
310
|
+
return errorResponse(new Error(`File already exists: ${filePath}`));
|
|
311
|
+
}
|
|
312
|
+
writeFileSync(filePath, generateExpoForm(args.form_name, fields), "utf-8");
|
|
313
|
+
return textResponse(JSON.stringify({
|
|
314
|
+
success: true,
|
|
315
|
+
framework: "expo",
|
|
316
|
+
file_created: filePath,
|
|
317
|
+
form_name: args.form_name,
|
|
318
|
+
fields: fields.map((f) => f.name),
|
|
319
|
+
dependencies_needed: [
|
|
320
|
+
"react-hook-form",
|
|
321
|
+
"@hookform/resolvers",
|
|
322
|
+
"zod",
|
|
323
|
+
],
|
|
324
|
+
next_steps: [
|
|
325
|
+
"Install dependencies: npx expo install react-hook-form @hookform/resolvers zod",
|
|
326
|
+
"Import and render the form in your screen",
|
|
327
|
+
"Implement the onSubmit handler with your API call",
|
|
328
|
+
"Add KeyboardAvoidingView wrapper if fields are below the fold",
|
|
329
|
+
],
|
|
330
|
+
}, null, 2));
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return errorResponse(err);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=generateForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateForm.js","sourceRoot":"","sources":["../../src/tools/generateForm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateScreenshots.d.ts","sourceRoot":"","sources":["../../src/tools/generateScreenshots.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4EzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8EhD"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const IOS_DEVICES = [
|
|
6
|
+
{ name: '6.7" Display', width: 1290, height: 2796, label: "iPhone 15 Pro Max / 16 Pro Max" },
|
|
7
|
+
{ name: '6.5" Display', width: 1284, height: 2778, label: "iPhone 14 Plus / 15 Plus" },
|
|
8
|
+
{ name: '5.5" Display', width: 1242, height: 2208, label: "iPhone 8 Plus (legacy)" },
|
|
9
|
+
{ name: '12.9" iPad Pro', width: 2048, height: 2732, label: "iPad Pro 12.9-inch" },
|
|
10
|
+
];
|
|
11
|
+
const ANDROID_DEVICES = [
|
|
12
|
+
{ name: "Phone", width: 1080, height: 1920, label: "Standard phone (1080x1920)" },
|
|
13
|
+
{ name: "Phone Hi-Res", width: 1440, height: 3120, label: "Flagship phone (1440x3120)" },
|
|
14
|
+
{ name: '7" Tablet', width: 1200, height: 1920, label: "7-inch tablet" },
|
|
15
|
+
{ name: '10" Tablet', width: 1600, height: 2560, label: "10-inch tablet" },
|
|
16
|
+
];
|
|
17
|
+
const HELPER_SCRIPT = `#!/usr/bin/env node
|
|
18
|
+
/**
|
|
19
|
+
* Screenshot helper - captures screenshots at store-required dimensions.
|
|
20
|
+
* Run from your project root with a running dev server.
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* node scripts/capture-screenshots.js --platform ios
|
|
24
|
+
* node scripts/capture-screenshots.js --platform android
|
|
25
|
+
*
|
|
26
|
+
* Prerequisites:
|
|
27
|
+
* - Simulator/emulator running with your app loaded
|
|
28
|
+
* - For iOS: Xcode command line tools (xcrun simctl)
|
|
29
|
+
* - For Android: adb in PATH
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const { execSync } = require("child_process");
|
|
33
|
+
const { mkdirSync, existsSync } = require("fs");
|
|
34
|
+
const path = require("path");
|
|
35
|
+
|
|
36
|
+
const platform = process.argv.includes("--android") ? "android" : "ios";
|
|
37
|
+
const outDir = path.join("screenshots", platform);
|
|
38
|
+
|
|
39
|
+
if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
|
|
40
|
+
|
|
41
|
+
if (platform === "ios") {
|
|
42
|
+
const timestamp = Date.now();
|
|
43
|
+
const file = path.join(outDir, \`screenshot_\${timestamp}.png\`);
|
|
44
|
+
try {
|
|
45
|
+
execSync(\`xcrun simctl io booted screenshot "\${file}"\`, { stdio: "pipe" });
|
|
46
|
+
console.log("Saved:", file);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error("Failed. Is the iOS Simulator running?");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
const timestamp = Date.now();
|
|
53
|
+
const file = path.join(outDir, \`screenshot_\${timestamp}.png\`);
|
|
54
|
+
try {
|
|
55
|
+
execSync(\`adb exec-out screencap -p > "\${file}"\`, { stdio: "pipe", shell: true });
|
|
56
|
+
console.log("Saved:", file);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error("Failed. Is an Android device/emulator connected?");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
const inputSchema = {
|
|
64
|
+
project_path: z
|
|
65
|
+
.string()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Absolute path to the Expo project root. Defaults to cwd."),
|
|
68
|
+
platform: z
|
|
69
|
+
.enum(["ios", "android", "both"])
|
|
70
|
+
.optional()
|
|
71
|
+
.default("both")
|
|
72
|
+
.describe("Target platform for screenshot dimensions (default: both)"),
|
|
73
|
+
};
|
|
74
|
+
export function register(server) {
|
|
75
|
+
server.tool("mobile_generateScreenshots", "Generate a screenshot capture helper script and list required App Store and Play Store screenshot dimensions. Creates scripts/capture-screenshots.js.", inputSchema, async (args) => {
|
|
76
|
+
try {
|
|
77
|
+
const root = args.project_path || process.cwd();
|
|
78
|
+
const scriptsDir = join(root, "scripts");
|
|
79
|
+
if (!existsSync(scriptsDir)) {
|
|
80
|
+
mkdirSync(scriptsDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
const scriptPath = join(scriptsDir, "capture-screenshots.js");
|
|
83
|
+
writeFileSync(scriptPath, HELPER_SCRIPT, "utf-8");
|
|
84
|
+
const devices = [];
|
|
85
|
+
if (args.platform === "ios" || args.platform === "both") {
|
|
86
|
+
devices.push(...IOS_DEVICES.map((d) => ({ platform: "ios", ...d })));
|
|
87
|
+
}
|
|
88
|
+
if (args.platform === "android" || args.platform === "both") {
|
|
89
|
+
devices.push(...ANDROID_DEVICES.map((d) => ({ platform: "android", ...d })));
|
|
90
|
+
}
|
|
91
|
+
return textResponse(JSON.stringify({
|
|
92
|
+
success: true,
|
|
93
|
+
message: "Screenshot helper script created and dimension reference generated",
|
|
94
|
+
script: "scripts/capture-screenshots.js",
|
|
95
|
+
usage: [
|
|
96
|
+
"node scripts/capture-screenshots.js --ios",
|
|
97
|
+
"node scripts/capture-screenshots.js --android",
|
|
98
|
+
],
|
|
99
|
+
required_dimensions: devices,
|
|
100
|
+
guidelines: {
|
|
101
|
+
ios: [
|
|
102
|
+
"Minimum 3 screenshots, maximum 10 per device size",
|
|
103
|
+
"6.7-inch and 6.5-inch displays are required for current iPhones",
|
|
104
|
+
"5.5-inch is required if supporting older iPhones",
|
|
105
|
+
"No device frames, status bars, or alpha transparency",
|
|
106
|
+
"PNG or JPEG, RGB color space",
|
|
107
|
+
],
|
|
108
|
+
android: [
|
|
109
|
+
"Minimum 2 screenshots, maximum 8",
|
|
110
|
+
"JPEG or 24-bit PNG, minimum 320px, maximum 3840px per side",
|
|
111
|
+
"16:9 aspect ratio recommended for phones",
|
|
112
|
+
"At least one phone and one 7-inch or 10-inch tablet screenshot",
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
next_steps: [
|
|
116
|
+
"Navigate to each key screen in your app",
|
|
117
|
+
"Run the capture script for each screen",
|
|
118
|
+
"Resize captures to required dimensions if needed",
|
|
119
|
+
"Upload to App Store Connect / Play Console",
|
|
120
|
+
],
|
|
121
|
+
}, null, 2));
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
return errorResponse(err);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=generateScreenshots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateScreenshots.js","sourceRoot":"","sources":["../../src/tools/generateScreenshots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTestFile.d.ts","sourceRoot":"","sources":["../../src/tools/generateTestFile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwHzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyGhD"}
|