taphound 0.2.0-dev.1 → 0.2.0-dev.11

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 (447) 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 +500 -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 +561 -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 +349 -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 +34 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +240 -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/external-flow-registry.d.ts +17 -0
  73. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  74. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  75. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  76. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  77. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  78. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  79. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  80. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  81. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  82. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  83. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  84. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  85. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  86. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  87. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  88. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  89. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  90. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  91. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  92. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  93. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  94. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  95. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  96. package/dist/adapters/filesystem/skill-installer.js +40 -11
  97. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  98. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  99. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  100. package/dist/adapters/git/node-git-diff.js +114 -0
  101. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  102. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  103. package/dist/adapters/process/node-process-runner.js +11 -2
  104. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  105. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  106. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  107. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  108. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  109. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  110. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  111. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  112. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  113. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  114. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  115. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  116. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  122. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  123. package/dist/adapters/runtime/session-adb-view.js +193 -0
  124. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  125. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  126. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  127. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  128. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  129. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  130. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  131. package/dist/adapters/ui/device-layout-temp.js +18 -0
  132. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  133. package/dist/adapters/ui/device-ui-environment.js +81 -0
  134. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  135. package/dist/adapters/ui/layout-normalization.js +44 -0
  136. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  137. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  138. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  139. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  140. package/dist/application/align/align-service.d.ts +42 -0
  141. package/dist/application/align/align-service.js +106 -0
  142. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  143. package/dist/application/assertion/expectation-evaluator.js +156 -18
  144. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  145. package/dist/application/assertion/guarded-expectation.js +74 -0
  146. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  147. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  148. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  149. package/dist/application/checkpoint/baseline-error.js +8 -0
  150. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  151. package/dist/application/checkpoint/baseline-service.js +147 -0
  152. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  153. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  154. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  155. package/dist/application/checkpoint/regression-comparator.js +192 -0
  156. package/dist/application/collector/logcat-collector.d.ts +22 -1
  157. package/dist/application/collector/logcat-collector.js +103 -15
  158. package/dist/application/collector/logcat-event.d.ts +8 -0
  159. package/dist/application/collector/logcat-event.js +79 -0
  160. package/dist/application/collector/logcat-stop.d.ts +2 -0
  161. package/dist/application/collector/logcat-stop.js +11 -0
  162. package/dist/application/context/context-generator.d.ts +45 -0
  163. package/dist/application/context/context-generator.js +228 -0
  164. package/dist/application/context/context-loader.d.ts +40 -0
  165. package/dist/application/context/context-loader.js +223 -0
  166. package/dist/application/context/context-refresher.d.ts +59 -0
  167. package/dist/application/context/context-refresher.js +349 -0
  168. package/dist/application/context/context-rehasher.d.ts +36 -0
  169. package/dist/application/context/context-rehasher.js +110 -0
  170. package/dist/application/context/context-validator.d.ts +23 -1
  171. package/dist/application/context/context-validator.js +116 -9
  172. package/dist/application/context/evidence-hash.d.ts +1 -0
  173. package/dist/application/context/evidence-hash.js +125 -0
  174. package/dist/application/context/evidence-match.d.ts +9 -0
  175. package/dist/application/context/evidence-match.js +8 -0
  176. package/dist/application/context/shard-identity.d.ts +2 -0
  177. package/dist/application/context/shard-identity.js +7 -0
  178. package/dist/application/contract/contract-loader.d.ts +25 -0
  179. package/dist/application/contract/contract-loader.js +68 -0
  180. package/dist/application/contract/contract-review.d.ts +25 -0
  181. package/dist/application/contract/contract-review.js +51 -0
  182. package/dist/application/contract/contract-verifier.d.ts +53 -0
  183. package/dist/application/contract/contract-verifier.js +645 -0
  184. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  185. package/dist/application/devices/resolve-device-assignments.js +60 -0
  186. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  187. package/dist/application/diagnosis/failure-classifier.js +179 -0
  188. package/dist/application/doctor/doctor-service.d.ts +36 -3
  189. package/dist/application/doctor/doctor-service.js +255 -25
  190. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  191. package/dist/application/generation/generation-app-preparer.js +28 -0
  192. package/dist/application/generation/generation-config-service.d.ts +21 -0
  193. package/dist/application/generation/generation-config-service.js +53 -0
  194. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  195. package/dist/application/generation/generation-confirmation-service.js +109 -24
  196. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  197. package/dist/application/generation/generation-context-snapshot.js +29 -0
  198. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  199. package/dist/application/generation/generation-finalizer.js +167 -70
  200. package/dist/application/generation/generation-publisher.js +12 -8
  201. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  202. package/dist/application/generation/generation-recovery-service.js +144 -0
  203. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  204. package/dist/application/generation/generation-reopen-service.js +37 -0
  205. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  206. package/dist/application/generation/generation-replace-service.js +116 -0
  207. package/dist/application/generation/generation-starter.d.ts +44 -4
  208. package/dist/application/generation/generation-starter.js +175 -8
  209. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  210. package/dist/application/generation/generation-step-executor.js +471 -108
  211. package/dist/application/generation/proposed-step-validator.js +96 -30
  212. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  213. package/dist/application/generation/replay-policy-loader.js +29 -0
  214. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  215. package/dist/application/generation/risk-evaluator.js +118 -3
  216. package/dist/application/generation/runtime-observer.d.ts +39 -7
  217. package/dist/application/generation/runtime-observer.js +193 -24
  218. package/dist/application/impact/impact-resolver.d.ts +32 -0
  219. package/dist/application/impact/impact-resolver.js +160 -0
  220. package/dist/application/init/init-service.js +26 -13
  221. package/dist/application/interaction/action-executor.d.ts +3 -2
  222. package/dist/application/interaction/action-executor.js +11 -1
  223. package/dist/application/interaction/action-target.d.ts +17 -0
  224. package/dist/application/interaction/action-target.js +40 -0
  225. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  226. package/dist/application/interaction/external-step-runner.js +332 -0
  227. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  228. package/dist/application/interaction/fallback-resolver.js +7 -5
  229. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  230. package/dist/application/interaction/scroll-to-executor.js +118 -36
  231. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  232. package/dist/application/journey/external-flow-resolver.js +22 -0
  233. package/dist/application/journey/journey-check-service.d.ts +54 -0
  234. package/dist/application/journey/journey-check-service.js +207 -0
  235. package/dist/application/journey/journey-promoter.d.ts +26 -0
  236. package/dist/application/journey/journey-promoter.js +123 -0
  237. package/dist/application/journey/journey-resolver.d.ts +42 -0
  238. package/dist/application/journey/journey-resolver.js +239 -0
  239. package/dist/application/journey/journey-retirer.d.ts +25 -0
  240. package/dist/application/journey/journey-retirer.js +87 -0
  241. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  242. package/dist/application/knowledge/anchor-resolver.js +110 -0
  243. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  244. package/dist/application/knowledge/knowledge-loader.js +36 -0
  245. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  246. package/dist/application/locator/layout-failure-summary.js +67 -0
  247. package/dist/application/locator/layout-traversal.d.ts +11 -0
  248. package/dist/application/locator/layout-traversal.js +18 -0
  249. package/dist/application/locator/locator-resolver.d.ts +13 -1
  250. package/dist/application/locator/locator-resolver.js +182 -18
  251. package/dist/application/observe/observe-service.d.ts +20 -0
  252. package/dist/application/observe/observe-service.js +91 -0
  253. package/dist/application/project/project-describer.d.ts +14 -6
  254. package/dist/application/project/project-describer.js +38 -5
  255. package/dist/application/recognition/screen-detector.d.ts +28 -0
  256. package/dist/application/recognition/screen-detector.js +111 -0
  257. package/dist/application/recorder/locator-selector.js +151 -17
  258. package/dist/application/recorder/recorder-service.d.ts +16 -4
  259. package/dist/application/recorder/recorder-service.js +420 -128
  260. package/dist/application/report/report-writer.js +1 -1
  261. package/dist/application/runtime/cold-launch.d.ts +28 -0
  262. package/dist/application/runtime/cold-launch.js +59 -0
  263. package/dist/application/runtime/step-runner.d.ts +49 -4
  264. package/dist/application/runtime/step-runner.js +721 -130
  265. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  266. package/dist/application/runtime/verify-runtime.js +554 -174
  267. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  268. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  269. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  270. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  271. package/dist/application/ui/ui-stability-probe.d.ts +3 -0
  272. package/dist/application/ui/ui-stability-probe.js +8 -0
  273. package/dist/application/wait/idle-advice.d.ts +6 -0
  274. package/dist/application/wait/idle-advice.js +27 -0
  275. package/dist/application/wait/idle-profiles.d.ts +15 -0
  276. package/dist/application/wait/idle-profiles.js +75 -0
  277. package/dist/application/wait/idle-waiter.d.ts +28 -4
  278. package/dist/application/wait/idle-waiter.js +186 -15
  279. package/dist/cli/commands/align.d.ts +3 -0
  280. package/dist/cli/commands/align.js +124 -0
  281. package/dist/cli/commands/baseline.d.ts +3 -0
  282. package/dist/cli/commands/baseline.js +130 -0
  283. package/dist/cli/commands/context.js +300 -27
  284. package/dist/cli/commands/contract.d.ts +3 -0
  285. package/dist/cli/commands/contract.js +120 -0
  286. package/dist/cli/commands/doctor.js +16 -9
  287. package/dist/cli/commands/failure.d.ts +3 -0
  288. package/dist/cli/commands/failure.js +63 -0
  289. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  290. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  291. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  292. package/dist/cli/commands/generation/session-commands.js +472 -0
  293. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  294. package/dist/cli/commands/generation/shared.js +291 -0
  295. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  296. package/dist/cli/commands/generation/step-commands.js +315 -0
  297. package/dist/cli/commands/generation.js +10 -507
  298. package/dist/cli/commands/impact.d.ts +3 -0
  299. package/dist/cli/commands/impact.js +87 -0
  300. package/dist/cli/commands/init.js +13 -6
  301. package/dist/cli/commands/journey.d.ts +3 -0
  302. package/dist/cli/commands/journey.js +382 -0
  303. package/dist/cli/commands/knowledge.d.ts +3 -0
  304. package/dist/cli/commands/knowledge.js +93 -0
  305. package/dist/cli/commands/observe.d.ts +3 -0
  306. package/dist/cli/commands/observe.js +127 -0
  307. package/dist/cli/commands/project.js +2 -1
  308. package/dist/cli/commands/record.js +18 -5
  309. package/dist/cli/commands/verify.js +273 -63
  310. package/dist/cli/dependencies.d.ts +125 -1
  311. package/dist/cli/dependencies.js +450 -51
  312. package/dist/cli/diff-verification.d.ts +41 -0
  313. package/dist/cli/diff-verification.js +192 -0
  314. package/dist/cli/main.js +49 -1
  315. package/dist/cli/output.d.ts +5 -3
  316. package/dist/cli/output.js +12 -0
  317. package/dist/cli/program.js +19 -1
  318. package/dist/cli/project-root.d.ts +1 -0
  319. package/dist/cli/project-root.js +6 -0
  320. package/dist/cli/runtime-selection.d.ts +22 -0
  321. package/dist/cli/runtime-selection.js +92 -0
  322. package/dist/cli/version.d.ts +1 -0
  323. package/dist/cli/version.js +14 -0
  324. package/dist/cli/workspace-guard.d.ts +2 -0
  325. package/dist/cli/workspace-guard.js +3 -0
  326. package/dist/domain/binding-reference.d.ts +4 -0
  327. package/dist/domain/binding-reference.js +23 -0
  328. package/dist/domain/checkpoint.d.ts +404 -0
  329. package/dist/domain/checkpoint.js +297 -0
  330. package/dist/domain/config.d.ts +107 -1
  331. package/dist/domain/config.js +52 -6
  332. package/dist/domain/contract.d.ts +413 -0
  333. package/dist/domain/contract.js +196 -0
  334. package/dist/domain/external-flow.d.ts +493 -0
  335. package/dist/domain/external-flow.js +15 -0
  336. package/dist/domain/failure-classification.d.ts +176 -0
  337. package/dist/domain/failure-classification.js +169 -0
  338. package/dist/domain/failure.d.ts +2 -1
  339. package/dist/domain/failure.js +123 -0
  340. package/dist/domain/generation.d.ts +1671 -132
  341. package/dist/domain/generation.js +202 -13
  342. package/dist/domain/geometry.d.ts +13 -0
  343. package/dist/domain/geometry.js +16 -0
  344. package/dist/domain/impact.d.ts +71 -0
  345. package/dist/domain/impact.js +76 -0
  346. package/dist/domain/init.d.ts +12 -4
  347. package/dist/domain/init.js +24 -18
  348. package/dist/domain/journey-composition.d.ts +2285 -0
  349. package/dist/domain/journey-composition.js +85 -0
  350. package/dist/domain/journey-lifecycle.d.ts +10 -0
  351. package/dist/domain/journey-lifecycle.js +9 -0
  352. package/dist/domain/journey.d.ts +2419 -212
  353. package/dist/domain/journey.js +384 -14
  354. package/dist/domain/knowledge.d.ts +165 -0
  355. package/dist/domain/knowledge.js +188 -0
  356. package/dist/domain/layout.d.ts +34 -5
  357. package/dist/domain/layout.js +64 -6
  358. package/dist/domain/locator-evidence.d.ts +3 -0
  359. package/dist/domain/locator-evidence.js +36 -0
  360. package/dist/domain/logcat-event.d.ts +54 -0
  361. package/dist/domain/logcat-event.js +40 -0
  362. package/dist/domain/observation.d.ts +33 -0
  363. package/dist/domain/observation.js +18 -0
  364. package/dist/domain/project-context.d.ts +219 -1
  365. package/dist/domain/project-context.js +209 -6
  366. package/dist/domain/proposed-step.d.ts +340 -60
  367. package/dist/domain/proposed-step.js +23 -3
  368. package/dist/domain/report.d.ts +1455 -28
  369. package/dist/domain/report.js +211 -14
  370. package/dist/domain/runtime-snapshot.d.ts +58 -1
  371. package/dist/domain/runtime-snapshot.js +14 -3
  372. package/dist/domain/runtime.d.ts +50 -0
  373. package/dist/domain/runtime.js +36 -0
  374. package/dist/domain/system-app-profiles.d.ts +6 -0
  375. package/dist/domain/system-app-profiles.js +43 -0
  376. package/dist/domain/ui-backend.d.ts +28 -0
  377. package/dist/domain/ui-backend.js +33 -0
  378. package/dist/domain/ui-cache.d.ts +11 -0
  379. package/dist/domain/ui-cache.js +10 -0
  380. package/dist/domain/window-hierarchy.d.ts +84 -0
  381. package/dist/domain/window-hierarchy.js +172 -0
  382. package/dist/domain/workflow-manifest.d.ts +77 -0
  383. package/dist/domain/workflow-manifest.js +136 -0
  384. package/dist/domain/workspace.d.ts +28 -0
  385. package/dist/domain/workspace.js +72 -0
  386. package/dist/ports/adb.d.ts +34 -1
  387. package/dist/ports/align-prompt.d.ts +11 -0
  388. package/dist/ports/align-prompt.js +6 -0
  389. package/dist/ports/anchor-resolver.d.ts +30 -0
  390. package/dist/ports/anchor-resolver.js +1 -0
  391. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  392. package/dist/ports/annotated-screen-resolver.js +1 -0
  393. package/dist/ports/camera-probe.d.ts +23 -0
  394. package/dist/ports/camera-probe.js +8 -0
  395. package/dist/ports/context-document-writer.d.ts +24 -0
  396. package/dist/ports/context-document-writer.js +1 -0
  397. package/dist/ports/detached-process-launcher.d.ts +12 -0
  398. package/dist/ports/detached-process-launcher.js +1 -0
  399. package/dist/ports/external-flow-registry.d.ts +37 -0
  400. package/dist/ports/external-flow-registry.js +1 -0
  401. package/dist/ports/generation-prompt.d.ts +2 -1
  402. package/dist/ports/generation-session-store.d.ts +12 -2
  403. package/dist/ports/git-diff.d.ts +9 -0
  404. package/dist/ports/git-diff.js +1 -0
  405. package/dist/ports/journey-composition-store.d.ts +17 -0
  406. package/dist/ports/journey-composition-store.js +1 -0
  407. package/dist/ports/knowledge-registry.d.ts +20 -0
  408. package/dist/ports/knowledge-registry.js +1 -0
  409. package/dist/ports/process-runner.d.ts +7 -0
  410. package/dist/ports/project-file-inspector.d.ts +1 -0
  411. package/dist/ports/project-identity-inspector.d.ts +24 -0
  412. package/dist/ports/project-identity-inspector.js +1 -0
  413. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  414. package/dist/ports/project-inventory-inspector.js +1 -0
  415. package/dist/ports/project-module-discoverer.d.ts +26 -0
  416. package/dist/ports/project-module-discoverer.js +1 -0
  417. package/dist/ports/recorder-prompt.d.ts +10 -1
  418. package/dist/ports/runtime-backend.d.ts +89 -0
  419. package/dist/ports/runtime-backend.js +13 -0
  420. package/dist/ports/runtime-capability.d.ts +12 -0
  421. package/dist/ports/runtime-capability.js +20 -0
  422. package/dist/ports/runtime-session-ports.d.ts +25 -0
  423. package/dist/ports/runtime-session-ports.js +1 -0
  424. package/dist/ports/screenshot.d.ts +11 -0
  425. package/dist/ports/screenshot.js +1 -0
  426. package/dist/ports/skill-installer.d.ts +2 -2
  427. package/dist/ports/ui-snapshot.d.ts +35 -0
  428. package/dist/ports/ui-snapshot.js +1 -0
  429. package/dist/ports/ui-stability.d.ts +19 -0
  430. package/dist/ports/ui-stability.js +1 -0
  431. package/dist/ports/workspace-layout.d.ts +4 -0
  432. package/dist/ports/workspace-layout.js +1 -0
  433. package/dist/shared/errors.d.ts +2 -0
  434. package/dist/shared/errors.js +22 -0
  435. package/dist/shared/paths.d.ts +2 -0
  436. package/dist/shared/paths.js +24 -0
  437. package/dist/shared/strings.d.ts +2 -0
  438. package/dist/shared/strings.js +16 -0
  439. package/package.json +6 -1
  440. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  441. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  442. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  443. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  444. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  445. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  446. package/dist/ports/android-cli.d.ts +0 -21
  447. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -1,11 +1,19 @@
