taphound 0.2.0-dev.1 → 0.2.0-dev.12

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 (467) hide show
  1. package/README.md +49 -149
  2. package/README.zh-CN.md +47 -147
  3. package/assets/skills/taphound-case-suite/SKILL.md +363 -0
  4. package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
  5. package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
  6. package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
  7. package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
  8. package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
  9. package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
  10. package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
  11. package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
  12. package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
  13. package/assets/skills/taphound-flash/SKILL.md +115 -0
  14. package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
  15. package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
  16. package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
  17. package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
  18. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
  19. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
  20. package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
  21. package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
  22. package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
  23. package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
  24. package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
  25. package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
  26. package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
  27. package/assets/skills/taphound-journey-generator/SKILL.md +507 -0
  28. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
  29. package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
  30. package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
  31. package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
  32. package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
  33. package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
  34. package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
  35. package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
  36. package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
  37. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
  38. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
  39. package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +578 -0
  40. package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
  41. package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
  42. package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
  43. package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
  44. package/assets/skills/taphound-verify-change/SKILL.md +91 -0
  45. package/assets/skills/taphound-verify-change/references/accept.md +38 -0
  46. package/assets/skills/taphound-verify-change/references/preserve.md +357 -0
  47. package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
  48. package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
  49. package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
  50. package/dist/adapters/adb/adb-adapter.d.ts +16 -2
  51. package/dist/adapters/adb/adb-adapter.js +199 -0
  52. package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
  53. package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
  54. package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
  55. package/dist/adapters/adb/ui-automator-parser.js +160 -0
  56. package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
  57. package/dist/adapters/adb/window-topology-parser.js +101 -0
  58. package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
  59. package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
  60. package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
  61. package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
  62. package/dist/adapters/android-cli/layout-parser.js +12 -8
  63. package/dist/adapters/appium/appium-doctor.d.ts +7 -0
  64. package/dist/adapters/appium/appium-doctor.js +128 -0
  65. package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +42 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +309 -0
  67. package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
  68. package/dist/adapters/camera/camera-probe-adapter.js +286 -0
  69. package/dist/adapters/filesystem/artifact-store.js +40 -1
  70. package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
  71. package/dist/adapters/filesystem/context-document-writer.js +112 -0
  72. package/dist/adapters/filesystem/diagnostics-journal.d.ts +17 -0
  73. package/dist/adapters/filesystem/diagnostics-journal.js +130 -0
  74. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  75. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  76. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  77. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  78. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  79. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  80. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  81. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  82. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  83. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  84. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  85. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  86. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  87. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  88. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  89. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  90. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  91. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  92. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  93. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  94. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  95. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  96. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  97. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  98. package/dist/adapters/filesystem/skill-installer.js +40 -11
  99. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  100. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  101. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  102. package/dist/adapters/git/node-git-diff.js +114 -0
  103. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  104. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  105. package/dist/adapters/process/node-process-runner.js +11 -2
  106. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  107. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  108. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  109. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  110. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  111. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  112. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  113. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  114. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  115. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  116. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  122. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  123. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  124. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  125. package/dist/adapters/runtime/session-adb-view.js +193 -0
  126. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  127. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  128. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  129. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  130. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  131. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  132. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  133. package/dist/adapters/ui/device-layout-temp.js +18 -0
  134. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  135. package/dist/adapters/ui/device-ui-environment.js +81 -0
  136. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  137. package/dist/adapters/ui/layout-normalization.js +44 -0
  138. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  139. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  140. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  141. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  142. package/dist/application/align/align-service.d.ts +42 -0
  143. package/dist/application/align/align-service.js +106 -0
  144. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  145. package/dist/application/assertion/expectation-evaluator.js +156 -18
  146. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  147. package/dist/application/assertion/guarded-expectation.js +74 -0
  148. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  149. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  150. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  151. package/dist/application/checkpoint/baseline-error.js +8 -0
  152. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  153. package/dist/application/checkpoint/baseline-service.js +147 -0
  154. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  155. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  156. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  157. package/dist/application/checkpoint/regression-comparator.js +192 -0
  158. package/dist/application/collector/logcat-collector.d.ts +22 -1
  159. package/dist/application/collector/logcat-collector.js +103 -15
  160. package/dist/application/collector/logcat-event.d.ts +8 -0
  161. package/dist/application/collector/logcat-event.js +79 -0
  162. package/dist/application/collector/logcat-stop.d.ts +2 -0
  163. package/dist/application/collector/logcat-stop.js +11 -0
  164. package/dist/application/context/context-generator.d.ts +45 -0
  165. package/dist/application/context/context-generator.js +228 -0
  166. package/dist/application/context/context-loader.d.ts +40 -0
  167. package/dist/application/context/context-loader.js +223 -0
  168. package/dist/application/context/context-refresher.d.ts +59 -0
  169. package/dist/application/context/context-refresher.js +349 -0
  170. package/dist/application/context/context-rehasher.d.ts +36 -0
  171. package/dist/application/context/context-rehasher.js +110 -0
  172. package/dist/application/context/context-validator.d.ts +23 -1
  173. package/dist/application/context/context-validator.js +116 -9
  174. package/dist/application/context/evidence-hash.d.ts +1 -0
  175. package/dist/application/context/evidence-hash.js +125 -0
  176. package/dist/application/context/evidence-match.d.ts +9 -0
  177. package/dist/application/context/evidence-match.js +8 -0
  178. package/dist/application/context/shard-identity.d.ts +2 -0
  179. package/dist/application/context/shard-identity.js +7 -0
  180. package/dist/application/contract/contract-loader.d.ts +25 -0
  181. package/dist/application/contract/contract-loader.js +68 -0
  182. package/dist/application/contract/contract-review.d.ts +25 -0
  183. package/dist/application/contract/contract-review.js +51 -0
  184. package/dist/application/contract/contract-verifier.d.ts +53 -0
  185. package/dist/application/contract/contract-verifier.js +645 -0
  186. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  187. package/dist/application/devices/resolve-device-assignments.js +60 -0
  188. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  189. package/dist/application/diagnosis/failure-classifier.js +179 -0
  190. package/dist/application/diagnostics/diagnostics-exporter.d.ts +29 -0
  191. package/dist/application/diagnostics/diagnostics-exporter.js +283 -0
  192. package/dist/application/diagnostics/ui-capture-telemetry.d.ts +16 -0
  193. package/dist/application/diagnostics/ui-capture-telemetry.js +81 -0
  194. package/dist/application/doctor/doctor-service.d.ts +36 -3
  195. package/dist/application/doctor/doctor-service.js +255 -25
  196. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  197. package/dist/application/generation/generation-app-preparer.js +28 -0
  198. package/dist/application/generation/generation-config-service.d.ts +21 -0
  199. package/dist/application/generation/generation-config-service.js +53 -0
  200. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  201. package/dist/application/generation/generation-confirmation-service.js +109 -24
  202. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  203. package/dist/application/generation/generation-context-snapshot.js +29 -0
  204. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  205. package/dist/application/generation/generation-finalizer.js +167 -70
  206. package/dist/application/generation/generation-publisher.js +12 -8
  207. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  208. package/dist/application/generation/generation-recovery-service.js +144 -0
  209. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  210. package/dist/application/generation/generation-reopen-service.js +37 -0
  211. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  212. package/dist/application/generation/generation-replace-service.js +116 -0
  213. package/dist/application/generation/generation-starter.d.ts +44 -4
  214. package/dist/application/generation/generation-starter.js +175 -8
  215. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  216. package/dist/application/generation/generation-step-executor.js +471 -108
  217. package/dist/application/generation/proposed-step-validator.js +96 -30
  218. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  219. package/dist/application/generation/replay-policy-loader.js +29 -0
  220. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  221. package/dist/application/generation/risk-evaluator.js +118 -3
  222. package/dist/application/generation/runtime-observer.d.ts +39 -7
  223. package/dist/application/generation/runtime-observer.js +193 -24
  224. package/dist/application/impact/impact-resolver.d.ts +32 -0
  225. package/dist/application/impact/impact-resolver.js +160 -0
  226. package/dist/application/init/init-service.js +26 -13
  227. package/dist/application/interaction/action-executor.d.ts +3 -2
  228. package/dist/application/interaction/action-executor.js +11 -1
  229. package/dist/application/interaction/action-target.d.ts +17 -0
  230. package/dist/application/interaction/action-target.js +40 -0
  231. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  232. package/dist/application/interaction/external-step-runner.js +332 -0
  233. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  234. package/dist/application/interaction/fallback-resolver.js +7 -5
  235. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  236. package/dist/application/interaction/scroll-to-executor.js +118 -36
  237. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  238. package/dist/application/journey/external-flow-resolver.js +22 -0
  239. package/dist/application/journey/journey-check-service.d.ts +54 -0
  240. package/dist/application/journey/journey-check-service.js +207 -0
  241. package/dist/application/journey/journey-promoter.d.ts +26 -0
  242. package/dist/application/journey/journey-promoter.js +123 -0
  243. package/dist/application/journey/journey-resolver.d.ts +42 -0
  244. package/dist/application/journey/journey-resolver.js +239 -0
  245. package/dist/application/journey/journey-retirer.d.ts +25 -0
  246. package/dist/application/journey/journey-retirer.js +87 -0
  247. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  248. package/dist/application/knowledge/anchor-resolver.js +110 -0
  249. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  250. package/dist/application/knowledge/knowledge-loader.js +36 -0
  251. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  252. package/dist/application/locator/layout-failure-summary.js +67 -0
  253. package/dist/application/locator/layout-traversal.d.ts +11 -0
  254. package/dist/application/locator/layout-traversal.js +18 -0
  255. package/dist/application/locator/locator-resolver.d.ts +13 -1
  256. package/dist/application/locator/locator-resolver.js +182 -18
  257. package/dist/application/observe/observe-service.d.ts +20 -0
  258. package/dist/application/observe/observe-service.js +91 -0
  259. package/dist/application/project/project-describer.d.ts +14 -6
  260. package/dist/application/project/project-describer.js +38 -5
  261. package/dist/application/recognition/screen-detector.d.ts +28 -0
  262. package/dist/application/recognition/screen-detector.js +111 -0
  263. package/dist/application/recorder/locator-selector.js +151 -17
  264. package/dist/application/recorder/recorder-service.d.ts +16 -4
  265. package/dist/application/recorder/recorder-service.js +420 -128
  266. package/dist/application/report/report-writer.d.ts +5 -0
  267. package/dist/application/report/report-writer.js +17 -1
  268. package/dist/application/runtime/cold-launch.d.ts +28 -0
  269. package/dist/application/runtime/cold-launch.js +59 -0
  270. package/dist/application/runtime/step-runner.d.ts +49 -4
  271. package/dist/application/runtime/step-runner.js +721 -130
  272. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  273. package/dist/application/runtime/verify-runtime.js +577 -175
  274. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  275. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  276. package/dist/application/ui/observed-ui-snapshot-provider.d.ts +15 -0
  277. package/dist/application/ui/observed-ui-snapshot-provider.js +66 -0
  278. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  279. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  280. package/dist/application/ui/ui-stability-probe.d.ts +9 -0
  281. package/dist/application/ui/ui-stability-probe.js +24 -0
  282. package/dist/application/wait/idle-advice.d.ts +6 -0
  283. package/dist/application/wait/idle-advice.js +27 -0
  284. package/dist/application/wait/idle-profiles.d.ts +15 -0
  285. package/dist/application/wait/idle-profiles.js +75 -0
  286. package/dist/application/wait/idle-waiter.d.ts +28 -4
  287. package/dist/application/wait/idle-waiter.js +201 -15
  288. package/dist/cli/commands/align.d.ts +3 -0
  289. package/dist/cli/commands/align.js +124 -0
  290. package/dist/cli/commands/baseline.d.ts +3 -0
  291. package/dist/cli/commands/baseline.js +130 -0
  292. package/dist/cli/commands/context.js +300 -27
  293. package/dist/cli/commands/contract.d.ts +3 -0
  294. package/dist/cli/commands/contract.js +120 -0
  295. package/dist/cli/commands/diagnose.d.ts +3 -0
  296. package/dist/cli/commands/diagnose.js +84 -0
  297. package/dist/cli/commands/doctor.js +16 -9
  298. package/dist/cli/commands/failure.d.ts +3 -0
  299. package/dist/cli/commands/failure.js +63 -0
  300. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  301. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  302. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  303. package/dist/cli/commands/generation/session-commands.js +472 -0
  304. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  305. package/dist/cli/commands/generation/shared.js +291 -0
  306. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  307. package/dist/cli/commands/generation/step-commands.js +315 -0
  308. package/dist/cli/commands/generation.js +10 -507
  309. package/dist/cli/commands/impact.d.ts +3 -0
  310. package/dist/cli/commands/impact.js +87 -0
  311. package/dist/cli/commands/init.js +13 -6
  312. package/dist/cli/commands/journey.d.ts +3 -0
  313. package/dist/cli/commands/journey.js +382 -0
  314. package/dist/cli/commands/knowledge.d.ts +3 -0
  315. package/dist/cli/commands/knowledge.js +93 -0
  316. package/dist/cli/commands/observe.d.ts +3 -0
  317. package/dist/cli/commands/observe.js +127 -0
  318. package/dist/cli/commands/project.js +2 -1
  319. package/dist/cli/commands/record.js +18 -5
  320. package/dist/cli/commands/verify.js +326 -64
  321. package/dist/cli/dependencies.d.ts +136 -1
  322. package/dist/cli/dependencies.js +504 -52
  323. package/dist/cli/diagnostics-recorder.d.ts +31 -0
  324. package/dist/cli/diagnostics-recorder.js +82 -0
  325. package/dist/cli/diff-verification.d.ts +41 -0
  326. package/dist/cli/diff-verification.js +192 -0
  327. package/dist/cli/main.d.ts +1 -1
  328. package/dist/cli/main.js +107 -2
  329. package/dist/cli/output.d.ts +5 -3
  330. package/dist/cli/output.js +12 -0
  331. package/dist/cli/program.js +21 -1
  332. package/dist/cli/project-root.d.ts +1 -0
  333. package/dist/cli/project-root.js +6 -0
  334. package/dist/cli/runtime-selection.d.ts +22 -0
  335. package/dist/cli/runtime-selection.js +92 -0
  336. package/dist/cli/version.d.ts +1 -0
  337. package/dist/cli/version.js +14 -0
  338. package/dist/cli/workspace-guard.d.ts +2 -0
  339. package/dist/cli/workspace-guard.js +3 -0
  340. package/dist/domain/binding-reference.d.ts +4 -0
  341. package/dist/domain/binding-reference.js +23 -0
  342. package/dist/domain/checkpoint.d.ts +404 -0
  343. package/dist/domain/checkpoint.js +297 -0
  344. package/dist/domain/config.d.ts +107 -1
  345. package/dist/domain/config.js +52 -6
  346. package/dist/domain/contract.d.ts +413 -0
  347. package/dist/domain/contract.js +196 -0
  348. package/dist/domain/diagnostics.d.ts +1396 -0
  349. package/dist/domain/diagnostics.js +193 -0
  350. package/dist/domain/external-flow.d.ts +493 -0
  351. package/dist/domain/external-flow.js +15 -0
  352. package/dist/domain/failure-classification.d.ts +176 -0
  353. package/dist/domain/failure-classification.js +169 -0
  354. package/dist/domain/failure.d.ts +2 -1
  355. package/dist/domain/failure.js +123 -0
  356. package/dist/domain/generation.d.ts +1671 -132
  357. package/dist/domain/generation.js +202 -13
  358. package/dist/domain/geometry.d.ts +13 -0
  359. package/dist/domain/geometry.js +16 -0
  360. package/dist/domain/impact.d.ts +71 -0
  361. package/dist/domain/impact.js +76 -0
  362. package/dist/domain/init.d.ts +12 -4
  363. package/dist/domain/init.js +24 -18
  364. package/dist/domain/journey-composition.d.ts +2285 -0
  365. package/dist/domain/journey-composition.js +85 -0
  366. package/dist/domain/journey-lifecycle.d.ts +10 -0
  367. package/dist/domain/journey-lifecycle.js +9 -0
  368. package/dist/domain/journey.d.ts +2419 -212
  369. package/dist/domain/journey.js +384 -14
  370. package/dist/domain/knowledge.d.ts +165 -0
  371. package/dist/domain/knowledge.js +188 -0
  372. package/dist/domain/layout.d.ts +34 -5
  373. package/dist/domain/layout.js +64 -6
  374. package/dist/domain/locator-evidence.d.ts +3 -0
  375. package/dist/domain/locator-evidence.js +36 -0
  376. package/dist/domain/logcat-event.d.ts +54 -0
  377. package/dist/domain/logcat-event.js +40 -0
  378. package/dist/domain/observation.d.ts +33 -0
  379. package/dist/domain/observation.js +18 -0
  380. package/dist/domain/project-context.d.ts +219 -1
  381. package/dist/domain/project-context.js +209 -6
  382. package/dist/domain/proposed-step.d.ts +340 -60
  383. package/dist/domain/proposed-step.js +23 -3
  384. package/dist/domain/report.d.ts +1455 -28
  385. package/dist/domain/report.js +211 -14
  386. package/dist/domain/runtime-snapshot.d.ts +58 -1
  387. package/dist/domain/runtime-snapshot.js +14 -3
  388. package/dist/domain/runtime.d.ts +50 -0
  389. package/dist/domain/runtime.js +36 -0
  390. package/dist/domain/system-app-profiles.d.ts +6 -0
  391. package/dist/domain/system-app-profiles.js +43 -0
  392. package/dist/domain/ui-backend.d.ts +28 -0
  393. package/dist/domain/ui-backend.js +33 -0
  394. package/dist/domain/ui-cache.d.ts +11 -0
  395. package/dist/domain/ui-cache.js +10 -0
  396. package/dist/domain/verify-receipt.d.ts +17 -0
  397. package/dist/domain/verify-receipt.js +17 -0
  398. package/dist/domain/window-hierarchy.d.ts +84 -0
  399. package/dist/domain/window-hierarchy.js +172 -0
  400. package/dist/domain/workflow-manifest.d.ts +77 -0
  401. package/dist/domain/workflow-manifest.js +136 -0
  402. package/dist/domain/workspace.d.ts +30 -0
  403. package/dist/domain/workspace.js +74 -0
  404. package/dist/ports/adb.d.ts +34 -1
  405. package/dist/ports/align-prompt.d.ts +11 -0
  406. package/dist/ports/align-prompt.js +6 -0
  407. package/dist/ports/anchor-resolver.d.ts +30 -0
  408. package/dist/ports/anchor-resolver.js +1 -0
  409. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  410. package/dist/ports/annotated-screen-resolver.js +1 -0
  411. package/dist/ports/camera-probe.d.ts +23 -0
  412. package/dist/ports/camera-probe.js +8 -0
  413. package/dist/ports/context-document-writer.d.ts +24 -0
  414. package/dist/ports/context-document-writer.js +1 -0
  415. package/dist/ports/detached-process-launcher.d.ts +12 -0
  416. package/dist/ports/detached-process-launcher.js +1 -0
  417. package/dist/ports/diagnostics.d.ts +15 -0
  418. package/dist/ports/diagnostics.js +1 -0
  419. package/dist/ports/external-flow-registry.d.ts +37 -0
  420. package/dist/ports/external-flow-registry.js +1 -0
  421. package/dist/ports/generation-prompt.d.ts +2 -1
  422. package/dist/ports/generation-session-store.d.ts +12 -2
  423. package/dist/ports/git-diff.d.ts +9 -0
  424. package/dist/ports/git-diff.js +1 -0
  425. package/dist/ports/journey-composition-store.d.ts +17 -0
  426. package/dist/ports/journey-composition-store.js +1 -0
  427. package/dist/ports/knowledge-registry.d.ts +20 -0
  428. package/dist/ports/knowledge-registry.js +1 -0
  429. package/dist/ports/process-runner.d.ts +7 -0
  430. package/dist/ports/project-file-inspector.d.ts +1 -0
  431. package/dist/ports/project-identity-inspector.d.ts +24 -0
  432. package/dist/ports/project-identity-inspector.js +1 -0
  433. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  434. package/dist/ports/project-inventory-inspector.js +1 -0
  435. package/dist/ports/project-module-discoverer.d.ts +26 -0
  436. package/dist/ports/project-module-discoverer.js +1 -0
  437. package/dist/ports/recorder-prompt.d.ts +10 -1
  438. package/dist/ports/runtime-backend.d.ts +89 -0
  439. package/dist/ports/runtime-backend.js +13 -0
  440. package/dist/ports/runtime-capability.d.ts +12 -0
  441. package/dist/ports/runtime-capability.js +20 -0
  442. package/dist/ports/runtime-session-ports.d.ts +25 -0
  443. package/dist/ports/runtime-session-ports.js +1 -0
  444. package/dist/ports/screenshot.d.ts +11 -0
  445. package/dist/ports/screenshot.js +1 -0
  446. package/dist/ports/skill-installer.d.ts +2 -2
  447. package/dist/ports/ui-snapshot.d.ts +35 -0
  448. package/dist/ports/ui-snapshot.js +1 -0
  449. package/dist/ports/ui-stability.d.ts +19 -0
  450. package/dist/ports/ui-stability.js +1 -0
  451. package/dist/ports/workspace-layout.d.ts +4 -0
  452. package/dist/ports/workspace-layout.js +1 -0
  453. package/dist/shared/errors.d.ts +2 -0
  454. package/dist/shared/errors.js +22 -0
  455. package/dist/shared/paths.d.ts +2 -0
  456. package/dist/shared/paths.js +24 -0
  457. package/dist/shared/strings.d.ts +2 -0
  458. package/dist/shared/strings.js +16 -0
  459. package/package.json +7 -2
  460. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  461. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  462. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  463. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  464. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  465. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  466. package/dist/ports/android-cli.d.ts +0 -21
  467. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -0,0 +1,40 @@
