nativeapptemplate-agent 0.1.1 → 0.2.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/CLAUDE.md +9 -7
- package/README.md +65 -21
- package/dist/agents/judge.d.ts +8 -0
- package/dist/agents/judge.d.ts.map +1 -1
- package/dist/agents/judge.js +100 -14
- package/dist/agents/judge.js.map +1 -1
- package/dist/agents/repair.d.ts +14 -0
- package/dist/agents/repair.d.ts.map +1 -0
- package/dist/agents/repair.js +103 -0
- package/dist/agents/repair.js.map +1 -0
- package/dist/agents/types.d.ts +34 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/dispatch.d.ts +21 -2
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +250 -14
- package/dist/dispatch.js.map +1 -1
- package/dist/env-bridge.d.ts +17 -0
- package/dist/env-bridge.d.ts.map +1 -0
- package/dist/env-bridge.js +211 -0
- package/dist/env-bridge.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +5 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +83 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mobile.d.ts +30 -0
- package/dist/mobile.d.ts.map +1 -0
- package/dist/mobile.js +173 -0
- package/dist/mobile.js.map +1 -0
- package/dist/rails-lifecycle.d.ts +16 -0
- package/dist/rails-lifecycle.d.ts.map +1 -0
- package/dist/rails-lifecycle.js +184 -0
- package/dist/rails-lifecycle.js.map +1 -0
- package/dist/rename-overrides.d.ts +23 -0
- package/dist/rename-overrides.d.ts.map +1 -0
- package/dist/rename-overrides.js +58 -0
- package/dist/rename-overrides.js.map +1 -0
- package/dist/repair-loop.d.ts +25 -0
- package/dist/repair-loop.d.ts.map +1 -0
- package/dist/repair-loop.js +67 -0
- package/dist/repair-loop.js.map +1 -0
- package/dist/report/collect.d.ts +28 -0
- package/dist/report/collect.d.ts.map +1 -0
- package/dist/report/collect.js +117 -0
- package/dist/report/collect.js.map +1 -0
- package/dist/report/model.d.ts +49 -0
- package/dist/report/model.d.ts.map +1 -0
- package/dist/report/model.js +2 -0
- package/dist/report/model.js.map +1 -0
- package/dist/report/render.d.ts +3 -0
- package/dist/report/render.d.ts.map +1 -0
- package/dist/report/render.js +242 -0
- package/dist/report/render.js.map +1 -0
- package/dist/report/theme.d.ts +2 -0
- package/dist/report/theme.d.ts.map +1 -0
- package/dist/report/theme.js +115 -0
- package/dist/report/theme.js.map +1 -0
- package/dist/ruby.d.ts.map +1 -1
- package/dist/ruby.js +11 -2
- package/dist/ruby.js.map +1 -1
- package/dist/slug.d.ts +3 -0
- package/dist/slug.d.ts.map +1 -1
- package/dist/slug.js +30 -0
- package/dist/slug.js.map +1 -1
- package/dist/validation/capture.d.ts.map +1 -1
- package/dist/validation/capture.js +19 -2
- package/dist/validation/capture.js.map +1 -1
- package/dist/validation/index.d.ts +6 -0
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +3 -0
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/launch.d.ts +10 -0
- package/dist/validation/launch.d.ts.map +1 -1
- package/dist/validation/launch.js +103 -5
- package/dist/validation/launch.js.map +1 -1
- package/dist/validation/layer1.d.ts.map +1 -1
- package/dist/validation/layer1.js +12 -4
- package/dist/validation/layer1.js.map +1 -1
- package/dist/validation/scenarios/queue.d.ts +12 -0
- package/dist/validation/scenarios/queue.d.ts.map +1 -0
- package/dist/validation/scenarios/queue.js +204 -0
- package/dist/validation/scenarios/queue.js.map +1 -0
- package/dist/validation/stage2-judge.d.ts +21 -0
- package/dist/validation/stage2-judge.d.ts.map +1 -0
- package/dist/validation/stage2-judge.js +204 -0
- package/dist/validation/stage2-judge.js.map +1 -0
- package/dist/validation/stage2.d.ts +73 -0
- package/dist/validation/stage2.d.ts.map +1 -0
- package/dist/validation/stage2.js +313 -0
- package/dist/validation/stage2.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +17 -0
- package/dist/version.js.map +1 -0
- package/package.json +6 -3
- package/scripts/ruby/rename.rb +18 -8
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { runStage2Scenario } from "./stage2.js";
|
|
4
|
+
import { runLayer3 } from "./layer3.js";
|
|
5
|
+
import { createMobileClient } from "../mobile.js";
|
|
6
|
+
// Stage 2 rubric — domain content (because we've now navigated to the
|
|
7
|
+
// list/detail view past auth) plus a defensive substrate-leak check.
|
|
8
|
+
// Stage 1's "renders cleanly" criterion is intentionally not repeated;
|
|
9
|
+
// if the app crashed Layer 2 build mode would have caught it.
|
|
10
|
+
export const DEFAULT_STAGE2_RUBRIC = [
|
|
11
|
+
{
|
|
12
|
+
id: "domain-content",
|
|
13
|
+
question: "Does this screen show the user's domain content (a list with at least one user-created entry, or a detail view of one such entry, with that entry's state badge visible)? PASS if there's a visible list/detail item the user just created. FAIL if it shows only a launch / welcome / login / signup / empty state.",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "no-substrate-leak",
|
|
17
|
+
question: "Is the screen free of substrate-original tokens like 'Shop', 'Shopkeeper', 'ItemTag', 'NativeAppTemplate', or 'Number Tag'?",
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
export async function runStage2Visual(input) {
|
|
21
|
+
const screenshotDir = input.screenshotDir ?? join(process.cwd(), "tmp", "screenshots");
|
|
22
|
+
await mkdir(screenshotDir, { recursive: true });
|
|
23
|
+
const rubric = input.rubric ?? DEFAULT_STAGE2_RUBRIC;
|
|
24
|
+
const result = {};
|
|
25
|
+
if (input.iosScenario) {
|
|
26
|
+
result.ios = await runOnePlatform({
|
|
27
|
+
platform: "ios",
|
|
28
|
+
scenario: input.iosScenario,
|
|
29
|
+
screenshotDir,
|
|
30
|
+
spec: input.spec,
|
|
31
|
+
rubric,
|
|
32
|
+
...(input.iosClient !== undefined ? { client: input.iosClient } : {}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (input.androidScenario) {
|
|
36
|
+
result.android = await runOnePlatform({
|
|
37
|
+
platform: "android",
|
|
38
|
+
scenario: input.androidScenario,
|
|
39
|
+
screenshotDir,
|
|
40
|
+
spec: input.spec,
|
|
41
|
+
rubric,
|
|
42
|
+
...(input.androidClient !== undefined ? { client: input.androidClient } : {}),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
async function runOnePlatform(args) {
|
|
48
|
+
const ownsClient = args.client === undefined;
|
|
49
|
+
const client = args.client ?? (await createMobileClient());
|
|
50
|
+
try {
|
|
51
|
+
// mobile-mcp requires a `device` argument on every tool call.
|
|
52
|
+
// Bootstrap: list available devices, pick the right one for this
|
|
53
|
+
// platform, set it as the active device on the wrapper. Subsequent
|
|
54
|
+
// calls inject device transparently.
|
|
55
|
+
const targetingErr = await selectDevice(client, args.platform);
|
|
56
|
+
if (targetingErr) {
|
|
57
|
+
return {
|
|
58
|
+
pass: false,
|
|
59
|
+
scenarioName: args.scenario.name,
|
|
60
|
+
stepCount: args.scenario.steps.length,
|
|
61
|
+
stepsPassed: 0,
|
|
62
|
+
screenshots: [],
|
|
63
|
+
error: targetingErr,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const scenario = await runStage2Scenario({
|
|
67
|
+
client,
|
|
68
|
+
scenario: args.scenario,
|
|
69
|
+
screenshotDir: args.screenshotDir,
|
|
70
|
+
});
|
|
71
|
+
const baseReport = toBaseReport(scenario);
|
|
72
|
+
// Run Layer 3 on the LAST captured screenshot even if a later
|
|
73
|
+
// scenario step failed — a partial walk that reached the domain
|
|
74
|
+
// content is still worth scoring. Stage2PlatformReport.pass
|
|
75
|
+
// remains gated on scenario.ok && layer3.pass below, so partial
|
|
76
|
+
// walks don't sneak through as overall PASS.
|
|
77
|
+
if (scenario.screenshots.length === 0) {
|
|
78
|
+
return baseReport;
|
|
79
|
+
}
|
|
80
|
+
const representative = scenario.screenshots[scenario.screenshots.length - 1];
|
|
81
|
+
const layer3 = await runLayer3({
|
|
82
|
+
screenshotPath: representative,
|
|
83
|
+
rubric: args.rubric,
|
|
84
|
+
spec: args.spec,
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
...baseReport,
|
|
88
|
+
pass: scenario.ok && layer3.pass,
|
|
89
|
+
representativeScreenshot: representative,
|
|
90
|
+
layer3Scores: layer3.scores,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
if (ownsClient)
|
|
95
|
+
await client.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Picks the mobile-mcp device for a platform and sets it as active on
|
|
99
|
+
// the wrapper. Returns undefined on success, an error string on
|
|
100
|
+
// failure. Heuristic: filter listDevices() by platform field if
|
|
101
|
+
// available; otherwise filter by a substring match on the name (iOS
|
|
102
|
+
// names tend to start with "iPhone"/"iPad"; Android emulators with
|
|
103
|
+
// "emulator-"). Honors NATIVEAPPTEMPLATE_MOBILE_<IOS|ANDROID>_DEVICE
|
|
104
|
+
// env var as an override for explicit targeting.
|
|
105
|
+
export async function selectDevice(client, platform) {
|
|
106
|
+
const overrideKey = platform === "ios" ? "NATIVEAPPTEMPLATE_MOBILE_IOS_DEVICE" : "NATIVEAPPTEMPLATE_MOBILE_ANDROID_DEVICE";
|
|
107
|
+
const override = process.env[overrideKey];
|
|
108
|
+
let devices;
|
|
109
|
+
try {
|
|
110
|
+
devices = await client.listDevices();
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
// Discovery failed. If an override is set, fall back to using it raw as a
|
|
114
|
+
// best-effort escape hatch; otherwise surface the failure.
|
|
115
|
+
if (override) {
|
|
116
|
+
client.useDevice(override);
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return `mobile-mcp listDevices failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
120
|
+
}
|
|
121
|
+
if (override) {
|
|
122
|
+
// Resolve the override against the device list, matching either the
|
|
123
|
+
// canonical id or the display name, and pass the id onward. mobile-mcp's
|
|
124
|
+
// per-device tools require the id (UDID for iOS sims, serial for Android);
|
|
125
|
+
// a display name like "iPhone 17" passed raw fails every call with
|
|
126
|
+
// "Device not found" (and the wrapper reads that as 0 elements). Map
|
|
127
|
+
// name -> id here instead of trusting the override string blindly.
|
|
128
|
+
const hit = devices.find((d) => deviceMatchesHandle(d, override));
|
|
129
|
+
if (hit) {
|
|
130
|
+
const id = deviceNameOf(hit);
|
|
131
|
+
if (id) {
|
|
132
|
+
client.useDevice(id);
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const seen = devices.map((d) => deviceNameOf(d) ?? "<unnamed>").join(", ");
|
|
137
|
+
return `${overrideKey}="${override}" matched no booted device (saw: ${seen}). Pass the device id or its exact name.`;
|
|
138
|
+
}
|
|
139
|
+
if (devices.length === 0) {
|
|
140
|
+
return `no mobile-mcp devices available (boot the ${platform} sim/emulator first)`;
|
|
141
|
+
}
|
|
142
|
+
const match = devices.find((d) => devicePlatformMatches(d, platform));
|
|
143
|
+
if (!match) {
|
|
144
|
+
const names = devices.map((d) => deviceNameOf(d) ?? "<unnamed>").join(", ");
|
|
145
|
+
return `no mobile-mcp device matched platform=${platform} (saw: ${names}). Override with ${overrideKey}=<device-name-or-id>.`;
|
|
146
|
+
}
|
|
147
|
+
const name = deviceNameOf(match);
|
|
148
|
+
if (!name) {
|
|
149
|
+
return `mobile-mcp returned a matching device with no usable name field`;
|
|
150
|
+
}
|
|
151
|
+
client.useDevice(name);
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
// True if `handle` equals any of the device's identifying fields — used to
|
|
155
|
+
// resolve a user-supplied override (which may be a display name OR an id)
|
|
156
|
+
// against mobile-mcp's device list.
|
|
157
|
+
function deviceMatchesHandle(d, handle) {
|
|
158
|
+
for (const key of ["id", "udid", "serial", "name", "deviceName"]) {
|
|
159
|
+
if (d[key] === handle)
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
function deviceNameOf(d) {
|
|
165
|
+
// mobile-mcp's response carries both `id` (canonical handle — UDID
|
|
166
|
+
// for iOS sims, serial for Android emulators/devices) and `name`
|
|
167
|
+
// (display name like "Pixel 6", "iPhone 17"). Pass the canonical id
|
|
168
|
+
// to the `device` parameter on subsequent tool calls — it's
|
|
169
|
+
// unambiguous when multiple devices share a display name.
|
|
170
|
+
for (const key of ["id", "udid", "serial", "name", "deviceName"]) {
|
|
171
|
+
const v = d[key];
|
|
172
|
+
if (typeof v === "string" && v.length > 0)
|
|
173
|
+
return v;
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
function devicePlatformMatches(d, platform) {
|
|
178
|
+
// Direct platform field is the easy case.
|
|
179
|
+
for (const key of ["platform", "type", "os"]) {
|
|
180
|
+
const v = d[key];
|
|
181
|
+
if (typeof v === "string" && v.toLowerCase().includes(platform))
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
// Fallback: heuristic on the name.
|
|
185
|
+
const name = deviceNameOf(d) ?? "";
|
|
186
|
+
if (platform === "ios")
|
|
187
|
+
return /^(iPhone|iPad|iPod)/i.test(name);
|
|
188
|
+
return /^(emulator-|Android|Pixel|Galaxy|Nexus)/i.test(name);
|
|
189
|
+
}
|
|
190
|
+
function toBaseReport(scenario) {
|
|
191
|
+
const stepsPassed = scenario.steps.filter((s) => s.ok).length;
|
|
192
|
+
const failingError = scenario.steps.find((s) => !s.ok)?.error;
|
|
193
|
+
const report = {
|
|
194
|
+
pass: scenario.ok,
|
|
195
|
+
scenarioName: scenario.scenarioName,
|
|
196
|
+
stepCount: scenario.steps.length,
|
|
197
|
+
stepsPassed,
|
|
198
|
+
screenshots: scenario.screenshots,
|
|
199
|
+
};
|
|
200
|
+
if (failingError !== undefined)
|
|
201
|
+
report.error = failingError;
|
|
202
|
+
return report;
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=stage2-judge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage2-judge.js","sourceRoot":"","sources":["../../src/validation/stage2-judge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { MobileClient } from "../mobile.js";
|
|
2
|
+
export type Stage2Step = {
|
|
3
|
+
kind: "wait_for_text";
|
|
4
|
+
text: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
exact?: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "tap_text";
|
|
9
|
+
text: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
optional?: boolean;
|
|
12
|
+
exact?: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "tap_coordinates";
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
label?: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "tap_below_text";
|
|
20
|
+
text: string;
|
|
21
|
+
offsetY?: number;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "type";
|
|
25
|
+
text: string;
|
|
26
|
+
submit?: boolean;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "press_button";
|
|
29
|
+
button: string;
|
|
30
|
+
optional?: boolean;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "screenshot";
|
|
33
|
+
label: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "assert_text";
|
|
36
|
+
text: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "rails_runner";
|
|
39
|
+
outDir: string;
|
|
40
|
+
ruby: string;
|
|
41
|
+
label?: string;
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "tap_field";
|
|
45
|
+
fieldTypes: readonly string[];
|
|
46
|
+
nth?: number;
|
|
47
|
+
};
|
|
48
|
+
export type Stage2Scenario = {
|
|
49
|
+
name: string;
|
|
50
|
+
steps: readonly Stage2Step[];
|
|
51
|
+
};
|
|
52
|
+
export type Stage2StepResult = {
|
|
53
|
+
step: Stage2Step;
|
|
54
|
+
ok: boolean;
|
|
55
|
+
durationMs: number;
|
|
56
|
+
error?: string;
|
|
57
|
+
screenshotPath?: string;
|
|
58
|
+
};
|
|
59
|
+
export type Stage2Result = {
|
|
60
|
+
ok: boolean;
|
|
61
|
+
scenarioName: string;
|
|
62
|
+
steps: readonly Stage2StepResult[];
|
|
63
|
+
screenshots: readonly string[];
|
|
64
|
+
};
|
|
65
|
+
export type Stage2Input = {
|
|
66
|
+
client: MobileClient;
|
|
67
|
+
scenario: Stage2Scenario;
|
|
68
|
+
screenshotDir: string;
|
|
69
|
+
pollIntervalMs?: number;
|
|
70
|
+
defaultWaitMs?: number;
|
|
71
|
+
};
|
|
72
|
+
export declare function runStage2Scenario(input: Stage2Input): Promise<Stage2Result>;
|
|
73
|
+
//# sourceMappingURL=stage2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage2.d.ts","sourceRoot":"","sources":["../../src/validation/stage2.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,cAAc,CAAC;AAsBhE,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAS5E;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3F;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAKjE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAI9E;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAOrC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAW1F;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,cAAc,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAKF,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDjF"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
5
|
+
import { scrubbedEnv } from "../env.js";
|
|
6
|
+
const DEFAULT_POLL_INTERVAL_MS = 500;
|
|
7
|
+
const DEFAULT_WAIT_MS = 10_000;
|
|
8
|
+
export async function runStage2Scenario(input) {
|
|
9
|
+
await mkdir(input.screenshotDir, { recursive: true });
|
|
10
|
+
const pollMs = input.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
11
|
+
const waitMs = input.defaultWaitMs ?? DEFAULT_WAIT_MS;
|
|
12
|
+
const stepResults = [];
|
|
13
|
+
const screenshots = [];
|
|
14
|
+
let ok = true;
|
|
15
|
+
for (let i = 0; i < input.scenario.steps.length; i++) {
|
|
16
|
+
const step = input.scenario.steps[i];
|
|
17
|
+
const started = Date.now();
|
|
18
|
+
try {
|
|
19
|
+
const screenshotPath = await runStep({
|
|
20
|
+
step,
|
|
21
|
+
index: i,
|
|
22
|
+
client: input.client,
|
|
23
|
+
scenario: input.scenario,
|
|
24
|
+
screenshotDir: input.screenshotDir,
|
|
25
|
+
pollMs,
|
|
26
|
+
waitMs,
|
|
27
|
+
});
|
|
28
|
+
const result = {
|
|
29
|
+
step,
|
|
30
|
+
ok: true,
|
|
31
|
+
durationMs: Date.now() - started,
|
|
32
|
+
};
|
|
33
|
+
if (screenshotPath) {
|
|
34
|
+
result.screenshotPath = screenshotPath;
|
|
35
|
+
screenshots.push(screenshotPath);
|
|
36
|
+
}
|
|
37
|
+
stepResults.push(result);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
ok = false;
|
|
41
|
+
stepResults.push({
|
|
42
|
+
step,
|
|
43
|
+
ok: false,
|
|
44
|
+
durationMs: Date.now() - started,
|
|
45
|
+
error: err instanceof Error ? err.message : String(err),
|
|
46
|
+
});
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
ok,
|
|
52
|
+
scenarioName: input.scenario.name,
|
|
53
|
+
steps: stepResults,
|
|
54
|
+
screenshots,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function runStep(a) {
|
|
58
|
+
switch (a.step.kind) {
|
|
59
|
+
case "wait_for_text": {
|
|
60
|
+
await waitForText(a.client, a.step.text, a.step.timeoutMs ?? a.waitMs, a.pollMs, undefined, a.step.exact);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
case "tap_text": {
|
|
64
|
+
// Prefer a Button-typed match when multiple elements share the
|
|
65
|
+
// text — tap_text implies tapping something interactive, and
|
|
66
|
+
// pages often duplicate copy between a StaticText header and a
|
|
67
|
+
// Button at the bottom (e.g. iOS sign-up form has both).
|
|
68
|
+
const optional = a.step.optional === true;
|
|
69
|
+
try {
|
|
70
|
+
const el = await waitForText(a.client, a.step.text, a.step.timeoutMs ?? a.waitMs, a.pollMs, "Button", a.step.exact);
|
|
71
|
+
const center = centerOf(el);
|
|
72
|
+
if (!center)
|
|
73
|
+
throw new Error(`tap_text "${a.step.text}": found element but could not extract coordinates`);
|
|
74
|
+
await a.client.click(center.x, center.y);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (optional)
|
|
78
|
+
return undefined;
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
case "tap_coordinates": {
|
|
84
|
+
await a.client.click(a.step.x, a.step.y);
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
case "tap_below_text": {
|
|
88
|
+
const el = await waitForText(a.client, a.step.text, a.step.timeoutMs ?? a.waitMs, a.pollMs);
|
|
89
|
+
const center = centerOf(el);
|
|
90
|
+
if (!center)
|
|
91
|
+
throw new Error(`tap_below_text "${a.step.text}": found element but could not extract coordinates`);
|
|
92
|
+
const labelHeight = labelHeightOf(el) ?? 0;
|
|
93
|
+
const offsetY = a.step.offsetY ?? 30;
|
|
94
|
+
// Bias to the center of where the field below typically sits:
|
|
95
|
+
// labelCenter.y + labelHeight/2 (bottom of label) + offsetY.
|
|
96
|
+
const targetY = center.y + labelHeight / 2 + offsetY;
|
|
97
|
+
await a.client.click(center.x, targetY);
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
case "type": {
|
|
101
|
+
await a.client.typeKeys(a.step.text, a.step.submit ?? false);
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
case "press_button": {
|
|
105
|
+
try {
|
|
106
|
+
await a.client.pressButton(a.step.button);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
if (a.step.optional)
|
|
110
|
+
return undefined;
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
case "screenshot": {
|
|
116
|
+
const filename = `${slug(a.scenario.name)}-${pad(a.index)}-${slug(a.step.label)}.png`;
|
|
117
|
+
const path = join(a.screenshotDir, filename);
|
|
118
|
+
await a.client.saveScreenshot(path);
|
|
119
|
+
return path;
|
|
120
|
+
}
|
|
121
|
+
case "assert_text": {
|
|
122
|
+
const elements = await a.client.listElements();
|
|
123
|
+
if (!findByText(elements, a.step.text)) {
|
|
124
|
+
throw new Error(`assert_text "${a.step.text}": not visible on screen`);
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
case "rails_runner": {
|
|
129
|
+
await runRailsRunner(a.step.outDir, a.step.ruby, a.step.timeoutMs ?? 30_000, a.step.label);
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
case "tap_field": {
|
|
133
|
+
const fieldTypes = a.step.fieldTypes.map((t) => t.toLowerCase());
|
|
134
|
+
const rawNth = a.step.nth ?? 0;
|
|
135
|
+
const elements = await a.client.listElements();
|
|
136
|
+
const matches = elements.filter((el) => {
|
|
137
|
+
const t = el["type"];
|
|
138
|
+
if (typeof t !== "string")
|
|
139
|
+
return false;
|
|
140
|
+
const lower = t.toLowerCase();
|
|
141
|
+
return fieldTypes.some((ft) => lower.includes(ft));
|
|
142
|
+
});
|
|
143
|
+
// Negative nth counts from the end (Python-style). Useful for
|
|
144
|
+
// cross-platform forms where the same fieldTypes list yields a
|
|
145
|
+
// different number of matches per platform: iOS Sign In has 1
|
|
146
|
+
// SecureTextField; Android has 2 EditText (Email + Password).
|
|
147
|
+
// nth=-1 = "last match" = password on both.
|
|
148
|
+
const nth = rawNth < 0 ? matches.length + rawNth : rawNth;
|
|
149
|
+
const target = matches[nth];
|
|
150
|
+
if (!target) {
|
|
151
|
+
throw new Error(`tap_field [${a.step.fieldTypes.join(",")}] (nth=${rawNth}, resolved=${nth}): no element matched (saw ${matches.length} of these types out of ${elements.length} total)`);
|
|
152
|
+
}
|
|
153
|
+
const center = centerOf(target);
|
|
154
|
+
if (!center)
|
|
155
|
+
throw new Error(`tap_field [${a.step.fieldTypes.join(",")}]: found element but could not extract coordinates`);
|
|
156
|
+
await a.client.click(center.x, center.y);
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function runRailsRunner(outDir, ruby, timeoutMs, label) {
|
|
162
|
+
await new Promise((resolveStep, rejectStep) => {
|
|
163
|
+
const child = spawn("mise", ["exec", "--", "bin/rails", "runner", ruby], {
|
|
164
|
+
cwd: outDir,
|
|
165
|
+
env: scrubbedEnv(),
|
|
166
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
167
|
+
});
|
|
168
|
+
const out = [];
|
|
169
|
+
child.stdout?.on("data", (c) => out.push(c.toString("utf8")));
|
|
170
|
+
child.stderr?.on("data", (c) => out.push(c.toString("utf8")));
|
|
171
|
+
const timer = setTimeout(() => child.kill("SIGTERM"), timeoutMs);
|
|
172
|
+
child.on("exit", (code) => {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
if (code === 0)
|
|
175
|
+
resolveStep();
|
|
176
|
+
else
|
|
177
|
+
rejectStep(new Error(`rails_runner${label ? ` (${label})` : ""} exited ${code}: ${out.join("").slice(-500)}`));
|
|
178
|
+
});
|
|
179
|
+
child.on("error", (err) => {
|
|
180
|
+
clearTimeout(timer);
|
|
181
|
+
rejectStep(err);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
async function waitForText(client, text, timeoutMs, pollMs, preferType, exact) {
|
|
186
|
+
const deadline = Date.now() + timeoutMs;
|
|
187
|
+
let lastSeen = 0;
|
|
188
|
+
while (Date.now() < deadline) {
|
|
189
|
+
const elements = await client.listElements();
|
|
190
|
+
lastSeen = elements.length;
|
|
191
|
+
const match = findByText(elements, text, preferType, exact);
|
|
192
|
+
if (match)
|
|
193
|
+
return match;
|
|
194
|
+
await sleep(pollMs);
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`wait_for_text "${text}": not found within ${timeoutMs}ms (last poll saw ${lastSeen} elements)`);
|
|
197
|
+
}
|
|
198
|
+
const TEXT_FIELDS = ["label", "name", "text", "value", "title", "accessibilityLabel", "placeholder", "identifier"];
|
|
199
|
+
function findByText(elements, needle, preferType, exact) {
|
|
200
|
+
const target = needle.toLowerCase();
|
|
201
|
+
const matches = [];
|
|
202
|
+
for (const el of elements) {
|
|
203
|
+
for (const field of TEXT_FIELDS) {
|
|
204
|
+
const v = el[field];
|
|
205
|
+
if (typeof v !== "string")
|
|
206
|
+
continue;
|
|
207
|
+
const lower = v.toLowerCase();
|
|
208
|
+
const hit = exact ? lower === target : lower.includes(target);
|
|
209
|
+
if (hit) {
|
|
210
|
+
matches.push(el);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (matches.length === 0)
|
|
216
|
+
return undefined;
|
|
217
|
+
// When the same text appears on multiple elements (e.g. "Sign Up"
|
|
218
|
+
// shows up as both a StaticText page-header AND a Button at the
|
|
219
|
+
// bottom of the form), prefer the typed match the caller asked for
|
|
220
|
+
// — typically Button for tappable intents. preferType is a
|
|
221
|
+
// case-insensitive substring match so it covers both iOS ("Button")
|
|
222
|
+
// and Android ("android.widget.Button") type strings.
|
|
223
|
+
if (preferType) {
|
|
224
|
+
const want = preferType.toLowerCase();
|
|
225
|
+
const typed = matches.find((el) => {
|
|
226
|
+
const t = el["type"];
|
|
227
|
+
return typeof t === "string" && t.toLowerCase().includes(want);
|
|
228
|
+
});
|
|
229
|
+
if (typed)
|
|
230
|
+
return typed;
|
|
231
|
+
// preferType was asked but didn't match — common on Android
|
|
232
|
+
// Compose where a submit "Button" is rendered as TextView instead
|
|
233
|
+
// of a typed widget. Fall back to the bottom-most match (submit
|
|
234
|
+
// buttons sit below page headers in every form pattern we've
|
|
235
|
+
// seen). Only do this when preferType was specified — otherwise
|
|
236
|
+
// bottom-most would pick validation messages over labels for
|
|
237
|
+
// cases like wait_for_text "Password" on a form.
|
|
238
|
+
if (matches.length > 1) {
|
|
239
|
+
const withY = matches.map((el) => ({ el, y: topYOf(el) ?? 0 }));
|
|
240
|
+
withY.sort((a, b) => b.y - a.y);
|
|
241
|
+
return withY[0].el;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return matches[0];
|
|
245
|
+
}
|
|
246
|
+
function topYOf(element) {
|
|
247
|
+
const candidates = [
|
|
248
|
+
element,
|
|
249
|
+
element["coordinates"] ?? {},
|
|
250
|
+
element["rect"] ?? {},
|
|
251
|
+
element["bounds"] ?? {},
|
|
252
|
+
element["frame"] ?? {},
|
|
253
|
+
];
|
|
254
|
+
for (const c of candidates) {
|
|
255
|
+
const y = numberAt(c, "y");
|
|
256
|
+
if (y !== undefined)
|
|
257
|
+
return y;
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
// mobile-mcp's element shape varies by platform: iOS often returns a flat
|
|
262
|
+
// {x, y, width, height}; Android sometimes nests under {rect: {...}} or
|
|
263
|
+
// {bounds: {...}}. Probe the common shapes; return undefined if none match.
|
|
264
|
+
function centerOf(element) {
|
|
265
|
+
const candidates = [
|
|
266
|
+
element,
|
|
267
|
+
// mobile-mcp 0.0.54 nests under `coordinates: {x,y,width,height}`.
|
|
268
|
+
// iOS/Android variants have used `rect`, `bounds`, `frame` over time.
|
|
269
|
+
element["coordinates"] ?? {},
|
|
270
|
+
element["rect"] ?? {},
|
|
271
|
+
element["bounds"] ?? {},
|
|
272
|
+
element["frame"] ?? {},
|
|
273
|
+
];
|
|
274
|
+
for (const c of candidates) {
|
|
275
|
+
const x = numberAt(c, "x");
|
|
276
|
+
const y = numberAt(c, "y");
|
|
277
|
+
const w = numberAt(c, "width") ?? numberAt(c, "w");
|
|
278
|
+
const h = numberAt(c, "height") ?? numberAt(c, "h");
|
|
279
|
+
if (x !== undefined && y !== undefined && w !== undefined && h !== undefined) {
|
|
280
|
+
return { x: x + w / 2, y: y + h / 2 };
|
|
281
|
+
}
|
|
282
|
+
if (x !== undefined && y !== undefined) {
|
|
283
|
+
return { x, y };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
function labelHeightOf(element) {
|
|
289
|
+
const candidates = [
|
|
290
|
+
element,
|
|
291
|
+
element["coordinates"] ?? {},
|
|
292
|
+
element["rect"] ?? {},
|
|
293
|
+
element["bounds"] ?? {},
|
|
294
|
+
element["frame"] ?? {},
|
|
295
|
+
];
|
|
296
|
+
for (const c of candidates) {
|
|
297
|
+
const h = numberAt(c, "height") ?? numberAt(c, "h");
|
|
298
|
+
if (h !== undefined)
|
|
299
|
+
return h;
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
function numberAt(obj, key) {
|
|
304
|
+
const v = obj[key];
|
|
305
|
+
return typeof v === "number" ? v : undefined;
|
|
306
|
+
}
|
|
307
|
+
function slug(s) {
|
|
308
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "step";
|
|
309
|
+
}
|
|
310
|
+
function pad(n) {
|
|
311
|
+
return n.toString().padStart(2, "0");
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=stage2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage2.js","sourceRoot":"","sources":["../../src/validation/stage2.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
// Read the agent's version from the published package.json. Resolves
|
|
5
|
+
// relative to the compiled module (dist/version.js → ../package.json),
|
|
6
|
+
// so it works under `npx`, global installs, and local dev alike.
|
|
7
|
+
export function readPackageVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const pkg = JSON.parse(readFileSync(resolve(here, "..", "package.json"), "utf8"));
|
|
11
|
+
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return "0.0.0";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,qEAAqE;AACrE,uEAAuE;AACvE,iEAAiE;AACjE,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClF,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
|