nativeapptemplate-agent 0.1.2 → 0.2.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.
- package/CLAUDE.md +10 -8
- 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 +167 -29
- 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 +31 -0
- package/dist/mobile.d.ts.map +1 -0
- package/dist/mobile.js +179 -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/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/discover.js +1 -1
- package/dist/validation/discover.js.map +1 -1
- package/dist/validation/index.d.ts +8 -2
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +4 -1
- 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 +127 -12
- 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/layer2.js +1 -1
- package/dist/validation/layer2.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 +216 -0
- package/dist/validation/scenarios/queue.js.map +1 -0
- package/dist/validation/stage1.d.ts +2 -0
- package/dist/validation/stage1.d.ts.map +1 -1
- package/dist/validation/stage1.js +2 -0
- package/dist/validation/stage1.js.map +1 -1
- package/dist/validation/stage2-judge.d.ts +23 -0
- package/dist/validation/stage2-judge.d.ts.map +1 -0
- package/dist/validation/stage2-judge.js +225 -0
- package/dist/validation/stage2-judge.js.map +1 -0
- package/dist/validation/stage2.d.ts +74 -0
- package/dist/validation/stage2.d.ts.map +1 -0
- package/dist/validation/stage2.js +328 -0
- package/dist/validation/stage2.js.map +1 -0
- package/dist/validation/visual-judge.d.ts +37 -0
- package/dist/validation/visual-judge.d.ts.map +1 -1
- package/dist/validation/visual-judge.js +100 -16
- package/dist/validation/visual-judge.js.map +1 -1
- 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 +7 -3
|
@@ -0,0 +1,328 @@
|
|
|
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
|
+
// Recover from the app's intermittent "Something went wrong" error screen.
|
|
199
|
+
// Its "Back to Start Screen" button logs out, resets login info, and returns to
|
|
200
|
+
// the welcome screen — a clean state to (re)start the walk from. Returns true
|
|
201
|
+
// if it tapped the recovery button, false if no error screen was up.
|
|
202
|
+
export async function recoverFromErrorScreen(client) {
|
|
203
|
+
const elements = await client.listElements();
|
|
204
|
+
const button = findByText(elements, "Back to Start Screen");
|
|
205
|
+
if (!button)
|
|
206
|
+
return false;
|
|
207
|
+
const center = centerOf(button);
|
|
208
|
+
if (!center)
|
|
209
|
+
return false;
|
|
210
|
+
await client.click(center.x, center.y);
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
const TEXT_FIELDS = ["label", "name", "text", "value", "title", "accessibilityLabel", "placeholder", "identifier"];
|
|
214
|
+
function findByText(elements, needle, preferType, exact) {
|
|
215
|
+
const target = needle.toLowerCase();
|
|
216
|
+
const matches = [];
|
|
217
|
+
for (const el of elements) {
|
|
218
|
+
for (const field of TEXT_FIELDS) {
|
|
219
|
+
const v = el[field];
|
|
220
|
+
if (typeof v !== "string")
|
|
221
|
+
continue;
|
|
222
|
+
const lower = v.toLowerCase();
|
|
223
|
+
const hit = exact ? lower === target : lower.includes(target);
|
|
224
|
+
if (hit) {
|
|
225
|
+
matches.push(el);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (matches.length === 0)
|
|
231
|
+
return undefined;
|
|
232
|
+
// When the same text appears on multiple elements (e.g. "Sign Up"
|
|
233
|
+
// shows up as both a StaticText page-header AND a Button at the
|
|
234
|
+
// bottom of the form), prefer the typed match the caller asked for
|
|
235
|
+
// — typically Button for tappable intents. preferType is a
|
|
236
|
+
// case-insensitive substring match so it covers both iOS ("Button")
|
|
237
|
+
// and Android ("android.widget.Button") type strings.
|
|
238
|
+
if (preferType) {
|
|
239
|
+
const want = preferType.toLowerCase();
|
|
240
|
+
const typed = matches.find((el) => {
|
|
241
|
+
const t = el["type"];
|
|
242
|
+
return typeof t === "string" && t.toLowerCase().includes(want);
|
|
243
|
+
});
|
|
244
|
+
if (typed)
|
|
245
|
+
return typed;
|
|
246
|
+
// preferType was asked but didn't match — common on Android
|
|
247
|
+
// Compose where a submit "Button" is rendered as TextView instead
|
|
248
|
+
// of a typed widget. Fall back to the bottom-most match (submit
|
|
249
|
+
// buttons sit below page headers in every form pattern we've
|
|
250
|
+
// seen). Only do this when preferType was specified — otherwise
|
|
251
|
+
// bottom-most would pick validation messages over labels for
|
|
252
|
+
// cases like wait_for_text "Password" on a form.
|
|
253
|
+
if (matches.length > 1) {
|
|
254
|
+
const withY = matches.map((el) => ({ el, y: topYOf(el) ?? 0 }));
|
|
255
|
+
withY.sort((a, b) => b.y - a.y);
|
|
256
|
+
return withY[0].el;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return matches[0];
|
|
260
|
+
}
|
|
261
|
+
function topYOf(element) {
|
|
262
|
+
const candidates = [
|
|
263
|
+
element,
|
|
264
|
+
element["coordinates"] ?? {},
|
|
265
|
+
element["rect"] ?? {},
|
|
266
|
+
element["bounds"] ?? {},
|
|
267
|
+
element["frame"] ?? {},
|
|
268
|
+
];
|
|
269
|
+
for (const c of candidates) {
|
|
270
|
+
const y = numberAt(c, "y");
|
|
271
|
+
if (y !== undefined)
|
|
272
|
+
return y;
|
|
273
|
+
}
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
// mobile-mcp's element shape varies by platform: iOS often returns a flat
|
|
277
|
+
// {x, y, width, height}; Android sometimes nests under {rect: {...}} or
|
|
278
|
+
// {bounds: {...}}. Probe the common shapes; return undefined if none match.
|
|
279
|
+
function centerOf(element) {
|
|
280
|
+
const candidates = [
|
|
281
|
+
element,
|
|
282
|
+
// mobile-mcp 0.0.54 nests under `coordinates: {x,y,width,height}`.
|
|
283
|
+
// iOS/Android variants have used `rect`, `bounds`, `frame` over time.
|
|
284
|
+
element["coordinates"] ?? {},
|
|
285
|
+
element["rect"] ?? {},
|
|
286
|
+
element["bounds"] ?? {},
|
|
287
|
+
element["frame"] ?? {},
|
|
288
|
+
];
|
|
289
|
+
for (const c of candidates) {
|
|
290
|
+
const x = numberAt(c, "x");
|
|
291
|
+
const y = numberAt(c, "y");
|
|
292
|
+
const w = numberAt(c, "width") ?? numberAt(c, "w");
|
|
293
|
+
const h = numberAt(c, "height") ?? numberAt(c, "h");
|
|
294
|
+
if (x !== undefined && y !== undefined && w !== undefined && h !== undefined) {
|
|
295
|
+
return { x: x + w / 2, y: y + h / 2 };
|
|
296
|
+
}
|
|
297
|
+
if (x !== undefined && y !== undefined) {
|
|
298
|
+
return { x, y };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
function labelHeightOf(element) {
|
|
304
|
+
const candidates = [
|
|
305
|
+
element,
|
|
306
|
+
element["coordinates"] ?? {},
|
|
307
|
+
element["rect"] ?? {},
|
|
308
|
+
element["bounds"] ?? {},
|
|
309
|
+
element["frame"] ?? {},
|
|
310
|
+
];
|
|
311
|
+
for (const c of candidates) {
|
|
312
|
+
const h = numberAt(c, "height") ?? numberAt(c, "h");
|
|
313
|
+
if (h !== undefined)
|
|
314
|
+
return h;
|
|
315
|
+
}
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
function numberAt(obj, key) {
|
|
319
|
+
const v = obj[key];
|
|
320
|
+
return typeof v === "number" ? v : undefined;
|
|
321
|
+
}
|
|
322
|
+
function slug(s) {
|
|
323
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "step";
|
|
324
|
+
}
|
|
325
|
+
function pad(n) {
|
|
326
|
+
return n.toString().padStart(2, "0");
|
|
327
|
+
}
|
|
328
|
+
//# 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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"}
|
|
@@ -10,6 +10,10 @@ export type VisualJudgeInput = {
|
|
|
10
10
|
spec: string;
|
|
11
11
|
rubric: readonly Layer3Criterion[];
|
|
12
12
|
renderWaitMs?: number;
|
|
13
|
+
stabilityIntervalMs?: number;
|
|
14
|
+
stabilityTimeoutMs?: number;
|
|
15
|
+
maxJudgeRetries?: number;
|
|
16
|
+
recover?: () => Promise<void>;
|
|
13
17
|
samplesPerCriterion?: number;
|
|
14
18
|
model?: string;
|
|
15
19
|
};
|
|
@@ -21,5 +25,38 @@ export type VisualJudgeResult = {
|
|
|
21
25
|
error?: string;
|
|
22
26
|
};
|
|
23
27
|
export declare function runVisualJudge(input: VisualJudgeInput): Promise<VisualJudgeResult>;
|
|
28
|
+
export type StableCaptureDeps = {
|
|
29
|
+
captureOnce: () => Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
bytes?: Buffer;
|
|
32
|
+
error?: string;
|
|
33
|
+
}>;
|
|
34
|
+
sleep: (ms: number) => Promise<void>;
|
|
35
|
+
now: () => number;
|
|
36
|
+
};
|
|
37
|
+
export declare function waitForStableCapture(deps: StableCaptureDeps, opts: {
|
|
38
|
+
intervalMs: number;
|
|
39
|
+
maxWaitMs: number;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
ok: boolean;
|
|
42
|
+
settled: boolean;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function isTransientRenderFail(layer3: Layer3Result): boolean;
|
|
46
|
+
export type JudgeRetryDeps = {
|
|
47
|
+
settleCapture: () => Promise<{
|
|
48
|
+
ok: boolean;
|
|
49
|
+
error?: string;
|
|
50
|
+
}>;
|
|
51
|
+
judge: () => Promise<Layer3Result>;
|
|
52
|
+
recover?: () => Promise<void>;
|
|
53
|
+
};
|
|
54
|
+
export declare function judgeWithRetry(deps: JudgeRetryDeps, opts: {
|
|
55
|
+
maxRetries: number;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
ok: boolean;
|
|
58
|
+
layer3?: Layer3Result;
|
|
59
|
+
error?: string;
|
|
60
|
+
}>;
|
|
24
61
|
export declare const DEFAULT_STAGE1_RUBRIC: readonly Layer3Criterion[];
|
|
25
62
|
//# sourceMappingURL=visual-judge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-judge.d.ts","sourceRoot":"","sources":["../../src/validation/visual-judge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"visual-judge.d.ts","sourceRoot":"","sources":["../../src/validation/visual-judge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,eAAe,CAAC;IAE1B,YAAY,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;IAGnC,YAAY,CAAC,EAAE,MAAM,CAAC;IAItB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAK5B,eAAe,CAAC,EAAE,MAAM,CAAC;IAIzB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAsBF,wBAAsB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiFxF;AAKD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB5D;AAMD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAInE;AAOD,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAInC,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,CAAC;AAEF,wBAAsB,cAAc,CAClC,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBjE;AAeD,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAW3D,CAAC"}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { runLayer3 } from "./layer3.js";
|
|
3
4
|
import { captureScreenshot } from "./capture.js";
|
|
4
5
|
import { installAndLaunch } from "./launch.js";
|
|
5
6
|
const DEFAULT_RENDER_WAIT_MS = 3_000;
|
|
7
|
+
const DEFAULT_STABILITY_INTERVAL_MS = 700;
|
|
8
|
+
const DEFAULT_STABILITY_TIMEOUT_MS = 8_000;
|
|
9
|
+
const DEFAULT_MAX_JUDGE_RETRIES = 1;
|
|
10
|
+
// Criteria whose failure is plausibly a transient bad capture (mid-transition
|
|
11
|
+
// frame) rather than a deterministic content problem — safe to retry with a
|
|
12
|
+
// fresh capture. Substrate-leak is content-based and NOT in here.
|
|
13
|
+
const RETRYABLE_CRITERIA = new Set(["renders-cleanly"]);
|
|
6
14
|
// End-to-end Stage 1 visual judge for one platform:
|
|
7
15
|
// 1. install + launch the built app on the booted sim/emulator
|
|
8
16
|
// 2. wait for render
|
|
@@ -33,31 +41,107 @@ export async function runVisualJudge(input) {
|
|
|
33
41
|
};
|
|
34
42
|
}
|
|
35
43
|
await sleep(input.renderWaitMs ?? DEFAULT_RENDER_WAIT_MS);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
44
|
+
const stabilityOpts = {
|
|
45
|
+
intervalMs: input.stabilityIntervalMs ?? DEFAULT_STABILITY_INTERVAL_MS,
|
|
46
|
+
maxWaitMs: input.stabilityTimeoutMs ?? DEFAULT_STABILITY_TIMEOUT_MS,
|
|
47
|
+
};
|
|
48
|
+
// Settle the screen (two consecutive byte-identical frames) before judging,
|
|
49
|
+
// and retry the settle+judge if the judge fails *only* on transient render
|
|
50
|
+
// quality — a fresh frame may render clean. See judgeWithRetry.
|
|
51
|
+
const result = await judgeWithRetry({
|
|
52
|
+
settleCapture: async () => {
|
|
53
|
+
// Each capture overwrites screenshotPath, so on success it holds the
|
|
54
|
+
// settled (or last) frame the judge then reads.
|
|
55
|
+
const stable = await waitForStableCapture({
|
|
56
|
+
captureOnce: async () => {
|
|
57
|
+
const c = await captureScreenshot({ platform: input.platform, outPath: input.screenshotPath });
|
|
58
|
+
if (!c.ok)
|
|
59
|
+
return { ok: false, ...(c.error !== undefined ? { error: c.error } : {}) };
|
|
60
|
+
try {
|
|
61
|
+
return { ok: true, bytes: await readFile(input.screenshotPath) };
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
sleep: (ms) => sleep(ms),
|
|
68
|
+
now: () => Date.now(),
|
|
69
|
+
}, stabilityOpts);
|
|
70
|
+
return stable.ok ? { ok: true } : { ok: false, ...(stable.error !== undefined ? { error: stable.error } : {}) };
|
|
71
|
+
},
|
|
72
|
+
judge: () => runLayer3({
|
|
73
|
+
screenshotPath: input.screenshotPath,
|
|
74
|
+
rubric: input.rubric,
|
|
75
|
+
spec: input.spec,
|
|
76
|
+
...(input.samplesPerCriterion !== undefined ? { samplesPerCriterion: input.samplesPerCriterion } : {}),
|
|
77
|
+
...(input.model !== undefined ? { model: input.model } : {}),
|
|
78
|
+
}),
|
|
79
|
+
...(input.recover !== undefined ? { recover: input.recover } : {}),
|
|
80
|
+
}, { maxRetries: input.maxJudgeRetries ?? DEFAULT_MAX_JUDGE_RETRIES });
|
|
81
|
+
if (!result.ok || result.layer3 === undefined) {
|
|
41
82
|
return {
|
|
42
83
|
ok: false,
|
|
43
84
|
launch,
|
|
44
|
-
error: `screenshot capture failed: ${
|
|
85
|
+
error: `screenshot capture failed: ${result.error ?? "unknown"}`,
|
|
45
86
|
};
|
|
46
87
|
}
|
|
47
|
-
const layer3 = await runLayer3({
|
|
48
|
-
screenshotPath: capture.path,
|
|
49
|
-
rubric: input.rubric,
|
|
50
|
-
spec: input.spec,
|
|
51
|
-
...(input.samplesPerCriterion !== undefined ? { samplesPerCriterion: input.samplesPerCriterion } : {}),
|
|
52
|
-
...(input.model !== undefined ? { model: input.model } : {}),
|
|
53
|
-
});
|
|
54
88
|
return {
|
|
55
|
-
ok: layer3.pass,
|
|
89
|
+
ok: result.layer3.pass,
|
|
56
90
|
launch,
|
|
57
|
-
screenshotPath:
|
|
58
|
-
layer3,
|
|
91
|
+
screenshotPath: input.screenshotPath,
|
|
92
|
+
layer3: result.layer3,
|
|
59
93
|
};
|
|
60
94
|
}
|
|
95
|
+
export async function waitForStableCapture(deps, opts) {
|
|
96
|
+
const deadline = deps.now() + opts.maxWaitMs;
|
|
97
|
+
let prev;
|
|
98
|
+
for (;;) {
|
|
99
|
+
const cap = await deps.captureOnce();
|
|
100
|
+
if (!cap.ok) {
|
|
101
|
+
return { ok: false, settled: false, ...(cap.error !== undefined ? { error: cap.error } : {}) };
|
|
102
|
+
}
|
|
103
|
+
if (prev !== undefined && cap.bytes !== undefined && cap.bytes.equals(prev)) {
|
|
104
|
+
return { ok: true, settled: true };
|
|
105
|
+
}
|
|
106
|
+
prev = cap.bytes;
|
|
107
|
+
if (deps.now() >= deadline) {
|
|
108
|
+
return { ok: true, settled: false }; // cap hit — accept the last frame
|
|
109
|
+
}
|
|
110
|
+
await deps.sleep(opts.intervalMs);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// True when the judge failed and *every* failing criterion is retry-safe
|
|
114
|
+
// (transient render quality), so a fresh capture might pass. A content failure
|
|
115
|
+
// (e.g. substrate-leak) is deterministic — re-capturing the same screen won't
|
|
116
|
+
// change it — so this returns false and the caller won't waste a judge pass.
|
|
117
|
+
export function isTransientRenderFail(layer3) {
|
|
118
|
+
if (layer3.pass)
|
|
119
|
+
return false;
|
|
120
|
+
const failing = layer3.scores.filter((s) => !s.pass);
|
|
121
|
+
return failing.length > 0 && failing.every((s) => RETRYABLE_CRITERIA.has(s.criterionId));
|
|
122
|
+
}
|
|
123
|
+
export async function judgeWithRetry(deps, opts) {
|
|
124
|
+
const first = await deps.settleCapture();
|
|
125
|
+
if (!first.ok) {
|
|
126
|
+
return { ok: false, ...(first.error !== undefined ? { error: first.error } : {}) };
|
|
127
|
+
}
|
|
128
|
+
let layer3 = await deps.judge();
|
|
129
|
+
let retries = 0;
|
|
130
|
+
while (!layer3.pass && retries < opts.maxRetries && isTransientRenderFail(layer3)) {
|
|
131
|
+
retries++;
|
|
132
|
+
if (deps.recover) {
|
|
133
|
+
try {
|
|
134
|
+
await deps.recover();
|
|
135
|
+
}
|
|
136
|
+
catch { /* best-effort recovery */ }
|
|
137
|
+
}
|
|
138
|
+
const re = await deps.settleCapture();
|
|
139
|
+
if (!re.ok)
|
|
140
|
+
break; // capture failed on retry — keep the prior judgement
|
|
141
|
+
layer3 = await deps.judge();
|
|
142
|
+
}
|
|
143
|
+
return { ok: true, layer3 };
|
|
144
|
+
}
|
|
61
145
|
// Default Stage 1 rubric — two Yes/No criteria covering substrate-leak
|
|
62
146
|
// detection and basic render sanity. Phrased so pass=true is the desired
|
|
63
147
|
// state on every criterion.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-judge.js","sourceRoot":"","sources":["../../src/validation/visual-judge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAA2C,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAwB,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAqB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"visual-judge.js","sourceRoot":"","sources":["../../src/validation/visual-judge.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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nativeapptemplate-agent",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "A Claude Code agent that turns a natural-language SaaS spec into a working three-platform implementation (Rails API + SwiftUI iOS + Jetpack Compose Android).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"nativeapptemplate-agent": "dist/index.js"
|
|
8
|
+
"nativeapptemplate-agent": "dist/index.js",
|
|
9
|
+
"nativeapptemplate-agent-mcp": "dist/mcp.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist/",
|
|
@@ -64,6 +65,8 @@
|
|
|
64
65
|
"dependencies": {
|
|
65
66
|
"@anthropic-ai/claude-agent-sdk": "^0.2.114",
|
|
66
67
|
"@anthropic-ai/sdk": "^0.90.0",
|
|
67
|
-
"
|
|
68
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
69
|
+
"yaml": "^2.8.4",
|
|
70
|
+
"zod": "^4.3.6"
|
|
68
71
|
}
|
|
69
72
|
}
|