taphound 0.2.0-dev.1 → 0.2.0-dev.12

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 (467) 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 +507 -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 +578 -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 +357 -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 +42 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +309 -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/diagnostics-journal.d.ts +17 -0
  73. package/dist/adapters/filesystem/diagnostics-journal.js +130 -0
  74. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  75. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  76. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  77. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  78. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  79. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  80. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  81. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  82. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  83. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  84. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  85. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  86. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  87. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  88. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  89. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  90. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  91. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  92. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  93. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  94. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  95. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  96. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  97. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  98. package/dist/adapters/filesystem/skill-installer.js +40 -11
  99. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  100. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  101. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  102. package/dist/adapters/git/node-git-diff.js +114 -0
  103. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  104. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  105. package/dist/adapters/process/node-process-runner.js +11 -2
  106. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  107. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  108. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  109. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  110. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  111. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  112. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  113. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  114. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  115. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  116. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  122. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  123. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  124. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  125. package/dist/adapters/runtime/session-adb-view.js +193 -0
  126. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  127. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  128. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  129. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  130. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  131. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  132. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  133. package/dist/adapters/ui/device-layout-temp.js +18 -0
  134. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  135. package/dist/adapters/ui/device-ui-environment.js +81 -0
  136. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  137. package/dist/adapters/ui/layout-normalization.js +44 -0
  138. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  139. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  140. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  141. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  142. package/dist/application/align/align-service.d.ts +42 -0
  143. package/dist/application/align/align-service.js +106 -0
  144. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  145. package/dist/application/assertion/expectation-evaluator.js +156 -18
  146. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  147. package/dist/application/assertion/guarded-expectation.js +74 -0
  148. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  149. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  150. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  151. package/dist/application/checkpoint/baseline-error.js +8 -0
  152. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  153. package/dist/application/checkpoint/baseline-service.js +147 -0
  154. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  155. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  156. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  157. package/dist/application/checkpoint/regression-comparator.js +192 -0
  158. package/dist/application/collector/logcat-collector.d.ts +22 -1
  159. package/dist/application/collector/logcat-collector.js +103 -15
  160. package/dist/application/collector/logcat-event.d.ts +8 -0
  161. package/dist/application/collector/logcat-event.js +79 -0
  162. package/dist/application/collector/logcat-stop.d.ts +2 -0
  163. package/dist/application/collector/logcat-stop.js +11 -0
  164. package/dist/application/context/context-generator.d.ts +45 -0
  165. package/dist/application/context/context-generator.js +228 -0
  166. package/dist/application/context/context-loader.d.ts +40 -0
  167. package/dist/application/context/context-loader.js +223 -0
  168. package/dist/application/context/context-refresher.d.ts +59 -0
  169. package/dist/application/context/context-refresher.js +349 -0
  170. package/dist/application/context/context-rehasher.d.ts +36 -0
  171. package/dist/application/context/context-rehasher.js +110 -0
  172. package/dist/application/context/context-validator.d.ts +23 -1
  173. package/dist/application/context/context-validator.js +116 -9
  174. package/dist/application/context/evidence-hash.d.ts +1 -0
  175. package/dist/application/context/evidence-hash.js +125 -0
  176. package/dist/application/context/evidence-match.d.ts +9 -0
  177. package/dist/application/context/evidence-match.js +8 -0
  178. package/dist/application/context/shard-identity.d.ts +2 -0
  179. package/dist/application/context/shard-identity.js +7 -0
  180. package/dist/application/contract/contract-loader.d.ts +25 -0
  181. package/dist/application/contract/contract-loader.js +68 -0
  182. package/dist/application/contract/contract-review.d.ts +25 -0
  183. package/dist/application/contract/contract-review.js +51 -0
  184. package/dist/application/contract/contract-verifier.d.ts +53 -0
  185. package/dist/application/contract/contract-verifier.js +645 -0
  186. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  187. package/dist/application/devices/resolve-device-assignments.js +60 -0
  188. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  189. package/dist/application/diagnosis/failure-classifier.js +179 -0
  190. package/dist/application/diagnostics/diagnostics-exporter.d.ts +29 -0
  191. package/dist/application/diagnostics/diagnostics-exporter.js +283 -0
  192. package/dist/application/diagnostics/ui-capture-telemetry.d.ts +16 -0
  193. package/dist/application/diagnostics/ui-capture-telemetry.js +81 -0
  194. package/dist/application/doctor/doctor-service.d.ts +36 -3
  195. package/dist/application/doctor/doctor-service.js +255 -25
  196. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  197. package/dist/application/generation/generation-app-preparer.js +28 -0
  198. package/dist/application/generation/generation-config-service.d.ts +21 -0
  199. package/dist/application/generation/generation-config-service.js +53 -0
  200. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  201. package/dist/application/generation/generation-confirmation-service.js +109 -24
  202. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  203. package/dist/application/generation/generation-context-snapshot.js +29 -0
  204. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  205. package/dist/application/generation/generation-finalizer.js +167 -70
  206. package/dist/application/generation/generation-publisher.js +12 -8
  207. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  208. package/dist/application/generation/generation-recovery-service.js +144 -0
  209. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  210. package/dist/application/generation/generation-reopen-service.js +37 -0
  211. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  212. package/dist/application/generation/generation-replace-service.js +116 -0
  213. package/dist/application/generation/generation-starter.d.ts +44 -4
  214. package/dist/application/generation/generation-starter.js +175 -8
  215. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  216. package/dist/application/generation/generation-step-executor.js +471 -108
  217. package/dist/application/generation/proposed-step-validator.js +96 -30
  218. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  219. package/dist/application/generation/replay-policy-loader.js +29 -0
  220. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  221. package/dist/application/generation/risk-evaluator.js +118 -3
  222. package/dist/application/generation/runtime-observer.d.ts +39 -7
  223. package/dist/application/generation/runtime-observer.js +193 -24
  224. package/dist/application/impact/impact-resolver.d.ts +32 -0
  225. package/dist/application/impact/impact-resolver.js +160 -0
  226. package/dist/application/init/init-service.js +26 -13
  227. package/dist/application/interaction/action-executor.d.ts +3 -2
  228. package/dist/application/interaction/action-executor.js +11 -1
  229. package/dist/application/interaction/action-target.d.ts +17 -0
  230. package/dist/application/interaction/action-target.js +40 -0
  231. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  232. package/dist/application/interaction/external-step-runner.js +332 -0
  233. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  234. package/dist/application/interaction/fallback-resolver.js +7 -5
  235. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  236. package/dist/application/interaction/scroll-to-executor.js +118 -36
  237. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  238. package/dist/application/journey/external-flow-resolver.js +22 -0
  239. package/dist/application/journey/journey-check-service.d.ts +54 -0
  240. package/dist/application/journey/journey-check-service.js +207 -0
  241. package/dist/application/journey/journey-promoter.d.ts +26 -0
  242. package/dist/application/journey/journey-promoter.js +123 -0
  243. package/dist/application/journey/journey-resolver.d.ts +42 -0
  244. package/dist/application/journey/journey-resolver.js +239 -0
  245. package/dist/application/journey/journey-retirer.d.ts +25 -0
  246. package/dist/application/journey/journey-retirer.js +87 -0
  247. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  248. package/dist/application/knowledge/anchor-resolver.js +110 -0
  249. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  250. package/dist/application/knowledge/knowledge-loader.js +36 -0
  251. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  252. package/dist/application/locator/layout-failure-summary.js +67 -0
  253. package/dist/application/locator/layout-traversal.d.ts +11 -0
  254. package/dist/application/locator/layout-traversal.js +18 -0
  255. package/dist/application/locator/locator-resolver.d.ts +13 -1
  256. package/dist/application/locator/locator-resolver.js +182 -18
  257. package/dist/application/observe/observe-service.d.ts +20 -0
  258. package/dist/application/observe/observe-service.js +91 -0
  259. package/dist/application/project/project-describer.d.ts +14 -6
  260. package/dist/application/project/project-describer.js +38 -5
  261. package/dist/application/recognition/screen-detector.d.ts +28 -0
  262. package/dist/application/recognition/screen-detector.js +111 -0
  263. package/dist/application/recorder/locator-selector.js +151 -17
  264. package/dist/application/recorder/recorder-service.d.ts +16 -4
  265. package/dist/application/recorder/recorder-service.js +420 -128
  266. package/dist/application/report/report-writer.d.ts +5 -0
  267. package/dist/application/report/report-writer.js +17 -1
  268. package/dist/application/runtime/cold-launch.d.ts +28 -0
  269. package/dist/application/runtime/cold-launch.js +59 -0
  270. package/dist/application/runtime/step-runner.d.ts +49 -4
  271. package/dist/application/runtime/step-runner.js +721 -130
  272. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  273. package/dist/application/runtime/verify-runtime.js +577 -175
  274. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  275. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  276. package/dist/application/ui/observed-ui-snapshot-provider.d.ts +15 -0
  277. package/dist/application/ui/observed-ui-snapshot-provider.js +66 -0
  278. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  279. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  280. package/dist/application/ui/ui-stability-probe.d.ts +9 -0
  281. package/dist/application/ui/ui-stability-probe.js +24 -0
  282. package/dist/application/wait/idle-advice.d.ts +6 -0
  283. package/dist/application/wait/idle-advice.js +27 -0
  284. package/dist/application/wait/idle-profiles.d.ts +15 -0
  285. package/dist/application/wait/idle-profiles.js +75 -0
  286. package/dist/application/wait/idle-waiter.d.ts +28 -4
  287. package/dist/application/wait/idle-waiter.js +201 -15
  288. package/dist/cli/commands/align.d.ts +3 -0
  289. package/dist/cli/commands/align.js +124 -0
  290. package/dist/cli/commands/baseline.d.ts +3 -0
  291. package/dist/cli/commands/baseline.js +130 -0
  292. package/dist/cli/commands/context.js +300 -27
  293. package/dist/cli/commands/contract.d.ts +3 -0
  294. package/dist/cli/commands/contract.js +120 -0
  295. package/dist/cli/commands/diagnose.d.ts +3 -0
  296. package/dist/cli/commands/diagnose.js +84 -0
  297. package/dist/cli/commands/doctor.js +16 -9
  298. package/dist/cli/commands/failure.d.ts +3 -0
  299. package/dist/cli/commands/failure.js +63 -0
  300. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  301. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  302. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  303. package/dist/cli/commands/generation/session-commands.js +472 -0
  304. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  305. package/dist/cli/commands/generation/shared.js +291 -0
  306. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  307. package/dist/cli/commands/generation/step-commands.js +315 -0
  308. package/dist/cli/commands/generation.js +10 -507
  309. package/dist/cli/commands/impact.d.ts +3 -0
  310. package/dist/cli/commands/impact.js +87 -0
  311. package/dist/cli/commands/init.js +13 -6
  312. package/dist/cli/commands/journey.d.ts +3 -0
  313. package/dist/cli/commands/journey.js +382 -0
  314. package/dist/cli/commands/knowledge.d.ts +3 -0
  315. package/dist/cli/commands/knowledge.js +93 -0
  316. package/dist/cli/commands/observe.d.ts +3 -0
  317. package/dist/cli/commands/observe.js +127 -0
  318. package/dist/cli/commands/project.js +2 -1
  319. package/dist/cli/commands/record.js +18 -5
  320. package/dist/cli/commands/verify.js +326 -64
  321. package/dist/cli/dependencies.d.ts +136 -1
  322. package/dist/cli/dependencies.js +504 -52
  323. package/dist/cli/diagnostics-recorder.d.ts +31 -0
  324. package/dist/cli/diagnostics-recorder.js +82 -0
  325. package/dist/cli/diff-verification.d.ts +41 -0
  326. package/dist/cli/diff-verification.js +192 -0
  327. package/dist/cli/main.d.ts +1 -1
  328. package/dist/cli/main.js +107 -2
  329. package/dist/cli/output.d.ts +5 -3
  330. package/dist/cli/output.js +12 -0
  331. package/dist/cli/program.js +21 -1
  332. package/dist/cli/project-root.d.ts +1 -0
  333. package/dist/cli/project-root.js +6 -0
  334. package/dist/cli/runtime-selection.d.ts +22 -0
  335. package/dist/cli/runtime-selection.js +92 -0
  336. package/dist/cli/version.d.ts +1 -0
  337. package/dist/cli/version.js +14 -0
  338. package/dist/cli/workspace-guard.d.ts +2 -0
  339. package/dist/cli/workspace-guard.js +3 -0
  340. package/dist/domain/binding-reference.d.ts +4 -0
  341. package/dist/domain/binding-reference.js +23 -0
  342. package/dist/domain/checkpoint.d.ts +404 -0
  343. package/dist/domain/checkpoint.js +297 -0
  344. package/dist/domain/config.d.ts +107 -1
  345. package/dist/domain/config.js +52 -6
  346. package/dist/domain/contract.d.ts +413 -0
  347. package/dist/domain/contract.js +196 -0
  348. package/dist/domain/diagnostics.d.ts +1396 -0
  349. package/dist/domain/diagnostics.js +193 -0
  350. package/dist/domain/external-flow.d.ts +493 -0
  351. package/dist/domain/external-flow.js +15 -0
  352. package/dist/domain/failure-classification.d.ts +176 -0
  353. package/dist/domain/failure-classification.js +169 -0
  354. package/dist/domain/failure.d.ts +2 -1
  355. package/dist/domain/failure.js +123 -0
  356. package/dist/domain/generation.d.ts +1671 -132
  357. package/dist/domain/generation.js +202 -13
  358. package/dist/domain/geometry.d.ts +13 -0
  359. package/dist/domain/geometry.js +16 -0
  360. package/dist/domain/impact.d.ts +71 -0
  361. package/dist/domain/impact.js +76 -0
  362. package/dist/domain/init.d.ts +12 -4
  363. package/dist/domain/init.js +24 -18
  364. package/dist/domain/journey-composition.d.ts +2285 -0
  365. package/dist/domain/journey-composition.js +85 -0
  366. package/dist/domain/journey-lifecycle.d.ts +10 -0
  367. package/dist/domain/journey-lifecycle.js +9 -0
  368. package/dist/domain/journey.d.ts +2419 -212
  369. package/dist/domain/journey.js +384 -14
  370. package/dist/domain/knowledge.d.ts +165 -0
  371. package/dist/domain/knowledge.js +188 -0
  372. package/dist/domain/layout.d.ts +34 -5
  373. package/dist/domain/layout.js +64 -6
  374. package/dist/domain/locator-evidence.d.ts +3 -0
  375. package/dist/domain/locator-evidence.js +36 -0
  376. package/dist/domain/logcat-event.d.ts +54 -0
  377. package/dist/domain/logcat-event.js +40 -0
  378. package/dist/domain/observation.d.ts +33 -0
  379. package/dist/domain/observation.js +18 -0
  380. package/dist/domain/project-context.d.ts +219 -1
  381. package/dist/domain/project-context.js +209 -6
  382. package/dist/domain/proposed-step.d.ts +340 -60
  383. package/dist/domain/proposed-step.js +23 -3
  384. package/dist/domain/report.d.ts +1455 -28
  385. package/dist/domain/report.js +211 -14
  386. package/dist/domain/runtime-snapshot.d.ts +58 -1
  387. package/dist/domain/runtime-snapshot.js +14 -3
  388. package/dist/domain/runtime.d.ts +50 -0
  389. package/dist/domain/runtime.js +36 -0
  390. package/dist/domain/system-app-profiles.d.ts +6 -0
  391. package/dist/domain/system-app-profiles.js +43 -0
  392. package/dist/domain/ui-backend.d.ts +28 -0
  393. package/dist/domain/ui-backend.js +33 -0
  394. package/dist/domain/ui-cache.d.ts +11 -0
  395. package/dist/domain/ui-cache.js +10 -0
  396. package/dist/domain/verify-receipt.d.ts +17 -0
  397. package/dist/domain/verify-receipt.js +17 -0
  398. package/dist/domain/window-hierarchy.d.ts +84 -0
  399. package/dist/domain/window-hierarchy.js +172 -0
  400. package/dist/domain/workflow-manifest.d.ts +77 -0
  401. package/dist/domain/workflow-manifest.js +136 -0
  402. package/dist/domain/workspace.d.ts +30 -0
  403. package/dist/domain/workspace.js +74 -0
  404. package/dist/ports/adb.d.ts +34 -1
  405. package/dist/ports/align-prompt.d.ts +11 -0
  406. package/dist/ports/align-prompt.js +6 -0
  407. package/dist/ports/anchor-resolver.d.ts +30 -0
  408. package/dist/ports/anchor-resolver.js +1 -0
  409. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  410. package/dist/ports/annotated-screen-resolver.js +1 -0
  411. package/dist/ports/camera-probe.d.ts +23 -0
  412. package/dist/ports/camera-probe.js +8 -0
  413. package/dist/ports/context-document-writer.d.ts +24 -0
  414. package/dist/ports/context-document-writer.js +1 -0
  415. package/dist/ports/detached-process-launcher.d.ts +12 -0
  416. package/dist/ports/detached-process-launcher.js +1 -0
  417. package/dist/ports/diagnostics.d.ts +15 -0
  418. package/dist/ports/diagnostics.js +1 -0
  419. package/dist/ports/external-flow-registry.d.ts +37 -0
  420. package/dist/ports/external-flow-registry.js +1 -0
  421. package/dist/ports/generation-prompt.d.ts +2 -1
  422. package/dist/ports/generation-session-store.d.ts +12 -2
  423. package/dist/ports/git-diff.d.ts +9 -0
  424. package/dist/ports/git-diff.js +1 -0
  425. package/dist/ports/journey-composition-store.d.ts +17 -0
  426. package/dist/ports/journey-composition-store.js +1 -0
  427. package/dist/ports/knowledge-registry.d.ts +20 -0
  428. package/dist/ports/knowledge-registry.js +1 -0
  429. package/dist/ports/process-runner.d.ts +7 -0
  430. package/dist/ports/project-file-inspector.d.ts +1 -0
  431. package/dist/ports/project-identity-inspector.d.ts +24 -0
  432. package/dist/ports/project-identity-inspector.js +1 -0
  433. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  434. package/dist/ports/project-inventory-inspector.js +1 -0
  435. package/dist/ports/project-module-discoverer.d.ts +26 -0
  436. package/dist/ports/project-module-discoverer.js +1 -0
  437. package/dist/ports/recorder-prompt.d.ts +10 -1
  438. package/dist/ports/runtime-backend.d.ts +89 -0
  439. package/dist/ports/runtime-backend.js +13 -0
  440. package/dist/ports/runtime-capability.d.ts +12 -0
  441. package/dist/ports/runtime-capability.js +20 -0
  442. package/dist/ports/runtime-session-ports.d.ts +25 -0
  443. package/dist/ports/runtime-session-ports.js +1 -0
  444. package/dist/ports/screenshot.d.ts +11 -0
  445. package/dist/ports/screenshot.js +1 -0
  446. package/dist/ports/skill-installer.d.ts +2 -2
  447. package/dist/ports/ui-snapshot.d.ts +35 -0
  448. package/dist/ports/ui-snapshot.js +1 -0
  449. package/dist/ports/ui-stability.d.ts +19 -0
  450. package/dist/ports/ui-stability.js +1 -0
  451. package/dist/ports/workspace-layout.d.ts +4 -0
  452. package/dist/ports/workspace-layout.js +1 -0
  453. package/dist/shared/errors.d.ts +2 -0
  454. package/dist/shared/errors.js +22 -0
  455. package/dist/shared/paths.d.ts +2 -0
  456. package/dist/shared/paths.js +24 -0
  457. package/dist/shared/strings.d.ts +2 -0
  458. package/dist/shared/strings.js +16 -0
  459. package/package.json +7 -2
  460. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  461. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  462. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  463. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  464. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  465. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  466. package/dist/ports/android-cli.d.ts +0 -21
  467. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -1,32 +1,74 @@
