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,561 @@
1
+ #!/usr/bin/env node
2
+ // Local proposed-step envelope helper for the taphound-journey-generator skill.
3
+ //
4
+ // Validates a `generation step --input` envelope offline (no device, no
5
+ // session) and auto-fills proposal.binding from a preceding observe/step
6
+ // output so baseRevision and snapshotHash never need hand-copying.
7
+ //
8
+ // The validation rules mirror schemas/proposed-step-envelope.json. When that
9
+ // schema changes, update this script and its test together.
10
+ import process from "node:process";
11
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
12
+ import { dirname, resolve } from "node:path";
13
+
14
+ const sha256Pattern = /^[a-f\d]{64}$/;
15
+ const generationIdPattern = /^[A-Za-z\d](?:[A-Za-z\d._-]*[A-Za-z\d])?$/;
16
+ const qualifiedNamePattern = /^(?:[A-Za-z_$][\w$]*\.)+[A-Za-z_$][\w$]*$/;
17
+ const snapshotRefPattern
18
+ = /^\.taphound\/build\/generations\/(?:\.[^/]+\.work|[^/]+)\/evidence\/snapshots\/revision-\d+\/[^/]+\/snapshot\.json$/;
19
+ const directions = new Set(["up", "down", "left", "right"]);
20
+ const logcatLevels = new Set(["V", "D", "I", "W", "E", "F", "A"]);
21
+ const logcatMatches = new Set(["literal", "regex"]);
22
+
23
+ const proposalShapes = new Map([
24
+ ["click", { required: ["action", "locator", "binding", "activity"], optional: ["expect"] }],
25
+ ["longClick", {
26
+ required: ["action", "locator", "binding", "activity"],
27
+ optional: ["durationMs", "expect"]
28
+ }],
29
+ ["inputText", {
30
+ required: ["action", "text", "binding", "activity"],
31
+ optional: ["expect"]
32
+ }],
33
+ ["swipe", {
34
+ required: ["action", "locator", "direction", "binding", "activity"],
35
+ optional: ["distancePercent", "durationMs", "expect"]
36
+ }],
37
+ ["scrollTo", {
38
+ required: ["action", "locator", "container", "direction", "binding", "activity"],
39
+ optional: ["maxSwipes", "distancePercent", "durationMs", "expect"]
40
+ }],
41
+ ["back", { required: ["action", "binding", "activity"], optional: ["expect"] }],
42
+ ["wait", { required: ["action", "binding", "activity"], optional: ["expect"] }]
43
+ ]);
44
+
45
+ function fail(code, message) {
46
+ const error = new Error(message);
47
+ error.code = code;
48
+ throw error;
49
+ }
50
+
51
+ function isPlainObject(value) {
52
+ return value !== null && typeof value === "object" && !Array.isArray(value);
53
+ }
54
+
55
+ function exactKeys(where, value, required, optional = [], subject = undefined) {
56
+ if (!isPlainObject(value)) {
57
+ fail("ENVELOPE_INVALID", `${where} must be a JSON object`);
58
+ }
59
+ const allowed = new Set([...required, ...optional]);
60
+ for (const key of Object.keys(value)) {
61
+ if (!allowed.has(key)) {
62
+ const name = subject ?? where;
63
+ fail(
64
+ "ENVELOPE_INVALID",
65
+ `${where}: unknown field "${key}"; ${name} allows fields: `
66
+ + [...required, ...optional].join(", ")
67
+ );
68
+ }
69
+ }
70
+ for (const key of required) {
71
+ if (!(key in value)) {
72
+ fail("ENVELOPE_INVALID", `${where}: missing required field "${key}"`);
73
+ }
74
+ }
75
+ }
76
+
77
+ function positiveInteger(where, value) {
78
+ if (!Number.isInteger(value) || value < 1) {
79
+ fail("ENVELOPE_INVALID", `${where} must be an integer >= 1`);
80
+ }
81
+ }
82
+
83
+ function nonEmptyString(where, value) {
84
+ if (typeof value !== "string" || value.length === 0) {
85
+ fail("ENVELOPE_INVALID", `${where} must be a non-empty string`);
86
+ }
87
+ }
88
+
89
+ function validateQualifiedName(where, value) {
90
+ if (typeof value !== "string" || !qualifiedNamePattern.test(value)) {
91
+ fail(
92
+ "ENVELOPE_INVALID",
93
+ `${where} must be a dot-separated qualified name (for example com.example.app.MainActivity)`
94
+ );
95
+ }
96
+ }
97
+
98
+ function validateLocator(where, value) {
99
+ exactKeys(
100
+ where,
101
+ value,
102
+ [],
103
+ ["resourceId", "text", "contentDescription", "index", "within", "evidence"],
104
+ "locator"
105
+ );
106
+ if (
107
+ value.resourceId === undefined
108
+ && value.text === undefined
109
+ && value.contentDescription === undefined
110
+ ) {
111
+ fail(
112
+ "ENVELOPE_INVALID",
113
+ `${where}: at least one of resourceId, text, or contentDescription is required`
114
+ );
115
+ }
116
+ for (const key of ["resourceId", "text", "contentDescription"]) {
117
+ if (value[key] !== undefined) {
118
+ nonEmptyString(`${where}.${key}`, value[key]);
119
+ }
120
+ }
121
+ if (value.index !== undefined) {
122
+ if (!Number.isInteger(value.index) || value.index < 0) {
123
+ fail("ENVELOPE_INVALID", `${where}.index must be an integer >= 0`);
124
+ }
125
+ }
126
+ if (value.within !== undefined) {
127
+ validateLocator(`${where}.within`, value.within);
128
+ }
129
+ if (value.evidence !== undefined) {
130
+ exactKeys(`${where}.evidence`, value.evidence, ["version", "semanticSha256"]);
131
+ if (value.evidence.version !== 1) {
132
+ fail("ENVELOPE_INVALID", `${where}.evidence.version must be 1`);
133
+ }
134
+ if (
135
+ typeof value.evidence.semanticSha256 !== "string"
136
+ || !sha256Pattern.test(value.evidence.semanticSha256)
137
+ ) {
138
+ fail(
139
+ "ENVELOPE_INVALID",
140
+ `${where}.evidence.semanticSha256 must be a 64-character lowercase hex string`
141
+ );
142
+ }
143
+ if (value.index === undefined) {
144
+ fail(
145
+ "ENVELOPE_INVALID",
146
+ `${where}: evidence requires index (Core only binds evidence for indexed elements)`
147
+ );
148
+ }
149
+ }
150
+ }
151
+
152
+ function validateBinding(where, value) {
153
+ exactKeys(
154
+ where, value, ["generationId", "baseRevision", "snapshotHash"], [],
155
+ "binding"
156
+ );
157
+ if (
158
+ typeof value.generationId !== "string"
159
+ || !generationIdPattern.test(value.generationId)
160
+ ) {
161
+ fail(
162
+ "ENVELOPE_INVALID",
163
+ `${where}.generationId must match ^[A-Za-z\\d](?:[A-Za-z\\d._-]*[A-Za-z\\d])?$`
164
+ );
165
+ }
166
+ positiveInteger(`${where}.baseRevision`, value.baseRevision);
167
+ if (
168
+ typeof value.snapshotHash !== "string"
169
+ || !sha256Pattern.test(value.snapshotHash)
170
+ ) {
171
+ fail(
172
+ "ENVELOPE_INVALID",
173
+ `${where}.snapshotHash must be a 64-character lowercase hex string`
174
+ );
175
+ }
176
+ }
177
+
178
+ function validateActivity(where, value) {
179
+ exactKeys(where, value, ["before"], [], "activity");
180
+ validateQualifiedName(`${where}.before`, value.before);
181
+ }
182
+
183
+ function validateExpect(where, value) {
184
+ if (!isPlainObject(value)) {
185
+ fail("ENVELOPE_INVALID", `${where} must be a JSON object`);
186
+ }
187
+ if (value.type === "activity") {
188
+ exactKeys(
189
+ where, value, ["type", "value", "timeoutMs"], [],
190
+ 'expect.type "activity"'
191
+ );
192
+ validateQualifiedName(`${where}.value`, value.value);
193
+ positiveInteger(`${where}.timeoutMs`, value.timeoutMs);
194
+ return;
195
+ }
196
+ if (value.type === "element") {
197
+ exactKeys(
198
+ where,
199
+ value,
200
+ ["type", "locator", "timeoutMs"],
201
+ ["enabled", "clickable", "absent"],
202
+ 'expect.type "element"'
203
+ );
204
+ validateLocator(`${where}.locator`, value.locator);
205
+ for (const key of ["enabled", "clickable", "absent"]) {
206
+ if (value[key] !== undefined && typeof value[key] !== "boolean") {
207
+ fail("ENVELOPE_INVALID", `${where}.${key} must be a boolean`);
208
+ }
209
+ }
210
+ if (value.absent === true
211
+ && (value.enabled !== undefined || value.clickable !== undefined)) {
212
+ fail(
213
+ "ENVELOPE_INVALID",
214
+ `${where}: absent: true cannot be combined with enabled or clickable`
215
+ );
216
+ }
217
+ positiveInteger(`${where}.timeoutMs`, value.timeoutMs);
218
+ return;
219
+ }
220
+ if (value.type === "logcat") {
221
+ exactKeys(
222
+ where, value, ["type", "tag", "pattern", "match", "timeoutMs"],
223
+ ["level"], 'expect.type "logcat"'
224
+ );
225
+ nonEmptyString(`${where}.tag`, value.tag);
226
+ nonEmptyString(`${where}.pattern`, value.pattern);
227
+ if (!logcatMatches.has(value.match)) {
228
+ fail("ENVELOPE_INVALID", `${where}.match must be "literal" or "regex"`);
229
+ }
230
+ if (value.level !== undefined && !logcatLevels.has(value.level)) {
231
+ fail(
232
+ "ENVELOPE_INVALID",
233
+ `${where}.level must be one of V, D, I, W, E, F, A`
234
+ );
235
+ }
236
+ positiveInteger(`${where}.timeoutMs`, value.timeoutMs);
237
+ return;
238
+ }
239
+ fail(
240
+ "ENVELOPE_INVALID",
241
+ `${where}.type must be one of "activity", "element", or "logcat"`
242
+ );
243
+ }
244
+
245
+ function validateProposal(where, value) {
246
+ if (!isPlainObject(value)) {
247
+ fail("ENVELOPE_INVALID", `${where} must be a JSON object`);
248
+ }
249
+ const shape = proposalShapes.get(value.action);
250
+ if (shape === undefined) {
251
+ fail(
252
+ "ENVELOPE_INVALID",
253
+ `${where}.action must be one of ${[...proposalShapes.keys()].map((action) => `"${action}"`).join(", ")}`
254
+ );
255
+ }
256
+ exactKeys(
257
+ where, value, shape.required, shape.optional,
258
+ `action "${String(value.action)}"`
259
+ );
260
+ if (value.locator !== undefined) {
261
+ validateLocator(`${where}.locator`, value.locator);
262
+ }
263
+ if (value.container !== undefined) {
264
+ validateLocator(`${where}.container`, value.container);
265
+ }
266
+ if (value.text !== undefined) {
267
+ nonEmptyString(`${where}.text`, value.text);
268
+ }
269
+ if (value.direction !== undefined && !directions.has(value.direction)) {
270
+ fail(
271
+ "ENVELOPE_INVALID",
272
+ `${where}.direction must be one of "up", "down", "left", "right"`
273
+ );
274
+ }
275
+ if (value.durationMs !== undefined) {
276
+ positiveInteger(`${where}.durationMs`, value.durationMs);
277
+ }
278
+ if (value.maxSwipes !== undefined) {
279
+ if (!Number.isInteger(value.maxSwipes)
280
+ || value.maxSwipes < 1 || value.maxSwipes > 30) {
281
+ fail("ENVELOPE_INVALID", `${where}.maxSwipes must be an integer 1..30`);
282
+ }
283
+ }
284
+ if (value.distancePercent !== undefined) {
285
+ if (typeof value.distancePercent !== "number"
286
+ || !(value.distancePercent > 0 && value.distancePercent <= 1)) {
287
+ fail(
288
+ "ENVELOPE_INVALID",
289
+ `${where}.distancePercent must be a number > 0 and <= 1`
290
+ );
291
+ }
292
+ }
293
+ validateBinding(`${where}.binding`, value.binding);
294
+ validateActivity(`${where}.activity`, value.activity);
295
+ if (value.expect !== undefined) {
296
+ validateExpect(`${where}.expect`, value.expect);
297
+ }
298
+ }
299
+
300
+ function validateSnapshotIdentity(where, snapshot, binding) {
301
+ if (!isPlainObject(snapshot)) {
302
+ fail("ENVELOPE_INVALID", `${where} must be a RuntimeSnapshot object`);
303
+ }
304
+ if (typeof snapshot.generationId !== "string"
305
+ || snapshot.generationId.length === 0) {
306
+ fail("ENVELOPE_INVALID", `${where}.generationId must be a non-empty string`);
307
+ }
308
+ if (!Number.isInteger(snapshot.baseRevision) || snapshot.baseRevision < 1) {
309
+ fail("ENVELOPE_INVALID", `${where}.baseRevision must be an integer >= 1`);
310
+ }
311
+ if (snapshot.generationId !== binding.generationId) {
312
+ fail(
313
+ "ENVELOPE_INVALID",
314
+ `${where}.generationId does not match proposal.binding.generationId`
315
+ );
316
+ }
317
+ if (snapshot.baseRevision !== binding.baseRevision) {
318
+ fail(
319
+ "ENVELOPE_INVALID",
320
+ `${where}.baseRevision does not match proposal.binding.baseRevision`
321
+ );
322
+ }
323
+ }
324
+
325
+ function validateEnvelope(envelope) {
326
+ exactKeys(
327
+ "envelope",
328
+ envelope,
329
+ ["version", "proposal"],
330
+ ["snapshot", "snapshotRef"]
331
+ );
332
+ if (envelope.version !== 1) {
333
+ fail("ENVELOPE_INVALID", "envelope.version must be 1");
334
+ }
335
+ if (envelope.snapshot !== undefined && envelope.snapshotRef !== undefined) {
336
+ fail(
337
+ "ENVELOPE_INVALID",
338
+ "envelope: exactly one of snapshot or snapshotRef is allowed, not both"
339
+ );
340
+ }
341
+ if (envelope.snapshot === undefined && envelope.snapshotRef === undefined) {
342
+ fail(
343
+ "ENVELOPE_INVALID",
344
+ "envelope: one of snapshot or snapshotRef is required"
345
+ );
346
+ }
347
+ validateProposal("proposal", envelope.proposal);
348
+ if (envelope.snapshotRef !== undefined
349
+ && !snapshotRefPattern.test(envelope.snapshotRef)) {
350
+ fail(
351
+ "ENVELOPE_INVALID",
352
+ "envelope.snapshotRef must be a Store-owned evidence reference returned by the preceding observe or step output"
353
+ );
354
+ }
355
+ if (envelope.snapshot !== undefined) {
356
+ validateSnapshotIdentity(
357
+ "envelope.snapshot",
358
+ envelope.snapshot,
359
+ envelope.proposal.binding
360
+ );
361
+ }
362
+ return {
363
+ status: "valid",
364
+ exitCode: 0,
365
+ action: envelope.proposal.action,
366
+ binding: envelope.proposal.binding,
367
+ snapshotSource: envelope.snapshot === undefined ? "reference" : "inline"
368
+ };
369
+ }
370
+
371
+ // A bind source is one observe output, one step output, or a raw binding
372
+ // object. The binding fields are copied verbatim; nothing is invented.
373
+ function readBindingFromSource(source) {
374
+ if (!isPlainObject(source)) {
375
+ fail("ENVELOPE_INVALID", "bind source must be a JSON object");
376
+ }
377
+ if (source.status === "observed") {
378
+ validateBinding("observe output", {
379
+ generationId: source.generationId,
380
+ baseRevision: source.baseRevision,
381
+ snapshotHash: source.snapshotHash
382
+ });
383
+ if (typeof source.snapshotRef !== "string"
384
+ || !snapshotRefPattern.test(source.snapshotRef)) {
385
+ fail(
386
+ "ENVELOPE_INVALID",
387
+ "observe output.snapshotRef is missing or not a Store-owned evidence reference"
388
+ );
389
+ }
390
+ return {
391
+ binding: {
392
+ generationId: source.generationId,
393
+ baseRevision: source.baseRevision,
394
+ snapshotHash: source.snapshotHash
395
+ },
396
+ snapshotRef: source.snapshotRef
397
+ };
398
+ }
399
+ if (source.status === "succeeded" && source.nextBinding !== undefined) {
400
+ validateBinding("step output.nextBinding", source.nextBinding);
401
+ if (typeof source.nextSnapshotRef !== "string"
402
+ || !snapshotRefPattern.test(source.nextSnapshotRef)) {
403
+ fail(
404
+ "ENVELOPE_INVALID",
405
+ "step output.nextSnapshotRef is missing or not a Store-owned evidence reference"
406
+ );
407
+ }
408
+ return {
409
+ binding: source.nextBinding,
410
+ snapshotRef: source.nextSnapshotRef
411
+ };
412
+ }
413
+ validateBinding("bind source", source);
414
+ return {
415
+ binding: {
416
+ generationId: source.generationId,
417
+ baseRevision: source.baseRevision,
418
+ snapshotHash: source.snapshotHash
419
+ },
420
+ snapshotRef: typeof source.snapshotRef === "string"
421
+ && snapshotRefPattern.test(source.snapshotRef)
422
+ ? source.snapshotRef
423
+ : undefined
424
+ };
425
+ }
426
+
427
+ async function readJsonFile(path, label) {
428
+ let text;
429
+ try {
430
+ text = await readFile(path, "utf8");
431
+ } catch (error) {
432
+ fail(
433
+ "ENVELOPE_IO",
434
+ `Unable to read ${label} at ${path}: ${
435
+ error instanceof Error ? error.message : String(error)
436
+ }`
437
+ );
438
+ }
439
+ try {
440
+ return JSON.parse(text);
441
+ } catch (error) {
442
+ fail(
443
+ "ENVELOPE_INVALID",
444
+ `${label} at ${path} is not valid JSON: ${
445
+ error instanceof Error ? error.message : String(error)
446
+ }`
447
+ );
448
+ }
449
+ }
450
+
451
+ async function bind(inputPath, fromPath, outPath) {
452
+ const envelope = await readJsonFile(inputPath, "envelope input");
453
+ exactKeys(
454
+ "envelope input",
455
+ envelope,
456
+ ["version", "proposal"],
457
+ ["snapshot", "snapshotRef"]
458
+ );
459
+ if (envelope.version !== 1) {
460
+ fail("ENVELOPE_INVALID", "envelope.version must be 1");
461
+ }
462
+ const source = await readJsonFile(fromPath, "bind source");
463
+ const { binding, snapshotRef } = readBindingFromSource(source);
464
+ const proposal = isPlainObject(envelope.proposal)
465
+ ? { ...envelope.proposal, binding }
466
+ : undefined;
467
+ if (proposal === undefined) {
468
+ fail("ENVELOPE_INVALID", "envelope.proposal must be a JSON object");
469
+ }
470
+ const bound = {
471
+ version: 1,
472
+ proposal,
473
+ ...(envelope.snapshot === undefined
474
+ ? envelope.snapshotRef === undefined && snapshotRef !== undefined
475
+ ? { snapshotRef }
476
+ : {}
477
+ : { snapshot: envelope.snapshot })
478
+ };
479
+ validateEnvelope(bound);
480
+ if (outPath !== undefined) {
481
+ const absolute = resolve(outPath);
482
+ await mkdir(dirname(absolute), { recursive: true });
483
+ const temp = `${absolute}.tmp-${process.pid}`;
484
+ await writeFile(temp, `${JSON.stringify(bound, null, 2)}\n`);
485
+ await rename(temp, absolute);
486
+ process.stdout.write(`${JSON.stringify({
487
+ status: "bound",
488
+ exitCode: 0,
489
+ path: outPath,
490
+ binding,
491
+ ...(snapshotRef === undefined ? {} : { snapshotRef })
492
+ })}\n`);
493
+ return;
494
+ }
495
+ process.stdout.write(`${JSON.stringify(bound)}\n`);
496
+ }
497
+
498
+ function options(argv, names) {
499
+ const result = {};
500
+ for (let index = 0; index < argv.length; index += 2) {
501
+ const name = argv[index];
502
+ const value = argv[index + 1];
503
+ if (!names.includes(name) || value === undefined) {
504
+ fail("ENVELOPE_USAGE", `Invalid option ${String(name)}`);
505
+ }
506
+ result[name.slice(2)] = value;
507
+ }
508
+ return result;
509
+ }
510
+
511
+ function help() {
512
+ return [
513
+ "TapHound Proposed Step Envelope Helper",
514
+ "",
515
+ "Commands:",
516
+ " validate --input <envelope.json>",
517
+ " Validate one generation step envelope offline (no device, no session).",
518
+ " bind --input <envelope.json> --from <observe-or-step-output.json> [--out <path>]",
519
+ " Fill proposal.binding (and snapshotRef when absent) from the preceding",
520
+ " observe output, step output, or raw binding, then validate.",
521
+ "",
522
+ "bind writes the bound envelope to --out; without --out the bound envelope",
523
+ "itself is the single stdout JSON value.",
524
+ "",
525
+ "Revision rule: each accepted step advances the session revision by 2 and",
526
+ "each observe by 1, so one observe-then-step cycle needs baseRevision + 3.",
527
+ "Prefer binding from the latest output instead of computing revisions."
528
+ ].join("\n");
529
+ }
530
+
531
+ async function main() {
532
+ const [command, ...argv] = process.argv.slice(2);
533
+ if (command === undefined || command === "help" || command === "--help") {
534
+ process.stdout.write(`${help()}\n`);
535
+ return;
536
+ }
537
+ if (command === "validate") {
538
+ const input = options(argv, ["--input"]);
539
+ const envelope = await readJsonFile(input.input, "envelope input");
540
+ process.stdout.write(`${JSON.stringify(validateEnvelope(envelope))}\n`);
541
+ return;
542
+ }
543
+ if (command === "bind") {
544
+ const input = options(argv, ["--input", "--from", "--out"]);
545
+ if (input.input === undefined || input.from === undefined) {
546
+ fail("ENVELOPE_USAGE", "bind requires --input and --from");
547
+ }
548
+ await bind(input.input, input.from, input.out);
549
+ return;
550
+ }
551
+ fail("ENVELOPE_USAGE", `Unknown command ${command}`);
552
+ }
553
+
554
+ main().catch((error) => {
555
+ process.stdout.write(`${JSON.stringify({
556
+ status: "error",
557
+ code: error?.code ?? "ENVELOPE_INTERNAL",
558
+ message: error instanceof Error ? error.message : String(error)
559
+ })}\n`);
560
+ process.exitCode = 2;
561
+ });
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "externalFlow",
4
+ "name": "camera/photo-capture",
5
+ "description": "Capture a photo using the AOSP Camera2 app: wait for readiness then tap the shutter button",
6
+ "escapedPackageName": "com.android.camera2",
7
+ "expectedEscapeActivity": "com.android.camera2.CameraActivity",
8
+ "includes": [],
9
+ "steps": [
10
+ {
11
+ "action": "wait",
12
+ "expectedActivity": "com.android.camera2.CameraActivity"
13
+ },
14
+ {
15
+ "action": "click",
16
+ "locator": {
17
+ "resourceId": "com.android.camera2:id/shutter_button"
18
+ },
19
+ "expectedActivity": "com.android.camera2.CameraActivity"
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "flow",
4
+ "name": "core/launch-home",
5
+ "includes": [],
6
+ "steps": [
7
+ {
8
+ "action": "wait",
9
+ "activity": {
10
+ "before": "com.example.app.HomeActivity",
11
+ "after": "com.example.app.HomeActivity"
12
+ },
13
+ "expect": {
14
+ "type": "element",
15
+ "locator": {
16
+ "resourceId": "home_root"
17
+ },
18
+ "timeoutMs": 3000
19
+ }
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "journeySource",
4
+ "name": "chat/send-message",
5
+ "includes": [
6
+ "chat/open-thread"
7
+ ],
8
+ "steps": [
9
+ {
10
+ "action": "wait",
11
+ "activity": {
12
+ "before": "com.example.app.ChatActivity",
13
+ "after": "com.example.app.ChatActivity"
14
+ }
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,70 @@
1
+ ---
2
+ schemaVersion: 2
3
+ kind: taphound.journeyBrief
4
+ caseId: CASE-002
5
+ ---
6
+
7
+ # Goal
8
+
9
+ Open Search, submit an empty query, and verify validation.
10
+
11
+ ## Preconditions
12
+
13
+ - Start from an independent cold launch.
14
+ - Use the approved `search-basic` fixture.
15
+
16
+ ## Expected Journey
17
+
18
+ 1. Open Search from Home.
19
+ 2. Leave the query empty.
20
+ 3. Submit the query.
21
+ 4. Observe the empty-query validation state.
22
+
23
+ ## State Transition Map
24
+
25
+ ```mermaid
26
+ stateDiagram-v2
27
+ HomeActivity --> SearchActivity: click open_search [source]
28
+ SearchActivity --> SearchActivity+Keyboard: click search_input [source]
29
+ SearchActivity+Keyboard --> SearchActivity+Dialog: click submit_search [needs-observation]
30
+ ```
31
+
32
+ | edge | action | from | to | confidence | locator hint |
33
+ |------|--------|------|----|-----------|--------------|
34
+ | e1 | click | HomeActivity | SearchActivity | source | resourceId: open_search |
35
+ | e2 | click | SearchActivity | SearchActivity+Keyboard | source | resourceId: search_input |
36
+ | e3 | click | SearchActivity+Keyboard | SearchActivity+Dialog | needs-observation | text: submit_search |
37
+
38
+ Overlay sub-states of the same Activity (keyboard/dialog/drawer) use distinct
39
+ node names (`Activity+Suffix`).
40
+
41
+ ## Capability Notes
42
+
43
+ - Runtime variable capture: not supported — use a fixed unique string as the
44
+ business identifier.
45
+ - Multi-field locators: stop at the first field with a unique match; later
46
+ fields are not validated — text assertions must use a text-only locator.
47
+ - logcat expect: tag matches by exact equality (including all prefixes);
48
+ literal matches by substring.
49
+
50
+ ## Assertions
51
+
52
+ - `SearchActivity` remains foreground.
53
+ - The `empty_query_error` element is visible.
54
+
55
+ ## Implementation Hints
56
+
57
+ - Home entry resource ID: `open_search`.
58
+ - Submit resource ID: `submit_search`.
59
+ - Relevant module: `:feature:search`.
60
+
61
+ ## Constraints
62
+
63
+ - Do not use coordinates or visual guessing.
64
+ - Final Replay must pass.
65
+ - Idempotency: repeat runs create duplicate search history entries; history list uses index: 0.
66
+
67
+ ## Evidence References
68
+
69
+ - `feature/search/src/main/java/com/example/search/SearchScreen.kt`
70
+ - `feature/search/src/main/res/layout/search_screen.xml`