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.
Files changed (99) hide show
  1. package/CLAUDE.md +9 -7
  2. package/README.md +65 -21
  3. package/dist/agents/judge.d.ts +8 -0
  4. package/dist/agents/judge.d.ts.map +1 -1
  5. package/dist/agents/judge.js +100 -14
  6. package/dist/agents/judge.js.map +1 -1
  7. package/dist/agents/repair.d.ts +14 -0
  8. package/dist/agents/repair.d.ts.map +1 -0
  9. package/dist/agents/repair.js +103 -0
  10. package/dist/agents/repair.js.map +1 -0
  11. package/dist/agents/types.d.ts +34 -1
  12. package/dist/agents/types.d.ts.map +1 -1
  13. package/dist/dispatch.d.ts +21 -2
  14. package/dist/dispatch.d.ts.map +1 -1
  15. package/dist/dispatch.js +250 -14
  16. package/dist/dispatch.js.map +1 -1
  17. package/dist/env-bridge.d.ts +17 -0
  18. package/dist/env-bridge.d.ts.map +1 -0
  19. package/dist/env-bridge.js +211 -0
  20. package/dist/env-bridge.js.map +1 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +88 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/mcp.d.ts +5 -0
  26. package/dist/mcp.d.ts.map +1 -0
  27. package/dist/mcp.js +83 -0
  28. package/dist/mcp.js.map +1 -0
  29. package/dist/mobile.d.ts +30 -0
  30. package/dist/mobile.d.ts.map +1 -0
  31. package/dist/mobile.js +173 -0
  32. package/dist/mobile.js.map +1 -0
  33. package/dist/rails-lifecycle.d.ts +16 -0
  34. package/dist/rails-lifecycle.d.ts.map +1 -0
  35. package/dist/rails-lifecycle.js +184 -0
  36. package/dist/rails-lifecycle.js.map +1 -0
  37. package/dist/rename-overrides.d.ts +23 -0
  38. package/dist/rename-overrides.d.ts.map +1 -0
  39. package/dist/rename-overrides.js +58 -0
  40. package/dist/rename-overrides.js.map +1 -0
  41. package/dist/repair-loop.d.ts +25 -0
  42. package/dist/repair-loop.d.ts.map +1 -0
  43. package/dist/repair-loop.js +67 -0
  44. package/dist/repair-loop.js.map +1 -0
  45. package/dist/report/collect.d.ts +28 -0
  46. package/dist/report/collect.d.ts.map +1 -0
  47. package/dist/report/collect.js +117 -0
  48. package/dist/report/collect.js.map +1 -0
  49. package/dist/report/model.d.ts +49 -0
  50. package/dist/report/model.d.ts.map +1 -0
  51. package/dist/report/model.js +2 -0
  52. package/dist/report/model.js.map +1 -0
  53. package/dist/report/render.d.ts +3 -0
  54. package/dist/report/render.d.ts.map +1 -0
  55. package/dist/report/render.js +242 -0
  56. package/dist/report/render.js.map +1 -0
  57. package/dist/report/theme.d.ts +2 -0
  58. package/dist/report/theme.d.ts.map +1 -0
  59. package/dist/report/theme.js +115 -0
  60. package/dist/report/theme.js.map +1 -0
  61. package/dist/ruby.d.ts.map +1 -1
  62. package/dist/ruby.js +11 -2
  63. package/dist/ruby.js.map +1 -1
  64. package/dist/slug.d.ts +3 -0
  65. package/dist/slug.d.ts.map +1 -1
  66. package/dist/slug.js +30 -0
  67. package/dist/slug.js.map +1 -1
  68. package/dist/validation/capture.d.ts.map +1 -1
  69. package/dist/validation/capture.js +19 -2
  70. package/dist/validation/capture.js.map +1 -1
  71. package/dist/validation/index.d.ts +6 -0
  72. package/dist/validation/index.d.ts.map +1 -1
  73. package/dist/validation/index.js +3 -0
  74. package/dist/validation/index.js.map +1 -1
  75. package/dist/validation/launch.d.ts +10 -0
  76. package/dist/validation/launch.d.ts.map +1 -1
  77. package/dist/validation/launch.js +103 -5
  78. package/dist/validation/launch.js.map +1 -1
  79. package/dist/validation/layer1.d.ts.map +1 -1
  80. package/dist/validation/layer1.js +12 -4
  81. package/dist/validation/layer1.js.map +1 -1
  82. package/dist/validation/scenarios/queue.d.ts +12 -0
  83. package/dist/validation/scenarios/queue.d.ts.map +1 -0
  84. package/dist/validation/scenarios/queue.js +204 -0
  85. package/dist/validation/scenarios/queue.js.map +1 -0
  86. package/dist/validation/stage2-judge.d.ts +21 -0
  87. package/dist/validation/stage2-judge.d.ts.map +1 -0
  88. package/dist/validation/stage2-judge.js +204 -0
  89. package/dist/validation/stage2-judge.js.map +1 -0
  90. package/dist/validation/stage2.d.ts +73 -0
  91. package/dist/validation/stage2.d.ts.map +1 -0
  92. package/dist/validation/stage2.js +313 -0
  93. package/dist/validation/stage2.js.map +1 -0
  94. package/dist/version.d.ts +2 -0
  95. package/dist/version.d.ts.map +1 -0
  96. package/dist/version.js +17 -0
  97. package/dist/version.js.map +1 -0
  98. package/package.json +6 -3
  99. 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":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAA0C,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAyC,MAAM,cAAc,CAAC;AA2CzF,sEAAsE;AACtE,qEAAqE;AACrE,uEAAuE;AACvE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,qBAAqB,GAA+B;IAC/D;QACE,EAAE,EAAE,gBAAgB;QACpB,QAAQ,EACN,sTAAsT;KACzT;IACD;QACE,EAAE,EAAE,mBAAmB;QACvB,QAAQ,EACN,6HAA6H;KAChI;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAwB;IAC5D,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;IACvF,MAAM,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,qBAAqB,CAAC;IAErD,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAAG,MAAM,cAAc,CAAC;YAChC,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,KAAK,CAAC,WAAW;YAC3B,aAAa;YACb,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM;YACN,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QAC1B,MAAM,CAAC,OAAO,GAAG,MAAM,cAAc,CAAC;YACpC,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK,CAAC,eAAe;YAC/B,aAAa;YACb,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM;YACN,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAWD,KAAK,UAAU,cAAc,CAAC,IAAgB;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,kBAAkB,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,8DAA8D;QAC9D,iEAAiE;QACjE,mEAAmE;QACnE,qCAAqC;QACrC,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO;gBACL,IAAI,EAAE,KAAK;gBACX,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBAChC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM;gBACrC,WAAW,EAAE,CAAC;gBACd,WAAW,EAAE,EAAE;gBACf,KAAK,EAAE,YAAY;aACpB,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC;YACvC,MAAM;YACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE1C,8DAA8D;QAC9D,gEAAgE;QAChE,4DAA4D;QAC5D,gEAAgE;QAChE,6CAA6C;QAC7C,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;YAC7B,cAAc,EAAE,cAAc;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,UAAU;YACb,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,MAAM,CAAC,IAAI;YAChC,wBAAwB,EAAE,cAAc;YACxC,YAAY,EAAE,MAAM,CAAC,MAAM;SAC5B,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,UAAU;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,gEAAgE;AAChE,gEAAgE;AAChE,oEAAoE;AACpE,mEAAmE;AACnE,qEAAqE;AACrE,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAoB,EACpB,QAA2B;IAE3B,MAAM,WAAW,GACf,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,yCAAyC,CAAC;IACzG,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE1C,IAAI,OAAiC,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,2DAA2D;QAC3D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9F,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,oEAAoE;QACpE,yEAAyE;QACzE,2EAA2E;QAC3E,mEAAmE;QACnE,qEAAqE;QACrE,mEAAmE;QACnE,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QAClE,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,EAAE,EAAE,CAAC;gBACP,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBACrB,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,OAAO,GAAG,WAAW,KAAK,QAAQ,oCAAoC,IAAI,0CAA0C,CAAC;IACvH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,6CAA6C,QAAQ,sBAAsB,CAAC;IACrF,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,OAAO,yCAAyC,QAAQ,UAAU,KAAK,oBAAoB,WAAW,uBAAuB,CAAC;IAChI,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,iEAAiE,CAAC;IAC3E,CAAC;IACD,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2EAA2E;AAC3E,0EAA0E;AAC1E,oCAAoC;AACpC,SAAS,mBAAmB,CAAC,CAAgB,EAAE,MAAc;IAC3D,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAU,EAAE,CAAC;QAC1E,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,CAAgB;IACpC,mEAAmE;IACnE,iEAAiE;IACjE,oEAAoE;IACpE,4DAA4D;IAC5D,0DAA0D;IAC1D,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAU,EAAE,CAAC;QAC1E,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,qBAAqB,CAAC,CAAgB,EAAE,QAA2B;IAC1E,0CAA0C;IAC1C,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAU,EAAE,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IAC/E,CAAC;IACD,mCAAmC;IACnC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,0CAA0C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,YAAY,CAAC,QAAsB;IAC1C,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;IAC9D,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;IAC9D,MAAM,MAAM,GAAyB;QACnC,IAAI,EAAE,QAAQ,CAAC,EAAE;QACjB,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM;QAChC,WAAW;QACX,WAAW,EAAE,QAAQ,CAAC,WAAW;KAClC,CAAC;IACF,IAAI,YAAY,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,YAAY,CAAC;IAC5D,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -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,2 @@
1
+ export declare function readPackageVersion(): string;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C"}
@@ -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"}