mobile-agent-mcp 0.1.1

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +4 -0
  4. package/README.md +115 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +142 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config.d.ts +115 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +137 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/driver/adb.d.ts +2 -0
  14. package/dist/driver/adb.d.ts.map +1 -0
  15. package/dist/driver/adb.js +12 -0
  16. package/dist/driver/adb.js.map +1 -0
  17. package/dist/driver/dev-server.d.ts +9 -0
  18. package/dist/driver/dev-server.d.ts.map +1 -0
  19. package/dist/driver/dev-server.js +24 -0
  20. package/dist/driver/dev-server.js.map +1 -0
  21. package/dist/driver/devices.d.ts +2 -0
  22. package/dist/driver/devices.d.ts.map +1 -0
  23. package/dist/driver/devices.js +46 -0
  24. package/dist/driver/devices.js.map +1 -0
  25. package/dist/driver/doctor.d.ts +11 -0
  26. package/dist/driver/doctor.d.ts.map +1 -0
  27. package/dist/driver/doctor.js +64 -0
  28. package/dist/driver/doctor.js.map +1 -0
  29. package/dist/driver/exec.d.ts +17 -0
  30. package/dist/driver/exec.d.ts.map +1 -0
  31. package/dist/driver/exec.js +60 -0
  32. package/dist/driver/exec.js.map +1 -0
  33. package/dist/driver/maestro.d.ts +11 -0
  34. package/dist/driver/maestro.d.ts.map +1 -0
  35. package/dist/driver/maestro.js +73 -0
  36. package/dist/driver/maestro.js.map +1 -0
  37. package/dist/driver/open-url.d.ts +3 -0
  38. package/dist/driver/open-url.d.ts.map +1 -0
  39. package/dist/driver/open-url.js +26 -0
  40. package/dist/driver/open-url.js.map +1 -0
  41. package/dist/driver/screenshot.d.ts +3 -0
  42. package/dist/driver/screenshot.d.ts.map +1 -0
  43. package/dist/driver/screenshot.js +27 -0
  44. package/dist/driver/screenshot.js.map +1 -0
  45. package/dist/errors.d.ts +19 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +45 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/index.d.ts +17 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +13 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/mcp/tools.d.ts +12 -0
  54. package/dist/mcp/tools.d.ts.map +1 -0
  55. package/dist/mcp/tools.js +152 -0
  56. package/dist/mcp/tools.js.map +1 -0
  57. package/dist/mcp-server.d.ts +3 -0
  58. package/dist/mcp-server.d.ts.map +1 -0
  59. package/dist/mcp-server.js +34 -0
  60. package/dist/mcp-server.js.map +1 -0
  61. package/dist/runtime.d.ts +20 -0
  62. package/dist/runtime.d.ts.map +1 -0
  63. package/dist/runtime.js +71 -0
  64. package/dist/runtime.js.map +1 -0
  65. package/dist/version.d.ts +3 -0
  66. package/dist/version.d.ts.map +1 -0
  67. package/dist/version.js +4 -0
  68. package/dist/version.js.map +1 -0
  69. package/mobile-agent.config.example.json +20 -0
  70. package/package.json +73 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here. This project follows [Semantic Versioning](https://semver.org):
4
+ `MAJOR.MINOR.PATCH`: breaking, feature, or fix.
5
+
6
+ ## [0.1.1] - 2026-05-30
7
+
8
+ ### Added
9
+
10
+ - Driver unit tests (Maestro arg building, adb reverse, open-url) with a mocked `spawnSync`.
11
+ - Biome for lint + format; `pnpm lint`, `pnpm format`, and `pnpm check` now gate on it.
12
+ - `CONTRIBUTING.md` with SemVer policy and release steps.
13
+
14
+ ### Fixed
15
+
16
+ - `AgentError` no longer double-wraps the underlying `cause` when raised from config parsing.
17
+
18
+ ### Changed
19
+
20
+ - Dropped the unused `fallback` parameter from `assertPlatform`.
21
+
22
+ ## [0.1.0] - 2026-05-30
23
+
24
+ ### Added
25
+
26
+ - MCP stdio server and `mobile-agent` CLI: `doctor`, `list_devices`, `screenshot`,
27
+ `run_maestro_flow`, `run_smoke_flows`, `adb_reverse`, `open_url`, `open_dev_url`.
28
+ - Per-repo `mobile-agent.config.json` with upward discovery and env overrides.
29
+ - Typed errors with stable exit codes and Zod-validated config.
30
+
31
+ [0.1.1]: https://github.com/anthonysbr/mobile-agent-mcp/compare/v0.1.0...v0.1.1
32
+ [0.1.0]: https://github.com/anthonysbr/mobile-agent-mcp/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anthony Batista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ mobile-agent-mcp
2
+ Copyright (c) 2026 Anthony Batista · https://entkreis.de
3
+
4
+ Keep the LICENSE notice if you redistribute or fork. MIT allows commercial use; a link back is appreciated.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # mobile-agent-mcp
2
+
3
+ Drive **iOS simulators, Android emulators, and USB devices** from Cursor, Claude, Codex, or a shell. Maestro runs your flows; this package handles the host side: list devices, screenshots, deep links, `adb reverse`, per-repo config.
4
+
5
+ No Expo or Flutter lock-in. Your Maestro YAML and env vars live in your project.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -D mobile-agent-mcp
11
+ ```
12
+
13
+ You need Node 20+, [Maestro](https://maestro.mobile.dev/), Xcode on macOS for iOS, and `adb` for Android.
14
+
15
+ ## Config
16
+
17
+ Put `mobile-agent.config.json` in the repo root. Example: [`mobile-agent.config.example.json`](mobile-agent.config.example.json).
18
+
19
+ ```json
20
+ {
21
+ "projectRoot": ".",
22
+ "flowsDir": "e2e/maestro/flows",
23
+ "screenshotDir": "artifacts/mobile-screenshots",
24
+ "smokeFlows": ["smoke-login", "smoke-logout"],
25
+ "maestro": {
26
+ "bin": "maestro",
27
+ "defaultEnv": { "APP_ID": "com.example.app" }
28
+ }
29
+ }
30
+ ```
31
+
32
+ Optional `devServerUrl` builds something like `exp://192.168.x.x:8081` for Maestro and `open-dev-url`:
33
+
34
+ ```json
35
+ "devServerUrl": {
36
+ "scheme": "exp",
37
+ "port": 8081,
38
+ "hostEnv": "EXPO_DEV_HOST",
39
+ "outputEnvKey": "EXPO_URL"
40
+ }
41
+ ```
42
+
43
+ Env overrides: `MOBILE_AGENT_PROJECT_ROOT`, `MOBILE_AGENT_FLOWS_DIR`, `MOBILE_AGENT_SCREENSHOT_DIR`, `MAESTRO_BIN`, `MAESTRO_DEVICE`.
44
+
45
+ If MCP starts from a random cwd, set `MOBILE_AGENT_PROJECT_ROOT` to your repo path.
46
+
47
+ Run `mobile-agent doctor` before a long session. Saves guessing why nothing boots.
48
+
49
+ ## CLI
50
+
51
+ ```bash
52
+ mobile-agent doctor
53
+ mobile-agent devices
54
+ mobile-agent screenshot ios
55
+ mobile-agent run my-flow ios -e APP_ID=com.example.app
56
+ mobile-agent run-all ios
57
+ mobile-agent adb-reverse 8081 4000
58
+ mobile-agent open-url "myapp://home" ios
59
+ mobile-agent open-dev-url ios
60
+ ```
61
+
62
+ Flags: `--project-root`, `--flows-dir`, `--screenshot-dir`.
63
+
64
+ ## MCP
65
+
66
+ ```bash
67
+ mobile-agent-mcp
68
+ ```
69
+
70
+ | Tool | What it does |
71
+ |------|----------------|
72
+ | `doctor` | Config, flows dir, Maestro, adb/simctl |
73
+ | `list_devices` | Sims, USB, Maestro version |
74
+ | `screenshot` | PNG path |
75
+ | `run_maestro_flow` | One flow from `flowsDir` |
76
+ | `run_smoke_flows` | All `smokeFlows` |
77
+ | `adb_reverse` | USB Android → localhost ports |
78
+ | `open_url` | Any deep link |
79
+ | `open_dev_url` | URL from config |
80
+
81
+ **Cursor** (`.cursor/mcp.json`):
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "mobile-agent": {
87
+ "command": "npx",
88
+ "args": ["-y", "mobile-agent-mcp"],
89
+ "env": {
90
+ "MOBILE_AGENT_PROJECT_ROOT": "/absolute/path/to/your/project"
91
+ }
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ Local checkout: point at `dist/mcp-server.js` instead of `npx`.
98
+
99
+ Claude Desktop: same block in `~/Library/Application Support/Claude/claude_desktop_config.json`.
100
+
101
+ No MCP? Shell works fine. See [`docs/agent-skill.md`](docs/agent-skill.md).
102
+
103
+ ## Programmatic use
104
+
105
+ ```ts
106
+ import { createRuntime } from 'mobile-agent-mcp';
107
+
108
+ const agent = createRuntime();
109
+ agent.doctor();
110
+ agent.screenshot('ios');
111
+ ```
112
+
113
+ ## Roadmap
114
+
115
+ [`ROADMAP.md`](ROADMAP.md): next up **`tail_logs`** (Metro, logcat, iOS sim logs).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ import path from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { parseEnvPairs, parsePorts } from './config.js';
5
+ import { formatError, getExitCode } from './errors.js';
6
+ import { createRuntime } from './runtime.js';
7
+ import { PACKAGE_NAME, PACKAGE_VERSION } from './version.js';
8
+ function printResult(text) {
9
+ process.stdout.write(`${text}\n`);
10
+ }
11
+ function printError(error) {
12
+ process.stderr.write(`[${PACKAGE_NAME}] ${formatError(error)}\n`);
13
+ process.exit(getExitCode(error));
14
+ }
15
+ const program = new Command();
16
+ program
17
+ .name('mobile-agent')
18
+ .description('iOS/Android simulators, emulators, and USB devices via Maestro, adb, simctl')
19
+ .version(PACKAGE_VERSION, '-V, --version', 'Print version')
20
+ .option('--project-root <path>', 'Override MOBILE_AGENT_PROJECT_ROOT')
21
+ .option('--flows-dir <path>', 'Override MOBILE_AGENT_FLOWS_DIR')
22
+ .option('--screenshot-dir <path>', 'Override MOBILE_AGENT_SCREENSHOT_DIR');
23
+ function createCliRuntime(command) {
24
+ const opts = command.parent?.opts() ?? {};
25
+ return createRuntime({
26
+ env: {
27
+ ...process.env,
28
+ ...(opts.projectRoot ? { MOBILE_AGENT_PROJECT_ROOT: opts.projectRoot } : {}),
29
+ ...(opts.flowsDir ? { MOBILE_AGENT_FLOWS_DIR: opts.flowsDir } : {}),
30
+ ...(opts.screenshotDir ? { MOBILE_AGENT_SCREENSHOT_DIR: opts.screenshotDir } : {}),
31
+ },
32
+ overrides: {
33
+ ...(opts.projectRoot ? { projectRoot: path.resolve(opts.projectRoot) } : {}),
34
+ ...(opts.flowsDir ? { flowsDir: path.resolve(opts.flowsDir) } : {}),
35
+ ...(opts.screenshotDir ? { screenshotDir: path.resolve(opts.screenshotDir) } : {}),
36
+ },
37
+ });
38
+ }
39
+ program
40
+ .command('doctor')
41
+ .description('Sanity check before running flows')
42
+ .action((_args, command) => {
43
+ try {
44
+ const runtime = createCliRuntime(command);
45
+ printResult(runtime.doctor());
46
+ if (runtime.doctorFailed()) {
47
+ process.exit(4);
48
+ }
49
+ }
50
+ catch (error) {
51
+ printError(error);
52
+ }
53
+ });
54
+ program
55
+ .command('devices')
56
+ .description('Sims, USB devices, Maestro version')
57
+ .action((_args, command) => {
58
+ try {
59
+ printResult(createCliRuntime(command).listDevices());
60
+ }
61
+ catch (error) {
62
+ printError(error);
63
+ }
64
+ });
65
+ program
66
+ .command('screenshot')
67
+ .argument('[platform]', 'ios or android', 'ios')
68
+ .description('PNG to screenshotDir; prints path')
69
+ .action((platform, _args, command) => {
70
+ try {
71
+ printResult(createCliRuntime(command).screenshot(platform));
72
+ }
73
+ catch (error) {
74
+ printError(error);
75
+ }
76
+ });
77
+ program
78
+ .command('run')
79
+ .argument('<flow>', 'Maestro flow name or path relative to flowsDir')
80
+ .argument('[platform]', 'ios or android', 'ios')
81
+ .option('-e, --env <pair...>', 'Maestro env var KEY=VALUE')
82
+ .description('Run one Maestro flow')
83
+ .action((flow, platform, options, command) => {
84
+ try {
85
+ printResult(createCliRuntime(command).runFlow(flow, platform, parseEnvPairs(options.env)));
86
+ }
87
+ catch (error) {
88
+ printError(error);
89
+ }
90
+ });
91
+ program
92
+ .command('run-all')
93
+ .argument('[platform]', 'ios or android', 'ios')
94
+ .option('-e, --env <pair...>', 'Maestro env var KEY=VALUE')
95
+ .description('Run every flow in smokeFlows from config')
96
+ .action((platform, options, command) => {
97
+ try {
98
+ printResult(createCliRuntime(command).runSmoke(platform, parseEnvPairs(options.env)));
99
+ }
100
+ catch (error) {
101
+ printError(error);
102
+ }
103
+ });
104
+ program
105
+ .command('adb-reverse')
106
+ .argument('[ports...]', 'TCP ports to reverse')
107
+ .description('adb reverse for localhost ports (USB Android)')
108
+ .action((ports, _args, command) => {
109
+ try {
110
+ printResult(createCliRuntime(command).adbReverse(parsePorts(ports)));
111
+ }
112
+ catch (error) {
113
+ printError(error);
114
+ }
115
+ });
116
+ program
117
+ .command('open-dev-url')
118
+ .argument('[platform]', 'ios or android', 'ios')
119
+ .description('Open URL from devServerUrl in config')
120
+ .action((platform, _args, command) => {
121
+ try {
122
+ printResult(createCliRuntime(command).openDevUrl(platform));
123
+ }
124
+ catch (error) {
125
+ printError(error);
126
+ }
127
+ });
128
+ program
129
+ .command('open-url')
130
+ .argument('<url>', 'Deep link or URL to open on device')
131
+ .argument('[platform]', 'ios or android', 'ios')
132
+ .description('Open a deep link on sim or device')
133
+ .action((url, platform, _args, command) => {
134
+ try {
135
+ printResult(createCliRuntime(command).openUrl(url, platform));
136
+ }
137
+ catch (error) {
138
+ printError(error);
139
+ }
140
+ });
141
+ program.parse();
142
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import { z } from 'zod';
2
+ export declare const CONFIG_FILENAME = "mobile-agent.config.json";
3
+ export type Platform = 'ios' | 'android';
4
+ declare const ConfigFileSchema: z.ZodObject<{
5
+ projectRoot: z.ZodOptional<z.ZodString>;
6
+ flowsDir: z.ZodOptional<z.ZodString>;
7
+ screenshotDir: z.ZodOptional<z.ZodString>;
8
+ smokeFlows: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ devServerUrl: z.ZodOptional<z.ZodObject<{
10
+ scheme: z.ZodOptional<z.ZodString>;
11
+ port: z.ZodOptional<z.ZodNumber>;
12
+ hostEnv: z.ZodOptional<z.ZodString>;
13
+ outputEnvKey: z.ZodOptional<z.ZodString>;
14
+ }, "strip", z.ZodTypeAny, {
15
+ scheme?: string | undefined;
16
+ port?: number | undefined;
17
+ hostEnv?: string | undefined;
18
+ outputEnvKey?: string | undefined;
19
+ }, {
20
+ scheme?: string | undefined;
21
+ port?: number | undefined;
22
+ hostEnv?: string | undefined;
23
+ outputEnvKey?: string | undefined;
24
+ }>>;
25
+ maestro: z.ZodOptional<z.ZodObject<{
26
+ bin: z.ZodOptional<z.ZodString>;
27
+ defaultEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
28
+ appId: z.ZodOptional<z.ZodObject<{
29
+ ios: z.ZodOptional<z.ZodString>;
30
+ android: z.ZodOptional<z.ZodString>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ ios?: string | undefined;
33
+ android?: string | undefined;
34
+ }, {
35
+ ios?: string | undefined;
36
+ android?: string | undefined;
37
+ }>>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ bin?: string | undefined;
40
+ defaultEnv?: Record<string, string> | undefined;
41
+ appId?: {
42
+ ios?: string | undefined;
43
+ android?: string | undefined;
44
+ } | undefined;
45
+ }, {
46
+ bin?: string | undefined;
47
+ defaultEnv?: Record<string, string> | undefined;
48
+ appId?: {
49
+ ios?: string | undefined;
50
+ android?: string | undefined;
51
+ } | undefined;
52
+ }>>;
53
+ }, "strip", z.ZodTypeAny, {
54
+ projectRoot?: string | undefined;
55
+ flowsDir?: string | undefined;
56
+ screenshotDir?: string | undefined;
57
+ smokeFlows?: string[] | undefined;
58
+ devServerUrl?: {
59
+ scheme?: string | undefined;
60
+ port?: number | undefined;
61
+ hostEnv?: string | undefined;
62
+ outputEnvKey?: string | undefined;
63
+ } | undefined;
64
+ maestro?: {
65
+ bin?: string | undefined;
66
+ defaultEnv?: Record<string, string> | undefined;
67
+ appId?: {
68
+ ios?: string | undefined;
69
+ android?: string | undefined;
70
+ } | undefined;
71
+ } | undefined;
72
+ }, {
73
+ projectRoot?: string | undefined;
74
+ flowsDir?: string | undefined;
75
+ screenshotDir?: string | undefined;
76
+ smokeFlows?: string[] | undefined;
77
+ devServerUrl?: {
78
+ scheme?: string | undefined;
79
+ port?: number | undefined;
80
+ hostEnv?: string | undefined;
81
+ outputEnvKey?: string | undefined;
82
+ } | undefined;
83
+ maestro?: {
84
+ bin?: string | undefined;
85
+ defaultEnv?: Record<string, string> | undefined;
86
+ appId?: {
87
+ ios?: string | undefined;
88
+ android?: string | undefined;
89
+ } | undefined;
90
+ } | undefined;
91
+ }>;
92
+ export type MobileAgentConfigFile = z.infer<typeof ConfigFileSchema>;
93
+ export interface ResolvedConfig {
94
+ projectRoot: string;
95
+ flowsDir: string;
96
+ screenshotDir: string;
97
+ smokeFlows: string[];
98
+ maestroBin: string;
99
+ maestroDefaultEnv: Record<string, string>;
100
+ maestroAppIds: Partial<Record<Platform, string>>;
101
+ devServerUrl: MobileAgentConfigFile['devServerUrl'];
102
+ configPath: string | null;
103
+ }
104
+ export declare function findConfigFile(startDir?: string): string | null;
105
+ export interface LoadConfigOptions {
106
+ startDir?: string;
107
+ overrides?: Partial<ResolvedConfig>;
108
+ env?: NodeJS.ProcessEnv;
109
+ }
110
+ export declare function loadConfig(options?: LoadConfigOptions): ResolvedConfig;
111
+ export declare function assertPlatform(value: string | undefined): Platform;
112
+ export declare function parseEnvPairs(pairs: string[] | undefined): Record<string, string>;
113
+ export declare function parsePorts(ports: string[]): number[];
114
+ export {};
115
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,eAAe,6BAA6B,CAAC;AAE1D,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AASzC,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBpB,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAC;IACpD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AA0CD,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAgB9E;AAOD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CAiD1E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAWlE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUjF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CASpD"}
package/dist/config.js ADDED
@@ -0,0 +1,137 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { z } from 'zod';
4
+ import { AgentError, ErrorCode } from './errors.js';
5
+ export const CONFIG_FILENAME = 'mobile-agent.config.json';
6
+ const DevServerUrlSchema = z.object({
7
+ scheme: z.string().min(1).optional(),
8
+ port: z.number().int().positive().max(65535).optional(),
9
+ hostEnv: z.string().min(1).optional(),
10
+ outputEnvKey: z.string().min(1).optional(),
11
+ });
12
+ const ConfigFileSchema = z.object({
13
+ projectRoot: z.string().min(1).optional(),
14
+ flowsDir: z.string().min(1).optional(),
15
+ screenshotDir: z.string().min(1).optional(),
16
+ smokeFlows: z.array(z.string().min(1)).optional(),
17
+ devServerUrl: DevServerUrlSchema.optional(),
18
+ maestro: z
19
+ .object({
20
+ bin: z.string().min(1).optional(),
21
+ defaultEnv: z.record(z.string(), z.string()).optional(),
22
+ appId: z
23
+ .object({
24
+ ios: z.string().min(1).optional(),
25
+ android: z.string().min(1).optional(),
26
+ })
27
+ .optional(),
28
+ })
29
+ .optional(),
30
+ });
31
+ const DEFAULT_FLOWS_DIR = 'e2e/maestro/flows';
32
+ const DEFAULT_SCREENSHOT_DIR = 'artifacts/mobile-screenshots';
33
+ function readConfigFile(filePath) {
34
+ let raw;
35
+ try {
36
+ raw = fs.readFileSync(filePath, 'utf-8');
37
+ }
38
+ catch (error) {
39
+ throw new AgentError(`Unable to read ${filePath}: ${error instanceof Error ? error.message : String(error)}`, ErrorCode.CONFIG_INVALID, error);
40
+ }
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(raw);
44
+ }
45
+ catch (error) {
46
+ throw new AgentError(`Invalid JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}`, ErrorCode.CONFIG_INVALID, error);
47
+ }
48
+ const result = ConfigFileSchema.safeParse(parsed);
49
+ if (!result.success) {
50
+ const details = result.error.issues
51
+ .map((issue) => `${issue.path.join('.') || 'root'}: ${issue.message}`)
52
+ .join('; ');
53
+ throw new AgentError(`Invalid ${CONFIG_FILENAME} at ${filePath}: ${details}`, ErrorCode.CONFIG_INVALID);
54
+ }
55
+ return result.data;
56
+ }
57
+ export function findConfigFile(startDir = process.cwd()) {
58
+ let dir = path.resolve(startDir);
59
+ const root = path.parse(dir).root;
60
+ while (true) {
61
+ const candidate = path.join(dir, CONFIG_FILENAME);
62
+ if (fs.existsSync(candidate)) {
63
+ return candidate;
64
+ }
65
+ if (dir === root) {
66
+ break;
67
+ }
68
+ dir = path.dirname(dir);
69
+ }
70
+ return null;
71
+ }
72
+ function resolvePath(baseDir, value, fallback) {
73
+ const target = value ?? fallback;
74
+ return path.resolve(baseDir, target);
75
+ }
76
+ export function loadConfig(options = {}) {
77
+ const env = options.env ?? process.env;
78
+ const startDir = options.startDir ?? process.cwd();
79
+ const configSearchDir = env.MOBILE_AGENT_PROJECT_ROOT ?? startDir;
80
+ const configPath = findConfigFile(configSearchDir);
81
+ const fileConfig = configPath ? readConfigFile(configPath) : {};
82
+ const configBaseDir = configPath ? path.dirname(configPath) : path.resolve(startDir);
83
+ const projectRoot = resolvePath(configBaseDir, env.MOBILE_AGENT_PROJECT_ROOT ?? fileConfig.projectRoot, '.');
84
+ const flowsDir = resolvePath(projectRoot, env.MOBILE_AGENT_FLOWS_DIR ?? fileConfig.flowsDir, DEFAULT_FLOWS_DIR);
85
+ const screenshotDir = resolvePath(projectRoot, env.MOBILE_AGENT_SCREENSHOT_DIR ?? fileConfig.screenshotDir, DEFAULT_SCREENSHOT_DIR);
86
+ const maestroBin = env.MAESTRO_BIN ?? fileConfig.maestro?.bin ?? 'maestro';
87
+ const maestroDefaultEnv = fileConfig.maestro?.defaultEnv ?? {};
88
+ const maestroAppIds = fileConfig.maestro?.appId ?? {};
89
+ const devServerUrl = fileConfig.devServerUrl;
90
+ const smokeFlows = fileConfig.smokeFlows ?? [];
91
+ const resolved = {
92
+ projectRoot,
93
+ flowsDir,
94
+ screenshotDir,
95
+ smokeFlows,
96
+ maestroBin,
97
+ maestroDefaultEnv,
98
+ maestroAppIds,
99
+ devServerUrl,
100
+ configPath,
101
+ };
102
+ if (options.overrides) {
103
+ return { ...resolved, ...options.overrides };
104
+ }
105
+ return resolved;
106
+ }
107
+ export function assertPlatform(value) {
108
+ if (!value || value === 'ios') {
109
+ return 'ios';
110
+ }
111
+ if (value === 'android') {
112
+ return 'android';
113
+ }
114
+ throw new AgentError(`Unknown platform: ${value} (use ios or android)`, ErrorCode.PLATFORM_INVALID);
115
+ }
116
+ export function parseEnvPairs(pairs) {
117
+ const env = {};
118
+ for (const pair of pairs ?? []) {
119
+ const index = pair.indexOf('=');
120
+ if (index <= 0) {
121
+ throw new AgentError(`Invalid env pair: ${pair} (expected KEY=VALUE)`, ErrorCode.VALIDATION);
122
+ }
123
+ env[pair.slice(0, index)] = pair.slice(index + 1);
124
+ }
125
+ return env;
126
+ }
127
+ export function parsePorts(ports) {
128
+ const portArgs = ports.length > 0 ? ports : ['8081'];
129
+ return portArgs.map((port) => {
130
+ const value = Number(port);
131
+ if (!Number.isInteger(value) || value <= 0 || value > 65535) {
132
+ throw new AgentError(`Invalid port: ${port}`, ErrorCode.VALIDATION);
133
+ }
134
+ return value;
135
+ });
136
+ }
137
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function adbReverse(ports: number[]): string;
2
+ //# sourceMappingURL=adb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../../src/driver/adb.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAUlD"}
@@ -0,0 +1,12 @@
1
+ import { AgentError, ErrorCode } from '../errors.js';
2
+ import { commandExists, runCommand } from './exec.js';
3
+ export function adbReverse(ports) {
4
+ if (!commandExists('adb')) {
5
+ throw new AgentError('adb not installed', ErrorCode.TOOL_UNAVAILABLE);
6
+ }
7
+ for (const port of ports) {
8
+ runCommand('adb', ['reverse', `tcp:${port}`, `tcp:${port}`]);
9
+ }
10
+ return `adb reverse ok (${ports.join(', ')})`;
11
+ }
12
+ //# sourceMappingURL=adb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb.js","sourceRoot":"","sources":["../../src/driver/adb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,UAAU,UAAU,CAAC,KAAe;IACxC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,UAAU,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,IAAI,EAAE,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,mBAAmB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAChD,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function detectLanIp(): string;
2
+ export interface DevServerUrlConfig {
3
+ scheme?: string;
4
+ port?: number;
5
+ hostEnv?: string;
6
+ outputEnvKey?: string;
7
+ }
8
+ export declare function resolveDevServerEnv(config: DevServerUrlConfig | undefined, env?: NodeJS.ProcessEnv): Record<string, string>;
9
+ //# sourceMappingURL=dev-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/driver/dev-server.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,IAAI,MAAM,CAWpC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB"}