1
+ import { resolveLocator } from "../locator/locator-resolver.js";
2
+ /**
3
+ * The element an action acts on, with the capability semantics Generation,
4
+ * generated Replay, and External Flow steps share: a click or longClick
5
+ * reaches the nearest ancestor with that capability (touching the matched
6
+ * element itself), and a swipe needs a scrollable element with bounds.
7
+ */
8
+ export function resolveActionTarget(layout, action, locator, viewport) {
9
+ const located = resolveLocator(layout, locator, {
10
+ viewport,
11
+ ...(action === "swipe" ? {} : {
12
+ requiredCapability: action === "click" ? "clickable" : "longClickable"
13
+ })
14
+ });
15
+ if (located.status !== "found") {
16
+ return located;
17
+ }
18
+ const element = located.element;
19
+ if (action === "click" && element.clickable !== true) {
20
+ return actionFailure("click target is not clickable");
21
+ }
22
+ if (action === "longClick" && element.longClickable !== true) {
23
+ return actionFailure("longClick target is not longClickable");
24
+ }
25
+ if (action === "swipe"
26
+ && (element.scrollable !== true || element.bounds === undefined)) {
27
+ return actionFailure("swipe target lacks scrollable bounds");
28
+ }
29
+ return {
30
+ status: "found",
31
+ located,
32
+ target: {
33
+ point: located.point,
34
+ ...(element.bounds === undefined ? {} : { bounds: element.bounds })
35
+ }
36
+ };
37
+ }
38
+ function actionFailure(message) {
39
+ return { status: "failed", code: "ACTION_FAILED", message };
40
+ }
@@ -0,0 +1,153 @@
1
+ import type { ExternalStep } from "../../domain/external-flow.js";
2
+ import type { FailureCode } from "../../domain/failure.js";
3
+ import type { DisplayViewport } from "../../domain/geometry.js";
4
+ import { type JourneyStep } from "../../domain/journey.js";
5
+ import type { LayoutElement } from "../../domain/layout.js";
6
+ import type { AdbPort } from "../../ports/adb.js";
7
+ import type { Clock } from "../../ports/clock.js";
8
+ import type { UiSnapshotProvider } from "../../ports/ui-snapshot.js";
9
+ import type { IdleConfig, IdleResult, IdleWaiter } from "../wait/idle-waiter.js";
10
+ import type { ActionExecutor, ActionTarget } from "./action-executor.js";
11
+ /**
12
+ * The single implementation of External Flow steps and bridge foreground
13
+ * polling shared by Replay and Generation, so a flow that generates also
14
+ * replays under exactly the same rules.
15
+ */
16
+ /** Foreground/layout observation budget inside an escaped app. */
17
+ export declare const EXTERNAL_OBSERVATION_TIMEOUT_MS = 5000;
18
+ export interface ExternalStepFailure {
19
+ code: FailureCode;
20
+ message: string;
21
+ details?: unknown;
22
+ }
23
+ export type ExternalFlowOutcome = {
24
+ status: "passed";
25
+ } | {
26
+ status: "cancelled";
27
+ } | ({
28
+ status: "failed";
29
+ stepIndex: number;
30
+ } & ExternalStepFailure);
31
+ export interface ExternalStepRunnerDependencies {
32
+ adb: Pick<AdbPort, "foregroundComponent">;
33
+ actionExecutor: ActionExecutor;
34
+ uiSnapshotProvider: UiSnapshotProvider;
35
+ captureLayout: (reason: "locate" | "expect", timeoutMs: number, signal?: AbortSignal) => Promise<readonly LayoutElement[]>;
36
+ createIdleWaiter: (packageName: string) => IdleWaiter;
37
+ idle: IdleConfig;
38
+ viewport: () => DisplayViewport | undefined;
39
+ deviceSerial: string;
40
+ /** Records idle-timeout evidence before the failure is reported. */
41
+ onIdleTimeout?: ((stepIndex: number, idle: Extract<IdleResult, {
42
+ status: "timeout";
43
+ }>) => Promise<void>) | undefined;
44
+ }
45
+ export declare function idleTimeoutDetails(idle: Extract<IdleResult, {
46
+ status: "timeout";
47
+ }>): Record<string, unknown>;
48
+ export declare function externalStepToJourneyStep(step: ExternalStep): JourneyStep;
49
+ export declare class ExternalStepRunner {
50
+ private readonly dependencies;
51
+ constructor(dependencies: ExternalStepRunnerDependencies);
52
+ run(steps: readonly ExternalStep[], escapedPackageName: string, signal?: AbortSignal): Promise<ExternalFlowOutcome>;
53
+ private assertForeground;
54
+ private runStep;
55
+ private evaluateExpect;
56
+ }
57
+ export type ForegroundPollOutcome = {
58
+ status: "matched";
59
+ packageName: string;
60
+ } | {
61
+ status: "timeout";
62
+ } | {
63
+ status: "cancelled";
64
+ };
65
+ /**
66
+ * Polls the foreground package until `until` accepts it: bridge escape
67
+ * detection (`packageName !== target`) and return detection (`=== target`).
68
+ */
69
+ export declare function pollForegroundPackage(input: {
70
+ adb: Pick<AdbPort, "foregroundComponent">;
71
+ clock: Clock;
72
+ packageName: string;
73
+ deviceSerial: string;
74
+ until: (packageName: string) => boolean;
75
+ timeoutMs: number;
76
+ signal?: AbortSignal | undefined;
77
+ }): Promise<ForegroundPollOutcome>;
78
+ export interface BridgeRunDependencies {
79
+ adb: Pick<AdbPort, "foregroundComponent">;
80
+ clock: Clock;
81
+ actionExecutor: ActionExecutor;
82
+ externalSteps: ExternalStepRunner;
83
+ idleWaiter: IdleWaiter;
84
+ idle: IdleConfig;
85
+ packageName: string;
86
+ deviceSerial: string;
87
+ }
88
+ export interface BridgeRunInput {
89
+ trigger: {
90
+ step: JourneyStep;
91
+ target: ActionTarget;
92
+ };
93
+ escapeTimeoutMs: number;
94
+ returnTimeoutMs: number;
95
+ /** Engine policy for the escaped package; a failure stops the bridge. */
96
+ acceptEscape: (escapedPackageName: string) => ExternalStepFailure | undefined;
97
+ external: ExternalPhase;
98
+ signal?: AbortSignal | undefined;
99
+ }
100
+ /** What happens inside the escaped app between escape and return. */
101
+ export type ExternalPhase =
102
+ /** Replay and Generation run a known step list, if any. */
103
+ {
104
+ kind: "steps";
105
+ steps: (escapedPackageName: string) => Promise<readonly ExternalStep[] | undefined>;
106
+ }
107
+ /**
108
+ * The Recorder drives the escaped app one chosen step at a time (each
109
+ * through the same ExternalStepRunner) and reports the steps it ran.
110
+ */
111
+ | {
112
+ kind: "drive";
113
+ drive: (escapedPackageName: string) => Promise<ExternalDriveOutcome>;
114
+ };
115
+ export type ExternalDriveOutcome = {
116
+ status: "driven";
117
+ steps: readonly ExternalStep[];
118
+ } | {
119
+ status: "cancelled";
120
+ } | ({
121
+ status: "failed";
122
+ } & ExternalStepFailure);
123
+ export interface BridgeTiming {
124
+ actionMs: number;
125
+ waitMs: number;
126
+ }
127
+ export type BridgeOutcome = {
128
+ status: "returned";
129
+ escapedPackageName: string;
130
+ externalSteps?: readonly ExternalStep[] | undefined;
131
+ idle: Extract<IdleResult, {
132
+ status: "stable";
133
+ }>;
134
+ timing: BridgeTiming;
135
+ } | ({
136
+ status: "failed";
137
+ idle?: Extract<IdleResult, {
138
+ status: "timeout";
139
+ }> | undefined;
140
+ timing: BridgeTiming;
141
+ } & ExternalStepFailure) | {
142
+ status: "cancelled";
143
+ timing: BridgeTiming;
144
+ };
145
+ /**
146
+ * The single bridge step flow for Replay and Generation: trigger, escape,
147
+ * policy check, external steps, return, and settle.
148
+ */
149
+ export declare class BridgeRunner {
150
+ private readonly dependencies;
151
+ constructor(dependencies: BridgeRunDependencies);
152
+ run(input: BridgeRunInput): Promise<BridgeOutcome>;
153
+ }
@@ -0,0 +1,332 @@
1
+ import { JourneyStepSchema } from "../../domain/journey.js";
2
+ import { elementPredicateMismatch } from "../assertion/expectation-evaluator.js";
3
+ import { resolveLocator } from "../locator/locator-resolver.js";
4
+ import { withIdleAdvice } from "../wait/idle-advice.js";
5
+ import { resolveActionTarget } from "./action-target.js";
6
+ import { ScrollToExecutor } from "./scroll-to-executor.js";
7
+ /**
8
+ * The single implementation of External Flow steps and bridge foreground
9
+ * polling shared by Replay and Generation, so a flow that generates also
10
+ * replays under exactly the same rules.
11
+ */
12
+ /** Foreground/layout observation budget inside an escaped app. */
13
+ export const EXTERNAL_OBSERVATION_TIMEOUT_MS = 5000;
14
+ const BRIDGE_POLL_INTERVAL_MS = 500;
15
+ class ExternalStepStop extends Error {
16
+ failure;
17
+ constructor(failure) {
18
+ super(failure === "cancelled" ? "cancelled" : failure.message);
19
+ this.failure = failure;
20
+ }
21
+ }
22
+ function stop(code, message, details) {
23
+ throw new ExternalStepStop({
24
+ code,
25
+ message,
26
+ ...(details === undefined ? {} : { details })
27
+ });
28
+ }
29
+ function cancelled() {
30
+ throw new ExternalStepStop("cancelled");
31
+ }
32
+ function checkCancelled(signal) {
33
+ if (signal?.aborted === true)
34
+ cancelled();
35
+ }
36
+ export function idleTimeoutDetails(idle) {
37
+ return {
38
+ idle: {
39
+ strategy: idle.strategy,
40
+ ...(idle.backend === undefined ? {} : { backend: idle.backend }),
41
+ polls: idle.polls,
42
+ durationMs: idle.durationMs,
43
+ samplingDurationMs: idle.samplingDurationMs,
44
+ fallbackUsed: idle.fallbackUsed,
45
+ frameActivityDetected: idle.frameActivityDetected,
46
+ lastDiff: idle.lastDiff
47
+ }
48
+ };
49
+ }
50
+ export function externalStepToJourneyStep(step) {
51
+ const { expectedActivity, ...rest } = step;
52
+ return JourneyStepSchema.parse({
53
+ ...rest,
54
+ activity: { before: expectedActivity, after: expectedActivity }
55
+ });
56
+ }
57
+ function requireExternalTarget(layout, step, viewport) {
58
+ if (step.action !== "click"
59
+ && step.action !== "longClick"
60
+ && step.action !== "swipe") {
61
+ return undefined;
62
+ }
63
+ const resolution = resolveActionTarget(layout, step.action, step.locator, viewport);
64
+ if (resolution.status !== "found") {
65
+ stop(resolution.code, resolution.message);
66
+ }
67
+ return resolution.target;
68
+ }
69
+ export class ExternalStepRunner {
70
+ dependencies;
71
+ constructor(dependencies) {
72
+ this.dependencies = dependencies;
73
+ }
74
+ async run(steps, escapedPackageName, signal) {
75
+ for (const [stepIndex, step] of steps.entries()) {
76
+ try {
77
+ checkCancelled(signal);
78
+ await this.runStep(stepIndex, step, escapedPackageName, signal);
79
+ }
80
+ catch (error) {
81
+ if (!(error instanceof ExternalStepStop))
82
+ throw error;
83
+ return error.failure === "cancelled"
84
+ ? { status: "cancelled" }
85
+ : { status: "failed", stepIndex, ...error.failure };
86
+ }
87
+ }
88
+ return { status: "passed" };
89
+ }
90
+ async assertForeground(escapedPackageName, expectedActivity, phase, signal) {
91
+ const foreground = await this.dependencies.adb.foregroundComponent({
92
+ packageName: escapedPackageName,
93
+ deviceSerial: this.dependencies.deviceSerial,
94
+ ...(signal === undefined ? {} : { signal }),
95
+ timeoutMs: EXTERNAL_OBSERVATION_TIMEOUT_MS
96
+ });
97
+ checkCancelled(signal);
98
+ if (foreground.packageName !== escapedPackageName) {
99
+ stop("EXTERNAL_PACKAGE_MISMATCH", `External app foreground changed ${phase}: expected "${escapedPackageName}", got "${foreground.packageName}"`);
100
+ }
101
+ if (foreground.activity !== expectedActivity) {
102
+ stop("EXTERNAL_ACTIVITY_MISMATCH", `External Activity mismatch ${phase}: expected "${expectedActivity}", got "${foreground.activity}"`);
103
+ }
104
+ }
105
+ async runStep(stepIndex, step, escapedPackageName, signal) {
106
+ const { dependencies } = this;
107
+ await this.assertForeground(escapedPackageName, step.expectedActivity, "before the step", signal);
108
+ const layout = await dependencies.captureLayout("locate", EXTERNAL_OBSERVATION_TIMEOUT_MS, signal);
109
+ checkCancelled(signal);
110
+ if (step.action === "scrollTo") {
111
+ const scroll = await new ScrollToExecutor({
112
+ uiSnapshotProvider: dependencies.uiSnapshotProvider,
113
+ actionExecutor: dependencies.actionExecutor,
114
+ idleWaiter: dependencies.createIdleWaiter(escapedPackageName),
115
+ deviceSerial: dependencies.deviceSerial,
116
+ idle: dependencies.idle,
117
+ viewport: dependencies.viewport,
118
+ beforeSwipe: async () => {
119
+ await this.assertForeground(escapedPackageName, step.expectedActivity, "during scrolling", signal);
120
+ return dependencies.captureLayout("locate", EXTERNAL_OBSERVATION_TIMEOUT_MS, signal);
121
+ },
122
+ beforeMutation: () => this.assertForeground(escapedPackageName, step.expectedActivity, "before mutation", signal),
123
+ requireLiveContainerCapability: true
124
+ }).execute(externalStepToJourneyStep(step), signal, layout);
125
+ if (scroll.status === "cancelled")
126
+ cancelled();
127
+ if (scroll.status === "failed") {
128
+ stop(scroll.code, scroll.message, scroll.idle === undefined ? undefined : { idle: scroll.idle });
129
+ }
130
+ }
131
+ else {
132
+ const target = requireExternalTarget(layout, step, dependencies.viewport());
133
+ const action = await dependencies.actionExecutor.execute(externalStepToJourneyStep(step), target, signal);
134
+ if (action.status === "failed")
135
+ stop(action.code, action.message);
136
+ }
137
+ const idle = await dependencies
138
+ .createIdleWaiter(escapedPackageName)
139
+ .waitUntilIdle(dependencies.idle, signal);
140
+ if (idle.status === "cancelled")
141
+ cancelled();
142
+ if (idle.status === "timeout") {
143
+ await dependencies.onIdleTimeout?.(stepIndex, idle);
144
+ stop(idle.code, withIdleAdvice("External app layout did not become stable after step", idle), idleTimeoutDetails(idle));
145
+ }
146
+ checkCancelled(signal);
147
+ await this.evaluateExpect(step, escapedPackageName, signal);
148
+ }
149
+ async evaluateExpect(step, escapedPackageName, signal) {
150
+ const expect = step.expect;
151
+ if (expect === undefined)
152
+ return;
153
+ if (expect.type === "activity") {
154
+ const foreground = await this.dependencies.adb.foregroundComponent({
155
+ packageName: expect.packageName ?? escapedPackageName,
156
+ deviceSerial: this.dependencies.deviceSerial,
157
+ ...(signal === undefined ? {} : { signal }),
158
+ timeoutMs: expect.timeoutMs
159
+ });
160
+ checkCancelled(signal);
161
+ if (foreground.activity !== expect.value) {
162
+ stop("EXTERNAL_STEP_FAILED", `External expect Activity mismatch: expected "${expect.value}", got "${foreground.activity}"`);
163
+ }
164
+ return;
165
+ }
166
+ if (expect.type !== "element") {
167
+ stop("EXTERNAL_STEP_FAILED", "Logcat expectations are not supported for external steps");
168
+ }
169
+ const layout = await this.dependencies.captureLayout("expect", expect.timeoutMs, signal);
170
+ checkCancelled(signal);
171
+ const resolution = resolveLocator(layout, expect.locator, {
172
+ requireEnabled: false
173
+ });
174
+ if (expect.absent === true) {
175
+ if (resolution.status !== "failed"
176
+ || resolution.code !== "LOCATOR_NOT_FOUND"
177
+ || resolution.evidenceMismatch === true) {
178
+ stop("EXTERNAL_STEP_FAILED", resolution.status === "found"
179
+ ? "External expect expected an absent element but it was found"
180
+ : `External expect expected an absent element: ${resolution.message}`);
181
+ }
182
+ return;
183
+ }
184
+ if (resolution.status !== "found") {
185
+ stop("EXTERNAL_STEP_FAILED", `External expect element not found: ${resolution.message}`);
186
+ }
187
+ const mismatch = elementPredicateMismatch(resolution.element, expect);
188
+ if (mismatch !== undefined) {
189
+ stop("EXTERNAL_STEP_FAILED", `External expect element predicate mismatch: ${mismatch}`);
190
+ }
191
+ }
192
+ }
193
+ /**
194
+ * Polls the foreground package until `until` accepts it: bridge escape
195
+ * detection (`packageName !== target`) and return detection (`=== target`).
196
+ */
197
+ export async function pollForegroundPackage(input) {
198
+ const deadline = input.clock.now() + input.timeoutMs;
199
+ while (input.clock.now() < deadline) {
200
+ if (input.signal?.aborted === true)
201
+ return { status: "cancelled" };
202
+ const foreground = await input.adb.foregroundComponent({
203
+ packageName: input.packageName,
204
+ deviceSerial: input.deviceSerial,
205
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
206
+ timeoutMs: EXTERNAL_OBSERVATION_TIMEOUT_MS
207
+ });
208
+ if (input.until(foreground.packageName)) {
209
+ return { status: "matched", packageName: foreground.packageName };
210
+ }
211
+ await input.clock.sleep(Math.min(BRIDGE_POLL_INTERVAL_MS, Math.max(0, deadline - input.clock.now())), input.signal);
212
+ }
213
+ return { status: "timeout" };
214
+ }
215
+ /**
216
+ * The single bridge step flow for Replay and Generation: trigger, escape,
217
+ * policy check, external steps, return, and settle.
218
+ */
219
+ export class BridgeRunner {
220
+ dependencies;
221
+ constructor(dependencies) {
222
+ this.dependencies = dependencies;
223
+ }
224
+ async run(input) {
225
+ const { clock } = this.dependencies;
226
+ const timing = { actionMs: 0, waitMs: 0 };
227
+ const failed = (failure, idle) => ({
228
+ status: "failed",
229
+ ...failure,
230
+ ...(idle === undefined ? {} : { idle }),
231
+ timing
232
+ });
233
+ const cancelledOutcome = () => ({ status: "cancelled", timing });
234
+ const actionStartedAt = clock.now();
235
+ const action = await this.dependencies.actionExecutor.execute(input.trigger.step, input.trigger.target, input.signal);
236
+ timing.actionMs = clock.now() - actionStartedAt;
237
+ if (input.signal?.aborted === true)
238
+ return cancelledOutcome();
239
+ if (action.status === "failed") {
240
+ return failed({ code: action.code, message: action.message });
241
+ }
242
+ const waitStartedAt = clock.now();
243
+ const escaped = await pollForegroundPackage({
244
+ adb: this.dependencies.adb,
245
+ clock,
246
+ packageName: this.dependencies.packageName,
247
+ deviceSerial: this.dependencies.deviceSerial,
248
+ until: (packageName) => packageName !== this.dependencies.packageName,
249
+ timeoutMs: input.escapeTimeoutMs,
250
+ signal: input.signal
251
+ });
252
+ timing.waitMs += clock.now() - waitStartedAt;
253
+ if (escaped.status === "cancelled")
254
+ return cancelledOutcome();
255
+ if (escaped.status === "timeout") {
256
+ return failed({
257
+ code: "BRIDGE_NO_ESCAPE",
258
+ message: "Bridge trigger did not cause a package escape"
259
+ });
260
+ }
261
+ const rejected = input.acceptEscape(escaped.packageName);
262
+ if (rejected !== undefined)
263
+ return failed(rejected);
264
+ let externalSteps;
265
+ if (input.external.kind === "drive") {
266
+ const driven = await input.external.drive(escaped.packageName);
267
+ if (driven.status === "cancelled")
268
+ return cancelledOutcome();
269
+ if (driven.status === "failed") {
270
+ return failed({
271
+ code: driven.code,
272
+ message: driven.message,
273
+ ...(driven.details === undefined ? {} : { details: driven.details })
274
+ });
275
+ }
276
+ externalSteps = driven.steps;
277
+ }
278
+ else {
279
+ externalSteps = await input.external.steps(escaped.packageName);
280
+ if (externalSteps !== undefined) {
281
+ const external = await this.dependencies.externalSteps.run(externalSteps, escaped.packageName, input.signal);
282
+ if (external.status === "cancelled")
283
+ return cancelledOutcome();
284
+ if (external.status === "failed") {
285
+ return failed({
286
+ code: external.code,
287
+ message: external.message,
288
+ ...(external.details === undefined ? {} : { details: external.details })
289
+ });
290
+ }
291
+ }
292
+ }
293
+ const returnStartedAt = clock.now();
294
+ const returned = await pollForegroundPackage({
295
+ adb: this.dependencies.adb,
296
+ clock,
297
+ packageName: this.dependencies.packageName,
298
+ deviceSerial: this.dependencies.deviceSerial,
299
+ until: (packageName) => packageName === this.dependencies.packageName,
300
+ timeoutMs: input.returnTimeoutMs,
301
+ signal: input.signal
302
+ });
303
+ timing.waitMs += clock.now() - returnStartedAt;
304
+ if (returned.status === "cancelled")
305
+ return cancelledOutcome();
306
+ if (returned.status === "timeout") {
307
+ return failed({
308
+ code: "BRIDGE_NOT_RETURNED",
309
+ message: "Foreground did not return to target package within the timeout"
310
+ });
311
+ }
312
+ const idleStartedAt = clock.now();
313
+ const idle = await this.dependencies.idleWaiter.waitUntilIdle(this.dependencies.idle, input.signal);
314
+ timing.waitMs += clock.now() - idleStartedAt;
315
+ if (idle.status === "cancelled")
316
+ return cancelledOutcome();
317
+ if (idle.status === "timeout") {
318
+ return failed({
319
+ code: idle.code,
320
+ message: withIdleAdvice("Layout did not become stable after bridge return", idle),
321
+ details: idleTimeoutDetails(idle)
322
+ }, idle);
323
+ }
324
+ return {
325
+ status: "returned",
326
+ escapedPackageName: escaped.packageName,
327
+ ...(externalSteps === undefined ? {} : { externalSteps }),
328
+ idle,
329
+ timing
330
+ };
331
+ }
332
+ }
@@ -1,6 +1,8 @@
1
1
  import type { FailureCode } from "../../domain/failure.js";
