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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/README.md +49 -149
  2. package/README.zh-CN.md +47 -147
  3. package/assets/skills/taphound-case-suite/SKILL.md +363 -0
  4. package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
  5. package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
  6. package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
  7. package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
  8. package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
  9. package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
  10. package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
  11. package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
  12. package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
  13. package/assets/skills/taphound-flash/SKILL.md +115 -0
  14. package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
  15. package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
  16. package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
  17. package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
  18. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
  19. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
  20. package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
  21. package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
  22. package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
  23. package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
  24. package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
  25. package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
  26. package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
  27. package/assets/skills/taphound-journey-generator/SKILL.md +500 -0
  28. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
  29. package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
  30. package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
  31. package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
  32. package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
  33. package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
  34. package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
  35. package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
  36. package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
  37. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
  38. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
  39. package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +561 -0
  40. package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
  41. package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
  42. package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
  43. package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
  44. package/assets/skills/taphound-verify-change/SKILL.md +91 -0
  45. package/assets/skills/taphound-verify-change/references/accept.md +38 -0
  46. package/assets/skills/taphound-verify-change/references/preserve.md +349 -0
  47. package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
  48. package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
  49. package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
  50. package/dist/adapters/adb/adb-adapter.d.ts +16 -2
  51. package/dist/adapters/adb/adb-adapter.js +199 -0
  52. package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
  53. package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
  54. package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
  55. package/dist/adapters/adb/ui-automator-parser.js +160 -0
  56. package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
  57. package/dist/adapters/adb/window-topology-parser.js +101 -0
  58. package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
  59. package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
  60. package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
  61. package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
  62. package/dist/adapters/android-cli/layout-parser.js +12 -8
  63. package/dist/adapters/appium/appium-doctor.d.ts +7 -0
  64. package/dist/adapters/appium/appium-doctor.js +128 -0
  65. package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +34 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +240 -0
  67. package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
  68. package/dist/adapters/camera/camera-probe-adapter.js +286 -0
  69. package/dist/adapters/filesystem/artifact-store.js +40 -1
  70. package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
  71. package/dist/adapters/filesystem/context-document-writer.js +112 -0
  72. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  73. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  74. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  75. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  76. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  77. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  78. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  79. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  80. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  81. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  82. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  83. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  84. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  85. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  86. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  87. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  88. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  89. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  90. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  91. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  92. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  93. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  94. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  95. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  96. package/dist/adapters/filesystem/skill-installer.js +40 -11
  97. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  98. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  99. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  100. package/dist/adapters/git/node-git-diff.js +114 -0
  101. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  102. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  103. package/dist/adapters/process/node-process-runner.js +11 -2
  104. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  105. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  106. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  107. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  108. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  109. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  110. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  111. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  112. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  113. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  114. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  115. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  116. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  122. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  123. package/dist/adapters/runtime/session-adb-view.js +193 -0
  124. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  125. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  126. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  127. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  128. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  129. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  130. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  131. package/dist/adapters/ui/device-layout-temp.js +18 -0
  132. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  133. package/dist/adapters/ui/device-ui-environment.js +81 -0
  134. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  135. package/dist/adapters/ui/layout-normalization.js +44 -0
  136. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  137. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  138. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  139. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  140. package/dist/application/align/align-service.d.ts +42 -0
  141. package/dist/application/align/align-service.js +106 -0
  142. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  143. package/dist/application/assertion/expectation-evaluator.js +156 -18
  144. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  145. package/dist/application/assertion/guarded-expectation.js +74 -0
  146. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  147. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  148. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  149. package/dist/application/checkpoint/baseline-error.js +8 -0
  150. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  151. package/dist/application/checkpoint/baseline-service.js +147 -0
  152. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  153. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  154. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  155. package/dist/application/checkpoint/regression-comparator.js +192 -0
  156. package/dist/application/collector/logcat-collector.d.ts +22 -1
  157. package/dist/application/collector/logcat-collector.js +103 -15
  158. package/dist/application/collector/logcat-event.d.ts +8 -0
  159. package/dist/application/collector/logcat-event.js +79 -0
  160. package/dist/application/collector/logcat-stop.d.ts +2 -0
  161. package/dist/application/collector/logcat-stop.js +11 -0
  162. package/dist/application/context/context-generator.d.ts +45 -0
  163. package/dist/application/context/context-generator.js +228 -0
  164. package/dist/application/context/context-loader.d.ts +40 -0
  165. package/dist/application/context/context-loader.js +223 -0
  166. package/dist/application/context/context-refresher.d.ts +59 -0
  167. package/dist/application/context/context-refresher.js +349 -0
  168. package/dist/application/context/context-rehasher.d.ts +36 -0
  169. package/dist/application/context/context-rehasher.js +110 -0
  170. package/dist/application/context/context-validator.d.ts +23 -1
  171. package/dist/application/context/context-validator.js +116 -9
  172. package/dist/application/context/evidence-hash.d.ts +1 -0
  173. package/dist/application/context/evidence-hash.js +125 -0
  174. package/dist/application/context/evidence-match.d.ts +9 -0
  175. package/dist/application/context/evidence-match.js +8 -0
  176. package/dist/application/context/shard-identity.d.ts +2 -0
  177. package/dist/application/context/shard-identity.js +7 -0
  178. package/dist/application/contract/contract-loader.d.ts +25 -0
  179. package/dist/application/contract/contract-loader.js +68 -0
  180. package/dist/application/contract/contract-review.d.ts +25 -0
  181. package/dist/application/contract/contract-review.js +51 -0
  182. package/dist/application/contract/contract-verifier.d.ts +53 -0
  183. package/dist/application/contract/contract-verifier.js +645 -0
  184. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  185. package/dist/application/devices/resolve-device-assignments.js +60 -0
  186. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  187. package/dist/application/diagnosis/failure-classifier.js +179 -0
  188. package/dist/application/doctor/doctor-service.d.ts +36 -3
  189. package/dist/application/doctor/doctor-service.js +255 -25
  190. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  191. package/dist/application/generation/generation-app-preparer.js +28 -0
  192. package/dist/application/generation/generation-config-service.d.ts +21 -0
  193. package/dist/application/generation/generation-config-service.js +53 -0
  194. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  195. package/dist/application/generation/generation-confirmation-service.js +109 -24
  196. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  197. package/dist/application/generation/generation-context-snapshot.js +29 -0
  198. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  199. package/dist/application/generation/generation-finalizer.js +167 -70
  200. package/dist/application/generation/generation-publisher.js +12 -8
  201. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  202. package/dist/application/generation/generation-recovery-service.js +144 -0
  203. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  204. package/dist/application/generation/generation-reopen-service.js +37 -0
  205. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  206. package/dist/application/generation/generation-replace-service.js +116 -0
  207. package/dist/application/generation/generation-starter.d.ts +44 -4
  208. package/dist/application/generation/generation-starter.js +175 -8
  209. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  210. package/dist/application/generation/generation-step-executor.js +471 -108
  211. package/dist/application/generation/proposed-step-validator.js +96 -30
  212. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  213. package/dist/application/generation/replay-policy-loader.js +29 -0
  214. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  215. package/dist/application/generation/risk-evaluator.js +118 -3
  216. package/dist/application/generation/runtime-observer.d.ts +39 -7
  217. package/dist/application/generation/runtime-observer.js +193 -24
  218. package/dist/application/impact/impact-resolver.d.ts +32 -0
  219. package/dist/application/impact/impact-resolver.js +160 -0
  220. package/dist/application/init/init-service.js +26 -13
  221. package/dist/application/interaction/action-executor.d.ts +3 -2
  222. package/dist/application/interaction/action-executor.js +11 -1
  223. package/dist/application/interaction/action-target.d.ts +17 -0
  224. package/dist/application/interaction/action-target.js +40 -0
  225. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  226. package/dist/application/interaction/external-step-runner.js +332 -0
  227. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  228. package/dist/application/interaction/fallback-resolver.js +7 -5
  229. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  230. package/dist/application/interaction/scroll-to-executor.js +118 -36
  231. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  232. package/dist/application/journey/external-flow-resolver.js +22 -0
  233. package/dist/application/journey/journey-check-service.d.ts +54 -0
  234. package/dist/application/journey/journey-check-service.js +207 -0
  235. package/dist/application/journey/journey-promoter.d.ts +26 -0
  236. package/dist/application/journey/journey-promoter.js +123 -0
  237. package/dist/application/journey/journey-resolver.d.ts +42 -0
  238. package/dist/application/journey/journey-resolver.js +239 -0
  239. package/dist/application/journey/journey-retirer.d.ts +25 -0
  240. package/dist/application/journey/journey-retirer.js +87 -0
  241. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  242. package/dist/application/knowledge/anchor-resolver.js +110 -0
  243. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  244. package/dist/application/knowledge/knowledge-loader.js +36 -0
  245. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  246. package/dist/application/locator/layout-failure-summary.js +67 -0
  247. package/dist/application/locator/layout-traversal.d.ts +11 -0
  248. package/dist/application/locator/layout-traversal.js +18 -0
  249. package/dist/application/locator/locator-resolver.d.ts +13 -1
  250. package/dist/application/locator/locator-resolver.js +182 -18
  251. package/dist/application/observe/observe-service.d.ts +20 -0
  252. package/dist/application/observe/observe-service.js +91 -0
  253. package/dist/application/project/project-describer.d.ts +14 -6
  254. package/dist/application/project/project-describer.js +38 -5
  255. package/dist/application/recognition/screen-detector.d.ts +28 -0
  256. package/dist/application/recognition/screen-detector.js +111 -0
  257. package/dist/application/recorder/locator-selector.js +151 -17
  258. package/dist/application/recorder/recorder-service.d.ts +16 -4
  259. package/dist/application/recorder/recorder-service.js +420 -128
  260. package/dist/application/report/report-writer.js +1 -1
  261. package/dist/application/runtime/cold-launch.d.ts +28 -0
  262. package/dist/application/runtime/cold-launch.js +59 -0
  263. package/dist/application/runtime/step-runner.d.ts +49 -4
  264. package/dist/application/runtime/step-runner.js +721 -130
  265. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  266. package/dist/application/runtime/verify-runtime.js +554 -174
  267. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  268. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  269. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  270. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  271. package/dist/application/ui/ui-stability-probe.d.ts +3 -0
  272. package/dist/application/ui/ui-stability-probe.js +8 -0
  273. package/dist/application/wait/idle-advice.d.ts +6 -0
  274. package/dist/application/wait/idle-advice.js +27 -0
  275. package/dist/application/wait/idle-profiles.d.ts +15 -0
  276. package/dist/application/wait/idle-profiles.js +75 -0
  277. package/dist/application/wait/idle-waiter.d.ts +28 -4
  278. package/dist/application/wait/idle-waiter.js +186 -15
  279. package/dist/cli/commands/align.d.ts +3 -0
  280. package/dist/cli/commands/align.js +124 -0
  281. package/dist/cli/commands/baseline.d.ts +3 -0
  282. package/dist/cli/commands/baseline.js +130 -0
  283. package/dist/cli/commands/context.js +300 -27
  284. package/dist/cli/commands/contract.d.ts +3 -0
  285. package/dist/cli/commands/contract.js +120 -0
  286. package/dist/cli/commands/doctor.js +16 -9
  287. package/dist/cli/commands/failure.d.ts +3 -0
  288. package/dist/cli/commands/failure.js +63 -0
  289. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  290. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  291. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  292. package/dist/cli/commands/generation/session-commands.js +472 -0
  293. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  294. package/dist/cli/commands/generation/shared.js +291 -0
  295. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  296. package/dist/cli/commands/generation/step-commands.js +315 -0
  297. package/dist/cli/commands/generation.js +10 -507
  298. package/dist/cli/commands/impact.d.ts +3 -0
  299. package/dist/cli/commands/impact.js +87 -0
  300. package/dist/cli/commands/init.js +13 -6
  301. package/dist/cli/commands/journey.d.ts +3 -0
  302. package/dist/cli/commands/journey.js +382 -0
  303. package/dist/cli/commands/knowledge.d.ts +3 -0
  304. package/dist/cli/commands/knowledge.js +93 -0
  305. package/dist/cli/commands/observe.d.ts +3 -0
  306. package/dist/cli/commands/observe.js +127 -0
  307. package/dist/cli/commands/project.js +2 -1
  308. package/dist/cli/commands/record.js +18 -5
  309. package/dist/cli/commands/verify.js +273 -63
  310. package/dist/cli/dependencies.d.ts +125 -1
  311. package/dist/cli/dependencies.js +450 -51
  312. package/dist/cli/diff-verification.d.ts +41 -0
  313. package/dist/cli/diff-verification.js +192 -0
  314. package/dist/cli/main.js +49 -1
  315. package/dist/cli/output.d.ts +5 -3
  316. package/dist/cli/output.js +12 -0
  317. package/dist/cli/program.js +19 -1
  318. package/dist/cli/project-root.d.ts +1 -0
  319. package/dist/cli/project-root.js +6 -0
  320. package/dist/cli/runtime-selection.d.ts +22 -0
  321. package/dist/cli/runtime-selection.js +92 -0
  322. package/dist/cli/version.d.ts +1 -0
  323. package/dist/cli/version.js +14 -0
  324. package/dist/cli/workspace-guard.d.ts +2 -0
  325. package/dist/cli/workspace-guard.js +3 -0
  326. package/dist/domain/binding-reference.d.ts +4 -0
  327. package/dist/domain/binding-reference.js +23 -0
  328. package/dist/domain/checkpoint.d.ts +404 -0
  329. package/dist/domain/checkpoint.js +297 -0
  330. package/dist/domain/config.d.ts +107 -1
  331. package/dist/domain/config.js +52 -6
  332. package/dist/domain/contract.d.ts +413 -0
  333. package/dist/domain/contract.js +196 -0
  334. package/dist/domain/external-flow.d.ts +493 -0
  335. package/dist/domain/external-flow.js +15 -0
  336. package/dist/domain/failure-classification.d.ts +176 -0
  337. package/dist/domain/failure-classification.js +169 -0
  338. package/dist/domain/failure.d.ts +2 -1
  339. package/dist/domain/failure.js +123 -0
  340. package/dist/domain/generation.d.ts +1671 -132
  341. package/dist/domain/generation.js +202 -13
  342. package/dist/domain/geometry.d.ts +13 -0
  343. package/dist/domain/geometry.js +16 -0
  344. package/dist/domain/impact.d.ts +71 -0
  345. package/dist/domain/impact.js +76 -0
  346. package/dist/domain/init.d.ts +12 -4
  347. package/dist/domain/init.js +24 -18
  348. package/dist/domain/journey-composition.d.ts +2285 -0
  349. package/dist/domain/journey-composition.js +85 -0
  350. package/dist/domain/journey-lifecycle.d.ts +10 -0
  351. package/dist/domain/journey-lifecycle.js +9 -0
  352. package/dist/domain/journey.d.ts +2419 -212
  353. package/dist/domain/journey.js +384 -14
  354. package/dist/domain/knowledge.d.ts +165 -0
  355. package/dist/domain/knowledge.js +188 -0
  356. package/dist/domain/layout.d.ts +34 -5
  357. package/dist/domain/layout.js +64 -6
  358. package/dist/domain/locator-evidence.d.ts +3 -0
  359. package/dist/domain/locator-evidence.js +36 -0
  360. package/dist/domain/logcat-event.d.ts +54 -0
  361. package/dist/domain/logcat-event.js +40 -0
  362. package/dist/domain/observation.d.ts +33 -0
  363. package/dist/domain/observation.js +18 -0
  364. package/dist/domain/project-context.d.ts +219 -1
  365. package/dist/domain/project-context.js +209 -6
  366. package/dist/domain/proposed-step.d.ts +340 -60
  367. package/dist/domain/proposed-step.js +23 -3
  368. package/dist/domain/report.d.ts +1455 -28
  369. package/dist/domain/report.js +211 -14
  370. package/dist/domain/runtime-snapshot.d.ts +58 -1
  371. package/dist/domain/runtime-snapshot.js +14 -3
  372. package/dist/domain/runtime.d.ts +50 -0
  373. package/dist/domain/runtime.js +36 -0
  374. package/dist/domain/system-app-profiles.d.ts +6 -0
  375. package/dist/domain/system-app-profiles.js +43 -0
  376. package/dist/domain/ui-backend.d.ts +28 -0
  377. package/dist/domain/ui-backend.js +33 -0
  378. package/dist/domain/ui-cache.d.ts +11 -0
  379. package/dist/domain/ui-cache.js +10 -0
  380. package/dist/domain/window-hierarchy.d.ts +84 -0
  381. package/dist/domain/window-hierarchy.js +172 -0
  382. package/dist/domain/workflow-manifest.d.ts +77 -0
  383. package/dist/domain/workflow-manifest.js +136 -0
  384. package/dist/domain/workspace.d.ts +28 -0
  385. package/dist/domain/workspace.js +72 -0
  386. package/dist/ports/adb.d.ts +34 -1
  387. package/dist/ports/align-prompt.d.ts +11 -0
  388. package/dist/ports/align-prompt.js +6 -0
  389. package/dist/ports/anchor-resolver.d.ts +30 -0
  390. package/dist/ports/anchor-resolver.js +1 -0
  391. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  392. package/dist/ports/annotated-screen-resolver.js +1 -0
  393. package/dist/ports/camera-probe.d.ts +23 -0
  394. package/dist/ports/camera-probe.js +8 -0
  395. package/dist/ports/context-document-writer.d.ts +24 -0
  396. package/dist/ports/context-document-writer.js +1 -0
  397. package/dist/ports/detached-process-launcher.d.ts +12 -0
  398. package/dist/ports/detached-process-launcher.js +1 -0
  399. package/dist/ports/external-flow-registry.d.ts +37 -0
  400. package/dist/ports/external-flow-registry.js +1 -0
  401. package/dist/ports/generation-prompt.d.ts +2 -1
  402. package/dist/ports/generation-session-store.d.ts +12 -2
  403. package/dist/ports/git-diff.d.ts +9 -0
  404. package/dist/ports/git-diff.js +1 -0
  405. package/dist/ports/journey-composition-store.d.ts +17 -0
  406. package/dist/ports/journey-composition-store.js +1 -0
  407. package/dist/ports/knowledge-registry.d.ts +20 -0
  408. package/dist/ports/knowledge-registry.js +1 -0
  409. package/dist/ports/process-runner.d.ts +7 -0
  410. package/dist/ports/project-file-inspector.d.ts +1 -0
  411. package/dist/ports/project-identity-inspector.d.ts +24 -0
  412. package/dist/ports/project-identity-inspector.js +1 -0
  413. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  414. package/dist/ports/project-inventory-inspector.js +1 -0
  415. package/dist/ports/project-module-discoverer.d.ts +26 -0
  416. package/dist/ports/project-module-discoverer.js +1 -0
  417. package/dist/ports/recorder-prompt.d.ts +10 -1
  418. package/dist/ports/runtime-backend.d.ts +89 -0
  419. package/dist/ports/runtime-backend.js +13 -0
  420. package/dist/ports/runtime-capability.d.ts +12 -0
  421. package/dist/ports/runtime-capability.js +20 -0
  422. package/dist/ports/runtime-session-ports.d.ts +25 -0
  423. package/dist/ports/runtime-session-ports.js +1 -0
  424. package/dist/ports/screenshot.d.ts +11 -0
  425. package/dist/ports/screenshot.js +1 -0
  426. package/dist/ports/skill-installer.d.ts +2 -2
  427. package/dist/ports/ui-snapshot.d.ts +35 -0
  428. package/dist/ports/ui-snapshot.js +1 -0
  429. package/dist/ports/ui-stability.d.ts +19 -0
  430. package/dist/ports/ui-stability.js +1 -0
  431. package/dist/ports/workspace-layout.d.ts +4 -0
  432. package/dist/ports/workspace-layout.js +1 -0
  433. package/dist/shared/errors.d.ts +2 -0
  434. package/dist/shared/errors.js +22 -0
  435. package/dist/shared/paths.d.ts +2 -0
  436. package/dist/shared/paths.js +24 -0
  437. package/dist/shared/strings.d.ts +2 -0
  438. package/dist/shared/strings.js +16 -0
  439. package/package.json +6 -1
  440. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  441. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  442. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  443. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  444. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  445. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  446. package/dist/ports/android-cli.d.ts +0 -21
  447. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -2,9 +2,14 @@ import { z } from "zod";
