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
@@ -0,0 +1,110 @@
1
+ import { ProjectContextModuleSchema, ProjectContextSchema } from "../../domain/project-context.js";
2
+ import { projectRelativePath } from "../../shared/paths.js";
3
+ import { MAX_CONTEXT_SHARD_BYTES } from "./context-loader.js";
4
+ import { assertShardIdentity } from "./shard-identity.js";
5
+ import { assertProjectPathUnder, CONTEXT_DIR } from "../../domain/workspace.js";
6
+ export class ContextRehashError extends Error {
7
+ code;
8
+ name = "ContextRehashError";
9
+ constructor(code, message) {
10
+ super(message);
11
+ this.code = code;
12
+ }
13
+ }
14
+ export class ContextRehasher {
15
+ dependencies;
16
+ constructor(dependencies) {
17
+ this.dependencies = dependencies;
18
+ }
19
+ rehash = async (input) => {
20
+ const contextRelativePath = projectRelativePath(input.projectRoot, input.contextPath, (message) => new ContextRehashError("CONTEXT_INVALID", message));
21
+ try {
22
+ assertProjectPathUnder(input.projectRoot, contextRelativePath, CONTEXT_DIR, "Project Context output");
23
+ }
24
+ catch (error) {
25
+ throw new ContextRehashError("CONTEXT_INVALID", error instanceof Error ? error.message : String(error));
26
+ }
27
+ const { bundle, indexHash } = await this.dependencies.loader.readIndex({
28
+ projectRoot: input.projectRoot,
29
+ contextPath: input.contextPath
30
+ });
31
+ const requestedIds = input.moduleIds === undefined || input.moduleIds.length === 0
32
+ ? undefined
33
+ : new Set(input.moduleIds);
34
+ const moduleResults = [];
35
+ let anyChanged = false;
36
+ for (const reference of bundle.modules) {
37
+ if (requestedIds !== undefined && !requestedIds.has(reference.id)) {
38
+ continue;
39
+ }
40
+ const inspection = await this.dependencies.files.inspectProjectFile({
41
+ projectRoot: input.projectRoot,
42
+ relativePath: reference.contextPath,
43
+ maximumBytes: MAX_CONTEXT_SHARD_BYTES
44
+ });
45
+ if (inspection.status !== "inspected") {
46
+ throw new ContextRehashError("CONTEXT_INVALID", `Context shard cannot be read: ${reference.contextPath}`);
47
+ }
48
+ let parsedJson;
49
+ try {
50
+ parsedJson = JSON.parse(inspection.bytes?.toString("utf8") ?? "");
51
+ }
52
+ catch {
53
+ throw new ContextRehashError("CONTEXT_INVALID", `Context shard is not valid JSON: ${reference.contextPath}`);
54
+ }
55
+ const document = ProjectContextModuleSchema.safeParse(parsedJson);
56
+ if (!document.success) {
57
+ throw new ContextRehashError("CONTEXT_INVALID", `Context shard does not match the module schema: ${reference.contextPath}`);
58
+ }
59
+ assertShardIdentity(reference, document.data, (message) => new ContextRehashError("CONTEXT_INVALID", message));
60
+ const changed = inspection.sha256 !== reference.sha256;
61
+ if (changed) {
62
+ anyChanged = true;
63
+ }
64
+ moduleResults.push({
65
+ id: reference.id,
66
+ previousSha256: reference.sha256,
67
+ currentSha256: inspection.sha256,
68
+ changed
69
+ });
70
+ }
71
+ if (!anyChanged) {
72
+ return {
73
+ status: "unchanged",
74
+ modules: moduleResults,
75
+ previousIndexHash: indexHash,
76
+ indexHash
77
+ };
78
+ }
79
+ const nextModules = bundle.modules.map((reference) => {
80
+ const result = moduleResults.find((r) => r.id === reference.id);
81
+ return result !== undefined && result.changed
82
+ ? { ...reference, sha256: result.currentSha256 }
83
+ : reference;
84
+ });
85
+ const nextBundle = {
86
+ ...bundle,
87
+ modules: nextModules
88
+ };
89
+ const parsedBundle = ProjectContextSchema.safeParse(nextBundle);
90
+ if (!parsedBundle.success) {
91
+ throw new ContextRehashError("CONTEXT_INVALID", "Rehashed Project Context index does not match the version 2 schema");
92
+ }
93
+ const written = await this.dependencies.writer.writeContextDocument({
94
+ projectRoot: input.projectRoot,
95
+ relativePath: contextRelativePath,
96
+ document: parsedBundle.data
97
+ });
98
+ if (written.status !== "written") {
99
+ throw new ContextRehashError("CONTEXT_WRITE_FAILED", written.status === "escape"
100
+ ? `Context document resolves outside the project: ${contextRelativePath}`
101
+ : `Context document cannot be written: ${contextRelativePath}${"message" in written ? `: ${written.message}` : ""}`);
102
+ }
103
+ return {
104
+ status: "rehashed",
105
+ modules: moduleResults,
106
+ previousIndexHash: indexHash,
107
+ indexHash: written.sha256
108
+ };
109
+ };
110
+ }
@@ -1,27 +1,49 @@
1
1
  import type { TapHoundConfig } from "../../domain/config.js";