2
2
  import type { JourneyStep } from "../../domain/journey.js";
3
- import type { AndroidCliPort, Point } from "../../ports/android-cli.js";
3
+ import type { Point } from "../../domain/geometry.js";
4
+ import type { AnnotatedScreenResolverPort } from "../../ports/annotated-screen-resolver.js";
5
+ import type { ScreenshotPort } from "../../ports/screenshot.js";
4
6
  export type FallbackResolution = {
5
7
  status: "unavailable";
6
8
  } | {
@@ -17,8 +19,9 @@ export type FallbackResolution = {
17
19
  annotatedScreenshotPath?: string | undefined;
18
20
  };
19
21
  export declare class FallbackResolver {
20
- private readonly androidCli;
22
+ private readonly screenshots;
23
+ private readonly annotatedScreens;
21
24
  private readonly deviceSerial;
22
- constructor(androidCli: AndroidCliPort, deviceSerial: string);
25
+ constructor(screenshots: ScreenshotPort, annotatedScreens: AnnotatedScreenResolverPort, deviceSerial: string);
23
26
  resolve(step: JourneyStep, annotatedScreenshotPath: string, signal?: AbortSignal): Promise<FallbackResolution>;
24
27
  }
@@ -1,8 +1,10 @@
1
1
  export class FallbackResolver {
2
- androidCli;
2
+ screenshots;
3
+ annotatedScreens;
3
4
  deviceSerial;
4
- constructor(androidCli, deviceSerial) {
5
- this.androidCli = androidCli;
5
+ constructor(screenshots, annotatedScreens, deviceSerial) {
6
+ this.screenshots = screenshots;
7
+ this.annotatedScreens = annotatedScreens;
6
8
  this.deviceSerial = deviceSerial;
7
9
  }
8
10
  async resolve(step, annotatedScreenshotPath, signal) {
@@ -10,7 +12,7 @@ export class FallbackResolver {
10
12
  || step.fallback === undefined) {
11
13
  return { status: "unavailable" };
12
14
  }
13
- const capture = await this.androidCli.captureScreen({
15
+ const capture = await this.screenshots.capture({
14
16
  outputPath: annotatedScreenshotPath,
15
17
  annotate: true,
16
18
  deviceSerial: this.deviceSerial,
@@ -24,7 +26,7 @@ export class FallbackResolver {
24
26
  };
25
27
  }
26
28
  try {
27
- const point = await this.androidCli.resolveScreen(annotatedScreenshotPath, step.fallback.label, signal);
29
+ const point = await this.annotatedScreens.resolve(annotatedScreenshotPath, step.fallback.label, signal);
28
30
  return {
29
31
  status: "found",
30
32
  point,
@@ -1,39 +1,53 @@
1
1
  import type { FailureCode } from "../../domain/failure.js";
2
2
  import type { JourneyStep } from "../../domain/journey.js";
3
3
  import type { LayoutElement } from "../../domain/layout.js";
4
- import type { AndroidCliPort } from "../../ports/android-cli.js";
5
- import type { IdleConfig, IdleWaiter } from "../wait/idle-waiter.js";
4
+ import type { DisplayViewport } from "../../domain/geometry.js";
5
+ import type { AnchorResolverPort } from "../../ports/anchor-resolver.js";
6
+ import type { UiSnapshotProvider } from "../../ports/ui-snapshot.js";
7
+ import type { IdleBackend, IdleConfig, IdleStrategy, IdleWaiter } from "../wait/idle-waiter.js";
6
8
  import type { ActionExecutor } from "./action-executor.js";
7
9
  export type ScrollToExecutionResult = {
8
10
  status: "found";
9
11
  swipesUsed: number;
12
+ idleDurationMs: number;
10
13
  } | {
11
14
  status: "failed";
12
15
  code: FailureCode;
13
16
  message: string;
14
17
  swipesUsed: number;
18
+ idleDurationMs: number;
15
19
  idle?: {
16
20
  polls: number;
21
+ durationMs: number;
22
+ samplingDurationMs: number;
23
+ strategy: IdleStrategy;
24
+ backend?: IdleBackend | undefined;
25
+ fallbackUsed: boolean;
26
+ frameActivityDetected: boolean;
17
27
  lastDiff: readonly unknown[];
18
28
  };
19
29
  } | {
20
30
  status: "cancelled";
21
31
  swipesUsed: number;
32
+ idleDurationMs: number;
22
33
  };
23
34
  export interface ScrollToExecutorOptions {
24
- androidCli: Pick<AndroidCliPort, "layout">;
35
+ uiSnapshotProvider: UiSnapshotProvider;
25
36
  actionExecutor: Pick<ActionExecutor, "swipeBounds">;
26
37
  idleWaiter: Pick<IdleWaiter, "waitUntilIdle">;
27
38
  deviceSerial: string;
28
39
  idle: IdleConfig;
40
+ anchorResolver?: AnchorResolverPort | undefined;
29
41
  readLayout?: (() => Promise<readonly LayoutElement[]>) | undefined;
30
42
  beforeSwipe?: (() => Promise<readonly LayoutElement[]>) | undefined;
31
43
  beforeMutation?: (() => Promise<void>) | undefined;
32
44
  requireLiveContainerCapability?: boolean | undefined;
45
+ viewport?: (() => DisplayViewport | undefined) | undefined;
33
46
  }
34
47
  export declare class ScrollToExecutor {
35
48
  private readonly options;
36
49
  constructor(options: ScrollToExecutorOptions);
50
+ private resolveTarget;
37
51
  execute(step: Extract<JourneyStep, {
38
52
  action: "scrollTo";
39
53
  }>, signal?: AbortSignal, initialLayout?: readonly LayoutElement[]): Promise<ScrollToExecutionResult>;