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,415 @@
1
+ import { createHash } from "node:crypto";
2
+ import { matchesLogcatEvent } from "../collector/logcat-event.js";
3
+ import { resolveLocatorIdentity } from "../locator/locator-resolver.js";
4
+ import { ScreenDetector } from "../recognition/screen-detector.js";
5
+ function errorMessage(error) {
6
+ return error instanceof Error ? error.message : String(error);
7
+ }
8
+ function unresolvedConditions(expect, message) {
9
+ return [
10
+ ...(expect.activity === undefined ? [] : [{
11
+ kind: "activity",
12
+ status: "unresolved",
13
+ expected: expect.activity,
14
+ message
15
+ }]),
16
+ ...(expect.screen === undefined ? [] : [{
17
+ kind: "screen",
18
+ status: "unresolved",
19
+ expected: expect.screen,
20
+ message
21
+ }]),
22
+ ...expect.visibleElements.map((locator) => ({
23
+ kind: "visibleElement",
24
+ status: "unresolved",
25
+ locator,
26
+ message
27
+ })),
28
+ ...expect.absentElements.map((locator) => ({
29
+ kind: "absentElement",
30
+ status: "unresolved",
31
+ locator,
32
+ message
33
+ }))
34
+ ];
35
+ }
36
+ function checkpointResult(checkpoint, conditions, matchedScreen) {
37
+ const status = conditions.some((condition) => condition.status === "failed")
38
+ ? "failed"
39
+ : conditions.some((condition) => condition.status === "unresolved")
40
+ ? "unresolved"
41
+ : "passed";
42
+ return {
43
+ report: {
44
+ id: checkpoint.id,
45
+ ...(checkpoint.stepIndex === undefined ? {} : { stepIndex: checkpoint.stepIndex }),
46
+ status,
47
+ conditions
48
+ },
49
+ ...(matchedScreen === undefined ? {} : { matchedScreen })
50
+ };
51
+ }
52
+ export class CheckpointEvaluator {
53
+ detector = new ScreenDetector();
54
+ observeUi = async (input, expect) => {
55
+ let snapshot;
56
+ try {
57
+ snapshot = await input.provider.capture({
58
+ reason: "evidence",
59
+ freshness: "forceFresh",
60
+ timeoutMs: input.timeoutMs,
61
+ ...(input.signal === undefined ? {} : { signal: input.signal })
62
+ });
63
+ }
64
+ catch (error) {
65
+ return {
66
+ conditions: unresolvedConditions(expect, `Checkpoint layout unavailable: ${errorMessage(error)}`)
67
+ };
68
+ }
69
+ let foreground;
70
+ try {
71
+ foreground = await input.adb.foregroundComponent({
72
+ packageName: input.packageName,
73
+ deviceSerial: input.deviceSerial,
74
+ timeoutMs: input.timeoutMs,
75
+ ...(input.signal === undefined ? {} : { signal: input.signal })
76
+ });
77
+ }
78
+ catch (error) {
79
+ return {
80
+ conditions: unresolvedConditions(expect, `Checkpoint foreground unavailable: ${errorMessage(error)}`)
81
+ };
82
+ }
83
+ if (foreground.packageName !== input.packageName) {
84
+ return {
85
+ conditions: unresolvedConditions(expect, `Checkpoint foreground package ${foreground.packageName} is not ${input.packageName}`)
86
+ };
87
+ }
88
+ const activity = foreground.activity;
89
+ const conditions = [];
90
+ if (expect.activity !== undefined) {
91
+ const expected = expect.activity;
92
+ conditions.push({
93
+ kind: "activity",
94
+ status: activity === expected ? "passed" : "failed",
95
+ expected,
96
+ actual: activity
97
+ });
98
+ }
99
+ let matchedScreen;
100
+ if (expect.screen !== undefined) {
101
+ const expected = expect.screen;
102
+ if (input.knowledge === undefined
103
+ || input.knowledge.index.packageName !== input.packageName) {
104
+ conditions.push({
105
+ kind: "screen",
106
+ status: "unresolved",
107
+ expected,
108
+ message: input.knowledgeError ?? (input.knowledge === undefined
109
+ ? "Project Knowledge is unavailable"
110
+ : "Project Knowledge belongs to another package")
111
+ });
112
+ }
113
+ else if (!input.knowledge.screens.some((screen) => screen.id === expected)) {
114
+ conditions.push({
115
+ kind: "screen",
116
+ status: "unresolved",
117
+ expected,
118
+ message: `Screen ${expected} is not defined in Project Knowledge`
119
+ });
120
+ }
121
+ else {
122
+ const runtimeSnapshot = {
123
+ activity,
124
+ layout: [...snapshot.roots]
125
+ };
126
+ try {
127
+ const detection = this.detector.detect({
128
+ snapshot: runtimeSnapshot,
129
+ anchors: input.knowledge.anchors,
130
+ screens: input.knowledge.screens
131
+ });
132
+ if (detection.status === "matched") {
133
+ matchedScreen = detection.screenId;
134
+ conditions.push({
135
+ kind: "screen",
136
+ status: matchedScreen === expected ? "passed" : "failed",
137
+ expected,
138
+ actual: matchedScreen
139
+ });
140
+ }
141
+ else {
142
+ conditions.push({
143
+ kind: "screen",
144
+ status: "unresolved",
145
+ expected,
146
+ message: detection.status === "ambiguous"
147
+ ? `Screen detection is ambiguous: ${detection.screenIds.join(", ")}`
148
+ : "Screen detection could not identify a screen"
149
+ });
150
+ }
151
+ }
152
+ catch (error) {
153
+ conditions.push({
154
+ kind: "screen",
155
+ status: "unresolved",
156
+ expected,
157
+ message: `Screen detection failed: ${errorMessage(error)}`
158
+ });
159
+ }
160
+ }
161
+ }
162
+ for (const [kind, locators] of [
163
+ ["visibleElement", expect.visibleElements],
164
+ ["absentElement", expect.absentElements]
165
+ ]) {
166
+ for (const locator of locators) {
167
+ const resolution = resolveLocatorIdentity(snapshot.roots, locator);
168
+ if (resolution.status === "found") {
169
+ conditions.push({
170
+ kind,
171
+ locator,
172
+ status: kind === "visibleElement" ? "passed" : "failed"
173
+ });
174
+ }
175
+ else if (resolution.code === "LOCATOR_AMBIGUOUS"
176
+ || resolution.evidenceMismatch === true
177
+ || (resolution.code !== "LOCATOR_NOT_FOUND")) {
178
+ conditions.push({
179
+ kind,
180
+ locator,
181
+ status: "unresolved",
182
+ message: resolution.message
183
+ });
184
+ }
185
+ else {
186
+ conditions.push({
187
+ kind,
188
+ locator,
189
+ status: kind === "absentElement" ? "passed" : "failed",
190
+ ...(kind === "visibleElement" ? { message: resolution.message } : {})
191
+ });
192
+ }
193
+ }
194
+ }
195
+ return { conditions, matchedScreen, snapshot };
196
+ };
197
+ evaluate = async (input) => {
198
+ const { checkpoint, clock, logcat } = input;
199
+ const allOf = checkpoint.expect.allOf;
200
+ const startedAtMs = clock?.now() ?? 0;
201
+ const timeoutMs = checkpoint.expect.timeoutMs;
202
+ const deadline = startedAtMs + timeoutMs;
203
+ const uiConditions = allOf.filter((condition) => condition.kind !== "logcatEvent");
204
+ const activityCondition = uiConditions.find((condition) => condition.kind === "activity");
205
+ const screenCondition = uiConditions.find((condition) => condition.kind === "screen");
206
+ const uiExpect = {
207
+ ...(activityCondition?.kind === "activity" ? { activity: activityCondition.expected } : {}),
208
+ ...(screenCondition?.kind === "screen" ? { screen: screenCondition.expected } : {}),
209
+ visibleElements: uiConditions.flatMap((condition) => (condition.kind === "visibleElement" ? [condition.locator] : [])),
210
+ absentElements: uiConditions.flatMap((condition) => (condition.kind === "absentElement" ? [condition.locator] : []))
211
+ };
212
+ const observed = new Map();
213
+ let matchedScreen;
214
+ const identity = (condition) => JSON.stringify([
215
+ condition.kind,
216
+ condition.kind === "activity" || condition.kind === "screen"
217
+ ? condition.expected
218
+ : condition.kind === "logcatEvent" ? condition.expect : condition.locator
219
+ ]);
220
+ const buildReport = () => {
221
+ const conditions = allOf.map((condition, index) => (observed.get(index) ?? (condition.kind === "logcatEvent"
222
+ ? {
223
+ kind: "logcatEvent",
224
+ expect: condition.expect,
225
+ status: "failed",
226
+ matchedCount: 0,
227
+ startedAtMs,
228
+ message: "Logcat event did not appear before the shared timeout"
229
+ }
230
+ : {
231
+ ...condition,
232
+ status: "failed",
233
+ startedAtMs,
234
+ message: "Condition did not match before the shared timeout"
235
+ })));
236
+ return checkpointResult(checkpoint, conditions, matchedScreen);
237
+ };
238
+ const unresolved = (message) => checkpointResult(checkpoint, allOf.map((condition) => condition.kind === "logcatEvent"
239
+ ? {
240
+ kind: "logcatEvent", expect: condition.expect,
241
+ status: "unresolved", matchedCount: 0, startedAtMs, message
242
+ }
243
+ : { ...condition, status: "unresolved", startedAtMs, message }));
244
+ if (clock === undefined || timeoutMs <= 0) {
245
+ const conditions = allOf.map((condition) => (condition.kind === "logcatEvent"
246
+ ? {
247
+ kind: "logcatEvent", expect: condition.expect,
248
+ status: "unresolved", matchedCount: 0, startedAtMs,
249
+ message: "Checkpoint event clock is unavailable"
250
+ }
251
+ : { ...condition, status: "unresolved", startedAtMs,
252
+ message: "Checkpoint observation clock is unavailable" }));
253
+ return checkpointResult(checkpoint, conditions);
254
+ }
255
+ // Even a Logcat-only Checkpoint requires one fresh layout and a valid
256
+ // foreground package before it can assert application evidence.
257
+ if (uiConditions.length === 0) {
258
+ try {
259
+ await input.provider.capture({
260
+ reason: "evidence",
261
+ freshness: "forceFresh",
262
+ timeoutMs: Math.min(input.timeoutMs, timeoutMs),
263
+ ...(input.signal === undefined ? {} : { signal: input.signal })
264
+ });
265
+ const foreground = await input.adb.foregroundComponent({
266
+ packageName: input.packageName,
267
+ deviceSerial: input.deviceSerial,
268
+ timeoutMs: Math.max(1, Math.min(input.timeoutMs, deadline - clock.now())),
269
+ ...(input.signal === undefined ? {} : { signal: input.signal })
270
+ });
271
+ if (foreground.packageName !== input.packageName) {
272
+ return unresolved(`Checkpoint target app is not foreground: ${foreground.packageName}`);
273
+ }
274
+ }
275
+ catch (error) {
276
+ return unresolved(`Checkpoint UI or foreground unavailable: ${errorMessage(error)}`);
277
+ }
278
+ }
279
+ for (;;) {
280
+ if (input.signal?.aborted === true) {
281
+ return unresolved("Checkpoint was cancelled");
282
+ }
283
+ const now = clock.now();
284
+ const remaining = Math.max(1, deadline - now);
285
+ if (uiConditions.length === 0) {
286
+ try {
287
+ const foreground = await input.adb.foregroundComponent({
288
+ packageName: input.packageName,
289
+ deviceSerial: input.deviceSerial,
290
+ timeoutMs: Math.min(input.timeoutMs, remaining),
291
+ ...(input.signal === undefined ? {} : { signal: input.signal })
292
+ });
293
+ if (foreground.packageName !== input.packageName) {
294
+ return unresolved(`Checkpoint target app is not foreground: ${foreground.packageName}`);
295
+ }
296
+ }
297
+ catch (error) {
298
+ return unresolved(`Checkpoint foreground unavailable: ${errorMessage(error)}`);
299
+ }
300
+ }
301
+ if (uiConditions.some((condition) => observed.get(allOf.indexOf(condition))?.status !== "passed")) {
302
+ const ui = await this.observeUi({
303
+ ...input,
304
+ timeoutMs: Math.min(input.timeoutMs, remaining)
305
+ }, uiExpect);
306
+ const uiObservedAtMs = clock.now();
307
+ if (ui.matchedScreen !== undefined) {
308
+ matchedScreen = ui.matchedScreen;
309
+ }
310
+ for (const [index, condition] of allOf.entries()) {
311
+ if (condition.kind === "logcatEvent"
312
+ || observed.get(index)?.status === "passed") {
313
+ continue;
314
+ }
315
+ const matching = ui.conditions.find((entry) => (identity(entry) === identity({
316
+ ...condition,
317
+ status: "passed"
318
+ })));
319
+ if (matching === undefined) {
320
+ return unresolved("Checkpoint UI observation did not cover every condition");
321
+ }
322
+ if (matching.status === "unresolved") {
323
+ return unresolved(matching.message ?? "Checkpoint UI evidence is unresolved");
324
+ }
325
+ if (uiObservedAtMs > deadline && matching.status === "passed") {
326
+ observed.set(index, {
327
+ ...matching,
328
+ status: "failed",
329
+ startedAtMs,
330
+ message: "UI condition matched after the shared timeout"
331
+ });
332
+ continue;
333
+ }
334
+ let evidenceRef;
335
+ if (input.writeSnapshot !== undefined && ui.snapshot !== undefined
336
+ && (matching.status === "passed" || clock.now() >= deadline)) {
337
+ evidenceRef = `checkpoints/${checkpoint.id}-${String(index)}-ui.json`;
338
+ try {
339
+ await input.writeSnapshot(evidenceRef, ui.snapshot);
340
+ }
341
+ catch (error) {
342
+ return unresolved(`Checkpoint UI artifact unavailable: ${errorMessage(error)}`);
343
+ }
344
+ }
345
+ observed.set(index, {
346
+ ...matching,
347
+ startedAtMs,
348
+ ...(matching.status === "passed" ? { matchedAtMs: uiObservedAtMs } : {}),
349
+ ...(evidenceRef === undefined ? {} : { evidenceRef })
350
+ });
351
+ }
352
+ }
353
+ for (const [index, condition] of allOf.entries()) {
354
+ if (condition.kind !== "logcatEvent") {
355
+ continue;
356
+ }
357
+ const window = condition.expect.window;
358
+ const windowStart = window.from === "stepStart"
359
+ ? input.stepStartedAt
360
+ : window.from === "runStart" ? input.runStartedAt
361
+ : input.markers?.get(window.markerId);
362
+ if (windowStart === undefined || logcat === undefined
363
+ || !logcat.completeSince(windowStart)) {
364
+ observed.set(index, {
365
+ kind: "logcatEvent", expect: condition.expect, status: "unresolved",
366
+ matchedCount: 0, startedAtMs,
367
+ message: "Checkpoint Logcat window is unavailable or incomplete"
368
+ });
369
+ continue;
370
+ }
371
+ const matches = logcat.linesBetween(windowStart, Math.min(clock.now(), deadline))
372
+ .filter((line) => matchesLogcatEvent(line, {
373
+ ...condition.expect,
374
+ timeoutMs
375
+ }));
376
+ const first = matches[0];
377
+ observed.set(index, {
378
+ kind: "logcatEvent",
379
+ expect: condition.expect,
380
+ status: matches.length > 1 ? "failed"
381
+ : matches.length === 1 ? "passed" : "failed",
382
+ matchedCount: matches.length,
383
+ startedAtMs: windowStart,
384
+ ...(first === undefined || matches.length !== 1 ? {} : {
385
+ matchedLineSha256: createHash("sha256")
386
+ .update(first.raw).digest("hex"),
387
+ matchedAtMs: first.receivedAt
388
+ }),
389
+ ...(input.logcatEvidenceRef === undefined ? {} : {
390
+ evidenceRef: input.logcatEvidenceRef
391
+ }),
392
+ ...(matches.length > 1 ? { message: "Logcat event is not unique" } : {})
393
+ });
394
+ }
395
+ if ([...observed.values()].some((condition) => (condition.status === "unresolved"
396
+ || (condition.kind === "logcatEvent" && condition.matchedCount > 1)))) {
397
+ return buildReport();
398
+ }
399
+ const allPassed = observed.size === allOf.length
400
+ && [...observed.values()].every((condition) => condition.status === "passed");
401
+ if (allPassed && !allOf.some((condition) => condition.kind === "logcatEvent")) {
402
+ return buildReport();
403
+ }
404
+ if (clock.now() >= deadline) {
405
+ return buildReport();
406
+ }
407
+ try {
408
+ await clock.sleep(Math.min(100, deadline - clock.now()), input.signal);
409
+ }
410
+ catch (error) {
411
+ return unresolved(`Checkpoint polling was interrupted: ${errorMessage(error)}`);
412
+ }
413
+ }
414
+ };
415
+ }
@@ -0,0 +1,18 @@
1
+ import type { Baseline, RegressionCompareResult } from "../../domain/checkpoint.js";
2
+ import type { TapHoundReport } from "../../domain/report.js";
3
+ export interface RegressionCompareInput {
4
+ baseline: Baseline;
5
+ current: Pick<TapHoundReport, "steps" | "screens" | "checkpoints" | "logcatEvidence">;
6
+ journeySha256: string;
7
+ comparedAt: string;
8
+ }
9
+ /**
10
+ * Deterministic Regression Comparator (architecture doc §16.1): is current
11
+ * behavior still equivalent to the known-good Baseline?
12
+ *
13
+ * `equivalent: true` only when every baseline activity fact and element fact
14
+ * is reproduced. A drift yields one `RegressionDiff` entry per fact with
15
+ * `expected` (baseline) vs `actual` (current). This comparator is pure and
16
+ * never calls a model; ambiguity is the job of the escalation policy.
17
+ */
18
+ export declare const compareRegression: (input: RegressionCompareInput) => RegressionCompareResult;
@@ -0,0 +1,192 @@
1
+ import { BaselineSchema, RegressionCompareResultSchema } from "../../domain/checkpoint.js";
2
+ import { BaselineError } from "./baseline-error.js";
3
+ function currentActivities(steps) {
4
+ const map = new Map();
5
+ for (const step of steps) {
6
+ map.set(step.index, {
7
+ before: step.activity?.before.actual,
8
+ after: step.activity?.after.actual
9
+ });
10
+ }
11
+ return map;
12
+ }
13
+ function elementIdentity(fact) {
14
+ return fact.anchorId === undefined
15
+ ? JSON.stringify(["locator", fact.locator])
16
+ : JSON.stringify(["anchor", fact.anchorId]);
17
+ }
18
+ function conditionIdentity(fact) {
19
+ return JSON.stringify([
20
+ fact.kind,
21
+ "locator" in fact ? fact.locator
22
+ : "expect" in fact ? fact.expect : fact.expected
23
+ ]);
24
+ }
25
+ function reportConditionIdentity(condition) {
26
+ return JSON.stringify([
27
+ condition.kind,
28
+ "locator" in condition ? condition.locator
29
+ : "expect" in condition ? condition.expect : condition.expected
30
+ ]);
31
+ }
32
+ /**
33
+ * Deterministic Regression Comparator (architecture doc §16.1): is current
34
+ * behavior still equivalent to the known-good Baseline?
35
+ *
36
+ * `equivalent: true` only when every baseline activity fact and element fact
37
+ * is reproduced. A drift yields one `RegressionDiff` entry per fact with
38
+ * `expected` (baseline) vs `actual` (current). This comparator is pure and
39
+ * never calls a model; ambiguity is the job of the escalation policy.
40
+ */
41
+ export const compareRegression = (input) => {
42
+ BaselineSchema.parse(input.baseline);
43
+ if (input.baseline.screens.some((fact) => fact.status !== "matched")) {
44
+ throw new BaselineError("BASELINE_INCOMPARABLE", "An unresolved Screen fact cannot establish equivalence");
45
+ }
46
+ const regressions = [];
47
+ const currentActs = currentActivities(input.current.steps);
48
+ for (const fact of input.baseline.activities) {
49
+ const actual = currentActs.get(fact.stepIndex);
50
+ if (actual === undefined) {
51
+ regressions.push({
52
+ kind: "activity",
53
+ stepIndex: fact.stepIndex,
54
+ expected: `before ${fact.before}`,
55
+ actual: "missing"
56
+ });
57
+ continue;
58
+ }
59
+ if (actual.before !== fact.before) {
60
+ regressions.push({
61
+ kind: "activity",
62
+ stepIndex: fact.stepIndex,
63
+ expected: `before ${fact.before}`,
64
+ actual: `before ${actual.before ?? "missing"}`
65
+ });
66
+ }
67
+ if (actual.after !== fact.after) {
68
+ regressions.push({
69
+ kind: "activity",
70
+ stepIndex: fact.stepIndex,
71
+ expected: `after ${fact.after}`,
72
+ actual: `after ${actual.after ?? "missing"}`
73
+ });
74
+ }
75
+ }
76
+ for (const fact of input.baseline.elements) {
77
+ const stepIndex = fact.stepIndex;
78
+ const current = input.current.steps.find((step) => step.index === stepIndex)?.locator;
79
+ if (current?.status === "found" && (current.anchorId === undefined
80
+ && current.requested === undefined)) {
81
+ throw new BaselineError("BASELINE_INCOMPARABLE", `Current locator at step ${String(stepIndex)} has no stable identity`);
82
+ }
83
+ if (current?.status !== "found"
84
+ || elementIdentity({
85
+ anchorId: current.anchorId,
86
+ locator: current.requested
87
+ }) !== elementIdentity(fact)) {
88
+ regressions.push({
89
+ kind: "element",
90
+ ...(fact.locator === undefined ? {} : { locator: fact.locator }),
91
+ stepIndex,
92
+ expected: `${fact.kind} element`,
93
+ actual: current?.status === "found"
94
+ ? "different element"
95
+ : "missing"
96
+ });
97
+ continue;
98
+ }
99
+ if (fact.matchedBy !== undefined && current.matchedBy !== fact.matchedBy) {
100
+ regressions.push({
101
+ kind: "element",
102
+ ...(fact.locator === undefined ? {} : { locator: fact.locator }),
103
+ stepIndex,
104
+ expected: `matched by ${fact.matchedBy}`,
105
+ actual: `matched by ${current.matchedBy ?? "none"}`
106
+ });
107
+ }
108
+ if (fact.fallbackUsed !== undefined
109
+ && fact.fallbackUsed !== current.fallbackUsed) {
110
+ regressions.push({
111
+ kind: "element",
112
+ ...(fact.locator === undefined ? {} : { locator: fact.locator }),
113
+ stepIndex,
114
+ expected: `annotated fallback ${String(fact.fallbackUsed)}`,
115
+ actual: `annotated fallback ${String(current.fallbackUsed)}`
116
+ });
117
+ }
118
+ }
119
+ const currentScreens = new Map((input.current.screens ?? []).map((screen) => [
120
+ screen.screen, screen.status
121
+ ]));
122
+ for (const fact of input.baseline.screens) {
123
+ const currentStatus = currentScreens.get(fact.screen);
124
+ if (currentStatus !== fact.status) {
125
+ regressions.push({
126
+ kind: "screen",
127
+ screen: fact.screen,
128
+ expected: fact.status,
129
+ actual: currentStatus ?? "missing"
130
+ });
131
+ }
132
+ }
133
+ const checkpointFacts = input.baseline.checkpoints ?? [];
134
+ const checkpointIds = new Set(checkpointFacts.map((fact) => fact.checkpointId));
135
+ for (const id of checkpointIds) {
136
+ const baselineConditions = checkpointFacts.filter((fact) => fact.checkpointId === id);
137
+ const matches = (input.current.checkpoints ?? []).filter((entry) => entry.id === id);
138
+ const checkpoint = matches[0];
139
+ if (matches.length !== 1 || checkpoint === undefined) {
140
+ throw new BaselineError("BASELINE_INCOMPARABLE", `Checkpoint ${id} has no unique current evaluation`);
141
+ }
142
+ if (checkpoint.stepIndex !== baselineConditions[0]?.stepIndex
143
+ || checkpoint.conditions.length !== baselineConditions.length
144
+ || checkpoint.conditions.some((condition) => !baselineConditions.some((fact) => conditionIdentity(fact) === reportConditionIdentity(condition)))) {
145
+ throw new BaselineError("BASELINE_INCOMPARABLE", `Checkpoint ${id} does not have the same condition identities`);
146
+ }
147
+ for (const fact of baselineConditions) {
148
+ const condition = checkpoint.conditions.find((entry) => (conditionIdentity(fact) === reportConditionIdentity(entry)));
149
+ if (condition?.status === "unresolved"
150
+ || (condition?.kind === "logcatEvent" && condition.status === "passed"
151
+ && (condition.matchedCount !== 1
152
+ || condition.matchedLineSha256 === undefined
153
+ || condition.matchedAtMs === undefined
154
+ || condition.evidenceRef === undefined))
155
+ || (fact.kind === "logcatEvent"
156
+ && input.current.logcatEvidence?.some((entry) => (entry.lastDroppedAtMs === undefined
157
+ || (condition?.kind === "logcatEvent"
158
+ && entry.lastDroppedAtMs >= condition.startedAtMs))) === true)) {
159
+ throw new BaselineError("BASELINE_INCOMPARABLE", `Checkpoint ${id} has unresolved current evidence`);
160
+ }
161
+ if (condition?.status !== "passed") {
162
+ regressions.push({
163
+ kind: fact.kind === "activity"
164
+ ? "activity"
165
+ : fact.kind === "screen" ? "screen"
166
+ : fact.kind === "logcatEvent" ? "logcatEvent" : "element",
167
+ checkpointId: id,
168
+ ...(fact.stepIndex === undefined ? {} : { stepIndex: fact.stepIndex }),
169
+ ...("locator" in fact ? { locator: fact.locator } : {}),
170
+ ...(fact.kind === "screen" ? { screen: fact.expected } : {}),
171
+ expected: `passed ${fact.kind}`,
172
+ actual: condition?.status ?? "missing"
173
+ });
174
+ }
175
+ }
176
+ }
177
+ const result = RegressionCompareResultSchema.parse({
178
+ version: 1,
179
+ baselineId: input.baseline.id,
180
+ journeySha256: input.journeySha256,
181
+ comparedAt: input.comparedAt,
182
+ coverage: {
183
+ activities: input.baseline.activities.length,
184
+ elements: input.baseline.elements.length,
185
+ screens: input.baseline.screens.length,
186
+ ...(checkpointFacts.length === 0 ? {} : { checkpoints: checkpointFacts.length })
187
+ },
188
+ equivalent: regressions.length === 0,
189
+ regressions
190
+ });
191
+ return result;
192
+ };
@@ -4,6 +4,8 @@ import type { CommandResult } from "../../ports/process-runner.js";
4
4
  export type LogLevel = "V" | "D" | "I" | "W" | "E" | "F" | "A";
