@tmhs/mobile-mcp 0.9.0 → 0.11.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 +15 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/auditAccessibility.d.ts +3 -0
- package/dist/tools/auditAccessibility.d.ts.map +1 -0
- package/dist/tools/auditAccessibility.js +236 -0
- package/dist/tools/auditAccessibility.js.map +1 -0
- package/dist/tools/checkOfflineReady.d.ts +3 -0
- package/dist/tools/checkOfflineReady.d.ts.map +1 -0
- package/dist/tools/checkOfflineReady.js +190 -0
- package/dist/tools/checkOfflineReady.js.map +1 -0
- package/dist/tools/profilePerformance.d.ts +3 -0
- package/dist/tools/profilePerformance.d.ts.map +1 -0
- package/dist/tools/profilePerformance.js +222 -0
- package/dist/tools/profilePerformance.js.map +1 -0
- package/dist/tools/securityAudit.d.ts +3 -0
- package/dist/tools/securityAudit.d.ts.map +1 -0
- package/dist/tools/securityAudit.js +213 -0
- package/dist/tools/securityAudit.js.map +1 -0
- package/dist/tools/setupFeatureFlags.d.ts +3 -0
- package/dist/tools/setupFeatureFlags.d.ts.map +1 -0
- package/dist/tools/setupFeatureFlags.js +266 -0
- package/dist/tools/setupFeatureFlags.js.map +1 -0
- package/dist/tools/setupMonitoring.d.ts +3 -0
- package/dist/tools/setupMonitoring.d.ts.map +1 -0
- package/dist/tools/setupMonitoring.js +250 -0
- package/dist/tools/setupMonitoring.js.map +1 -0
- package/dist/tools/setupTheming.d.ts +3 -0
- package/dist/tools/setupTheming.d.ts.map +1 -0
- package/dist/tools/setupTheming.js +303 -0
- package/dist/tools/setupTheming.js.map +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -27,9 +27,16 @@ import { register as registerSetupI18n } from "./tools/setupI18n.js";
|
|
|
27
27
|
import { register as registerAddMap } from "./tools/addMap.js";
|
|
28
28
|
import { register as registerGenerateForm } from "./tools/generateForm.js";
|
|
29
29
|
import { register as registerSetupRealtime } from "./tools/setupRealtime.js";
|
|
30
|
+
import { register as registerSecurityAudit } from "./tools/securityAudit.js";
|
|
31
|
+
import { register as registerProfilePerformance } from "./tools/profilePerformance.js";
|
|
32
|
+
import { register as registerCheckOfflineReady } from "./tools/checkOfflineReady.js";
|
|
33
|
+
import { register as registerSetupMonitoring } from "./tools/setupMonitoring.js";
|
|
34
|
+
import { register as registerSetupTheming } from "./tools/setupTheming.js";
|
|
35
|
+
import { register as registerAuditAccessibility } from "./tools/auditAccessibility.js";
|
|
36
|
+
import { register as registerSetupFeatureFlags } from "./tools/setupFeatureFlags.js";
|
|
30
37
|
const server = new McpServer({
|
|
31
38
|
name: "mobile-mcp",
|
|
32
|
-
version: "0.
|
|
39
|
+
version: "0.11.0",
|
|
33
40
|
});
|
|
34
41
|
registerCheckDevEnvironment(server);
|
|
35
42
|
registerScaffoldProject(server);
|
|
@@ -57,6 +64,13 @@ registerSetupI18n(server);
|
|
|
57
64
|
registerAddMap(server);
|
|
58
65
|
registerGenerateForm(server);
|
|
59
66
|
registerSetupRealtime(server);
|
|
67
|
+
registerSecurityAudit(server);
|
|
68
|
+
registerProfilePerformance(server);
|
|
69
|
+
registerCheckOfflineReady(server);
|
|
70
|
+
registerSetupMonitoring(server);
|
|
71
|
+
registerSetupTheming(server);
|
|
72
|
+
registerAuditAccessibility(server);
|
|
73
|
+
registerSetupFeatureFlags(server);
|
|
60
74
|
async function main() {
|
|
61
75
|
const transport = new StdioServerTransport();
|
|
62
76
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,QAAQ,IAAI,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAE,QAAQ,IAAI,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,QAAQ,IAAI,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,QAAQ,IAAI,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,QAAQ,IAAI,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,QAAQ,IAAI,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,QAAQ,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,QAAQ,IAAI,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,QAAQ,IAAI,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,QAAQ,IAAI,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAC3F,OAAO,EAAE,QAAQ,IAAI,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,QAAQ,IAAI,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAE,QAAQ,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,QAAQ,IAAI,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAAE,QAAQ,IAAI,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,QAAQ,IAAI,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,QAAQ,IAAI,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAE,QAAQ,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,QAAQ,IAAI,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,QAAQ,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditAccessibility.d.ts","sourceRoot":"","sources":["../../src/tools/auditAccessibility.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsNzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2ChD"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { join, extname } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
project_path: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
10
|
+
framework: z
|
|
11
|
+
.enum(["expo", "flutter"])
|
|
12
|
+
.optional()
|
|
13
|
+
.default("expo")
|
|
14
|
+
.describe("Framework to audit (default: expo)."),
|
|
15
|
+
};
|
|
16
|
+
function collectFiles(dir, extensions, maxDepth = 5, depth = 0) {
|
|
17
|
+
if (depth >= maxDepth || !existsSync(dir))
|
|
18
|
+
return [];
|
|
19
|
+
const results = [];
|
|
20
|
+
try {
|
|
21
|
+
for (const entry of readdirSync(dir)) {
|
|
22
|
+
if (entry.startsWith(".") || entry === "node_modules" || entry === "build" || entry === ".dart_tool")
|
|
23
|
+
continue;
|
|
24
|
+
const full = join(dir, entry);
|
|
25
|
+
try {
|
|
26
|
+
const stat = statSync(full);
|
|
27
|
+
if (stat.isDirectory()) {
|
|
28
|
+
results.push(...collectFiles(full, extensions, maxDepth, depth + 1));
|
|
29
|
+
}
|
|
30
|
+
else if (extensions.includes(extname(entry))) {
|
|
31
|
+
results.push(full);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch { /* skip */ }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch { /* skip */ }
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
function auditExpo(root) {
|
|
41
|
+
const violations = [];
|
|
42
|
+
const srcDir = existsSync(join(root, "src")) ? join(root, "src") : join(root, "app");
|
|
43
|
+
const files = collectFiles(srcDir, [".tsx", ".jsx"]);
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
let content;
|
|
46
|
+
try {
|
|
47
|
+
content = readFileSync(file, "utf-8");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const rel = file.replace(root, "").replace(/\\/g, "/");
|
|
53
|
+
const touchableRegex = /<(TouchableOpacity|TouchableHighlight|Pressable|TouchableWithoutFeedback)\b/g;
|
|
54
|
+
let match;
|
|
55
|
+
while ((match = touchableRegex.exec(content)) !== null) {
|
|
56
|
+
const afterTag = content.slice(match.index, match.index + 300);
|
|
57
|
+
if (!afterTag.includes("accessibilityLabel") && !afterTag.includes("aria-label") && !afterTag.includes("accessible={false}")) {
|
|
58
|
+
violations.push({
|
|
59
|
+
severity: "critical",
|
|
60
|
+
wcag: "1.1.1 Non-text Content",
|
|
61
|
+
message: `<${match[1]}> without accessibilityLabel. Screen readers cannot describe this control.`,
|
|
62
|
+
fix: `Add accessibilityLabel="descriptive text" to the <${match[1]}>.`,
|
|
63
|
+
file: rel,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (!afterTag.includes("accessibilityRole") && !afterTag.includes("role=")) {
|
|
67
|
+
violations.push({
|
|
68
|
+
severity: "serious",
|
|
69
|
+
wcag: "4.1.2 Name, Role, Value",
|
|
70
|
+
message: `<${match[1]}> without accessibilityRole. Screen readers do not know this is a button.`,
|
|
71
|
+
fix: `Add accessibilityRole="button" (or "link", "tab", etc.).`,
|
|
72
|
+
file: rel,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const imageRegex = /<Image\b/g;
|
|
77
|
+
while ((match = imageRegex.exec(content)) !== null) {
|
|
78
|
+
const afterTag = content.slice(match.index, match.index + 300);
|
|
79
|
+
if (!afterTag.includes("accessibilityLabel") && !afterTag.includes("aria-label") && !afterTag.includes("accessible={false}")) {
|
|
80
|
+
violations.push({
|
|
81
|
+
severity: "serious",
|
|
82
|
+
wcag: "1.1.1 Non-text Content",
|
|
83
|
+
message: "<Image> without accessibilityLabel. Decorative images should set accessible={false}.",
|
|
84
|
+
fix: "Add accessibilityLabel describing the image, or accessible={false} for decorative images.",
|
|
85
|
+
file: rel,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const smallSizeRegex = /(?:width|height|minWidth|minHeight)\s*:\s*(\d+)/g;
|
|
90
|
+
while ((match = smallSizeRegex.exec(content)) !== null) {
|
|
91
|
+
const size = parseInt(match[1], 10);
|
|
92
|
+
if (size > 0 && size < 44) {
|
|
93
|
+
const context = content.slice(Math.max(0, match.index - 100), match.index + 50);
|
|
94
|
+
if (/Touchable|Pressable|Button|onPress/i.test(context)) {
|
|
95
|
+
violations.push({
|
|
96
|
+
severity: "serious",
|
|
97
|
+
wcag: "2.5.5 Target Size",
|
|
98
|
+
message: `Touch target size ${size}px is below the 44px minimum. Difficult for users with motor impairments.`,
|
|
99
|
+
fix: "Set minimum width and height to 44 (or use hitSlop to expand the tappable area).",
|
|
100
|
+
file: rel,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (content.includes("color:") && !content.includes("accessibilityLabel") && /color:\s*["']?(red|green|#ff0000|#00ff00)/i.test(content)) {
|
|
106
|
+
violations.push({
|
|
107
|
+
severity: "moderate",
|
|
108
|
+
wcag: "1.4.1 Use of Color",
|
|
109
|
+
message: "Color may be the only indicator of state. Color-blind users cannot distinguish this.",
|
|
110
|
+
fix: "Add a text label, icon, or pattern in addition to the color change.",
|
|
111
|
+
file: rel,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (violations.length === 0) {
|
|
116
|
+
violations.push({
|
|
117
|
+
severity: "minor",
|
|
118
|
+
wcag: "General",
|
|
119
|
+
message: "No common a11y violations detected in source files. Test with VoiceOver/TalkBack for full coverage.",
|
|
120
|
+
fix: "Run the app with a screen reader and verify all flows are navigable.",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return violations;
|
|
124
|
+
}
|
|
125
|
+
function auditFlutter(root) {
|
|
126
|
+
const violations = [];
|
|
127
|
+
const libDir = join(root, "lib");
|
|
128
|
+
const files = collectFiles(libDir, [".dart"]);
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
let content;
|
|
131
|
+
try {
|
|
132
|
+
content = readFileSync(file, "utf-8");
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const rel = file.replace(root, "").replace(/\\/g, "/");
|
|
138
|
+
const gestureDetectorRegex = /GestureDetector\(/g;
|
|
139
|
+
let match;
|
|
140
|
+
while ((match = gestureDetectorRegex.exec(content)) !== null) {
|
|
141
|
+
const afterTag = content.slice(match.index, match.index + 500);
|
|
142
|
+
if (!afterTag.includes("Semantics") && !afterTag.includes("Tooltip")) {
|
|
143
|
+
violations.push({
|
|
144
|
+
severity: "critical",
|
|
145
|
+
wcag: "1.1.1 Non-text Content",
|
|
146
|
+
message: "GestureDetector without Semantics wrapper. Invisible to screen readers.",
|
|
147
|
+
fix: "Wrap in Semantics(label: '...', button: true, child: GestureDetector(...)).",
|
|
148
|
+
file: rel,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const inkwellRegex = /InkWell\(/g;
|
|
153
|
+
while ((match = inkwellRegex.exec(content)) !== null) {
|
|
154
|
+
const afterTag = content.slice(match.index, match.index + 500);
|
|
155
|
+
if (!afterTag.includes("Semantics") && !afterTag.includes("Tooltip") && !afterTag.includes("semanticsLabel")) {
|
|
156
|
+
violations.push({
|
|
157
|
+
severity: "serious",
|
|
158
|
+
wcag: "4.1.2 Name, Role, Value",
|
|
159
|
+
message: "InkWell without Semantics. Screen readers cannot describe this interactive element.",
|
|
160
|
+
fix: "Wrap in Semantics(label: '...', button: true) or use a named widget like ElevatedButton.",
|
|
161
|
+
file: rel,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const imageRegex = /Image\.(asset|network|file|memory)\(/g;
|
|
166
|
+
while ((match = imageRegex.exec(content)) !== null) {
|
|
167
|
+
const afterTag = content.slice(match.index, match.index + 300);
|
|
168
|
+
if (!afterTag.includes("semanticsLabel") && !afterTag.includes("Semantics") && !afterTag.includes("excludeFromSemantics")) {
|
|
169
|
+
violations.push({
|
|
170
|
+
severity: "serious",
|
|
171
|
+
wcag: "1.1.1 Non-text Content",
|
|
172
|
+
message: `Image.${match[1]}() without semanticsLabel. Screen readers skip this image.`,
|
|
173
|
+
fix: "Add semanticsLabel: '...' or excludeFromSemantics: true for decorative images.",
|
|
174
|
+
file: rel,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const sizedBoxRegex = /SizedBox\(\s*(?:width|height)\s*:\s*(\d+)/g;
|
|
179
|
+
while ((match = sizedBoxRegex.exec(content)) !== null) {
|
|
180
|
+
const size = parseInt(match[1], 10);
|
|
181
|
+
if (size > 0 && size < 44) {
|
|
182
|
+
const context = content.slice(Math.max(0, match.index - 200), match.index + 100);
|
|
183
|
+
if (/onTap|onPressed|InkWell|GestureDetector|IconButton/i.test(context)) {
|
|
184
|
+
violations.push({
|
|
185
|
+
severity: "serious",
|
|
186
|
+
wcag: "2.5.5 Target Size",
|
|
187
|
+
message: `Touch target constrained to ${size}px. Below the 44px minimum.`,
|
|
188
|
+
fix: "Ensure interactive elements have at least 48x48 logical pixels (Material guideline).",
|
|
189
|
+
file: rel,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (violations.length === 0) {
|
|
196
|
+
violations.push({
|
|
197
|
+
severity: "minor",
|
|
198
|
+
wcag: "General",
|
|
199
|
+
message: "No common a11y violations detected. Test with TalkBack (Android) and VoiceOver (iOS).",
|
|
200
|
+
fix: "Enable TalkBack in device settings and navigate the entire app by swipe gestures.",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return violations;
|
|
204
|
+
}
|
|
205
|
+
export function register(server) {
|
|
206
|
+
server.tool("mobile_auditAccessibility", "Scan a mobile project for accessibility violations: missing labels, small touch targets, images without alt text, color-only indicators. Reports WCAG level for each finding.", inputSchema, async (args) => {
|
|
207
|
+
try {
|
|
208
|
+
const root = args.project_path || process.cwd();
|
|
209
|
+
if (!existsSync(root)) {
|
|
210
|
+
return errorResponse(new Error(`Project path does not exist: ${root}`));
|
|
211
|
+
}
|
|
212
|
+
const violations = args.framework === "flutter"
|
|
213
|
+
? auditFlutter(root)
|
|
214
|
+
: auditExpo(root);
|
|
215
|
+
const criticalCount = violations.filter((v) => v.severity === "critical").length;
|
|
216
|
+
const seriousCount = violations.filter((v) => v.severity === "serious").length;
|
|
217
|
+
const moderateCount = violations.filter((v) => v.severity === "moderate").length;
|
|
218
|
+
return textResponse(JSON.stringify({
|
|
219
|
+
success: true,
|
|
220
|
+
framework: args.framework,
|
|
221
|
+
summary: {
|
|
222
|
+
total_violations: violations.length,
|
|
223
|
+
critical: criticalCount,
|
|
224
|
+
serious: seriousCount,
|
|
225
|
+
moderate: moderateCount,
|
|
226
|
+
minor: violations.length - criticalCount - seriousCount - moderateCount,
|
|
227
|
+
},
|
|
228
|
+
violations,
|
|
229
|
+
}, null, 2));
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
return errorResponse(err);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=auditAccessibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditAccessibility.js","sourceRoot":"","sources":["../../src/tools/auditAccessibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkOfflineReady.d.ts","sourceRoot":"","sources":["../../src/tools/checkOfflineReady.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2KzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6ChD"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
project_path: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
10
|
+
framework: z
|
|
11
|
+
.enum(["expo", "flutter"])
|
|
12
|
+
.optional()
|
|
13
|
+
.default("expo")
|
|
14
|
+
.describe("Framework to check (default: expo)."),
|
|
15
|
+
};
|
|
16
|
+
function readFileSafe(filePath) {
|
|
17
|
+
try {
|
|
18
|
+
if (!existsSync(filePath))
|
|
19
|
+
return null;
|
|
20
|
+
return readFileSync(filePath, "utf-8");
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function checkExpoOffline(root) {
|
|
27
|
+
const checks = [];
|
|
28
|
+
const pkgStr = readFileSafe(join(root, "package.json"));
|
|
29
|
+
const deps = pkgStr
|
|
30
|
+
? (() => {
|
|
31
|
+
const pkg = JSON.parse(pkgStr);
|
|
32
|
+
return { ...pkg.dependencies, ...pkg.devDependencies };
|
|
33
|
+
})()
|
|
34
|
+
: {};
|
|
35
|
+
const localDbLibs = ["@nozbe/watermelondb", "expo-sqlite", "realm", "powersync", "react-native-mmkv"];
|
|
36
|
+
const foundDb = localDbLibs.filter((lib) => deps[lib]);
|
|
37
|
+
if (foundDb.length > 0) {
|
|
38
|
+
checks.push({
|
|
39
|
+
category: "Local Database",
|
|
40
|
+
status: "pass",
|
|
41
|
+
message: `Local database found: ${foundDb.join(", ")}.`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
checks.push({
|
|
46
|
+
category: "Local Database",
|
|
47
|
+
status: "fail",
|
|
48
|
+
message: "No local database library detected. Offline data persistence requires a local DB.",
|
|
49
|
+
fix: "Install @nozbe/watermelondb, expo-sqlite, or react-native-mmkv for local data storage.",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const networkLibs = ["@react-native-community/netinfo", "expo-network"];
|
|
53
|
+
const foundNet = networkLibs.filter((lib) => deps[lib]);
|
|
54
|
+
if (foundNet.length > 0) {
|
|
55
|
+
checks.push({
|
|
56
|
+
category: "Network Status",
|
|
57
|
+
status: "pass",
|
|
58
|
+
message: `Network status library found: ${foundNet.join(", ")}.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
checks.push({
|
|
63
|
+
category: "Network Status",
|
|
64
|
+
status: "fail",
|
|
65
|
+
message: "No network status listener detected. The app cannot detect offline/online transitions.",
|
|
66
|
+
fix: "Install @react-native-community/netinfo to detect connectivity changes and adapt the UI.",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (deps["@tanstack/react-query"] || deps["react-query"]) {
|
|
70
|
+
checks.push({
|
|
71
|
+
category: "Query Caching",
|
|
72
|
+
status: "pass",
|
|
73
|
+
message: "React Query detected. Use its offline persistence plugin for cached query survival across restarts.",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (deps["swr"]) {
|
|
77
|
+
checks.push({
|
|
78
|
+
category: "Query Caching",
|
|
79
|
+
status: "pass",
|
|
80
|
+
message: "SWR detected. Configure a persistent cache provider for offline reads.",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
checks.push({
|
|
85
|
+
category: "Query Caching",
|
|
86
|
+
status: "warn",
|
|
87
|
+
message: "No query caching library found. API responses are lost when the app restarts.",
|
|
88
|
+
fix: "Add @tanstack/react-query with persistQueryClient for automatic offline caching.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (deps["@tanstack/react-query"]) {
|
|
92
|
+
checks.push({
|
|
93
|
+
category: "Mutation Queue",
|
|
94
|
+
status: "warn",
|
|
95
|
+
message: "Verify that useMutation calls include onMutate for optimistic updates and a retry/queue for offline writes.",
|
|
96
|
+
fix: "Use React Query's onlineMutationManager or build a custom queue with MMKV persistence.",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
checks.push({
|
|
101
|
+
category: "Mutation Queue",
|
|
102
|
+
status: "warn",
|
|
103
|
+
message: "No mutation queue pattern detected. Writes made offline may be lost.",
|
|
104
|
+
fix: "Implement an offline mutation queue that persists pending writes and replays them when connectivity returns.",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return checks;
|
|
108
|
+
}
|
|
109
|
+
function checkFlutterOffline(root) {
|
|
110
|
+
const checks = [];
|
|
111
|
+
const pubspec = readFileSafe(join(root, "pubspec.yaml")) ?? "";
|
|
112
|
+
const localDbLibs = ["drift", "isar", "sqflite", "hive", "objectbox"];
|
|
113
|
+
const foundDb = localDbLibs.filter((lib) => pubspec.includes(lib));
|
|
114
|
+
if (foundDb.length > 0) {
|
|
115
|
+
checks.push({
|
|
116
|
+
category: "Local Database",
|
|
117
|
+
status: "pass",
|
|
118
|
+
message: `Local database found: ${foundDb.join(", ")}.`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
checks.push({
|
|
123
|
+
category: "Local Database",
|
|
124
|
+
status: "fail",
|
|
125
|
+
message: "No local database package detected in pubspec.yaml.",
|
|
126
|
+
fix: "Add drift (recommended) or isar for typed, reactive local persistence.",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (pubspec.includes("connectivity_plus")) {
|
|
130
|
+
checks.push({
|
|
131
|
+
category: "Network Status",
|
|
132
|
+
status: "pass",
|
|
133
|
+
message: "connectivity_plus found for network state monitoring.",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
checks.push({
|
|
138
|
+
category: "Network Status",
|
|
139
|
+
status: "fail",
|
|
140
|
+
message: "No connectivity monitoring package found.",
|
|
141
|
+
fix: "Add connectivity_plus to detect online/offline transitions.",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (pubspec.includes("dio") || pubspec.includes("http")) {
|
|
145
|
+
checks.push({
|
|
146
|
+
category: "HTTP Client",
|
|
147
|
+
status: "pass",
|
|
148
|
+
message: "HTTP client package detected. Ensure requests handle SocketException for offline scenarios.",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
checks.push({
|
|
152
|
+
category: "Mutation Queue",
|
|
153
|
+
status: "warn",
|
|
154
|
+
message: "Verify you have a pending-operations queue that persists writes and replays on reconnect.",
|
|
155
|
+
fix: "Store failed mutations in the local DB with a sync status column and replay via a background isolate.",
|
|
156
|
+
});
|
|
157
|
+
return checks;
|
|
158
|
+
}
|
|
159
|
+
export function register(server) {
|
|
160
|
+
server.tool("mobile_checkOfflineReady", "Validate a mobile project's offline-first readiness: local database, network status listener, query caching, and mutation queue.", inputSchema, async (args) => {
|
|
161
|
+
try {
|
|
162
|
+
const root = args.project_path || process.cwd();
|
|
163
|
+
if (!existsSync(root)) {
|
|
164
|
+
return errorResponse(new Error(`Project path does not exist: ${root}`));
|
|
165
|
+
}
|
|
166
|
+
const checks = args.framework === "flutter"
|
|
167
|
+
? checkFlutterOffline(root)
|
|
168
|
+
: checkExpoOffline(root);
|
|
169
|
+
const passCount = checks.filter((c) => c.status === "pass").length;
|
|
170
|
+
const warnCount = checks.filter((c) => c.status === "warn").length;
|
|
171
|
+
const failCount = checks.filter((c) => c.status === "fail").length;
|
|
172
|
+
const readiness = failCount === 0 && warnCount === 0
|
|
173
|
+
? "ready"
|
|
174
|
+
: failCount === 0
|
|
175
|
+
? "partial"
|
|
176
|
+
: "not_ready";
|
|
177
|
+
return textResponse(JSON.stringify({
|
|
178
|
+
success: true,
|
|
179
|
+
framework: args.framework,
|
|
180
|
+
readiness,
|
|
181
|
+
summary: { pass: passCount, warn: warnCount, fail: failCount },
|
|
182
|
+
checks,
|
|
183
|
+
}, null, 2));
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
return errorResponse(err);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=checkOfflineReady.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkOfflineReady.js","sourceRoot":"","sources":["../../src/tools/checkOfflineReady.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profilePerformance.d.ts","sourceRoot":"","sources":["../../src/tools/profilePerformance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgNzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyChD"}
|