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
@@ -2,10 +2,12 @@ import { createHash } from "node:crypto";
2
2
  import { realpath } from "node:fs/promises";
3
3
  import { basename, extname } from "node:path";
4
4
  import { z } from "zod";
5
+ import { UiBackendDescriptorSchema } from "../../domain/ui-backend.js";
5
6
  import { normalizeActivity } from "../../domain/activity.js";
6
7
  import { GenerationMetaSchema, GenerationReportSchema, GenerationSessionSchema } from "../../domain/generation.js";
7
- import { JourneySchema } from "../../domain/journey.js";
8
- import { ProjectContextSchema, ProjectRelativePathSchema } from "../../domain/project-context.js";
8
+ import { DEFAULT_DEVICE_ROLE, JourneySchema } from "../../domain/journey.js";
9
+ import { ResolvedProjectContextSchema } from "../../domain/project-context.js";
10
+ import { JourneyOutputPathSchema } from "../../domain/journey-composition.js";
9
11
  import { hashJourney, TapHoundReportSchema } from "../../domain/report.js";
10
12
  import { TapHoundConfigSchema } from "../../domain/config.js";
11
13
  import { GenerationSessionStoreError } from "../../ports/generation-session-store.js";
@@ -35,7 +37,8 @@ const VerificationReceiptSchema = z.strictObject({
35
37
  projectHash: Sha256Schema,
36
38
  configHash: Sha256Schema,
37
39
  contextHash: Sha256Schema,
38
- snapshotHash: Sha256Schema.nullable()
40
+ snapshotHash: Sha256Schema.nullable(),
41
+ uiBackend: UiBackendDescriptorSchema
39
42
  }),
40
43
  tools: z.record(z.string(), z.string()),
41
44
  report: z.strictObject({
@@ -44,18 +47,19 @@ const VerificationReceiptSchema = z.strictObject({
44
47
  runId: z.string().min(1)
45
48
  })
46
49
  });