1
1
  import { resolve } from "node:path";
2
2
  import { Command } from "commander";
3
+ import { ContextGenerateError } from "../../application/context/context-generator.js";
4
+ import { ContextLoadError } from "../../application/context/context-loader.js";
5
+ import { ContextRehashError } from "../../application/context/context-rehasher.js";
6
+ import { ContextRefreshError } from "../../application/context/context-refresher.js";
3
7
  import { TapHoundConfigSchema } from "../../domain/config.js";
4
- import { ProjectContextSchema } from "../../domain/project-context.js";
8
+ import { assertProjectPathUnder, CONFIG_PATH, CONTEXT_DIR } from "../../domain/workspace.js";
5
9
  import { errorMessage, failureOutput, writeJson, writeLine } from "../output.js";
10
+ function contextPath(root, requested) {
11
+ return assertProjectPathUnder(root, requested, CONTEXT_DIR, "Project Context output");
12
+ }
6
13
  function exitCodeForContext(command, result) {
7
14
  if (result.status === "invalid") {
8
15
  return 2;
9
16
  }
10
17
  return command === "validate" && result.status === "stale" ? 1 : 0;
11
18
  }
19
+ function loadFailureResult(error) {
20
+ return error.code === "CONTEXT_STALE"
21
+ ? {
22
+ status: "stale",
23
+ reason: {
24
+ code: "EVIDENCE_HASH_MISMATCH",
25
+ message: error.message
26
+ }
27
+ }
28
+ : {
29
+ status: "invalid",
30
+ reason: {
31
+ code: "CONTEXT_SCHEMA_INVALID",
32
+ message: error.message
33
+ }
34
+ };
35
+ }
36
+ function writeContextResult(dependencies, options, name, result, details = {}) {
37
+ const exitCode = exitCodeForContext(name, result);
38
+ const output = { ...result, ...details, exitCode };
39
+ if (options.json === true) {
40
+ writeJson(dependencies.stdout, output);
41
+ }
42
+ else {
43
+ writeLine(dependencies.stdout, result.status === "valid"
44
+ ? "Context: valid"
45
+ : `Context: ${result.status} (${result.reason.message})`);
46
+ if (result.status === "valid" && result.divergence !== undefined) {
47
+ writeLine(dependencies.stderr, `identity divergence: evidence package ${result.divergence.evidencePackageName}, configured package ${result.divergence.configuredPackageName} (activity suffix matches)`);
48
+ }
49
+ }
50
+ dependencies.setExitCode(exitCode);
51
+ }
12
52
  function createContextOperation(dependencies, name) {
13
53
  return new Command(name)
14
54
  .description(name === "validate"
15
55
  ? "Validate deterministic Project Context evidence"
16
56
  : "Observe deterministic Project Context status")
17
57
  .option("--project <path>", "Android project root", dependencies.cwd())
18
- .option("--config <path>", "TapHound config path", "taphound.config.json")
19
- .requiredOption("--context <path>", "Project Context path")
58
+ .option("--config <path>", "TapHound config path", CONFIG_PATH)
59
+ .option("--context <path>", "Project Context path under .taphound/context", ".taphound/context/project-context.json")
60
+ .option("--module <id...>", "Select Context modules")
20
61
  .option("--json", "Emit one machine-readable JSON value")
21
62
  .action(async (options) => {
63
+ const json = options.json === true;
64
+ const projectRoot = options.project;
22
65
  let config;
23
- let context;
24
66
  try {
25
- config = TapHoundConfigSchema.parse(await dependencies.readJson(resolve(options.project, options.config)));
67
+ config = TapHoundConfigSchema.parse(await dependencies.readJson(resolve(projectRoot, options.config)));
26
68
  }
27
69
  catch (error) {
28
70
  const output = failureOutput(2, "CONFIG_INVALID", errorMessage(error));
29
- if (options.json === true) {
71
+ if (json) {
30
72
  writeJson(dependencies.stdout, output);
31
73
  }
32
74
  else {
@@ -36,53 +78,280 @@ function createContextOperation(dependencies, name) {
36
78
  return;
37
79
  }
38
80
  try {
39
- context = ProjectContextSchema.parse(await dependencies.readJson(resolve(options.project, options.context)));
81
+ const loaded = await dependencies.contextLoader.load({
82
+ projectRoot,
83
+ contextPath: contextPath(projectRoot, options.context),
84
+ ...(options.module === undefined ? {} : { moduleIds: options.module }),
85
+ allowIncomplete: name === "status"
86
+ });
87
+ const result = await dependencies.contextValidator.validate({
88
+ context: loaded.context,
89
+ projectRoot,
90
+ config,
91
+ ...(name === "status" ? { modules: loaded.modules } : {}),
92
+ ...(name === "status" ? { reportScopes: true } : {})
93
+ });
94
+ writeContextResult(dependencies, options, name, result, {
95
+ contextSelection: loaded.context.selection,
96
+ modules: loaded.modules.map((module) => ({
97
+ id: module.moduleId,
98
+ status: module.status
99
+ }))
100
+ });
40
101
  }
41
102
  catch (error) {
103
+ if (error instanceof ContextLoadError) {
104
+ writeContextResult(dependencies, options, name, loadFailureResult(error));
105
+ return;
106
+ }
107
+ const output = failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
108
+ if (options.json === true) {
109
+ writeJson(dependencies.stdout, output);
110
+ }
111
+ else {
112
+ writeLine(dependencies.stderr, output.failure.message);
113
+ }
114
+ dependencies.setExitCode(4);
115
+ }
116
+ });
117
+ }
118
+ function createContextListCommand(dependencies) {
119
+ return new Command("list")
120
+ .description("List Project Context modules without loading shards")
121
+ .option("--project <path>", "Android project root", dependencies.cwd())
122
+ .option("--context <path>", "Project Context path under .taphound/context", ".taphound/context/project-context.json")
123
+ .option("--json", "Emit one machine-readable JSON value")
124
+ .action(async (options) => {
125
+ try {
126
+ const { bundle, indexHash } = await dependencies.contextLoader.readIndex({
127
+ projectRoot: options.project,
128
+ contextPath: contextPath(options.project, options.context)
129
+ });
42
130
  const output = {
43
- status: "error",
44
- exitCode: 2,
45
- failure: {
46
- code: "CONTEXT_INVALID",
47
- message: errorMessage(error)
48
- }
131
+ status: "listed",
132
+ exitCode: 0,
133
+ version: bundle.version,
134
+ packageName: bundle.packageName,
135
+ launchActivity: bundle.launchActivity,
136
+ indexHash,
137
+ modules: bundle.modules
49
138
  };
50
139
  if (options.json === true) {
51
140
  writeJson(dependencies.stdout, output);
52
141
  }
142
+ else {
143
+ for (const module of bundle.modules) {
144
+ writeLine(dependencies.stdout, `${module.id}: ${module.status} (${module.contextPath})`);
145
+ }
146
+ }
147
+ dependencies.setExitCode(0);
148
+ }
149
+ catch (error) {
150
+ const output = error instanceof ContextLoadError
151
+ ? {
152
+ status: "error",
153
+ exitCode: 2,
154
+ failure: {
155
+ code: error.code,
156
+ message: error.message
157
+ }
158
+ }
159
+ : failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
160
+ if (options.json === true) {
161
+ writeJson(dependencies.stdout, output);
162
+ }
53
163
  else {
54
164
  writeLine(dependencies.stderr, output.failure.message);
55
165
  }
56
- dependencies.setExitCode(2);
57
- return;
166
+ dependencies.setExitCode(output.exitCode);
167
+ }
168
+ });
169
+ }
170
+ function refreshExitCode(result) {
171
+ return result.status === "blocked" ? 1 : 0;
172
+ }
173
+ function writeRefreshText(dependencies, result) {
174
+ writeLine(dependencies.stdout, `Context: ${result.status}`);
175
+ for (const scope of result.scopes) {
176
+ if (scope.semanticBackfilled === 0
177
+ && scope.formattingRehashed === 0
178
+ && scope.semanticChanged.length === 0
179
+ && scope.unresolved.length === 0
180
+ && scope.pruned === 0
181
+ && scope.droppedIneligible === 0
182
+ && !scope.inventoryChanged) {
183
+ continue;
58
184
  }
185
+ writeLine(dependencies.stdout, `${scope.id}: semantic ${String(scope.semanticBackfilled)}`
186
+ + `, rehashed ${String(scope.formattingRehashed)}`
187
+ + `, changed ${String(scope.semanticChanged.length)}`
188
+ + `, unresolved ${String(scope.unresolved.length)}`
189
+ + `, pruned ${String(scope.pruned)}`
190
+ + `, dropped ${String(scope.droppedIneligible)}`
191
+ + (scope.inventoryChanged ? ", inventory changed" : ""));
192
+ }
193
+ for (const block of result.blocked) {
194
+ writeLine(dependencies.stderr, `${block.code} [${block.resolution}]: ${block.message}`);
195
+ }
196
+ }
197
+ function createContextRefreshCommand(dependencies) {
198
+ return new Command("refresh")
199
+ .description("Recompute Project Context evidence hashes without analysis")
200
+ .option("--project <path>", "Android project root", dependencies.cwd())
201
+ .option("--context <path>", "Project Context path under .taphound/context", ".taphound/context/project-context.json")
202
+ .option("--module <id...>", "Refresh only the listed Context modules")
203
+ .option("--accept-source-changes", "Also rehash evidence whose semantics changed")
204
+ .option("--prune-deleted", "Drop evidence entries for files no longer on disk")
205
+ .option("--json", "Emit one machine-readable JSON value")
206
+ .action(async (options) => {
59
207
  try {
60
- const result = await dependencies.contextValidator.validate({
61
- context,
208
+ const result = await dependencies.contextRefresher.refresh({
62
209
  projectRoot: options.project,
63
- config
210
+ contextPath: contextPath(options.project, options.context),
211
+ ...(options.module === undefined ? {} : { moduleIds: options.module }),
212
+ ...(options.acceptSourceChanges === undefined
213
+ ? {}
214
+ : { acceptSourceChanges: options.acceptSourceChanges }),
215
+ ...(options.pruneDeleted === undefined
216
+ ? {}
217
+ : { pruneDeleted: options.pruneDeleted })
64
218
  });
65
- const exitCode = exitCodeForContext(name, result);
66
- const output = { ...result, exitCode };
219
+ const exitCode = refreshExitCode(result);
67
220
  if (options.json === true) {
68
- writeJson(dependencies.stdout, output);
221
+ writeJson(dependencies.stdout, { ...result, exitCode });
69
222
  }
70
223
  else {
71
- writeLine(dependencies.stdout, result.status === "valid"
72
- ? "Context: valid"
73
- : `Context: ${result.status} (${result.reason.message})`);
224
+ writeRefreshText(dependencies, result);
74
225
  }
75
226
  dependencies.setExitCode(exitCode);
76
227
  }
77
228
  catch (error) {
78
- const output = failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
229
+ const output = error instanceof ContextRefreshError
230
+ ? {
231
+ status: "error",
232
+ exitCode: 2,
233
+ failure: { code: error.code, message: error.message }
234
+ }
235
+ : error instanceof ContextLoadError
236
+ ? {
237
+ status: "error",
238
+ exitCode: 2,
239
+ failure: { code: error.code, message: error.message }
240
+ }
241
+ : failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
79
242
  if (options.json === true) {
80
243
  writeJson(dependencies.stdout, output);
81
244
  }
82
245
  else {
83
246
  writeLine(dependencies.stderr, output.failure.message);
84
247
  }
85
- dependencies.setExitCode(4);
248
+ dependencies.setExitCode(output.exitCode);
249
+ }
250
+ });
251
+ }
252
+ function writeGenerateText(dependencies, result) {
253
+ writeLine(dependencies.stdout, `Context: generated (${String(result.modules.length)} modules)`);
254
+ writeLine(dependencies.stdout, `Package: ${result.packageName}`);
255
+ writeLine(dependencies.stdout, `Activity: ${result.launchActivity}`);
256
+ for (const module of result.modules) {
257
+ writeLine(dependencies.stdout, ` ${module.id}: ${module.kind} (${String(module.evidenceCount)} evidence files)`);
258
+ }
259
+ }
260
+ function createContextGenerateCommand(dependencies) {
261
+ return new Command("generate")
262
+ .description("Generate Project Context scaffolding from project source")
263
+ .option("--project <path>", "Android project root", dependencies.cwd())
264
+ .option("--context <path>", "Project Context path under .taphound/context", ".taphound/context/project-context.json")
265
+ .option("--force", "Overwrite an existing Project Context")
266
+ .option("--json", "Emit one machine-readable JSON value")
267
+ .action(async (options) => {
268
+ const json = options.json === true;
269
+ const projectRoot = options.project;
270
+ try {
271
+ const result = await dependencies.contextGenerator.generate({
272
+ projectRoot,
273
+ contextPath: contextPath(projectRoot, options.context),
274
+ ...(options.force === undefined ? {} : { force: options.force })
275
+ });
276
+ const output = { ...result, exitCode: 0 };
277
+ if (json) {
278
+ writeJson(dependencies.stdout, output);
279
+ }
280
+ else {
281
+ writeGenerateText(dependencies, result);
282
+ }
283
+ dependencies.setExitCode(0);
284
+ }
285
+ catch (error) {
286
+ const output = error instanceof ContextGenerateError
287
+ ? {
288
+ status: "error",
289
+ exitCode: 2,
290
+ failure: { code: error.code, message: error.message }
291
+ }
292
+ : failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
293
+ if (json) {
294
+ writeJson(dependencies.stdout, output);
295
+ }
296
+ else {
297
+ writeLine(dependencies.stderr, output.failure.message);
298
+ }
299
+ dependencies.setExitCode(output.exitCode);
300
+ }
301
+ });
302
+ }
303
+ function writeRehashText(dependencies, result) {
304
+ writeLine(dependencies.stdout, `Context: ${result.status}`);
305
+ for (const module of result.modules) {
306
+ if (module.changed) {
307
+ writeLine(dependencies.stdout, ` ${module.id}: ${module.previousSha256} -> ${module.currentSha256}`);
308
+ }
309
+ }
310
+ }
311
+ function createContextRehashCommand(dependencies) {
312
+ return new Command("rehash")
313
+ .description("Recompute Project Context shard and index hashes")
314
+ .option("--project <path>", "Android project root", dependencies.cwd())
315
+ .option("--context <path>", "Project Context path under .taphound/context", ".taphound/context/project-context.json")
316
+ .option("--module <id...>", "Rehash only the listed Context modules")
317
+ .option("--json", "Emit one machine-readable JSON value")
318
+ .action(async (options) => {
319
+ try {
320
+ const result = await dependencies.contextRehasher.rehash({
321
+ projectRoot: options.project,
322
+ contextPath: contextPath(options.project, options.context),
323
+ ...(options.module === undefined ? {} : { moduleIds: options.module })
324
+ });
325
+ const output = { ...result, exitCode: 0 };
326
+ if (options.json === true) {
327
+ writeJson(dependencies.stdout, output);
328
+ }
329
+ else {
330
+ writeRehashText(dependencies, result);
331
+ }
332
+ dependencies.setExitCode(0);
333
+ }
334
+ catch (error) {
335
+ const output = error instanceof ContextRehashError
336
+ ? {
337
+ status: "error",
338
+ exitCode: 2,
339
+ failure: { code: error.code, message: error.message }
340
+ }
341
+ : error instanceof ContextLoadError
342
+ ? {
343
+ status: "error",
344
+ exitCode: 2,
345
+ failure: { code: error.code, message: error.message }
346
+ }
347
+ : failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
348
+ if (options.json === true) {
349
+ writeJson(dependencies.stdout, output);
350
+ }
351
+ else {
352
+ writeLine(dependencies.stderr, output.failure.message);
353
+ }
354
+ dependencies.setExitCode(output.exitCode);
86
355
  }
87
356
  });
88
357
  }
@@ -90,5 +359,9 @@ export function createContextCommand(dependencies) {
90
359
  return new Command("context")
91
360
  .description("Validate or inspect Project Context")
92
361
  .addCommand(createContextOperation(dependencies, "validate"))
93
- .addCommand(createContextOperation(dependencies, "status"));
362
+ .addCommand(createContextOperation(dependencies, "status"))
363
+ .addCommand(createContextListCommand(dependencies))
364
+ .addCommand(createContextRefreshCommand(dependencies))
365
+ .addCommand(createContextGenerateCommand(dependencies))
366
+ .addCommand(createContextRehashCommand(dependencies));
94
367
  }
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { CliDependencies } from "../dependencies.js";
3
+ export declare function createContractCommand(dependencies: CliDependencies): Command;
@@ -0,0 +1,120 @@
1
+ import { resolve } from "node:path";
2
+ import { Command } from "commander";
3
+ import { exitCodeForFailure, failureCodeFromUnknown } from "../../domain/failure.js";
4
+ import { ContractReviewInputSchema, ContractVerdictViewSchema } from "../../domain/contract.js";
5
+ import { failureOutput, writeJson, writeLine } from "../output.js";
6
+ import { prepareWorkspace } from "../workspace-guard.js";
7
+ function writeFailure(dependencies, json, code, message) {
8
+ const exitCode = exitCodeForFailure(code);
9
+ const output = failureOutput(exitCode, code, message);
10
+ if (json) {
11
+ writeJson(dependencies.stdout, output);
12
+ }
13
+ else {
14
+ writeLine(dependencies.stderr, output.failure.message);
15
+ }
16
+ dependencies.setExitCode(exitCode);
17
+ }
18
+ export function createContractCommand(dependencies) {
19
+ const command = new Command("contract")
20
+ .description("Validate an Acceptance Contract without touching a device")
21
+ .option("--project <path>", "Android project root", dependencies.cwd())
22
+ .option("--contract <path>", "Acceptance Contract path")
23
+ .option("--json", "Emit one machine-readable JSON value")
24
+ .action(async (options) => {
25
+ const json = options.json === true;
26
+ if (options.contract === undefined) {
27
+ writeFailure(dependencies, json, "CONTRACT_INVALID", "Missing required option '--contract'");
28
+ return;
29
+ }
30
+ if (dependencies.contractLoader === undefined) {
31
+ writeFailure(dependencies, json, "CONFIG_INVALID", "TapHound contract validation is not configured");
32
+ return;
33
+ }
34
+ const contractPath = resolve(options.project, options.contract);
35
+ try {
36
+ await prepareWorkspace(dependencies, options.project);
37
+ }
38
+ catch (error) {
39
+ writeFailure(dependencies, json, failureCodeFromUnknown(error) ?? "CONFIG_INVALID", error instanceof Error ? error.message : String(error));
40
+ return;
41
+ }
42
+ try {
43
+ const loaded = await dependencies.contractLoader.load({
44
+ projectRoot: options.project,
45
+ contractPath
46
+ });
47
+ if (json) {
48
+ writeJson(dependencies.stdout, {
49
+ status: "valid",
50
+ contractId: loaded.contract.id,
51
+ contractSha256: loaded.contractSha256,
52
+ journeySha256: loaded.contract.journey.sha256,
53
+ journeyPath: loaded.journeyPath
54
+ });
55
+ }
56
+ else {
57
+ writeLine(dependencies.stdout, `TapHound contract: ${loaded.contract.id} is valid (${loaded.contractSha256.slice(0, 12)}...)`);
58
+ }
59
+ dependencies.setExitCode(0);
60
+ }
61
+ catch (error) {
62
+ writeFailure(dependencies, json, failureCodeFromUnknown(error) ?? "CONTRACT_INVALID", error instanceof Error ? error.message : String(error));
63
+ }
64
+ });
65
+ command.addCommand(createContractReviewCommand(dependencies));
66
+ return command;
67
+ }
68
+ function createContractReviewCommand(dependencies) {
69
+ const command = new Command("review")
70
+ .description("Merge reviewer findings into a Verdict (never overwrites fail/invalid)")
71
+ .requiredOption("--verdict <path>", "Verdict JSON path (verdict.json)")
72
+ .requiredOption("--findings <path>", "Reviewer findings JSON path")
73
+ .option("--json", "Emit one machine-readable JSON value")
74
+ .action(async (options) => {
75
+ // `--project` and `--json` are also declared on the parent command;
76
+ // commander routes them to the parent when both are declared, so fall
77
+ // back to the parent's values.
78
+ const parentOpts = command.parent?.opts() ?? {};
79
+ const project = parentOpts.project
80
+ ?? dependencies.cwd();
81
+ const json = options.json === true
82
+ || parentOpts.json === true;
83
+ if (dependencies.contractReview === undefined) {
84
+ writeFailure(dependencies, json, "CONFIG_INVALID", "TapHound contract review is not configured");
85
+ return;
86
+ }
87
+ const verdictPath = resolve(project, options.verdict);
88
+ const findingsPath = resolve(project, options.findings);
89
+ try {
90
+ await prepareWorkspace(dependencies, project);
91
+ }
92
+ catch (error) {
93
+ writeFailure(dependencies, json, failureCodeFromUnknown(error) ?? "CONFIG_INVALID", error instanceof Error ? error.message : String(error));
94
+ return;
95
+ }
96
+ try {
97
+ const verdict = ContractVerdictViewSchema.parse(await dependencies.readJson(verdictPath));
98
+ const review = ContractReviewInputSchema.parse(await dependencies.readJson(findingsPath));
99
+ const merged = await dependencies.contractReview.merge({
100
+ view: verdict,
101
+ review
102
+ });
103
+ await dependencies.contractReview.writeVerdict({
104
+ verdictPath,
105
+ view: merged.view
106
+ });
107
+ if (json) {
108
+ writeJson(dependencies.stdout, merged.view);
109
+ }
110
+ else {
111
+ writeLine(dependencies.stdout, `TapHound contract review: ${merged.view.verdict.toUpperCase()} (findings applied: ${String(merged.applied)})`);
112
+ }
113
+ dependencies.setExitCode(merged.view.verdict === "pass" ? 0 : 1);
114
+ }
115
+ catch (error) {
116
+ writeFailure(dependencies, json, failureCodeFromUnknown(error) ?? "CONTRACT_INVALID", error instanceof Error ? error.message : String(error));
117
+ }
118
+ });
119
+ return command;
120
+ }
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { CliDependencies } from "../dependencies.js";
3
+ export declare function createDiagnoseCommand(dependencies: CliDependencies): Command;
@@ -0,0 +1,84 @@
1
+ import { resolve } from "node:path";
2
+ import { Command, InvalidArgumentError } from "commander";
3
+ import { exitCodeForFailure, failureCodeFromUnknown } from "../../domain/failure.js";
4
+ import { DIAGNOSTICS_EXPORT_DIR } from "../../domain/workspace.js";
5
+ import { errorMessage, failureOutput, writeJson, writeLine } from "../output.js";
6
+ const REVIEW_NOTE = "Review the file before sharing it. It holds command outcomes, "
7
+ + "timings, and failure codes; project paths, package, Activity and Journey "
8
+ + "names, locator values, device serials, screenshots, UI hierarchies, and "
9
+ + "log text are left out or replaced by aliases.";
10
+ function positiveInteger(value) {
11
+ const parsed = Number(value);
12
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 1000) {
13
+ throw new InvalidArgumentError("must be an integer from 1 to 1000");
14
+ }
15
+ return parsed;
16
+ }
17
+ function exportFileName(at) {
18
+ return `taphound-diagnostics-${at.toISOString().replaceAll(":", "-")}.json`;
19
+ }
20
+ export function createDiagnoseCommand(dependencies) {
21
+ return new Command("diagnose")
22
+ .description("Collect redacted diagnostics to attach to TapHound feedback")
23
+ .addCommand(new Command("export")
24
+ .description("Write a redacted diagnostics bundle from the local journal and recent reports")
25
+ .option("--project <path>", "Android project root", dependencies.cwd())
26
+ .option("--out <path>", `Bundle path (default ${DIAGNOSTICS_EXPORT_DIR}/<timestamp>.json)`)
27
+ .option("--events <count>", "Most recent journal events to include", positiveInteger, 50)
28
+ .option("--runs <count>", "Most recent referenced runs to summarize", positiveInteger, 10)
29
+ .option("--json", "Emit one machine-readable JSON value")
30
+ .action(async (options) => {
31
+ const json = options.json === true;
32
+ const diagnostics = dependencies.diagnosticsExport;
33
+ if (diagnostics === undefined) {
34
+ const output = failureOutput(2, "CONFIG_INVALID", "TapHound diagnostics export is not configured");
35
+ if (json) {
36
+ writeJson(dependencies.stdout, output);
37
+ }
38
+ else {
39
+ writeLine(dependencies.stderr, output.failure.message);
40
+ }
41
+ dependencies.setExitCode(2);
42
+ return;
43
+ }
44
+ try {
45
+ const projectRoot = resolve(dependencies.cwd(), options.project);
46
+ const bundle = await diagnostics.export({
47
+ projectRoot,
48
+ eventLimit: options.events,
49
+ runLimit: options.runs
50
+ });
51
+ const path = options.out === undefined
52
+ ? resolve(projectRoot, DIAGNOSTICS_EXPORT_DIR, exportFileName(new Date(bundle.generatedAt)))
53
+ : resolve(dependencies.cwd(), options.out);
54
+ await diagnostics.write(path, `${JSON.stringify(bundle, null, 2)}\n`);
55
+ if (json) {
56
+ writeJson(dependencies.stdout, {
57
+ status: "exported",
58
+ exitCode: 0,
59
+ path,
60
+ events: bundle.journal.events.length,
61
+ runs: bundle.runs.length
62
+ });
63
+ }
64
+ else {
65
+ writeLine(dependencies.stdout, `TapHound diagnostics: ${path}\n${String(bundle.journal.events.length)} event(s), `
66
+ + `${String(bundle.runs.length)} run summary(ies)`);
67
+ }
68
+ writeLine(dependencies.stderr, REVIEW_NOTE);
69
+ dependencies.setExitCode(0);
70
+ }
71
+ catch (error) {
72
+ const code = failureCodeFromUnknown(error) ?? "INTERNAL_ERROR";
73
+ const exitCode = exitCodeForFailure(code);
74
+ const output = failureOutput(exitCode, code, errorMessage(error));
75
+ if (json) {
76
+ writeJson(dependencies.stdout, output);
77
+ }
78
+ else {
79
+ writeLine(dependencies.stderr, output.failure.message);
80
+ }
81
+ dependencies.setExitCode(exitCode);
82
+ }
83
+ }));
84
+ }
@@ -1,10 +1,12 @@
1
1
  import { resolve } from "node:path";
2
2
  import { Command } from "commander";
3
3
  import { TapHoundConfigSchema } from "../../domain/config.js";
4
+ import { CONFIG_PATH } from "../../domain/workspace.js";
5
+ import { exitCodeForFailure, failureCodeFromUnknown } from "../../domain/failure.js";
4
6
  import { doctorMessage, errorMessage, failureOutput, writeJson, writeLine } from "../output.js";
5
- async function configuredPackageName(dependencies, options) {
7
+ async function configuredConfig(dependencies, options) {
6
8
  try {
7
- return TapHoundConfigSchema.parse(await dependencies.readJson(resolve(options.project, options.config))).run.packageName;
9
+ return TapHoundConfigSchema.parse(await dependencies.readJson(resolve(options.project, options.config)));
8
10
  }
9
11
  catch {
10
12
  return undefined;
@@ -14,14 +16,18 @@ export function createDoctorCommand(dependencies) {
14
16
  return new Command("doctor")
15
17
  .description("Check TapHound tools, permissions, application, and device")
16
18
  .option("--project <path>", "Android project root", dependencies.cwd())
17
- .option("--config <path>", "TapHound config path", "taphound.config.json")
19
+ .option("--config <path>", "TapHound config path", CONFIG_PATH)
18
20
  .option("--device <serial>", "Select an online Android device")
19
21
  .option("--json", "Emit machine-readable JSON")
20
22
  .action(async (options) => {
23
+ const json = options.json === true;
21
24
  try {
22
- const packageName = await configuredPackageName(dependencies, options);
25
+ const config = await configuredConfig(dependencies, options);
23
26
  const report = await dependencies.doctor.run({
24
- ...(packageName === undefined ? {} : { packageName }),
27
+ ...(config === undefined ? {} : { packageName: config.run.packageName }),
28
+ ...(config?.ui?.backend === undefined
29
+ ? {}
30
+ : { requestedUiBackend: config.ui.backend }),
25
31
  ...(options.device === undefined
26
32
  ? {}
27
33
  : { requestedDevice: options.device }),
@@ -29,7 +35,7 @@ export function createDoctorCommand(dependencies) {
29
35
  ? {}
30
36
  : { signal: dependencies.signal })
31
37
  });
32
- if (options.json === true) {
38
+ if (json) {
33
39
  writeJson(dependencies.stdout, report);
34
40
  }
35
41
  else {
@@ -38,14 +44,15 @@ export function createDoctorCommand(dependencies) {
38
44
  dependencies.setExitCode(report.status === "passed" ? 0 : 3);
39
45
  }
40
46
  catch (error) {
41
- const output = failureOutput(4, "INTERNAL_ERROR", errorMessage(error));
42
- if (options.json === true) {
47
+ const code = failureCodeFromUnknown(error) ?? "INTERNAL_ERROR";
48
+ const output = failureOutput(exitCodeForFailure(code), code, errorMessage(error));
49
+ if (json) {
43
50
  writeJson(dependencies.stdout, output);
44
51
  }
45
52
  else {
46
53
  writeLine(dependencies.stderr, output.failure.message);
47
54
  }
48
- dependencies.setExitCode(4);
55
+ dependencies.setExitCode(exitCodeForFailure(code));
49
56
  }
50
57
  });
51
58
  }