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,74 @@
1
+ // qa_assert_visual — record a VISUAL assertion in one call: capture a screenshot as evidence
2
+ // and file a qa_note(verifiedVisually) pass/fail. For screens with no usable structured tree
3
+ // (maps, canvases, animations) where the agent confirms a rendered result by eye. Replaces the
4
+ // two-step qa_screenshot + qa_note(verifiedVisually) idiom with a single intent-revealing tool.
5
+ import { z } from 'zod';
6
+ import { qaOk, qaError } from '../lib/result.js';
7
+ import { captureCoordinateSpace } from '../lib/coordSpace.js';
8
+ import { sensitiveRefusal } from '../lib/sensitive.js';
9
+ import { getDriver } from '../session/attach.js';
10
+ export function registerAssertVisual(server, sessions) {
11
+ server.registerTool('qa_assert_visual', {
12
+ title: 'Assert a visual result',
13
+ description: 'Record a visual assertion for a screen that has no usable structured tree (map/canvas/animation): captures a screenshot as evidence and files a test outcome with verifiedVisually=true. Use `pass:false` if the expected thing is NOT visible. Equivalent to qa_screenshot + qa_note(verifiedVisually) but in one call. Returns the screenshot URI and the recorded note.',
14
+ inputSchema: {
15
+ sessionId: z.string(),
16
+ assertion: z.string().describe('what you visually confirmed, e.g. "Live Map rendered with the route polyline"'),
17
+ pass: z.boolean().optional().describe('default true; set false if the expected result is NOT visible'),
18
+ reason: z.string().optional().describe('extra detail (what you saw / why it failed)'),
19
+ },
20
+ }, async ({ sessionId, assertion, pass = true, reason }) => {
21
+ const session = sessions.get(sessionId);
22
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
23
+ if (!session || !driver) {
24
+ return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target first.'] });
25
+ }
26
+ if (session.sensitive)
27
+ return sensitiveRefusal('Visual assertion (screenshot)');
28
+ let uri;
29
+ let coordinateSpace;
30
+ try {
31
+ const png = await driver.screenshot();
32
+ uri = sessions.saveArtifact(session, 'screenshot', `visual-${Date.now()}.png`, png, 'image/png', `visual assertion: ${assertion}`);
33
+ sessions.bump(session, 'screenshots');
34
+ coordinateSpace = await captureCoordinateSpace(driver, png);
35
+ }
36
+ catch (e) {
37
+ return qaError({ what: `Could not capture the screenshot evidence: ${String(e)}`, changedState: false, retrySafe: true, nextSteps: ['Confirm the device is online (qa_doctor), then retry.'] });
38
+ }
39
+ sessions.addNote(session, {
40
+ at: Date.now(),
41
+ workflow: assertion,
42
+ outcome: pass ? 'pass' : 'fail',
43
+ reason,
44
+ method: 'visual',
45
+ evidenceKind: 'visual_match',
46
+ artifactUris: [uri],
47
+ verifiedVisually: true,
48
+ });
49
+ if (pass) {
50
+ const screenshotCrop = coordinateSpace?.screenshot
51
+ ? { x: 0, y: 0, width: coordinateSpace.screenshot.width, height: coordinateSpace.screenshot.height }
52
+ : undefined;
53
+ sessions.addRecordedAction(session, {
54
+ at: Date.now(),
55
+ action: 'assert_visual',
56
+ assertion,
57
+ exportability: 'semantic',
58
+ provenance: {
59
+ screenshotUri: uri,
60
+ selectorKind: 'visual_region',
61
+ selectorValue: assertion,
62
+ visual: {
63
+ screenshotCrop,
64
+ confidence: 1,
65
+ density: coordinateSpace?.density ?? null,
66
+ orientation: coordinateSpace?.orientation,
67
+ },
68
+ },
69
+ });
70
+ }
71
+ return qaOk({ assertion, pass, verifiedVisually: true, method: 'visual', screenshotUri: uri, coordinateSpace }, `visual assertion ${pass ? '✅ PASS' : '❌ FAIL'}: "${assertion}"\nevidence: ${uri}`);
72
+ });
73
+ }
74
+ //# sourceMappingURL=assertVisual.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertVisual.js","sourceRoot":"","sources":["../../src/tools/assertVisual.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,394 @@
1
+ // SWIPIUM-REQ-04 — "Automate my app" MCP tools. Generates a runnable JS/TS or Python Appium POM
2
+ // suite from a session's recorded actions, adapting to the project's language/platform/test stack.
3
+ //
4
+ // qa_automation_plan — read-only: project profile + generation plan + blockers.
5
+ // qa_automation_generate — emit + write the JS/Python suite (+ README, optional CI), validate.
6
+ // qa_automation_validate — validate generated code without a device (secrets, durability, syntax).
7
+ //
8
+ // The canonical Swipium YAML/POM remains the intermediate model (non-goal: don't replace it). JS/Python
9
+ // are emitted on top so they can't drift. Project-file mutation (integrateIntoProject) is consent-gated.
10
+ import { z } from 'zod';
11
+ import { existsSync, readdirSync, readFileSync, statSync, mkdirSync, writeFileSync } from 'node:fs';
12
+ import { join, relative, dirname } from 'node:path';
13
+ import { qaOk, qaError } from '../lib/result.js';
14
+ import { requireConsent, consumeConsent } from '../consent/consent.js';
15
+ import { assembleAutomationSuite, buildAutomationProfile, writeAutomationFiles, mapPresent, } from '../services/automationGenerate.js';
16
+ import { buildSuitePlan } from '../automationGen/suitePlan.js';
17
+ import { buildProjectProfile } from '../automationGen/projectProfile.js';
18
+ import { validateGeneratedSuite } from '../automationGen/validation.js';
19
+ import { getDriver } from '../session/attach.js';
20
+ import { runExplore } from '../explore/runner.js';
21
+ import { ensurePrelaunchAppMap } from '../appMap/prelaunch.js';
22
+ import { loadAppMap } from '../appMap/store.js';
23
+ import { detectFramework } from '../context/detect.js';
24
+ import { deriveAutomationLinks, linkAutomationSuite } from '../appMap/automationLink.js';
25
+ import { mergeFromAutomation } from '../services/testSuiteKnowledge.js';
26
+ import { bootstrapFeatureExecution } from '../featureTesting/executionBootstrap.js';
27
+ import { log } from '../lib/logger.js';
28
+ const languageEnum = z.enum(['auto', 'javascript', 'typescript', 'python']);
29
+ const platformEnum = z.enum(['auto', 'android', 'ios', 'both']);
30
+ const backendEnum = z.enum(['auto', 'appium', 'swipium_flow']);
31
+ /** Merge a prebuilt appMapUri into a tool result's structured content (Fix 6 — a bootstrap blocker
32
+ * still built the static map, so the URI must survive on the returned blocker/consent result). */
33
+ function withAppMapUri(result, appMapUri) {
34
+ if (!appMapUri)
35
+ return result;
36
+ const sc = (result.structuredContent ?? {});
37
+ if (sc.appMapUri)
38
+ return result;
39
+ return { ...result, structuredContent: { ...sc, appMapUri } };
40
+ }
41
+ function resolveRoot(sessions, sessionId, projectRoot) {
42
+ if (sessionId) {
43
+ const session = sessions.get(sessionId);
44
+ if (session)
45
+ return { session, root: session.root };
46
+ }
47
+ return { root: projectRoot };
48
+ }
49
+ /** profileInputs from tool args. */
50
+ function profileInputs(language, platform, integrateIntoProject) {
51
+ return {
52
+ language: (language ?? 'auto'),
53
+ platform: (platform ?? 'auto'),
54
+ integrateIntoProject: integrateIntoProject ?? false,
55
+ };
56
+ }
57
+ /** Read an already-generated suite from disk for validation (projectRoot path, no session). */
58
+ function readGeneratedFromDisk(root, outputDir) {
59
+ const base = join(root, outputDir);
60
+ if (!existsSync(base))
61
+ return [];
62
+ const files = [];
63
+ const walk = (dir) => {
64
+ for (const name of readdirSync(dir)) {
65
+ const abs = join(dir, name);
66
+ const st = statSync(abs);
67
+ if (st.isDirectory())
68
+ walk(abs);
69
+ else if (st.isFile())
70
+ files.push({ path: relative(base, abs), content: readFileSync(abs, 'utf8') });
71
+ }
72
+ };
73
+ walk(base);
74
+ return files;
75
+ }
76
+ export function registerAutomationGenerate(server, sessions) {
77
+ // ---- qa_automation_plan ----
78
+ server.registerTool('qa_automation_plan', {
79
+ title: 'Plan an Appium automation suite',
80
+ description: 'Read-only. Inspect the project (language, platform support, existing test stack) and build a plan for an "Automate my app" Appium POM suite: selected automation language (JS/TS/Python), Android-first/iOS backends, app-map/recorded-action coverage, the files that would be generated, locator readiness, and blockers. Pass sessionId to use recorded actions, or projectRoot to plan from scratch.',
81
+ inputSchema: {
82
+ sessionId: z.string().optional(),
83
+ projectRoot: z.string().optional(),
84
+ feature: z.string().optional().describe('Optional feature label to focus the suite (recorded for the plan).'),
85
+ language: languageEnum.optional(),
86
+ platform: platformEnum.optional(),
87
+ backend: backendEnum.optional(),
88
+ includeCi: z.boolean().optional(),
89
+ },
90
+ }, async ({ sessionId, projectRoot, feature, language, platform, backend, includeCi }) => {
91
+ const { session, root } = resolveRoot(sessions, sessionId, projectRoot);
92
+ if (!root)
93
+ return qaError({ what: 'No project root', changedState: false, retrySafe: true, nextSteps: ['Pass sessionId or projectRoot.'] });
94
+ const inputs = profileInputs(language, platform);
95
+ const profile = session ? buildAutomationProfile(session, inputs) : buildAutomationProfileFromRoot(root, inputs);
96
+ let plan;
97
+ if (session && session.recordedActions.length) {
98
+ const assembled = assembleAutomationSuite(session, { ...inputs, includeCi });
99
+ plan = assembled.plan;
100
+ }
101
+ else {
102
+ plan = buildSuitePlan(profile, { actionCount: session?.recordedActions.length ?? 0, mapPresent: mapPresent(root), includeCi });
103
+ }
104
+ const backendNote = backend && backend !== 'auto' && backend !== 'appium'
105
+ ? `\nNote: backend=${backend} requested — Appium code is generated as an ADDITIONAL layer; existing ${backend} flows are kept.`
106
+ : '';
107
+ const featureNote = feature ? ` (feature focus: ${feature})` : '';
108
+ const summary = `Automation plan${featureNote}: ${profile.automationLanguage} / ${profile.testFramework}, ` +
109
+ `default backend ${profile.defaultBackend}${profile.secondaryBackend ? ` (+${profile.secondaryBackend})` : ''}.\n` +
110
+ `platforms: android=${profile.platforms.android.level}, ios=${profile.platforms.ios.level}\n` +
111
+ (plan.mapCoverage
112
+ ? `coverage: ${plan.mapCoverage.actionCount} step(s), ${plan.mapCoverage.screenCount} screen(s); locators ${plan.locatorReadiness} (${plan.mapCoverage.brittlePct}% brittle)`
113
+ : 'coverage: no recorded actions yet') +
114
+ (plan.blockers.length ? `\nblockers: ${plan.blockers.map((b) => b.code).join(', ')}` : '') +
115
+ `\nfiles planned: ${plan.filesPlanned.length}\nnext: ${plan.nextAction}` +
116
+ backendNote;
117
+ return qaOk({ profile, plan, feature: feature ?? null, backend: backend ?? 'auto' }, summary);
118
+ });
119
+ // ---- qa_automation_generate ----
120
+ server.registerTool('qa_automation_generate', {
121
+ title: 'Generate an Appium automation suite',
122
+ description: 'Generate a runnable Appium POM suite from this session\'s recorded actions, adapting to the project language: WebdriverIO TS/JS or Python (Appium-Python-Client). Writes page/screen objects (centralized selectors), env-driven capabilities, structured waits, a smoke test, and a README under .swipium/automation/<lang>/ by default. Never inlines secrets; marks brittle/coordinate locators non-release-grade; never emits XPath. integrateIntoProject (consent-gated) writes into the project e2e dir without overwriting existing files.',
123
+ inputSchema: {
124
+ sessionId: z.string().optional().describe('Prepared session with recorded actions. Omit to bootstrap from projectRoot.'),
125
+ projectRoot: z.string().optional().describe('Project root — used to bootstrap a device/session when no sessionId is given (Fix 6 one-call workflow).'),
126
+ bootstrap: z.union([z.boolean(), z.literal('auto')]).optional().describe('Bootstrap the missing map/session/actions safely (smoke+explore) when none exist. Default "auto" when no sessionId is provided.'),
127
+ feature: z.string().optional().describe('Optional focus for the bootstrap exploration.'),
128
+ device: z.string().optional().describe('Specific device/simulator to prepare when bootstrapping.'),
129
+ name: z.string().optional(),
130
+ language: languageEnum.optional(),
131
+ platform: platformEnum.optional(),
132
+ save: z.boolean().optional().describe('Write files (default true).'),
133
+ integrateIntoProject: z.boolean().optional().describe('Write into the project test dir instead of .swipium (consent-gated, never overwrites).'),
134
+ includeCi: z.boolean().optional().describe('Also emit ci.example.yml.'),
135
+ candidateOnly: z.boolean().optional().describe('Label the suite candidate-only so brittle locators do not fail validation.'),
136
+ brittleThreshold: z.number().optional().describe('Max brittle-locator percent before validation fails (default 40).'),
137
+ consentId: z.string().optional(),
138
+ approve: z.boolean().optional(),
139
+ },
140
+ }, async ({ sessionId, projectRoot, bootstrap, feature, device, name, language, platform, save, integrateIntoProject, includeCi, candidateOnly, brittleThreshold, consentId, approve }) => {
141
+ let session = sessionId ? sessions.get(sessionId) : undefined;
142
+ if (sessionId && !session)
143
+ return qaError({ what: `Unknown sessionId ${sessionId}`, changedState: false, retrySafe: true, nextSteps: ['Call qa_start_session first, or omit sessionId to bootstrap from projectRoot.'] });
144
+ // Fix 6 — one-call "Automate my app": when no session/actions exist, build the static app map
145
+ // (so it always exists) and bootstrap a device (consent-gated) + record actions via exploration.
146
+ const wantBootstrap = bootstrap !== false && (bootstrap === true || bootstrap === 'auto' || !sessionId);
147
+ let appMapUri;
148
+ const rootForMap = session?.root ?? (projectRoot && projectRoot.trim() ? projectRoot.trim() : undefined);
149
+ if (rootForMap && existsSync(rootForMap)) {
150
+ try {
151
+ appMapUri = ensurePrelaunchAppMap(rootForMap, { at: new Date().toISOString() }).appMapUri;
152
+ }
153
+ catch (e) {
154
+ log('warn', 'automation prelaunch app map failed', { err: String(e) });
155
+ }
156
+ }
157
+ if ((!session || !session.recordedActions.length) && wantBootstrap) {
158
+ let driver = session ? (await getDriver(session)).driver : undefined;
159
+ if (!session || !driver) {
160
+ if (!projectRoot?.trim() && !session) {
161
+ return qaError({ what: 'Need a sessionId or projectRoot to bootstrap an automation suite', changedState: false, retrySafe: true, nextSteps: ['Pass projectRoot="/abs/path" (bootstrap defaults on), or a prepared sessionId.'] }, appMapUri ? { appMapUri } : {});
162
+ }
163
+ const boot = await bootstrapFeatureExecution({ server, sessions, projectRoot: projectRoot?.trim() ?? session.root, feature: feature ?? 'create automation suite', platform: platform === 'android' || platform === 'ios' ? platform : undefined, device, consentId, approve });
164
+ // Honest target blocker / consent request — but the static app map WAS still built, so the
165
+ // caller can read it even though no device/artifact is available (Fix 6 acceptance).
166
+ if (!boot.ok)
167
+ return withAppMapUri(boot.result, appMapUri);
168
+ session = boot.session;
169
+ driver = boot.driver;
170
+ if (!appMapUri && existsSync(session.root)) {
171
+ try {
172
+ appMapUri = ensurePrelaunchAppMap(session.root, { at: new Date().toISOString() }).appMapUri;
173
+ }
174
+ catch { /* best-effort */ }
175
+ }
176
+ }
177
+ // Record durable actions via a bounded, safe exploration so generation has something to emit.
178
+ if (driver && !session.recordedActions.length) {
179
+ try {
180
+ await runExplore(sessions, session, driver, { goal: feature, maxScreens: 6, maxActions: 16, stopOnAuth: true });
181
+ }
182
+ catch (e) {
183
+ log('warn', 'automation bootstrap exploration failed', { err: String(e) });
184
+ }
185
+ }
186
+ }
187
+ if (!session)
188
+ return qaError({ what: 'Need a sessionId or projectRoot', changedState: false, retrySafe: true, nextSteps: ['Pass a prepared sessionId, or projectRoot to bootstrap.'] }, appMapUri ? { appMapUri } : {});
189
+ if (!session.recordedActions.length) {
190
+ return qaError({
191
+ what: 'No recorded actions to turn into an automation suite (bootstrap could not record any)',
192
+ changedState: false,
193
+ retrySafe: true,
194
+ failureCode: 'NO_RECORDED_ACTIONS',
195
+ nextSteps: [
196
+ 'Run qa_test_this { goal: "create_automation_suite" } (smoke + explore records actions + builds the app map), then re-run qa_automation_generate.',
197
+ 'Or drive the app with qa_act/qa_smoke/qa_explore first.',
198
+ ],
199
+ }, appMapUri ? { appMapUri } : {});
200
+ }
201
+ const inputs = profileInputs(language, platform, integrateIntoProject);
202
+ const assembled = assembleAutomationSuite(session, { ...inputs, name, includeCi });
203
+ const validation = validateGeneratedSuite(assembled.files, {
204
+ brittlePct: assembled.model.audit.brittlePct,
205
+ brittleThreshold,
206
+ candidateOnly,
207
+ secrets: assembled.model.secrets,
208
+ });
209
+ const doSave = save !== false;
210
+ let written = [];
211
+ let targetDir = assembled.outputDir;
212
+ let integrated = false;
213
+ let skippedExisting = [];
214
+ if (doSave && integrateIntoProject) {
215
+ // Consent-gated project mutation; never overwrite existing files.
216
+ const projectDir = projectTestDir(session.root, assembled.profile.automationLanguage);
217
+ const affects = { projectDir, files: assembled.files.map((f) => f.path) };
218
+ const gate = consumeConsent(consentId, approve, { action: 'automation_project_write', affects });
219
+ if (!gate.approved) {
220
+ return requireConsent({
221
+ action: 'automation_project_write',
222
+ risk: 'medium',
223
+ exactCommand: `write ${assembled.files.length} files into ${projectDir} (no overwrite)`,
224
+ affects,
225
+ explain: `Write the generated Appium suite into your project at ${projectDir}? Existing files are never overwritten.`,
226
+ });
227
+ }
228
+ const res = writeProjectFilesNoOverwrite(session.root, projectDir, assembled.files);
229
+ written = res.written;
230
+ skippedExisting = res.skipped;
231
+ targetDir = projectDir;
232
+ integrated = true;
233
+ sessions.recordMutation(session, {
234
+ tool: 'qa_automation_generate',
235
+ action: 'automation_project_write',
236
+ risk: 'medium',
237
+ target: affects,
238
+ consent: { required: true, consentId, approved: true },
239
+ status: 'executed',
240
+ });
241
+ }
242
+ else if (doSave) {
243
+ written = writeAutomationFiles(session.root, assembled.outputDir, assembled.files);
244
+ }
245
+ // Fix 7 — link the generated suite back into the durable app map + persistent suite, so future
246
+ // feature/ticket decisions know which flows are automated. Best-effort (warnings, never fatal).
247
+ let suiteDelta;
248
+ let suiteUri;
249
+ const automationWarnings = [];
250
+ if (doSave) {
251
+ const now = new Date().toISOString();
252
+ const screenNames = assembled.model.screens.map((s) => s.pageName || s.className);
253
+ try {
254
+ const fw = detectFramework(session.root);
255
+ const fallback = { root: session.root, gitRemote: null, packageName: null, workspaceTarget: null, framework: fw, platforms: fw === 'native-android' ? ['android'] : fw === 'native-ios' ? ['ios'] : ['android', 'ios'] };
256
+ const existingMap = loadAppMap(session.root, fallback, now).map;
257
+ const links = existingMap ? deriveAutomationLinks(existingMap, screenNames) : { screenIds: [], featureIds: [] };
258
+ const suiteRef = {
259
+ name: name ?? `swipium-appium-${assembled.profile.automationLanguage}`,
260
+ path: targetDir,
261
+ framework: assembled.profile.automationLanguage === 'python' ? 'appium-python' : 'wdio',
262
+ linkedFeatureIds: links.featureIds,
263
+ linkedScreenIds: links.screenIds,
264
+ };
265
+ const linkRes = linkAutomationSuite(session.root, suiteRef, now);
266
+ if (linkRes.ok)
267
+ appMapUri = linkRes.appMapUri ?? appMapUri;
268
+ else
269
+ automationWarnings.push('app map not found — automation suite not linked into the map');
270
+ }
271
+ catch (e) {
272
+ automationWarnings.push(`app-map automation link failed: ${String(e)}`);
273
+ }
274
+ try {
275
+ const fw2 = detectFramework(session.root);
276
+ const fb2 = { root: session.root, gitRemote: null, packageName: null, workspaceTarget: null, framework: fw2, platforms: fw2 === 'native-android' ? ['android'] : fw2 === 'native-ios' ? ['ios'] : ['android', 'ios'] };
277
+ const mapForLinks = loadAppMap(session.root, fb2, now).map;
278
+ const links = mapForLinks ? deriveAutomationLinks(mapForLinks, assembled.model.screens.map((s) => s.pageName || s.className)) : { screenIds: [], featureIds: [] };
279
+ const merge = mergeFromAutomation(session.root, session, { assembled, validationOk: validation.ok, links }, { source: 'generate', now, runId: `automation-${Date.now()}`, sourceUri: appMapUri, appId: session.appId, sessionId: session.id });
280
+ suiteDelta = merge.delta;
281
+ suiteUri = merge.suiteUri;
282
+ if (merge.warning)
283
+ automationWarnings.push(merge.warning);
284
+ }
285
+ catch (e) {
286
+ automationWarnings.push(`suite automation merge failed: ${String(e)}`);
287
+ }
288
+ }
289
+ const a = assembled.model.audit;
290
+ const recommendation = integrated
291
+ ? undefined
292
+ : assembled.profile.outputMode === 'project_native'
293
+ ? 'Copy the suite into your project test dir, or re-run with integrateIntoProject:true (consent-gated).'
294
+ : `Generated under ${assembled.outputDir}. Install deps (${assembled.dependencyPatch.notes[0]}) and run per the README.`;
295
+ const summary = `✅ Generated ${assembled.profile.automationLanguage} Appium POM suite (${assembled.model.screens.length} screen(s), ${assembled.files.length} files).\n` +
296
+ `runner ${assembled.profile.testFramework}; backend ${assembled.profile.defaultBackend}${assembled.profile.secondaryBackend ? ` (+${assembled.profile.secondaryBackend})` : ''}\n` +
297
+ `locators: ${a.durable} durable / ${a.semi} semi / ${a.brittle} brittle (${a.brittlePct}% brittle)\n` +
298
+ `validation: ${validation.ok ? 'passed' : 'FAILED'} (${validation.findings.filter((f) => f.severity === 'error').length} error, ${validation.findings.filter((f) => f.severity === 'warning').length} warn); secrets ${validation.secretsClean ? 'clean' : 'LEAK'}\n` +
299
+ (written.length ? `wrote ${written.length} files under ${join(session.root, targetDir)}` : '(preview — pass save:true)') +
300
+ (skippedExisting.length ? `\nskipped ${skippedExisting.length} existing file(s) (no overwrite): ${skippedExisting.slice(0, 5).join(', ')}` : '') +
301
+ (recommendation ? `\n${recommendation}` : '');
302
+ return qaOk({
303
+ profile: assembled.profile,
304
+ outputDir: targetDir,
305
+ integrated,
306
+ files: assembled.files.map((f) => f.path),
307
+ written,
308
+ skippedExisting,
309
+ screens: assembled.model.screens.map((s) => s.className),
310
+ variables: assembled.model.variables,
311
+ secrets: assembled.model.secrets,
312
+ audit: a,
313
+ validation,
314
+ dependencyPatch: assembled.dependencyPatch,
315
+ plan: assembled.plan,
316
+ appMapUri: appMapUri ?? null,
317
+ suiteDelta: suiteDelta ?? null,
318
+ suiteUri: suiteUri ?? null,
319
+ automationWarnings,
320
+ }, summary);
321
+ });
322
+ // ---- qa_automation_validate ----
323
+ server.registerTool('qa_automation_validate', {
324
+ title: 'Validate a generated automation suite',
325
+ description: 'Validate generated Appium code without a device: no inlined secrets, locator durability within threshold (unless candidate-only), capability config present, balanced JS/TS syntax, no empty files. Pass sessionId to validate the suite from recorded actions, or projectRoot to validate already-written files under .swipium/automation/<lang>/.',
326
+ inputSchema: {
327
+ sessionId: z.string().optional(),
328
+ projectRoot: z.string().optional(),
329
+ language: languageEnum.optional(),
330
+ platform: platformEnum.optional(),
331
+ candidateOnly: z.boolean().optional(),
332
+ brittleThreshold: z.number().optional(),
333
+ },
334
+ }, async ({ sessionId, projectRoot, language, platform, candidateOnly, brittleThreshold }) => {
335
+ const { session, root } = resolveRoot(sessions, sessionId, projectRoot);
336
+ if (!root)
337
+ return qaError({ what: 'No project root', changedState: false, retrySafe: true, nextSteps: ['Pass sessionId or projectRoot.'] });
338
+ const inputs = profileInputs(language, platform);
339
+ let files;
340
+ let brittlePct = 0;
341
+ let secrets = [];
342
+ if (session && session.recordedActions.length) {
343
+ const assembled = assembleAutomationSuite(session, inputs);
344
+ files = assembled.files;
345
+ brittlePct = assembled.model.audit.brittlePct;
346
+ secrets = assembled.model.secrets;
347
+ }
348
+ else {
349
+ const profile = session ? buildAutomationProfile(session, inputs) : buildAutomationProfileFromRoot(root, inputs);
350
+ const outputDir = `.swipium/automation/${profile.automationLanguage === 'python' ? 'python' : 'js'}`;
351
+ files = readGeneratedFromDisk(root, outputDir);
352
+ if (!files.length) {
353
+ return qaError({
354
+ what: `No generated suite found under ${outputDir}`,
355
+ changedState: false,
356
+ retrySafe: true,
357
+ nextSteps: ['Run qa_automation_generate first, or pass a sessionId with recorded actions.'],
358
+ });
359
+ }
360
+ }
361
+ const validation = validateGeneratedSuite(files, { brittlePct, brittleThreshold, candidateOnly, secrets });
362
+ const errors = validation.findings.filter((f) => f.severity === 'error');
363
+ const summary = `Validation ${validation.ok ? 'passed' : 'FAILED'}: ${errors.length} error(s), ${validation.findings.length - errors.length} warning(s) over ${validation.filesChecked} files.\n` +
364
+ `secrets ${validation.secretsClean ? 'clean' : 'LEAK DETECTED'}; brittle ${validation.brittlePct}% (threshold ${validation.brittleThreshold}%${validation.candidateOnly ? ', candidate-only' : ''})` +
365
+ (validation.findings.length ? `\n` + validation.findings.slice(0, 12).map((f) => ` ${f.severity === 'error' ? '✗' : '⚠'} ${f.code}${f.file ? ` (${f.file})` : ''}: ${f.message}`).join('\n') : '');
366
+ const payload = { validation };
367
+ return validation.ok ? qaOk(payload, summary) : qaError({ what: 'Generated suite failed validation', changedState: false, retrySafe: true, failureCode: 'VALIDATION_FAILED', nextSteps: errors.map((e) => e.message) }, payload);
368
+ });
369
+ }
370
+ // ---- helpers that need root-only (no session) profile ----
371
+ function buildAutomationProfileFromRoot(root, inputs) {
372
+ return buildProjectProfile(root, inputs);
373
+ }
374
+ function projectTestDir(root, language) {
375
+ const candidates = language === 'python' ? ['tests/e2e', 'e2e', 'tests'] : ['e2e', 'test/e2e', 'tests/e2e'];
376
+ const found = candidates.find((c) => existsSync(join(root, c)));
377
+ return found ?? (language === 'python' ? 'tests/e2e' : 'e2e');
378
+ }
379
+ function writeProjectFilesNoOverwrite(root, dir, files) {
380
+ const written = [];
381
+ const skipped = [];
382
+ for (const f of files) {
383
+ const abs = join(root, dir, f.path);
384
+ if (existsSync(abs)) {
385
+ skipped.push(f.path);
386
+ continue;
387
+ }
388
+ mkdirSync(dirname(abs), { recursive: true });
389
+ writeFileSync(abs, f.content);
390
+ written.push(abs);
391
+ }
392
+ return { written, skipped };
393
+ }
394
+ //# sourceMappingURL=automationGenerate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automationGenerate.js","sourceRoot":"","sources":["../../src/tools/automationGenerate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { z } from 'zod';
2
+ import { qaOk } from '../lib/result.js';
3
+ import { SWIPIUM_VERSION, TOOL_COUNT } from '../version.js';
4
+ export const CAPABILITY_GROUPS = [
5
+ {
6
+ group: 'start',
7
+ purpose: 'Start a simulator QA run and recover from blockers.',
8
+ tools: [
9
+ { name: 'qa_agent_brief', summary: 'Brief for agent orchestration: first call, polling, report fetch, and blocker rules.' },
10
+ { name: 'qa_capabilities', summary: 'Grouped overview of the public v1 tool surface.' },
11
+ { name: 'qa_test_this', summary: 'Autopilot for "test it": resolve, prepare, smoke, explore, report, and optional suite output.' },
12
+ { name: 'qa_job_status', summary: 'Poll long-running jobs started by macro tools.' },
13
+ { name: 'qa_status', summary: 'Compact session status and current next action.' },
14
+ { name: 'qa_explain_blocker', summary: 'Explain a typed blocker and the owner of the fix.' },
15
+ { name: 'qa_continue_from_blocker', summary: 'Resume after user input, with secret redaction.' },
16
+ { name: 'qa_get_artifact', summary: 'Fetch Swipium artifact metadata or contents by URI.' },
17
+ ],
18
+ },
19
+ {
20
+ group: 'setup',
21
+ purpose: 'Resolve the project, create a session, and prepare Android Emulator or iOS Simulator targets.',
22
+ tools: [
23
+ { name: 'qa_doctor', summary: 'Check local toolchain readiness.' },
24
+ { name: 'qa_start_session', summary: 'Open a project session with budget and response mode.' },
25
+ { name: 'qa_detect_context', summary: 'Detect project framework, artifacts, devices, and blockers.' },
26
+ { name: 'qa_plan', summary: 'Propose safe workflows before acting.' },
27
+ { name: 'qa_prepare_target', summary: 'Prepare Android Emulator target and launch an APK.' },
28
+ { name: 'qa_prepare_ios_target', summary: 'Prepare iOS Simulator target and launch a simulator .app.' },
29
+ { name: 'qa_ios', summary: 'iOS Simulator operations: boot, install, launch, screenshot, logs, and reset.' },
30
+ { name: 'qa_wda', summary: 'WebDriverAgent attach/build/start for structured iOS Simulator automation.' },
31
+ ],
32
+ },
33
+ {
34
+ group: 'drive',
35
+ purpose: 'Observe, act, and make deterministic health assertions.',
36
+ tools: [
37
+ { name: 'qa_snapshot', summary: 'Capture compact structured UI elements.' },
38
+ { name: 'qa_act', summary: 'Tap, type, clear, swipe, scroll, press, open URL, or wait, then observe.' },
39
+ { name: 'qa_clear_overlay', summary: 'Dismiss common overlays blocking a target.' },
40
+ { name: 'qa_check_health', summary: 'Detect crash, ANR, error boundaries, and foreground health.' },
41
+ { name: 'qa_screenshot', summary: 'Capture a screenshot artifact.' },
42
+ { name: 'qa_note', summary: 'Record a structured QA outcome.' },
43
+ { name: 'qa_assert_visual', summary: 'Capture a visual assertion with evidence.' },
44
+ ],
45
+ },
46
+ {
47
+ group: 'run',
48
+ purpose: 'Run smoke checks, exploration, and reports.',
49
+ tools: [
50
+ { name: 'qa_smoke', summary: 'Run launch smoke and saved flows.' },
51
+ { name: 'qa_explore', summary: 'Guided simulator exploration with evidence and graph output.' },
52
+ { name: 'qa_report', summary: 'Summarize findings, blockers, evidence, and next actions.' },
53
+ ],
54
+ },
55
+ {
56
+ group: 'app-map',
57
+ purpose: 'Maintain the app knowledge map used as Swipium project memory.',
58
+ tools: [
59
+ { name: 'qa_app_map_build', summary: 'Build or update the app map from static analysis and exploration.' },
60
+ { name: 'qa_app_map_read', summary: 'Read compact app map sections.' },
61
+ { name: 'qa_app_map_query', summary: 'Search screens, features, tests, and code links.' },
62
+ { name: 'qa_app_map_feature_scope', summary: 'Resolve a feature query to a focused test scope.' },
63
+ { name: 'qa_app_map_validate', summary: 'Validate schema, provenance, and map links.' },
64
+ ],
65
+ },
66
+ {
67
+ group: 'flows',
68
+ purpose: 'Create and run durable simulator flows and test suites.',
69
+ tools: [
70
+ { name: 'qa_flow_check', summary: 'Parse and statically validate a Swipium flow.' },
71
+ { name: 'qa_flow_run', summary: 'Execute a flow against a prepared simulator session.' },
72
+ { name: 'qa_flow_generate', summary: 'Generate a flow from recorded actions.' },
73
+ { name: 'qa_suite_generate', summary: 'Generate a POM-style suite from recorded actions.' },
74
+ { name: 'qa_suite_compile', summary: 'Compile a generated suite into runnable flows.' },
75
+ { name: 'qa_testcase_generate', summary: 'Generate test case documentation from recorded behavior.' },
76
+ ],
77
+ },
78
+ {
79
+ group: 'first-run',
80
+ purpose: 'Handle login, account creation, onboarding, and paywall first-run screens safely.',
81
+ tools: [
82
+ { name: 'qa_first_run_plan', summary: 'Classify the current first-run screen and produce a safe plan.' },
83
+ { name: 'qa_first_run_continue', summary: 'Execute bounded first-run steps with safe generated test data when allowed.' },
84
+ ],
85
+ },
86
+ {
87
+ group: 'automation',
88
+ purpose: 'Generate Appium automation code from Swipium evidence on request.',
89
+ tools: [
90
+ { name: 'qa_automation_plan', summary: 'Plan generated JS/TS or Python Appium automation.' },
91
+ { name: 'qa_automation_generate', summary: 'Generate an Appium POM suite from recorded actions.' },
92
+ { name: 'qa_automation_validate', summary: 'Validate generated automation code without a device.' },
93
+ ],
94
+ },
95
+ ];
96
+ const groupNames = CAPABILITY_GROUPS.map((g) => g.group);
97
+ export function registerCapabilities(server, _sessions) {
98
+ server.registerTool('qa_capabilities', {
99
+ title: 'List Swipium capabilities',
100
+ description: 'Return the public Swipium v1 tools grouped by purpose with short summaries.',
101
+ inputSchema: {
102
+ group: z.enum(groupNames).optional().describe('Return only this group.'),
103
+ },
104
+ }, async ({ group }) => {
105
+ const groups = group ? CAPABILITY_GROUPS.filter((g) => g.group === group) : CAPABILITY_GROUPS;
106
+ const summary = `Swipium v${SWIPIUM_VERSION}: ${TOOL_COUNT} public v1 tools in ${CAPABILITY_GROUPS.length} groups.\n` +
107
+ groups
108
+ .map((g) => `\n[${g.group}] ${g.purpose}\n` + g.tools.map((t) => ` - ${t.name}: ${t.summary}`).join('\n'))
109
+ .join('\n') +
110
+ '\n\nStart with qa_test_this for low-context "test it" requests.';
111
+ return qaOk({ swipiumVersion: SWIPIUM_VERSION, totalTools: TOOL_COUNT, groups }, summary);
112
+ });
113
+ }
114
+ //# sourceMappingURL=capabilities.js.map