47
- export const GenerationOutputPathSchema = ProjectRelativePathSchema.refine((path) => path.split("/").every((segment) => segment.length > 0 && segment !== "."), "Generation output path must be normalized").refine((path) => (path !== ".taphound/generations"
48
- && !path.startsWith(".taphound/generations/")), "Generation output cannot overlap the authoritative bundle");
50
+ export const GenerationOutputPathSchema = JourneyOutputPathSchema;
49
51
  export class GenerationFinalizationError extends Error {
50
52
  code;
51
53
  stage;
52
54
  recoverable;
55
+ details;
53
56
  name = "GenerationFinalizationError";
54
- constructor(code, stage, recoverable, message, options) {
57
+ constructor(code, stage, recoverable, message, options, details) {
55
58
  super(message, options);
56
59
  this.code = code;
57
60
  this.stage = stage;
58
61
  this.recoverable = recoverable;
62
+ this.details = details;
59
63
  }
60
64
  }
61
65
  function serializeJson(value) {
@@ -64,12 +68,6 @@ function serializeJson(value) {
64
68
  function sha256(value) {
65
69
  return createHash("sha256").update(value).digest("hex");
66
70
  }
67
- function commandFailed(result) {
68
- return result.exitCode !== 0
69
- || result.timedOut
70
- || result.cancelled
71
- || result.spawnError !== undefined;
72
- }
73
71
  function derivedJourneyName(outputPath) {
74
72
  const file = basename(outputPath);
75
73
  const extension = extname(file);
@@ -89,13 +87,23 @@ function sameJson(left, right) {
89
87
  function locatorMatchIsEligible(matchedBy, step) {
90
88
  if (step.action !== "click"
91
89
  && step.action !== "longClick"
92
- && step.action !== "swipe") {
90
+ && step.action !== "swipe"
91
+ && step.action !== "bridge") {
93
92
  return matchedBy === undefined;
94
93
  }
95
- return matchedBy !== undefined && step.locator[matchedBy] !== undefined;
94
+ if (matchedBy === undefined) {
95
+ return false;
96
+ }
97
+ const locator = step.action === "bridge"
98
+ ? step.triggerLocator
99
+ : step.locator;
100
+ if (locator === undefined || matchedBy === "anchor") {
101
+ return false;
102
+ }
103
+ return locator[matchedBy] !== undefined;
96
104
  }
97
- function failure(code, stage, message, recoverable = false, cause) {
98
- return new GenerationFinalizationError(code, stage, recoverable, message, cause === undefined ? undefined : { cause });
105
+ function failure(code, stage, message, recoverable = false, cause, details) {
106
+ return new GenerationFinalizationError(code, stage, recoverable, message, cause === undefined ? undefined : { cause }, details);
99
107
  }
100
108
  export class GenerationFinalizer {
101
109
  dependencies;
@@ -104,7 +112,7 @@ export class GenerationFinalizer {
104
112
  }
105
113
  finalize = async (input) => {
106
114
  const config = TapHoundConfigSchema.parse(input.config);
107
- const context = ProjectContextSchema.parse(input.context);
115
+ const context = ResolvedProjectContextSchema.parse(input.context);
108
116
  const project = ProjectDescriptionSchema.parse(input.project);
109
117
  const canonicalProjectRoot = await realpath(input.projectRoot);
110
118
  const outputPath = GenerationOutputPathSchema.parse(input.outputPath);
@@ -114,13 +122,20 @@ export class GenerationFinalizer {
114
122
  let session = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
115
123
  this.assertBindings(session, input, config, context, project);
116
124
  const journey = JourneySchema.parse({
117
- version: 1,
125
+ version: 2,
118
126
  name,
127
+ devices: [{ role: DEFAULT_DEVICE_ROLE }],
119
128
  steps: session.candidateSteps
120
129
  });
130
+ if (input.manualReplay === false
131
+ && journey.steps.some((step) => step.replayMode === "manual")) {
132
+ throw failure("VERIFICATION_FAILED", "verification", "Journey contains manual steps; cannot finalize in non-interactive mode. Re-run finalize from an interactive terminal so manual steps can be replayed with human operation of the external application", false);
133
+ }
121
134
  let replayed = false;
122
135
  let verificationReport;
123
136
  if (session.verification.status === "notRun") {
137
+ this.revalidate(input, config, context, project, session);
138
+ this.dependencies.progress?.("verification");
124
139
  const begun = await this.beginVerification(session);
125
140
  session = begun.session;
126
141
  if (!begun.owned
@@ -136,7 +151,9 @@ export class GenerationFinalizer {
136
151
  let reconciled;
137
152
  try {
138
153
  reconciled = session.verification.status === "running"
139
- ? await this.reconcilePassedVerification(session, expected, () => this.revalidate(input, config, context, project, session))
154
+ ? await this.reconcilePassedVerification(session, expected, () => {
155
+ this.revalidate(input, config, context, project, session);
156
+ })
140
157
  : undefined;
141
158
  }
142
159
  catch (error) {
@@ -154,33 +171,33 @@ export class GenerationFinalizer {
154
171
  }
155
172
  if (begun.owned) {
156
173
  try {
157
- await this.revalidate(input, config, context, project, session);
158
174
  if (input.signal?.aborted === true) {
159
175
  throw failure("VERIFICATION_FAILED", "verification", "Generation finalization was cancelled");
160
176
  }
161
- const stopped = await this.dependencies.adb.forceStop({
162
- packageName: session.target.packageName,
163
- deviceSerial: session.target.deviceSerial,
164
- ...(input.signal === undefined ? {} : { signal: input.signal }),
165
- timeoutMs: config.idle.timeoutMs
166
- });
167
- if (commandFailed(stopped)) {
168
- throw failure("VERIFICATION_FAILED", "verification", stopped.stderr.trim()
169
- || stopped.spawnError
170
- || "Unable to reset the generated Journey process");
171
- }
177
+ const replayProgress = this.bridgeReplayProgress(session.id, expected.attemptId);
178
+ const replayConfig = session.idlePolicy === undefined
179
+ ? config
180
+ : { ...config, idle: session.idlePolicy };
172
181
  const result = await this.dependencies.verifyRuntime.verify({
173
- config,
182
+ config: replayConfig,
174
183
  journey,
175
184
  projectRoot: canonicalProjectRoot,
176
- deviceSerial: input.deviceSerial,
185
+ devices: [{
186
+ role: journey.devices[0]?.role ?? DEFAULT_DEVICE_ROLE,
187
+ deviceSerial: input.deviceSerial
188
+ }],
177
189
  toolVersions: input.toolVersions,
178
190
  requireFocusedInput: true,
179
191
  generatedReplayPolicy: true,
180
- ...(input.signal === undefined ? {} : { signal: input.signal })
192
+ ...(input.manualReplay === undefined
193
+ ? {}
194
+ : { manualReplay: input.manualReplay }),
195
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
196
+ progress: replayProgress.onEvent
181
197
  });
198
+ await replayProgress.settled();
182
199
  replayed = true;
183
- await this.revalidate(input, config, context, project, session);
200
+ this.revalidate(input, config, context, project, session);
184
201
  this.assertEligible(result, journey, expected);
185
202
  verificationReport = TapHoundReportSchema.parse(result.report);
186
203
  session = await this.persistPassedVerification(session, verificationReport, expected);
@@ -189,7 +206,12 @@ export class GenerationFinalizer {
189
206
  if (session.verification.status === "running"
190
207
  && !(error instanceof GenerationFinalizationError
191
208
  && error.code === "FINALIZATION_IN_PROGRESS")) {
192
- await this.persistFailedVerification(session, error);
209
+ const aborted = error instanceof GenerationFinalizationError
210
+ && error.stage === "precondition"
211
+ && await this.tryAbortVerification(session);
212
+ if (!aborted) {
213
+ await this.persistFailedVerification(session, error);
214
+ }
193
215
  }
194
216
  throw error instanceof GenerationFinalizationError
195
217
  ? error
@@ -203,7 +225,9 @@ export class GenerationFinalizer {
203
225
  const expected = this.expectedVerification(session, journey, config, canonicalProjectRoot, input.toolVersions);
204
226
  let reconciled;
205
227
  try {
206
- reconciled = await this.reconcilePassedVerification(session, expected, () => this.revalidate(input, config, context, project, session));
228
+ reconciled = await this.reconcilePassedVerification(session, expected, () => {
229
+ this.revalidate(input, config, context, project, session);
230
+ });
207
231
  }
208
232
  catch (error) {
209
233
  await this.persistFailedVerification(session, error);
@@ -228,7 +252,7 @@ export class GenerationFinalizer {
228
252
  }
229
253
  this.assertReport(verificationReport, journey, this.expectedVerification(session, journey, config, canonicalProjectRoot, input.toolVersions), "RECOVERY_REQUIRED");
230
254
  this.assertBindings(session, input, config, context, project);
231
- const meta = this.buildMeta(session, outputPath, verificationReport);
255
+ const meta = this.buildMeta(session, outputPath, verificationReport, config);
232
256
  const generationReport = GenerationReportSchema.parse({
233
257
  version: 1,
234
258
  generationId: session.id,
@@ -239,6 +263,7 @@ export class GenerationFinalizer {
239
263
  }))
240
264
  });
241
265
  if (session.publication.status === "notRun") {
266
+ this.dependencies.progress?.("publication");
242
267
  try {
243
268
  await this.dependencies.publisher.stage({
244
269
  generationId: session.id,
@@ -287,6 +312,7 @@ export class GenerationFinalizer {
287
312
  }
288
313
  }
289
314
  try {
315
+ this.dependencies.progress?.("export");
290
316
  const exported = await this.dependencies.publisher.export({
291
317
  generationId: session.id,
292
318
  projectRoot: input.projectRoot,
@@ -308,44 +334,75 @@ export class GenerationFinalizer {
308
334
  throw failure("EXPORT_FAILED", "export", "Authoritative bundle was published but Journey export failed", true, error);
309
335
  }
310
336
  };
337
+ bridgeReplayProgress(generationId, attemptId) {
338
+ let pending = Promise.resolve();
339
+ const onEvent = (event) => {
340
+ const phase = event;
341
+ pending = pending
342
+ .then(async () => {
343
+ await this.dependencies.store.updateVerificationPhase(generationId, attemptId, phase);
344
+ this.dependencies.replayProgress?.(phase);
345
+ })
346
+ .catch(() => undefined);
347
+ };
348
+ return {
349
+ onEvent,
350
+ settled: () => pending
351
+ };
352
+ }
311
353
  assertBindings(session, input, config, context, project) {
312
- if (input.projectRoot !== project.projectRoot
313
- || input.deviceSerial !== session.target.deviceSerial
314
- || project.packageName !== session.target.packageName
315
- || session.target.packageName !== config.run.packageName
316
- || normalizeActivity(project.packageName, project.launchActivity) !== normalizeActivity(config.run.packageName, config.run.activity)
317
- || session.inFlight !== null
318
- || session.pendingConfirmation !== null
319
- || session.state !== "active"
320
- || session.bindings.projectHash !== hashGenerationBinding(project)
321
- || session.bindings.configHash !== hashGenerationBinding(config)
322
- || session.bindings.contextHash !== hashGenerationBinding(context)
323
- || JSON.stringify(session.target.interactionPolicy)
324
- !== JSON.stringify(context.interactionPolicy)) {
325
- throw failure("CONTEXT_STALE", "precondition", "Generation identity, context, configuration, or process-only binding changed");
354
+ const hashSummary = (value) => value.slice(0, 8);
355
+ const mismatches = [];
356
+ const compare = (binding, expected, actual) => {
357
+ if (expected !== actual) {
358
+ mismatches.push({ binding, expected, actual });
359
+ }
360
+ };
361
+ compare("projectRoot", input.projectRoot, project.projectRoot);
362
+ compare("deviceSerial", session.target.deviceSerial, input.deviceSerial);
363
+ compare("project.packageName", session.target.packageName, project.packageName);
364
+ compare("config.packageName", session.target.packageName, config.run.packageName);
365
+ compare("launchActivity", normalizeActivity(config.run.packageName, config.run.activity), normalizeActivity(project.packageName, project.launchActivity));
366
+ compare("inFlight", "none", session.inFlight === null ? "none" : "present");
367
+ compare("pendingConfirmation", "none", session.pendingConfirmation === null ? "none" : "present");
368
+ compare("session.state", "active", session.state);
369
+ compare("projectHash", hashSummary(session.bindings.projectHash), hashSummary(hashGenerationBinding(project)));
370
+ compare("configHash", hashSummary(session.bindings.configHash), hashSummary(hashGenerationBinding(config)));
371
+ compare("contextHash", hashSummary(session.bindings.contextHash), hashSummary(hashGenerationBinding(context)));
372
+ compare("contextSelection", hashSummary(hashGenerationBinding(session.contextSelection)), hashSummary(hashGenerationBinding(context.selection)));
373
+ compare("interactionPolicy", hashSummary(hashGenerationBinding(session.target.interactionPolicy)), hashSummary(hashGenerationBinding(context.interactionPolicy)));
374
+ if (mismatches.length > 0) {
375
+ const summary = mismatches.map((entry) => `${entry.binding} expected=${entry.expected} actual=${entry.actual}`).join("; ");
376
+ throw failure("CONTEXT_STALE", "precondition", `Generation binding changed: ${summary}`, false, undefined, { mismatches });
326
377
  }
327
378
  }
328
- async revalidate(input, config, context, project, session) {
379
+ revalidate(input, config, context, project, session) {
380
+ // The session's stored context snapshot is authoritative; the CLI only
381
+ // warns when the live project context has drifted from it.
329
382
  this.assertBindings(session, input, config, context, project);
330
- const result = await this.dependencies.contextValidator.validate({
331
- context,
332
- projectRoot: input.projectRoot,
333
- config
334
- });
335
- if (result.status !== "valid") {
336
- throw failure(result.status === "stale" ? "CONTEXT_STALE" : "CONTEXT_INVALID", "precondition", result.reason.message);
337
- }
338
383
  }
339
384
  async beginVerification(session) {
340
385
  const attemptId = this.dependencies.generateAttemptId();
386
+ const owner = this.dependencies.owner === undefined
387
+ ? undefined
388
+ : {
389
+ pid: this.dependencies.owner.pid,
390
+ startedAt: this.dependencies.owner.now().toISOString()
391
+ };
341
392
  const expected = GenerationSessionSchema.parse({
342
393
  ...session,
343
394
  revision: session.revision + 1,
344
- verification: { status: "running", attemptId }
395
+ verification: {
396
+ status: "running",
397
+ attemptId,
398
+ ...(owner === undefined
399
+ ? {}
400
+ : { ownerPid: owner.pid, startedAt: owner.startedAt })
401
+ }
345
402
  });
346
403
  try {
347
404
  return {
348
- session: await this.dependencies.store.beginVerification(session.id, session.revision, attemptId),
405
+ session: await this.dependencies.store.beginVerification(session.id, session.revision, attemptId, owner),
349
406
  owned: true
350
407
  };
351
408
  }
@@ -390,6 +447,11 @@ export class GenerationFinalizer {
390
447
  this.assertReport(result.report, journey, expected, "VERIFICATION_FAILED");
391
448
  }
392
449
  assertReport(report, journey, expected, code) {
450
+ const reportDevice = report.environment.devices[0];
451
+ const singleDefaultDevice = report.environment.devices.length === 1
452
+ && reportDevice?.role === DEFAULT_DEVICE_ROLE
453
+ && reportDevice.deviceSerial === expected.deviceSerial;
454
+ const reportUiBackend = reportDevice?.uiBackend;
393
455
  if (report.status !== "passed"
394
456
  || report.fallbackUsed
395
457
  || report.primaryFailure !== undefined
@@ -400,7 +462,8 @@ export class GenerationFinalizer {
400
462
  || report.project.root !== expected.project.root
401
463
  || report.project.packageName !== expected.project.packageName
402
464
  || report.project.launchActivity !== expected.project.launchActivity
403
- || report.environment.deviceSerial !== expected.deviceSerial
465
+ || !singleDefaultDevice
466
+ || !sameJson(reportUiBackend, expected.bindings.uiBackend)
404
467
  || !sameJson(canonicalTools(report.environment.tools), expected.tools)
405
468
  || report.steps.length !== journey.steps.length) {
406
469
  throw failure(code, "verification", "Verification report does not match the exact generated replay");
@@ -410,7 +473,8 @@ export class GenerationFinalizer {
410
473
  const expectationType = candidate.expect?.type;
411
474
  const hasLocator = candidate.action === "click"
412
475
  || candidate.action === "longClick"
413
- || candidate.action === "swipe";
476
+ || candidate.action === "swipe"
477
+ || candidate.action === "bridge";
414
478
  const isScrollTo = candidate.action === "scrollTo";
415
479
  if (step === undefined
416
480
  || step.index !== index
@@ -529,8 +593,9 @@ export class GenerationFinalizer {
529
593
  throw new Error("Verification Report run ID does not match receipt");
530
594
  }
531
595
  this.assertReport(report, {
532
- version: 1,
596
+ version: 2,
533
597
  name: expected.journey.name,
598
+ devices: [{ role: DEFAULT_DEVICE_ROLE }],
534
599
  steps: running.candidateSteps
535
600
  }, expected, "VERIFICATION_FAILED");
536
601
  }
@@ -539,12 +604,28 @@ export class GenerationFinalizer {
539
604
  ? error
540
605
  : failure("VERIFICATION_FAILED", "verification", "Immutable verification Report does not match the receipt", false, error);
541
606
  }
542
- await revalidateCurrent();
607
+ revalidateCurrent();
543
608
  return {
544
609
  session: await this.persistPassedVerification(running, report, expected),
545
610
  report
546
611
  };
547
612
  }
613
+ async tryAbortVerification(running) {
614
+ const latest = GenerationSessionSchema.parse(await this.dependencies.store.read(running.id));
615
+ if (running.verification.status !== "running"
616
+ || latest.verification.status !== "running"
617
+ || latest.revision !== running.revision
618
+ || latest.verification.attemptId !== running.verification.attemptId) {
619
+ return false;
620
+ }
621
+ try {
622
+ await this.dependencies.store.abortVerification(latest.id, latest.revision);
623
+ return true;
624
+ }
625
+ catch {
626
+ return false;
627
+ }
628
+ }
548
629
  async persistFailedVerification(running, error) {
549
630
  const latest = GenerationSessionSchema.parse(await this.dependencies.store.read(running.id));
550
631
  if (running.verification.status !== "running"
@@ -603,13 +684,14 @@ export class GenerationFinalizer {
603
684
  throw failure("RECOVERY_REQUIRED", "verification", "Immutable verification report is not a clean passed replay");
604
685
  }
605
686
  this.assertReport(report, {
606
- version: 1,
687
+ version: 2,
607
688
  name: expected.journey.name,
689
+ devices: [{ role: DEFAULT_DEVICE_ROLE }],
608
690
  steps: session.candidateSteps
609
691
  }, expected, "RECOVERY_REQUIRED");
610
692
  return report;
611
693
  }
612
- buildMeta(session, outputPath, report) {
694
+ buildMeta(session, outputPath, report, config) {
613
695
  if (session.verification.status !== "passed") {
614
696
  throw failure("RECOVERY_REQUIRED", "verification", "Generation verification is not durably passed");
615
697
  }
@@ -618,17 +700,32 @@ export class GenerationFinalizer {
618
700
  status: "verified",
619
701
  generationId: session.id,
620
702
  journeyPath: outputPath,
703
+ journeySha256: report.journey.sha256,
621
704
  bindings: {
622
705
  projectHash: session.bindings.projectHash,
623
706
  configHash: session.bindings.configHash,
624
- contextHash: session.bindings.contextHash
707
+ contextHash: session.bindings.contextHash,
708
+ uiBackend: session.bindings.uiBackend
709
+ },
710
+ replayPolicy: {
711
+ generatedReplayPolicy: true,
712
+ requireFocusedInput: true,
713
+ idle: session.idlePolicy ?? config.idle
625
714
  },
715
+ contextSelection: session.contextSelection,
626
716
  verification: {
627
717
  reportPath: GENERATION_BUNDLE_PATHS.verificationReport,
628
718
  reportSha256: session.verification.reportSha256,
629
719
  runId: report.runId,
630
720
  runs: 1
631
721
  },
722
+ ...(session.baseFlow === undefined
723
+ ? {}
724
+ : { baseFlow: session.baseFlow }),
725
+ ...(session.sourceBrief === undefined
726
+ ? {}
727
+ : { sourceBrief: session.sourceBrief }),
728
+ externalFlows: session.externalFlows,
632
729
  manualOverrideStepIndexes: session.candidateSources.flatMap((source, index) => source === "manualOverride" ? [index] : [])
633
730
  });
634
731
  }
@@ -2,7 +2,8 @@ import { createHash } from "node:crypto";
2
2
  import { extname, resolve } from "node:path";
3
3
  import { GenerationBundleManifestSchema, GenerationMetaSchema, GenerationReportSchema } from "../../domain/generation.js";
4
4
  import { JourneySchema } from "../../domain/journey.js";
5
- import { TapHoundReportSchema } from "../../domain/report.js";
5
+ import { hashJourney, TapHoundReportSchema } from "../../domain/report.js";
6
+ import { BUILD_DIR } from "../../domain/workspace.js";
6
7
  import { GenerationSessionStoreError } from "../../ports/generation-session-store.js";
7
8
  export const GENERATION_BUNDLE_PATHS = {
8
9
  candidateJourney: "candidate/journey.json",
@@ -59,7 +60,9 @@ export class GenerationPublisher {
59
60
  const meta = GenerationMetaSchema.parse(input.meta);
60
61
  if (input.generationId !== report.generationId
61
62
  || input.generationId !== meta.generationId
62
- || report.steps.length !== journey.steps.length) {
63
+ || report.steps.length !== journey.steps.length
64
+ || meta.journeySha256 !== verificationReport.journey.sha256
65
+ || meta.journeySha256 !== hashJourney(journey)) {
63
66
  throw new Error("Generation bundle identities do not align");
64
67
  }
65
68
  const journeyBytes = serializeJson(journey);
@@ -97,12 +100,13 @@ export class GenerationPublisher {
97
100
  export = async (input) => {
98
101
  const journey = JourneySchema.parse(input.journey);
99
102
  const meta = GenerationMetaSchema.parse(input.meta);
100
- const journeyPath = resolve(input.projectRoot, input.journeyPath);
103
+ const exportRoot = input.projectRoot;
104
+ const journeyPath = resolve(exportRoot, input.journeyPath);
101
105
  const metaPath = generationMetaOutputPath(journeyPath);
102
- const authorityRoot = resolve(input.projectRoot, ".taphound");
106
+ const authorityRoot = resolve(exportRoot, BUILD_DIR);
103
107
  try {
104
108
  await this.dependencies.journeyWriter.writeProjectBound({
105
- projectRoot: input.projectRoot,
109
+ projectRoot: exportRoot,
106
110
  authorityRoot,
107
111
  outputPath: journeyPath,
108
112
  journey
@@ -110,7 +114,7 @@ export class GenerationPublisher {
110
114
  const expectedJourney = Buffer.from(serializeJson(journey));
111
115
  const actualJourney = await this.dependencies.journeyWriter
112
116
  .readProjectBound({
113
- projectRoot: input.projectRoot,
117
+ projectRoot: exportRoot,
114
118
  authorityRoot,
115
119
  outputPath: journeyPath
116
120
  });
@@ -125,14 +129,14 @@ export class GenerationPublisher {
125
129
  }
126
130
  try {
127
131
  await this.dependencies.metaWriter.writeProjectBound({
128
- projectRoot: input.projectRoot,
132
+ projectRoot: exportRoot,
129
133
  authorityRoot,
130
134
  outputPath: metaPath,
131
135
  meta
132
136
  });
133
137
  const expectedMeta = Buffer.from(serializeJson(meta));
134
138
  const actualMeta = await this.dependencies.metaWriter.readProjectBound({
135
- projectRoot: input.projectRoot,
139
+ projectRoot: exportRoot,
136
140
  authorityRoot,
137
141
  outputPath: metaPath
138
142
  });
@@ -0,0 +1,35 @@
1
+ import { type GenerationSession } from "../../domain/generation.js";
2
+ import { type GenerationSessionStore } from "../../ports/generation-session-store.js";
3
+ export interface GenerationRecoveryStatus {
4
+ generationId: string;
5
+ revision: number;
6
+ state: GenerationSession["state"];
7
+ candidateStepCount: number;
8
+ idlePolicy?: GenerationSession["idlePolicy"];
9
+ inFlight: GenerationSession["inFlight"];
10
+ pendingConfirmation: (NonNullable<GenerationSession["pendingConfirmation"]> & {
11
+ expired: boolean;
12
+ }) | null;
13
+ verification: GenerationSession["verification"];
14
+ publication: GenerationSession["publication"];
15
+ recovery: {
16
+ available: boolean;
17
+ kind: "step" | "verification" | null;
18
+ actionMayHaveExecuted: boolean;
19
+ attemptOutcome: "succeeded" | "failed" | "cancelled" | "unknown" | null;
20
+ requiredDecision: "retry" | null;
21
+ ownerAlive: boolean | null;
22
+ };
23
+ }
24
+ export interface GenerationRecoveryDependencies {
25
+ store: Pick<GenerationSessionStore, "read" | "readEvidence" | "recover" | "recoverVerification">;
26
+ ownerAlive?: ((pid: number) => boolean) | undefined;
27
+ now: () => Date;
28
+ }
29
+ export declare class GenerationRecoveryService {
30
+ private readonly dependencies;
31
+ constructor(dependencies: GenerationRecoveryDependencies);
32
+ readonly status: (generationId: string) => Promise<GenerationRecoveryStatus>;
33
+ readonly retry: (generationId: string) => Promise<GenerationSession>;
34
+ private evidenceExists;
35
+ }