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
@@ -0,0 +1,144 @@
1
+ import { z } from "zod";
2
+ import { GenerationSessionSchema, isGenerationConfirmationExpired } from "../../domain/generation.js";
3
+ import { GenerationSessionStoreError } from "../../ports/generation-session-store.js";
4
+ import { GenerationOperationError } from "./generation-starter.js";
5
+ const AttemptOutcomeSchema = z.looseObject({
6
+ status: z.enum(["succeeded", "failed", "cancelled"])
7
+ });
8
+ function resultPath(session) {
9
+ const inFlight = session.inFlight;
10
+ return inFlight === null
11
+ ? undefined
12
+ : `evidence/steps/${String(inFlight.stepIndex)}-${inFlight.attemptId}/result.json`;
13
+ }
14
+ export class GenerationRecoveryService {
15
+ dependencies;
16
+ constructor(dependencies) {
17
+ this.dependencies = dependencies;
18
+ }
19
+ status = async (generationId) => {
20
+ const session = GenerationSessionSchema.parse(await this.dependencies.store.read(generationId));
21
+ const path = resultPath(session);
22
+ let attemptOutcome = null;
23
+ if (path !== undefined) {
24
+ try {
25
+ const bytes = await this.dependencies.store.readEvidence(session.id, path);
26
+ const parsed = z.looseObject({
27
+ outcome: AttemptOutcomeSchema
28
+ }).parse(JSON.parse(bytes.toString("utf8")));
29
+ attemptOutcome = parsed.outcome.status;
30
+ }
31
+ catch (error) {
32
+ if (error instanceof GenerationSessionStoreError
33
+ && error.code === "EVIDENCE_NOT_FOUND") {
34
+ attemptOutcome = "unknown";
35
+ }
36
+ else if (error instanceof SyntaxError || error instanceof z.ZodError) {
37
+ attemptOutcome = "unknown";
38
+ }
39
+ else {
40
+ throw error;
41
+ }
42
+ }
43
+ }
44
+ const stepAvailable = session.state === "recoveryRequired"
45
+ && session.inFlight !== null
46
+ && session.verification.status === "notRun"
47
+ && session.publication.status === "notRun";
48
+ const verificationMayRecover = session.state === "active"
49
+ && session.inFlight === null
50
+ && session.verification.status === "running"
51
+ && session.publication.status === "notRun";
52
+ const [hasReceipt, hasReport] = verificationMayRecover
53
+ ? await Promise.all([
54
+ this.evidenceExists(session.id, "verification/receipt.json"),
55
+ this.evidenceExists(session.id, "verification/report.json")
56
+ ])
57
+ : [false, false];
58
+ const verificationOwnerAlive = session.verification.status === "running"
59
+ && session.verification.ownerPid !== undefined
60
+ ? (this.dependencies.ownerAlive?.(session.verification.ownerPid) ?? null)
61
+ : null;
62
+ const verificationAvailable = verificationMayRecover
63
+ && verificationOwnerAlive !== true
64
+ && !hasReceipt
65
+ && !hasReport;
66
+ const available = stepAvailable || verificationAvailable;
67
+ return {
68
+ generationId: session.id,
69
+ revision: session.revision,
70
+ state: session.state,
71
+ candidateStepCount: session.candidateSteps.length,
72
+ ...(session.idlePolicy === undefined
73
+ ? {}
74
+ : { idlePolicy: session.idlePolicy }),
75
+ inFlight: session.inFlight,
76
+ pendingConfirmation: session.pendingConfirmation === null
77
+ ? null
78
+ : {
79
+ ...session.pendingConfirmation,
80
+ expired: isGenerationConfirmationExpired(session.pendingConfirmation, this.dependencies.now())
81
+ },
82
+ verification: session.verification,
83
+ publication: session.publication,
84
+ recovery: {
85
+ available,
86
+ kind: stepAvailable
87
+ ? "step"
88
+ : verificationAvailable ? "verification" : null,
89
+ actionMayHaveExecuted: session.inFlight !== null
90
+ || session.verification.status === "running",
91
+ attemptOutcome,
92
+ requiredDecision: available ? "retry" : null,
93
+ ownerAlive: verificationOwnerAlive
94
+ }
95
+ };
96
+ };
97
+ retry = async (generationId) => {
98
+ const session = GenerationSessionSchema.parse(await this.dependencies.store.read(generationId));
99
+ if (session.state === "recoveryRequired"
100
+ && session.inFlight !== null
101
+ && session.verification.status === "notRun"
102
+ && session.publication.status === "notRun") {
103
+ const next = GenerationSessionSchema.parse({
104
+ ...session,
105
+ revision: session.revision + 1,
106
+ state: "active",
107
+ inFlight: null
108
+ });
109
+ await this.dependencies.store.recover(session.id, session.revision, next);
110
+ return next;
111
+ }
112
+ if (session.state === "active"
113
+ && session.inFlight === null
114
+ && session.verification.status === "running"
115
+ && session.publication.status === "notRun"
116
+ && (session.verification.ownerPid === undefined
117
+ || this.dependencies.ownerAlive?.(session.verification.ownerPid)
118
+ !== true)
119
+ && !await this.evidenceExists(session.id, "verification/receipt.json")
120
+ && !await this.evidenceExists(session.id, "verification/report.json")) {
121
+ const next = GenerationSessionSchema.parse({
122
+ ...session,
123
+ revision: session.revision + 1,
124
+ verification: { status: "notRun" }
125
+ });
126
+ await this.dependencies.store.recoverVerification(session.id, session.revision, next);
127
+ return next;
128
+ }
129
+ throw new GenerationOperationError("RECOVERY_REQUIRED", "Session recovery is unavailable or immutable verification evidence already exists");
130
+ };
131
+ async evidenceExists(generationId, path) {
132
+ try {
133
+ await this.dependencies.store.readEvidence(generationId, path);
134
+ return true;
135
+ }
136
+ catch (error) {
137
+ if (error instanceof GenerationSessionStoreError
138
+ && error.code === "EVIDENCE_NOT_FOUND") {
139
+ return false;
140
+ }
141
+ throw error;
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,15 @@
1
+ import { type GenerationSession } from "../../domain/generation.js";
2
+ import type { GenerationSessionStore } from "../../ports/generation-session-store.js";
3
+ export interface GenerationReopenInput {
4
+ generationId: string;
5
+ reason: string;
6
+ }
7
+ export interface GenerationReopenDependencies {
8
+ store: Pick<GenerationSessionStore, "read" | "reopenVerification">;
9
+ now: () => Date;
10
+ }
11
+ export declare class GenerationReopenService {
12
+ private readonly dependencies;
13
+ constructor(dependencies: GenerationReopenDependencies);
14
+ readonly reopen: (input: GenerationReopenInput) => Promise<GenerationSession>;
15
+ }
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { GenerationSessionSchema } from "../../domain/generation.js";
3
+ import { GenerationOperationError } from "./generation-starter.js";
4
+ const ReopenReasonSchema = z.string().trim().min(1).max(500);
5
+ export class GenerationReopenService {
6
+ dependencies;
7
+ constructor(dependencies) {
8
+ this.dependencies = dependencies;
9
+ }
10
+ reopen = async (input) => {
11
+ const reason = ReopenReasonSchema.parse(input.reason);
12
+ const current = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
13
+ if (current.state !== "active"
14
+ || current.inFlight !== null
15
+ || current.pendingConfirmation !== null
16
+ || current.verification.status !== "failed"
17
+ || current.publication.status !== "notRun") {
18
+ throw new GenerationOperationError("CONFIG_INVALID", "Only an idle active session with failed verification and no publication can be reopened");
19
+ }
20
+ const next = GenerationSessionSchema.parse({
21
+ ...current,
22
+ revision: current.revision + 1,
23
+ verification: { status: "notRun" },
24
+ verificationHistory: [
25
+ ...current.verificationHistory,
26
+ {
27
+ failedRevision: current.revision,
28
+ reopenedAt: this.dependencies.now().toISOString(),
29
+ reason,
30
+ failure: current.verification.failure
31
+ }
32
+ ]
33
+ });
34
+ await this.dependencies.store.reopenVerification(current.id, current.revision, next);
35
+ return next;
36
+ };
37
+ }
@@ -0,0 +1,32 @@
1
+ import type { TapHoundConfig } from "../../domain/config.js";
2
+ import type { GenerationSessionStore } from "../../ports/generation-session-store.js";
3
+ import type { RuntimeObservation, RuntimeObserver } from "./runtime-observer.js";
4
+ import type { VerifyRuntime } from "../runtime/verify-runtime.js";
5
+ import type { GenerationAppPreparer } from "./generation-app-preparer.js";
6
+ export interface GenerationReplaceInput {
7
+ generationId: string;
8
+ stepIndex: number;
9
+ projectRoot: string;
10
+ config: TapHoundConfig;
11
+ toolVersions: Record<string, string>;
12
+ manualReplay?: boolean | undefined;
13
+ signal?: AbortSignal | undefined;
14
+ }
15
+ export interface GenerationReplaceResult {
16
+ status: "replaced";
17
+ stepIndex: number;
18
+ remainingStepCount: number;
19
+ truncatedStepCount: number;
20
+ observation: RuntimeObservation;
21
+ }
22
+ export interface GenerationReplaceDependencies {
23
+ store: Pick<GenerationSessionStore, "read" | "update">;
24
+ observer: Pick<RuntimeObserver, "observe">;
25
+ verifyRuntime: Pick<VerifyRuntime, "verify">;
26
+ appPreparer: Pick<GenerationAppPreparer, "prepare">;
27
+ }
28
+ export declare class GenerationReplaceService {
29
+ private readonly dependencies;
30
+ constructor(dependencies: GenerationReplaceDependencies);
31
+ readonly replace: (input: GenerationReplaceInput) => Promise<GenerationReplaceResult>;
32
+ }
@@ -0,0 +1,116 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { GenerationSessionSchema } from "../../domain/generation.js";
3
+ import { DEFAULT_DEVICE_ROLE, JourneySchema } from "../../domain/journey.js";
4
+ import { GenerationOperationError } from "./generation-starter.js";
5
+ function assertReplaceable(session) {
6
+ if (session.state === "recoveryRequired") {
7
+ throw new GenerationOperationError("RECOVERY_REQUIRED", "Generation session must be recovered before replacing steps");
8
+ }
9
+ if (session.state !== "active") {
10
+ throw new GenerationOperationError("CONFIG_INVALID", `Generation steps can only be replaced on an active session (state: ${session.state})`);
11
+ }
12
+ if (session.inFlight !== null) {
13
+ throw new GenerationOperationError("RECOVERY_REQUIRED", "Generation steps cannot be replaced while a step is in flight");
14
+ }
15
+ if (session.pendingConfirmation !== null) {
16
+ throw new GenerationOperationError("RISK_CONFIRMATION_REQUIRED", `Generation confirmation ${session.pendingConfirmation.challengeId} must be resolved before replacing steps`);
17
+ }
18
+ if (session.verification.status !== "notRun") {
19
+ throw new GenerationOperationError("CONFIG_INVALID", "Generation steps cannot be replaced once verification has started");
20
+ }
21
+ if (session.publication.status !== "notRun") {
22
+ throw new GenerationOperationError("CONFIG_INVALID", "Generation steps cannot be replaced after publication");
23
+ }
24
+ }
25
+ function assertReplaceIndex(session, stepIndex) {
26
+ if (!Number.isInteger(stepIndex)
27
+ || stepIndex < 0
28
+ || stepIndex > session.candidateSteps.length) {
29
+ throw new GenerationOperationError("CONFIG_INVALID", `Replace step index must be between 0 and the candidate step count (${String(session.candidateSteps.length)})`);
30
+ }
31
+ const flowStepCount = session.candidateSources.filter((source) => source === "flow").length;
32
+ if (stepIndex < flowStepCount) {
33
+ throw new GenerationOperationError("FLOW_INVALID", "Replace step index cannot target the bound Base Flow prefix; start a new session with a different Flow");
34
+ }
35
+ }
36
+ export class GenerationReplaceService {
37
+ dependencies;
38
+ constructor(dependencies) {
39
+ this.dependencies = dependencies;
40
+ }
41
+ replace = async (input) => {
42
+ const session = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
43
+ assertReplaceable(session);
44
+ assertReplaceIndex(session, input.stepIndex);
45
+ const replayConfig = session.idlePolicy === undefined
46
+ ? input.config
47
+ : { ...input.config, idle: session.idlePolicy };
48
+ const prefixSteps = session.candidateSteps.slice(0, input.stepIndex);
49
+ if (prefixSteps.length === 0) {
50
+ try {
51
+ await this.dependencies.appPreparer.prepare({
52
+ config: replayConfig,
53
+ deviceSerial: session.target.deviceSerial,
54
+ ...(input.signal === undefined ? {} : { signal: input.signal })
55
+ });
56
+ }
57
+ catch (error) {
58
+ throw new GenerationOperationError("APP_LAUNCH_FAILED", error instanceof Error ? error.message : String(error));
59
+ }
60
+ }
61
+ else {
62
+ const canonicalProjectRoot = await realpath(input.projectRoot);
63
+ const journey = JourneySchema.parse({
64
+ version: 2,
65
+ name: `generation-${session.id}-prefix-${String(input.stepIndex)}`,
66
+ devices: [{ role: DEFAULT_DEVICE_ROLE }],
67
+ steps: prefixSteps
68
+ });
69
+ const result = await this.dependencies.verifyRuntime.verify({
70
+ config: replayConfig,
71
+ journey,
72
+ projectRoot: canonicalProjectRoot,
73
+ devices: [{
74
+ role: DEFAULT_DEVICE_ROLE,
75
+ deviceSerial: session.target.deviceSerial
76
+ }],
77
+ toolVersions: input.toolVersions,
78
+ requireFocusedInput: true,
79
+ generatedReplayPolicy: true,
80
+ ...(input.manualReplay === undefined
81
+ ? {}
82
+ : { manualReplay: input.manualReplay }),
83
+ ...(input.signal === undefined ? {} : { signal: input.signal })
84
+ });
85
+ if (result.status !== "passed" || result.exitCode !== 0) {
86
+ const failure = result.report.primaryFailure;
87
+ throw new GenerationOperationError("VERIFICATION_FAILED", `Prefix replay failed before step replacement${failure === undefined
88
+ ? ""
89
+ : ` (${failure.stepIndex === undefined
90
+ ? ""
91
+ : `step ${String(failure.stepIndex)}: `}${failure.code} - ${failure.message})`}; see ${result.reportPath}`);
92
+ }
93
+ }
94
+ if (input.stepIndex < session.candidateSteps.length) {
95
+ const truncated = GenerationSessionSchema.parse({
96
+ ...session,
97
+ revision: session.revision + 1,
98
+ candidateSteps: prefixSteps,
99
+ candidateSources: session.candidateSources.slice(0, input.stepIndex)
100
+ });
101
+ await this.dependencies.store.update(session.id, session.revision, truncated);
102
+ }
103
+ const observation = await this.dependencies.observer.observe({
104
+ generationId: session.id,
105
+ idle: input.config.idle,
106
+ ...(input.signal === undefined ? {} : { signal: input.signal })
107
+ });
108
+ return {
109
+ status: "replaced",
110
+ stepIndex: input.stepIndex,
111
+ remainingStepCount: prefixSteps.length,
112
+ truncatedStepCount: session.candidateSteps.length - input.stepIndex,
113
+ observation
114
+ };
115
+ };
116
+ }
@@ -1,29 +1,69 @@
1
1
  import type { ContextValidator } from "../context/context-validator.js";
2
2
  import type { ProjectDescription } from "../project/project-describer.js";
3
3
  import { type GenerationErrorCode, type GenerationSession } from "../../domain/generation.js";
4
- import { type ProjectContext } from "../../domain/project-context.js";
4
+ import { type ResolvedProjectContext } from "../../domain/project-context.js";
5
5
  import { type TapHoundConfig } from "../../domain/config.js";
6
6
  import type { GenerationSessionStore } from "../../ports/generation-session-store.js";
7
+ import { type Journey } from "../../domain/journey.js";
8
+ import { type TapHoundReport } from "../../domain/report.js";
9
+ import type { GenerationAppPreparer } from "./generation-app-preparer.js";
10
+ import type { UiSnapshotProviderFactory } from "../../ports/ui-snapshot.js";
11
+ export interface GenerationRecoveryDetails {
12
+ diagnostics: readonly {
13
+ code: string;
14
+ message: string;
15
+ }[];
16
+ recovery: readonly string[];
17
+ }
7
18
  export declare class GenerationOperationError extends Error {
8
19
  readonly code: GenerationErrorCode;
20
+ readonly details?: unknown | undefined;
9
21
  readonly name = "GenerationOperationError";
10
- constructor(code: GenerationErrorCode, message: string);
22
+ constructor(code: GenerationErrorCode, message: string, details?: unknown | undefined);
23
+ }
24
+ export interface GenerationExternalFlowInput {
25
+ name: string;
26
+ flowSha256: string;
27
+ escapedPackageName: string;
28
+ stepCount: number;
11
29
  }
12
30
  export interface GenerationStartInput {
13
31
  projectRoot: string;
14
32
  config: TapHoundConfig;
15
- context: ProjectContext;
33
+ context: ResolvedProjectContext;
16
34
  project: ProjectDescription;
17
35
  deviceSerial: string;
36
+ signal?: AbortSignal | undefined;
37
+ allowEvidenceDrift?: boolean | undefined;
38
+ baseFlow?: {
39
+ name: string;
40
+ resolutionSha256: string;
41
+ journey: Journey;
42
+ verificationReport: TapHoundReport;
43
+ verificationReportPath: string;
44
+ } | undefined;
45
+ externalFlows?: readonly GenerationExternalFlowInput[] | undefined;
46
+ sourceBrief?: {
47
+ path: string;
48
+ sha256: string;
49
+ } | undefined;
18
50
  }
19
51
  export interface GenerationStarterDependencies {
20
52
  contextValidator: Pick<ContextValidator, "validate">;
21
- store: Pick<GenerationSessionStore, "create">;
53
+ appPreparer: Pick<GenerationAppPreparer, "prepare">;
54
+ uiSnapshots: UiSnapshotProviderFactory;
55
+ store: Pick<GenerationSessionStore, "create" | "writeEvidence">;
22
56
  now: () => Date;
23
57
  generateId: () => string;
24
58
  randomBytes: (size: number) => Uint8Array;
25
59
  }
26
60
  export declare function hashGenerationBinding(value: unknown): string;
61
+ export declare function flowReplayFailureDetails(input: {
62
+ flowName: string;
63
+ reportPath: string;
64
+ journey: Journey;
65
+ report: TapHoundReport;
66
+ }): unknown;
27
67
  export declare class GenerationStarter {
28
68
  private readonly dependencies;
29
69
  constructor(dependencies: GenerationStarterDependencies);
@@ -1,13 +1,22 @@
1
1
  import { createHash } from "node:crypto";
2
- import { GenerationSessionSchema } from "../../domain/generation.js";
3
- import { ProjectContextSchema } from "../../domain/project-context.js";
2
+ import { GenerationSessionSchema, GenerationExternalFlowBindingSchema, GenerationSourceBriefSchema } from "../../domain/generation.js";
3
+ import { ResolvedProjectContextSchema } from "../../domain/project-context.js";
4
4
  import { TapHoundConfigSchema } from "../../domain/config.js";
5
+ import { JourneySchema } from "../../domain/journey.js";
6
+ import { normalizeActivity } from "../../domain/activity.js";
7
+ import { GENERATION_CONTEXT_SNAPSHOT_PATH } from "../../domain/workspace.js";
8
+ import { FlowNameSchema } from "../../domain/journey-composition.js";
9
+ import { TapHoundReportSchema, hashJourney } from "../../domain/report.js";
10
+ import { isRuntimeCapabilityError } from "../../ports/runtime-capability.js";
11
+ import { closeUiSnapshotProvider } from "../ui/ui-snapshot-lifecycle.js";
5
12
  export class GenerationOperationError extends Error {
6
13
  code;
14
+ details;
7
15
  name = "GenerationOperationError";
8
- constructor(code, message) {
16
+ constructor(code, message, details) {
9
17
  super(message);
10
18
  this.code = code;
19
+ this.details = details;
11
20
  }
12
21
  }
13
22
  function canonicalize(value) {
@@ -30,6 +39,57 @@ export function hashGenerationBinding(value) {
30
39
  function randomHex(bytes) {
31
40
  return Buffer.from(bytes).toString("hex");
32
41
  }
42
+ function failedFlowStepSummary(step, stepIndex) {
43
+ if (step === undefined || stepIndex === undefined) {
44
+ return null;
45
+ }
46
+ return {
47
+ stepIndex,
48
+ action: step.action,
49
+ activity: step.activity,
50
+ ...("locator" in step ? { locator: step.locator } : {}),
51
+ ...(step.expect === undefined ? {} : { expectation: step.expect })
52
+ };
53
+ }
54
+ export function flowReplayFailureDetails(input) {
55
+ const primaryFailure = input.report.primaryFailure;
56
+ const stepIndex = primaryFailure?.stepIndex;
57
+ const relatedStepIndex = stepIndex
58
+ ?? (primaryFailure?.phase === "readiness" ? 0 : undefined);
59
+ const stepReport = relatedStepIndex === undefined
60
+ ? undefined
61
+ : input.report.steps[relatedStepIndex];
62
+ return {
63
+ flowName: input.flowName,
64
+ reportPath: input.reportPath,
65
+ primaryFailure: primaryFailure === undefined
66
+ ? null
67
+ : {
68
+ code: primaryFailure.code,
69
+ phase: primaryFailure.phase,
70
+ stepIndex: stepIndex ?? null,
71
+ message: primaryFailure.message
72
+ },
73
+ failedStep: failedFlowStepSummary(relatedStepIndex === undefined
74
+ ? undefined
75
+ : input.journey.steps[relatedStepIndex], relatedStepIndex),
76
+ // The device state at the moment of failure, so an environment blocker
77
+ // (lock screen, permission dialog) is distinguishable from a genuine
78
+ // regression without re-dumping the UI hierarchy.
79
+ actualActivity: stepReport?.activity === undefined
80
+ ? null
81
+ : {
82
+ before: stepReport.activity.before.actual ?? null,
83
+ after: stepReport.activity.after.actual ?? null
84
+ },
85
+ recovery: [
86
+ "Check that the first Flow step starts from a stable Activity deterministically reached after cold launch.",
87
+ "Replace a transient Splash transition with a Home readiness anchor such as wait: Home -> Home plus an expectation for a unique Home element.",
88
+ "Repair or re-record the Flow, then retry generation start.",
89
+ "Omit --base-flow only when the user explicitly chooses to bypass reuse."
90
+ ]
91
+ };
92
+ }
33
93
  function distinctId(generationId, generateId) {
34
94
  for (let attempt = 0; attempt < 32; attempt += 1) {
35
95
  const candidate = generateId();
@@ -57,14 +117,114 @@ export class GenerationStarter {
57
117
  projectRoot: input.projectRoot,
58
118
  config
59
119
  });
60
- if (validation.status !== "valid") {
120
+ if (validation.status !== "valid"
121
+ && !(validation.status === "stale" && input.allowEvidenceDrift === true)) {
61
122
  throw new GenerationOperationError(validation.status === "stale" ? "CONTEXT_STALE" : "CONTEXT_INVALID", validation.reason.message);
62
123
  }
63
- const context = ProjectContextSchema.parse(input.context);
124
+ const context = ResolvedProjectContextSchema.parse(input.context);
64
125
  if (context.packageName !== input.project.packageName
65
126
  || context.launchActivity !== input.project.launchActivity) {
66
127
  throw new GenerationOperationError("CONTEXT_INVALID", "Context package and launch identity do not match the project");
67
128
  }
129
+ const baseFlow = input.baseFlow === undefined
130
+ ? undefined
131
+ : (() => {
132
+ const journey = JourneySchema.parse(input.baseFlow.journey);
133
+ const report = TapHoundReportSchema.parse(input.baseFlow.verificationReport);
134
+ const journeySha256 = hashJourney(journey);
135
+ if (report.status !== "passed"
136
+ || report.primaryFailure !== undefined
137
+ || report.secondaryErrors.length !== 0
138
+ || report.fallbackUsed
139
+ || Object.values(report.layers).some((status) => status !== "passed")
140
+ || report.journey.name !== journey.name
141
+ || report.journey.sha256 !== journeySha256
142
+ || report.steps.length !== journey.steps.length
143
+ || report.project.root !== input.projectRoot
144
+ || report.project.packageName !== config.run.packageName
145
+ || report.project.launchActivity !== normalizeActivity(config.run.packageName, config.run.activity)
146
+ || report.environment.devices.length !== 1
147
+ || report.environment.devices[0]?.deviceSerial !== input.deviceSerial
148
+ || journey.steps.some((step, index) => {
149
+ const result = report.steps[index];
150
+ const expectationType = step.expect?.type;
151
+ const requiresLocator = step.action === "click"
152
+ || step.action === "longClick"
153
+ || step.action === "swipe";
154
+ return result === undefined
155
+ || result.index !== index
156
+ || result.action !== step.action
157
+ || result.status !== "passed"
158
+ || result.activity?.before.status !== "passed"
159
+ || result.activity.before.expected !== step.activity.before
160
+ || result.activity.before.actual !== step.activity.before
161
+ || result.activity.after.status !== "passed"
162
+ || result.activity.after.expected !== step.activity.after
163
+ || result.activity.after.actual !== step.activity.after
164
+ || (expectationType === undefined
165
+ ? result.expectation !== undefined
166
+ : (result.expectation?.type !== expectationType
167
+ || result.expectation.status !== "passed"))
168
+ || (requiresLocator
169
+ ? (result.locator?.status !== "found"
170
+ || result.locator.fallbackUsed)
171
+ : result.locator !== undefined)
172
+ || result.locator?.fallbackUsed === true;
173
+ })) {
174
+ throw new GenerationOperationError("FLOW_REPLAY_FAILED", "Base Flow requires a clean exact replay before generation", flowReplayFailureDetails({
175
+ flowName: input.baseFlow.name,
176
+ reportPath: input.baseFlow.verificationReportPath,
177
+ journey,
178
+ report
179
+ }));
180
+ }
181
+ return {
182
+ journey,
183
+ binding: {
184
+ name: FlowNameSchema.parse(input.baseFlow.name),
185
+ resolutionSha256: input.baseFlow.resolutionSha256,
186
+ journeySha256,
187
+ verificationReportSha256: hashGenerationBinding(report),
188
+ verificationRunId: report.runId,
189
+ stepCount: journey.steps.length
190
+ }
191
+ };
192
+ })();
193
+ if (baseFlow === undefined) {
194
+ try {
195
+ await this.dependencies.appPreparer.prepare({
196
+ config,
197
+ deviceSerial: input.deviceSerial,
198
+ ...(input.signal === undefined ? {} : { signal: input.signal })
199
+ });
200
+ }
201
+ catch (error) {
202
+ if (isRuntimeCapabilityError(error)) {
203
+ throw error;
204
+ }
205
+ throw new GenerationOperationError("APP_LAUNCH_FAILED", error instanceof Error ? error.message : String(error));
206
+ }
207
+ }
208
+ const externalFlowBindings = input.externalFlows === undefined
209
+ ? []
210
+ : input.externalFlows.map((entry) => GenerationExternalFlowBindingSchema.parse({
211
+ name: FlowNameSchema.parse(entry.name),
212
+ flowSha256: entry.flowSha256,
213
+ escapedPackageName: entry.escapedPackageName,
214
+ stepCount: entry.stepCount
215
+ }));
216
+ const sourceBrief = input.sourceBrief === undefined
217
+ ? undefined
218
+ : GenerationSourceBriefSchema.parse(input.sourceBrief);
219
+ const uiSnapshotProvider = await this.dependencies.uiSnapshots.open({
220
+ deviceSerial: input.deviceSerial,
221
+ timeoutMs: config.ui?.snapshotTimeoutMs ?? config.idle.timeoutMs,
222
+ backend: config.ui?.backend ?? "auto",
223
+ cacheEnabled: config.ui?.cacheEnabled ?? true,
224
+ ...(input.signal === undefined ? {} : { signal: input.signal })
225
+ });
226
+ const uiBackend = uiSnapshotProvider.descriptor;
227
+ await closeUiSnapshotProvider(uiSnapshotProvider);
68
228
  const generationId = this.dependencies.generateId();
69
229
  const runId = distinctId(generationId, this.dependencies.generateId);
70
230
  const session = GenerationSessionSchema.parse({
@@ -76,7 +236,8 @@ export class GenerationStarter {
76
236
  projectHash: hashGenerationBinding(input.project),
77
237
  configHash: hashGenerationBinding(config),
78
238
  contextHash: hashGenerationBinding(context),
79
- snapshotHash: null
239
+ snapshotHash: null,
240
+ uiBackend
80
241
  },
81
242
  target: {
82
243
  packageName: config.run.packageName,
@@ -84,19 +245,25 @@ export class GenerationStarter {
84
245
  resetStrategy: "processOnly",
85
246
  interactionPolicy: context.interactionPolicy
86
247
  },
248
+ contextSelection: context.selection,
87
249
  variables: {
88
250
  runId,
89
251
  timestamp: this.dependencies.now().toISOString(),
90
252
  randomHex: randomHex(this.dependencies.randomBytes(16))
91
253
  },
92
- candidateSteps: [],
93
- candidateSources: [],
254
+ ...(baseFlow === undefined ? {} : { baseFlow: baseFlow.binding }),
255
+ ...(sourceBrief === undefined ? {} : { sourceBrief }),
256
+ externalFlows: externalFlowBindings,
257
+ candidateSteps: baseFlow?.journey.steps ?? [],
258
+ candidateSources: baseFlow?.journey.steps.map(() => "flow") ?? [],
94
259
  inFlight: null,
95
260
  pendingConfirmation: null,
96
261
  verification: { status: "notRun" },
262
+ verificationHistory: [],
97
263
  publication: { status: "notRun" }
98
264
  });
99
265
  await this.dependencies.store.create(session);
266
+ await this.dependencies.store.writeEvidence(session.id, GENERATION_CONTEXT_SNAPSHOT_PATH, context);
100
267
  return session;
101
268
  };
102
269
  }