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,331 @@
1
+ // qa_flow_check + qa_flow_run.
2
+ // Flows live as .swipium/flows/*.yaml. check = parse + static validation (no device).
3
+ // run = the orchestrator (src/flows/run.ts), reporting the exact failing step + evidence.
4
+ import { z } from 'zod';
5
+ import { createHash } from 'node:crypto';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join, isAbsolute } from 'node:path';
8
+ import { qaOk, qaError, qaStop } from '../lib/result.js';
9
+ import { parseFlow } from '../flows/schema.js';
10
+ import { lintFlowObjectWithOptions } from '../flows/lint.js';
11
+ import { runFlow } from '../flows/run.js';
12
+ import { getDriver } from '../session/attach.js';
13
+ import { loadPolicy } from '../report/policy.js';
14
+ import { classifyFlakeResults } from '../report/flake.js';
15
+ import { validateCiMutationPolicy, validateCiVariables } from '../ci/preflight.js';
16
+ import { requireConsent, consumeConsent } from '../consent/consent.js';
17
+ import { displayArgv } from '../lib/commandTemplate.js';
18
+ import { GitScopeForbiddenError } from '../lib/spawn.js';
19
+ import { configuredOcrCommand } from '../visual/ocr.js';
20
+ import { resolveMaskProvider, resolveVisualProvider } from '../visual/provider.js';
21
+ /** Resolve a flow's YAML from explicit text, an absolute/relative path, or a name under .swipium/flows. */
22
+ function loadFlowSource(root, flow, flowYaml) {
23
+ if (flowYaml && flowYaml.trim())
24
+ return { yamlText: flowYaml, source: 'inline' };
25
+ if (!flow)
26
+ return { error: 'Provide a flow name, a path, or flowYaml.' };
27
+ const candidates = [];
28
+ if (isAbsolute(flow))
29
+ candidates.push(flow);
30
+ else if (root) {
31
+ if (/[\\/]/.test(flow) || /\.ya?ml$/i.test(flow))
32
+ candidates.push(join(root, flow));
33
+ candidates.push(join(root, '.swipium', 'flows', `${flow}.yaml`), join(root, '.swipium', 'flows', `${flow}.yml`), join(root, '.swipium', 'flows', flow));
34
+ }
35
+ for (const p of candidates) {
36
+ if (existsSync(p)) {
37
+ try {
38
+ return { yamlText: readFileSync(p, 'utf8'), source: p };
39
+ }
40
+ catch (e) {
41
+ return { error: `Could not read ${p}: ${String(e)}` };
42
+ }
43
+ }
44
+ }
45
+ return { error: `Flow not found. Looked for: ${candidates.join(', ') || '(no project root)'}` };
46
+ }
47
+ const MUTATING_FLOW_STEPS = new Set(['networkOffline', 'networkOnline', 'seed', 'restartApp']);
48
+ const EXTERNAL_PROVIDER_FLOW_STEPS = new Set(['tapOcrText', 'assertOcrText']);
49
+ function stable(value) {
50
+ if (Array.isArray(value))
51
+ return value.map(stable);
52
+ if (value && typeof value === 'object')
53
+ return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, stable(v)]));
54
+ return value;
55
+ }
56
+ function fullHash(value) {
57
+ return createHash('sha256').update(JSON.stringify(stable(value))).digest('hex');
58
+ }
59
+ function hash(value) {
60
+ return fullHash(value).slice(0, 16);
61
+ }
62
+ function allFlowSteps(flow) {
63
+ return [...flow.setup, ...flow.steps, ...flow.teardown];
64
+ }
65
+ function flowMutationAffects(flow, session, source, repeat, externalProviders = []) {
66
+ const mutations = allFlowSteps(flow)
67
+ .map((step, index) => {
68
+ if (!MUTATING_FLOW_STEPS.has(step.kind))
69
+ return null;
70
+ if (step.kind === 'seed') {
71
+ const seedType = session.fixtures.find((f) => f.name === step.fixture)?.seed?.type ?? 'unknown';
72
+ return { step: index + 1, kind: step.kind, fixture: step.fixture, seedType };
73
+ }
74
+ return { step: index + 1, kind: step.kind };
75
+ })
76
+ .filter((x) => !!x);
77
+ return {
78
+ flow: flow.name,
79
+ source: source ?? 'inline',
80
+ flowHash: hash(flow),
81
+ appId: flow.appId ?? session.appId ?? null,
82
+ repeat,
83
+ mutations,
84
+ externalProviders,
85
+ };
86
+ }
87
+ function flowMutationRisk(affects) {
88
+ if (affects.mutations.some((m) => m.kind === 'seed' && m.seedType === 'script'))
89
+ return 'high';
90
+ if (affects.externalProviders.length || affects.mutations.some((m) => m.kind === 'networkOffline' || m.kind === 'networkOnline' || m.kind === 'seed'))
91
+ return 'medium';
92
+ return 'low';
93
+ }
94
+ function ocrSteps(flow) {
95
+ const out = [];
96
+ allFlowSteps(flow).forEach((step, index) => {
97
+ if (step.kind !== 'tapOcrText' && step.kind !== 'assertOcrText')
98
+ return;
99
+ out.push({ step: index + 1, kind: step.kind, query: step.query, minConfidence: step.minConfidence });
100
+ });
101
+ return out;
102
+ }
103
+ export function registerFlow(server, sessions) {
104
+ server.registerTool('qa_flow_check', {
105
+ title: 'Check a flow',
106
+ description: 'Parse and statically validate a Swipium flow (a .swipium/flows/*.yaml authored as name + steps) WITHOUT running it. Reports syntax/schema errors with the offending step, plus warnings (e.g. selector resolvability is only known at run time). Provide `flow` (a name under .swipium/flows, or a path) or `flowYaml` (inline). A sessionId lets it resolve names against that session\'s project root.',
107
+ inputSchema: {
108
+ sessionId: z.string().optional(),
109
+ flow: z.string().optional().describe('Flow name under .swipium/flows, or a path to a .yaml file.'),
110
+ flowYaml: z.string().optional().describe('Inline flow YAML (instead of a file).'),
111
+ platform: z.enum(['android', 'ios', 'cross-platform']).optional().describe('Optional authoring target for platform-aware warnings.'),
112
+ ci: z.boolean().optional().describe('When true, add CI preflight warnings such as missing variables and mutating steps not allowed by policy.'),
113
+ },
114
+ }, async ({ sessionId, flow, flowYaml, platform, ci }) => {
115
+ const root = sessionId ? sessions.get(sessionId)?.root : undefined;
116
+ const src = loadFlowSource(root, flow, flowYaml);
117
+ if (src.error)
118
+ return qaError({ what: src.error, changedState: false, retrySafe: true, nextSteps: ['Pass an existing flow name/path or inline flowYaml.'] });
119
+ const { flow: parsed, errors } = parseFlow(src.yamlText);
120
+ if (errors.length || !parsed) {
121
+ return qaError({ what: `Flow is invalid (${errors.length} error${errors.length === 1 ? '' : 's'})`, changedState: false, retrySafe: true, nextSteps: ['Fix the listed errors and re-check.'] }, { source: src.source, errors });
122
+ }
123
+ const allSteps = [...parsed.setup, ...parsed.steps, ...parsed.teardown];
124
+ const STRUCTURED_KINDS = new Set(['tap', 'assertVisible', 'assertNotVisible', 'scrollTo', 'waitForVisible', 'inputText']);
125
+ const warnings = [];
126
+ if (!parsed.appId)
127
+ warnings.push('No appId — a prepareTarget step will rely on the session\'s prepared appId.');
128
+ if (allSteps.some((s) => s.kind === 'tap' && s.selector.startsWith('@')))
129
+ warnings.push('Uses @ref selectors — refs are run-time only; prefer text/id selectors for durable flows.');
130
+ if (src.yamlText.includes('${'))
131
+ warnings.push('Uses ${VARIABLES} — provide them via qa_flow_run { variables } or the environment.');
132
+ const flowOcrSteps = ocrSteps(parsed);
133
+ if (flowOcrSteps.length) {
134
+ warnings.push(`Uses OCR visual-provider steps (${flowOcrSteps.map((s) => `${s.step}:${s.kind}`).join(', ')}); qa_flow_run will require provider consent and a configured ocrCommand.`);
135
+ if (root && !configuredOcrCommand(root))
136
+ warnings.push('OCR command is not configured in .swipium/config.json or SWIPIUM_OCR_CMD.');
137
+ }
138
+ // Backend/mode combination check (caught before runtime where the session's backend is known).
139
+ const driverKind = sessionId ? sessions.get(sessionId)?.driver?.kind : undefined;
140
+ const inferredPlatform = platform ?? (driverKind === 'simulator' || driverKind === 'wda' ? 'ios' : driverKind === 'direct' ? 'android' : undefined);
141
+ const usesStructured = allSteps.some((s) => STRUCTURED_KINDS.has(s.kind));
142
+ if (driverKind === 'simulator' && parsed.mode === 'structured') {
143
+ warnings.push('mode:structured on the iOS simulator backend — tap/assertVisible/inputText need a UI tree (unavailable). Use mode: visual with image/visual steps.');
144
+ }
145
+ if (parsed.mode === 'visual' && usesStructured) {
146
+ warnings.push('mode:visual but the flow uses structured steps (tap/assertVisible/…) — those need a UI tree and will fail on a visual-only screen.');
147
+ }
148
+ for (const s of allSteps) {
149
+ const text = s.kind === 'tap' ? s.selector : s.kind === 'inputText' ? s.into ?? s.value : 'query' in s && typeof s.query === 'string' ? s.query : '';
150
+ if (!text)
151
+ continue;
152
+ if (inferredPlatform === 'ios' && /resource-id=|uiautomator|android\./i.test(text))
153
+ warnings.push(`Android-specific locator in iOS flow: "${text}". Prefer accessibilityIdentifier/name/label on iOS.`);
154
+ if (inferredPlatform === 'android' && /class chain|predicate string|XCUIElementType|accessibility id=/i.test(text))
155
+ warnings.push(`iOS-specific locator in Android flow: "${text}". Prefer resource-id/content-desc/text on Android.`);
156
+ if (inferredPlatform === 'cross-platform' && /(resource-id=|uiautomator|android\.|accessibility id=|class chain|predicate string|XCUIElementType|xpath=|^\/\/)/i.test(text)) {
157
+ warnings.push(`Platform-specific or brittle locator in cross-platform flow: "${text}". Prefer shared text/testID/accessibility labels.`);
158
+ }
159
+ }
160
+ if (ci) {
161
+ const policy = root ? loadPolicy(root) : null;
162
+ const mutationViolations = validateCiMutationPolicy([parsed], policy).violations;
163
+ for (const v of mutationViolations)
164
+ warnings.push(`CI policy: ${v.flow} step ${v.step} ${v.kind} is mutating and is not allowed by .swipium/policy.json ciAllowMutations.`);
165
+ const missingVars = validateCiVariables([parsed]).missing;
166
+ for (const v of missingVars)
167
+ warnings.push(`CI variable: ${v.variable} is required by ${v.flow} step ${v.step} but is not set in the environment.`);
168
+ }
169
+ const lintFindings = lintFlowObjectWithOptions(src.source ?? 'inline', parsed, { platform, policy: ci ? (root ? loadPolicy(root) : null) : undefined });
170
+ for (const f of lintFindings) {
171
+ const prefix = f.severity === 'error' ? 'Lint error' : 'Lint warning';
172
+ warnings.push(`${prefix} ${f.code}${f.step ? ` step ${f.step}` : ''}: ${f.message}`);
173
+ }
174
+ // Image-template steps: verify the referenced files exist (best-effort, when a root is known).
175
+ if (root) {
176
+ for (const s of allSteps) {
177
+ if ((s.kind === 'tapImage' || s.kind === 'assertImage')) {
178
+ const p = isAbsolute(s.template) ? s.template : join(root, s.template);
179
+ if (!existsSync(p))
180
+ warnings.push(`image template not found: ${s.template} (resolve relative to the project root).`);
181
+ }
182
+ }
183
+ }
184
+ return qaOk({ valid: true, source: src.source, name: parsed.name, appId: parsed.appId ?? null, mode: parsed.mode, budgetProfile: parsed.budgetProfile ?? null, stepCount: parsed.steps.length, setupCount: parsed.setup.length, teardownCount: parsed.teardown.length, fixtures: parsed.fixtures, warnings, lintFindings }, `✅ flow "${parsed.name}" is valid — ${parsed.steps.length} steps (mode=${parsed.mode}${parsed.setup.length ? `, ${parsed.setup.length} setup` : ''}${parsed.teardown.length ? `, ${parsed.teardown.length} teardown` : ''})${warnings.length ? `\nwarnings:\n - ${warnings.join('\n - ')}` : ''}`);
185
+ });
186
+ server.registerTool('qa_flow_run', {
187
+ title: 'Run a flow',
188
+ description: 'Run a Swipium flow against the prepared app and report the result. Drives steps server-side: tap/tapAt/tapImage, inputText (incl. { into, text } to focus a named field), assertVisible/assertNotVisible/assertImage/assertVisual/assertDiff, swipe (device-relative { direction, area, distance }), scrollTo, press, openUrl, wait/waitForIdle/waitForVisible, clearOverlay, networkOffline/Online, restartApp, seed, note, screenshot — with optional setup/teardown (teardown always runs) and mode structured|visual|auto. Fail-fast, NO auto-retry of mutating steps; on failure returns the exact failing step + screenshot + typed failureCode + health. Provide `flow` (name/path) or `flowYaml`, plus `variables` for any ${VAR}.',
189
+ inputSchema: {
190
+ sessionId: z.string(),
191
+ flow: z.string().optional(),
192
+ flowYaml: z.string().optional(),
193
+ variables: z.record(z.string()).optional().describe('Values for ${VAR} placeholders (merged over process.env). Credential-looking names are auto-redacted.'),
194
+ repeat: z.number().int().min(1).max(10).optional().describe('Run the flow N times for flake detection (default 1). Reports pass-rate + a deterministic-pass | deterministic-fail | flaky classification.'),
195
+ consentId: z.string().optional().describe('Consent token returned when the flow contains mutating steps or external visual-provider steps such as OCR.'),
196
+ approve: z.boolean().optional().describe('Set true with consentId to execute after reviewing the exact flow hash, mutation list, and external provider command if present.'),
197
+ },
198
+ }, async ({ sessionId, flow, flowYaml, variables, repeat, consentId, approve }) => {
199
+ const session = sessions.get(sessionId);
200
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
201
+ if (!session || !driver) {
202
+ return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target / qa_ios boot first, then qa_flow_run.'] });
203
+ }
204
+ const src = loadFlowSource(session.root, flow, flowYaml);
205
+ if (src.error)
206
+ return qaError({ what: src.error, changedState: false, retrySafe: true, nextSteps: ['Pass an existing flow name/path or inline flowYaml.'] });
207
+ const { flow: parsed, errors } = parseFlow(src.yamlText);
208
+ if (errors.length || !parsed) {
209
+ return qaError({ what: `Flow is invalid — run qa_flow_check first`, changedState: false, retrySafe: true, nextSteps: ['Fix the flow and re-run.'] }, { errors });
210
+ }
211
+ // Backend/mode gate (NEXT-PLAN: catch unsupported combos before running). A structured-mode
212
+ // flow needs a UI tree, which the iOS simulator and a visual-fallback session don't have.
213
+ if (parsed.mode === 'structured' && (driver.kind === 'simulator' || session.mode === 'visual-fallback')) {
214
+ return qaError({
215
+ what: `This flow is mode:structured but ${driver.kind === 'simulator' ? 'the iOS simulator backend has no UI tree' : 'the session is in visual-fallback'}`,
216
+ changedState: false,
217
+ retrySafe: false,
218
+ failureCode: 'BACKEND_UNSUPPORTED',
219
+ nextSteps: ['Author the flow with `mode: visual` (or auto) and use image/visual steps (tapImage/assertImage/assertDiff/assertVisual).'],
220
+ });
221
+ }
222
+ const budget = sessions.budgetStop(session);
223
+ if (budget)
224
+ return qaStop(budget, { counters: session.counters });
225
+ const runs = repeat ?? 1;
226
+ const externalProviderSteps = ocrSteps(parsed);
227
+ const externalProviders = [];
228
+ if (externalProviderSteps.length) {
229
+ if (session.sensitive) {
230
+ return qaError({
231
+ what: 'Sensitive mode refuses OCR flow steps because they would pass screenshots to an external provider',
232
+ changedState: false,
233
+ retrySafe: false,
234
+ failureCode: 'UNSAFE_ACTION_REFUSED',
235
+ nextSteps: ['Disable sensitive mode only for a safe, masked QA screen, or remove tapOcrText/assertOcrText from the flow.'],
236
+ });
237
+ }
238
+ const command = configuredOcrCommand(session.root);
239
+ if (!command) {
240
+ return qaError({
241
+ what: 'Flow uses OCR text steps, but OCR is not configured',
242
+ changedState: false,
243
+ retrySafe: true,
244
+ failureCode: 'VISUAL_ONLY_SCREEN',
245
+ nextSteps: ['Configure ocrCommand in .swipium/config.json or remove tapOcrText/assertOcrText from the flow.'],
246
+ });
247
+ }
248
+ try {
249
+ const preview = resolveVisualProvider(command, { image: '<screenshot>' }, 30000);
250
+ const maskPreview = resolveMaskProvider(session.root);
251
+ externalProviders.push({
252
+ provider: 'ocr',
253
+ steps: externalProviderSteps,
254
+ argv: preview.argv,
255
+ io: preview.io,
256
+ maskConfigured: !!maskPreview,
257
+ maskArgv: maskPreview?.argv ?? null,
258
+ screenshotsSharedWithProvider: runs * externalProviderSteps.length,
259
+ });
260
+ }
261
+ catch (e) {
262
+ return qaError({
263
+ what: e instanceof GitScopeForbiddenError ? e.message : `Invalid OCR command template: ${String(e)}`,
264
+ changedState: false,
265
+ retrySafe: !(e instanceof GitScopeForbiddenError),
266
+ failureCode: e instanceof GitScopeForbiddenError ? 'GIT_SCOPE_FORBIDDEN' : 'INVALID_FLOW',
267
+ nextSteps: e instanceof GitScopeForbiddenError ? ['Run Git yourself outside Swipium; configure ocrCommand to use a non-Git executable.'] : ['Use an argv array in .swipium/config.json, e.g. ["node","ocr.js","{image}"].'],
268
+ });
269
+ }
270
+ }
271
+ const affects = flowMutationAffects(parsed, session, src.source, runs, externalProviders);
272
+ const mutationRisk = flowMutationRisk(affects);
273
+ let mutationConsent = { required: false, approved: true, payloadHash: affects.flowHash };
274
+ const privileged = affects.mutations.length > 0 || affects.externalProviders.length > 0;
275
+ if (privileged) {
276
+ const payloadHash = fullHash(affects);
277
+ const gate = consumeConsent(consentId, approve, { action: 'flow_mutation_run', affects });
278
+ if (!gate.approved) {
279
+ sessions.recordMutation(session, {
280
+ tool: 'qa_flow_run',
281
+ action: 'flow_mutation_run',
282
+ risk: mutationRisk,
283
+ target: affects,
284
+ consent: { required: true, approved: false, payloadHash },
285
+ status: 'requested',
286
+ });
287
+ const externalCommand = affects.externalProviders.length
288
+ ? `; external provider: ${displayArgv(affects.externalProviders[0].argv ?? [])}`
289
+ : '';
290
+ return requireConsent({
291
+ action: 'flow_mutation_run',
292
+ risk: mutationRisk,
293
+ exactCommand: `qa_flow_run ${parsed.name} (${[...affects.mutations.map((m) => `${m.step}:${m.kind}`), ...externalProviderSteps.map((s) => `${s.step}:${s.kind}`)].join(', ')})${externalCommand}`,
294
+ affects,
295
+ explain: affects.externalProviders.length
296
+ ? `Run flow "${parsed.name}" with external visual provider steps? OCR steps pass ${runs * externalProviderSteps.length} screenshot(s) to the configured provider and any mutating steps can change app/device/test state.`
297
+ : `Run mutating flow "${parsed.name}"? Mutating steps can change app/device/test state and will be recorded in the mutation ledger.`,
298
+ });
299
+ }
300
+ mutationConsent = { required: true, consentId, approved: true, payloadHash };
301
+ sessions.recordMutation(session, {
302
+ tool: 'qa_flow_run',
303
+ action: 'flow_mutation_run',
304
+ risk: mutationRisk,
305
+ target: affects,
306
+ consent: mutationConsent,
307
+ status: 'approved',
308
+ });
309
+ }
310
+ // Flake detection: run N times and classify (deterministic-pass | deterministic-fail | flaky).
311
+ if (runs > 1) {
312
+ const results = [];
313
+ for (let i = 0; i < runs; i++) {
314
+ const b = sessions.budgetStop(session);
315
+ if (b)
316
+ break;
317
+ results.push(await runFlow(sessions, session, driver, parsed, { variables, mutationConsent }));
318
+ }
319
+ const flake = classifyFlakeResults(results, runs);
320
+ return qaOk({ flow: parsed.name, runs: results.length, passes: flake.passed, fails: flake.failed, passRate: flake.passRate, classification: flake.classification, triage: flake.triage, results: results.map((r) => ({ passed: r.passed, failedAtStep: r.failedAtStep, reason: r.reason, failureCode: r.failureCode })) }, `flow "${parsed.name}" × ${results.length}: ${flake.passed} passed, ${flake.failed} failed → ${flake.classification === 'flaky' ? '⚠ FLAKY' : flake.classification === 'deterministic-pass' ? '✅ deterministic-pass' : '❌ deterministic-fail'} (${flake.passRate}% pass-rate); triage=${flake.triage.likelyCause}`);
321
+ }
322
+ const result = await runFlow(sessions, session, driver, parsed, { variables, mutationConsent });
323
+ const head = `flow "${result.name}" ${result.passed ? '✅ PASSED' : `❌ FAILED at step ${result.failedAtStep} (${result.reason})`} ` +
324
+ `— ${result.steps.filter((s) => s.ok).length}/${result.steps.length} steps in ${result.durationSec}s` +
325
+ (result.appHealth ? `\nhealth: native=${result.nativeHealth} app=${result.appHealth}` : '');
326
+ const stepLines = result.steps.map((s) => `${s.ok ? '✓' : '✗'} ${s.index}. ${s.summary}${s.detail ? ` — ${s.detail}` : ''}${s.screenshotUri ? `\n evidence: ${s.screenshotUri}` : ''}`).join('\n');
327
+ // A failed flow is a structured result, not a protocol error — the agent should record it.
328
+ return qaOk({ ...result }, `${head}\n${stepLines}`);
329
+ });
330
+ }
331
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/tools/flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ // qa_flow_generate (PHASE3-PLAN §4.1 / DESIGN §8) — turn the actions recorded during this
2
+ // session (via qa_act) into a durable flow YAML, with a durability grade and the brittle
3
+ // steps that need testIDs. Optionally saves it to .swipium/flows/<name>.yaml so it shows up
4
+ // in qa_plan and can be replayed with qa_flow_run.
5
+ import { z } from 'zod';
6
+ import { mkdirSync, writeFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { qaOk, qaError } from '../lib/result.js';
9
+ import { generateFlow } from '../flows/generate.js';
10
+ import { loadProjectConfig } from '../cli/scan.js';
11
+ export function registerFlowGenerate(server, sessions) {
12
+ server.registerTool('qa_flow_generate', {
13
+ title: 'Generate a flow from this run',
14
+ description: 'Draft a repeatable flow YAML from the actions recorded during this session (every qa_act is recorded). Translates @ref taps into durable text selectors where possible, turns typed credentials into ${VARS}, and reports a durability grade (A/B/C) + the steps that need a testID/accessibilityLabel. Pass save:true to write it to .swipium/flows/<name>.yaml (so qa_plan lists it and qa_flow_run can replay it).',
15
+ inputSchema: {
16
+ sessionId: z.string(),
17
+ name: z.string().optional().describe('Flow name (default derived from the app/session).'),
18
+ budgetProfile: z.enum(['guardrail', 'login_smoke', 'full_smoke', 'install_smoke']).optional(),
19
+ save: z.boolean().optional().describe('Write to .swipium/flows/<name>.yaml (default false → returned + saved as an artifact only).'),
20
+ },
21
+ }, async ({ sessionId, name, budgetProfile, save }) => {
22
+ const session = sessions.get(sessionId);
23
+ if (!session) {
24
+ return qaError({ what: `Unknown sessionId ${sessionId}`, changedState: false, retrySafe: true, nextSteps: ['Call qa_start_session first.'] });
25
+ }
26
+ if (!session.recordedActions.length) {
27
+ return qaError({
28
+ what: 'No actions recorded in this session yet',
29
+ changedState: false,
30
+ retrySafe: true,
31
+ nextSteps: ['Drive the app with qa_act first (each action is recorded), then qa_flow_generate.'],
32
+ });
33
+ }
34
+ const appId = session.appId ?? (loadProjectConfig(session.root)?.appId ?? undefined);
35
+ const flowName = (name ?? `${(appId ?? 'app').split('.').pop()}-smoke`).replace(/[^\w.-]+/g, '-');
36
+ const gen = generateFlow(session.recordedActions, { name: flowName, appId, budgetProfile });
37
+ // Always keep a copy as an artifact; optionally write into the project's flows dir.
38
+ const artifactUri = sessions.saveArtifact(session, 'flow', `${flowName}.yaml`, gen.yaml, 'text/yaml', `generated flow (durability ${gen.durability.grade})`);
39
+ let savedTo;
40
+ if (save) {
41
+ const dir = join(session.root, '.swipium', 'flows');
42
+ mkdirSync(dir, { recursive: true });
43
+ savedTo = join(dir, `${flowName}.yaml`);
44
+ writeFileSync(savedTo, gen.yaml);
45
+ }
46
+ const summary = `Generated flow "${flowName}" — durability ${gen.durability.grade} (${gen.durability.semanticPct}% semantic; ` +
47
+ `${gen.durability.coordinate} coordinate, ${gen.durability.needsHumanData} needs-human-data), ${gen.stepCount} steps.` +
48
+ (gen.variables.length ? `\nvariables: ${gen.variables.join(', ')} (provide via qa_flow_run { variables }).` : '') +
49
+ (gen.brittleSteps.length ? `\n⚠ brittle steps:\n - ${gen.brittleSteps.map((b) => `step ${b.index}: ${b.reason}`).join('\n - ')}` : '') +
50
+ (savedTo ? `\nsaved: ${savedTo}` : `\n(not saved to disk — pass save:true to write it under .swipium/flows)`) +
51
+ `\n\n${gen.yaml}`;
52
+ return qaOk({ name: flowName, appId: appId ?? null, durability: gen.durability, brittleSteps: gen.brittleSteps, variables: gen.variables, stepCount: gen.stepCount, artifactUri, savedTo: savedTo ?? null, yaml: gen.yaml }, summary);
53
+ });
54
+ }
55
+ //# sourceMappingURL=flowGenerate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowGenerate.js","sourceRoot":"","sources":["../../src/tools/flowGenerate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ // qa_get_artifact — portable fallback for clients without MCP resource support.
2
+ // To protect the context budget (review #7), images default to METADATA (uri/mime/size);
3
+ // fetch pixels explicitly with mode:"inline". Text defaults to inline.
4
+ import { z } from 'zod';
5
+ import { readFileSync, statSync } from 'node:fs';
6
+ import { qaError } from '../lib/result.js';
7
+ /** Images → metadata by default (large); text → inline. Explicit mode always wins. */
8
+ export function chooseMode(mime, mode) {
9
+ return mode ?? (mime.startsWith('image/') ? 'metadata' : 'inline');
10
+ }
11
+ export function registerGetArtifact(server, sessions) {
12
+ server.registerTool('qa_get_artifact', {
13
+ title: 'Get an artifact',
14
+ description: 'Fetch a session artifact by its swipium://session/<id>/<kind>/<name> URI (screenshots, reports, dumps, logs) where the client lacks MCP resources. Images default to metadata (uri/mime/size) to protect context — pass mode:"inline" when you actually need the pixels. Prefer qa_report links for browsing.',
15
+ inputSchema: { uri: z.string(), mode: z.enum(['metadata', 'inline']).optional() },
16
+ }, async ({ uri, mode }) => {
17
+ const found = sessions.findArtifact(uri);
18
+ if (!found) {
19
+ return qaError({ what: `Unknown artifact ${uri}`, changedState: false, retrySafe: true, nextSteps: ['List artifacts via qa_report, or check the URI.'] });
20
+ }
21
+ const { rec } = found;
22
+ const resolved = chooseMode(rec.mime, mode);
23
+ try {
24
+ if (resolved === 'metadata') {
25
+ const bytes = statSync(rec.path).size;
26
+ const meta = { uri: rec.uri, mime: rec.mime, kind: rec.kind, bytes, path: rec.path, hint: rec.mime.startsWith('image/') ? 'pass mode:"inline" to fetch the image bytes' : 'pass mode:"inline" to fetch contents' };
27
+ return { content: [{ type: 'text', text: `${rec.uri}\n${JSON.stringify(meta, null, 2)}` }], structuredContent: meta };
28
+ }
29
+ if (rec.mime.startsWith('image/')) {
30
+ return { content: [{ type: 'image', data: readFileSync(rec.path).toString('base64'), mimeType: rec.mime }] };
31
+ }
32
+ return { content: [{ type: 'text', text: readFileSync(rec.path, 'utf8') }] };
33
+ }
34
+ catch (e) {
35
+ return qaError({ what: `Could not read artifact: ${String(e)}`, changedState: false, retrySafe: true, nextSteps: ['The file may have been cleaned up.'] });
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=getArtifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getArtifact.js","sourceRoot":"","sources":["../../src/tools/getArtifact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ // qa_check_health — run the Tier-1 deterministic oracle on demand.
2
+ import { z } from 'zod';
3
+ import { qaOk, qaError } from '../lib/result.js';
4
+ import { checkHealth } from '../oracle/health.js';
5
+ import { recordHealthFindings } from '../oracle/record.js';
6
+ import { getDriver } from '../session/attach.js';
7
+ export function registerCheckHealth(server, sessions) {
8
+ server.registerTool('qa_check_health', {
9
+ title: 'Check app health',
10
+ description: 'Deterministic Tier-1 health check of the current screen: crash / ANR / framework error-boundary / error-surface, plus whether the app is still in the foreground. High-severity findings are real bugs (not flake). Runs automatically after qa_act too.',
11
+ inputSchema: { sessionId: z.string() },
12
+ }, async ({ sessionId }) => {
13
+ const session = sessions.get(sessionId);
14
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
15
+ if (!session || !driver) {
16
+ return qaError({
17
+ what: 'No device attached to this session',
18
+ changedState: false,
19
+ retrySafe: true,
20
+ nextSteps: ['Call qa_prepare_target first.'],
21
+ });
22
+ }
23
+ const health = await checkHealth(driver, session.appId);
24
+ await recordHealthFindings(sessions, session, health.findings, driver, health.foreground); // feeds qa_report
25
+ const summary = `native health: ${health.nativeHealthy ? '✅ OK' : `❌ ${health.nativeStatus}`} · ` +
26
+ `app health: ${health.appStatus === 'ok' ? '✅ OK' : health.appStatus === 'degraded' ? '⚠ degraded' : '❌ error'} — foreground=${health.foreground}\n` +
27
+ (health.findings.length
28
+ ? health.findings.map((f) => `[${f.severity}] ${f.layer ?? '?'}/${f.kind}: ${f.detail}${f.evidence ? ` — "${f.evidence}"` : ''}`).join('\n')
29
+ : 'no findings');
30
+ return qaOk({
31
+ healthy: health.healthy,
32
+ nativeHealthy: health.nativeHealthy,
33
+ appHealthy: health.appHealthy,
34
+ nativeStatus: health.nativeStatus,
35
+ appStatus: health.appStatus,
36
+ foreground: health.foreground,
37
+ findings: health.findings,
38
+ }, summary);
39
+ });
40
+ }
41
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/tools/health.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGjD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,QAAsB;IAC3E,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,0PAA0P;QAC5P,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC9E,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC;gBACb,IAAI,EAAE,oCAAoC;gBAC1C,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,CAAC,+BAA+B,CAAC;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB;QAC7G,MAAM,OAAO,GACX,kBAAkB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,YAAY,EAAE,KAAK;YACjF,eAAe,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,iBAAiB,MAAM,CAAC,UAAU,IAAI;YACpJ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;gBACrB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC5I,CAAC,CAAC,aAAa,CAAC,CAAC;QACrB,OAAO,IAAI,CACT;YACE,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,EACD,OAAO,CACR,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}