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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/README.md +49 -149
  2. package/README.zh-CN.md +47 -147
  3. package/assets/skills/taphound-case-suite/SKILL.md +363 -0
  4. package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
  5. package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
  6. package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
  7. package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
  8. package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
  9. package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
  10. package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
  11. package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
  12. package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
  13. package/assets/skills/taphound-flash/SKILL.md +115 -0
  14. package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
  15. package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
  16. package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
  17. package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
  18. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
  19. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
  20. package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
  21. package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
  22. package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
  23. package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
  24. package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
  25. package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
  26. package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
  27. package/assets/skills/taphound-journey-generator/SKILL.md +500 -0
  28. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
  29. package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
  30. package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
  31. package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
  32. package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
  33. package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
  34. package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
  35. package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
  36. package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
  37. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
  38. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
  39. package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +561 -0
  40. package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
  41. package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
  42. package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
  43. package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
  44. package/assets/skills/taphound-verify-change/SKILL.md +91 -0
  45. package/assets/skills/taphound-verify-change/references/accept.md +38 -0
  46. package/assets/skills/taphound-verify-change/references/preserve.md +349 -0
  47. package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
  48. package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
  49. package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
  50. package/dist/adapters/adb/adb-adapter.d.ts +16 -2
  51. package/dist/adapters/adb/adb-adapter.js +199 -0
  52. package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
  53. package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
  54. package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
  55. package/dist/adapters/adb/ui-automator-parser.js +160 -0
  56. package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
  57. package/dist/adapters/adb/window-topology-parser.js +101 -0
  58. package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
  59. package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
  60. package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
  61. package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
  62. package/dist/adapters/android-cli/layout-parser.js +12 -8
  63. package/dist/adapters/appium/appium-doctor.d.ts +7 -0
  64. package/dist/adapters/appium/appium-doctor.js +128 -0
  65. package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +34 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +240 -0
  67. package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
  68. package/dist/adapters/camera/camera-probe-adapter.js +286 -0
  69. package/dist/adapters/filesystem/artifact-store.js +40 -1
  70. package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
  71. package/dist/adapters/filesystem/context-document-writer.js +112 -0
  72. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  73. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  74. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  75. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  76. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  77. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  78. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  79. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  80. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  81. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  82. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  83. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  84. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  85. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  86. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  87. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  88. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  89. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  90. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  91. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  92. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  93. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  94. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  95. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  96. package/dist/adapters/filesystem/skill-installer.js +40 -11
  97. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  98. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  99. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  100. package/dist/adapters/git/node-git-diff.js +114 -0
  101. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  102. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  103. package/dist/adapters/process/node-process-runner.js +11 -2
  104. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  105. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  106. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  107. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  108. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  109. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  110. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  111. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  112. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  113. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  114. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  115. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  116. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  122. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  123. package/dist/adapters/runtime/session-adb-view.js +193 -0
  124. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  125. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  126. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  127. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  128. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  129. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  130. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  131. package/dist/adapters/ui/device-layout-temp.js +18 -0
  132. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  133. package/dist/adapters/ui/device-ui-environment.js +81 -0
  134. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  135. package/dist/adapters/ui/layout-normalization.js +44 -0
  136. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  137. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  138. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  139. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  140. package/dist/application/align/align-service.d.ts +42 -0
  141. package/dist/application/align/align-service.js +106 -0
  142. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  143. package/dist/application/assertion/expectation-evaluator.js +156 -18
  144. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  145. package/dist/application/assertion/guarded-expectation.js +74 -0
  146. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  147. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  148. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  149. package/dist/application/checkpoint/baseline-error.js +8 -0
  150. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  151. package/dist/application/checkpoint/baseline-service.js +147 -0
  152. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  153. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  154. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  155. package/dist/application/checkpoint/regression-comparator.js +192 -0
  156. package/dist/application/collector/logcat-collector.d.ts +22 -1
  157. package/dist/application/collector/logcat-collector.js +103 -15
  158. package/dist/application/collector/logcat-event.d.ts +8 -0
  159. package/dist/application/collector/logcat-event.js +79 -0
  160. package/dist/application/collector/logcat-stop.d.ts +2 -0
  161. package/dist/application/collector/logcat-stop.js +11 -0
  162. package/dist/application/context/context-generator.d.ts +45 -0
  163. package/dist/application/context/context-generator.js +228 -0
  164. package/dist/application/context/context-loader.d.ts +40 -0
  165. package/dist/application/context/context-loader.js +223 -0
  166. package/dist/application/context/context-refresher.d.ts +59 -0
  167. package/dist/application/context/context-refresher.js +349 -0
  168. package/dist/application/context/context-rehasher.d.ts +36 -0
  169. package/dist/application/context/context-rehasher.js +110 -0
  170. package/dist/application/context/context-validator.d.ts +23 -1
  171. package/dist/application/context/context-validator.js +116 -9
  172. package/dist/application/context/evidence-hash.d.ts +1 -0
  173. package/dist/application/context/evidence-hash.js +125 -0
  174. package/dist/application/context/evidence-match.d.ts +9 -0
  175. package/dist/application/context/evidence-match.js +8 -0
  176. package/dist/application/context/shard-identity.d.ts +2 -0
  177. package/dist/application/context/shard-identity.js +7 -0
  178. package/dist/application/contract/contract-loader.d.ts +25 -0
  179. package/dist/application/contract/contract-loader.js +68 -0
  180. package/dist/application/contract/contract-review.d.ts +25 -0
  181. package/dist/application/contract/contract-review.js +51 -0
  182. package/dist/application/contract/contract-verifier.d.ts +53 -0
  183. package/dist/application/contract/contract-verifier.js +645 -0
  184. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  185. package/dist/application/devices/resolve-device-assignments.js +60 -0
  186. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  187. package/dist/application/diagnosis/failure-classifier.js +179 -0
  188. package/dist/application/doctor/doctor-service.d.ts +36 -3
  189. package/dist/application/doctor/doctor-service.js +255 -25
  190. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  191. package/dist/application/generation/generation-app-preparer.js +28 -0
  192. package/dist/application/generation/generation-config-service.d.ts +21 -0
  193. package/dist/application/generation/generation-config-service.js +53 -0
  194. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  195. package/dist/application/generation/generation-confirmation-service.js +109 -24
  196. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  197. package/dist/application/generation/generation-context-snapshot.js +29 -0
  198. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  199. package/dist/application/generation/generation-finalizer.js +167 -70
  200. package/dist/application/generation/generation-publisher.js +12 -8
  201. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  202. package/dist/application/generation/generation-recovery-service.js +144 -0
  203. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  204. package/dist/application/generation/generation-reopen-service.js +37 -0
  205. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  206. package/dist/application/generation/generation-replace-service.js +116 -0
  207. package/dist/application/generation/generation-starter.d.ts +44 -4
  208. package/dist/application/generation/generation-starter.js +175 -8
  209. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  210. package/dist/application/generation/generation-step-executor.js +471 -108
  211. package/dist/application/generation/proposed-step-validator.js +96 -30
  212. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  213. package/dist/application/generation/replay-policy-loader.js +29 -0
  214. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  215. package/dist/application/generation/risk-evaluator.js +118 -3
  216. package/dist/application/generation/runtime-observer.d.ts +39 -7
  217. package/dist/application/generation/runtime-observer.js +193 -24
  218. package/dist/application/impact/impact-resolver.d.ts +32 -0
  219. package/dist/application/impact/impact-resolver.js +160 -0
  220. package/dist/application/init/init-service.js +26 -13
  221. package/dist/application/interaction/action-executor.d.ts +3 -2
  222. package/dist/application/interaction/action-executor.js +11 -1
  223. package/dist/application/interaction/action-target.d.ts +17 -0
  224. package/dist/application/interaction/action-target.js +40 -0
  225. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  226. package/dist/application/interaction/external-step-runner.js +332 -0
  227. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  228. package/dist/application/interaction/fallback-resolver.js +7 -5
  229. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  230. package/dist/application/interaction/scroll-to-executor.js +118 -36
  231. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  232. package/dist/application/journey/external-flow-resolver.js +22 -0
  233. package/dist/application/journey/journey-check-service.d.ts +54 -0
  234. package/dist/application/journey/journey-check-service.js +207 -0
  235. package/dist/application/journey/journey-promoter.d.ts +26 -0
  236. package/dist/application/journey/journey-promoter.js +123 -0
  237. package/dist/application/journey/journey-resolver.d.ts +42 -0
  238. package/dist/application/journey/journey-resolver.js +239 -0
  239. package/dist/application/journey/journey-retirer.d.ts +25 -0
  240. package/dist/application/journey/journey-retirer.js +87 -0
  241. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  242. package/dist/application/knowledge/anchor-resolver.js +110 -0
  243. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  244. package/dist/application/knowledge/knowledge-loader.js +36 -0
  245. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  246. package/dist/application/locator/layout-failure-summary.js +67 -0
  247. package/dist/application/locator/layout-traversal.d.ts +11 -0
  248. package/dist/application/locator/layout-traversal.js +18 -0
  249. package/dist/application/locator/locator-resolver.d.ts +13 -1
  250. package/dist/application/locator/locator-resolver.js +182 -18
  251. package/dist/application/observe/observe-service.d.ts +20 -0
  252. package/dist/application/observe/observe-service.js +91 -0
  253. package/dist/application/project/project-describer.d.ts +14 -6
  254. package/dist/application/project/project-describer.js +38 -5
  255. package/dist/application/recognition/screen-detector.d.ts +28 -0
  256. package/dist/application/recognition/screen-detector.js +111 -0
  257. package/dist/application/recorder/locator-selector.js +151 -17
  258. package/dist/application/recorder/recorder-service.d.ts +16 -4
  259. package/dist/application/recorder/recorder-service.js +420 -128
  260. package/dist/application/report/report-writer.js +1 -1
  261. package/dist/application/runtime/cold-launch.d.ts +28 -0
  262. package/dist/application/runtime/cold-launch.js +59 -0
  263. package/dist/application/runtime/step-runner.d.ts +49 -4
  264. package/dist/application/runtime/step-runner.js +721 -130
  265. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  266. package/dist/application/runtime/verify-runtime.js +554 -174
  267. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  268. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  269. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  270. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  271. package/dist/application/ui/ui-stability-probe.d.ts +3 -0
  272. package/dist/application/ui/ui-stability-probe.js +8 -0
  273. package/dist/application/wait/idle-advice.d.ts +6 -0
  274. package/dist/application/wait/idle-advice.js +27 -0
  275. package/dist/application/wait/idle-profiles.d.ts +15 -0
  276. package/dist/application/wait/idle-profiles.js +75 -0
  277. package/dist/application/wait/idle-waiter.d.ts +28 -4
  278. package/dist/application/wait/idle-waiter.js +186 -15
  279. package/dist/cli/commands/align.d.ts +3 -0
  280. package/dist/cli/commands/align.js +124 -0
  281. package/dist/cli/commands/baseline.d.ts +3 -0
  282. package/dist/cli/commands/baseline.js +130 -0
  283. package/dist/cli/commands/context.js +300 -27
  284. package/dist/cli/commands/contract.d.ts +3 -0
  285. package/dist/cli/commands/contract.js +120 -0
  286. package/dist/cli/commands/doctor.js +16 -9
  287. package/dist/cli/commands/failure.d.ts +3 -0
  288. package/dist/cli/commands/failure.js +63 -0
  289. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  290. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  291. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  292. package/dist/cli/commands/generation/session-commands.js +472 -0
  293. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  294. package/dist/cli/commands/generation/shared.js +291 -0
  295. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  296. package/dist/cli/commands/generation/step-commands.js +315 -0
  297. package/dist/cli/commands/generation.js +10 -507
  298. package/dist/cli/commands/impact.d.ts +3 -0
  299. package/dist/cli/commands/impact.js +87 -0
  300. package/dist/cli/commands/init.js +13 -6
  301. package/dist/cli/commands/journey.d.ts +3 -0
  302. package/dist/cli/commands/journey.js +382 -0
  303. package/dist/cli/commands/knowledge.d.ts +3 -0
  304. package/dist/cli/commands/knowledge.js +93 -0
  305. package/dist/cli/commands/observe.d.ts +3 -0
  306. package/dist/cli/commands/observe.js +127 -0
  307. package/dist/cli/commands/project.js +2 -1
  308. package/dist/cli/commands/record.js +18 -5
  309. package/dist/cli/commands/verify.js +273 -63
  310. package/dist/cli/dependencies.d.ts +125 -1
  311. package/dist/cli/dependencies.js +450 -51
  312. package/dist/cli/diff-verification.d.ts +41 -0
  313. package/dist/cli/diff-verification.js +192 -0
  314. package/dist/cli/main.js +49 -1
  315. package/dist/cli/output.d.ts +5 -3
  316. package/dist/cli/output.js +12 -0
  317. package/dist/cli/program.js +19 -1
  318. package/dist/cli/project-root.d.ts +1 -0
  319. package/dist/cli/project-root.js +6 -0
  320. package/dist/cli/runtime-selection.d.ts +22 -0
  321. package/dist/cli/runtime-selection.js +92 -0
  322. package/dist/cli/version.d.ts +1 -0
  323. package/dist/cli/version.js +14 -0
  324. package/dist/cli/workspace-guard.d.ts +2 -0
  325. package/dist/cli/workspace-guard.js +3 -0
  326. package/dist/domain/binding-reference.d.ts +4 -0
  327. package/dist/domain/binding-reference.js +23 -0
  328. package/dist/domain/checkpoint.d.ts +404 -0
  329. package/dist/domain/checkpoint.js +297 -0
  330. package/dist/domain/config.d.ts +107 -1
  331. package/dist/domain/config.js +52 -6
  332. package/dist/domain/contract.d.ts +413 -0
  333. package/dist/domain/contract.js +196 -0
  334. package/dist/domain/external-flow.d.ts +493 -0
  335. package/dist/domain/external-flow.js +15 -0
  336. package/dist/domain/failure-classification.d.ts +176 -0
  337. package/dist/domain/failure-classification.js +169 -0
  338. package/dist/domain/failure.d.ts +2 -1
  339. package/dist/domain/failure.js +123 -0
  340. package/dist/domain/generation.d.ts +1671 -132
  341. package/dist/domain/generation.js +202 -13
  342. package/dist/domain/geometry.d.ts +13 -0
  343. package/dist/domain/geometry.js +16 -0
  344. package/dist/domain/impact.d.ts +71 -0
  345. package/dist/domain/impact.js +76 -0
  346. package/dist/domain/init.d.ts +12 -4
  347. package/dist/domain/init.js +24 -18
  348. package/dist/domain/journey-composition.d.ts +2285 -0
  349. package/dist/domain/journey-composition.js +85 -0
  350. package/dist/domain/journey-lifecycle.d.ts +10 -0
  351. package/dist/domain/journey-lifecycle.js +9 -0
  352. package/dist/domain/journey.d.ts +2419 -212
  353. package/dist/domain/journey.js +384 -14
  354. package/dist/domain/knowledge.d.ts +165 -0
  355. package/dist/domain/knowledge.js +188 -0
  356. package/dist/domain/layout.d.ts +34 -5
  357. package/dist/domain/layout.js +64 -6
  358. package/dist/domain/locator-evidence.d.ts +3 -0
  359. package/dist/domain/locator-evidence.js +36 -0
  360. package/dist/domain/logcat-event.d.ts +54 -0
  361. package/dist/domain/logcat-event.js +40 -0
  362. package/dist/domain/observation.d.ts +33 -0
  363. package/dist/domain/observation.js +18 -0
  364. package/dist/domain/project-context.d.ts +219 -1
  365. package/dist/domain/project-context.js +209 -6
  366. package/dist/domain/proposed-step.d.ts +340 -60
  367. package/dist/domain/proposed-step.js +23 -3
  368. package/dist/domain/report.d.ts +1455 -28
  369. package/dist/domain/report.js +211 -14
  370. package/dist/domain/runtime-snapshot.d.ts +58 -1
  371. package/dist/domain/runtime-snapshot.js +14 -3
  372. package/dist/domain/runtime.d.ts +50 -0
  373. package/dist/domain/runtime.js +36 -0
  374. package/dist/domain/system-app-profiles.d.ts +6 -0
  375. package/dist/domain/system-app-profiles.js +43 -0
  376. package/dist/domain/ui-backend.d.ts +28 -0
  377. package/dist/domain/ui-backend.js +33 -0
  378. package/dist/domain/ui-cache.d.ts +11 -0
  379. package/dist/domain/ui-cache.js +10 -0
  380. package/dist/domain/window-hierarchy.d.ts +84 -0
  381. package/dist/domain/window-hierarchy.js +172 -0
  382. package/dist/domain/workflow-manifest.d.ts +77 -0
  383. package/dist/domain/workflow-manifest.js +136 -0
  384. package/dist/domain/workspace.d.ts +28 -0
  385. package/dist/domain/workspace.js +72 -0
  386. package/dist/ports/adb.d.ts +34 -1
  387. package/dist/ports/align-prompt.d.ts +11 -0
  388. package/dist/ports/align-prompt.js +6 -0
  389. package/dist/ports/anchor-resolver.d.ts +30 -0
  390. package/dist/ports/anchor-resolver.js +1 -0
  391. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  392. package/dist/ports/annotated-screen-resolver.js +1 -0
  393. package/dist/ports/camera-probe.d.ts +23 -0
  394. package/dist/ports/camera-probe.js +8 -0
  395. package/dist/ports/context-document-writer.d.ts +24 -0
  396. package/dist/ports/context-document-writer.js +1 -0
  397. package/dist/ports/detached-process-launcher.d.ts +12 -0
  398. package/dist/ports/detached-process-launcher.js +1 -0
  399. package/dist/ports/external-flow-registry.d.ts +37 -0
  400. package/dist/ports/external-flow-registry.js +1 -0
  401. package/dist/ports/generation-prompt.d.ts +2 -1
  402. package/dist/ports/generation-session-store.d.ts +12 -2
  403. package/dist/ports/git-diff.d.ts +9 -0
  404. package/dist/ports/git-diff.js +1 -0
  405. package/dist/ports/journey-composition-store.d.ts +17 -0
  406. package/dist/ports/journey-composition-store.js +1 -0
  407. package/dist/ports/knowledge-registry.d.ts +20 -0
  408. package/dist/ports/knowledge-registry.js +1 -0
  409. package/dist/ports/process-runner.d.ts +7 -0
  410. package/dist/ports/project-file-inspector.d.ts +1 -0
  411. package/dist/ports/project-identity-inspector.d.ts +24 -0
  412. package/dist/ports/project-identity-inspector.js +1 -0
  413. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  414. package/dist/ports/project-inventory-inspector.js +1 -0
  415. package/dist/ports/project-module-discoverer.d.ts +26 -0
  416. package/dist/ports/project-module-discoverer.js +1 -0
  417. package/dist/ports/recorder-prompt.d.ts +10 -1
  418. package/dist/ports/runtime-backend.d.ts +89 -0
  419. package/dist/ports/runtime-backend.js +13 -0
  420. package/dist/ports/runtime-capability.d.ts +12 -0
  421. package/dist/ports/runtime-capability.js +20 -0
  422. package/dist/ports/runtime-session-ports.d.ts +25 -0
  423. package/dist/ports/runtime-session-ports.js +1 -0
  424. package/dist/ports/screenshot.d.ts +11 -0
  425. package/dist/ports/screenshot.js +1 -0
  426. package/dist/ports/skill-installer.d.ts +2 -2
  427. package/dist/ports/ui-snapshot.d.ts +35 -0
  428. package/dist/ports/ui-snapshot.js +1 -0
  429. package/dist/ports/ui-stability.d.ts +19 -0
  430. package/dist/ports/ui-stability.js +1 -0
  431. package/dist/ports/workspace-layout.d.ts +4 -0
  432. package/dist/ports/workspace-layout.js +1 -0
  433. package/dist/shared/errors.d.ts +2 -0
  434. package/dist/shared/errors.js +22 -0
  435. package/dist/shared/paths.d.ts +2 -0
  436. package/dist/shared/paths.js +24 -0
  437. package/dist/shared/strings.d.ts +2 -0
  438. package/dist/shared/strings.js +16 -0
  439. package/package.json +6 -1
  440. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  441. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  442. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  443. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  444. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  445. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  446. package/dist/ports/android-cli.d.ts +0 -21
  447. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -0,0 +1,29 @@