2
+ import { type ProjectContextModule } from "../../domain/project-context.js";
2
3
  import { type ProjectFileInspector } from "../../ports/project-file-inspector.js";
4
+ import type { ProjectInventoryInspector } from "../../ports/project-inventory-inspector.js";
3
5
  export declare const MAX_CONTEXT_EVIDENCE_BYTES: number;
4
6
  export type ContextValidationReasonCode = "CONTEXT_SCHEMA_INVALID" | "CONTEXT_IDENTITY_MISMATCH" | "PROJECT_ROOT_UNREADABLE" | "PROJECT_ROOT_NOT_DIRECTORY" | "EVIDENCE_SECRET_PATH" | "EVIDENCE_NOT_FOUND" | "EVIDENCE_UNREADABLE" | "EVIDENCE_NOT_FILE" | "EVIDENCE_PATH_ESCAPE" | "EVIDENCE_CHANGED_IDENTITY" | "EVIDENCE_TOO_LARGE" | "EVIDENCE_HASH_MISMATCH";
5
7
  export interface ContextValidationReason {
6
8
  code: ContextValidationReasonCode;
7
9
  message: string;
8
10
  }
11
+ export interface ContextValidationScope {
12
+ id: string;
13
+ inventoryChanged: boolean;
14
+ missingPaths: string[];
15
+ changedPaths: string[];
16
+ }
17
+ export interface ContextIdentityDivergence {
18
+ evidencePackageName: string;
19
+ configuredPackageName: string;
20
+ launchActivity: string;
21
+ }
9
22
  export type ContextValidationResult = {
10
23
  status: "valid";
24
+ scopes?: ContextValidationScope[] | undefined;
25
+ divergence?: ContextIdentityDivergence | undefined;
11
26
  } | {
12
27
  status: "stale";
13
28
  reason: ContextValidationReason;
29
+ scopes?: ContextValidationScope[];
14
30
  } | {
15
31
  status: "invalid";
16
32
  reason: ContextValidationReason;
33
+ scopes?: ContextValidationScope[];
17
34
  };
18
35
  export interface ContextValidationInput {
19
36
  context: unknown;
20
37
  projectRoot: string;
21
38
  config: TapHoundConfig;
39
+ modules?: ProjectContextModule[] | undefined;
40
+ reportScopes?: boolean | undefined;
41
+ identityPolicy?: "strict" | "configured" | undefined;
22
42
  }
23
43
  export declare class ContextValidator {
24
44
  private readonly files;
25
- constructor(files: ProjectFileInspector);
45
+ private readonly inventory?;
46
+ constructor(files: ProjectFileInspector, inventory?: ProjectInventoryInspector | undefined);
26
47
  readonly validate: (input: ContextValidationInput) => Promise<ContextValidationResult>;
48
+ private readonly inspectScopes;
27
49
  }
@@ -1,5 +1,6 @@
1
1
  import { normalizeActivity } from "../../domain/activity.js";
2
- import { ProjectContextSchema } from "../../domain/project-context.js";
2
+ import { evidenceMatches } from "./evidence-match.js";
3
+ import { ResolvedProjectContextSchema } from "../../domain/project-context.js";
3
4
  export const MAX_CONTEXT_EVIDENCE_BYTES = 1024 * 1024;
