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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/README.md +49 -149
  2. package/README.zh-CN.md +47 -147
  3. package/assets/skills/taphound-case-suite/SKILL.md +363 -0
  4. package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
  5. package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
  6. package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
  7. package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
  8. package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
  9. package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
  10. package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
  11. package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
  12. package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
  13. package/assets/skills/taphound-flash/SKILL.md +115 -0
  14. package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
  15. package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
  16. package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
  17. package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
  18. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
  19. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
  20. package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
  21. package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
  22. package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
  23. package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
  24. package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
  25. package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
  26. package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
  27. package/assets/skills/taphound-journey-generator/SKILL.md +500 -0
  28. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
  29. package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
  30. package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
  31. package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
  32. package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
  33. package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
  34. package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
  35. package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
  36. package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
  37. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
  38. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
  39. package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +561 -0
  40. package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
  41. package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
  42. package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
  43. package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
  44. package/assets/skills/taphound-verify-change/SKILL.md +91 -0
  45. package/assets/skills/taphound-verify-change/references/accept.md +38 -0
  46. package/assets/skills/taphound-verify-change/references/preserve.md +349 -0
  47. package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
  48. package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
  49. package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
  50. package/dist/adapters/adb/adb-adapter.d.ts +16 -2
  51. package/dist/adapters/adb/adb-adapter.js +199 -0
  52. package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
  53. package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
  54. package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
  55. package/dist/adapters/adb/ui-automator-parser.js +160 -0
  56. package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
  57. package/dist/adapters/adb/window-topology-parser.js +101 -0
  58. package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
  59. package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
  60. package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
  61. package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
  62. package/dist/adapters/android-cli/layout-parser.js +12 -8
  63. package/dist/adapters/appium/appium-doctor.d.ts +7 -0
  64. package/dist/adapters/appium/appium-doctor.js +128 -0
  65. package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +34 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +240 -0
  67. package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
  68. package/dist/adapters/camera/camera-probe-adapter.js +286 -0
  69. package/dist/adapters/filesystem/artifact-store.js +40 -1
  70. package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
  71. package/dist/adapters/filesystem/context-document-writer.js +112 -0
  72. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  73. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  74. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  75. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  76. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  77. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  78. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  79. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  80. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  81. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  82. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  83. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  84. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  85. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  86. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  87. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  88. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  89. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  90. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  91. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  92. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  93. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  94. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  95. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  96. package/dist/adapters/filesystem/skill-installer.js +40 -11
  97. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  98. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  99. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  100. package/dist/adapters/git/node-git-diff.js +114 -0
  101. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  102. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  103. package/dist/adapters/process/node-process-runner.js +11 -2
  104. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  105. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  106. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  107. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  108. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  109. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  110. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  111. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  112. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  113. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  114. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  115. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  116. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  122. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  123. package/dist/adapters/runtime/session-adb-view.js +193 -0
  124. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  125. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  126. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  127. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  128. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  129. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  130. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  131. package/dist/adapters/ui/device-layout-temp.js +18 -0
  132. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  133. package/dist/adapters/ui/device-ui-environment.js +81 -0
  134. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  135. package/dist/adapters/ui/layout-normalization.js +44 -0
  136. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  137. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  138. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  139. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  140. package/dist/application/align/align-service.d.ts +42 -0
  141. package/dist/application/align/align-service.js +106 -0
  142. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  143. package/dist/application/assertion/expectation-evaluator.js +156 -18
  144. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  145. package/dist/application/assertion/guarded-expectation.js +74 -0
  146. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  147. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  148. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  149. package/dist/application/checkpoint/baseline-error.js +8 -0
  150. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  151. package/dist/application/checkpoint/baseline-service.js +147 -0
  152. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  153. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  154. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  155. package/dist/application/checkpoint/regression-comparator.js +192 -0
  156. package/dist/application/collector/logcat-collector.d.ts +22 -1
  157. package/dist/application/collector/logcat-collector.js +103 -15
  158. package/dist/application/collector/logcat-event.d.ts +8 -0
  159. package/dist/application/collector/logcat-event.js +79 -0
  160. package/dist/application/collector/logcat-stop.d.ts +2 -0
  161. package/dist/application/collector/logcat-stop.js +11 -0
  162. package/dist/application/context/context-generator.d.ts +45 -0
  163. package/dist/application/context/context-generator.js +228 -0
  164. package/dist/application/context/context-loader.d.ts +40 -0
  165. package/dist/application/context/context-loader.js +223 -0
  166. package/dist/application/context/context-refresher.d.ts +59 -0
  167. package/dist/application/context/context-refresher.js +349 -0
  168. package/dist/application/context/context-rehasher.d.ts +36 -0
  169. package/dist/application/context/context-rehasher.js +110 -0
  170. package/dist/application/context/context-validator.d.ts +23 -1
  171. package/dist/application/context/context-validator.js +116 -9
  172. package/dist/application/context/evidence-hash.d.ts +1 -0
  173. package/dist/application/context/evidence-hash.js +125 -0
  174. package/dist/application/context/evidence-match.d.ts +9 -0
  175. package/dist/application/context/evidence-match.js +8 -0
  176. package/dist/application/context/shard-identity.d.ts +2 -0
  177. package/dist/application/context/shard-identity.js +7 -0
  178. package/dist/application/contract/contract-loader.d.ts +25 -0
  179. package/dist/application/contract/contract-loader.js +68 -0
  180. package/dist/application/contract/contract-review.d.ts +25 -0
  181. package/dist/application/contract/contract-review.js +51 -0
  182. package/dist/application/contract/contract-verifier.d.ts +53 -0
  183. package/dist/application/contract/contract-verifier.js +645 -0
  184. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  185. package/dist/application/devices/resolve-device-assignments.js +60 -0
  186. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  187. package/dist/application/diagnosis/failure-classifier.js +179 -0
  188. package/dist/application/doctor/doctor-service.d.ts +36 -3
  189. package/dist/application/doctor/doctor-service.js +255 -25
  190. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  191. package/dist/application/generation/generation-app-preparer.js +28 -0
  192. package/dist/application/generation/generation-config-service.d.ts +21 -0
  193. package/dist/application/generation/generation-config-service.js +53 -0
  194. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  195. package/dist/application/generation/generation-confirmation-service.js +109 -24
  196. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  197. package/dist/application/generation/generation-context-snapshot.js +29 -0
  198. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  199. package/dist/application/generation/generation-finalizer.js +167 -70
  200. package/dist/application/generation/generation-publisher.js +12 -8
  201. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  202. package/dist/application/generation/generation-recovery-service.js +144 -0
  203. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  204. package/dist/application/generation/generation-reopen-service.js +37 -0
  205. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  206. package/dist/application/generation/generation-replace-service.js +116 -0
  207. package/dist/application/generation/generation-starter.d.ts +44 -4
  208. package/dist/application/generation/generation-starter.js +175 -8
  209. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  210. package/dist/application/generation/generation-step-executor.js +471 -108
  211. package/dist/application/generation/proposed-step-validator.js +96 -30
  212. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  213. package/dist/application/generation/replay-policy-loader.js +29 -0
  214. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  215. package/dist/application/generation/risk-evaluator.js +118 -3
  216. package/dist/application/generation/runtime-observer.d.ts +39 -7
  217. package/dist/application/generation/runtime-observer.js +193 -24
  218. package/dist/application/impact/impact-resolver.d.ts +32 -0
  219. package/dist/application/impact/impact-resolver.js +160 -0
  220. package/dist/application/init/init-service.js +26 -13
  221. package/dist/application/interaction/action-executor.d.ts +3 -2
  222. package/dist/application/interaction/action-executor.js +11 -1
  223. package/dist/application/interaction/action-target.d.ts +17 -0
  224. package/dist/application/interaction/action-target.js +40 -0
  225. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  226. package/dist/application/interaction/external-step-runner.js +332 -0
  227. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  228. package/dist/application/interaction/fallback-resolver.js +7 -5
  229. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  230. package/dist/application/interaction/scroll-to-executor.js +118 -36
  231. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  232. package/dist/application/journey/external-flow-resolver.js +22 -0
  233. package/dist/application/journey/journey-check-service.d.ts +54 -0
  234. package/dist/application/journey/journey-check-service.js +207 -0
  235. package/dist/application/journey/journey-promoter.d.ts +26 -0
  236. package/dist/application/journey/journey-promoter.js +123 -0
  237. package/dist/application/journey/journey-resolver.d.ts +42 -0
  238. package/dist/application/journey/journey-resolver.js +239 -0
  239. package/dist/application/journey/journey-retirer.d.ts +25 -0
  240. package/dist/application/journey/journey-retirer.js +87 -0
  241. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  242. package/dist/application/knowledge/anchor-resolver.js +110 -0
  243. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  244. package/dist/application/knowledge/knowledge-loader.js +36 -0
  245. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  246. package/dist/application/locator/layout-failure-summary.js +67 -0
  247. package/dist/application/locator/layout-traversal.d.ts +11 -0
  248. package/dist/application/locator/layout-traversal.js +18 -0
  249. package/dist/application/locator/locator-resolver.d.ts +13 -1
  250. package/dist/application/locator/locator-resolver.js +182 -18
  251. package/dist/application/observe/observe-service.d.ts +20 -0
  252. package/dist/application/observe/observe-service.js +91 -0
  253. package/dist/application/project/project-describer.d.ts +14 -6
  254. package/dist/application/project/project-describer.js +38 -5
  255. package/dist/application/recognition/screen-detector.d.ts +28 -0
  256. package/dist/application/recognition/screen-detector.js +111 -0
  257. package/dist/application/recorder/locator-selector.js +151 -17
  258. package/dist/application/recorder/recorder-service.d.ts +16 -4
  259. package/dist/application/recorder/recorder-service.js +420 -128
  260. package/dist/application/report/report-writer.js +1 -1
  261. package/dist/application/runtime/cold-launch.d.ts +28 -0
  262. package/dist/application/runtime/cold-launch.js +59 -0
  263. package/dist/application/runtime/step-runner.d.ts +49 -4
  264. package/dist/application/runtime/step-runner.js +721 -130
  265. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  266. package/dist/application/runtime/verify-runtime.js +554 -174
  267. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  268. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  269. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  270. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  271. package/dist/application/ui/ui-stability-probe.d.ts +3 -0
  272. package/dist/application/ui/ui-stability-probe.js +8 -0
  273. package/dist/application/wait/idle-advice.d.ts +6 -0
  274. package/dist/application/wait/idle-advice.js +27 -0
  275. package/dist/application/wait/idle-profiles.d.ts +15 -0
  276. package/dist/application/wait/idle-profiles.js +75 -0
  277. package/dist/application/wait/idle-waiter.d.ts +28 -4
  278. package/dist/application/wait/idle-waiter.js +186 -15
  279. package/dist/cli/commands/align.d.ts +3 -0
  280. package/dist/cli/commands/align.js +124 -0
  281. package/dist/cli/commands/baseline.d.ts +3 -0
  282. package/dist/cli/commands/baseline.js +130 -0
  283. package/dist/cli/commands/context.js +300 -27
  284. package/dist/cli/commands/contract.d.ts +3 -0
  285. package/dist/cli/commands/contract.js +120 -0
  286. package/dist/cli/commands/doctor.js +16 -9
  287. package/dist/cli/commands/failure.d.ts +3 -0
  288. package/dist/cli/commands/failure.js +63 -0
  289. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  290. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  291. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  292. package/dist/cli/commands/generation/session-commands.js +472 -0
  293. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  294. package/dist/cli/commands/generation/shared.js +291 -0
  295. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  296. package/dist/cli/commands/generation/step-commands.js +315 -0
  297. package/dist/cli/commands/generation.js +10 -507
  298. package/dist/cli/commands/impact.d.ts +3 -0
  299. package/dist/cli/commands/impact.js +87 -0
  300. package/dist/cli/commands/init.js +13 -6
  301. package/dist/cli/commands/journey.d.ts +3 -0
  302. package/dist/cli/commands/journey.js +382 -0
  303. package/dist/cli/commands/knowledge.d.ts +3 -0
  304. package/dist/cli/commands/knowledge.js +93 -0
  305. package/dist/cli/commands/observe.d.ts +3 -0
  306. package/dist/cli/commands/observe.js +127 -0
  307. package/dist/cli/commands/project.js +2 -1
  308. package/dist/cli/commands/record.js +18 -5
  309. package/dist/cli/commands/verify.js +273 -63
  310. package/dist/cli/dependencies.d.ts +125 -1
  311. package/dist/cli/dependencies.js +450 -51
  312. package/dist/cli/diff-verification.d.ts +41 -0
  313. package/dist/cli/diff-verification.js +192 -0
  314. package/dist/cli/main.js +49 -1
  315. package/dist/cli/output.d.ts +5 -3
  316. package/dist/cli/output.js +12 -0
  317. package/dist/cli/program.js +19 -1
  318. package/dist/cli/project-root.d.ts +1 -0
  319. package/dist/cli/project-root.js +6 -0
  320. package/dist/cli/runtime-selection.d.ts +22 -0
  321. package/dist/cli/runtime-selection.js +92 -0
  322. package/dist/cli/version.d.ts +1 -0
  323. package/dist/cli/version.js +14 -0
  324. package/dist/cli/workspace-guard.d.ts +2 -0
  325. package/dist/cli/workspace-guard.js +3 -0
  326. package/dist/domain/binding-reference.d.ts +4 -0
  327. package/dist/domain/binding-reference.js +23 -0
  328. package/dist/domain/checkpoint.d.ts +404 -0
  329. package/dist/domain/checkpoint.js +297 -0
  330. package/dist/domain/config.d.ts +107 -1
  331. package/dist/domain/config.js +52 -6
  332. package/dist/domain/contract.d.ts +413 -0
  333. package/dist/domain/contract.js +196 -0
  334. package/dist/domain/external-flow.d.ts +493 -0
  335. package/dist/domain/external-flow.js +15 -0
  336. package/dist/domain/failure-classification.d.ts +176 -0
  337. package/dist/domain/failure-classification.js +169 -0
  338. package/dist/domain/failure.d.ts +2 -1
  339. package/dist/domain/failure.js +123 -0
  340. package/dist/domain/generation.d.ts +1671 -132
  341. package/dist/domain/generation.js +202 -13
  342. package/dist/domain/geometry.d.ts +13 -0
  343. package/dist/domain/geometry.js +16 -0
  344. package/dist/domain/impact.d.ts +71 -0
  345. package/dist/domain/impact.js +76 -0
  346. package/dist/domain/init.d.ts +12 -4
  347. package/dist/domain/init.js +24 -18
  348. package/dist/domain/journey-composition.d.ts +2285 -0
  349. package/dist/domain/journey-composition.js +85 -0
  350. package/dist/domain/journey-lifecycle.d.ts +10 -0
  351. package/dist/domain/journey-lifecycle.js +9 -0
  352. package/dist/domain/journey.d.ts +2419 -212
  353. package/dist/domain/journey.js +384 -14
  354. package/dist/domain/knowledge.d.ts +165 -0
  355. package/dist/domain/knowledge.js +188 -0
  356. package/dist/domain/layout.d.ts +34 -5
  357. package/dist/domain/layout.js +64 -6
  358. package/dist/domain/locator-evidence.d.ts +3 -0
  359. package/dist/domain/locator-evidence.js +36 -0
  360. package/dist/domain/logcat-event.d.ts +54 -0
  361. package/dist/domain/logcat-event.js +40 -0
  362. package/dist/domain/observation.d.ts +33 -0
  363. package/dist/domain/observation.js +18 -0
  364. package/dist/domain/project-context.d.ts +219 -1
  365. package/dist/domain/project-context.js +209 -6
  366. package/dist/domain/proposed-step.d.ts +340 -60
  367. package/dist/domain/proposed-step.js +23 -3
  368. package/dist/domain/report.d.ts +1455 -28
  369. package/dist/domain/report.js +211 -14
  370. package/dist/domain/runtime-snapshot.d.ts +58 -1
  371. package/dist/domain/runtime-snapshot.js +14 -3
  372. package/dist/domain/runtime.d.ts +50 -0
  373. package/dist/domain/runtime.js +36 -0
  374. package/dist/domain/system-app-profiles.d.ts +6 -0
  375. package/dist/domain/system-app-profiles.js +43 -0
  376. package/dist/domain/ui-backend.d.ts +28 -0
  377. package/dist/domain/ui-backend.js +33 -0
  378. package/dist/domain/ui-cache.d.ts +11 -0
  379. package/dist/domain/ui-cache.js +10 -0
  380. package/dist/domain/window-hierarchy.d.ts +84 -0
  381. package/dist/domain/window-hierarchy.js +172 -0
  382. package/dist/domain/workflow-manifest.d.ts +77 -0
  383. package/dist/domain/workflow-manifest.js +136 -0
  384. package/dist/domain/workspace.d.ts +28 -0
  385. package/dist/domain/workspace.js +72 -0
  386. package/dist/ports/adb.d.ts +34 -1
  387. package/dist/ports/align-prompt.d.ts +11 -0
  388. package/dist/ports/align-prompt.js +6 -0
  389. package/dist/ports/anchor-resolver.d.ts +30 -0
  390. package/dist/ports/anchor-resolver.js +1 -0
  391. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  392. package/dist/ports/annotated-screen-resolver.js +1 -0
  393. package/dist/ports/camera-probe.d.ts +23 -0
  394. package/dist/ports/camera-probe.js +8 -0
  395. package/dist/ports/context-document-writer.d.ts +24 -0
  396. package/dist/ports/context-document-writer.js +1 -0
  397. package/dist/ports/detached-process-launcher.d.ts +12 -0
  398. package/dist/ports/detached-process-launcher.js +1 -0
  399. package/dist/ports/external-flow-registry.d.ts +37 -0
  400. package/dist/ports/external-flow-registry.js +1 -0
  401. package/dist/ports/generation-prompt.d.ts +2 -1
  402. package/dist/ports/generation-session-store.d.ts +12 -2
  403. package/dist/ports/git-diff.d.ts +9 -0
  404. package/dist/ports/git-diff.js +1 -0
  405. package/dist/ports/journey-composition-store.d.ts +17 -0
  406. package/dist/ports/journey-composition-store.js +1 -0
  407. package/dist/ports/knowledge-registry.d.ts +20 -0
  408. package/dist/ports/knowledge-registry.js +1 -0
  409. package/dist/ports/process-runner.d.ts +7 -0
  410. package/dist/ports/project-file-inspector.d.ts +1 -0
  411. package/dist/ports/project-identity-inspector.d.ts +24 -0
  412. package/dist/ports/project-identity-inspector.js +1 -0
  413. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  414. package/dist/ports/project-inventory-inspector.js +1 -0
  415. package/dist/ports/project-module-discoverer.d.ts +26 -0
  416. package/dist/ports/project-module-discoverer.js +1 -0
  417. package/dist/ports/recorder-prompt.d.ts +10 -1
  418. package/dist/ports/runtime-backend.d.ts +89 -0
  419. package/dist/ports/runtime-backend.js +13 -0
  420. package/dist/ports/runtime-capability.d.ts +12 -0
  421. package/dist/ports/runtime-capability.js +20 -0
  422. package/dist/ports/runtime-session-ports.d.ts +25 -0
  423. package/dist/ports/runtime-session-ports.js +1 -0
  424. package/dist/ports/screenshot.d.ts +11 -0
  425. package/dist/ports/screenshot.js +1 -0
  426. package/dist/ports/skill-installer.d.ts +2 -2
  427. package/dist/ports/ui-snapshot.d.ts +35 -0
  428. package/dist/ports/ui-snapshot.js +1 -0
  429. package/dist/ports/ui-stability.d.ts +19 -0
  430. package/dist/ports/ui-stability.js +1 -0
  431. package/dist/ports/workspace-layout.d.ts +4 -0
  432. package/dist/ports/workspace-layout.js +1 -0
  433. package/dist/shared/errors.d.ts +2 -0
  434. package/dist/shared/errors.js +22 -0
  435. package/dist/shared/paths.d.ts +2 -0
  436. package/dist/shared/paths.js +24 -0
  437. package/dist/shared/strings.d.ts +2 -0
  438. package/dist/shared/strings.js +16 -0
  439. package/package.json +6 -1
  440. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  441. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  442. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  443. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  444. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  445. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  446. package/dist/ports/android-cli.d.ts +0 -21
  447. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -2,7 +2,7 @@ import { resolveLocator } from "../locator/locator-resolver.js";