1
- import type { AndroidCliPort, CaptureScreenOptions, DeviceCommandOptions, Point } from "../../ports/android-cli.js";
1
+ import type { Point } from "../../domain/geometry.js";
2
+ import type { AnnotatedScreenResolverPort } from "../../ports/annotated-screen-resolver.js";
2
3
  import type { CommandResult, ProcessRunner } from "../../ports/process-runner.js";
3
- import { parseLayout, parseLayoutDiff } from "./layout-parser.js";
4
- export declare class AndroidCliAdapter implements AndroidCliPort {
4
+ import type { ScreenshotOptions, ScreenshotPort } from "../../ports/screenshot.js";
5
+ import type { UiStabilityObservation, UiStabilityProbe, UiStabilitySampleOptions } from "../../ports/ui-stability.js";
6
+ export declare class AndroidCliAdapter implements ScreenshotPort, AnnotatedScreenResolverPort, UiStabilityProbe {
5
7
  private readonly runner;
6
- constructor(runner: ProcessRunner);
7
- layout(options: DeviceCommandOptions): Promise<ReturnType<typeof parseLayout>>;
8
- layoutDiff(options: DeviceCommandOptions): Promise<ReturnType<typeof parseLayoutDiff>>;
9
- captureScreen(options: CaptureScreenOptions): Promise<CommandResult>;
10
- resolveScreen(screenshotPath: string, label: string, signal?: AbortSignal): Promise<Point>;
8
+ private readonly createLayoutPath;
9
+ private readonly frameSignatures;
10
+ private readonly layoutSignatures;
11
+ private deviceLayoutTempSwept;
12
+ constructor(runner: ProcessRunner, createLayoutPath?: () => string);
13
+ private sweepDeviceLayoutTempOnce;
14
+ private readUiAutomator;
15
+ reset(): void;
16
+ sample(options: UiStabilitySampleOptions): Promise<UiStabilityObservation>;
17
+ capture(options: ScreenshotOptions): Promise<CommandResult>;
18
+ resolve(screenshotPath: string, label: string, signal?: AbortSignal): Promise<Point>;
11
19
  }
@@ -1,4 +1,8 @@
1
- import { parseLayout, parseLayoutDiff } from "./layout-parser.js";
1
+ import { createHash } from "node:crypto";
2
+ import { performance } from "node:perf_hooks";
3
+ import { parseLayoutDiff } from "./layout-parser.js";
4
+ import { parseUiAutomatorLayout } from "../adb/ui-automator-parser.js";
5
+ import { createDeviceLayoutPath, sweepDeviceLayoutTemp } from "../ui/device-layout-temp.js";
2
6
  function commandSpec(args, signal, timeoutMs) {
3
7
  return {
4
8
  executable: "android",
@@ -7,34 +11,152 @@ function commandSpec(args, signal, timeoutMs) {
7
11
  ...(timeoutMs === undefined ? {} : { timeoutMs })
8
12
  };
9
13
  }
14
+ function adbCommandSpec(deviceSerial, args, signal, timeoutMs) {
15
+ return {
16
+ executable: "adb",
17
+ args: ["-s", deviceSerial, ...args],
18
+ ...(signal === undefined ? {} : { signal }),
19
+ ...(timeoutMs === undefined ? {} : { timeoutMs })
20
+ };
21
+ }
10
22
  function assertSuccess(result, operation) {
11
- if (result.exitCode !== 0) {
12
- throw new Error(`Android CLI ${operation} failed: ${result.stderr.trim()}`);
23
+ if (result.exitCode !== 0
24
+ || result.timedOut
25
+ || result.cancelled
26
+ || result.spawnError !== undefined) {
27
+ throw new Error(`Android CLI ${operation} failed: ${result.stderr.trim() || result.spawnError || "command failed"}`);
13
28
  }
14
29
  }
30
+ class UiAutomatorUnavailableError extends Error {
31
+ name = "UiAutomatorUnavailableError";
32
+ }
33
+ function assertUiAutomatorSuccess(result, operation) {
34
+ if (result.timedOut || result.cancelled) {
35
+ throw Object.assign(new Error(`UIAutomator ${operation} did not complete before its deadline`), { terminal: true });
36
+ }
37
+ if (result.exitCode !== 0 || result.spawnError !== undefined) {
38
+ throw new UiAutomatorUnavailableError(result.stderr.trim()
39
+ || result.spawnError
40
+ || `UIAutomator ${operation} failed`);
41
+ }
42
+ }
43
+ function terminalBackendFailure(error) {
44
+ return error !== null
45
+ && typeof error === "object"
46
+ && "terminal" in error
47
+ && error.terminal === true;
48
+ }
15
49
  export class AndroidCliAdapter {
16
50
  runner;
17
- constructor(runner) {
51
+ createLayoutPath;
52
+ frameSignatures = new Map();
53
+ layoutSignatures = new Map();
54
+ deviceLayoutTempSwept = false;
55
+ constructor(runner, createLayoutPath = createDeviceLayoutPath) {
18
56
  this.runner = runner;
57
+ this.createLayoutPath = createLayoutPath;
19
58
  }
20
- async layout(options) {
21
- const result = await this.runner.run(commandSpec([
22
- "layout",
23
- `--device=${options.deviceSerial}`
24
- ], options.signal, options.timeoutMs));
25
- assertSuccess(result, "layout");
26
- return parseLayout(result.stdout);
59
+ async sweepDeviceLayoutTempOnce(deviceSerial) {
60
+ if (this.deviceLayoutTempSwept) {
61
+ return;
62
+ }
63
+ this.deviceLayoutTempSwept = true;
64
+ await sweepDeviceLayoutTemp(this.runner, deviceSerial);
65
+ }
66
+ async readUiAutomator(options) {
67
+ const path = this.createLayoutPath();
68
+ await this.sweepDeviceLayoutTempOnce(options.deviceSerial);
69
+ const deadline = options.timeoutMs === undefined
70
+ ? undefined
71
+ : performance.now() + options.timeoutMs;
72
+ const dumped = await this.runner.run(adbCommandSpec(options.deviceSerial, ["shell", "uiautomator", "dump", path], options.signal, options.timeoutMs));
73
+ try {
74
+ assertUiAutomatorSuccess(dumped, "dump");
75
+ const remainingMs = deadline === undefined
76
+ ? undefined
77
+ : Math.max(1, deadline - performance.now());
78
+ const xml = await this.runner.run(adbCommandSpec(options.deviceSerial, ["exec-out", "cat", path], options.signal, remainingMs));
79
+ assertUiAutomatorSuccess(xml, "read");
80
+ const layout = parseUiAutomatorLayout(xml.stdout);
81
+ if (layout.length === 0) {
82
+ throw new Error("UIAutomator dump contained no layout roots");
83
+ }
84
+ return { layout };
85
+ }
86
+ finally {
87
+ await this.runner.run(adbCommandSpec(options.deviceSerial, ["shell", "rm", "-f", path], undefined, 5000)).catch(() => { });
88
+ }
89
+ }
90
+ reset() {
91
+ this.frameSignatures.clear();
92
+ this.layoutSignatures.clear();
27
93
  }
28
- async layoutDiff(options) {
94
+ async sample(options) {
95
+ const startedAt = performance.now();
96
+ if (options.stabilityBackend === "uiautomator") {
97
+ try {
98
+ const current = await this.readUiAutomator(options);
99
+ const signature = createHash("sha256")
100
+ .update(JSON.stringify(current.layout))
101
+ .digest("hex");
102
+ const key = options.deviceSerial;
103
+ const previous = this.layoutSignatures.get(key);
104
+ this.layoutSignatures.set(key, signature);
105
+ return {
106
+ changes: previous === signature
107
+ ? []
108
+ : [{ layoutSha256: signature }],
109
+ layout: current.layout,
110
+ backend: "uiautomator",
111
+ durationMs: performance.now() - startedAt
112
+ };
113
+ }
114
+ catch (error) {
115
+ if (terminalBackendFailure(error))
116
+ throw error;
117
+ const result = await this.runner.run(commandSpec([
118
+ "layout",
119
+ "--diff",
120
+ `--device=${options.deviceSerial}`
121
+ ], options.signal, options.timeoutMs === undefined
122
+ ? undefined
123
+ : Math.max(1, options.timeoutMs - (performance.now() - startedAt))));
124
+ assertSuccess(result, "layout --diff");
125
+ return {
126
+ changes: parseLayoutDiff(result.stdout),
127
+ backend: "androidCli",
128
+ durationMs: performance.now() - startedAt
129
+ };
130
+ }
131
+ }
132
+ if (options.packageName !== undefined) {
133
+ const result = await this.runner.run(adbCommandSpec(options.deviceSerial, ["shell", "dumpsys", "gfxinfo", options.packageName], options.signal, options.timeoutMs));
134
+ assertSuccess(result, "frame stability");
135
+ const signature = result.stdout.match(/^Total frames rendered:\s*(\d+)\s*$/m)?.[1];
136
+ if (signature !== undefined) {
137
+ const key = `${options.deviceSerial}\u0000${options.packageName}`;
138
+ const previous = this.frameSignatures.get(key);
139
+ this.frameSignatures.set(key, signature);
140
+ return {
141
+ changes: previous === signature ? [] : [{ frameStats: signature }],
142
+ backend: "gfxFrameStats",
143
+ durationMs: performance.now() - startedAt
144
+ };
145
+ }
146
+ }
29
147
  const result = await this.runner.run(commandSpec([
30
148
  "layout",
31
149
  "--diff",
32
150
  `--device=${options.deviceSerial}`
33
151
  ], options.signal, options.timeoutMs));
34
152
  assertSuccess(result, "layout --diff");
35
- return parseLayoutDiff(result.stdout);
153
+ return {
154
+ changes: parseLayoutDiff(result.stdout),
155
+ backend: "androidCli",
156
+ durationMs: performance.now() - startedAt
157
+ };
36
158
  }
37
- captureScreen(options) {
159
+ capture(options) {
38
160
  return this.runner.run(commandSpec([
39
161
  "screen",
40
162
  "capture",
@@ -43,7 +165,7 @@ export class AndroidCliAdapter {
43
165
  `--device=${options.deviceSerial}`
44
166
  ], options.signal, options.timeoutMs));
45
167
  }
46
- async resolveScreen(screenshotPath, label, signal) {
168
+ async resolve(screenshotPath, label, signal) {
47
169
  const result = await this.runner.run(commandSpec([
48
170
  "screen",
49
171
  "resolve",
@@ -0,0 +1,9 @@
1
+ import type { ProcessRunner } from "../../ports/process-runner.js";
2
+ import type { OpenUiSnapshotProviderOptions, UiSnapshotProvider, UiSnapshotProviderFactory } from "../../ports/ui-snapshot.js";
3
+ import { type UiSnapshotTiming } from "../ui/ui-snapshot-support.js";
4
+ export declare class AndroidCliSnapshotProviderFactory implements UiSnapshotProviderFactory {
5
+ private readonly runner;
6
+ private readonly timing;
7
+ constructor(runner: ProcessRunner, timing?: UiSnapshotTiming);
8
+ open(options: OpenUiSnapshotProviderOptions): Promise<UiSnapshotProvider>;
9
+ }
@@ -0,0 +1,99 @@
1
+ import { createHash } from "node:crypto";
2
+ import { performance } from "node:perf_hooks";
3
+ import { parseLayout } from "./layout-parser.js";
4
+ import { readDeviceUiEnvironment } from "../ui/device-ui-environment.js";
5
+ import { UiSnapshotError } from "../ui/ui-snapshot-error.js";
6
+ import { snapshotFromCapture } from "../ui/ui-snapshot-support.js";
7
+ function descriptor(sdkLevel) {
8
+ return {
9
+ id: "android-cli",
10
+ adapterVersion: "android-cli-layout-v1",
11
+ engineVersion: `android-api-${String(sdkLevel)}`,
12
+ configSha256: createHash("sha256")
13
+ .update(JSON.stringify({ command: "android layout", version: 1 }))
14
+ .digest("hex")
15
+ };
16
+ }
17
+ class AndroidCliSnapshotProvider {
18
+ runner;
19
+ deviceSerial;
20
+ environment;
21
+ descriptor;
22
+ timing;
23
+ closed = false;
24
+ constructor(runner, deviceSerial, environment, descriptor, timing) {
25
+ this.runner = runner;
26
+ this.deviceSerial = deviceSerial;
27
+ this.environment = environment;
28
+ this.descriptor = descriptor;
29
+ this.timing = timing;
30
+ }
31
+ async capture(options) {
32
+ if (this.closed) {
33
+ throw new UiSnapshotError("UI_SNAPSHOT_FAILED", this.descriptor.id, "UI snapshot provider is closed");
34
+ }
35
+ const startedAt = performance.now();
36
+ const result = await this.runner.run({
37
+ executable: "android",
38
+ args: ["layout", `--device=${this.deviceSerial}`],
39
+ timeoutMs: options.timeoutMs,
40
+ ...(options.signal === undefined ? {} : { signal: options.signal })
41
+ });
42
+ if (result.exitCode !== 0
43
+ || result.timedOut
44
+ || result.cancelled
45
+ || result.spawnError !== undefined) {
46
+ throw new UiSnapshotError("UI_SNAPSHOT_FAILED", this.descriptor.id, result.stderr.trim() || result.spawnError || "Android CLI layout failed", { terminal: result.timedOut || result.cancelled });
47
+ }
48
+ let roots;
49
+ try {
50
+ roots = parseLayout(result.stdout);
51
+ }
52
+ catch (error) {
53
+ throw new UiSnapshotError("UI_SNAPSHOT_INVALID", this.descriptor.id, "Android CLI returned malformed layout source", { cause: error });
54
+ }
55
+ if (roots.length === 0) {
56
+ throw new UiSnapshotError("UI_SNAPSHOT_INVALID", this.descriptor.id, "Android CLI returned an empty layout");
57
+ }
58
+ return snapshotFromCapture({
59
+ startedAt,
60
+ roots,
61
+ backend: this.descriptor,
62
+ viewport: this.environment.viewport,
63
+ timing: this.timing
64
+ });
65
+ }
66
+ close() {
67
+ this.closed = true;
68
+ return Promise.resolve();
69
+ }
70
+ }
71
+ export class AndroidCliSnapshotProviderFactory {
72
+ runner;
73
+ timing;
74
+ constructor(runner, timing = {}) {
75
+ this.runner = runner;
76
+ this.timing = timing;
77
+ }
78
+ async open(options) {
79
+ const environment = await readDeviceUiEnvironment(this.runner, "android-cli", options);
80
+ const provider = new AndroidCliSnapshotProvider(this.runner, options.deviceSerial, environment, descriptor(environment.sdkLevel), this.timing);
81
+ try {
82
+ await provider.capture({
83
+ reason: "evidence",
84
+ timeoutMs: options.timeoutMs,
85
+ ...(options.signal === undefined ? {} : { signal: options.signal })
86
+ });
87
+ }
88
+ catch (error) {
89
+ if (error instanceof UiSnapshotError
90
+ && error.code === "UI_SNAPSHOT_FAILED"
91
+ && !error.terminal
92
+ && options.signal?.aborted !== true) {
93
+ throw new UiSnapshotError("UI_BACKEND_UNAVAILABLE", "android-cli", error.message, { cause: error });
94
+ }
95
+ throw error;
96
+ }
97
+ return provider;
98
+ }
99
+ }
@@ -1,4 +1,5 @@
1
- import { BoundsSchema, LayoutPointSchema } from "../../domain/layout.js";
1
+ import { LayoutPointSchema } from "../../domain/layout.js";
2
+ import { normalizeBounds, normalizeResourceId } from "../ui/layout-normalization.js";
2
3
  function parseJson(stdout, label) {
3
4
  try {
4
5
  return JSON.parse(stdout);
@@ -44,14 +45,14 @@ function parseBounds(value) {
44
45
  if (match === null) {
45
46
  throw new Error("Invalid Android Layout bounds");
46
47
  }
47
- return BoundsSchema.parse({
48
+ return normalizeBounds({
48
49
  left: Number(match[1]),
49
50
  top: Number(match[2]),
50
51
  right: Number(match[3]),
51
52
  bottom: Number(match[4])
52
53
  });
53
54
  }
54
- return BoundsSchema.parse(value);
55
+ return normalizeBounds(value);
55
56
  }
56
57
  function parseCenter(value) {
57
58
  if (value === undefined) {
@@ -98,7 +99,7 @@ function parseElement(value, path) {
98
99
  if (!Array.isArray(childrenValue)) {
99
100
  throw new Error("Invalid Android Layout children");
100
101
  }
101
- const resourceId = optionalString(record, "resourceId", "resource-id");
102
+ const resourceId = normalizeResourceId(optionalString(record, "resourceId", "resource-id"));
102
103
  const text = optionalString(record, "text");
103
104
  const contentDescription = optionalString(record, "contentDescription", "content-desc");
104
105
  const interactions = stringSet(record, "interactions");
@@ -120,15 +121,18 @@ function parseElement(value, path) {
120
121
  x: Math.round((bounds.left + bounds.right) / 2),
121
122
  y: Math.round((bounds.top + bounds.bottom) / 2)
122
123
  });
123
- if (center === undefined) {
124
- throw new Error("Android Layout element has no visible center or bounds");
125
- }
126
124
  const children = childrenValue.flatMap((child, index) => {
127
125
  const parsed = parseElement(child, `${path}/${String(index)}`);
128
126
  return parsed === undefined ? [] : [parsed];
129
127
  });
128
+ const serializerKey = record.key;
129
+ const windowId = typeof serializerKey === "string"
130
+ || typeof serializerKey === "number"
131
+ ? String(serializerKey)
132
+ : undefined;
130
133
  return {
131
134
  id: elementId(record, path),
135
+ ...(windowId === undefined ? {} : { windowId }),
132
136
  ...(resourceId === undefined ? {} : { resourceId }),
133
137
  ...(text === undefined ? {} : { text }),
134
138
  ...(contentDescription === undefined ? {} : { contentDescription }),
@@ -138,7 +142,7 @@ function parseElement(value, path) {
138
142
  ...(focusable === undefined ? {} : { focusable }),
139
143
  ...(focused === undefined ? {} : { focused }),
140
144
  enabled: optionalBoolean(record, "enabled") ?? true,
141
- center,
145
+ ...(center === undefined ? {} : { center }),
142
146
  ...(bounds === undefined ? {} : { bounds }),
143
147
  children
144
148
  };
@@ -0,0 +1,7 @@
1
+ import type { ProcessRunner } from "../../ports/process-runner.js";
2
+ export interface AppiumDoctorResult {
3
+ status: "passed" | "failed";
4
+ version?: string | undefined;
5
+ message?: string | undefined;
6
+ }
7
+ export declare function checkAppiumUiAutomator2(runner: ProcessRunner, signal?: AbortSignal): Promise<AppiumDoctorResult>;
@@ -0,0 +1,128 @@
1
+ function firstLine(value) {
2
+ return value.trim().split(/\r?\n/, 1)[0] ?? "unknown";
3
+ }
4
+ function driverVersion(value) {
5
+ if (value === null || typeof value !== "object")
6
+ return undefined;
7
+ const serialized = JSON.stringify(value);
8
+ const match = serialized.match(/uiautomator2[^\d]*([\d]+(?:\.[\d]+)+(?:[-+][\w.-]+)?)/i);
9
+ return match?.[1];
10
+ }
11
+ export async function checkAppiumUiAutomator2(runner, signal) {
12
+ const command = async (args) => runner.run({
13
+ executable: "appium",
14
+ args,
15
+ timeoutMs: 5000,
16
+ ...(signal === undefined ? {} : { signal })
17
+ });
18
+ const serverStatus = async () => {
19
+ try {
20
+ const response = await fetch("http://127.0.0.1:4723/status", {
21
+ signal: AbortSignal.timeout(5000)
22
+ });
23
+ const payload = await response.json();
24
+ if (!response.ok)
25
+ throw new Error(`HTTP ${String(response.status)}`);
26
+ return {
27
+ ok: true,
28
+ version: typeof payload.value?.build?.version === "string"
29
+ ? payload.value.build.version
30
+ : undefined
31
+ };
32
+ }
33
+ catch (error) {
34
+ return {
35
+ ok: false,
36
+ error: error instanceof Error ? error.message : String(error)
37
+ };
38
+ }
39
+ };
40
+ try {
41
+ const version = await command(["--version"]);
42
+ if (version.exitCode !== 0
43
+ || version.spawnError !== undefined
44
+ || version.timedOut
45
+ || version.cancelled) {
46
+ const server = await serverStatus();
47
+ if (server.ok) {
48
+ return {
49
+ status: "passed",
50
+ message: `UiAutomator2 (verified via running server); server ${server.version ?? "unknown"}; start: appium --address 127.0.0.1 --port 4723`
51
+ };
52
+ }
53
+ return {
54
+ status: "failed",
55
+ message: version.stderr.trim() || version.spawnError || "Appium server is unavailable"
56
+ };
57
+ }
58
+ const drivers = await command(["driver", "list", "--installed", "--json"]);
59
+ if (drivers.exitCode !== 0
60
+ || drivers.spawnError !== undefined
61
+ || drivers.timedOut
62
+ || drivers.cancelled) {
63
+ const server = await serverStatus();
64
+ if (server.ok) {
65
+ return {
66
+ status: "passed",
67
+ version: firstLine(version.stdout),
68
+ message: `UiAutomator2 (verified via running server); server ${server.version ?? "unknown"}; start: appium --address 127.0.0.1 --port 4723`
69
+ };
70
+ }
71
+ return {
72
+ status: "failed",
73
+ version: firstLine(version.stdout),
74
+ message: drivers.stderr.trim() || drivers.spawnError
75
+ || "Appium UiAutomator2 driver check failed"
76
+ };
77
+ }
78
+ let installed;
79
+ try {
80
+ installed = JSON.parse(drivers.stdout);
81
+ }
82
+ catch {
83
+ return {
84
+ status: "failed",
85
+ version: firstLine(version.stdout),
86
+ message: "Appium driver list returned invalid JSON"
87
+ };
88
+ }
89
+ const driver = driverVersion(installed);
90
+ if (driver === undefined || !/uiautomator2/i.test(JSON.stringify(installed))) {
91
+ return {
92
+ status: "failed",
93
+ version: firstLine(version.stdout),
94
+ message: "Appium UiAutomator2 driver is not installed"
95
+ };
96
+ }
97
+ let serverVersion;
98
+ try {
99
+ const response = await fetch("http://127.0.0.1:4723/status", {
100
+ signal: AbortSignal.timeout(5000)
101
+ });
102
+ const payload = await response.json();
103
+ if (!response.ok)
104
+ throw new Error(`HTTP ${String(response.status)}`);
105
+ serverVersion = typeof payload.value?.build?.version === "string"
106
+ ? payload.value.build.version
107
+ : undefined;
108
+ }
109
+ catch (error) {
110
+ return {
111
+ status: "failed",
112
+ version: firstLine(version.stdout),
113
+ message: `UiAutomator2 ${driver}; start: appium --address 127.0.0.1 --port 4723 (${error instanceof Error ? error.message : String(error)})`
114
+ };
115
+ }
116
+ return {
117
+ status: "passed",
118
+ version: firstLine(version.stdout),
119
+ message: `UiAutomator2 ${driver}; server ${serverVersion ?? "unknown"}; start: appium --address 127.0.0.1 --port 4723`
120
+ };
121
+ }
122
+ catch (error) {
123
+ return {
124
+ status: "failed",
125
+ message: error instanceof Error ? error.message : String(error)
126
+ };
127
+ }
128
+ }
@@ -0,0 +1,34 @@
1
+ import type { ProcessRunner } from "../../ports/process-runner.js";
2
+ import type { OpenUiSnapshotProviderOptions, UiSnapshotProvider, UiSnapshotProviderFactory } from "../../ports/ui-snapshot.js";
3
+ export interface AppiumHttpRequest {
4
+ method: "GET" | "POST" | "DELETE";
5
+ path: string;
6
+ body?: unknown;
7
+ timeoutMs: number;
8
+ signal?: AbortSignal | undefined;
9
+ }
10
+ export interface AppiumHttpClient {
11
+ request(input: AppiumHttpRequest): Promise<{
12
+ value: unknown;
13
+ }>;
14
+ }
15
+ export interface AppiumProviderOptions {
16
+ endpoint?: string | undefined;
17
+ mapTestTagToResourceId?: boolean | undefined;
18
+ }
19
+ export declare class FetchAppiumHttpClient implements AppiumHttpClient {
20
+ private readonly endpoint;
21
+ constructor(endpoint: URL);
22
+ request(input: AppiumHttpRequest): Promise<{
23
+ value: unknown;
24
+ }>;
25
+ }
26
+ export declare class AppiumUiSnapshotProviderFactory implements UiSnapshotProviderFactory {
27
+ private readonly runner;
28
+ private readonly endpoint;
29
+ private readonly http;
30
+ private readonly settings;
31
+ constructor(runner: ProcessRunner, http?: AppiumHttpClient, options?: AppiumProviderOptions);
32
+ probe(timeoutMs?: number): Promise<boolean>;
33
+ open(options: OpenUiSnapshotProviderOptions): Promise<UiSnapshotProvider>;
34
+ }