5
5
  export interface LogcatLine {
6
6
  receivedAt: number;
7
+ /** Device threadtime timestamp without a year; receivedAt remains the monotonic window clock. */
8
+ deviceTimestamp?: string | undefined;
7
9
  raw: string;
8
10
  pid?: number | undefined;
9
11
  tid?: number | undefined;
@@ -14,25 +16,44 @@ export interface LogcatLine {
14
16
  export interface LogcatMetadata {
15
17
  deviceSerial: string;
16
18
  pids: readonly number[];
19
+ droppedLines?: number | undefined;
20
+ droppedBytes?: number | undefined;
21
+ lastDroppedAtMs?: number | undefined;
17
22
  }
18
23
  export interface StartLogcatOptions {
19
24
  deviceSerial: string;
25
+ pids?: readonly number[] | undefined;
20
26
  signal?: AbortSignal | undefined;
21
27
  }
22
28
  export declare class LogcatCollector {
23
29
  private readonly adb;
24
30
  private readonly clock;
31
+ private readonly limits;
32
+ /** Live lines are `collected[head..]`; dropped lines are compacted lazily. */
25
33
  private readonly collected;
34
+ private head;
35
+ private bufferedBytes;
36
+ private readonly droppedByPid;
26
37
  private readonly stderr;
27
38
  private readonly scopedPids;
28
39
  private running?;
29
40
  private streamMetadata?;
30
41
  private stopPromise?;
31
- constructor(adb: AdbPort, clock: Clock);
42
+ constructor(adb: AdbPort, clock: Clock, limits?: {
43
+ maxLines: number;
44
+ maxBytes: number;
45
+ });
46
+ private append;
47
+ private retained;
48
+ private addScopedPids;
49
+ private droppedEvidence;
32
50
  start(options: StartLogcatOptions): Promise<void>;
33
51
  scopeToPids(pids: readonly number[]): void;
34
52
  metadata(): LogcatMetadata;
35
53
  lines(): readonly LogcatLine[];
54
+ /** Includes unparsed lines as raw artifacts, within the declared buffer limit. */
55
+ rawLines(): readonly LogcatLine[];
56
+ completeSince(startedAt: number): boolean;
36
57
  diagnosticLines(): readonly string[];
37
58
  linesBetween(startedAt: number, finishedAt: number): LogcatLine[];
38
59
  stop(): Promise<CommandResult>;