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,53 @@
1
+ import type { AdbPort, AppIdentity, DeviceIdentity, DeviceInfo, DumpLogcatOptions, LaunchActivityOptions, LogcatOptions, ResolvedActivity, StartActivityByIntentOptions } from "../../ports/adb.js";
2
+ import type { CommandResult, RunningCommand } from "../../ports/process-runner.js";
3
+ import type { RuntimeSession } from "../../ports/runtime-backend.js";
4
+ import type { RuntimeSessionPortViews } from "../../ports/runtime-session-ports.js";
5
+ import type { ScreenshotOptions, ScreenshotPort } from "../../ports/screenshot.js";
6
+ import type { Point } from "../../domain/geometry.js";
7
+ import type { ForegroundComponent } from "../../domain/activity.js";
8
+ import type { AppProcess } from "../../domain/app-process.js";
9
+ import type { WindowTopology } from "../../domain/window-hierarchy.js";
10
+ /**
11
+ * One borrowed `RuntimeSession` exposed as the legacy `AdbPort`. The view
12
+ * holds a single already-opened session: the serial in every call must match
13
+ * the session's bound serial, and device discovery belongs to
14
+ * `RuntimeBackend.listDevices`. Level 1 session-first orchestrators feed their
15
+ * `AdbPort`-shaped helpers through this view until Level 2 retypes them.
16
+ */
17
+ export declare class RuntimeSessionAdbView implements AdbPort {
18
+ private readonly session;
19
+ constructor(session: RuntimeSession);
20
+ devices(): Promise<readonly DeviceInfo[]>;
21
+ foregroundComponent(identity: AppIdentity): Promise<ForegroundComponent>;
22
+ currentActivity(identity: AppIdentity): Promise<string>;
23
+ deviceIdentity(identity: AppIdentity): Promise<DeviceIdentity>;
24
+ isInstalled(identity: AppIdentity): Promise<boolean>;
25
+ launchActivity(options: LaunchActivityOptions): Promise<CommandResult>;
26
+ startActivityByIntent(options: StartActivityByIntentOptions): Promise<CommandResult>;
27
+ resolveLauncherActivity(): Promise<ResolvedActivity | undefined>;
28
+ forceStop(identity: AppIdentity): Promise<CommandResult>;
29
+ appProcesses(identity: AppIdentity): Promise<readonly AppProcess[]>;
30
+ windowTopology(identity: AppIdentity): Promise<WindowTopology>;
31
+ tap(point: Point, deviceSerial: string, signal?: AbortSignal): Promise<CommandResult>;
32
+ longClick(point: Point, durationMs: number, deviceSerial: string, signal?: AbortSignal): Promise<CommandResult>;
33
+ swipe(from: Point, to: Point, durationMs: number, deviceSerial: string, signal?: AbortSignal): Promise<CommandResult>;
34
+ back(deviceSerial: string, signal?: AbortSignal): Promise<CommandResult>;
35
+ inputText(text: string, deviceSerial: string, signal?: AbortSignal): Promise<CommandResult>;
36
+ startLogcat(options: LogcatOptions): RunningCommand;
37
+ dumpLogcat(options: DumpLogcatOptions): Promise<CommandResult>;
38
+ private assertBoundSerial;
39
+ }
40
+ /** One borrowed session exposed as the serial-keyed `ScreenshotPort`. */
41
+ export declare class SessionBoundScreenshotAdapter implements ScreenshotPort {
42
+ private readonly session;
43
+ constructor(session: RuntimeSession);
44
+ capture(options: ScreenshotOptions): Promise<CommandResult>;
45
+ }
46
+ /**
47
+ * Legacy port views for one borrowed session: the `AdbPort` view above, a
48
+ * session-bound screenshot port, the session's annotated-screen resolver
49
+ * (fail-closed when the backend lacks the capability), and the required UI
50
+ * stability probe. Session-first orchestrators pass these views to helpers
51
+ * that still speak the legacy port types.
52
+ */
53
+ export declare function runtimeSessionPortViews(session: RuntimeSession): RuntimeSessionPortViews;
@@ -0,0 +1,193 @@
1
+ import { runtimeCapabilityMissing } from "../../ports/runtime-capability.js";
2
+ import { FailClosedAnnotatedScreenResolver } from "./session-backed-ports.js";
3
+ function appQuery(identity) {
4
+ return {
5
+ packageName: identity.packageName,
6
+ ...(identity.signal === undefined ? {} : { signal: identity.signal }),
7
+ ...(identity.timeoutMs === undefined
8
+ ? {}
9
+ : { timeoutMs: identity.timeoutMs })
10
+ };
11
+ }
12
+ function launchOptions(options) {
13
+ return {
14
+ packageName: options.packageName,
15
+ activity: options.activity,
16
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
17
+ ...(options.timeoutMs === undefined
18
+ ? {}
19
+ : { timeoutMs: options.timeoutMs })
20
+ };
21
+ }
22
+ /**
23
+ * One borrowed `RuntimeSession` exposed as the legacy `AdbPort`. The view
24
+ * holds a single already-opened session: the serial in every call must match
25
+ * the session's bound serial, and device discovery belongs to
26
+ * `RuntimeBackend.listDevices`. Level 1 session-first orchestrators feed their
27
+ * `AdbPort`-shaped helpers through this view until Level 2 retypes them.
28
+ */
29
+ export class RuntimeSessionAdbView {
30
+ session;
31
+ constructor(session) {
32
+ this.session = session;
33
+ }
34
+ devices() {
35
+ return Promise.reject(new Error("Device discovery is not available through a runtime session view; "
36
+ + "use the runtime backend instead"));
37
+ }
38
+ async foregroundComponent(identity) {
39
+ this.assertBoundSerial(identity.deviceSerial);
40
+ if (this.session.foregroundComponent === undefined) {
41
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "foregroundComponent");
42
+ }
43
+ return this.session.foregroundComponent(appQuery(identity));
44
+ }
45
+ async currentActivity(identity) {
46
+ this.assertBoundSerial(identity.deviceSerial);
47
+ if (this.session.currentActivity === undefined) {
48
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "currentActivity");
49
+ }
50
+ return this.session.currentActivity(appQuery(identity));
51
+ }
52
+ async deviceIdentity(identity) {
53
+ this.assertBoundSerial(identity.deviceSerial);
54
+ if (this.session.deviceIdentity === undefined) {
55
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "deviceIdentity");
56
+ }
57
+ return this.session.deviceIdentity(appQuery(identity));
58
+ }
59
+ async isInstalled(identity) {
60
+ this.assertBoundSerial(identity.deviceSerial);
61
+ return this.session.isInstalled(appQuery(identity));
62
+ }
63
+ async launchActivity(options) {
64
+ this.assertBoundSerial(options.deviceSerial);
65
+ return this.session.launchApp(launchOptions(options));
66
+ }
67
+ async startActivityByIntent(options) {
68
+ this.assertBoundSerial(options.deviceSerial);
69
+ if (this.session.startActivityByIntent === undefined) {
70
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "startActivityByIntent");
71
+ }
72
+ return this.session.startActivityByIntent({
73
+ action: options.action,
74
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
75
+ ...(options.timeoutMs === undefined
76
+ ? {}
77
+ : { timeoutMs: options.timeoutMs })
78
+ });
79
+ }
80
+ resolveLauncherActivity() {
81
+ return Promise.reject(new Error("resolveLauncherActivity is not available through the runtime backend SPI"));
82
+ }
83
+ async forceStop(identity) {
84
+ this.assertBoundSerial(identity.deviceSerial);
85
+ return this.session.forceStop(appQuery(identity));
86
+ }
87
+ async appProcesses(identity) {
88
+ this.assertBoundSerial(identity.deviceSerial);
89
+ if (this.session.appProcesses === undefined) {
90
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "appProcesses");
91
+ }
92
+ return this.session.appProcesses(appQuery(identity));
93
+ }
94
+ async windowTopology(identity) {
95
+ this.assertBoundSerial(identity.deviceSerial);
96
+ if (this.session.windowTopology === undefined) {
97
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "windowTopology");
98
+ }
99
+ return this.session.windowTopology(appQuery(identity));
100
+ }
101
+ async tap(point, deviceSerial, signal) {
102
+ this.assertBoundSerial(deviceSerial);
103
+ return this.session.tap(point, signal);
104
+ }
105
+ async longClick(point, durationMs, deviceSerial, signal) {
106
+ this.assertBoundSerial(deviceSerial);
107
+ return this.session.longClick(point, durationMs, signal);
108
+ }
109
+ async swipe(from, to, durationMs, deviceSerial, signal) {
110
+ this.assertBoundSerial(deviceSerial);
111
+ return this.session.swipe(from, to, durationMs, signal);
112
+ }
113
+ async back(deviceSerial, signal) {
114
+ this.assertBoundSerial(deviceSerial);
115
+ return this.session.back(signal);
116
+ }
117
+ async inputText(text, deviceSerial, signal) {
118
+ this.assertBoundSerial(deviceSerial);
119
+ return this.session.inputText(text, signal);
120
+ }
121
+ startLogcat(options) {
122
+ this.assertBoundSerial(options.deviceSerial);
123
+ if (this.session.startLogcat === undefined) {
124
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "startLogcat");
125
+ }
126
+ const running = this.session.startLogcat({
127
+ onStdoutLine: options.onStdoutLine,
128
+ ...(options.onStderrLine === undefined
129
+ ? {}
130
+ : { onStderrLine: options.onStderrLine }),
131
+ ...(options.signal === undefined ? {} : { signal: options.signal })
132
+ });
133
+ return {
134
+ started: running.started,
135
+ completion: running.completion,
136
+ stop: () => running.stop()
137
+ };
138
+ }
139
+ async dumpLogcat(options) {
140
+ this.assertBoundSerial(options.deviceSerial);
141
+ if (this.session.dumpLogcat === undefined) {
142
+ throw runtimeCapabilityMissing(this.session.descriptor.id, "dumpLogcat");
143
+ }
144
+ return this.session.dumpLogcat({
145
+ maxLines: options.maxLines,
146
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
147
+ ...(options.timeoutMs === undefined
148
+ ? {}
149
+ : { timeoutMs: options.timeoutMs })
150
+ });
151
+ }
152
+ assertBoundSerial(deviceSerial) {
153
+ if (deviceSerial !== this.session.deviceSerial) {
154
+ throw new Error(`Runtime session bound to "${this.session.deviceSerial}" cannot `
155
+ + `serve device "${deviceSerial}"`);
156
+ }
157
+ }
158
+ }
159
+ /** One borrowed session exposed as the serial-keyed `ScreenshotPort`. */
160
+ export class SessionBoundScreenshotAdapter {
161
+ session;
162
+ constructor(session) {
163
+ this.session = session;
164
+ }
165
+ capture(options) {
166
+ if (options.deviceSerial !== this.session.deviceSerial) {
167
+ return Promise.reject(new Error(`Runtime session bound to "${this.session.deviceSerial}" cannot `
168
+ + `serve device "${options.deviceSerial}"`));
169
+ }
170
+ return this.session.captureScreenshot({
171
+ outputPath: options.outputPath,
172
+ ...(options.annotate === undefined ? {} : { annotate: options.annotate }),
173
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
174
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })
175
+ });
176
+ }
177
+ }
178
+ /**
179
+ * Legacy port views for one borrowed session: the `AdbPort` view above, a
180
+ * session-bound screenshot port, the session's annotated-screen resolver
181
+ * (fail-closed when the backend lacks the capability), and the required UI
182
+ * stability probe. Session-first orchestrators pass these views to helpers
183
+ * that still speak the legacy port types.
184
+ */
185
+ export function runtimeSessionPortViews(session) {
186
+ return {
187
+ adb: new RuntimeSessionAdbView(session),
188
+ screenshots: new SessionBoundScreenshotAdapter(session),
189
+ annotatedScreens: session.annotatedScreens
190
+ ?? new FailClosedAnnotatedScreenResolver(session.descriptor.id),
191
+ uiStability: session.uiStability
192
+ };
193
+ }
@@ -0,0 +1,21 @@
1
+ import type { Point } from "../../domain/geometry.js";
2
+ import type { AnnotatedScreenResolverPort } from "../../ports/annotated-screen-resolver.js";
3
+ import type { CommandResult } from "../../ports/process-runner.js";
4
+ import type { RuntimeSessionOpener } from "../../ports/runtime-backend.js";
5
+ import type { ScreenshotOptions, ScreenshotPort } from "../../ports/screenshot.js";
6
+ import type { OpenUiSnapshotProviderOptions, UiSnapshotProvider, UiSnapshotProviderFactory } from "../../ports/ui-snapshot.js";
7
+ export declare class SessionBackedScreenshotAdapter implements ScreenshotPort {
8
+ private readonly sessions;
9
+ constructor(sessions: RuntimeSessionOpener);
10
+ capture(options: ScreenshotOptions): Promise<CommandResult>;
11
+ }
12
+ export declare class SessionBackedUiSnapshotProviderFactory implements UiSnapshotProviderFactory {
13
+ private readonly sessions;
14
+ constructor(sessions: RuntimeSessionOpener);
15
+ open(options: OpenUiSnapshotProviderOptions): Promise<UiSnapshotProvider>;
16
+ }
17
+ export declare class FailClosedAnnotatedScreenResolver implements AnnotatedScreenResolverPort {
18
+ private readonly backendId;
19
+ constructor(backendId: string);
20
+ resolve(): Promise<Point>;
21
+ }
@@ -0,0 +1,43 @@
1
+ import { runtimeCapabilityMissing } from "../../ports/runtime-capability.js";
2
+ export class SessionBackedScreenshotAdapter {
3
+ sessions;
4
+ constructor(sessions) {
5
+ this.sessions = sessions;
6
+ }
7
+ capture(options) {
8
+ return this.sessions.openSession({
9
+ deviceSerial: options.deviceSerial,
10
+ ...(options.signal === undefined ? {} : { signal: options.signal })
11
+ }).then((session) => (session.captureScreenshot({
12
+ outputPath: options.outputPath,
13
+ ...(options.annotate === undefined ? {} : { annotate: options.annotate }),
14
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
15
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })
16
+ })));
17
+ }
18
+ }
19
+ export class SessionBackedUiSnapshotProviderFactory {
20
+ sessions;
21
+ constructor(sessions) {
22
+ this.sessions = sessions;
23
+ }
24
+ open(options) {
25
+ return this.sessions.openSession({
26
+ deviceSerial: options.deviceSerial,
27
+ ...(options.signal === undefined ? {} : { signal: options.signal })
28
+ }).then((session) => (session.openUiSnapshots({
29
+ timeoutMs: options.timeoutMs,
30
+ ...(options.backend === undefined ? {} : { backend: options.backend }),
31
+ ...(options.signal === undefined ? {} : { signal: options.signal })
32
+ })));
33
+ }
34
+ }
35
+ export class FailClosedAnnotatedScreenResolver {
36
+ backendId;
37
+ constructor(backendId) {
38
+ this.backendId = backendId;
39
+ }
40
+ resolve() {
41
+ return Promise.reject(runtimeCapabilityMissing(this.backendId, "annotated screens"));
42
+ }
43
+ }
@@ -0,0 +1,12 @@
1
+ import type { DeviceInfo } from "../../domain/runtime.js";
2
+ import type { OpenRuntimeSessionOptions, RuntimeBackend, RuntimeSession } from "../../ports/runtime-backend.js";
3
+ export declare class SharedSessionRuntimeBackend implements RuntimeBackend {
4
+ private readonly backend;
5
+ private readonly sessions;
6
+ constructor(backend: RuntimeBackend);
7
+ get descriptor(): RuntimeBackend["descriptor"];
8
+ get capabilities(): RuntimeBackend["capabilities"];
9
+ listDevices(signal?: AbortSignal): Promise<readonly DeviceInfo[]>;
10
+ openSession(options: OpenRuntimeSessionOptions): Promise<RuntimeSession>;
11
+ close(): Promise<void>;
12
+ }
@@ -0,0 +1,64 @@
1
+ function borrowedProvider(provider) {
2
+ return new Proxy(provider, {
3
+ get(target, property, receiver) {
4
+ if (property === "close") {
5
+ return () => Promise.resolve();
6
+ }
7
+ const value = Reflect.get(target, property, receiver);
8
+ return typeof value === "function"
9
+ ? value.bind(target)
10
+ : value;
11
+ }
12
+ });
13
+ }
14
+ function borrowedSession(session) {
15
+ return new Proxy(session, {
16
+ get(target, property, receiver) {
17
+ if (property === "close") {
18
+ return () => Promise.resolve();
19
+ }
20
+ if (property === "openUiSnapshots") {
21
+ return async (options) => borrowedProvider(await target.openUiSnapshots(options));
22
+ }
23
+ const value = Reflect.get(target, property, receiver);
24
+ return typeof value === "function"
25
+ ? value.bind(target)
26
+ : value;
27
+ }
28
+ });
29
+ }
30
+ export class SharedSessionRuntimeBackend {
31
+ backend;
32
+ sessions = new Map();
33
+ constructor(backend) {
34
+ this.backend = backend;
35
+ }
36
+ get descriptor() {
37
+ return this.backend.descriptor;
38
+ }
39
+ get capabilities() {
40
+ return this.backend.capabilities;
41
+ }
42
+ listDevices(signal) {
43
+ return this.backend.listDevices(signal);
44
+ }
45
+ openSession(options) {
46
+ const existing = this.sessions.get(options.deviceSerial);
47
+ if (existing !== undefined) {
48
+ return existing.then(borrowedSession);
49
+ }
50
+ const opened = this.backend.openSession(options);
51
+ opened.catch(() => {
52
+ if (this.sessions.get(options.deviceSerial) === opened) {
53
+ this.sessions.delete(options.deviceSerial);
54
+ }
55
+ });
56
+ this.sessions.set(options.deviceSerial, opened);
57
+ return opened.then(borrowedSession);
58
+ }
59
+ async close() {
60
+ const sessions = [...this.sessions.values()];
61
+ this.sessions.clear();
62
+ await Promise.all(sessions.map((session) => (session.then((opened) => opened.close(), () => undefined))));
63
+ }
64
+ }
@@ -0,0 +1,8 @@
1
+ import type { OpenUiSnapshotProviderOptions, UiSnapshotProvider, UiSnapshotProviderFactory } from "../../ports/ui-snapshot.js";
2
+ export declare class AutoUiSnapshotProviderFactory implements UiSnapshotProviderFactory {
3
+ private readonly system;
4
+ private readonly androidCli;
5
+ private readonly appium?;
6
+ constructor(system: UiSnapshotProviderFactory, androidCli: UiSnapshotProviderFactory, appium?: UiSnapshotProviderFactory | undefined);
7
+ open(options: OpenUiSnapshotProviderOptions): Promise<UiSnapshotProvider>;
8
+ }
@@ -0,0 +1,48 @@
1
+ import { UiSnapshotError } from "./ui-snapshot-error.js";
2
+ export class AutoUiSnapshotProviderFactory {
3
+ system;
4
+ androidCli;
5
+ appium;
6
+ constructor(system, androidCli, appium) {
7
+ this.system = system;
8
+ this.androidCli = androidCli;
9
+ this.appium = appium;
10
+ }
11
+ async open(options) {
12
+ if (options.backend === "system-uiautomator") {
13
+ return this.system.open(options);
14
+ }
15
+ if (options.backend === "android-cli") {
16
+ return this.androidCli.open(options);
17
+ }
18
+ if (options.backend === "appium-uiautomator2") {
19
+ if (this.appium !== undefined)
20
+ return this.appium.open(options);
21
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", "appium-uiautomator2", "Appium UiAutomator2 provider is not installed");
22
+ }
23
+ const appium = this.appium;
24
+ const probe = appium;
25
+ if (probe?.probe !== undefined && await probe.probe(options.timeoutMs)) {
26
+ try {
27
+ return await appium.open(options);
28
+ }
29
+ catch (error) {
30
+ if (!isAutoFallbackable(error))
31
+ throw error;
32
+ }
33
+ }
34
+ try {
35
+ return await this.system.open(options);
36
+ }
37
+ catch (error) {
38
+ if (!isAutoFallbackable(error))
39
+ throw error;
40
+ }
41
+ return this.androidCli.open(options);
42
+ }
43
+ }
44
+ function isAutoFallbackable(error) {
45
+ return error instanceof UiSnapshotError
46
+ && (error.code === "UI_BACKEND_UNAVAILABLE"
47
+ || error.code === "UI_SNAPSHOT_INVALID");
48
+ }
@@ -0,0 +1,6 @@
1
+ import type { ProcessRunner } from "../../ports/process-runner.js";
2
+ export declare const DEVICE_LAYOUT_TEMP_PREFIX = "/data/local/tmp/taphound-uiautomator-";
3
+ export declare const DEVICE_LAYOUT_TEMP_GLOB = "/data/local/tmp/taphound-uiautomator-*.xml";
4
+ export declare const DEVICE_LAYOUT_TEMP_SWEEP_TIMEOUT_MS = 5000;
5
+ export declare function createDeviceLayoutPath(): string;
6
+ export declare function sweepDeviceLayoutTemp(runner: ProcessRunner, deviceSerial: string, signal?: AbortSignal): Promise<void>;
@@ -0,0 +1,18 @@
1
+ import { randomUUID } from "node:crypto";
2
+ export const DEVICE_LAYOUT_TEMP_PREFIX = "/data/local/tmp/taphound-uiautomator-";
3
+ export const DEVICE_LAYOUT_TEMP_GLOB = `${DEVICE_LAYOUT_TEMP_PREFIX}*.xml`;
4
+ export const DEVICE_LAYOUT_TEMP_SWEEP_TIMEOUT_MS = 5000;
5
+ export function createDeviceLayoutPath() {
6
+ return `${DEVICE_LAYOUT_TEMP_PREFIX}${randomUUID()}.xml`;
7
+ }
8
+ export async function sweepDeviceLayoutTemp(runner, deviceSerial, signal) {
9
+ if (signal?.aborted === true) {
10
+ return;
11
+ }
12
+ await runner.run({
13
+ executable: "adb",
14
+ args: ["-s", deviceSerial, "shell", "rm", "-f", DEVICE_LAYOUT_TEMP_GLOB],
15
+ timeoutMs: DEVICE_LAYOUT_TEMP_SWEEP_TIMEOUT_MS,
16
+ ...(signal === undefined ? {} : { signal })
17
+ }).catch(() => undefined);
18
+ }
@@ -0,0 +1,13 @@
1
+ import { type DisplayViewport } from "../../domain/geometry.js";
2
+ import type { UiBackendDescriptor } from "../../domain/ui-backend.js";
3
+ import type { ProcessRunner } from "../../ports/process-runner.js";
4
+ export interface DeviceUiEnvironment {
5
+ sdkLevel: number;
6
+ viewport: DisplayViewport;
7
+ }
8
+ export declare function parseDisplayRotation(dumpsysInput: string): DisplayViewport["rotation"] | undefined;
9
+ export declare function readDeviceUiEnvironment(runner: ProcessRunner, backendId: UiBackendDescriptor["id"], options: {
10
+ deviceSerial: string;
11
+ timeoutMs: number;
12
+ signal?: AbortSignal | undefined;
13
+ }): Promise<DeviceUiEnvironment>;
@@ -0,0 +1,81 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { DisplayViewportSchema } from "../../domain/geometry.js";
3
+ import { UiSnapshotError } from "./ui-snapshot-error.js";
4
+ function usable(result) {
5
+ return result.exitCode === 0
6
+ && !result.timedOut
7
+ && !result.cancelled
8
+ && result.spawnError === undefined;
9
+ }
10
+ function message(result, fallback) {
11
+ return result.stderr.trim() || result.spawnError || fallback;
12
+ }
13
+ export function parseDisplayRotation(dumpsysInput) {
14
+ const orientation = /SurfaceOrientation:\s*([0-3])/i.exec(dumpsysInput)?.[1]
15
+ ?? /Viewport[^\n]*\borientation=([0-3])\b/i.exec(dumpsysInput)?.[1];
16
+ if (orientation !== undefined) {
17
+ return [0, 90, 180, 270][Number(orientation)];
18
+ }
19
+ const rotationIndex = /\bRotation([0-3])\b/i.exec(dumpsysInput)?.[1];
20
+ if (rotationIndex !== undefined) {
21
+ return [0, 90, 180, 270][Number(rotationIndex)];
22
+ }
23
+ const degrees = /\bROT_(0|90|180|270)\b/i.exec(dumpsysInput)?.[1];
24
+ if (degrees === undefined)
25
+ return undefined;
26
+ const parsed = Number(degrees);
27
+ return parsed === 0 || parsed === 90 || parsed === 180 || parsed === 270
28
+ ? parsed
29
+ : undefined;
30
+ }
31
+ export async function readDeviceUiEnvironment(runner, backendId, options) {
32
+ const startedAt = performance.now();
33
+ const run = async (args) => {
34
+ const remainingMs = Math.max(1, options.timeoutMs - (performance.now() - startedAt));
35
+ const result = await runner.run({
36
+ executable: "adb",
37
+ args: ["-s", options.deviceSerial, ...args],
38
+ timeoutMs: remainingMs,
39
+ ...(options.signal === undefined ? {} : { signal: options.signal })
40
+ });
41
+ if (!usable(result)) {
42
+ throw new UiSnapshotError(result.timedOut || result.cancelled
43
+ ? "UI_SNAPSHOT_FAILED"
44
+ : "UI_BACKEND_UNAVAILABLE", backendId, message(result, `Unable to inspect device UI environment`));
45
+ }
46
+ return result;
47
+ };
48
+ const sdkResult = await run([
49
+ "shell",
50
+ "getprop",
51
+ "ro.build.version.sdk"
52
+ ]);
53
+ const sdkLevel = Number(sdkResult.stdout.trim());
54
+ if (!Number.isSafeInteger(sdkLevel)) {
55
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", backendId, "Device returned an invalid Android SDK level");
56
+ }
57
+ if (sdkLevel < 26) {
58
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", backendId, `UI snapshots require Android API 26 or newer; device is API ${String(sdkLevel)}`);
59
+ }
60
+ const sizeResult = await run(["shell", "wm", "size"]);
61
+ const size = /(?:Physical size:\s*)?(\d+)x(\d+)/i.exec(sizeResult.stdout);
62
+ const width = Number(size?.[1]);
63
+ const height = Number(size?.[2]);
64
+ if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height)) {
65
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", backendId, "Device returned an invalid physical display size");
66
+ }
67
+ const rotationResult = await run(["shell", "dumpsys", "input"]);
68
+ const rotation = parseDisplayRotation(rotationResult.stdout);
69
+ if (rotation === undefined) {
70
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", backendId, "Device returned an invalid display rotation");
71
+ }
72
+ return {
73
+ sdkLevel,
74
+ viewport: DisplayViewportSchema.parse({
75
+ width,
76
+ height,
77
+ rotation,
78
+ coordinateSpace: "physicalDisplayPixels"
79
+ })
80
+ };
81
+ }
@@ -0,0 +1,9 @@
1
+ import { type Bounds } from "../../domain/layout.js";
2
+ export declare function normalizeResourceId(value: string | undefined): string | undefined;
3
+ /**
4
+ * Hot-path variant for already-numeric edges (one call per parsed node).
5
+ * Enforces the same contract as `RawBoundsSchema` plus `BoundsSchema`
6
+ * without allocating Zod issues for valid input.
7
+ */
8
+ export declare function normalizeBoundsEdges(left: number, top: number, right: number, bottom: number): Bounds | undefined;
9
+ export declare function normalizeBounds(value: unknown): Bounds | undefined;
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ import { BoundsSchema } from "../../domain/layout.js";
3
+ const RawBoundsSchema = z.strictObject({
4
+ left: z.number().int().nonnegative(),
5
+ top: z.number().int().nonnegative(),
6
+ right: z.number().int().nonnegative(),
7
+ bottom: z.number().int().nonnegative()
8
+ });
9
+ export function normalizeResourceId(value) {
10
+ if (value === undefined || value.length === 0)
11
+ return undefined;
12
+ const separator = value.lastIndexOf(":id/");
13
+ return separator >= 0 ? value.slice(separator + 4) : value;
14
+ }
15
+ function isEdge(value) {
16
+ return Number.isSafeInteger(value) && value >= 0;
17
+ }
18
+ /**
19
+ * Hot-path variant for already-numeric edges (one call per parsed node).
20
+ * Enforces the same contract as `RawBoundsSchema` plus `BoundsSchema`
21
+ * without allocating Zod issues for valid input.
22
+ */
23
+ export function normalizeBoundsEdges(left, top, right, bottom) {
24
+ if (!isEdge(left) || !isEdge(top) || !isEdge(right) || !isEdge(bottom)) {
25
+ return normalizeBounds({ left, top, right, bottom });
26
+ }
27
+ if (right < left || bottom < top) {
28
+ throw new Error("Bounds edges are reversed");
29
+ }
30
+ if (right === left || bottom === top) {
31
+ return undefined;
32
+ }
33
+ return { left, top, right, bottom };
34
+ }
35
+ export function normalizeBounds(value) {
36
+ const raw = RawBoundsSchema.parse(value);
37
+ if (raw.right < raw.left || raw.bottom < raw.top) {
38
+ throw new Error("Bounds edges are reversed");
39
+ }
40
+ if (raw.right === raw.left || raw.bottom === raw.top) {
41
+ return undefined;
42
+ }
43
+ return BoundsSchema.parse(raw);
44
+ }
@@ -0,0 +1,11 @@
1
+ import type { UiBackendDescriptor } from "../../domain/ui-backend.js";
2
+ export type UiSnapshotErrorCode = "UI_BACKEND_UNAVAILABLE" | "UI_SNAPSHOT_FAILED" | "UI_SNAPSHOT_INVALID";
3
+ export declare class UiSnapshotError extends Error {
4
+ readonly code: UiSnapshotErrorCode;
5
+ readonly backendId: UiBackendDescriptor["id"];
6
+ readonly name = "UiSnapshotError";
7
+ readonly terminal: boolean;
8
+ constructor(code: UiSnapshotErrorCode, backendId: UiBackendDescriptor["id"], message: string, options?: ErrorOptions & {
9
+ terminal?: boolean | undefined;
10
+ });
11
+ }
@@ -0,0 +1,12 @@
1
+ export class UiSnapshotError extends Error {
2
+ code;
3
+ backendId;
4
+ name = "UiSnapshotError";
5
+ terminal;
6
+ constructor(code, backendId, message, options) {
7
+ super(message, options);
8
+ this.code = code;
9
+ this.backendId = backendId;
10
+ this.terminal = options?.terminal ?? false;
11
+ }
12
+ }