2
2
  function isCancelled(signal) {
3
3
  return signal?.aborted === true;
4
4
  }
5
- function callbackFailure(error, swipesUsed) {
5
+ function callbackFailure(error, swipesUsed, idleDurationMs) {
6
6
  if (error !== null
7
7
  && typeof error === "object"
8
8
  && "code" in error
@@ -16,7 +16,8 @@ function callbackFailure(error, swipesUsed) {
16
16
  status: "failed",
17
17
  code: error.code,
18
18
  message: error instanceof Error ? error.message : error.code,
19
- swipesUsed
19
+ swipesUsed,
20
+ idleDurationMs
20
21
  };
21
22
  }
22
23
  return undefined;
@@ -26,41 +27,102 @@ export class ScrollToExecutor {
26
27
  constructor(options) {
27
28
  this.options = options;
28
29
  }
30
+ async resolveTarget(step, layout, signal) {
31
+ if (step.anchor !== undefined) {
32
+ const anchorResolver = this.options.anchorResolver;
33
+ if (anchorResolver !== undefined) {
34
+ const anchorResolution = await anchorResolver.resolve({
35
+ anchorId: step.anchor,
36
+ layout,
37
+ ...(this.options.viewport === undefined
38
+ ? {}
39
+ : { viewport: this.options.viewport() }),
40
+ ...(signal === undefined ? {} : { signal })
41
+ });
42
+ if (anchorResolution.status === "found") {
43
+ const fallbackElement = anchorResolution.element
44
+ ?? {
45
+ id: step.anchor,
46
+ enabled: true,
47
+ bounds: anchorResolution.bounds,
48
+ children: []
49
+ };
50
+ return {
51
+ status: "found",
52
+ element: fallbackElement,
53
+ point: anchorResolution.point ?? { x: 0, y: 0 }
54
+ };
55
+ }
56
+ if (anchorResolution.status === "ambiguous") {
57
+ return {
58
+ status: "failed",
59
+ code: "ANCHOR_AMBIGUOUS",
60
+ message: anchorResolution.message
61
+ ?? `Knowledge anchor ${step.anchor} resolved ambiguously`
62
+ };
63
+ }
64
+ }
65
+ }
66
+ if (step.locator === undefined) {
67
+ return {
68
+ status: "failed",
69
+ code: "ANCHOR_NOT_FOUND",
70
+ message: `Knowledge anchor ${step.anchor ?? "(none)"} was not found and no locator fallback exists`
71
+ };
72
+ }
73
+ const resolution = resolveLocator(layout, step.locator, { requireEnabled: false, viewport: this.options.viewport?.() });
74
+ if (resolution.status === "found") {
75
+ return {
76
+ status: "found",
77
+ element: resolution.element,
78
+ point: resolution.point
79
+ };
80
+ }
81
+ return {
82
+ status: "failed",
83
+ code: resolution.code,
84
+ message: resolution.message
85
+ };
86
+ }
29
87
  async execute(step, signal, initialLayout) {
30
88
  let swipesUsed = 0;
89
+ let idleDurationMs = 0;
31
90
  let layout = initialLayout;
32
91
  for (;;) {
33
92
  if (isCancelled(signal)) {
34
- return { status: "cancelled", swipesUsed };
93
+ return { status: "cancelled", swipesUsed, idleDurationMs };
35
94
  }
36
95
  try {
37
96
  layout ??= this.options.readLayout === undefined
38
- ? await this.options.androidCli.layout({
39
- deviceSerial: this.options.deviceSerial,
97
+ ? (await this.options.uiSnapshotProvider.capture({
98
+ reason: "locate",
99
+ freshness: "sameMutationEpoch",
40
100
  ...(signal === undefined ? {} : { signal }),
41
101
  timeoutMs: this.options.idle.timeoutMs
42
- })
102
+ })).roots
43
103
  : await this.options.readLayout();
44
104
  }
45
105
  catch (error) {
46
- const failed = callbackFailure(error, swipesUsed);
106
+ const failed = callbackFailure(error, swipesUsed, idleDurationMs);
47
107
  if (failed !== undefined)
48
108
  return failed;
49
109
  throw error;
50
110
  }
51
111
  if (isCancelled(signal)) {
52
- return { status: "cancelled", swipesUsed };
112
+ return { status: "cancelled", swipesUsed, idleDurationMs };
53
113
  }
54
- const target = resolveLocator(layout, step.locator, { requireEnabled: false });
114
+ const target = await this.resolveTarget(step, layout, signal);
55
115
  if (target.status === "found") {
56
- return { status: "found", swipesUsed };
116
+ return { status: "found", swipesUsed, idleDurationMs };
57
117
  }
58
- if (target.code === "LOCATOR_AMBIGUOUS") {
118
+ if (target.code === "LOCATOR_AMBIGUOUS"
119
+ || target.code === "ANCHOR_AMBIGUOUS") {
59
120
  return {
60
121
  status: "failed",
61
- code: "LOCATOR_AMBIGUOUS",
122
+ code: target.code,
62
123
  message: target.message,
63
- swipesUsed
124
+ swipesUsed,
125
+ idleDurationMs
64
126
  };
65
127
  }
66
128
  if (swipesUsed >= step.maxSwipes) {
@@ -68,16 +130,18 @@ export class ScrollToExecutor {
68
130
  status: "failed",
69
131
  code: "SCROLL_TARGET_NOT_FOUND",
70
132
  message: `Target not visible after ${String(step.maxSwipes)} swipes`,
71
- swipesUsed
133
+ swipesUsed,
134
+ idleDurationMs
72
135
  };
73
136
  }
74
- let container = resolveLocator(layout, step.container, { requireEnabled: false });
137
+ let container = resolveLocator(layout, step.container, { requireEnabled: false, viewport: this.options.viewport?.() });
75
138
  if (container.status !== "found") {
76
139
  return {
77
140
  status: "failed",
78
141
  code: container.code,
79
142
  message: container.message,
80
- swipesUsed
143
+ swipesUsed,
144
+ idleDurationMs
81
145
  };
82
146
  }
83
147
  if (container.element.bounds === undefined) {
@@ -85,7 +149,8 @@ export class ScrollToExecutor {
85
149
  status: "failed",
86
150
  code: "ACTION_FAILED",
87
151
  message: "scroll container has no bounds to swipe",
88
- swipesUsed
152
+ swipesUsed,
153
+ idleDurationMs
89
154
  };
90
155
  }
91
156
  if (this.options.beforeSwipe !== undefined) {
@@ -93,33 +158,36 @@ export class ScrollToExecutor {
93
158
  layout = await this.options.beforeSwipe();
94
159
  }
95
160
  catch (error) {
96
- const failed = callbackFailure(error, swipesUsed);
161
+ const failed = callbackFailure(error, swipesUsed, idleDurationMs);
97
162
  if (failed !== undefined)
98
163
  return failed;
99
164
  throw error;
100
165
  }
101
166
  if (isCancelled(signal)) {
102
- return { status: "cancelled", swipesUsed };
167
+ return { status: "cancelled", swipesUsed, idleDurationMs };
103
168
  }
104
- const liveTarget = resolveLocator(layout, step.locator, { requireEnabled: false });
169
+ const liveTarget = await this.resolveTarget(step, layout, signal);
105
170
  if (liveTarget.status === "found") {
106
- return { status: "found", swipesUsed };
171
+ return { status: "found", swipesUsed, idleDurationMs };
107
172
  }
108
- if (liveTarget.code === "LOCATOR_AMBIGUOUS") {
173
+ if (liveTarget.code === "LOCATOR_AMBIGUOUS"
174
+ || liveTarget.code === "ANCHOR_AMBIGUOUS") {
109
175
  return {
110
176
  status: "failed",
111
- code: "LOCATOR_AMBIGUOUS",
177
+ code: liveTarget.code,
112
178
  message: liveTarget.message,
113
- swipesUsed
179
+ swipesUsed,
180
+ idleDurationMs
114
181
  };
115
182
  }
116
- container = resolveLocator(layout, step.container, { requireEnabled: false });
183
+ container = resolveLocator(layout, step.container, { requireEnabled: false, viewport: this.options.viewport?.() });
117
184
  if (container.status !== "found") {
118
185
  return {
119
186
  status: "failed",
120
187
  code: container.code,
121
188
  message: container.message,
122
- swipesUsed
189
+ swipesUsed,
190
+ idleDurationMs
123
191
  };
124
192
  }
125
193
  if (container.element.bounds === undefined) {
@@ -127,12 +195,13 @@ export class ScrollToExecutor {
127
195
  status: "failed",
128
196
  code: "ACTION_FAILED",
129
197
  message: "scroll container has no bounds to swipe",
130
- swipesUsed
198
+ swipesUsed,
199
+ idleDurationMs
131
200
  };
132
201
  }
133
202
  }
134
203
  if (isCancelled(signal)) {
135
- return { status: "cancelled", swipesUsed };
204
+ return { status: "cancelled", swipesUsed, idleDurationMs };
136
205
  }
137
206
  if (this.options.requireLiveContainerCapability === true
138
207
  && (!container.element.enabled
@@ -141,39 +210,42 @@ export class ScrollToExecutor {
141
210
  status: "failed",
142
211
  code: "ACTION_FAILED",
143
212
  message: "scroll container lost enabled scrollable bounds",
144
- swipesUsed
213
+ swipesUsed,
214
+ idleDurationMs
145
215
  };
146
216
  }
147
217
  try {
148
218
  await this.options.beforeMutation?.();
149
219
  }
150
220
  catch (error) {
151
- const failed = callbackFailure(error, swipesUsed);
221
+ const failed = callbackFailure(error, swipesUsed, idleDurationMs);
152
222
  if (failed !== undefined)
153
223
  return failed;
154
224
  throw error;
155
225
  }
156
226
  if (isCancelled(signal)) {
157
- return { status: "cancelled", swipesUsed };
227
+ return { status: "cancelled", swipesUsed, idleDurationMs };
158
228
  }
159
229
  const swipe = await this.options.actionExecutor.swipeBounds(container.element.bounds, step.direction, step.distancePercent, step.durationMs, signal);
160
230
  if (isCancelled(signal)) {
161
- return { status: "cancelled", swipesUsed };
231
+ return { status: "cancelled", swipesUsed, idleDurationMs };
162
232
  }
163
233
  if (swipe.status === "failed") {
164
234
  return {
165
235
  status: "failed",
166
236
  code: swipe.code,
167
237
  message: swipe.message,
168
- swipesUsed
238
+ swipesUsed,
239
+ idleDurationMs
169
240
  };
170
241
  }
171
242
  const idle = await this.options.idleWaiter.waitUntilIdle(this.options.idle, signal);
243
+ idleDurationMs += idle.durationMs;
172
244
  if (isCancelled(signal)) {
173
- return { status: "cancelled", swipesUsed };
245
+ return { status: "cancelled", swipesUsed, idleDurationMs };
174
246
  }
175
247
  if (idle.status === "cancelled") {
176
- return { status: "cancelled", swipesUsed };
248
+ return { status: "cancelled", swipesUsed, idleDurationMs };
177
249
  }
178
250
  if (idle.status === "timeout") {
179
251
  return {
@@ -181,7 +253,17 @@ export class ScrollToExecutor {
181
253
  code: idle.code,
182
254
  message: "Layout did not become stable before timeout",
183
255
  swipesUsed,
184
- idle: { polls: idle.polls, lastDiff: idle.lastDiff }
256
+ idleDurationMs,
257
+ idle: {
258
+ polls: idle.polls,
259
+ durationMs: idle.durationMs,
260
+ samplingDurationMs: idle.samplingDurationMs,
261
+ strategy: idle.strategy,
262
+ ...(idle.backend === undefined ? {} : { backend: idle.backend }),
263
+ fallbackUsed: idle.fallbackUsed,
264
+ frameActivityDetected: idle.frameActivityDetected,
265
+ lastDiff: idle.lastDiff
266
+ }
185
267
  };
186
268
  }
187
269
  swipesUsed += 1;
@@ -0,0 +1,25 @@
1
+ import type { ExternalFlow } from "../../domain/external-flow.js";
2
+ import type { ExternalFlowCatalogEntry, ExternalFlowRecord } from "../../ports/external-flow-registry.js";
3
+ export interface ExternalFlowResolution {
4
+ flow: ExternalFlow;
5
+ flowSha256: string;
6
+ stepCount: number;
7
+ }
8
+ export interface ExternalFlowResolverDependencies {
9
+ registry: {
10
+ read: (input: {
11
+ projectRoot: string;
12
+ name: string;
13
+ }) => Promise<ExternalFlowRecord>;
14
+ list: (projectRoot: string) => Promise<readonly ExternalFlowCatalogEntry[]>;
15
+ };
16
+ }
17
+ export declare class ExternalFlowResolver {
18
+ private readonly dependencies;
19
+ constructor(dependencies: ExternalFlowResolverDependencies);
20
+ readonly resolve: (input: {
21
+ projectRoot: string;
22
+ name: string;
23
+ }) => Promise<ExternalFlowResolution>;
24
+ readonly list: (projectRoot: string) => Promise<readonly ExternalFlowCatalogEntry[]>;
25
+ }
@@ -0,0 +1,22 @@
1
+ import { createHash } from "node:crypto";
2
+ export class ExternalFlowResolver {
3
+ dependencies;
4
+ constructor(dependencies) {
5
+ this.dependencies = dependencies;
6
+ }
7
+ resolve = async (input) => {
8
+ const record = await this.dependencies.registry.read(input);
9
+ if (record.flow.includes.length > 0) {
10
+ throw new Error(`External Flow "${input.name}" uses includes, which are not supported in v1`);
11
+ }
12
+ return {
13
+ flow: record.flow,
14
+ flowSha256: sha256(record.bytes),
15
+ stepCount: record.flow.steps.length
16
+ };
17
+ };
18
+ list = async (projectRoot) => this.dependencies.registry.list(projectRoot);
19
+ }
20
+ function sha256(bytes) {
21
+ return createHash("sha256").update(bytes).digest("hex");
22
+ }
@@ -0,0 +1,54 @@
1
+ import type { TapHoundConfig } from "../../domain/config.js";
2
+ import type { JourneyLifecycleState } from "../../domain/journey-lifecycle.js";
3
+ import type { ProjectContext } from "../../domain/project-context.js";
4
+ import type { JourneyCompositionStore } from "../../ports/journey-composition-store.js";
5
+ import type { ProjectDescription } from "../project/project-describer.js";
6
+ export type JourneyCheckStatus = "fresh" | "stale" | "no-meta" | "invalid";
7
+ export type JourneyCheckReason = "journey-unreadable" | "journey-schema" | "meta-unreadable" | "meta-schema" | "journey-path-mismatch" | "project-hash" | "config-hash" | "module-drift" | "module-missing" | "brief-drift" | "brief-missing";
8
+ export interface JourneyCheckDriftedModule {
9
+ id: string;
10
+ reason: "sha256" | "missing";
11
+ }
12
+ export interface JourneyCheckEntry {
13
+ name: string;
14
+ journeyPath: string;
15
+ metaPath: string;
16
+ status: JourneyCheckStatus;
17
+ lifecycle: JourneyLifecycleState | undefined;
18
+ reasons: readonly JourneyCheckReason[];
19
+ driftedModules: readonly JourneyCheckDriftedModule[];
20
+ message: string | undefined;
21
+ }
22
+ export interface JourneyCheckSummary {
23
+ total: number;
24
+ fresh: number;
25
+ stale: number;
26
+ noMeta: number;
27
+ invalid: number;
28
+ }
29
+ export interface JourneyCheckResult {
30
+ entries: readonly JourneyCheckEntry[];
31
+ summary: JourneyCheckSummary;
32
+ }
33
+ export type JourneyCheckErrorCode = "CONFIG_INVALID";
34
+ export declare class JourneyCheckError extends Error {
35
+ readonly code: JourneyCheckErrorCode;
36
+ readonly name = "JourneyCheckError";
37
+ constructor(code: JourneyCheckErrorCode, message: string, options?: ErrorOptions);
38
+ }
39
+ export interface JourneyCheckInput {
40
+ projectRoot: string;
41
+ config: TapHoundConfig;
42
+ project: ProjectDescription;
43
+ bundle: ProjectContext;
44
+ }
45
+ export interface JourneyCheckDependencies {
46
+ store: Pick<JourneyCompositionStore, "read" | "listJourneyPaths" | "readJourneyMeta">;
47
+ }
48
+ export declare class JourneyCheckService {
49
+ private readonly dependencies;
50
+ constructor(dependencies: JourneyCheckDependencies);
51
+ readonly check: (input: JourneyCheckInput) => Promise<JourneyCheckResult>;
52
+ private readonly checkJourney;
53
+ private briefDriftReason;
54
+ }
@@ -0,0 +1,207 @@
1
+ import { createHash } from "node:crypto";
2
+ import { GenerationMetaSchema } from "../../domain/generation.js";
3
+ import { JourneySchema } from "../../domain/journey.js";
4
+ import { JOURNEYS_DIR } from "../../domain/workspace.js";
5
+ import { hashGenerationBinding } from "../generation/generation-starter.js";
6
+ export class JourneyCheckError extends Error {
7
+ code;
8
+ name = "JourneyCheckError";
9
+ constructor(code, message, options) {
10
+ super(message, options);
11
+ this.code = code;
12
+ }
13
+ }
14
+ function metaPathFor(journeyPath) {
15
+ return `${journeyPath.slice(0, -".json".length)}.meta.json`;
16
+ }
17
+ function journeyName(journeyPath) {
18
+ const prefix = `${JOURNEYS_DIR}/`;
19
+ const withoutPrefix = journeyPath.startsWith(prefix)
20
+ ? journeyPath.slice(prefix.length)
21
+ : journeyPath;
22
+ return withoutPrefix.slice(0, -".json".length);
23
+ }
24
+ function summarize(entries) {
25
+ const summary = {
26
+ total: entries.length,
27
+ fresh: 0,
28
+ stale: 0,
29
+ noMeta: 0,
30
+ invalid: 0
31
+ };
32
+ for (const entry of entries) {
33
+ if (entry.status === "fresh") {
34
+ summary.fresh += 1;
35
+ }
36
+ else if (entry.status === "stale") {
37
+ summary.stale += 1;
38
+ }
39
+ else if (entry.status === "no-meta") {
40
+ summary.noMeta += 1;
41
+ }
42
+ else {
43
+ summary.invalid += 1;
44
+ }
45
+ }
46
+ return summary;
47
+ }
48
+ function parseJson(bytes) {
49
+ return JSON.parse(bytes.toString("utf8"));
50
+ }
51
+ export class JourneyCheckService {
52
+ dependencies;
53
+ constructor(dependencies) {
54
+ this.dependencies = dependencies;
55
+ }
56
+ check = async (input) => {
57
+ const paths = await this.dependencies.store.listJourneyPaths(input.projectRoot);
58
+ const projectHash = hashGenerationBinding(input.project);
59
+ const configHash = hashGenerationBinding(input.config);
60
+ const modulesById = new Map(input.bundle.modules.map((module) => [module.id, module]));
61
+ const entries = [];
62
+ for (const journeyPath of paths) {
63
+ entries.push(await this.checkJourney({
64
+ projectRoot: input.projectRoot,
65
+ journeyPath,
66
+ projectHash,
67
+ configHash,
68
+ modulesById
69
+ }));
70
+ }
71
+ return { entries, summary: summarize(entries) };
72
+ };
73
+ checkJourney = async (input) => {
74
+ const entry = (status, reasons, message) => ({
75
+ name: journeyName(input.journeyPath),
76
+ journeyPath: input.journeyPath,
77
+ metaPath: metaPathFor(input.journeyPath),
78
+ status,
79
+ lifecycle: lifecycleFor(status, reasons),
80
+ reasons,
81
+ driftedModules: [],
82
+ message
83
+ });
84
+ let bytes;
85
+ try {
86
+ bytes = await this.dependencies.store.read({
87
+ projectRoot: input.projectRoot,
88
+ relativePath: input.journeyPath
89
+ });
90
+ }
91
+ catch (error) {
92
+ return entry("invalid", ["journey-unreadable"], error instanceof Error ? error.message : String(error));
93
+ }
94
+ try {
95
+ JourneySchema.parse(parseJson(bytes));
96
+ }
97
+ catch (error) {
98
+ return entry("invalid", ["journey-schema"], error instanceof Error ? error.message : String(error));
99
+ }
100
+ let metaBytes;
101
+ try {
102
+ metaBytes = await this.dependencies.store.readJourneyMeta({
103
+ projectRoot: input.projectRoot,
104
+ journeyPath: input.journeyPath
105
+ });
106
+ }
107
+ catch (error) {
108
+ return entry("invalid", ["meta-unreadable"], error instanceof Error ? error.message : String(error));
109
+ }
110
+ if (metaBytes === null) {
111
+ return entry("no-meta", [], undefined);
112
+ }
113
+ let meta;
114
+ try {
115
+ meta = GenerationMetaSchema.parse(parseJson(metaBytes));
116
+ }
117
+ catch (error) {
118
+ return entry("invalid", ["meta-schema"], error instanceof Error ? error.message : String(error));
119
+ }
120
+ const reasons = [];
121
+ const driftedModules = [];
122
+ if (meta.journeyPath !== input.journeyPath) {
123
+ reasons.push("journey-path-mismatch");
124
+ }
125
+ if (meta.bindings.projectHash !== input.projectHash) {
126
+ reasons.push("project-hash");
127
+ }
128
+ if (meta.bindings.configHash !== input.configHash) {
129
+ reasons.push("config-hash");
130
+ }
131
+ for (const module of meta.contextSelection.modules) {
132
+ const reference = input.modulesById.get(module.id);
133
+ if (reference === undefined) {
134
+ driftedModules.push({ id: module.id, reason: "missing" });
135
+ }
136
+ else if (reference.sha256 !== module.sha256) {
137
+ driftedModules.push({ id: module.id, reason: "sha256" });
138
+ }
139
+ }
140
+ if (driftedModules.some((module) => module.reason === "sha256")) {
141
+ reasons.push("module-drift");
142
+ }
143
+ if (driftedModules.some((module) => module.reason === "missing")) {
144
+ reasons.push("module-missing");
145
+ }
146
+ if (meta.sourceBrief !== undefined) {
147
+ reasons.push(...await this.briefDriftReason(input.projectRoot, meta.sourceBrief));
148
+ }
149
+ const status = reasons.length === 0 ? "fresh" : "stale";
150
+ return {
151
+ name: journeyName(input.journeyPath),
152
+ journeyPath: input.journeyPath,
153
+ metaPath: metaPathFor(input.journeyPath),
154
+ status,
155
+ lifecycle: meta.retired !== undefined
156
+ ? "retired"
157
+ : status === "fresh"
158
+ ? meta.status
159
+ : classifyLifecycle(reasons),
160
+ reasons,
161
+ driftedModules,
162
+ message: undefined
163
+ };
164
+ };
165
+ async briefDriftReason(projectRoot, brief) {
166
+ let bytes;
167
+ try {
168
+ bytes = await this.dependencies.store.read({
169
+ projectRoot,
170
+ relativePath: brief.path
171
+ });
172
+ }
173
+ catch {
174
+ return ["brief-missing"];
175
+ }
176
+ return createHash("sha256").update(bytes).digest("hex") === brief.sha256
177
+ ? []
178
+ : ["brief-drift"];
179
+ }
180
+ }
181
+ const STALE_REASONS = new Set([
182
+ "journey-path-mismatch",
183
+ "project-hash",
184
+ "module-drift",
185
+ "module-missing",
186
+ "brief-drift",
187
+ "brief-missing"
188
+ ]);
189
+ function lifecycleFor(status, reasons) {
190
+ if (status === "invalid") {
191
+ return undefined;
192
+ }
193
+ if (status === "no-meta") {
194
+ return "draft";
195
+ }
196
+ if (reasons.length === 0) {
197
+ return "verified";
198
+ }
199
+ return reasons.some((reason) => STALE_REASONS.has(reason))
200
+ ? "stale"
201
+ : "suspect";
202
+ }
203
+ function classifyLifecycle(reasons) {
204
+ return reasons.some((reason) => STALE_REASONS.has(reason))
205
+ ? "stale"
206
+ : "suspect";
207
+ }
@@ -0,0 +1,26 @@
1
+ import type { JourneyCompositionStore } from "../../ports/journey-composition-store.js";
2
+ export type JourneyPromotionErrorCode = "JOURNEY_NOT_FOUND" | "JOURNEY_INVALID" | "META_MISSING" | "META_INVALID" | "JOURNEY_ALREADY_PROMOTED" | "EVIDENCE_MISSING" | "EVIDENCE_HASH_MISMATCH" | "JOURNEY_MODIFIED";
3
+ export declare class JourneyPromotionError extends Error {
4
+ readonly code: JourneyPromotionErrorCode;
5
+ readonly name = "JourneyPromotionError";
6
+ constructor(code: JourneyPromotionErrorCode, message: string, options?: ErrorOptions);
7
+ }
8
+ export interface JourneyPromotionResult {
9
+ status: "promoted";
10
+ journeyPath: string;
11
+ metaPath: string;
12
+ generationId: string;
13
+ promotedAt: string;
14
+ }
15
+ export declare class JourneyPromoter {
16
+ private readonly dependencies;
17
+ constructor(dependencies: {
18
+ store: Pick<JourneyCompositionStore, "read" | "readJourneyMeta" | "writeText">;
19
+ });
20
+ readonly promote: (input: {
21
+ projectRoot: string;
22
+ journeyPath: string;
23
+ reason: string;
24
+ now: Date;
25
+ }) => Promise<JourneyPromotionResult>;
26
+ }