2
2
  import { primaryAppPid } from "../../domain/app-process.js";
3
3
  import { GenerationSessionIdSchema, GenerationSessionSchema } from "../../domain/generation.js";
4
4
  import { LayoutElementSchema } from "../../domain/layout.js";
5
+ import { uiBackendIdAsSelection } from "../../domain/ui-backend.js";
5
6
  import { ProposalBindingSchema } from "../../domain/proposed-step.js";
6
7
  import { RuntimeSnapshotSchema, hashRuntimeSnapshot } from "../../domain/runtime-snapshot.js";
8
+ import { assessWindowHierarchy } from "../../domain/window-hierarchy.js";
9
+ import { withIdleAdvice } from "../wait/idle-advice.js";
7
10
  import { GenerationOperationError } from "./generation-starter.js";
11
+ import { closeUiSnapshotProvider } from "../ui/ui-snapshot-lifecycle.js";
12
+ import { uiStabilityProbe } from "../ui/ui-stability-probe.js";
8
13
  function failedCapture(result) {
9
14
  return result.exitCode !== 0
10
15
  || result.timedOut
@@ -15,9 +20,11 @@ function revisionPath(revision) {
15
20
  return `evidence/snapshots/revision-${String(revision).padStart(6, "0")}`;
16
21
  }
17
22
  function assertObservable(session) {
23
+ if (session.pendingConfirmation !== null) {
24
+ throw new GenerationOperationError("RISK_CONFIRMATION_REQUIRED", `Generation confirmation ${session.pendingConfirmation.challengeId} must be resolved before observation`, { challenge: session.pendingConfirmation });
25
+ }
18
26
  if (session.state !== "active"
19
- || session.inFlight !== null
20
- || session.pendingConfirmation !== null) {
27
+ || session.inFlight !== null) {
21
28
  throw new Error("Generation session must be active and idle to observe");
22
29
  }
23
30
  if (session.revision === Number.MAX_SAFE_INTEGER) {
@@ -30,17 +37,45 @@ async function collectRuntime(dependencies, session, signal) {
30
37
  deviceSerial: session.target.deviceSerial,
31
38
  ...(signal === undefined ? {} : { signal })
32
39
  };
33
- const foreground = await dependencies.adb.foregroundComponent(identity);
34
- const pid = primaryAppPid(await dependencies.adb.appProcesses(identity), session.target.packageName);
35
- const layout = z.array(LayoutElementSchema).parse(await dependencies.androidCli.layout({
36
- deviceSerial: session.target.deviceSerial,
37
- ...(signal === undefined ? {} : { signal })
38
- }));
40
+ const [foregroundResult, processesResult, topologyResult, snapshotResult] = await Promise.allSettled([
41
+ dependencies.adb.foregroundComponent(identity),
42
+ dependencies.adb.appProcesses(identity),
43
+ dependencies.adb.windowTopology(identity),
44
+ dependencies.uiSnapshotProvider.capture({
45
+ reason: "evidence",
46
+ timeoutMs: dependencies.uiSnapshotTimeoutMs,
47
+ ...(signal === undefined ? {} : { signal })
48
+ })
49
+ ]);
50
+ const settledValue = (result) => {
51
+ if (result.status === "fulfilled") {
52
+ return result.value;
53
+ }
54
+ const reason = result.reason;
55
+ if (reason instanceof Error) {
56
+ throw reason;
57
+ }
58
+ throw new Error("Runtime observation failed");
59
+ };
60
+ const foreground = settledValue(foregroundResult);
61
+ const processes = settledValue(processesResult);
62
+ const topology = settledValue(topologyResult);
63
+ const uiSnapshot = settledValue(snapshotResult);
64
+ const pid = primaryAppPid(processes, session.target.packageName);
65
+ const layout = z.array(LayoutElementSchema).parse(uiSnapshot.roots);
39
66
  return {
40
67
  foregroundPackageName: foreground.packageName,
41
68
  activity: foreground.activity,
42
69
  pid,
43
- layout
70
+ layout,
71
+ uiSnapshot: {
72
+ observationId: uiSnapshot.observationId,
73
+ capturedAt: uiSnapshot.capturedAt,
74
+ durationMs: uiSnapshot.durationMs,
75
+ backend: uiSnapshot.backend,
76
+ viewport: uiSnapshot.viewport
77
+ },
78
+ windowHierarchy: assessWindowHierarchy(topology, layout)
44
79
  };
45
80
  }
46
81
  export class RuntimeObserver {
@@ -51,16 +86,101 @@ export class RuntimeObserver {
51
86
  observe = async (input) => {
52
87
  const current = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
53
88
  assertObservable(current);
54
- const runtime = await collectRuntime(this.dependencies, current, input.signal);
89
+ const idle = current.idlePolicy === undefined
90
+ ? input.idle
91
+ : current.idlePolicy;
92
+ const session = await this.dependencies.sessions.openSession({
93
+ deviceSerial: current.target.deviceSerial,
94
+ ...(input.signal === undefined ? {} : { signal: input.signal })
95
+ });
96
+ try {
97
+ const views = this.dependencies.sessionPorts(session);
98
+ const boundBackendSelection = uiBackendIdAsSelection(current.bindings.uiBackend.id);
99
+ const uiSnapshotProvider = await session.openUiSnapshots({
100
+ timeoutMs: idle?.timeoutMs ?? 5000,
101
+ ...(boundBackendSelection === undefined
102
+ ? {}
103
+ : { backend: boundBackendSelection }),
104
+ ...(this.dependencies.uiCacheEnabled === undefined
105
+ ? {}
106
+ : { cacheEnabled: this.dependencies.uiCacheEnabled }),
107
+ ...(input.signal === undefined ? {} : { signal: input.signal })
108
+ });
109
+ let runtime;
110
+ try {
111
+ if (JSON.stringify(current.bindings.uiBackend)
112
+ !== JSON.stringify(uiSnapshotProvider.descriptor)) {
113
+ throw new GenerationOperationError("CONFIG_INVALID", "Generation UI backend does not match the authoritative session");
114
+ }
115
+ if (idle !== undefined
116
+ && this.dependencies.waitUntilIdle !== undefined) {
117
+ const idleResult = await this.dependencies.waitUntilIdle(current.target.deviceSerial, idle, input.signal, current.target.packageName, uiStabilityProbe(uiSnapshotProvider, views.uiStability), views.adb);
118
+ if (idleResult.status !== "stable") {
119
+ throw new GenerationOperationError(idleResult.status === "cancelled" ? "RECOVERY_REQUIRED" : "IDLE_TIMEOUT", idleResult.status === "cancelled"
120
+ ? "Runtime observation was cancelled while waiting for layout stability"
121
+ : withIdleAdvice("Layout did not become stable before observation", idleResult), idleResult.status === "cancelled"
122
+ ? undefined
123
+ : {
124
+ idle: {
125
+ strategy: idleResult.strategy,
126
+ ...(idleResult.backend === undefined
127
+ ? {}
128
+ : { backend: idleResult.backend }),
129
+ polls: idleResult.polls,
130
+ durationMs: idleResult.durationMs,
131
+ samplingDurationMs: idleResult.samplingDurationMs,
132
+ fallbackUsed: idleResult.fallbackUsed,
133
+ frameActivityDetected: idleResult.frameActivityDetected,
134
+ lastDiff: idleResult.lastDiff
135
+ }
136
+ });
137
+ }
138
+ }
139
+ runtime = await collectRuntime({
140
+ adb: views.adb,
141
+ uiSnapshotProvider,
142
+ uiSnapshotTimeoutMs: this.dependencies.uiSnapshotTimeoutMs ?? 5000
143
+ }, current, input.signal);
144
+ }
145
+ finally {
146
+ await closeUiSnapshotProvider(uiSnapshotProvider);
147
+ }
148
+ return await this.commit(current, runtime, views, input.signal);
149
+ }
150
+ finally {
151
+ await session.close();
152
+ }
153
+ };
154
+ observeCollected = async (input) => {
155
+ const current = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
156
+ assertObservable(current);
157
+ if (input.runtime.foregroundPackageName !== current.target.packageName
158
+ || input.runtime.pid === null) {
159
+ throw new GenerationOperationError("SNAPSHOT_STALE", "Collected post-action runtime is not a valid target-app state");
160
+ }
161
+ const session = await this.dependencies.sessions.openSession({
162
+ deviceSerial: current.target.deviceSerial,
163
+ ...(input.signal === undefined ? {} : { signal: input.signal })
164
+ });
165
+ try {
166
+ const views = this.dependencies.sessionPorts(session);
167
+ return await this.commit(current, input.runtime, views, input.signal);
168
+ }
169
+ finally {
170
+ await session.close();
171
+ }
172
+ };
173
+ async commit(current, runtime, views, signal) {
55
174
  const baseRevision = current.revision + 1;
56
175
  const attemptId = GenerationSessionIdSchema.parse(this.dependencies.createAttemptId());
57
176
  const evidenceDirectory = `${revisionPath(baseRevision)}/${attemptId}`;
58
177
  const screenshotPath = `${evidenceDirectory}/screen.png`;
178
+ const snapshotPath = `${evidenceDirectory}/snapshot.json`;
59
179
  await this.dependencies.store.produceEvidence(current.id, screenshotPath, async (temporaryPath) => {
60
- const capture = await this.dependencies.androidCli.captureScreen({
180
+ const capture = await views.screenshots.capture({
61
181
  outputPath: temporaryPath,
62
182
  deviceSerial: current.target.deviceSerial,
63
- ...(input.signal === undefined ? {} : { signal: input.signal })
183
+ ...(signal === undefined ? {} : { signal })
64
184
  });
65
185
  if (failedCapture(capture)) {
66
186
  throw new Error(capture.stderr.trim()
@@ -68,8 +188,23 @@ export class RuntimeObserver {
68
188
  || "Runtime screenshot capture failed");
69
189
  }
70
190
  });
191
+ const identity = {
192
+ packageName: current.target.packageName,
193
+ deviceSerial: current.target.deviceSerial,
194
+ ...(signal === undefined ? {} : { signal })
195
+ };
196
+ const [confirmedForeground, confirmedProcesses] = await Promise.all([
197
+ views.adb.foregroundComponent(identity),
198
+ views.adb.appProcesses(identity)
199
+ ]);
200
+ const confirmedPid = primaryAppPid(confirmedProcesses, current.target.packageName);
201
+ if (confirmedForeground.packageName !== runtime.foregroundPackageName
202
+ || confirmedForeground.activity !== runtime.activity
203
+ || confirmedPid !== runtime.pid) {
204
+ throw new GenerationOperationError("SNAPSHOT_STALE", "Runtime identity changed while snapshot evidence was captured");
205
+ }
71
206
  const snapshot = RuntimeSnapshotSchema.parse({
72
- version: 1,
207
+ version: 2,
73
208
  generationId: current.id,
74
209
  baseRevision,
75
210
  deviceSerial: current.target.deviceSerial,
@@ -77,21 +212,28 @@ export class RuntimeObserver {
77
212
  foregroundPackageName: runtime.foregroundPackageName,
78
213
  activity: runtime.activity,
79
214
  pid: runtime.pid,
80
- capturedAt: this.dependencies.now().toISOString(),
215
+ capturedAt: runtime.uiSnapshot.capturedAt,
81
216
  screenshotPath,
82
- layout: runtime.layout
217
+ layout: runtime.layout,
218
+ windowHierarchy: runtime.windowHierarchy,
219
+ uiBackend: runtime.uiSnapshot.backend,
220
+ uiObservationId: runtime.uiSnapshot.observationId,
221
+ uiCaptureDurationMs: runtime.uiSnapshot.durationMs,
222
+ viewport: runtime.uiSnapshot.viewport
83
223
  });
84
224
  const snapshotHash = hashRuntimeSnapshot(snapshot);
85
- await this.dependencies.store.writeEvidence(current.id, `${evidenceDirectory}/snapshot.json`, snapshot);
225
+ await this.dependencies.store.writeEvidence(current.id, snapshotPath, snapshot);
86
226
  const next = GenerationSessionSchema.parse({
87
227
  ...current,
88
228
  revision: baseRevision,
89
229
  bindings: {
90
230
  ...current.bindings,
91
- snapshotHash
231
+ snapshotHash,
232
+ uiBackend: runtime.uiSnapshot.backend
92
233
  }
93
234
  });
94
235
  await this.dependencies.store.commitSnapshot(current.id, current.revision, next);
236
+ const snapshotRef = await this.dependencies.store.evidenceReference(current.id, snapshotPath);
95
237
  return {
96
238
  binding: {
97
239
  generationId: current.id,
@@ -99,16 +241,17 @@ export class RuntimeObserver {
99
241
  snapshotHash
100
242
  },
101
243
  snapshot,
102
- snapshotHash
244
+ snapshotHash,
245
+ snapshotRef
103
246
  };
104
- };
247
+ }
105
248
  }
106
249
  export class SnapshotReobservationGuard {
107
250
  dependencies;
108
251
  constructor(dependencies) {
109
252
  this.dependencies = dependencies;
110
253
  }
111
- assertFresh = async (input, signal, approvedConfirmation) => {
254
+ assertFresh = async (input, signal, approvedConfirmation, tolerance) => {
112
255
  try {
113
256
  const binding = ProposalBindingSchema.parse(input);
114
257
  const session = GenerationSessionSchema.parse(await this.dependencies.store.read(binding.generationId));
@@ -127,9 +270,17 @@ export class SnapshotReobservationGuard {
127
270
  !== JSON.stringify(approvedConfirmation)))) {
128
271
  throw new GenerationOperationError("SNAPSHOT_STALE", "Proposal snapshot binding is no longer authoritative");
129
272
  }
130
- const runtime = await collectRuntime(this.dependencies, session, signal);
273
+ if (JSON.stringify(session.bindings.uiBackend)
274
+ !== JSON.stringify(this.dependencies.uiSnapshotProvider.descriptor)) {
275
+ throw new GenerationOperationError("SNAPSHOT_STALE", "Generation UI backend changed after snapshot binding");
276
+ }
277
+ const runtime = await collectRuntime({
278
+ adb: this.dependencies.adb,
279
+ uiSnapshotProvider: this.dependencies.uiSnapshotProvider,
280
+ uiSnapshotTimeoutMs: this.dependencies.uiSnapshotTimeoutMs ?? 5000
281
+ }, session, signal);
131
282
  const snapshot = RuntimeSnapshotSchema.parse({
132
- version: 1,
283
+ version: 2,
133
284
  generationId: session.id,
134
285
  baseRevision: binding.baseRevision,
135
286
  deviceSerial: session.target.deviceSerial,
@@ -137,11 +288,29 @@ export class SnapshotReobservationGuard {
137
288
  foregroundPackageName: runtime.foregroundPackageName,
138
289
  activity: runtime.activity,
139
290
  pid: runtime.pid,
140
- capturedAt: this.dependencies.now().toISOString(),
291
+ capturedAt: runtime.uiSnapshot.capturedAt,
141
292
  screenshotPath: "non-authoritative://runtime-reobservation",
142
- layout: runtime.layout
293
+ layout: runtime.layout,
294
+ windowHierarchy: runtime.windowHierarchy,
295
+ uiBackend: runtime.uiSnapshot.backend,
296
+ uiObservationId: runtime.uiSnapshot.observationId,
297
+ uiCaptureDurationMs: runtime.uiSnapshot.durationMs,
298
+ viewport: runtime.uiSnapshot.viewport
143
299
  });
144
300
  if (hashRuntimeSnapshot(snapshot) !== binding.snapshotHash) {
301
+ // A targetless proposal (wait) does not consume the Layout, so a
302
+ // pure Layout change (for example a loading indicator that
303
+ // disappeared between binding and execution) is tolerated when the
304
+ // caller hands back the authoritative bound Snapshot and every
305
+ // other hashed field still matches. Any other drift stays
306
+ // fail-closed.
307
+ const bound = tolerance?.layoutChangeFrom;
308
+ if (bound !== undefined
309
+ && hashRuntimeSnapshot(bound) === binding.snapshotHash
310
+ && hashRuntimeSnapshot({ ...snapshot, layout: [] })
311
+ === hashRuntimeSnapshot({ ...bound, layout: [] })) {
312
+ return snapshot;
313
+ }
145
314
  throw new GenerationOperationError("SNAPSHOT_STALE", "Runtime snapshot changed after proposal");
146
315
  }
147
316
  return snapshot;
@@ -0,0 +1,32 @@
1
+ import { type ChangeSet, type ImpactSet } from "../../domain/impact.js";
2
+ import type { Journey } from "../../domain/journey.js";
3
+ import type { ProjectContextModule, ResolvedProjectContext } from "../../domain/project-context.js";
4
+ import type { LoadedKnowledgeBundle } from "../../ports/knowledge-registry.js";
5
+ export interface ImpactResolverDependencies {
6
+ loadContext: (input: {
7
+ projectRoot: string;
8
+ }) => Promise<{
9
+ context: ResolvedProjectContext;
10
+ modules: ProjectContextModule[];
11
+ }>;
12
+ loadKnowledge: (input: {
13
+ projectRoot: string;
14
+ packageName: string;
15
+ }) => Promise<LoadedKnowledgeBundle>;
16
+ listJourneyPaths: (input: {
17
+ projectRoot: string;
18
+ }) => Promise<readonly string[]>;
19
+ readJourney: (input: {
20
+ projectRoot: string;
21
+ path: string;
22
+ }) => Promise<Journey | null>;
23
+ }
24
+ export declare class ImpactResolver {
25
+ private readonly dependencies;
26
+ constructor(dependencies: ImpactResolverDependencies);
27
+ readonly resolve: (input: {
28
+ projectRoot: string;
29
+ packageName: string;
30
+ changeSet: ChangeSet;
31
+ }) => Promise<ImpactSet>;
32
+ }
@@ -0,0 +1,160 @@
1
+ import { createHash } from "node:crypto";
2
+ import { ImpactSetSchema } from "../../domain/impact.js";
3
+ function unique(values) {
4
+ return [...new Set(values)];
5
+ }
6
+ function contextEvidenceHash(context, modules) {
7
+ const canonicalModules = modules
8
+ .map((module) => ({
9
+ moduleId: module.moduleId,
10
+ projectDir: module.projectDir,
11
+ inventory: module.inventory,
12
+ manifest: module.manifest
13
+ }))
14
+ .sort((left, right) => left.moduleId.localeCompare(right.moduleId));
15
+ const canonical = JSON.stringify({
16
+ selection: context.selection,
17
+ modules: canonicalModules
18
+ });
19
+ return createHash("sha256").update(canonical).digest("hex");
20
+ }
21
+ function journeyAnchorIds(journey) {
22
+ return journey.steps
23
+ .map((step) => ("anchor" in step && step.anchor !== undefined ? step.anchor : undefined))
24
+ .filter((id) => id !== undefined);
25
+ }
26
+ function moduleForChangedFiles(modules, changeSet) {
27
+ const changed = changeSet.files.flatMap((file) => [
28
+ file.path,
29
+ ...(file.oldPath === undefined ? [] : [file.oldPath])
30
+ ]);
31
+ const result = [];
32
+ for (const module of modules) {
33
+ const evidencePaths = new Set(module.manifest.files.map((file) => file.path));
34
+ const touched = changed.some((path) => (evidencePaths.has(path)
35
+ || (module.projectDir !== "."
36
+ && path.startsWith(`${module.projectDir}/`))));
37
+ if (touched) {
38
+ result.push(module.moduleId);
39
+ }
40
+ }
41
+ return result;
42
+ }
43
+ export class ImpactResolver {
44
+ dependencies;
45
+ constructor(dependencies) {
46
+ this.dependencies = dependencies;
47
+ }
48
+ resolve = async (input) => {
49
+ const { projectRoot, packageName, changeSet } = input;
50
+ const [context, knowledge, journeyPaths] = await Promise.all([
51
+ this.dependencies.loadContext({
52
+ projectRoot
53
+ }),
54
+ this.dependencies.loadKnowledge({
55
+ projectRoot,
56
+ packageName
57
+ }),
58
+ this.dependencies.listJourneyPaths({
59
+ projectRoot
60
+ })
61
+ ]);
62
+ const contextModules = context.modules;
63
+ const changedPathSet = new Set(changeSet.files.flatMap((file) => [
64
+ file.path,
65
+ ...(file.oldPath === undefined ? [] : [file.oldPath])
66
+ ]));
67
+ const affectedModules = unique(moduleForChangedFiles(contextModules, changeSet));
68
+ const affectedAnchors = unique(knowledge.anchors
69
+ .filter((anchor) => ((anchor.sourceFiles ?? []).some((path) => changedPathSet.has(path))))
70
+ .map((anchor) => anchor.id));
71
+ const affectedAnchorsSet = new Set(affectedAnchors);
72
+ const affectedScreens = unique(knowledge.screens
73
+ .filter((screen) => ((screen.sourceFiles ?? []).some((path) => changedPathSet.has(path))
74
+ || screen.requiredAnchors.some((id) => affectedAnchorsSet.has(id))
75
+ || screen.optionalAnchors.some((id) => affectedAnchorsSet.has(id))
76
+ || screen.forbiddenAnchors.some((id) => affectedAnchorsSet.has(id))
77
+ || screen.predicates.some((predicate) => ("anchorId" in predicate
78
+ && affectedAnchorsSet.has(predicate.anchorId)))))
79
+ .map((screen) => screen.id));
80
+ const affectedScreensSet = new Set(affectedScreens);
81
+ const affectedModulesSet = new Set(affectedModules);
82
+ const affectedFeatures = unique(contextModules
83
+ .filter((module) => affectedModulesSet.has(module.moduleId))
84
+ .flatMap((module) => module.summary.features));
85
+ const p0 = [];
86
+ const p1 = [];
87
+ const p2 = [];
88
+ const skipped = [];
89
+ for (const path of journeyPaths) {
90
+ const journey = await this.dependencies.readJourney({
91
+ projectRoot,
92
+ path
93
+ });
94
+ if (journey === null) {
95
+ continue;
96
+ }
97
+ const anchorsInJourney = journeyAnchorIds(journey);
98
+ const directAnchor = anchorsInJourney.find((id) => (affectedAnchorsSet.has(id)));
99
+ if (directAnchor !== undefined) {
100
+ p0.push({
101
+ id: path,
102
+ reason: `journey resolves affected Knowledge anchor ${directAnchor}`
103
+ });
104
+ continue;
105
+ }
106
+ const affectedAnchorByScreen = anchorsInJourney.find((id) => (knowledge.screens.some((screen) => (affectedScreensSet.has(screen.id)
107
+ && (screen.requiredAnchors.includes(id)
108
+ || screen.optionalAnchors.includes(id)
109
+ || screen.forbiddenAnchors.includes(id))))));
110
+ if (affectedAnchorByScreen !== undefined) {
111
+ p1.push({
112
+ id: path,
113
+ reason: `journey anchors share a screen with the affected change ${affectedAnchorByScreen}`
114
+ });
115
+ continue;
116
+ }
117
+ if (anchorsInJourney.length === 0) {
118
+ if (affectedModules.length > 0) {
119
+ p1.push({
120
+ id: path,
121
+ reason: "affected module requires conservative coverage for a locator-only journey"
122
+ });
123
+ }
124
+ else {
125
+ skipped.push({
126
+ id: path,
127
+ reason: "journey uses only runtime locators; no semantic anchor binding"
128
+ });
129
+ }
130
+ continue;
131
+ }
132
+ if (affectedModules.length > 0) {
133
+ p1.push({
134
+ id: path,
135
+ reason: "affected module requires conservative semantic journey coverage"
136
+ });
137
+ continue;
138
+ }
139
+ p2.push({
140
+ id: path,
141
+ reason: "journey anchors do not resolve affected anchor/screen ids"
142
+ });
143
+ }
144
+ return ImpactSetSchema.parse({
145
+ version: 1,
146
+ base: changeSet.base,
147
+ head: changeSet.head,
148
+ affectedModules,
149
+ affectedFeatures,
150
+ affectedScreens,
151
+ affectedAnchors,
152
+ selectedJourneys: { p0, p1, p2 },
153
+ skippedJourneys: skipped,
154
+ provenance: {
155
+ contextHash: contextEvidenceHash(context.context, contextModules),
156
+ knowledgeHash: knowledge.knowledgeHash
157
+ }
158
+ });
159
+ };
160
+ }
@@ -9,34 +9,47 @@ export class InitService {
9
9
  if (input.agents.length === 0) {
10
10
  throw new NoAgentsSelectedError();
11
11
  }
12
- const targets = resolveTargetPaths(input.agents, input.global, this.deps.cwd, this.deps.homedir);
13
- const installedPaths = [];
14
- const skippedPaths = [];
15
- const allAgents = [];
12
+ const skillNames = await this.deps.installer.listSkillNames();
13
+ const targets = resolveTargetPaths(skillNames, input.agents, input.global, this.deps.cwd, this.deps.homedir);
14
+ const groupMap = new Map();
16
15
  for (const target of targets) {
17
- const result = await this.deps.installer.installTo(target.absolutePath);
16
+ const result = await this.deps.installer.installTo(target.skillName, target.absolutePath);
17
+ let group = groupMap.get(target.skillName);
18
+ if (group === undefined) {
19
+ group = { name: target.skillName, paths: [], skipped: [] };
20
+ groupMap.set(target.skillName, group);
21
+ }
18
22
  if (result.skipped) {
19
- skippedPaths.push(target.relativePath);
23
+ group.skipped.push(target.relativePath);
20
24
  }
21
25
  else {
22
- installedPaths.push(target.relativePath);
26
+ group.paths.push(target.relativePath);
23
27
  }
28
+ }
29
+ const allAgents = [];
30
+ for (const target of targets) {
24
31
  for (const agent of target.agents) {
25
32
  if (!allAgents.includes(agent)) {
26
33
  allAgents.push(agent);
27
34
  }
28
35
  }
29
36
  }
30
- const result = {
37
+ const skills = [...groupMap.values()].map((group) => {
38
+ const skill = {
39
+ name: group.name,
40
+ paths: group.paths
41
+ };
42
+ if (group.skipped.length > 0) {
43
+ skill.skipped = group.skipped;
44
+ }
45
+ return skill;
46
+ });
47
+ return {
31
48
  status: "installed",
32
49
  exitCode: 0,
33
50
  agents: allAgents,
34
- paths: installedPaths
51
+ skills
35
52
  };
36
- if (skippedPaths.length > 0) {
37
- return { ...result, skipped: skippedPaths };
38
- }
39
- return result;
40
53
  }
41
54
  }
42
55
  export function defaultHomedir() {
@@ -2,7 +2,7 @@ import type { FailureCode } from "../../domain/failure.js";
2
2
  import type { JourneyStep } from "../../domain/journey.js";
3
3
  import type { Bounds } from "../../domain/layout.js";
4
4
  import type { AdbPort } from "../../ports/adb.js";
5
- import type { Point } from "../../ports/android-cli.js";
5
+ import type { Point } from "../../domain/geometry.js";
6
6
  export interface ActionTarget {
7
7
  point: Point;
8
8
  bounds?: Bounds | undefined;
@@ -17,7 +17,8 @@ export type ActionExecutionResult = {
17
17
  export declare class ActionExecutor {
18
18
  private readonly adb;
19
19
  private readonly deviceSerial;
20
- constructor(adb: AdbPort, deviceSerial: string);
20
+ private readonly beforeMutation?;
21
+ constructor(adb: AdbPort, deviceSerial: string, beforeMutation?: (() => void) | undefined);
21
22
  execute(step: JourneyStep, target?: ActionTarget, signal?: AbortSignal): Promise<ActionExecutionResult>;
22
23
  swipeBounds(bounds: Bounds, direction: Extract<JourneyStep, {
23
24
  action: "swipe";
@@ -52,9 +52,11 @@ function swipePoints(bounds, direction, distancePercent) {
52
52
  export class ActionExecutor {
53
53
  adb;
54
54
  deviceSerial;
55
- constructor(adb, deviceSerial) {
55
+ beforeMutation;
56
+ constructor(adb, deviceSerial, beforeMutation) {
56
57
  this.adb = adb;
57
58
  this.deviceSerial = deviceSerial;
59
+ this.beforeMutation = beforeMutation;
58
60
  }
59
61
  async execute(step, target, signal) {
60
62
  let result;
@@ -63,15 +65,18 @@ export class ActionExecutor {
63
65
  if (target === undefined) {
64
66
  return failed("click requires a resolved target");
65
67
  }
68
+ this.beforeMutation?.();
66
69
  result = await this.adb.tap(target.point, this.deviceSerial, signal);
67
70
  break;
68
71
  case "longClick":
69
72
  if (target === undefined) {
70
73
  return failed("longClick requires a resolved target");
71
74
  }
75
+ this.beforeMutation?.();
72
76
  result = await this.adb.longClick(target.point, step.durationMs, this.deviceSerial, signal);
73
77
  break;
74
78
  case "inputText":
79
+ this.beforeMutation?.();
75
80
  result = await this.adb.inputText(step.text, this.deviceSerial, signal);
76
81
  break;
77
82
  case "swipe": {
@@ -82,12 +87,16 @@ export class ActionExecutor {
82
87
  return failed("swipe requires target bounds from a scrollable element");
83
88
  }
84
89
  const points = swipePoints(target.bounds, step.direction, step.distancePercent);
90
+ this.beforeMutation?.();
85
91
  result = await this.adb.swipe(points.from, points.to, step.durationMs, this.deviceSerial, signal);
86
92
  break;
87
93
  }
88
94
  case "scrollTo":
89
95
  return failed("scrollTo is not executed via ActionExecutor");
96
+ case "bridge":
97
+ return failed("bridge is not executed via ActionExecutor");
90
98
  case "back":
99
+ this.beforeMutation?.();
91
100
  result = await this.adb.back(this.deviceSerial, signal);
92
101
  break;
93
102
  case "wait":
@@ -97,6 +106,7 @@ export class ActionExecutor {
97
106
  }
98
107
  async swipeBounds(bounds, direction, distancePercent, durationMs, signal) {
99
108
  const points = swipePoints(bounds, direction, distancePercent);
109
+ this.beforeMutation?.();
100
110
  const result = await this.adb.swipe(points.from, points.to, durationMs, this.deviceSerial, signal);
101
111
  return commandResult(result);
102
112
  }
@@ -0,0 +1,17 @@
1
+ import type { DisplayViewport } from "../../domain/geometry.js";
2
+ import type { LayoutElement, Locator } from "../../domain/layout.js";
3
+ import { type LocatedTarget, type LocatorFailure } from "../locator/locator-resolver.js";
4
+ import type { ActionTarget } from "./action-executor.js";
5
+ export type TargetedAction = "click" | "longClick" | "swipe";
6
+ export type ActionTargetResolution = {
7
+ status: "found";
8
+ target: ActionTarget;
9
+ located: LocatedTarget;
10
+ } | LocatorFailure;
11
+ /**
12
+ * The element an action acts on, with the capability semantics Generation,
13
+ * generated Replay, and External Flow steps share: a click or longClick
14
+ * reaches the nearest ancestor with that capability (touching the matched
15
+ * element itself), and a swipe needs a scrollable element with bounds.
16
+ */
17
+ export declare function resolveActionTarget(layout: readonly LayoutElement[], action: TargetedAction, locator: Locator, viewport: DisplayViewport | undefined): ActionTargetResolution;