swipium 1.0.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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/appMap/automationLink.js +74 -0
  4. package/dist/appMap/automationLink.js.map +1 -0
  5. package/dist/appMap/build.js +193 -0
  6. package/dist/appMap/build.js.map +1 -0
  7. package/dist/appMap/codeIndex.js +73 -0
  8. package/dist/appMap/codeIndex.js.map +1 -0
  9. package/dist/appMap/featureModel.js +83 -0
  10. package/dist/appMap/featureModel.js.map +1 -0
  11. package/dist/appMap/firstRunApply.js +131 -0
  12. package/dist/appMap/firstRunApply.js.map +1 -0
  13. package/dist/appMap/fsWalk.js +75 -0
  14. package/dist/appMap/fsWalk.js.map +1 -0
  15. package/dist/appMap/issues.js +227 -0
  16. package/dist/appMap/issues.js.map +1 -0
  17. package/dist/appMap/migrations.js +87 -0
  18. package/dist/appMap/migrations.js.map +1 -0
  19. package/dist/appMap/prelaunch.js +66 -0
  20. package/dist/appMap/prelaunch.js.map +1 -0
  21. package/dist/appMap/projectRegistry.js +70 -0
  22. package/dist/appMap/projectRegistry.js.map +1 -0
  23. package/dist/appMap/provenance.js +52 -0
  24. package/dist/appMap/provenance.js.map +1 -0
  25. package/dist/appMap/query.js +118 -0
  26. package/dist/appMap/query.js.map +1 -0
  27. package/dist/appMap/runtimeMerge.js +207 -0
  28. package/dist/appMap/runtimeMerge.js.map +1 -0
  29. package/dist/appMap/schema.js +65 -0
  30. package/dist/appMap/schema.js.map +1 -0
  31. package/dist/appMap/screenMatch.js +75 -0
  32. package/dist/appMap/screenMatch.js.map +1 -0
  33. package/dist/appMap/staticScan.js +614 -0
  34. package/dist/appMap/staticScan.js.map +1 -0
  35. package/dist/appMap/store.js +173 -0
  36. package/dist/appMap/store.js.map +1 -0
  37. package/dist/appMap/tsAstScan.js +184 -0
  38. package/dist/appMap/tsAstScan.js.map +1 -0
  39. package/dist/artifacts/bundletool.js +199 -0
  40. package/dist/artifacts/bundletool.js.map +1 -0
  41. package/dist/artifacts/resolve.js +388 -0
  42. package/dist/artifacts/resolve.js.map +1 -0
  43. package/dist/automationGen/appiumModel.js +129 -0
  44. package/dist/automationGen/appiumModel.js.map +1 -0
  45. package/dist/automationGen/ciEmitter.js +80 -0
  46. package/dist/automationGen/ciEmitter.js.map +1 -0
  47. package/dist/automationGen/jsEmitter.js +440 -0
  48. package/dist/automationGen/jsEmitter.js.map +1 -0
  49. package/dist/automationGen/packagePatch.js +56 -0
  50. package/dist/automationGen/packagePatch.js.map +1 -0
  51. package/dist/automationGen/projectProfile.js +317 -0
  52. package/dist/automationGen/projectProfile.js.map +1 -0
  53. package/dist/automationGen/pythonEmitter.js +386 -0
  54. package/dist/automationGen/pythonEmitter.js.map +1 -0
  55. package/dist/automationGen/readmeEmitter.js +66 -0
  56. package/dist/automationGen/readmeEmitter.js.map +1 -0
  57. package/dist/automationGen/suitePlan.js +94 -0
  58. package/dist/automationGen/suitePlan.js.map +1 -0
  59. package/dist/automationGen/validation.js +150 -0
  60. package/dist/automationGen/validation.js.map +1 -0
  61. package/dist/build/parseBuildLog.js +119 -0
  62. package/dist/build/parseBuildLog.js.map +1 -0
  63. package/dist/build/plan.js +150 -0
  64. package/dist/build/plan.js.map +1 -0
  65. package/dist/ci/preflight.js +85 -0
  66. package/dist/ci/preflight.js.map +1 -0
  67. package/dist/cli/init.js +105 -0
  68. package/dist/cli/init.js.map +1 -0
  69. package/dist/cli/scan.js +85 -0
  70. package/dist/cli/scan.js.map +1 -0
  71. package/dist/cli/suite.js +85 -0
  72. package/dist/cli/suite.js.map +1 -0
  73. package/dist/cli/verify.js +62 -0
  74. package/dist/cli/verify.js.map +1 -0
  75. package/dist/consent/consent.js +43 -0
  76. package/dist/consent/consent.js.map +1 -0
  77. package/dist/context/detect.js +156 -0
  78. package/dist/context/detect.js.map +1 -0
  79. package/dist/context/findApps.js +198 -0
  80. package/dist/context/findApps.js.map +1 -0
  81. package/dist/context/projectRoot.js +41 -0
  82. package/dist/context/projectRoot.js.map +1 -0
  83. package/dist/context/scan.js +167 -0
  84. package/dist/context/scan.js.map +1 -0
  85. package/dist/core/target.js +115 -0
  86. package/dist/core/target.js.map +1 -0
  87. package/dist/core/targetPlan.js +140 -0
  88. package/dist/core/targetPlan.js.map +1 -0
  89. package/dist/drivers/DirectDriver.js +228 -0
  90. package/dist/drivers/DirectDriver.js.map +1 -0
  91. package/dist/drivers/Driver.js +4 -0
  92. package/dist/drivers/Driver.js.map +1 -0
  93. package/dist/drivers/SimctlDriver.js +127 -0
  94. package/dist/drivers/SimctlDriver.js.map +1 -0
  95. package/dist/drivers/WdaDriver.js +250 -0
  96. package/dist/drivers/WdaDriver.js.map +1 -0
  97. package/dist/explore/candidates.js +93 -0
  98. package/dist/explore/candidates.js.map +1 -0
  99. package/dist/explore/graph.js +116 -0
  100. package/dist/explore/graph.js.map +1 -0
  101. package/dist/explore/memory.js +35 -0
  102. package/dist/explore/memory.js.map +1 -0
  103. package/dist/explore/planner.js +105 -0
  104. package/dist/explore/planner.js.map +1 -0
  105. package/dist/explore/policy.js +85 -0
  106. package/dist/explore/policy.js.map +1 -0
  107. package/dist/explore/runner.js +475 -0
  108. package/dist/explore/runner.js.map +1 -0
  109. package/dist/explore/signatures.js +35 -0
  110. package/dist/explore/signatures.js.map +1 -0
  111. package/dist/explore/suite.js +55 -0
  112. package/dist/explore/suite.js.map +1 -0
  113. package/dist/featureTesting/executionBootstrap.js +140 -0
  114. package/dist/featureTesting/executionBootstrap.js.map +1 -0
  115. package/dist/firstRun/authStateMachine.js +83 -0
  116. package/dist/firstRun/authStateMachine.js.map +1 -0
  117. package/dist/firstRun/classifyScreen.js +201 -0
  118. package/dist/firstRun/classifyScreen.js.map +1 -0
  119. package/dist/firstRun/firstRunPlanner.js +207 -0
  120. package/dist/firstRun/firstRunPlanner.js.map +1 -0
  121. package/dist/firstRun/firstRunRunner.js +331 -0
  122. package/dist/firstRun/firstRunRunner.js.map +1 -0
  123. package/dist/firstRun/generatedDataPolicy.js +215 -0
  124. package/dist/firstRun/generatedDataPolicy.js.map +1 -0
  125. package/dist/firstRun/inputPlanner.js +67 -0
  126. package/dist/firstRun/inputPlanner.js.map +1 -0
  127. package/dist/firstRun/onboardingStateMachine.js +46 -0
  128. package/dist/firstRun/onboardingStateMachine.js.map +1 -0
  129. package/dist/firstRun/paywallPolicy.js +54 -0
  130. package/dist/firstRun/paywallPolicy.js.map +1 -0
  131. package/dist/firstRun/types.js +7 -0
  132. package/dist/firstRun/types.js.map +1 -0
  133. package/dist/fixtures/catalog.js +131 -0
  134. package/dist/fixtures/catalog.js.map +1 -0
  135. package/dist/flows/discover.js +18 -0
  136. package/dist/flows/discover.js.map +1 -0
  137. package/dist/flows/generate.js +211 -0
  138. package/dist/flows/generate.js.map +1 -0
  139. package/dist/flows/lint.js +97 -0
  140. package/dist/flows/lint.js.map +1 -0
  141. package/dist/flows/pack.js +68 -0
  142. package/dist/flows/pack.js.map +1 -0
  143. package/dist/flows/run.js +738 -0
  144. package/dist/flows/run.js.map +1 -0
  145. package/dist/flows/schema.js +240 -0
  146. package/dist/flows/schema.js.map +1 -0
  147. package/dist/flows/seedExec.js +108 -0
  148. package/dist/flows/seedExec.js.map +1 -0
  149. package/dist/flows/templates.js +155 -0
  150. package/dist/flows/templates.js.map +1 -0
  151. package/dist/flows/waitGuards.js +12 -0
  152. package/dist/flows/waitGuards.js.map +1 -0
  153. package/dist/index.js +33 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/ios/signing.js +182 -0
  156. package/dist/ios/signing.js.map +1 -0
  157. package/dist/issues/classify.js +186 -0
  158. package/dist/issues/classify.js.map +1 -0
  159. package/dist/issues/fingerprint.js +130 -0
  160. package/dist/issues/fingerprint.js.map +1 -0
  161. package/dist/issues/index.js +240 -0
  162. package/dist/issues/index.js.map +1 -0
  163. package/dist/issues/metrics.js +155 -0
  164. package/dist/issues/metrics.js.map +1 -0
  165. package/dist/issues/recurrence.js +193 -0
  166. package/dist/issues/recurrence.js.map +1 -0
  167. package/dist/issues/report.js +110 -0
  168. package/dist/issues/report.js.map +1 -0
  169. package/dist/issues/reportBridge.js +119 -0
  170. package/dist/issues/reportBridge.js.map +1 -0
  171. package/dist/issues/schema.js +90 -0
  172. package/dist/issues/schema.js.map +1 -0
  173. package/dist/issues/sourceRevision.js +108 -0
  174. package/dist/issues/sourceRevision.js.map +1 -0
  175. package/dist/issues/store.js +155 -0
  176. package/dist/issues/store.js.map +1 -0
  177. package/dist/lib/android.js +278 -0
  178. package/dist/lib/android.js.map +1 -0
  179. package/dist/lib/commandTemplate.js +55 -0
  180. package/dist/lib/commandTemplate.js.map +1 -0
  181. package/dist/lib/coordSpace.js +23 -0
  182. package/dist/lib/coordSpace.js.map +1 -0
  183. package/dist/lib/device.js +87 -0
  184. package/dist/lib/device.js.map +1 -0
  185. package/dist/lib/gitignore.js +22 -0
  186. package/dist/lib/gitignore.js.map +1 -0
  187. package/dist/lib/image.js +97 -0
  188. package/dist/lib/image.js.map +1 -0
  189. package/dist/lib/logger.js +8 -0
  190. package/dist/lib/logger.js.map +1 -0
  191. package/dist/lib/metroState.js +45 -0
  192. package/dist/lib/metroState.js.map +1 -0
  193. package/dist/lib/needsInput.js +201 -0
  194. package/dist/lib/needsInput.js.map +1 -0
  195. package/dist/lib/png.js +103 -0
  196. package/dist/lib/png.js.map +1 -0
  197. package/dist/lib/redact.js +21 -0
  198. package/dist/lib/redact.js.map +1 -0
  199. package/dist/lib/result.js +87 -0
  200. package/dist/lib/result.js.map +1 -0
  201. package/dist/lib/schemaHash.js +65 -0
  202. package/dist/lib/schemaHash.js.map +1 -0
  203. package/dist/lib/sensitive.js +13 -0
  204. package/dist/lib/sensitive.js.map +1 -0
  205. package/dist/lib/simctl.js +149 -0
  206. package/dist/lib/simctl.js.map +1 -0
  207. package/dist/lib/spawn.js +144 -0
  208. package/dist/lib/spawn.js.map +1 -0
  209. package/dist/lib/wda.js +347 -0
  210. package/dist/lib/wda.js.map +1 -0
  211. package/dist/lib/wdaConfig.js +69 -0
  212. package/dist/lib/wdaConfig.js.map +1 -0
  213. package/dist/lib/wdaTune.js +58 -0
  214. package/dist/lib/wdaTune.js.map +1 -0
  215. package/dist/oracle/auth.js +22 -0
  216. package/dist/oracle/auth.js.map +1 -0
  217. package/dist/oracle/failures.js +193 -0
  218. package/dist/oracle/failures.js.map +1 -0
  219. package/dist/oracle/health.js +123 -0
  220. package/dist/oracle/health.js.map +1 -0
  221. package/dist/oracle/record.js +36 -0
  222. package/dist/oracle/record.js.map +1 -0
  223. package/dist/orchestration/envelope.js +52 -0
  224. package/dist/orchestration/envelope.js.map +1 -0
  225. package/dist/orchestration/goal.js +98 -0
  226. package/dist/orchestration/goal.js.map +1 -0
  227. package/dist/plan/plan.js +124 -0
  228. package/dist/plan/plan.js.map +1 -0
  229. package/dist/prompts/index.js +63 -0
  230. package/dist/prompts/index.js.map +1 -0
  231. package/dist/report/artifactManifest.js +44 -0
  232. package/dist/report/artifactManifest.js.map +1 -0
  233. package/dist/report/coverage.js +60 -0
  234. package/dist/report/coverage.js.map +1 -0
  235. package/dist/report/evidence.js +84 -0
  236. package/dist/report/evidence.js.map +1 -0
  237. package/dist/report/export.js +447 -0
  238. package/dist/report/export.js.map +1 -0
  239. package/dist/report/flake.js +61 -0
  240. package/dist/report/flake.js.map +1 -0
  241. package/dist/report/history.js +564 -0
  242. package/dist/report/history.js.map +1 -0
  243. package/dist/report/policy.js +98 -0
  244. package/dist/report/policy.js.map +1 -0
  245. package/dist/report/qaLevel.js +96 -0
  246. package/dist/report/qaLevel.js.map +1 -0
  247. package/dist/report/readiness.js +213 -0
  248. package/dist/report/readiness.js.map +1 -0
  249. package/dist/report/summary.js +42 -0
  250. package/dist/report/summary.js.map +1 -0
  251. package/dist/report/testCatalog.js +93 -0
  252. package/dist/report/testCatalog.js.map +1 -0
  253. package/dist/report/timing.js +37 -0
  254. package/dist/report/timing.js.map +1 -0
  255. package/dist/server.js +180 -0
  256. package/dist/server.js.map +1 -0
  257. package/dist/services/automationGenerate.js +60 -0
  258. package/dist/services/automationGenerate.js.map +1 -0
  259. package/dist/services/build.js +66 -0
  260. package/dist/services/build.js.map +1 -0
  261. package/dist/services/preflight.js +51 -0
  262. package/dist/services/preflight.js.map +1 -0
  263. package/dist/services/prepareAndroid.js +183 -0
  264. package/dist/services/prepareAndroid.js.map +1 -0
  265. package/dist/services/prepareIos.js +162 -0
  266. package/dist/services/prepareIos.js.map +1 -0
  267. package/dist/services/report.js +537 -0
  268. package/dist/services/report.js.map +1 -0
  269. package/dist/services/smoke.js +120 -0
  270. package/dist/services/smoke.js.map +1 -0
  271. package/dist/services/suiteGenerate.js +123 -0
  272. package/dist/services/suiteGenerate.js.map +1 -0
  273. package/dist/services/testSuiteKnowledge.js +150 -0
  274. package/dist/services/testSuiteKnowledge.js.map +1 -0
  275. package/dist/session/attach.js +47 -0
  276. package/dist/session/attach.js.map +1 -0
  277. package/dist/session/progress.js +56 -0
  278. package/dist/session/progress.js.map +1 -0
  279. package/dist/session/store.js +329 -0
  280. package/dist/session/store.js.map +1 -0
  281. package/dist/snapshot/overlays.js +132 -0
  282. package/dist/snapshot/overlays.js.map +1 -0
  283. package/dist/snapshot/parse.js +204 -0
  284. package/dist/snapshot/parse.js.map +1 -0
  285. package/dist/snapshot/present.js +12 -0
  286. package/dist/snapshot/present.js.map +1 -0
  287. package/dist/snapshot/settle.js +36 -0
  288. package/dist/snapshot/settle.js.map +1 -0
  289. package/dist/state/profile.js +318 -0
  290. package/dist/state/profile.js.map +1 -0
  291. package/dist/suite/compile.js +176 -0
  292. package/dist/suite/compile.js.map +1 -0
  293. package/dist/suite/lint.js +45 -0
  294. package/dist/suite/lint.js.map +1 -0
  295. package/dist/suite/pom.js +285 -0
  296. package/dist/suite/pom.js.map +1 -0
  297. package/dist/suite/testcase.js +87 -0
  298. package/dist/suite/testcase.js.map +1 -0
  299. package/dist/testSuite/generator.js +222 -0
  300. package/dist/testSuite/generator.js.map +1 -0
  301. package/dist/testSuite/history.js +44 -0
  302. package/dist/testSuite/history.js.map +1 -0
  303. package/dist/testSuite/issueLinks.js +96 -0
  304. package/dist/testSuite/issueLinks.js.map +1 -0
  305. package/dist/testSuite/merge.js +190 -0
  306. package/dist/testSuite/merge.js.map +1 -0
  307. package/dist/testSuite/schema.js +86 -0
  308. package/dist/testSuite/schema.js.map +1 -0
  309. package/dist/testSuite/store.js +116 -0
  310. package/dist/testSuite/store.js.map +1 -0
  311. package/dist/testSuite/traceability.js +55 -0
  312. package/dist/testSuite/traceability.js.map +1 -0
  313. package/dist/tools/act.js +457 -0
  314. package/dist/tools/act.js.map +1 -0
  315. package/dist/tools/agent.js +225 -0
  316. package/dist/tools/agent.js.map +1 -0
  317. package/dist/tools/appMap.js +317 -0
  318. package/dist/tools/appMap.js.map +1 -0
  319. package/dist/tools/assertVisual.js +74 -0
  320. package/dist/tools/assertVisual.js.map +1 -0
  321. package/dist/tools/automationGenerate.js +394 -0
  322. package/dist/tools/automationGenerate.js.map +1 -0
  323. package/dist/tools/capabilities.js +114 -0
  324. package/dist/tools/capabilities.js.map +1 -0
  325. package/dist/tools/clearOverlay.js +150 -0
  326. package/dist/tools/clearOverlay.js.map +1 -0
  327. package/dist/tools/detectContext.js +41 -0
  328. package/dist/tools/detectContext.js.map +1 -0
  329. package/dist/tools/doctor.js +116 -0
  330. package/dist/tools/doctor.js.map +1 -0
  331. package/dist/tools/explore.js +289 -0
  332. package/dist/tools/explore.js.map +1 -0
  333. package/dist/tools/firstRun.js +136 -0
  334. package/dist/tools/firstRun.js.map +1 -0
  335. package/dist/tools/flow.js +331 -0
  336. package/dist/tools/flow.js.map +1 -0
  337. package/dist/tools/flowGenerate.js +55 -0
  338. package/dist/tools/flowGenerate.js.map +1 -0
  339. package/dist/tools/getArtifact.js +39 -0
  340. package/dist/tools/getArtifact.js.map +1 -0
  341. package/dist/tools/health.js +41 -0
  342. package/dist/tools/health.js.map +1 -0
  343. package/dist/tools/ios.js +492 -0
  344. package/dist/tools/ios.js.map +1 -0
  345. package/dist/tools/jobs.js +20 -0
  346. package/dist/tools/jobs.js.map +1 -0
  347. package/dist/tools/network.js +50 -0
  348. package/dist/tools/network.js.map +1 -0
  349. package/dist/tools/note.js +69 -0
  350. package/dist/tools/note.js.map +1 -0
  351. package/dist/tools/plan.js +49 -0
  352. package/dist/tools/plan.js.map +1 -0
  353. package/dist/tools/prepareIosTarget.js +99 -0
  354. package/dist/tools/prepareIosTarget.js.map +1 -0
  355. package/dist/tools/prepareTarget.js +257 -0
  356. package/dist/tools/prepareTarget.js.map +1 -0
  357. package/dist/tools/report.js +42 -0
  358. package/dist/tools/report.js.map +1 -0
  359. package/dist/tools/screenRecord.js +24 -0
  360. package/dist/tools/screenRecord.js.map +1 -0
  361. package/dist/tools/screenshot.js +63 -0
  362. package/dist/tools/screenshot.js.map +1 -0
  363. package/dist/tools/smoke.js +39 -0
  364. package/dist/tools/smoke.js.map +1 -0
  365. package/dist/tools/snapshot.js +129 -0
  366. package/dist/tools/snapshot.js.map +1 -0
  367. package/dist/tools/startSession.js +169 -0
  368. package/dist/tools/startSession.js.map +1 -0
  369. package/dist/tools/state.js +87 -0
  370. package/dist/tools/state.js.map +1 -0
  371. package/dist/tools/suite.js +412 -0
  372. package/dist/tools/suite.js.map +1 -0
  373. package/dist/tools/testThis.js +774 -0
  374. package/dist/tools/testThis.js.map +1 -0
  375. package/dist/tools/wda.js +477 -0
  376. package/dist/tools/wda.js.map +1 -0
  377. package/dist/version.js +62 -0
  378. package/dist/version.js.map +1 -0
  379. package/dist/visual/ocr.js +72 -0
  380. package/dist/visual/ocr.js.map +1 -0
  381. package/dist/visual/provider.js +75 -0
  382. package/dist/visual/provider.js.map +1 -0
  383. package/docs/README.md +19 -0
  384. package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
  385. package/docs/mcp-server.md +135 -0
  386. package/docs/tools.md +130 -0
  387. package/package.json +70 -0