4
5
  const SECRET_FILE_NAMES = new Set([
5
6
  ".git-credentials",
@@ -70,13 +71,15 @@ function invalidInspection(path, inspection) {
70
71
  }
71
72
  export class ContextValidator {
72
73
  files;
73
- constructor(files) {
74
+ inventory;
75
+ constructor(files, inventory) {
74
76
  this.files = files;
77
+ this.inventory = inventory;
75
78
  }
76
79
  validate = async (input) => {
77
- const parsed = ProjectContextSchema.safeParse(input.context);
80
+ const parsed = ResolvedProjectContextSchema.safeParse(input.context);
78
81
  if (!parsed.success) {
79
- return invalid("CONTEXT_SCHEMA_INVALID", "Project Context does not match the version 1 schema");
82
+ return invalid("CONTEXT_SCHEMA_INVALID", "Resolved Project Context does not match the version 2 schema");
80
83
  }
81
84
  let configuredActivity;
82
85
  try {
@@ -85,11 +88,55 @@ export class ContextValidator {
85
88
  catch {
86
89
  return invalid("CONTEXT_IDENTITY_MISMATCH", "Project Context identity does not match the configured project");
87
90
  }
88
- if (parsed.data.packageName !== input.config.run.packageName
91
+ let divergence;
92
+ if (input.identityPolicy === "configured") {
93
+ const evidenceActivity = parsed.data.launchActivity;
94
+ const activityIsRelative = input.config.run.activity.startsWith(".");
95
+ const suffixMatch = (activityIsRelative
96
+ && evidenceActivity.endsWith(input.config.run.activity));
97
+ if (evidenceActivity === configuredActivity
98
+ || suffixMatch) {
99
+ if (parsed.data.packageName !== input.config.run.packageName) {
100
+ const evidencePackageName = suffixMatch
101
+ ? evidenceActivity.slice(0, evidenceActivity.length - input.config.run.activity.length)
102
+ : parsed.data.packageName;
103
+ divergence = {
104
+ evidencePackageName,
105
+ configuredPackageName: input.config.run.packageName,
106
+ launchActivity: evidenceActivity
107
+ };
108
+ }
109
+ }
110
+ else {
111
+ return invalid("CONTEXT_IDENTITY_MISMATCH", `Project Context identity does not match the configured project (evidence launchActivity ${evidenceActivity}, configured ${configuredActivity}; declare the activity with: taphound local add <id> --path <path> --package <pkg> --activity <relative-or-fq>)`);
112
+ }
113
+ }
114
+ else if (parsed.data.packageName !== input.config.run.packageName
89
115
  || parsed.data.launchActivity !== configuredActivity) {
90
116
  return invalid("CONTEXT_IDENTITY_MISMATCH", "Project Context identity does not match the configured project");
91
117
  }
92
118
  let staleReason;
119
+ const inventoryCache = new Map();
120
+ if (this.inventory !== undefined) {
121
+ for (const module of parsed.data.selection.modules) {
122
+ const inspection = await this.inventory.inspectProjectInventory({
123
+ projectRoot: input.projectRoot,
124
+ projectDir: module.projectDir,
125
+ categories: module.inventory.categories
126
+ });
127
+ inventoryCache.set(module.projectDir, inspection);
128
+ if (inspection.status !== "inspected") {
129
+ return invalid("CONTEXT_SCHEMA_INVALID", `Unable to inspect module inventory: ${module.id}`);
130
+ }
131
+ if (inspection.pathSetSha256 !== module.inventory.pathSetSha256
132
+ && staleReason === undefined) {
133
+ staleReason = {
134
+ code: "EVIDENCE_HASH_MISMATCH",
135
+ message: `Module file inventory changed: ${module.id}`
136
+ };
137
+ }
138
+ }
139
+ }
93
140
  for (const evidence of parsed.data.manifest.files) {
94
141
  if (isSecretEvidencePath(evidence.path)) {
95
142
  return invalid("EVIDENCE_SECRET_PATH", `Secret files cannot be context evidence: ${evidence.path}`);
@@ -106,15 +153,75 @@ export class ContextValidator {
106
153
  if (inspection.status !== "inspected") {
107
154
  return invalidInspection(evidence.path, inspection);
108
155
  }
109
- if (inspection.sha256 !== evidence.sha256) {
156
+ const inspected = inspection;
157
+ if (!evidenceMatches(evidence, inspected)) {
110
158
  staleReason ??= {
111
159
  code: "EVIDENCE_HASH_MISMATCH",
112
- message: `Evidence file changed: ${evidence.path}`
160
+ message: evidence.semanticSha256 !== undefined
161
+ ? `Semantic evidence changed: ${evidence.path}`
162
+ : `Evidence file changed: ${evidence.path}`
113
163
  };
114
164
  }
115
165
  }
166
+ const scopes = input.reportScopes === true && input.modules !== undefined
167
+ ? await this.inspectScopes(input.projectRoot, input.modules, inventoryCache)
168
+ : undefined;
116
169
  return staleReason === undefined
117
- ? { status: "valid" }
118
- : { status: "stale", reason: staleReason };
170
+ ? {
171
+ status: "valid",
172
+ ...(scopes === undefined ? {} : { scopes }),
173
+ ...(divergence === undefined ? {} : { divergence })
174
+ }
175
+ : {
176
+ status: "stale",
177
+ reason: staleReason,
178
+ ...(scopes === undefined ? {} : { scopes })
179
+ };
180
+ };
181
+ inspectScopes = async (projectRoot, modules, inventoryCache) => {
182
+ const scopes = [];
183
+ for (const module of modules) {
184
+ const cached = inventoryCache?.get(module.projectDir);
185
+ const inventory = cached !== undefined
186
+ ? cached
187
+ : this.inventory === undefined
188
+ ? undefined
189
+ : await this.inventory.inspectProjectInventory({
190
+ projectRoot,
191
+ projectDir: module.projectDir,
192
+ categories: module.inventory.categories
193
+ });
194
+ const inventoryChanged = inventory !== undefined
195
+ && inventory.status === "inspected"
196
+ && inventory.pathSetSha256 !== module.inventory.pathSetSha256;
197
+ const missingPaths = [];
198
+ const changedPaths = [];
199
+ for (const evidence of module.manifest.files) {
200
+ const inspection = await this.files.inspectProjectFile({
201
+ projectRoot,
202
+ relativePath: evidence.path,
203
+ maximumBytes: MAX_CONTEXT_EVIDENCE_BYTES
204
+ });
205
+ if (inspection.status !== "inspected") {
206
+ if (inspection.status === "notFound") {
207
+ missingPaths.push(evidence.path);
208
+ }
209
+ continue;
210
+ }
211
+ if (inspection.bytes === undefined) {
212
+ continue;
213
+ }
214
+ if (!evidenceMatches(evidence, inspection)) {
215
+ changedPaths.push(evidence.path);
216
+ }
217
+ }
218
+ scopes.push({
219
+ id: module.moduleId,
220
+ inventoryChanged,
221
+ missingPaths,
222
+ changedPaths
223
+ });
224
+ }
225
+ return scopes;
119
226
  };
120
227
  }
@@ -0,0 +1 @@
1
+ export declare function semanticSha256(value: string | Uint8Array): string;
@@ -0,0 +1,125 @@
1
+ import { createHash } from "node:crypto";
2
+ // Produces a conservative semantic hash for source and resource evidence.
3
+ //
4
+ // Comments and formatting whitespace are ignored, while string contents and
5
+ // all other tokens remain significant. This intentionally prefers false
6
+ // positives over allowing a potentially meaningful UI change to pass
7
+ // unnoticed.
8
+ //
9
+ // Supported comment forms: double-slash and hash line comments, C-style and
10
+ // XML block comments. Hash is retained because Gradle .properties provenance
11
+ // files use it.
12
+ //
13
+ // String literals (single quote, double quote, backtick) preserve their
14
+ // contents verbatim, with backslash escapes honored so a quote inside a
15
+ // string does not close it.
16
+ //
17
+ // Kotlin raw strings (triple double-quote) and XML CDATA sections are
18
+ // treated as opaque literals: their full content is preserved (including
19
+ // internal whitespace, which is semantically significant in both) and no
20
+ // comment or quote sequence inside them is interpreted.
21
+ export function semanticSha256(value) {
22
+ const source = typeof value === "string"
23
+ ? value
24
+ : Buffer.from(value).toString("utf8");
25
+ let normalized = "";
26
+ let quote;
27
+ let rawString = false;
28
+ let cdata = false;
29
+ let escaped = false;
30
+ let lineComment = false;
31
+ let blockComment = false;
32
+ for (let index = 0; index < source.length; index += 1) {
33
+ const current = source.charAt(index);
34
+ const next = source.charAt(index + 1);
35
+ const after = source.charAt(index + 2);
36
+ if (lineComment) {
37
+ if (current === "\n") {
38
+ lineComment = false;
39
+ }
40
+ continue;
41
+ }
42
+ if (blockComment) {
43
+ if ((current === "*" && next === "/")
44
+ || (current === "-"
45
+ && next === "-"
46
+ && after === ">")) {
47
+ blockComment = false;
48
+ index += current === "*" ? 1 : 2;
49
+ }
50
+ continue;
51
+ }
52
+ if (cdata) {
53
+ if (current === "]" && next === "]" && after === ">") {
54
+ cdata = false;
55
+ index += 2;
56
+ continue;
57
+ }
58
+ normalized += current;
59
+ continue;
60
+ }
61
+ if (rawString) {
62
+ if (current === "\"" && next === "\"" && after === "\"") {
63
+ rawString = false;
64
+ normalized += "\"\"\"";
65
+ index += 2;
66
+ continue;
67
+ }
68
+ normalized += current;
69
+ continue;
70
+ }
71
+ if (quote !== undefined) {
72
+ normalized += current;
73
+ if (escaped) {
74
+ escaped = false;
75
+ }
76
+ else if (current === "\\") {
77
+ escaped = true;
78
+ }
79
+ else if (current === quote) {
80
+ quote = undefined;
81
+ }
82
+ continue;
83
+ }
84
+ if (current === "\"" && next === "\"" && after === "\"") {
85
+ rawString = true;
86
+ normalized += "\"\"\"";
87
+ index += 2;
88
+ continue;
89
+ }
90
+ if (current === "<"
91
+ && next === "!"
92
+ && after === "["
93
+ && source.startsWith("[CDATA[", index + 2)) {
94
+ cdata = true;
95
+ normalized += source.slice(index, index + 9);
96
+ index += 8;
97
+ continue;
98
+ }
99
+ if ((current === "/" && next === "/") || current === "#") {
100
+ lineComment = true;
101
+ if (current === "/") {
102
+ index += 1;
103
+ }
104
+ continue;
105
+ }
106
+ if ((current === "/" && next === "*")
107
+ || (current === "<"
108
+ && next === "!"
109
+ && after === "-"
110
+ && source.charAt(index + 3) === "-")) {
111
+ blockComment = true;
112
+ index += current === "/" ? 1 : 3;
113
+ continue;
114
+ }
115
+ if (current === "'" || current === "\"" || current === "`") {
116
+ quote = current;
117
+ normalized += current;
118
+ continue;
119
+ }
120
+ if (!/\s/.test(current)) {
121
+ normalized += current;
122
+ }
123
+ }
124
+ return createHash("sha256").update(normalized).digest("hex");
125
+ }
@@ -0,0 +1,9 @@
1
+ export interface EvidenceRecord {
2
+ readonly sha256: string;
3
+ readonly semanticSha256?: string | undefined;
4
+ }
5
+ export interface InspectedFile {
6
+ readonly sha256: string;
7
+ readonly bytes?: Buffer | undefined;
8
+ }
9
+ export declare function evidenceMatches(evidence: EvidenceRecord, inspected: InspectedFile): boolean;
@@ -0,0 +1,8 @@
1
+ import { semanticSha256 } from "./evidence-hash.js";
2
+ export function evidenceMatches(evidence, inspected) {
3
+ if (evidence.semanticSha256 !== undefined) {
4
+ return inspected.bytes !== undefined
5
+ && semanticSha256(inspected.bytes) === evidence.semanticSha256;
6
+ }
7
+ return inspected.sha256 === evidence.sha256;
8
+ }
@@ -0,0 +1,2 @@
1
+ import type { ContextModuleReference, ProjectContextModule } from "../../domain/project-context.js";
2
+ export declare function assertShardIdentity(reference: ContextModuleReference, document: ProjectContextModule, createError: (message: string) => Error): void;
@@ -0,0 +1,7 @@
1
+ export function assertShardIdentity(reference, document, createError) {
2
+ if (document.moduleId !== reference.id
3
+ || document.projectDir !== reference.projectDir
4
+ || document.status !== reference.status) {
5
+ throw createError(`Context shard identity does not match its index: ${reference.id}`);
6
+ }
7
+ }
@@ -0,0 +1,25 @@
1
+ import { type AcceptanceContract } from "../../domain/contract.js";
2
+ import type { FailureCode } from "../../domain/failure.js";
3
+ import { type Journey } from "../../domain/journey.js";
4
+ export declare class ContractError extends Error {
5
+ readonly code: FailureCode;
6
+ constructor(code: FailureCode, message: string);
7
+ }
8
+ export interface LoadedContract {
9
+ contract: AcceptanceContract;
10
+ contractSha256: string;
11
+ journey: Journey;
12
+ journeyPath: string;
13
+ }
14
+ export interface ContractLoaderDependencies {
15
+ readText: (path: string) => Promise<string>;
16
+ }
17
+ export declare function hashContractText(text: string): string;
18
+ export declare class ContractLoader {
19
+ private readonly dependencies;
20
+ constructor(dependencies: ContractLoaderDependencies);
21
+ readonly load: (input: {
22
+ projectRoot: string;
23
+ contractPath: string;
24
+ }) => Promise<LoadedContract>;
25
+ }
@@ -0,0 +1,68 @@
1
+ import { createHash } from "node:crypto";
2
+ import { join } from "node:path";
3
+ import { AcceptanceContractSchema } from "../../domain/contract.js";
4
+ import { JourneySchema } from "../../domain/journey.js";
5
+ import { hashJourney } from "../../domain/report.js";
6
+ export class ContractError extends Error {
7
+ code;
8
+ constructor(code, message) {
9
+ super(message);
10
+ this.code = code;
11
+ this.name = "ContractError";
12
+ }
13
+ }
14
+ export function hashContractText(text) {
15
+ return createHash("sha256").update(text).digest("hex");
16
+ }
17
+ export class ContractLoader {
18
+ dependencies;
19
+ constructor(dependencies) {
20
+ this.dependencies = dependencies;
21
+ }
22
+ load = async (input) => {
23
+ let contractText;
24
+ try {
25
+ contractText = await this.dependencies.readText(input.contractPath);
26
+ }
27
+ catch (error) {
28
+ throw new ContractError("CONTRACT_INVALID", `Cannot read Acceptance Contract at ${input.contractPath}: ${error instanceof Error ? error.message : String(error)}`);
29
+ }
30
+ let contract;
31
+ try {
32
+ contract = AcceptanceContractSchema.parse(JSON.parse(contractText));
33
+ }
34
+ catch (error) {
35
+ throw new ContractError("CONTRACT_INVALID", `Acceptance Contract at ${input.contractPath} is invalid: ${error instanceof Error ? error.message : String(error)}`);
36
+ }
37
+ const journeyPath = join(input.projectRoot, contract.journey.path);
38
+ let journeyText;
39
+ try {
40
+ journeyText = await this.dependencies.readText(journeyPath);
41
+ }
42
+ catch (error) {
43
+ throw new ContractError("CONTRACT_JOURNEY_MISSING", `Bound Journey ${contract.journey.path} is missing: ${error instanceof Error ? error.message : String(error)}`);
44
+ }
45
+ let journey;
46
+ try {
47
+ journey = JourneySchema.parse(JSON.parse(journeyText));
48
+ }
49
+ catch (error) {
50
+ throw new ContractError("CONTRACT_JOURNEY_MISSING", `Bound Journey ${contract.journey.path} is invalid: ${error instanceof Error ? error.message : String(error)}`);
51
+ }
52
+ const journeySha256 = hashJourney(journey);
53
+ if (journeySha256 !== contract.journey.sha256) {
54
+ throw new ContractError("CONTRACT_JOURNEY_DRIFT", `Bound Journey ${contract.journey.path} drifted: binding ${contract.journey.sha256}, found ${journeySha256}. Re-bind the contract to the current Journey or restore the bound content.`);
55
+ }
56
+ for (const id of contract.requiredCheckpoints) {
57
+ if (!journey.checkpoints?.some((checkpoint) => checkpoint.id === id)) {
58
+ throw new ContractError("CONTRACT_INVALID", `Required Checkpoint ${id} is not defined by the bound Journey`);
59
+ }
60
+ }
61
+ return {
62
+ contract,
63
+ contractSha256: hashContractText(contractText),
64
+ journey,
65
+ journeyPath
66
+ };
67
+ };
68
+ }
@@ -0,0 +1,25 @@
1
+ import { type ContractReviewInput, type ContractVerdictView } from "../../domain/contract.js";
2
+ export interface ContractReviewMergeDependencies {
3
+ now: () => Date;
4
+ }
5
+ export interface ContractReviewMergeResult {
6
+ view: ContractVerdictView;
7
+ applied: boolean;
8
+ }
9
+ /**
10
+ * Applies reviewer findings on top of a deterministic Verdict view.
11
+ *
12
+ * Source-of-Truth enforcement (docs/source-of-truth.md):
13
+ * - a lower-trust layer (semantic / multimodal reviewer) may escalate a
14
+ * successful or uncertain result into `needsReview`;
15
+ * - it must never rewrite a deterministic `fail` or `invalid` back to
16
+ * success; those stay immutable and the review is recorded as not applied.
17
+ */
18
+ export declare class ContractReviewMerger {
19
+ private readonly dependencies;
20
+ constructor(dependencies: ContractReviewMergeDependencies);
21
+ readonly merge: (input: {
22
+ view: ContractVerdictView;
23
+ review: ContractReviewInput;
24
+ }) => Promise<ContractReviewMergeResult>;
25
+ }
@@ -0,0 +1,51 @@
1
+ import { ContractReviewSchema, ContractVerdictViewSchema } from "../../domain/contract.js";
2
+ const IMMUTABLE_VERDICTS = new Set([
3
+ "fail",
4
+ "invalid"
5
+ ]);
6
+ /**
7
+ * Applies reviewer findings on top of a deterministic Verdict view.
8
+ *
9
+ * Source-of-Truth enforcement (docs/source-of-truth.md):
10
+ * - a lower-trust layer (semantic / multimodal reviewer) may escalate a
11
+ * successful or uncertain result into `needsReview`;
12
+ * - it must never rewrite a deterministic `fail` or `invalid` back to
13
+ * success; those stay immutable and the review is recorded as not applied.
14
+ */
15
+ export class ContractReviewMerger {
16
+ dependencies;
17
+ constructor(dependencies) {
18
+ this.dependencies = dependencies;
19
+ }
20
+ merge = (input) => {
21
+ const { view, review } = input;
22
+ const immutable = IMMUTABLE_VERDICTS.has(view.verdict);
23
+ const applied = !immutable;
24
+ const previousFindings = view.review?.findings ?? [];
25
+ const record = ContractReviewSchema.parse({
26
+ version: 1,
27
+ source: review.source,
28
+ ...(review.model === undefined ? {} : { model: review.model }),
29
+ ...(review.promptVersion === undefined
30
+ ? {}
31
+ : { promptVersion: review.promptVersion }),
32
+ findings: [...previousFindings, ...review.findings],
33
+ appliedAt: new Date(this.dependencies.now()).toISOString(),
34
+ applied,
35
+ baseVerdict: view.verdict,
36
+ baseReason: view.reason
37
+ });
38
+ const merged = ContractVerdictViewSchema.parse({
39
+ ...view,
40
+ ...(applied
41
+ ? {
42
+ verdict: "needsReview",
43
+ reason: "REVIEW_FINDINGS",
44
+ message: `Reviewer ${review.source} found ${String(record.findings.length)} finding(s) requiring human review`
45
+ }
46
+ : {}),
47
+ review: record
48
+ });
49
+ return Promise.resolve({ view: merged, applied });
50
+ };
51
+ }