expo-agent-bridge 0.1.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/LICENSE +21 -0
- package/README.md +234 -0
- package/bin/cli.js +9 -0
- package/dist/DevAgentBridge.d.ts +31 -0
- package/dist/DevAgentBridge.d.ts.map +1 -0
- package/dist/DevAgentBridge.js +355 -0
- package/dist/DevAgentBridge.js.map +1 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +262 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +10 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +74 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +276 -0
- package/dist/server.js.map +1 -0
- package/package.json +68 -0
- package/skills/expo-agent-bridge/SKILL.md +65 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startAgentBridgeMcpServer = startAgentBridgeMcpServer;
|
|
4
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
function startAgentBridgeMcpServer(options = {}) {
|
|
8
|
+
const PLUGIN_NAME = options.pluginName ?? process.env.EXPO_AGENT_BRIDGE_PLUGIN ?? 'expo-agent-bridge';
|
|
9
|
+
const METRO_PORT = options.metroPort ?? Number(process.env.EXPO_METRO_PORT ?? 8081);
|
|
10
|
+
const PROTOCOL_VERSION = 1;
|
|
11
|
+
const COMMAND_TIMEOUT_MS = options.commandTimeoutMs ?? 30000;
|
|
12
|
+
let commandSeq = 0;
|
|
13
|
+
const pendingCommands = new Map();
|
|
14
|
+
// ─── In-memory log buffer ───────────────────────────────────────────────────
|
|
15
|
+
const recentLogs = [];
|
|
16
|
+
const MAX_LOGS = 100;
|
|
17
|
+
function addLog(entry) {
|
|
18
|
+
if (!entry)
|
|
19
|
+
return;
|
|
20
|
+
recentLogs.push(entry);
|
|
21
|
+
if (recentLogs.length > MAX_LOGS)
|
|
22
|
+
recentLogs.shift();
|
|
23
|
+
}
|
|
24
|
+
// ─── DevTools Plugin WebSocket connection ───────────────────────────────────
|
|
25
|
+
let ws = null;
|
|
26
|
+
let wsReady = false;
|
|
27
|
+
let connectionPromise = null;
|
|
28
|
+
const browserClientId = Date.now().toString();
|
|
29
|
+
function packMessage(method, payload) {
|
|
30
|
+
const messageKey = { pluginName: PLUGIN_NAME, method };
|
|
31
|
+
return JSON.stringify({ messageKey, payload });
|
|
32
|
+
}
|
|
33
|
+
function unpackMessage(data) {
|
|
34
|
+
if (typeof data === 'string')
|
|
35
|
+
return JSON.parse(data);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function sendHandshake() {
|
|
39
|
+
ws.send(JSON.stringify({
|
|
40
|
+
__isHandshakeMessages: true,
|
|
41
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
42
|
+
pluginName: PLUGIN_NAME,
|
|
43
|
+
method: 'handshake',
|
|
44
|
+
browserClientId,
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
function connectToMetro() {
|
|
48
|
+
if (connectionPromise)
|
|
49
|
+
return connectionPromise;
|
|
50
|
+
connectionPromise = new Promise((resolve, reject) => {
|
|
51
|
+
const url = `ws://localhost:${METRO_PORT}/expo-dev-plugins/broadcast`;
|
|
52
|
+
process.stderr.write(`[expo-agent-bridge] Connecting to ${url}\n`);
|
|
53
|
+
ws = new WebSocket(url);
|
|
54
|
+
ws.addEventListener('open', () => {
|
|
55
|
+
wsReady = true;
|
|
56
|
+
sendHandshake();
|
|
57
|
+
process.stderr.write('[expo-agent-bridge] Connected to DevTools broadcast channel ✓\n');
|
|
58
|
+
resolve();
|
|
59
|
+
});
|
|
60
|
+
ws.addEventListener('message', (event) => {
|
|
61
|
+
const raw = event.data;
|
|
62
|
+
let msg;
|
|
63
|
+
try {
|
|
64
|
+
msg = unpackMessage(typeof raw === 'string' ? raw : raw.toString());
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!msg)
|
|
70
|
+
return;
|
|
71
|
+
if (msg.__isHandshakeMessages)
|
|
72
|
+
return;
|
|
73
|
+
const { messageKey, payload } = msg;
|
|
74
|
+
if (!messageKey || messageKey.pluginName !== PLUGIN_NAME)
|
|
75
|
+
return;
|
|
76
|
+
// Real-time log/error streamed from app
|
|
77
|
+
if (messageKey.method === 'log') {
|
|
78
|
+
addLog(payload);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (messageKey.method !== 'result')
|
|
82
|
+
return;
|
|
83
|
+
const pending = pendingCommands.get(payload?.id);
|
|
84
|
+
if (!pending)
|
|
85
|
+
return;
|
|
86
|
+
clearTimeout(pending.timer);
|
|
87
|
+
pendingCommands.delete(payload.id);
|
|
88
|
+
if (payload.error) {
|
|
89
|
+
pending.reject(new Error(payload.error));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
pending.resolve(payload);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
ws.addEventListener('close', () => {
|
|
96
|
+
wsReady = false;
|
|
97
|
+
connectionPromise = null;
|
|
98
|
+
ws = null;
|
|
99
|
+
process.stderr.write('[expo-agent-bridge] DevTools connection closed — will reconnect on next tool call\n');
|
|
100
|
+
for (const [id, pending] of pendingCommands) {
|
|
101
|
+
clearTimeout(pending.timer);
|
|
102
|
+
pending.reject(new Error('Connection closed while waiting for phone response'));
|
|
103
|
+
pendingCommands.delete(id);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
ws.addEventListener('error', (e) => {
|
|
107
|
+
process.stderr.write(`[expo-agent-bridge] WS error: ${e?.message ?? 'connection failed'}\n`);
|
|
108
|
+
connectionPromise = null;
|
|
109
|
+
reject(e);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
return connectionPromise;
|
|
113
|
+
}
|
|
114
|
+
async function sendCommand(action, params = {}) {
|
|
115
|
+
try {
|
|
116
|
+
await connectToMetro();
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
throw new Error(`Cannot connect to Metro dev server on port ${METRO_PORT}. ` +
|
|
120
|
+
`Make sure 'npx expo start' is running. (${e.message})`);
|
|
121
|
+
}
|
|
122
|
+
if (!wsReady) {
|
|
123
|
+
throw new Error('DevTools connection not ready. Is expo running and the dev app open on phone/simulator?');
|
|
124
|
+
}
|
|
125
|
+
// The app-side DevTools listener needs a brief moment after the broadcast
|
|
126
|
+
// handshake before it can reliably receive the first command. The direct
|
|
127
|
+
// CLI uses the same delay; keeping both transports aligned avoids a
|
|
128
|
+
// first-call race in MCP clients.
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
130
|
+
const id = String(++commandSeq);
|
|
131
|
+
const cmd = { id, action, ...params };
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
const timer = setTimeout(() => {
|
|
134
|
+
pendingCommands.delete(id);
|
|
135
|
+
const lastError = recentLogs.slice().reverse().find((l) => l.level === 'error');
|
|
136
|
+
let msg = `Timed out after ${COMMAND_TIMEOUT_MS / 1000}s waiting for phone response. Is the dev app open?`;
|
|
137
|
+
if (lastError) {
|
|
138
|
+
msg += `\n[Recent App Error]: ${lastError.message}`;
|
|
139
|
+
if (lastError.stack)
|
|
140
|
+
msg += `\n${lastError.stack}`;
|
|
141
|
+
}
|
|
142
|
+
reject(new Error(msg));
|
|
143
|
+
}, COMMAND_TIMEOUT_MS);
|
|
144
|
+
pendingCommands.set(id, { resolve, reject, timer });
|
|
145
|
+
ws.send(packMessage('command', cmd));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function triggerMetroReload() {
|
|
149
|
+
return new Promise((resolve) => {
|
|
150
|
+
try {
|
|
151
|
+
const reloadWs = new WebSocket(`ws://localhost:${METRO_PORT}/message`);
|
|
152
|
+
reloadWs.addEventListener('open', () => {
|
|
153
|
+
reloadWs.send(JSON.stringify({ version: 2, method: 'reload' }));
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
try {
|
|
156
|
+
reloadWs.close();
|
|
157
|
+
}
|
|
158
|
+
catch { }
|
|
159
|
+
resolve();
|
|
160
|
+
}, 300);
|
|
161
|
+
});
|
|
162
|
+
reloadWs.addEventListener('error', () => resolve());
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
resolve();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// ─── MCP Server ─────────────────────────────────────────────────────────────
|
|
170
|
+
const mcp = new mcp_js_1.McpServer({ name: 'expo-agent-bridge', version: '0.1.0' });
|
|
171
|
+
mcp.tool('get_screenshot', 'Capture the current mobile screen as a PNG. Returns base64 image data. If the app crashed or timed out, recent error logs will be included.', {}, async () => {
|
|
172
|
+
const res = await sendCommand('screenshot');
|
|
173
|
+
if (!res.data)
|
|
174
|
+
throw new Error('No image data returned from app.');
|
|
175
|
+
return { content: [{ type: 'image', data: res.data, mimeType: 'image/png' }] };
|
|
176
|
+
});
|
|
177
|
+
mcp.tool('get_logs', 'Get recent console errors, warnings, and unhandled exceptions streamed from the app.', {
|
|
178
|
+
level: zod_1.z.enum(['error', 'warn', 'all']).optional().describe('Filter by log level (default: "all")'),
|
|
179
|
+
limit: zod_1.z.number().optional().describe('Maximum entries to return (default: 30)'),
|
|
180
|
+
}, async ({ level = 'all', limit = 30 }) => {
|
|
181
|
+
let logs = recentLogs;
|
|
182
|
+
if (level === 'error')
|
|
183
|
+
logs = logs.filter((l) => l.level === 'error');
|
|
184
|
+
else if (level === 'warn')
|
|
185
|
+
logs = logs.filter((l) => l.level === 'error' || l.level === 'warn');
|
|
186
|
+
const entries = logs.slice(-limit);
|
|
187
|
+
if (entries.length === 0) {
|
|
188
|
+
return { content: [{ type: 'text', text: 'No logs recorded.' }] };
|
|
189
|
+
}
|
|
190
|
+
const text = entries
|
|
191
|
+
.map((e) => {
|
|
192
|
+
const time = new Date(e.timestamp).toLocaleTimeString();
|
|
193
|
+
let s = `[${time}] [${e.level.toUpperCase()}] ${e.message}`;
|
|
194
|
+
if (e.stack)
|
|
195
|
+
s += `\n${e.stack}`;
|
|
196
|
+
return s;
|
|
197
|
+
})
|
|
198
|
+
.join('\n\n');
|
|
199
|
+
return { content: [{ type: 'text', text }] };
|
|
200
|
+
});
|
|
201
|
+
mcp.tool('reload', 'Reload the app bundle on the phone. Triggers both Metro reload broadcast and in-app DevSettings.reload.', {}, async () => {
|
|
202
|
+
await triggerMetroReload();
|
|
203
|
+
try {
|
|
204
|
+
await sendCommand('reload');
|
|
205
|
+
}
|
|
206
|
+
catch { }
|
|
207
|
+
return { content: [{ type: 'text', text: 'App reload triggered successfully.' }] };
|
|
208
|
+
});
|
|
209
|
+
mcp.tool('get_route', 'Get the current active route, pathname, and segments from Expo Router.', {}, async () => {
|
|
210
|
+
const res = await sendCommand('get_route');
|
|
211
|
+
return { content: [{ type: 'text', text: JSON.stringify(res.route, null, 2) }] };
|
|
212
|
+
});
|
|
213
|
+
mcp.tool('get_elements', 'List all currently mounted interactive UI elements (testIDs, titles, types) on screen.', {}, async () => {
|
|
214
|
+
const res = await sendCommand('get_elements');
|
|
215
|
+
const elements = res.elements || [];
|
|
216
|
+
if (elements.length === 0) {
|
|
217
|
+
return { content: [{ type: 'text', text: 'No interactive elements registered on current screen.' }] };
|
|
218
|
+
}
|
|
219
|
+
return { content: [{ type: 'text', text: JSON.stringify(elements, null, 2) }] };
|
|
220
|
+
});
|
|
221
|
+
mcp.tool('get_state', 'Inspect app custom state or stores exposed to the bridge.', {}, async () => {
|
|
222
|
+
const res = await sendCommand('get_state');
|
|
223
|
+
if (res.error)
|
|
224
|
+
throw new Error(res.error);
|
|
225
|
+
return { content: [{ type: 'text', text: JSON.stringify(res.state, null, 2) }] };
|
|
226
|
+
});
|
|
227
|
+
mcp.tool('reset_storage', 'Clear AsyncStorage on the device to test clean first-time install experience.', {}, async () => {
|
|
228
|
+
const res = await sendCommand('reset_storage');
|
|
229
|
+
if (res.error)
|
|
230
|
+
throw new Error(res.error);
|
|
231
|
+
return { content: [{ type: 'text', text: 'AsyncStorage cleared.' }] };
|
|
232
|
+
});
|
|
233
|
+
mcp.tool('open_dev_menu', 'Open the developer menu on the phone without shaking the device.', {}, async () => {
|
|
234
|
+
try {
|
|
235
|
+
await sendCommand('open_dev_menu');
|
|
236
|
+
}
|
|
237
|
+
catch { }
|
|
238
|
+
return { content: [{ type: 'text', text: 'Developer menu triggered.' }] };
|
|
239
|
+
});
|
|
240
|
+
mcp.tool('navigate', 'Navigate to an Expo Router route in the app.', { route: zod_1.z.string().describe('Route path (e.g. "/settings")') }, async ({ route }) => {
|
|
241
|
+
await sendCommand('navigate', { route });
|
|
242
|
+
return { content: [{ type: 'text', text: `Navigated to ${route}` }] };
|
|
243
|
+
});
|
|
244
|
+
mcp.tool('tap', 'Tap an element by its testID prop.', { target: zod_1.z.string().describe('testID of the element') }, async ({ target }) => {
|
|
245
|
+
const res = await sendCommand('tap', { target });
|
|
246
|
+
if (!res.success)
|
|
247
|
+
throw new Error(`Element "${target}" not found or has no onPress.`);
|
|
248
|
+
return { content: [{ type: 'text', text: `Tapped "${target}"` }] };
|
|
249
|
+
});
|
|
250
|
+
mcp.tool('scroll', 'Scroll the active scroll view up or down.', {
|
|
251
|
+
direction: zod_1.z.enum(['up', 'down']),
|
|
252
|
+
amount: zod_1.z.number().optional().describe('Pixels to scroll (default 300)'),
|
|
253
|
+
}, async ({ direction, amount = 300 }) => {
|
|
254
|
+
await sendCommand('scroll', { direction, amount });
|
|
255
|
+
return { content: [{ type: 'text', text: `Scrolled ${direction} ${amount}px` }] };
|
|
256
|
+
});
|
|
257
|
+
mcp.tool('type_text', 'Type text into a TextInput by testID.', {
|
|
258
|
+
target: zod_1.z.string().describe('testID of TextInput'),
|
|
259
|
+
text: zod_1.z.string().describe('Text to type'),
|
|
260
|
+
}, async ({ target, text }) => {
|
|
261
|
+
const res = await sendCommand('type', { target, text });
|
|
262
|
+
if (!res.success)
|
|
263
|
+
throw new Error(`Input "${target}" not found or has no onChangeText handler.`);
|
|
264
|
+
return { content: [{ type: 'text', text: `Typed "${text}" into "${target}"` }] };
|
|
265
|
+
});
|
|
266
|
+
async function run() {
|
|
267
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
268
|
+
await mcp.connect(transport);
|
|
269
|
+
process.stderr.write(`[expo-agent-bridge] MCP server running. DevTools plugin: ${PLUGIN_NAME}, Metro port: ${METRO_PORT}\n`);
|
|
270
|
+
}
|
|
271
|
+
run().catch((e) => {
|
|
272
|
+
process.stderr.write(`[expo-agent-bridge] fatal: ${e.message}\n`);
|
|
273
|
+
process.exit(1);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;AAUA,8DAqWC;AA/WD,oEAAoE;AACpE,wEAAiF;AACjF,6BAAwB;AAQxB,SAAgB,yBAAyB,CAAC,UAAyB,EAAE;IACnE,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,mBAAmB,CAAC;IACtG,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC;IACpF,MAAM,gBAAgB,GAAG,CAAC,CAAC;IAC3B,MAAM,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,IAAI,KAAK,CAAC;IAE7D,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,eAAe,GAAG,IAAI,GAAG,EAAmF,CAAC;IAEnH,+EAA+E;IAE/E,MAAM,UAAU,GAAiF,EAAE,CAAC;IACpG,MAAM,QAAQ,GAAG,GAAG,CAAC;IAErB,SAAS,MAAM,CAAC,KAAU;QACxB,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,UAAU,CAAC,MAAM,GAAG,QAAQ;YAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC;IAED,+EAA+E;IAE/E,IAAI,EAAE,GAAQ,IAAI,CAAC;IACnB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,iBAAiB,GAAyB,IAAI,CAAC;IACnD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAE9C,SAAS,WAAW,CAAC,MAAc,EAAE,OAAY;QAC/C,MAAM,UAAU,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,SAAS,aAAa,CAAC,IAAS;QAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,aAAa;QACpB,EAAE,CAAC,IAAI,CACL,IAAI,CAAC,SAAS,CAAC;YACb,qBAAqB,EAAE,IAAI;YAC3B,eAAe,EAAE,gBAAgB;YACjC,UAAU,EAAE,WAAW;YACvB,MAAM,EAAE,WAAW;YACnB,eAAe;SAChB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,SAAS,cAAc;QACrB,IAAI,iBAAiB;YAAE,OAAO,iBAAiB,CAAC;QAEhD,iBAAiB,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClD,MAAM,GAAG,GAAG,kBAAkB,UAAU,6BAA6B,CAAC;YACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,GAAG,IAAI,CAAC,CAAC;YAEnE,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;YAExB,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC/B,OAAO,GAAG,IAAI,CAAC;gBACf,aAAa,EAAE,CAAC;gBAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;gBACxF,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAU,EAAE,EAAE;gBAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;gBACvB,IAAI,GAAQ,CAAC;gBACb,IAAI,CAAC;oBACH,GAAG,GAAG,aAAa,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACtE,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,GAAG;oBAAE,OAAO;gBAEjB,IAAI,GAAG,CAAC,qBAAqB;oBAAE,OAAO;gBAEtC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;gBACpC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,UAAU,KAAK,WAAW;oBAAE,OAAO;gBAEjE,wCAAwC;gBACxC,IAAI,UAAU,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;oBAChC,MAAM,CAAC,OAAO,CAAC,CAAC;oBAChB,OAAO;gBACT,CAAC;gBAED,IAAI,UAAU,CAAC,MAAM,KAAK,QAAQ;oBAAE,OAAO;gBAE3C,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACjD,IAAI,CAAC,OAAO;oBAAE,OAAO;gBAErB,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5B,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAEnC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBAChC,OAAO,GAAG,KAAK,CAAC;gBAChB,iBAAiB,GAAG,IAAI,CAAC;gBACzB,EAAE,GAAG,IAAI,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qFAAqF,CAAC,CAAC;gBAC5G,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,eAAe,EAAE,CAAC;oBAC5C,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBAC5B,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC,CAAC;oBAChF,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAM,EAAE,EAAE;gBACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,EAAE,OAAO,IAAI,mBAAmB,IAAI,CAAC,CAAC;gBAC7F,iBAAiB,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,SAA8B,EAAE;QACzE,IAAI,CAAC;YACH,MAAM,cAAc,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,8CAA8C,UAAU,IAAI;gBAC1D,2CAA2C,CAAC,CAAC,OAAO,GAAG,CAC1D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAC;QAC7G,CAAC;QAED,0EAA0E;QAC1E,yEAAyE;QACzE,oEAAoE;QACpE,kCAAkC;QAClC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAEzD,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;QAChC,MAAM,GAAG,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QAEtC,OAAO,IAAI,OAAO,CAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC3B,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;gBAChF,IAAI,GAAG,GAAG,mBAAmB,kBAAkB,GAAG,IAAI,oDAAoD,CAAC;gBAC3G,IAAI,SAAS,EAAE,CAAC;oBACd,GAAG,IAAI,yBAAyB,SAAS,CAAC,OAAO,EAAE,CAAC;oBACpD,IAAI,SAAS,CAAC,KAAK;wBAAE,GAAG,IAAI,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;gBACrD,CAAC;gBACD,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,CAAC,EAAE,kBAAkB,CAAC,CAAC;YAEvB,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACpD,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,kBAAkB;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,SAAS,CAAC,kBAAkB,UAAU,UAAU,CAAC,CAAC;gBACvE,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;oBACrC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;oBAChE,UAAU,CAAC,GAAG,EAAE;wBACd,IAAI,CAAC;4BACH,QAAQ,CAAC,KAAK,EAAE,CAAC;wBACnB,CAAC;wBAAC,MAAM,CAAC,CAAA,CAAC;wBACV,OAAO,EAAE,CAAC;oBACZ,CAAC,EAAE,GAAG,CAAC,CAAC;gBACV,CAAC,CAAC,CAAC;gBACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,+EAA+E;IAE/E,MAAM,GAAG,GAAG,IAAI,kBAAS,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3E,GAAG,CAAC,IAAI,CACN,gBAAgB,EAChB,6IAA6I,EAC7I,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACnE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IACjF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,UAAU,EACV,sFAAsF,EACtF;QACE,KAAK,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;QACnG,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;KACjF,EACD,KAAK,EAAE,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE;QACtC,IAAI,IAAI,GAAG,UAAU,CAAC;QACtB,IAAI,KAAK,KAAK,OAAO;YAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;aACjE,IAAI,KAAK,KAAK,MAAM;YAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;QAEhG,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC;QACpE,CAAC;QACD,MAAM,IAAI,GAAG,OAAO;aACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC;YACxD,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;YAC5D,IAAI,CAAC,CAAC,KAAK;gBAAE,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC;QACX,CAAC,CAAC;aACD,IAAI,CAAC,MAAM,CAAC,CAAC;QAChB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC/C,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,QAAQ,EACR,yGAAyG,EACzG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,kBAAkB,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oCAAoC,EAAE,CAAC,EAAE,CAAC;IACrF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,WAAW,EACX,wEAAwE,EACxE,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACnF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,cAAc,EACd,wFAAwF,EACxF,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;QACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uDAAuD,EAAE,CAAC,EAAE,CAAC;QACxG,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,WAAW,EACX,2DAA2D,EAC3D,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,GAAG,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACnF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,eAAe,EACf,+EAA+E,EAC/E,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,CAAC;QAC/C,IAAI,GAAG,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,EAAE,CAAC;IACxE,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,eAAe,EACf,kEAAkE,EAClE,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,eAAe,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC,EAAE,CAAC;IAC5E,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,UAAU,EACV,8CAA8C,EAC9C,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE,EAC/D,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,WAAW,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IACxE,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,KAAK,EACL,oCAAoC,EACpC,EAAE,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACxD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,MAAM,gCAAgC,CAAC,CAAC;QACtF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;IACrE,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,QAAQ,EACR,2CAA2C,EAC3C;QACE,SAAS,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KACzE,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE,EAAE,EAAE;QACpC,MAAM,WAAW,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,SAAS,IAAI,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IACpF,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,WAAW,EACX,uCAAuC,EACvC;QACE,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAClD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC1C,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;QACzB,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,6CAA6C,CAAC,CAAC;QACjG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,IAAI,WAAW,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;IACnF,CAAC,CACF,CAAC;IAEF,KAAK,UAAU,GAAG;QAChB,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;QAC7C,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4DAA4D,WAAW,iBAAiB,UAAU,IAAI,CACvG,CAAC;IACJ,CAAC;IAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "expo-agent-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Autonomous AI coding agent bridge for Expo and React Native apps. Live visual feedback, logs, navigation, and element interaction without cables.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"expo-agent-bridge": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"bin",
|
|
13
|
+
"skills",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"prepare": "npm run build",
|
|
21
|
+
"test": "npm run build && node --test test/**/*.test.js",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"expo",
|
|
26
|
+
"react-native",
|
|
27
|
+
"ai",
|
|
28
|
+
"agent",
|
|
29
|
+
"mcp",
|
|
30
|
+
"devtools",
|
|
31
|
+
"ui-ux",
|
|
32
|
+
"antigravity",
|
|
33
|
+
"cursor",
|
|
34
|
+
"claude-code",
|
|
35
|
+
"windsurf"
|
|
36
|
+
],
|
|
37
|
+
"author": "Fs02",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/Fs02/expo-agent-bridge"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
45
|
+
"zod": "^3.24.0 || ^4.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@expo/devtools": ">=50.0.0",
|
|
49
|
+
"expo": ">=50.0.0",
|
|
50
|
+
"react": ">=18.0.0",
|
|
51
|
+
"react-native": ">=0.73.0",
|
|
52
|
+
"react-native-view-shot": ">=4.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"expo-router": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"@react-native-async-storage/async-storage": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^22.0.0",
|
|
64
|
+
"@types/react": "^18.2.0 || ^19.0.0",
|
|
65
|
+
"@types/react-native": "^0.73.0",
|
|
66
|
+
"typescript": "^5.3.0"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: expo-agent-bridge
|
|
3
|
+
description: >-
|
|
4
|
+
Use when doing UI/UX work on Expo & React Native apps. Teaches how to use the agent
|
|
5
|
+
dev bridge to see live mobile screens, stream console logs & errors, and interact over Wi-Fi or
|
|
6
|
+
WSL+--tunnel — screenshot, logs, reload, navigate, tap, scroll — no cables.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Expo Agent Dev Bridge
|
|
10
|
+
|
|
11
|
+
Live visual feedback and interactive UI loop for React Native & Expo apps.
|
|
12
|
+
Uses Expo's DevTools Plugin broadcast channel — zero native cables, zero extra tunnels, works over WSL.
|
|
13
|
+
|
|
14
|
+
## Server Ownership
|
|
15
|
+
|
|
16
|
+
Assume the developer already started Expo/Metro and has the dev app open. Attach to that existing
|
|
17
|
+
server first; do **not** run `expo start`, restart Metro, or create a second dev server unless the
|
|
18
|
+
developer explicitly asks. If the bridge cannot connect, report the connection failure and ask the
|
|
19
|
+
developer to start or expose the server.
|
|
20
|
+
|
|
21
|
+
## Transport fallback
|
|
22
|
+
|
|
23
|
+
Use the MCP tools when they are available. If an MCP call is unavailable, times
|
|
24
|
+
out, or cannot reach the Expo server, immediately use the equivalent direct CLI
|
|
25
|
+
command below. Do not create a temporary JavaScript client. Both transports use
|
|
26
|
+
the same `expo-agent-bridge` protocol and control the same running app.
|
|
27
|
+
|
|
28
|
+
## Direct CLI Commands
|
|
29
|
+
|
|
30
|
+
For one-off shell actions, use the installed CLI instead of creating a temporary
|
|
31
|
+
JavaScript client:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx --no-install expo-agent-bridge screenshot /tmp/screen.png
|
|
35
|
+
npx --no-install expo-agent-bridge logs
|
|
36
|
+
npx --no-install expo-agent-bridge navigate /settings
|
|
37
|
+
npx --no-install expo-agent-bridge scroll down 300
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If multiple Expo apps are running, each app must use a distinct Metro port. For
|
|
41
|
+
example, initialize this project with `npx --no-install expo-agent-bridge init
|
|
42
|
+
--metro-port 8082` and start Expo with `npx expo start --port 8082`.
|
|
43
|
+
|
|
44
|
+
| CLI command | Description |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `screenshot [file]` | Captures the current mobile screen as a PNG |
|
|
47
|
+
| `logs` | Streams recent errors, warnings, and exceptions |
|
|
48
|
+
| `reload` | Reloads the app bundle on the device |
|
|
49
|
+
| `route` | Returns the current route |
|
|
50
|
+
| `elements` | Lists mounted interactive elements |
|
|
51
|
+
| `state` | Inspects custom app state |
|
|
52
|
+
| `reset-storage` | Clears AsyncStorage |
|
|
53
|
+
| `dev-menu` | Opens the developer menu |
|
|
54
|
+
| `navigate <route>` | Navigates to an Expo Router route |
|
|
55
|
+
| `tap <testID>` | Presses an element by test ID |
|
|
56
|
+
| `scroll <up\|down> [amount]` | Scrolls the active view |
|
|
57
|
+
| `type-text <testID> <text>` | Types into a TextInput |
|
|
58
|
+
|
|
59
|
+
## Standard Agentic UI/UX Loop
|
|
60
|
+
|
|
61
|
+
1. `get_screenshot()` — observe current screen
|
|
62
|
+
2. Edit code
|
|
63
|
+
3. Wait 3s for Fast Refresh (or call `reload()` if stuck)
|
|
64
|
+
4. `get_screenshot()` — verify visual changes
|
|
65
|
+
5. Iterate or commit
|