@@ -0,0 +1,123 @@
1
+ // Tier-1 deterministic health oracle (DESIGN §6). Phase 2.2: classifies BOTH layers —
2
+ // NATIVE health (process: crash dialog / ANR / wrong foreground) and APP health (JS/UI:
3
+ // RN RedBox / LogBox error / error-boundary fallback / WebView error). A green native
4
+ // process with a broken app UI (e.g. an ErrorBoundary screen) is now a first-class finding,
5
+ // so agents don't have to infer "healthy process but broken app" from raw snapshot text.
6
+ import { parseSnapshot } from '../snapshot/parse.js';
7
+ // APP-layer surfaces (JS/UI). Order matters: the first fatal RedBox variant wins over LogBox.
8
+ const APP_SURFACES = [
9
+ { re: /unable to load script|could not connect to development server|loadJSBundleFromAssets|index\.android\.bundle/i, kind: 'rn_redbox', severity: 'high', detail: 'RN RedBox — JS bundle failed to load (Metro/bundle issue)' },
10
+ { re: /unhandled (js|javascript) exception|invariant violation|TypeError:|ReferenceError|undefined is not an object|is not a function/i, kind: 'rn_redbox', severity: 'high', detail: 'RN RedBox — unhandled JS exception' },
11
+ { re: /we encountered an error|something went wrong|this screen (crashed|encountered)|oops[!,. ].{0,40}(wrong|error|crash)/i, kind: 'app_error_boundary', severity: 'high', detail: 'app ErrorBoundary fallback UI (process alive, screen broken)' },
12
+ { re: /net::ERR_|webpage not available|this site can.?t be reached|ERR_INTERNET_DISCONNECTED|ERR_NAME_NOT_RESOLVED|ERR_CONNECTION/i, kind: 'webview_error', severity: 'medium', detail: 'WebView error page' },
13
+ { re: /console error|\b[1-9]\d* errors?\b/i, kind: 'rn_logbox_error', severity: 'medium', detail: 'RN LogBox error overlay (app running but logging errors)' },
14
+ ];
15
+ // A conservative last-resort generic error surface (only when nothing more specific matched).
16
+ const GENERIC_ERROR_RE = /failed to load|couldn.?t load|an error (occurred|has occurred)|no internet connection|please try again/i;
17
+ // NATIVE-layer dialogs (process-level).
18
+ const ANR_RE = /isn['’]t responding|application not responding/i;
19
+ const CRASH_RE = /keeps stopping|has stopped|unfortunately/i;
20
+ function firstMatch(nodes, re) {
21
+ for (const n of nodes) {
22
+ const t = `${n.text} ${n.desc} ${n.cls ?? ''} ${n.id ?? ''}`.trim();
23
+ if (re.test(t))
24
+ return (n.text || n.desc).trim().slice(0, 160);
25
+ }
26
+ return undefined;
27
+ }
28
+ export async function checkHealth(driver, appId, xml) {
29
+ const foreground = await driver.foregroundOwner().catch(() => 'unknown');
30
+ let source = xml;
31
+ if (source === undefined)
32
+ source = await driver.dumpXml().catch(() => '');
33
+ // Parse to nodes so evidence is the VISIBLE text (not attribute names) — best-effort.
34
+ let nodes = [];
35
+ try {
36
+ nodes = parseSnapshot(source).allNodes.map((n) => ({ text: n.text, desc: n.desc, cls: n.cls, id: n.id }));
37
+ }
38
+ catch {
39
+ nodes = [];
40
+ }
41
+ const joined = nodes.map((n) => `${n.text} ${n.desc} ${n.cls ?? ''} ${n.id ?? ''}`).join(' ') || source;
42
+ const findings = [];
43
+ // ---- NATIVE layer ----
44
+ let nativeStatus = 'ok';
45
+ if (driver.kind === 'wda' && !source) {
46
+ findings.push({ severity: 'high', layer: 'native', kind: 'wda_unreachable', detail: 'WebDriverAgent did not return a UI source' });
47
+ nativeStatus = 'wda_unreachable';
48
+ }
49
+ if (ANR_RE.test(joined)) {
50
+ findings.push({ severity: 'high', layer: 'native', kind: 'anr', detail: 'Application Not Responding dialog', evidence: firstMatch(nodes, ANR_RE) });
51
+ nativeStatus = 'anr';
52
+ }
53
+ else if (CRASH_RE.test(joined)) {
54
+ findings.push({ severity: 'high', layer: 'native', kind: 'native_crash', detail: 'native crash dialog', evidence: firstMatch(nodes, CRASH_RE) });
55
+ nativeStatus = 'native_crash';
56
+ }
57
+ if (driver.kind === 'wda') {
58
+ const springboard = /SpringBoard|XCUIElementTypeApplication[^]*com\.apple\.springboard/i.test(joined);
59
+ const alert = /XCUIElementTypeAlert/i.test(joined);
60
+ const permission = /would like to|allow|don.?t allow|while using|permission/i.test(joined) && alert;
61
+ if (springboard) {
62
+ findings.push({ severity: 'high', layer: 'native', kind: 'wrong_foreground_app', detail: 'iOS SpringBoard is foreground (app not active or crashed)', evidence: firstMatch(nodes, /SpringBoard/i) });
63
+ if (nativeStatus === 'ok')
64
+ nativeStatus = 'wrong_foreground_app';
65
+ }
66
+ else if (permission) {
67
+ findings.push({ severity: 'medium', layer: 'native', kind: 'permission_dialog', detail: 'iOS runtime permission dialog is visible', evidence: firstMatch(nodes, /would like to|allow|don.?t allow|while using|permission/i) });
68
+ }
69
+ else if (alert) {
70
+ findings.push({ severity: 'medium', layer: 'native', kind: 'native_alert', detail: 'iOS native alert is visible', evidence: firstMatch(nodes, /.+/) });
71
+ }
72
+ }
73
+ if (appId && !foreground.startsWith(appId) && foreground !== 'unknown') {
74
+ if (/launcher/i.test(foreground)) {
75
+ findings.push({ severity: 'high', layer: 'native', kind: 'wrong_foreground_app', detail: `app left to the launcher (possible crash) — foreground=${foreground}` });
76
+ if (nativeStatus === 'ok')
77
+ nativeStatus = 'wrong_foreground_app';
78
+ }
79
+ else if (/permissioncontroller/i.test(foreground)) {
80
+ findings.push({ severity: 'medium', layer: 'native', kind: 'permission_dialog', detail: `Android runtime permission dialog is visible — foreground=${foreground}` });
81
+ }
82
+ else if (/packageinstaller|systemui|com\.android\.|inputmethod/i.test(foreground)) {
83
+ findings.push({ severity: 'info', layer: 'native', kind: 'system_surface', detail: foreground });
84
+ }
85
+ else {
86
+ findings.push({ severity: 'medium', layer: 'native', kind: 'wrong_foreground_app', detail: `foreground is a different app — foreground=${foreground}` });
87
+ if (nativeStatus === 'ok')
88
+ nativeStatus = 'wrong_foreground_app';
89
+ }
90
+ }
91
+ // ---- APP layer (only meaningful while OUR app owns the foreground) ----
92
+ const appInForeground = !appId || foreground.startsWith(appId) || driver.kind === 'wda';
93
+ let appStatus = 'ok';
94
+ if (appInForeground) {
95
+ let matched = false;
96
+ for (const s of APP_SURFACES) {
97
+ if (s.re.test(joined)) {
98
+ findings.push({ severity: s.severity, layer: 'app', kind: s.kind, detail: s.detail, evidence: firstMatch(nodes, s.re) });
99
+ appStatus = s.severity === 'high' ? 'error' : appStatus === 'error' ? 'error' : 'degraded';
100
+ matched = true;
101
+ // RedBox/error-boundary are terminal for the screen — don't also report lesser surfaces.
102
+ if (s.severity === 'high')
103
+ break;
104
+ }
105
+ }
106
+ if (!matched && GENERIC_ERROR_RE.test(joined)) {
107
+ findings.push({ severity: 'medium', layer: 'app', kind: 'unknown_error_surface', detail: 'generic error copy on screen (low confidence)', evidence: firstMatch(nodes, GENERIC_ERROR_RE) });
108
+ appStatus = 'degraded';
109
+ }
110
+ }
111
+ const nativeHealthy = !findings.some((f) => f.layer === 'native' && f.severity === 'high');
112
+ const appHealthy = appStatus === 'ok';
113
+ return {
114
+ healthy: !findings.some((f) => f.severity === 'high'),
115
+ nativeHealthy,
116
+ appHealthy,
117
+ nativeStatus,
118
+ appStatus,
119
+ foreground,
120
+ findings,
121
+ };
122
+ }
123
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/oracle/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ // Record health findings into the session for qa_report (review #3, Phase 2.2).
2
+ // Shared by qa_act (auto after each action) and qa_check_health (on demand). Carries the
3
+ // native/app layer + visible-text evidence, and — for app-layer error surfaces — captures
4
+ // ONE screenshot as evidence and attaches its URI to those findings.
5
+ export async function recordHealthFindings(sessions, session, findings, driver, screen) {
6
+ // Capture one screenshot of an app-layer error surface (RedBox / error-boundary / etc.)
7
+ // so the report shows WHAT broke, not just that something did. Evidence — not budgeted.
8
+ let evidenceUri;
9
+ const appError = findings.find((f) => f.layer === 'app' && (f.severity === 'high' || f.severity === 'medium'));
10
+ // Sensitive mode: record the finding but DON'T capture pixels.
11
+ if (appError && driver && !session.sensitive) {
12
+ try {
13
+ const png = await driver.screenshot();
14
+ evidenceUri = sessions.saveArtifact(session, 'screenshot', `app-error-${Date.now()}.png`, png, 'image/png', `app-health: ${appError.kind}`);
15
+ }
16
+ catch {
17
+ /* best-effort — evidence is a bonus, not required */
18
+ }
19
+ }
20
+ for (const f of findings) {
21
+ if (f.severity === 'info')
22
+ continue;
23
+ const screenshotUri = f.layer === 'app' ? (f.screenshotUri ?? evidenceUri) : f.screenshotUri;
24
+ sessions.addFinding(session, {
25
+ at: Date.now(),
26
+ severity: f.severity,
27
+ kind: f.kind,
28
+ detail: f.detail,
29
+ layer: f.layer,
30
+ evidence: f.evidence,
31
+ screen,
32
+ screenshotUri,
33
+ });
34
+ }
35
+ }
36
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/oracle/record.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,yFAAyF;AACzF,0FAA0F;AAC1F,qEAAqE;AAMrE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAsB,EACtB,OAAgB,EAChB,QAAmB,EACnB,MAAe,EACf,MAAe;IAEf,wFAAwF;IACxF,wFAAwF;IACxF,IAAI,WAA+B,CAAC;IACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC;IAC/G,+DAA+D;IAC/D,IAAI,QAAQ,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACtC,WAAW,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,eAAe,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9I,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;YAAE,SAAS;QACpC,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QAC7F,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE;YAC3B,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,MAAM;YACN,aAAa;SACd,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,52 @@
1
+ // Uniform terminal result envelope for qa_test_this (Developer 1, roadmap §3.1 Milestone B).
2
+ // Every terminal orchestration state — completed | blocked | unsafe | needs_input | running —
3
+ // is summarizable from STRUCTURED output, with no log parsing: what was attempted, what safe
4
+ // fallbacks were taken, which artifact/target was chosen and why, typed blockers with owner +
5
+ // fix, the report URI, and the single exact next call.
6
+ //
7
+ // Developer 1 owns the ENVELOPE shape, not the source data: artifact/target explanations come
8
+ // from Developer 2's services; suite/report/readiness summaries come from Developer 3's. This
9
+ // module only normalizes those into one stable contract.
10
+ import { FAILURES, failureOwner, isSelfFixable } from '../oracle/failures.js';
11
+ /** Build a typed blocker from a Swipium failure code (owner + retry-safety + fix come from the
12
+ * failure taxonomy, so an agent can route the blocker without a second lookup). */
13
+ export function typedBlockerFromCode(code, override) {
14
+ const info = FAILURES[code];
15
+ if (!info) {
16
+ return {
17
+ failureCode: code,
18
+ owner: 'swipium',
19
+ retrySafe: true,
20
+ canSwipiumFix: false,
21
+ whatItMeans: 'Unrecognized failure code.',
22
+ howToFix: 'Inspect the run report; call qa_explain_blocker for guidance.',
23
+ ...override,
24
+ };
25
+ }
26
+ return {
27
+ failureCode: code,
28
+ owner: failureOwner(code),
29
+ retrySafe: info.retrySafe,
30
+ canSwipiumFix: isSelfFixable(code),
31
+ whatItMeans: info.summary,
32
+ howToFix: info.recovery,
33
+ ...override,
34
+ };
35
+ }
36
+ /** Normalize the orchestration outcome into the uniform terminal envelope (never throws). */
37
+ export function buildTerminalEnvelope(input) {
38
+ return {
39
+ state: input.state,
40
+ sessionId: input.sessionId,
41
+ jobId: input.jobId ?? null,
42
+ summary: input.summary,
43
+ attempted: input.attempted ?? [],
44
+ workaroundsAttempted: input.workaroundsAttempted ?? [],
45
+ artifactChoice: input.artifactChoice ?? null,
46
+ targetChoice: input.targetChoice ?? null,
47
+ blockers: input.blockers ?? [],
48
+ reportUri: input.reportUri ?? null,
49
+ nextRecommendedAction: input.nextRecommendedAction ?? null,
50
+ };
51
+ }
52
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/orchestration/envelope.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,8FAA8F;AAC9F,6FAA6F;AAC7F,8FAA8F;AAC9F,uDAAuD;AACvD,EAAE;AACF,8FAA8F;AAC9F,8FAA8F;AAC9F,yDAAyD;AAEzD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAoB,MAAM,uBAAuB,CAAC;AA6DhG;oFACoF;AACpF,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,QAAgC;IACjF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAmB,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,KAAK;YACpB,WAAW,EAAE,4BAA4B;YACzC,QAAQ,EAAE,+DAA+D;YACzE,GAAG,QAAQ;SACZ,CAAC;IACJ,CAAC;IACD,OAAO;QACL,WAAW,EAAE,IAAI;QACjB,KAAK,EAAE,YAAY,CAAC,IAAmB,CAAC;QACxC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,aAAa,CAAC,IAAmB,CAAC;QACjD,WAAW,EAAE,IAAI,CAAC,OAAO;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,GAAG,QAAQ;KACZ,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,qBAAqB,CAAC,KAAoB;IACxD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;QAChC,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,IAAI,EAAE;QACtD,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,IAAI;QAC5C,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;QACxC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;QAC9B,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,qBAAqB,EAAE,KAAK,CAAC,qBAAqB,IAAI,IAAI;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,98 @@
1
+ // qa_test_this goal routing (Developer 1, roadmap §3.1 Milestone C). A `goal` adjusts ORCHESTRATION
2
+ // FLAGS and REQUIRED OUTPUTS only — it never duplicates suite/report/platform logic (those stay in
3
+ // the services Developer 2/3 own). Keeping the mapping a pure, exported helper makes goal behavior
4
+ // unit-testable without a device, and keeps `qa_test_this` an orchestrator rather than a switchboard.
5
+ export const TEST_GOALS = [
6
+ 'smoke',
7
+ 'explore',
8
+ 'create_automation_suite',
9
+ 'release_gate',
10
+ 'test_login',
11
+ 'reproduce_bug',
12
+ ];
13
+ const BASE = {
14
+ smoke: {
15
+ explore: false,
16
+ generateSuite: false,
17
+ stopOnNeedsInput: false,
18
+ releaseGate: false,
19
+ requiredOutputs: ['reportUri', 'smoke'],
20
+ description: 'Fastest launch + guardrail/smoke path.',
21
+ },
22
+ explore: {
23
+ explore: true,
24
+ generateSuite: false,
25
+ stopOnNeedsInput: false,
26
+ releaseGate: false,
27
+ requiredOutputs: ['reportUri', 'smoke', 'exploration'],
28
+ description: 'Smoke, then guided exploration to map reachable workflows.',
29
+ },
30
+ create_automation_suite: {
31
+ explore: true,
32
+ generateSuite: true,
33
+ stopOnNeedsInput: false,
34
+ releaseGate: false,
35
+ requiredOutputs: ['reportUri', 'smoke', 'exploration', 'suite'],
36
+ description: 'Smoke + explore, then request a POM suite from the suite service.',
37
+ },
38
+ release_gate: {
39
+ explore: true,
40
+ generateSuite: false,
41
+ stopOnNeedsInput: false,
42
+ releaseGate: true,
43
+ requiredOutputs: ['reportUri', 'smoke', 'readiness'],
44
+ description: 'Stricter report + readiness/release-gate summary required.',
45
+ },
46
+ test_login: {
47
+ explore: false,
48
+ generateSuite: false,
49
+ stopOnNeedsInput: true,
50
+ releaseGate: false,
51
+ requiredOutputs: ['reportUri', 'smoke'],
52
+ description: 'Drive the login flow; stop for credentials if no secure inputs exist.',
53
+ },
54
+ reproduce_bug: {
55
+ explore: true,
56
+ generateSuite: false,
57
+ stopOnNeedsInput: false,
58
+ releaseGate: false,
59
+ requiredOutputs: ['reportUri', 'exploration'],
60
+ description: 'Focused exploration/test plan driven by a text goal.',
61
+ },
62
+ };
63
+ /**
64
+ * Resolve a goal into orchestration flags. Explicit per-flag overrides win, so existing callers
65
+ * passing `explore`/`generateSuite`/`stopOnNeedsInput` keep working unchanged.
66
+ *
67
+ * DEFAULT POLICY (no explicit goal): "leave behind automation when possible" — the run still does
68
+ * a fast launch + smoke, but ALSO attempts POM suite generation afterward (the suite service skips
69
+ * honestly when no actions were recorded). Opt out with `goal:"smoke"` (fast, explicit) or
70
+ * `policy.fastSmoke:true`.
71
+ */
72
+ export function resolveGoalFlags(goal, overrides = {}, policy = {}) {
73
+ const explicit = goal !== undefined;
74
+ const g = goal ?? 'smoke';
75
+ const base = { ...BASE[g] };
76
+ if (!explicit) {
77
+ // Default autopilot: attempt automation. Stays fast (no forced exploration); suite generation
78
+ // is best-effort and skips when there are no recorded actions to turn into page objects.
79
+ base.generateSuite = true;
80
+ base.requiredOutputs = ['reportUri', 'smoke', 'suite'];
81
+ base.description = 'Default autopilot: fast launch + smoke, then generate a POM suite when actions exist (goal:"smoke" or fastSmoke:true to skip).';
82
+ }
83
+ if (policy.fastSmoke) {
84
+ // Strongest "just smoke, fast" signal — overrides the default automation attempt.
85
+ base.generateSuite = false;
86
+ base.explore = false;
87
+ }
88
+ return {
89
+ goal: g,
90
+ explore: overrides.explore ?? base.explore,
91
+ generateSuite: overrides.generateSuite ?? base.generateSuite,
92
+ stopOnNeedsInput: overrides.stopOnNeedsInput ?? base.stopOnNeedsInput,
93
+ releaseGate: base.releaseGate,
94
+ requiredOutputs: base.requiredOutputs,
95
+ description: base.description,
96
+ };
97
+ }
98
+ //# sourceMappingURL=goal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal.js","sourceRoot":"","sources":["../../src/orchestration/goal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ // qa_plan core (PHASE3-PLAN §3.2) — PURE synthesis. Given what we detected about the
2
+ // project + what the session declared (fixtures, observed auth, prepared appId), produce a
3
+ // safe test plan: which workflows are READY, which are BLOCKED (and why + how to unblock),
4
+ // and which are UNSAFE (and why). No device I/O lives here, so it is fully unit-testable;
5
+ // the tool wrapper (src/tools/plan.ts) gathers the inputs and calls buildPlan().
6
+ const LOGIN_FIXTURE = /login|auth|account|credential|sign[\s_-]?in/i;
7
+ function isDebugRN(fw) {
8
+ return fw === 'expo' || fw === 'bare-react-native';
9
+ }
10
+ export function buildPlan(i) {
11
+ const ready = [];
12
+ const blocked = [];
13
+ const unsafe = [];
14
+ const notes = [];
15
+ const appAvailable = i.appPrepared || i.hasApk;
16
+ const loginFixture = i.fixtures.find((f) => LOGIN_FIXTURE.test(f.name) || !!f.testAccount);
17
+ // Shared gate: every workflow needs a device and the app present. Emit the right blocked
18
+ // entry once per workflow so the agent sees exactly what each one needs.
19
+ const gateEnv = (workflow, budgetProfile) => {
20
+ if (!i.hasDevice) {
21
+ return {
22
+ workflow,
23
+ budgetProfile,
24
+ category: 'missing_device',
25
+ requiredState: 'an online device or a bootable AVD',
26
+ recommendedSetup: 'Create/boot an AVD (see qa_doctor), then qa_prepare_target.',
27
+ };
28
+ }
29
+ if (!appAvailable) {
30
+ return {
31
+ workflow,
32
+ budgetProfile,
33
+ category: 'missing_artifact',
34
+ requiredState: 'the app installed, or a prebuilt app artifact to install',
35
+ recommendedSetup: 'Drop an APK under apps/android or a simulator .app under apps/ios, then run the platform prepare/attach flow.',
36
+ };
37
+ }
38
+ return null;
39
+ };
40
+ // launch_smoke — the cheapest always-valuable check.
41
+ {
42
+ const g = gateEnv('launch_smoke', 'guardrail');
43
+ if (g)
44
+ blocked.push(g);
45
+ else
46
+ ready.push({ workflow: 'launch_smoke', budgetProfile: 'guardrail', requires: [] });
47
+ }
48
+ // visual_smoke — screenshot/landmark check for visual-only (map/canvas) screens.
49
+ {
50
+ const g = gateEnv('visual_smoke', 'login_smoke');
51
+ if (g)
52
+ blocked.push(g);
53
+ else
54
+ ready.push({ workflow: 'visual_smoke', budgetProfile: 'login_smoke', requires: [] });
55
+ }
56
+ // login_smoke — needs a credential fixture on top of the env gate.
57
+ {
58
+ const g = gateEnv('login_smoke', 'login_smoke');
59
+ if (g)
60
+ blocked.push(g);
61
+ else if (!loginFixture) {
62
+ blocked.push({
63
+ workflow: 'login_smoke',
64
+ budgetProfile: 'login_smoke',
65
+ category: 'missing_test_data',
66
+ requiredState: 'a test account (credentials)',
67
+ recommendedSetup: 'Declare a fixture with a testAccount label (and provide TEST_EMAIL/TEST_PASSWORD via env), or add it to .swipium/fixtures.json.',
68
+ });
69
+ }
70
+ else {
71
+ ready.push({ workflow: 'login_smoke', budgetProfile: 'login_smoke', requires: [loginFixture.name] });
72
+ }
73
+ }
74
+ // Discovered flow files become first-class candidate workflows (PR5+).
75
+ for (const name of i.flows) {
76
+ const g = gateEnv(name, 'full_smoke');
77
+ if (g)
78
+ blocked.push(g);
79
+ else
80
+ ready.push({ workflow: name, budgetProfile: 'full_smoke', requires: [] });
81
+ }
82
+ // Fixtures that declare an unmet requiredState surface as blocked workflows so "no saved
83
+ // flight to delete" reads as setup guidance, not a failure (DESIGN §6 / qa_note semantics).
84
+ for (const f of i.fixtures) {
85
+ if (f.requiredState && !LOGIN_FIXTURE.test(f.name) && !f.testAccount) {
86
+ blocked.push({
87
+ workflow: f.name,
88
+ budgetProfile: 'full_smoke',
89
+ category: 'missing_test_data',
90
+ requiredState: f.requiredState,
91
+ recommendedSetup: f.recommendedSetup ?? `Create the precondition: ${f.requiredState}.`,
92
+ });
93
+ }
94
+ }
95
+ // UNSAFE — destructive actions that Swipium will refuse by default.
96
+ if (isDebugRN(i.framework)) {
97
+ unsafe.push({
98
+ workflow: 'fresh_start',
99
+ reason: 'bundle_cache_loss',
100
+ detail: 'clear_data / fresh_start wipes the JS bundle of a debug RN/Expo build, leaving a RedBox it cannot reload. Use a release APK (embedded bundle) for clean-state tests, or run destructive workflows last.',
101
+ });
102
+ }
103
+ if (!i.fixtures.some((f) => f.disposable === true || f.environment === 'test')) {
104
+ unsafe.push({
105
+ workflow: 'destructive_exploration',
106
+ reason: 'needs_disposable_state',
107
+ detail: 'Delete/pay/send/logout workflows require a fixture marked disposable:true or environment:"test" before Swipium can approve an exact destructive candidate.',
108
+ });
109
+ }
110
+ // Safety gates the agent should expect (informational; enforced server-side regardless).
111
+ const safetyGates = [
112
+ 'Booting an emulator and installing an external APK each require one-time consent.',
113
+ 'Network toggle (offline/online) requires consent and is auto-restored at qa_report.',
114
+ 'Destructive app actions (clear_data/fresh_start) require consent; refused by default on debug RN/Expo builds.',
115
+ 'Destructive exploration requires dry_run_destructive first, then candidate-bound approval with disposable test state.',
116
+ ];
117
+ if (i.auth.authedAtStart === false || i.auth.loginScreenSeen) {
118
+ notes.push('A login screen was observed — authenticated workflows will need credentials.');
119
+ }
120
+ for (const b of i.blockers)
121
+ notes.push(b);
122
+ return { ready, blocked, unsafe, safetyGates, notes };
123
+ }
124
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/plan/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ // MCP prompts (PHASE3-PLAN §2.4 / §3.3) — the spec's third server capability (after tools +
2
+ // resources). Prompts are reusable workflow templates a prompt-capable client (e.g. Claude)
3
+ // can invoke by name, so common QA runs don't need a hand-written prompt each time.
4
+ //
5
+ // Design rules:
6
+ // - Prompts are THIN: they only orchestrate tools that already exist. No privileged logic
7
+ // lives here — consent stays server-side (security best-practices doc).
8
+ // - Clients that don't support prompts lose nothing: every step is "call <tool>", which the
9
+ // agent can do directly. Nothing is prompt-only.
10
+ //
11
+ import { z } from 'zod';
12
+ function userText(text) {
13
+ return { messages: [{ role: 'user', content: { type: 'text', text } }] };
14
+ }
15
+ export function registerPrompts(server) {
16
+ server.registerPrompt('swipium_setup_check', {
17
+ title: 'Check Swipium setup',
18
+ description: 'Verify Swipium can test a project and report what (if anything) is blocking.',
19
+ argsSchema: { projectRoot: z.string().optional().describe('Absolute path to the app project.') },
20
+ }, ({ projectRoot }) => userText(`Check whether Swipium can test ${projectRoot ? `the project at ${projectRoot}` : 'this project'}.\n\n` +
21
+ `1. Call qa_doctor to confirm the toolchain (adb/emulator/java) and that the client is not stale.\n` +
22
+ `2. Call qa_start_session${projectRoot ? ` { projectRoot: "${projectRoot}" }` : ''}.\n` +
23
+ `3. Call qa_detect_context, then qa_plan with the sessionId.\n` +
24
+ `4. Summarize: is it READY, PARTIAL, or BLOCKED? List the exact missing items (APK, device, credentials) and the recommended budget profile. Do not start testing yet.`));
25
+ server.registerPrompt('swipium_full_smoke', {
26
+ title: 'Run a full smoke test',
27
+ description: 'Plan, prepare, run the top ready workflows, and produce a report.',
28
+ argsSchema: {
29
+ projectRoot: z.string().optional(),
30
+ appId: z.string().optional().describe('Override the auto-detected app id.'),
31
+ },
32
+ }, ({ projectRoot, appId }) => userText(`Run a full smoke test and produce a report a developer can act on.\n\n` +
33
+ `1. qa_start_session${projectRoot ? ` { projectRoot: "${projectRoot}", ` : ' { '}profile: "full_smoke", responseMode: "compact" }.\n` +
34
+ `2. qa_plan — pick the READY workflows; respect anything listed as UNSAFE.\n` +
35
+ `3. qa_prepare_target${appId ? ` { appId: "${appId}" }` : ''} (approve consent for boot/install if prompted).\n` +
36
+ `4. For each ready workflow: drive it with qa_snapshot/qa_act, checking qa_check_health after key steps. Use qa_clear_overlay if a keyboard/dialog/banner blocks a target.\n` +
37
+ `5. Record each result with qa_note (pass/fail/blocked + category). For visual-only screens use qa_assert_visual.\n` +
38
+ `6. qa_report at the end. Summarize release risk and the single most important next action.`));
39
+ server.registerPrompt('swipium_bug_repro', {
40
+ title: 'Reproduce and document a bug',
41
+ description: 'Drive to a described bug, capture deterministic evidence, and file it as a structured outcome.',
42
+ argsSchema: {
43
+ bug: z.string().describe('What the bug is / how to reach it.'),
44
+ projectRoot: z.string().optional(),
45
+ },
46
+ }, ({ bug, projectRoot }) => userText(`Reproduce and document this bug with evidence:\n"${bug}"\n\n` +
47
+ `1. qa_start_session${projectRoot ? ` { projectRoot: "${projectRoot}", ` : ' { '}profile: "login_smoke" }, then qa_plan.\n` +
48
+ `2. qa_prepare_target, then navigate toward the reported bug with qa_snapshot/qa_act.\n` +
49
+ `3. At the failure, call qa_check_health (capture native vs app classification) and qa_screenshot for evidence.\n` +
50
+ `4. Record qa_note { outcome: "fail", category: "app_bug", reason, artifactUris } — or "blocked"/"not_applicable" if you could not reach it, with the precondition.\n` +
51
+ `5. qa_report. Include exact reproduction steps and the evidence artifact URIs so the report stands alone without the transcript.`));
52
+ server.registerPrompt('swipium_convert_run_to_flow', {
53
+ title: 'Convert a run into a reusable flow',
54
+ description: 'Draft a repeatable .swipium/flows/*.yaml from the steps you just performed, then validate it.',
55
+ argsSchema: { name: z.string().optional().describe('Flow name, e.g. login-smoke.') },
56
+ }, ({ name }) => userText(`Turn the workflow you just ran into a repeatable Swipium flow.\n\n` +
57
+ `1. Write a flow YAML named "${name ?? 'my-flow'}" with: name, appId, budgetProfile, fixtures, and a steps list.\n` +
58
+ `2. Use durable selectors: prefer text/id (e.g. tap: "Sign In") over @ref. Replace credentials with \${TEST_EMAIL}/\${TEST_PASSWORD} variables — never inline secrets.\n` +
59
+ ` Available steps: prepareTarget, tap, tapAt, inputText, assertVisible, assertNotVisible, swipe, scrollTo, press, openUrl, wait.\n` +
60
+ `3. Validate it with qa_flow_check { flowYaml: "<your yaml>" } and fix any reported errors.\n` +
61
+ `4. Save it under .swipium/flows/${name ?? 'my-flow'}.yaml so qa_plan lists it and qa_flow_run can replay it.`));
62
+ }
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,4FAA4F;AAC5F,oFAAoF;AACpF,EAAE;AACF,gBAAgB;AAChB,2FAA2F;AAC3F,2EAA2E;AAC3E,6FAA6F;AAC7F,oDAAoD;AACpD,EAAE;AACF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,cAAc,CACnB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,8EAA8E;QAC3F,UAAU,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAAE;KACjG,EACD,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAClB,QAAQ,CACN,kCAAkC,WAAW,CAAC,CAAC,CAAC,kBAAkB,WAAW,EAAE,CAAC,CAAC,CAAC,cAAc,OAAO;QACrG,oGAAoG;QACpG,2BAA2B,WAAW,CAAC,CAAC,CAAC,oBAAoB,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK;QACvF,+DAA+D;QAC/D,uKAAuK,CAC1K,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,oBAAoB,EACpB;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EAAE,mEAAmE;QAChF,UAAU,EAAE;YACV,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;SAC5E;KACF,EACD,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,CACzB,QAAQ,CACN,wEAAwE;QACtE,sBAAsB,WAAW,CAAC,CAAC,CAAC,oBAAoB,WAAW,KAAK,CAAC,CAAC,CAAC,KAAK,qDAAqD;QACrI,6EAA6E;QAC7E,uBAAuB,KAAK,CAAC,CAAC,CAAC,cAAc,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,oDAAoD;QAChH,6KAA6K;QAC7K,oHAAoH;QACpH,4FAA4F,CAC/F,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,mBAAmB,EACnB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EAAE,gGAAgG;QAC7G,UAAU,EAAE;YACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;YAC9D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SACnC;KACF,EACD,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CACvB,QAAQ,CACN,oDAAoD,GAAG,OAAO;QAC5D,sBAAsB,WAAW,CAAC,CAAC,CAAC,oBAAoB,WAAW,KAAK,CAAC,CAAC,CAAC,KAAK,2CAA2C;QAC3H,wFAAwF;QACxF,kHAAkH;QAClH,sKAAsK;QACtK,kIAAkI,CACrI,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,6BAA6B,EAC7B;QACE,KAAK,EAAE,oCAAoC;QAC3C,WAAW,EAAE,+FAA+F;QAC5G,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE;KACrF,EACD,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACX,QAAQ,CACN,oEAAoE;QAClE,+BAA+B,IAAI,IAAI,SAAS,mEAAmE;QACnH,yKAAyK;QACzK,qIAAqI;QACrI,8FAA8F;QAC9F,mCAAmC,IAAI,IAAI,SAAS,0DAA0D,CACjH,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, readFileSync, statSync } from 'node:fs';
3
+ function sha256(path) {
4
+ return createHash('sha256').update(readFileSync(path)).digest('hex');
5
+ }
6
+ export function buildSessionArtifactManifest(session) {
7
+ const files = [];
8
+ const missing = [];
9
+ const artifactCounts = session.artifacts.reduce((acc, a) => {
10
+ acc[a.kind] = (acc[a.kind] ?? 0) + 1;
11
+ return acc;
12
+ }, {});
13
+ for (const a of session.artifacts) {
14
+ if (!existsSync(a.path)) {
15
+ missing.push({ uri: a.uri, path: a.path, kind: a.kind });
16
+ continue;
17
+ }
18
+ const st = statSync(a.path);
19
+ files.push({
20
+ uri: a.uri,
21
+ kind: a.kind,
22
+ label: a.label,
23
+ mime: a.mime,
24
+ path: a.path,
25
+ bytes: st.size,
26
+ sha256: sha256(a.path),
27
+ createdAt: new Date(a.createdAt).toISOString(),
28
+ });
29
+ }
30
+ return {
31
+ schemaVersion: 1,
32
+ sessionId: session.id,
33
+ createdAt: new Date().toISOString(),
34
+ root: session.root,
35
+ device: session.device ?? null,
36
+ appId: session.appId ?? null,
37
+ sensitive: session.sensitive,
38
+ artifactCounts,
39
+ files,
40
+ missing,
41
+ environmentMutations: session.envChanges,
42
+ };
43
+ }
44
+ //# sourceMappingURL=artifactManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifactManifest.js","sourceRoot":"","sources":["../../src/report/artifactManifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0B7D,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,OAAgB;IAC3D,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,MAAM,OAAO,GAAuC,EAAE,CAAC;IACvD,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAyB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACjF,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,SAAS;QACX,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,EAAE,CAAC,IAAI;YACd,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACtB,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;SAC/C,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;QAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,cAAc;QACd,KAAK;QACL,OAAO;QACP,oBAAoB,EAAE,OAAO,CAAC,UAAU;KACzC,CAAC;AACJ,CAAC"}