1
+ import type { FileSystemGenerationSessionStoreHooks } from "../generation-session-store.js";
2
+ export interface SessionLockConfig {
3
+ generationRoot: string;
4
+ locksRoot: string;
5
+ lockTimeoutMs: number;
6
+ lockRetryMs: number;
7
+ hooks: Pick<FileSystemGenerationSessionStoreHooks, "beforeLockStagingWrite" | "beforeLockInstall" | "afterLockTombstoneRename">;
8
+ }
9
+ export interface LockOwner {
10
+ pid: number;
11
+ token: string;
12
+ }
13
+ /**
14
+ * The per-session exclusive lock: a linked owner file, reaped only when its
15
+ * owner process is gone. Every store operation runs inside `withLock`.
16
+ */
17
+ export declare class SessionLock {
18
+ private readonly config;
19
+ constructor(config: SessionLockConfig);
20
+ private readonly lockPath;
21
+ readonly withLock: <T>(id: string, operation: () => Promise<T>) => Promise<T>;
22
+ private readonly acquireLock;
23
+ private readonly tryInstallLock;
24
+ private readonly reapDeadOwnerLock;
25
+ private readonly releaseLock;
26
+ private readonly readLockOwner;
27
+ private readonly fileIdentity;
28
+ private readonly isProcessAlive;
29
+ }
@@ -0,0 +1,202 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { constants, link, lstat, open, rename, unlink } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { GenerationSessionStoreError } from "../../../ports/generation-session-store.js";
5
+ import { isErrnoException } from "../../../shared/errors.js";
6
+ import { asStoreIoError, captureStoreDirectory, serializeJson, verifyStoreDirectory } from "./store-files.js";
7
+ /**
8
+ * The per-session exclusive lock: a linked owner file, reaped only when its
9
+ * owner process is gone. Every store operation runs inside `withLock`.
10
+ */
11
+ export class SessionLock {
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ lockPath = (id) => (join(this.config.locksRoot, `${id}.lock`));
17
+ withLock = async (id, operation) => {
18
+ const token = randomUUID();
19
+ let generationRootEvidence;
20
+ let locksRootEvidence;
21
+ try {
22
+ generationRootEvidence = await captureStoreDirectory(this.config.generationRoot);
23
+ locksRootEvidence = await captureStoreDirectory(this.config.locksRoot);
24
+ await this.acquireLock(id, { pid: process.pid, token }, generationRootEvidence, locksRootEvidence);
25
+ await verifyStoreDirectory(generationRootEvidence);
26
+ await verifyStoreDirectory(locksRootEvidence);
27
+ }
28
+ catch (error) {
29
+ throw asStoreIoError(error, "acquire its exclusive lock");
30
+ }
31
+ let outcome;
32
+ let releaseError;
33
+ try {
34
+ outcome = {
35
+ status: "succeeded",
36
+ value: await operation()
37
+ };
38
+ }
39
+ catch (error) {
40
+ outcome = { status: "failed", error };
41
+ }
42
+ finally {
43
+ try {
44
+ await this.releaseLock(id, token);
45
+ }
46
+ catch (error) {
47
+ releaseError = error;
48
+ }
49
+ }
50
+ if (outcome.status === "failed") {
51
+ throw asStoreIoError(outcome.error, "complete a locked operation");
52
+ }
53
+ if (releaseError !== undefined) {
54
+ throw asStoreIoError(releaseError, "release its exclusive lock");
55
+ }
56
+ return outcome.value;
57
+ };
58
+ acquireLock = async (id, owner, generationRootEvidence, locksRootEvidence) => {
59
+ const lockPath = this.lockPath(id);
60
+ const deadline = Date.now() + this.config.lockTimeoutMs;
61
+ for (;;) {
62
+ if (await this.tryInstallLock(id, lockPath, owner, generationRootEvidence, locksRootEvidence)) {
63
+ return;
64
+ }
65
+ await this.reapDeadOwnerLock(id, lockPath);
66
+ if (Date.now() >= deadline) {
67
+ throw new GenerationSessionStoreError("LOCK_TIMEOUT", `Timed out acquiring generation session lock: ${id}`);
68
+ }
69
+ await new Promise((resolveDelay) => {
70
+ setTimeout(resolveDelay, this.config.lockRetryMs);
71
+ });
72
+ }
73
+ };
74
+ tryInstallLock = async (id, lockPath, owner, generationRootEvidence, locksRootEvidence) => {
75
+ const stagingPath = join(this.config.locksRoot, `.${id}.lock.acquire-${randomUUID()}.tmp`);
76
+ try {
77
+ const handle = await open(stagingPath, "wx", 0o600);
78
+ try {
79
+ await this.config.hooks.beforeLockStagingWrite?.();
80
+ await handle.writeFile(serializeJson(owner), "utf8");
81
+ await handle.sync();
82
+ }
83
+ finally {
84
+ await handle.close();
85
+ }
86
+ await this.config.hooks.beforeLockInstall?.();
87
+ await verifyStoreDirectory(generationRootEvidence);
88
+ await verifyStoreDirectory(locksRootEvidence);
89
+ try {
90
+ await link(stagingPath, lockPath);
91
+ }
92
+ catch (error) {
93
+ if (isErrnoException(error) && error.code === "EEXIST") {
94
+ return false;
95
+ }
96
+ throw error;
97
+ }
98
+ // The lock excludes other processes as soon as link() returns; it
99
+ // needs no directory sync. Only its owner record is synced (above), so
100
+ // a lock that survives a power loss names a dead owner and is reaped.
101
+ try {
102
+ await verifyStoreDirectory(generationRootEvidence);
103
+ await verifyStoreDirectory(locksRootEvidence);
104
+ }
105
+ catch (error) {
106
+ await this.releaseLock(id, owner.token).catch(() => undefined);
107
+ throw error;
108
+ }
109
+ return true;
110
+ }
111
+ finally {
112
+ await unlink(stagingPath).catch(() => undefined);
113
+ }
114
+ };
115
+ reapDeadOwnerLock = async (id, lockPath) => {
116
+ try {
117
+ const identity = await this.fileIdentity(lockPath);
118
+ const owner = await this.readLockOwner(lockPath);
119
+ if (owner === null || this.isProcessAlive(owner.pid)) {
120
+ return;
121
+ }
122
+ const tombstone = join(this.config.locksRoot, `.${id}.lock.reap-${randomUUID()}`);
123
+ await rename(lockPath, tombstone);
124
+ const movedIdentity = await this.fileIdentity(tombstone);
125
+ if (movedIdentity.dev !== identity.dev
126
+ || movedIdentity.ino !== identity.ino) {
127
+ await rename(tombstone, lockPath).catch(() => undefined);
128
+ return;
129
+ }
130
+ await this.config.hooks.afterLockTombstoneRename?.();
131
+ await unlink(tombstone);
132
+ }
133
+ catch (error) {
134
+ if (!isErrnoException(error) || error.code !== "ENOENT") {
135
+ throw error;
136
+ }
137
+ }
138
+ };
139
+ releaseLock = async (id, token) => {
140
+ const lockPath = this.lockPath(id);
141
+ try {
142
+ const identity = await this.fileIdentity(lockPath);
143
+ const current = await this.readLockOwner(lockPath);
144
+ if (current?.pid === process.pid && current.token === token) {
145
+ const tombstone = join(this.config.locksRoot, `.${id}.lock.release-${randomUUID()}`);
146
+ await rename(lockPath, tombstone);
147
+ const movedIdentity = await this.fileIdentity(tombstone);
148
+ if (movedIdentity.dev === identity.dev
149
+ && movedIdentity.ino === identity.ino) {
150
+ // A release lost to a power loss reappears as a dead-owner lock,
151
+ // which the next acquirer reaps; it needs no directory sync.
152
+ await unlink(tombstone);
153
+ }
154
+ else {
155
+ await rename(tombstone, lockPath).catch(() => undefined);
156
+ }
157
+ }
158
+ }
159
+ catch (error) {
160
+ if (!isErrnoException(error) || error.code !== "ENOENT") {
161
+ throw error;
162
+ }
163
+ }
164
+ };
165
+ readLockOwner = async (lockPath) => {
166
+ const handle = await open(lockPath, constants.O_RDONLY | constants.O_NOFOLLOW);
167
+ try {
168
+ const value = JSON.parse(await handle.readFile("utf8"));
169
+ if (value === null
170
+ || typeof value !== "object"
171
+ || !Number.isSafeInteger(value.pid)
172
+ || value.pid <= 0
173
+ || typeof value.token !== "string"
174
+ || value.token.length === 0) {
175
+ return null;
176
+ }
177
+ return value;
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ finally {
183
+ await handle.close();
184
+ }
185
+ };
186
+ fileIdentity = async (path) => {
187
+ const stats = await lstat(path, { bigint: true });
188
+ if (!stats.isFile() || stats.isSymbolicLink()) {
189
+ throw new GenerationSessionStoreError("IO_ERROR", `Generation lock path is not a real file: ${path}`);
190
+ }
191
+ return { dev: stats.dev, ino: stats.ino };
192
+ };
193
+ isProcessAlive = (pid) => {
194
+ try {
195
+ process.kill(pid, 0);
196
+ return true;
197
+ }
198
+ catch (error) {
199
+ return !isErrnoException(error) || error.code !== "ESRCH";
200
+ }
201
+ };
202
+ }
@@ -0,0 +1,24 @@
1
+ import { type GenerationInFlight, type GenerationSession, type VerificationPhase } from "../../../domain/generation.js";
2
+ export declare function assertId(id: unknown): asserts id is string;
3
+ export declare function parseSession(value: unknown, classifyInvalidId?: boolean): GenerationSession;
4
+ export declare function sessionId(value: GenerationSession): string;
5
+ export declare function parseVerificationPhase(value: unknown): VerificationPhase;
6
+ export declare function validateExpectedRevision(revision: number): void;
7
+ export declare function validateInitialRevision(session: GenerationSession): void;
8
+ export declare function validateNextRevision(id: string, expectedRevision: number, next: GenerationSession): void;
9
+ export declare function parseInFlight(value: unknown): GenerationInFlight;
10
+ export declare function sameInFlight(left: GenerationSession["inFlight"], right: GenerationSession["inFlight"]): boolean;
11
+ export declare function transitionStableState(session: GenerationSession): Record<string, unknown>;
12
+ export declare function assertCoreIdentityPreserved(current: GenerationSession, next: GenerationSession): void;
13
+ export declare function assertLatestSnapshotPreserved(current: GenerationSession, next: GenerationSession): void;
14
+ export declare function assertSnapshotTransition(current: GenerationSession, next: GenerationSession): void;
15
+ export declare function assertOrdinaryTransition(current: GenerationSession, next: GenerationSession): void;
16
+ export declare function verificationStableState(session: GenerationSession): Record<string, unknown>;
17
+ export declare function assertVerificationCompletionTransition(current: GenerationSession, next: GenerationSession, status: "passed" | "failed"): void;
18
+ export declare function assertVerificationRecoveryTransition(current: GenerationSession, next: GenerationSession): void;
19
+ export declare function assertVerificationReopenTransition(current: GenerationSession, next: GenerationSession): void;
20
+ export declare function assertBundlePublishableTransition(current: GenerationSession, next: GenerationSession): void;
21
+ export declare function confirmationStableState(session: GenerationSession): Record<string, unknown>;
22
+ export declare function assertConfirmationTransition(current: GenerationSession, next: GenerationSession): void;
23
+ export declare function assertRecoveryTransition(current: GenerationSession, next: GenerationSession): void;
24
+ export declare function assertArchiveTransition(current: GenerationSession, next: GenerationSession): void;
@@ -0,0 +1,340 @@
1
+ // Parsing and the allowed state transitions of a stored generation session.
2
+ import { GenerationInFlightSchema, GenerationSessionSchema, VerificationPhaseSchema, generationCoreIdentity } from "../../../domain/generation.js";
3
+ import { GenerationSessionStoreError } from "../../../ports/generation-session-store.js";
4
+ export function assertId(id) {
5
+ if (typeof id !== "string"
6
+ || !/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {
7
+ throw new GenerationSessionStoreError("INVALID_ID", "Invalid generation session id");
8
+ }
9
+ }
10
+ export function parseSession(value, classifyInvalidId = false) {
11
+ try {
12
+ return GenerationSessionSchema.parse(value);
13
+ }
14
+ catch (error) {
15
+ if (classifyInvalidId && value !== null && typeof value === "object") {
16
+ try {
17
+ const id = Reflect.get(value, "id");
18
+ if (typeof id === "string") {
19
+ assertId(id);
20
+ }
21
+ }
22
+ catch (idError) {
23
+ if (idError instanceof GenerationSessionStoreError) {
24
+ throw idError;
25
+ }
26
+ }
27
+ }
28
+ throw new GenerationSessionStoreError("INVALID_SESSION", "Generation session state is invalid", { cause: error });
29
+ }
30
+ }
31
+ export function sessionId(value) {
32
+ const id = value.id;
33
+ assertId(id);
34
+ return id;
35
+ }
36
+ export function parseVerificationPhase(value) {
37
+ try {
38
+ return VerificationPhaseSchema.parse(value);
39
+ }
40
+ catch (error) {
41
+ throw new GenerationSessionStoreError("INVALID_SESSION", "Verification phase is invalid", { cause: error });
42
+ }
43
+ }
44
+ export function validateExpectedRevision(revision) {
45
+ if (!Number.isSafeInteger(revision) || revision < 0) {
46
+ throw new GenerationSessionStoreError("INVALID_REVISION", "Invalid expected generation revision");
47
+ }
48
+ }
49
+ export function validateInitialRevision(session) {
50
+ if (session.revision !== 0) {
51
+ throw new GenerationSessionStoreError("INVALID_REVISION", "A new generation session must start at revision 0");
52
+ }
53
+ }
54
+ export function validateNextRevision(id, expectedRevision, next) {
55
+ validateExpectedRevision(expectedRevision);
56
+ if (expectedRevision === Number.MAX_SAFE_INTEGER) {
57
+ throw new GenerationSessionStoreError("INVALID_REVISION", "Generation revision cannot increment beyond Number.MAX_SAFE_INTEGER");
58
+ }
59
+ if (sessionId(next) !== id) {
60
+ throw new GenerationSessionStoreError("INVALID_ID", "Updated generation session id does not match the requested id");
61
+ }
62
+ if (next.revision !== expectedRevision + 1) {
63
+ throw new GenerationSessionStoreError("INVALID_REVISION", "Next generation revision must increment expectedRevision by exactly one");
64
+ }
65
+ }
66
+ export function parseInFlight(value) {
67
+ try {
68
+ return GenerationInFlightSchema.parse(value);
69
+ }
70
+ catch (error) {
71
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Expected inFlight record is invalid", { cause: error });
72
+ }
73
+ }
74
+ export function sameInFlight(left, right) {
75
+ return JSON.stringify(left) === JSON.stringify(right);
76
+ }
77
+ export function transitionStableState(session) {
78
+ return {
79
+ version: session.version,
80
+ id: session.id,
81
+ bindings: session.bindings,
82
+ target: session.target,
83
+ variables: session.variables,
84
+ ...(session.baseFlow === undefined ? {} : { baseFlow: session.baseFlow }),
85
+ candidateSteps: session.candidateSteps,
86
+ candidateSources: session.candidateSources,
87
+ pendingConfirmation: session.pendingConfirmation,
88
+ verification: session.verification,
89
+ verificationHistory: session.verificationHistory,
90
+ publication: session.publication
91
+ };
92
+ }
93
+ export function assertCoreIdentityPreserved(current, next) {
94
+ const currentIdentity = generationCoreIdentity(current);
95
+ const nextIdentity = generationCoreIdentity(next);
96
+ if (JSON.stringify(currentIdentity) !== JSON.stringify(nextIdentity)) {
97
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Generation Core identity is immutable");
98
+ }
99
+ }
100
+ export function assertLatestSnapshotPreserved(current, next) {
101
+ if (current.bindings.snapshotHash !== next.bindings.snapshotHash) {
102
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Latest snapshot may only change through commitSnapshot");
103
+ }
104
+ }
105
+ export function assertSnapshotTransition(current, next) {
106
+ assertCoreIdentityPreserved(current, next);
107
+ const currentBindings = {
108
+ projectHash: current.bindings.projectHash,
109
+ configHash: current.bindings.configHash,
110
+ contextHash: current.bindings.contextHash,
111
+ uiBackend: current.bindings.uiBackend
112
+ };
113
+ const { snapshotHash: nextSnapshotHash, ...nextBindings } = next.bindings;
114
+ if (current.state !== "active"
115
+ || current.inFlight !== null
116
+ || current.pendingConfirmation !== null
117
+ || current.verification.status !== "notRun"
118
+ || current.publication.status !== "notRun"
119
+ || next.state !== "active"
120
+ || next.inFlight !== null
121
+ || next.pendingConfirmation !== null
122
+ || nextSnapshotHash === null
123
+ || JSON.stringify(currentBindings) !== JSON.stringify(nextBindings)
124
+ || JSON.stringify({
125
+ ...transitionStableState(current),
126
+ bindings: undefined
127
+ }) !== JSON.stringify({
128
+ ...transitionStableState(next),
129
+ bindings: undefined
130
+ })) {
131
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Snapshot commit may only replace the active snapshot binding");
132
+ }
133
+ }
134
+ export function assertOrdinaryTransition(current, next) {
135
+ assertCoreIdentityPreserved(current, next);
136
+ assertLatestSnapshotPreserved(current, next);
137
+ if (current.verification.status !== "notRun"
138
+ || current.publication.status !== "notRun"
139
+ || JSON.stringify(current.verification) !== JSON.stringify(next.verification)
140
+ || JSON.stringify(current.publication) !== JSON.stringify(next.publication)) {
141
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Verification and publication require explicit transitions");
142
+ }
143
+ if (current.state === "recoveryRequired") {
144
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Recovery-required state must use the explicit recovery transition");
145
+ }
146
+ if (JSON.stringify(current.pendingConfirmation)
147
+ !== JSON.stringify(next.pendingConfirmation)) {
148
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Pending confirmation must use the explicit confirmation transition");
149
+ }
150
+ const stableStateMatches = JSON.stringify(transitionStableState(current))
151
+ === JSON.stringify(transitionStableState(next));
152
+ if (current.inFlight !== null) {
153
+ if (next.state === "recoveryRequired"
154
+ && sameInFlight(current.inFlight, next.inFlight)
155
+ && stableStateMatches) {
156
+ return;
157
+ }
158
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Persisted inFlight may only be marked recoveryRequired without mutation");
159
+ }
160
+ if (next.state === "recoveryRequired"
161
+ || (next.inFlight !== null && !stableStateMatches)) {
162
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Starting inFlight cannot mutate candidate or result state");
163
+ }
164
+ }
165
+ export function verificationStableState(session) {
166
+ return {
167
+ ...transitionStableState(session),
168
+ verification: undefined
169
+ };
170
+ }
171
+ export function assertVerificationCompletionTransition(current, next, status) {
172
+ assertCoreIdentityPreserved(current, next);
173
+ assertLatestSnapshotPreserved(current, next);
174
+ if (current.state !== "active"
175
+ || next.state !== "active"
176
+ || current.inFlight !== null
177
+ || next.inFlight !== null
178
+ || current.pendingConfirmation !== null
179
+ || next.pendingConfirmation !== null
180
+ || current.verification.status !== "running"
181
+ || next.verification.status !== status
182
+ || next.publication.status !== "notRun"
183
+ || JSON.stringify(verificationStableState(current))
184
+ !== JSON.stringify(verificationStableState(next))) {
185
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", `Verification completion must record ${status} from the running attempt`);
186
+ }
187
+ if (next.verification.status === "passed"
188
+ && next.verification.attemptId !== current.verification.attemptId) {
189
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Verification completion attempt does not match");
190
+ }
191
+ }
192
+ export function assertVerificationRecoveryTransition(current, next) {
193
+ assertCoreIdentityPreserved(current, next);
194
+ assertLatestSnapshotPreserved(current, next);
195
+ if (current.state !== "active"
196
+ || next.state !== "active"
197
+ || current.inFlight !== null
198
+ || next.inFlight !== null
199
+ || current.pendingConfirmation !== null
200
+ || next.pendingConfirmation !== null
201
+ || current.verification.status !== "running"
202
+ || next.verification.status !== "notRun"
203
+ || current.publication.status !== "notRun"
204
+ || next.publication.status !== "notRun"
205
+ || JSON.stringify(verificationStableState(current))
206
+ !== JSON.stringify(verificationStableState(next))) {
207
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Verification recovery may only reset an interrupted running attempt");
208
+ }
209
+ }
210
+ export function assertVerificationReopenTransition(current, next) {
211
+ assertCoreIdentityPreserved(current, next);
212
+ assertLatestSnapshotPreserved(current, next);
213
+ const currentHistory = current.verificationHistory;
214
+ const nextHistory = next.verificationHistory;
215
+ const expectedHistory = current.verification.status === "failed"
216
+ ? [
217
+ ...currentHistory,
218
+ {
219
+ failedRevision: current.revision,
220
+ reopenedAt: nextHistory.at(-1)?.reopenedAt,
221
+ reason: nextHistory.at(-1)?.reason,
222
+ failure: current.verification.failure
223
+ }
224
+ ]
225
+ : currentHistory;
226
+ const stable = (session) => ({
227
+ ...transitionStableState(session),
228
+ verification: undefined,
229
+ verificationHistory: undefined
230
+ });
231
+ if (current.state !== "active"
232
+ || next.state !== "active"
233
+ || current.inFlight !== null
234
+ || next.inFlight !== null
235
+ || current.pendingConfirmation !== null
236
+ || next.pendingConfirmation !== null
237
+ || current.verification.status !== "failed"
238
+ || next.verification.status !== "notRun"
239
+ || current.publication.status !== "notRun"
240
+ || next.publication.status !== "notRun"
241
+ || nextHistory.length !== currentHistory.length + 1
242
+ || nextHistory.at(-1)?.reason.trim().length === 0
243
+ || JSON.stringify(nextHistory) !== JSON.stringify(expectedHistory)
244
+ || JSON.stringify(stable(current)) !== JSON.stringify(stable(next))) {
245
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Verification reopen may only preserve one failed attempt in history and reset it to notRun");
246
+ }
247
+ }
248
+ export function assertBundlePublishableTransition(current, next) {
249
+ assertCoreIdentityPreserved(current, next);
250
+ assertLatestSnapshotPreserved(current, next);
251
+ if (current.state !== "active"
252
+ || next.state !== "active"
253
+ || current.inFlight !== null
254
+ || next.inFlight !== null
255
+ || current.pendingConfirmation !== null
256
+ || next.pendingConfirmation !== null
257
+ || current.verification.status !== "passed"
258
+ || JSON.stringify(current.verification) !== JSON.stringify(next.verification)
259
+ || current.publication.status !== "notRun"
260
+ || next.publication.status !== "published"
261
+ || JSON.stringify({
262
+ ...transitionStableState(current),
263
+ publication: undefined
264
+ }) !== JSON.stringify({
265
+ ...transitionStableState(next),
266
+ publication: undefined
267
+ })) {
268
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Bundle publication must be explicitly marked after passed verification");
269
+ }
270
+ }
271
+ export function confirmationStableState(session) {
272
+ const stable = transitionStableState(session);
273
+ return { ...stable, pendingConfirmation: undefined };
274
+ }
275
+ export function assertConfirmationTransition(current, next) {
276
+ assertCoreIdentityPreserved(current, next);
277
+ assertLatestSnapshotPreserved(current, next);
278
+ if (current.state !== "active"
279
+ || next.state !== "active"
280
+ || current.inFlight !== null
281
+ || next.inFlight !== null
282
+ || current.verification.status !== "notRun"
283
+ || current.publication.status !== "notRun"
284
+ || JSON.stringify(confirmationStableState(current))
285
+ !== JSON.stringify(confirmationStableState(next))) {
286
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Confirmation transition may only change pending confirmation state");
287
+ }
288
+ const before = current.pendingConfirmation;
289
+ const after = next.pendingConfirmation;
290
+ if (before === null) {
291
+ if (after !== null && after.status === "pending") {
292
+ return;
293
+ }
294
+ }
295
+ else if (after === null) {
296
+ return;
297
+ }
298
+ else if (before.status === "pending"
299
+ && after.status === "approved"
300
+ && before.approvalMode === undefined
301
+ && after.approvalMode !== undefined
302
+ && JSON.stringify({
303
+ ...before,
304
+ status: undefined,
305
+ approvalMode: undefined
306
+ }) === JSON.stringify({
307
+ ...after,
308
+ status: undefined,
309
+ approvalMode: undefined
310
+ })) {
311
+ return;
312
+ }
313
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Invalid pending confirmation lifecycle transition");
314
+ }
315
+ export function assertRecoveryTransition(current, next) {
316
+ assertCoreIdentityPreserved(current, next);
317
+ assertLatestSnapshotPreserved(current, next);
318
+ if (current.state !== "recoveryRequired"
319
+ || current.inFlight === null
320
+ || next.state !== "active"
321
+ || next.inFlight !== null
322
+ || JSON.stringify(transitionStableState(current))
323
+ !== JSON.stringify(transitionStableState(next))) {
324
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Recovery must only clear preserved inFlight evidence and reactivate state");
325
+ }
326
+ }
327
+ export function assertArchiveTransition(current, next) {
328
+ assertCoreIdentityPreserved(current, next);
329
+ assertLatestSnapshotPreserved(current, next);
330
+ if (current.state !== "active"
331
+ || current.inFlight !== null
332
+ || current.pendingConfirmation !== null
333
+ || next.state !== "archived"
334
+ || next.inFlight !== null
335
+ || next.pendingConfirmation !== null
336
+ || JSON.stringify(transitionStableState(current))
337
+ !== JSON.stringify(transitionStableState(next))) {
338
+ throw new GenerationSessionStoreError("INVALID_TRANSITION", "Archive may only mark an idle active session as archived without mutation");
339
+ }
340
+ }
@@ -0,0 +1,50 @@
1
+ import type { BigIntStats, Dirent } from "node:fs";
2
+ import type { GenerationInFlight, GenerationSession } from "../../../domain/generation.js";
3
+ import { GenerationSessionStoreError } from "../../../ports/generation-session-store.js";
4
+ export interface FileIdentity {
5
+ dev: bigint;
6
+ ino: bigint;
7
+ }
8
+ export interface FileSnapshotMetadata extends FileIdentity {
9
+ size: bigint;
10
+ mtimeNs: bigint;
11
+ ctimeNs: bigint;
12
+ }
13
+ export declare function snapshotMetadata(stats: BigIntStats): FileSnapshotMetadata;
14
+ export declare function sameSnapshotMetadata(left: FileSnapshotMetadata, right: FileSnapshotMetadata): boolean;
15
+ export declare function evidenceEntryType(entry: Dirent): string;
16
+ export declare function evidenceEntrySnapshot(entries: readonly Dirent[]): readonly string[];
17
+ export interface DirectoryEvidence {
18
+ path: string;
19
+ canonicalPath: string;
20
+ identity: FileIdentity;
21
+ }
22
+ export interface StoreDirectoryEvidence {
23
+ path: string;
24
+ canonicalPath: string;
25
+ identity: FileIdentity;
26
+ }
27
+ export declare function sameIdentity(left: FileIdentity, right: FileIdentity): boolean;
28
+ export declare function captureStoreDirectory(path: string): Promise<StoreDirectoryEvidence>;
29
+ export declare function verifyStoreDirectory(expected: StoreDirectoryEvidence): Promise<void>;
30
+ export declare function captureStoreFile(path: string): Promise<FileIdentity>;
31
+ export declare function captureOptionalStoreFile(path: string): Promise<FileIdentity | null>;
32
+ export declare function verifyOptionalStoreFile(path: string, expected: FileIdentity | null): Promise<void>;
33
+ export declare function asStoreIoError(error: unknown, action: string): Error;
34
+ export declare function pathExists(path: string): Promise<boolean>;
35
+ export declare function requireRealDirectory(path: string): Promise<void>;
36
+ export declare function createOrRequireDirectory(path: string): Promise<boolean>;
37
+ export declare function syncDirectory(path: string): Promise<void>;
38
+ export declare function serializeJson(value: unknown): string;
39
+ export declare function canonicalizeEvidenceValue(value: unknown, ancestors?: Set<object>): unknown;
40
+ export declare function canonicalizeEvidence(value: unknown): unknown;
41
+ export declare function validateEvidencePath(relativePath: unknown): string[];
42
+ export declare function assertContained(root: string, candidate: string, allowRoot?: boolean): void;
43
+ export declare function captureDirectoryEvidence(path: string): Promise<DirectoryEvidence>;
44
+ export declare function verifyDirectoryEvidence(activeCanonicalPath: string, directories: readonly DirectoryEvidence[]): Promise<void>;
45
+ export declare function assertEvidenceNamespaceAvailable(activeDirectory: string, activeEvidence: StoreDirectoryEvidence, inFlight: GenerationInFlight): Promise<void>;
46
+ export declare function fileIdentity(path: string): Promise<FileIdentity>;
47
+ export declare function evidenceNotFound(relativePath: string, cause: unknown): GenerationSessionStoreError;
48
+ export declare function readStateFromDirectory(directory: string, afterOpen?: () => Promise<void> | void, expectedDirectory?: StoreDirectoryEvidence): Promise<GenerationSession>;
49
+ export declare function readBoundState(directory: string, id: string, afterOpen?: () => Promise<void> | void, expectedDirectory?: StoreDirectoryEvidence): Promise<GenerationSession>;
50
+ export declare function writeStateAtomically(directory: string, session: GenerationSession, sync?: (path: string) => Promise<void>, beforeRename?: () => Promise<void> | void, expectedDirectory?: StoreDirectoryEvidence, beforeInstall?: () => Promise<void> | void): Promise<void>;