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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/README.md +49 -149
  2. package/README.zh-CN.md +47 -147
  3. package/assets/skills/taphound-case-suite/SKILL.md +363 -0
  4. package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
  5. package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
  6. package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
  7. package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
  8. package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
  9. package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
  10. package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
  11. package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
  12. package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
  13. package/assets/skills/taphound-flash/SKILL.md +115 -0
  14. package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
  15. package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
  16. package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
  17. package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
  18. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
  19. package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
  20. package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
  21. package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
  22. package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
  23. package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
  24. package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
  25. package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
  26. package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
  27. package/assets/skills/taphound-journey-generator/SKILL.md +507 -0
  28. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
  29. package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
  30. package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
  31. package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
  32. package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
  33. package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
  34. package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
  35. package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
  36. package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
  37. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
  38. package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
  39. package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +578 -0
  40. package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
  41. package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
  42. package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
  43. package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
  44. package/assets/skills/taphound-verify-change/SKILL.md +91 -0
  45. package/assets/skills/taphound-verify-change/references/accept.md +38 -0
  46. package/assets/skills/taphound-verify-change/references/preserve.md +357 -0
  47. package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
  48. package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
  49. package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
  50. package/dist/adapters/adb/adb-adapter.d.ts +16 -2
  51. package/dist/adapters/adb/adb-adapter.js +199 -0
  52. package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
  53. package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
  54. package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
  55. package/dist/adapters/adb/ui-automator-parser.js +160 -0
  56. package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
  57. package/dist/adapters/adb/window-topology-parser.js +101 -0
  58. package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
  59. package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
  60. package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
  61. package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
  62. package/dist/adapters/android-cli/layout-parser.js +12 -8
  63. package/dist/adapters/appium/appium-doctor.d.ts +7 -0
  64. package/dist/adapters/appium/appium-doctor.js +128 -0
  65. package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +42 -0
  66. package/dist/adapters/appium/appium-ui-snapshot-provider.js +309 -0
  67. package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
  68. package/dist/adapters/camera/camera-probe-adapter.js +286 -0
  69. package/dist/adapters/filesystem/artifact-store.js +40 -1
  70. package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
  71. package/dist/adapters/filesystem/context-document-writer.js +112 -0
  72. package/dist/adapters/filesystem/diagnostics-journal.d.ts +17 -0
  73. package/dist/adapters/filesystem/diagnostics-journal.js +130 -0
  74. package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
  75. package/dist/adapters/filesystem/external-flow-registry.js +325 -0
  76. package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
  77. package/dist/adapters/filesystem/generation-session-store.js +281 -855
  78. package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
  79. package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
  80. package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
  81. package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
  82. package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
  83. package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
  84. package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
  85. package/dist/adapters/filesystem/journey-composition-store.js +151 -0
  86. package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
  87. package/dist/adapters/filesystem/knowledge-registry.js +223 -0
  88. package/dist/adapters/filesystem/project-bound-file.js +3 -5
  89. package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
  90. package/dist/adapters/filesystem/project-file-inspector.js +57 -28
  91. package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
  92. package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
  93. package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
  94. package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
  95. package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
  96. package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
  97. package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
  98. package/dist/adapters/filesystem/skill-installer.js +40 -11
  99. package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
  100. package/dist/adapters/filesystem/workspace-layout.js +57 -0
  101. package/dist/adapters/git/node-git-diff.d.ts +17 -0
  102. package/dist/adapters/git/node-git-diff.js +114 -0
  103. package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
  104. package/dist/adapters/process/node-detached-process-launcher.js +96 -0
  105. package/dist/adapters/process/node-process-runner.js +11 -2
  106. package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
  107. package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
  108. package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
  109. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
  110. package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
  111. package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
  112. package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
  113. package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
  114. package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
  115. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
  116. package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
  117. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
  118. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
  119. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
  120. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
  121. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
  122. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
  123. package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
  124. package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
  125. package/dist/adapters/runtime/session-adb-view.js +193 -0
  126. package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
  127. package/dist/adapters/runtime/session-backed-ports.js +43 -0
  128. package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
  129. package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
  130. package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
  131. package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
  132. package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
  133. package/dist/adapters/ui/device-layout-temp.js +18 -0
  134. package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
  135. package/dist/adapters/ui/device-ui-environment.js +81 -0
  136. package/dist/adapters/ui/layout-normalization.d.ts +9 -0
  137. package/dist/adapters/ui/layout-normalization.js +44 -0
  138. package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
  139. package/dist/adapters/ui/ui-snapshot-error.js +12 -0
  140. package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
  141. package/dist/adapters/ui/ui-snapshot-support.js +12 -0
  142. package/dist/application/align/align-service.d.ts +42 -0
  143. package/dist/application/align/align-service.js +106 -0
  144. package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
  145. package/dist/application/assertion/expectation-evaluator.js +156 -18
  146. package/dist/application/assertion/guarded-expectation.d.ts +45 -0
  147. package/dist/application/assertion/guarded-expectation.js +74 -0
  148. package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
  149. package/dist/application/checkpoint/baseline-capturer.js +163 -0
  150. package/dist/application/checkpoint/baseline-error.d.ts +5 -0
  151. package/dist/application/checkpoint/baseline-error.js +8 -0
  152. package/dist/application/checkpoint/baseline-service.d.ts +31 -0
  153. package/dist/application/checkpoint/baseline-service.js +147 -0
  154. package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
  155. package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
  156. package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
  157. package/dist/application/checkpoint/regression-comparator.js +192 -0
  158. package/dist/application/collector/logcat-collector.d.ts +22 -1
  159. package/dist/application/collector/logcat-collector.js +103 -15
  160. package/dist/application/collector/logcat-event.d.ts +8 -0
  161. package/dist/application/collector/logcat-event.js +79 -0
  162. package/dist/application/collector/logcat-stop.d.ts +2 -0
  163. package/dist/application/collector/logcat-stop.js +11 -0
  164. package/dist/application/context/context-generator.d.ts +45 -0
  165. package/dist/application/context/context-generator.js +228 -0
  166. package/dist/application/context/context-loader.d.ts +40 -0
  167. package/dist/application/context/context-loader.js +223 -0
  168. package/dist/application/context/context-refresher.d.ts +59 -0
  169. package/dist/application/context/context-refresher.js +349 -0
  170. package/dist/application/context/context-rehasher.d.ts +36 -0
  171. package/dist/application/context/context-rehasher.js +110 -0
  172. package/dist/application/context/context-validator.d.ts +23 -1
  173. package/dist/application/context/context-validator.js +116 -9
  174. package/dist/application/context/evidence-hash.d.ts +1 -0
  175. package/dist/application/context/evidence-hash.js +125 -0
  176. package/dist/application/context/evidence-match.d.ts +9 -0
  177. package/dist/application/context/evidence-match.js +8 -0
  178. package/dist/application/context/shard-identity.d.ts +2 -0
  179. package/dist/application/context/shard-identity.js +7 -0
  180. package/dist/application/contract/contract-loader.d.ts +25 -0
  181. package/dist/application/contract/contract-loader.js +68 -0
  182. package/dist/application/contract/contract-review.d.ts +25 -0
  183. package/dist/application/contract/contract-review.js +51 -0
  184. package/dist/application/contract/contract-verifier.d.ts +53 -0
  185. package/dist/application/contract/contract-verifier.js +645 -0
  186. package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
  187. package/dist/application/devices/resolve-device-assignments.js +60 -0
  188. package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
  189. package/dist/application/diagnosis/failure-classifier.js +179 -0
  190. package/dist/application/diagnostics/diagnostics-exporter.d.ts +29 -0
  191. package/dist/application/diagnostics/diagnostics-exporter.js +283 -0
  192. package/dist/application/diagnostics/ui-capture-telemetry.d.ts +16 -0
  193. package/dist/application/diagnostics/ui-capture-telemetry.js +81 -0
  194. package/dist/application/doctor/doctor-service.d.ts +36 -3
  195. package/dist/application/doctor/doctor-service.js +255 -25
  196. package/dist/application/generation/generation-app-preparer.d.ts +20 -0
  197. package/dist/application/generation/generation-app-preparer.js +28 -0
  198. package/dist/application/generation/generation-config-service.d.ts +21 -0
  199. package/dist/application/generation/generation-config-service.js +53 -0
  200. package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
  201. package/dist/application/generation/generation-confirmation-service.js +109 -24
  202. package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
  203. package/dist/application/generation/generation-context-snapshot.js +29 -0
  204. package/dist/application/generation/generation-finalizer.d.ts +15 -9
  205. package/dist/application/generation/generation-finalizer.js +167 -70
  206. package/dist/application/generation/generation-publisher.js +12 -8
  207. package/dist/application/generation/generation-recovery-service.d.ts +35 -0
  208. package/dist/application/generation/generation-recovery-service.js +144 -0
  209. package/dist/application/generation/generation-reopen-service.d.ts +15 -0
  210. package/dist/application/generation/generation-reopen-service.js +37 -0
  211. package/dist/application/generation/generation-replace-service.d.ts +32 -0
  212. package/dist/application/generation/generation-replace-service.js +116 -0
  213. package/dist/application/generation/generation-starter.d.ts +44 -4
  214. package/dist/application/generation/generation-starter.js +175 -8
  215. package/dist/application/generation/generation-step-executor.d.ts +67 -5
  216. package/dist/application/generation/generation-step-executor.js +471 -108
  217. package/dist/application/generation/proposed-step-validator.js +96 -30
  218. package/dist/application/generation/replay-policy-loader.d.ts +16 -0
  219. package/dist/application/generation/replay-policy-loader.js +29 -0
  220. package/dist/application/generation/risk-evaluator.d.ts +4 -1
  221. package/dist/application/generation/risk-evaluator.js +118 -3
  222. package/dist/application/generation/runtime-observer.d.ts +39 -7
  223. package/dist/application/generation/runtime-observer.js +193 -24
  224. package/dist/application/impact/impact-resolver.d.ts +32 -0
  225. package/dist/application/impact/impact-resolver.js +160 -0
  226. package/dist/application/init/init-service.js +26 -13
  227. package/dist/application/interaction/action-executor.d.ts +3 -2
  228. package/dist/application/interaction/action-executor.js +11 -1
  229. package/dist/application/interaction/action-target.d.ts +17 -0
  230. package/dist/application/interaction/action-target.js +40 -0
  231. package/dist/application/interaction/external-step-runner.d.ts +153 -0
  232. package/dist/application/interaction/external-step-runner.js +332 -0
  233. package/dist/application/interaction/fallback-resolver.d.ts +6 -3
  234. package/dist/application/interaction/fallback-resolver.js +7 -5
  235. package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
  236. package/dist/application/interaction/scroll-to-executor.js +118 -36
  237. package/dist/application/journey/external-flow-resolver.d.ts +25 -0
  238. package/dist/application/journey/external-flow-resolver.js +22 -0
  239. package/dist/application/journey/journey-check-service.d.ts +54 -0
  240. package/dist/application/journey/journey-check-service.js +207 -0
  241. package/dist/application/journey/journey-promoter.d.ts +26 -0
  242. package/dist/application/journey/journey-promoter.js +123 -0
  243. package/dist/application/journey/journey-resolver.d.ts +42 -0
  244. package/dist/application/journey/journey-resolver.js +239 -0
  245. package/dist/application/journey/journey-retirer.d.ts +25 -0
  246. package/dist/application/journey/journey-retirer.js +87 -0
  247. package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
  248. package/dist/application/knowledge/anchor-resolver.js +110 -0
  249. package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
  250. package/dist/application/knowledge/knowledge-loader.js +36 -0
  251. package/dist/application/locator/layout-failure-summary.d.ts +2 -0
  252. package/dist/application/locator/layout-failure-summary.js +67 -0
  253. package/dist/application/locator/layout-traversal.d.ts +11 -0
  254. package/dist/application/locator/layout-traversal.js +18 -0
  255. package/dist/application/locator/locator-resolver.d.ts +13 -1
  256. package/dist/application/locator/locator-resolver.js +182 -18
  257. package/dist/application/observe/observe-service.d.ts +20 -0
  258. package/dist/application/observe/observe-service.js +91 -0
  259. package/dist/application/project/project-describer.d.ts +14 -6
  260. package/dist/application/project/project-describer.js +38 -5
  261. package/dist/application/recognition/screen-detector.d.ts +28 -0
  262. package/dist/application/recognition/screen-detector.js +111 -0
  263. package/dist/application/recorder/locator-selector.js +151 -17
  264. package/dist/application/recorder/recorder-service.d.ts +16 -4
  265. package/dist/application/recorder/recorder-service.js +420 -128
  266. package/dist/application/report/report-writer.d.ts +5 -0
  267. package/dist/application/report/report-writer.js +17 -1
  268. package/dist/application/runtime/cold-launch.d.ts +28 -0
  269. package/dist/application/runtime/cold-launch.js +59 -0
  270. package/dist/application/runtime/step-runner.d.ts +49 -4
  271. package/dist/application/runtime/step-runner.js +721 -130
  272. package/dist/application/runtime/verify-runtime.d.ts +57 -7
  273. package/dist/application/runtime/verify-runtime.js +577 -175
  274. package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
  275. package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
  276. package/dist/application/ui/observed-ui-snapshot-provider.d.ts +15 -0
  277. package/dist/application/ui/observed-ui-snapshot-provider.js +66 -0
  278. package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
  279. package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
  280. package/dist/application/ui/ui-stability-probe.d.ts +9 -0
  281. package/dist/application/ui/ui-stability-probe.js +24 -0
  282. package/dist/application/wait/idle-advice.d.ts +6 -0
  283. package/dist/application/wait/idle-advice.js +27 -0
  284. package/dist/application/wait/idle-profiles.d.ts +15 -0
  285. package/dist/application/wait/idle-profiles.js +75 -0
  286. package/dist/application/wait/idle-waiter.d.ts +28 -4
  287. package/dist/application/wait/idle-waiter.js +201 -15
  288. package/dist/cli/commands/align.d.ts +3 -0
  289. package/dist/cli/commands/align.js +124 -0
  290. package/dist/cli/commands/baseline.d.ts +3 -0
  291. package/dist/cli/commands/baseline.js +130 -0
  292. package/dist/cli/commands/context.js +300 -27
  293. package/dist/cli/commands/contract.d.ts +3 -0
  294. package/dist/cli/commands/contract.js +120 -0
  295. package/dist/cli/commands/diagnose.d.ts +3 -0
  296. package/dist/cli/commands/diagnose.js +84 -0
  297. package/dist/cli/commands/doctor.js +16 -9
  298. package/dist/cli/commands/failure.d.ts +3 -0
  299. package/dist/cli/commands/failure.js +63 -0
  300. package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
  301. package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
  302. package/dist/cli/commands/generation/session-commands.d.ts +11 -0
  303. package/dist/cli/commands/generation/session-commands.js +472 -0
  304. package/dist/cli/commands/generation/shared.d.ts +1414 -0
  305. package/dist/cli/commands/generation/shared.js +291 -0
  306. package/dist/cli/commands/generation/step-commands.d.ts +8 -0
  307. package/dist/cli/commands/generation/step-commands.js +315 -0
  308. package/dist/cli/commands/generation.js +10 -507
  309. package/dist/cli/commands/impact.d.ts +3 -0
  310. package/dist/cli/commands/impact.js +87 -0
  311. package/dist/cli/commands/init.js +13 -6
  312. package/dist/cli/commands/journey.d.ts +3 -0
  313. package/dist/cli/commands/journey.js +382 -0
  314. package/dist/cli/commands/knowledge.d.ts +3 -0
  315. package/dist/cli/commands/knowledge.js +93 -0
  316. package/dist/cli/commands/observe.d.ts +3 -0
  317. package/dist/cli/commands/observe.js +127 -0
  318. package/dist/cli/commands/project.js +2 -1
  319. package/dist/cli/commands/record.js +18 -5
  320. package/dist/cli/commands/verify.js +326 -64
  321. package/dist/cli/dependencies.d.ts +136 -1
  322. package/dist/cli/dependencies.js +504 -52
  323. package/dist/cli/diagnostics-recorder.d.ts +31 -0
  324. package/dist/cli/diagnostics-recorder.js +82 -0
  325. package/dist/cli/diff-verification.d.ts +41 -0
  326. package/dist/cli/diff-verification.js +192 -0
  327. package/dist/cli/main.d.ts +1 -1
  328. package/dist/cli/main.js +107 -2
  329. package/dist/cli/output.d.ts +5 -3
  330. package/dist/cli/output.js +12 -0
  331. package/dist/cli/program.js +21 -1
  332. package/dist/cli/project-root.d.ts +1 -0
  333. package/dist/cli/project-root.js +6 -0
  334. package/dist/cli/runtime-selection.d.ts +22 -0
  335. package/dist/cli/runtime-selection.js +92 -0
  336. package/dist/cli/version.d.ts +1 -0
  337. package/dist/cli/version.js +14 -0
  338. package/dist/cli/workspace-guard.d.ts +2 -0
  339. package/dist/cli/workspace-guard.js +3 -0
  340. package/dist/domain/binding-reference.d.ts +4 -0
  341. package/dist/domain/binding-reference.js +23 -0
  342. package/dist/domain/checkpoint.d.ts +404 -0
  343. package/dist/domain/checkpoint.js +297 -0
  344. package/dist/domain/config.d.ts +107 -1
  345. package/dist/domain/config.js +52 -6
  346. package/dist/domain/contract.d.ts +413 -0
  347. package/dist/domain/contract.js +196 -0
  348. package/dist/domain/diagnostics.d.ts +1396 -0
  349. package/dist/domain/diagnostics.js +193 -0
  350. package/dist/domain/external-flow.d.ts +493 -0
  351. package/dist/domain/external-flow.js +15 -0
  352. package/dist/domain/failure-classification.d.ts +176 -0
  353. package/dist/domain/failure-classification.js +169 -0
  354. package/dist/domain/failure.d.ts +2 -1
  355. package/dist/domain/failure.js +123 -0
  356. package/dist/domain/generation.d.ts +1671 -132
  357. package/dist/domain/generation.js +202 -13
  358. package/dist/domain/geometry.d.ts +13 -0
  359. package/dist/domain/geometry.js +16 -0
  360. package/dist/domain/impact.d.ts +71 -0
  361. package/dist/domain/impact.js +76 -0
  362. package/dist/domain/init.d.ts +12 -4
  363. package/dist/domain/init.js +24 -18
  364. package/dist/domain/journey-composition.d.ts +2285 -0
  365. package/dist/domain/journey-composition.js +85 -0
  366. package/dist/domain/journey-lifecycle.d.ts +10 -0
  367. package/dist/domain/journey-lifecycle.js +9 -0
  368. package/dist/domain/journey.d.ts +2419 -212
  369. package/dist/domain/journey.js +384 -14
  370. package/dist/domain/knowledge.d.ts +165 -0
  371. package/dist/domain/knowledge.js +188 -0
  372. package/dist/domain/layout.d.ts +34 -5
  373. package/dist/domain/layout.js +64 -6
  374. package/dist/domain/locator-evidence.d.ts +3 -0
  375. package/dist/domain/locator-evidence.js +36 -0
  376. package/dist/domain/logcat-event.d.ts +54 -0
  377. package/dist/domain/logcat-event.js +40 -0
  378. package/dist/domain/observation.d.ts +33 -0
  379. package/dist/domain/observation.js +18 -0
  380. package/dist/domain/project-context.d.ts +219 -1
  381. package/dist/domain/project-context.js +209 -6
  382. package/dist/domain/proposed-step.d.ts +340 -60
  383. package/dist/domain/proposed-step.js +23 -3
  384. package/dist/domain/report.d.ts +1455 -28
  385. package/dist/domain/report.js +211 -14
  386. package/dist/domain/runtime-snapshot.d.ts +58 -1
  387. package/dist/domain/runtime-snapshot.js +14 -3
  388. package/dist/domain/runtime.d.ts +50 -0
  389. package/dist/domain/runtime.js +36 -0
  390. package/dist/domain/system-app-profiles.d.ts +6 -0
  391. package/dist/domain/system-app-profiles.js +43 -0
  392. package/dist/domain/ui-backend.d.ts +28 -0
  393. package/dist/domain/ui-backend.js +33 -0
  394. package/dist/domain/ui-cache.d.ts +11 -0
  395. package/dist/domain/ui-cache.js +10 -0
  396. package/dist/domain/verify-receipt.d.ts +17 -0
  397. package/dist/domain/verify-receipt.js +17 -0
  398. package/dist/domain/window-hierarchy.d.ts +84 -0
  399. package/dist/domain/window-hierarchy.js +172 -0
  400. package/dist/domain/workflow-manifest.d.ts +77 -0
  401. package/dist/domain/workflow-manifest.js +136 -0
  402. package/dist/domain/workspace.d.ts +30 -0
  403. package/dist/domain/workspace.js +74 -0
  404. package/dist/ports/adb.d.ts +34 -1
  405. package/dist/ports/align-prompt.d.ts +11 -0
  406. package/dist/ports/align-prompt.js +6 -0
  407. package/dist/ports/anchor-resolver.d.ts +30 -0
  408. package/dist/ports/anchor-resolver.js +1 -0
  409. package/dist/ports/annotated-screen-resolver.d.ts +4 -0
  410. package/dist/ports/annotated-screen-resolver.js +1 -0
  411. package/dist/ports/camera-probe.d.ts +23 -0
  412. package/dist/ports/camera-probe.js +8 -0
  413. package/dist/ports/context-document-writer.d.ts +24 -0
  414. package/dist/ports/context-document-writer.js +1 -0
  415. package/dist/ports/detached-process-launcher.d.ts +12 -0
  416. package/dist/ports/detached-process-launcher.js +1 -0
  417. package/dist/ports/diagnostics.d.ts +15 -0
  418. package/dist/ports/diagnostics.js +1 -0
  419. package/dist/ports/external-flow-registry.d.ts +37 -0
  420. package/dist/ports/external-flow-registry.js +1 -0
  421. package/dist/ports/generation-prompt.d.ts +2 -1
  422. package/dist/ports/generation-session-store.d.ts +12 -2
  423. package/dist/ports/git-diff.d.ts +9 -0
  424. package/dist/ports/git-diff.js +1 -0
  425. package/dist/ports/journey-composition-store.d.ts +17 -0
  426. package/dist/ports/journey-composition-store.js +1 -0
  427. package/dist/ports/knowledge-registry.d.ts +20 -0
  428. package/dist/ports/knowledge-registry.js +1 -0
  429. package/dist/ports/process-runner.d.ts +7 -0
  430. package/dist/ports/project-file-inspector.d.ts +1 -0
  431. package/dist/ports/project-identity-inspector.d.ts +24 -0
  432. package/dist/ports/project-identity-inspector.js +1 -0
  433. package/dist/ports/project-inventory-inspector.d.ts +21 -0
  434. package/dist/ports/project-inventory-inspector.js +1 -0
  435. package/dist/ports/project-module-discoverer.d.ts +26 -0
  436. package/dist/ports/project-module-discoverer.js +1 -0
  437. package/dist/ports/recorder-prompt.d.ts +10 -1
  438. package/dist/ports/runtime-backend.d.ts +89 -0
  439. package/dist/ports/runtime-backend.js +13 -0
  440. package/dist/ports/runtime-capability.d.ts +12 -0
  441. package/dist/ports/runtime-capability.js +20 -0
  442. package/dist/ports/runtime-session-ports.d.ts +25 -0
  443. package/dist/ports/runtime-session-ports.js +1 -0
  444. package/dist/ports/screenshot.d.ts +11 -0
  445. package/dist/ports/screenshot.js +1 -0
  446. package/dist/ports/skill-installer.d.ts +2 -2
  447. package/dist/ports/ui-snapshot.d.ts +35 -0
  448. package/dist/ports/ui-snapshot.js +1 -0
  449. package/dist/ports/ui-stability.d.ts +19 -0
  450. package/dist/ports/ui-stability.js +1 -0
  451. package/dist/ports/workspace-layout.d.ts +4 -0
  452. package/dist/ports/workspace-layout.js +1 -0
  453. package/dist/shared/errors.d.ts +2 -0
  454. package/dist/shared/errors.js +22 -0
  455. package/dist/shared/paths.d.ts +2 -0
  456. package/dist/shared/paths.js +24 -0
  457. package/dist/shared/strings.d.ts +2 -0
  458. package/dist/shared/strings.js +16 -0
  459. package/package.json +7 -2
  460. package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
  461. package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
  462. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
  463. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
  464. package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
  465. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
  466. package/dist/ports/android-cli.d.ts +0 -21
  467. /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
@@ -1,11 +1,13 @@
1
- const THREADTIME = /^\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+\s+(\d+)\s+(\d+)\s+([VDIWEFA])\s+([^:]+):\s?(.*)$/;
1
+ const THREADTIME = /^(\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+)\s+(\d+)\s+(\d+)\s+([VDIWEFA])\s+(.+?):\s(.*)$/;
2
2
  function parseLine(raw, receivedAt) {
3
3
  const match = THREADTIME.exec(raw);
4
4
  if (match === null) {
5
5
  return { receivedAt, raw };
6
6
  }
7
- const [, pid, tid, level, tag, message] = match;
8
- if (pid === undefined
7
+ const [, deviceTimestamp, pid, tid, level, tag, message] = match;
8
+ if (deviceTimestamp === undefined
9
+ ||
10
+ pid === undefined
9
11
  || tid === undefined
10
12
  || level === undefined
11
13
  || tag === undefined
@@ -14,6 +16,7 @@ function parseLine(raw, receivedAt) {
14
16
  }
15
17
  return {
16
18
  receivedAt,
19
+ deviceTimestamp,
17
20
  raw,
18
21
  pid: Number(pid),
19
22
  tid: Number(tid),
@@ -31,30 +34,106 @@ function startupFailure(result) {
31
34
  ? "Logcat startup timed out"
32
35
  : `Logcat exited during startup with code ${String(result.exitCode)}`);
33
36
  }
37
+ const COMPACT_THRESHOLD = 1024;
34
38
  export class LogcatCollector {
35
39
  adb;
36
40
  clock;
41
+ limits;
42
+ /** Live lines are `collected[head..]`; dropped lines are compacted lazily. */
37
43
  collected = [];
44
+ head = 0;
45
+ bufferedBytes = 0;
46
+ droppedByPid = new Map();
38
47
  stderr = [];
39
48
  scopedPids = new Set();
40
49
  running;
41
50
  streamMetadata;
42
51
  stopPromise;
43
- constructor(adb, clock) {
52
+ constructor(adb, clock, limits = {
53
+ maxLines: 10000,
54
+ maxBytes: 2 * 1024 * 1024
55
+ }) {
44
56
  this.adb = adb;
45
57
  this.clock = clock;
58
+ this.limits = limits;
59
+ if (!Number.isInteger(limits.maxLines) || limits.maxLines < 1
60
+ || !Number.isInteger(limits.maxBytes) || limits.maxBytes < 1) {
61
+ throw new Error("Logcat buffer limits must be positive integers");
62
+ }
63
+ }
64
+ append(line) {
65
+ const parsed = parseLine(line, this.clock.now());
66
+ if (this.scopedPids.size > 0 && parsed.pid !== undefined
67
+ && !this.scopedPids.has(parsed.pid)) {
68
+ return;
69
+ }
70
+ const bytes = Buffer.byteLength(line, "utf8") + 1;
71
+ this.collected.push(parsed);
72
+ this.bufferedBytes += bytes;
73
+ while (this.collected.length - this.head > this.limits.maxLines
74
+ || this.bufferedBytes > this.limits.maxBytes) {
75
+ const dropped = this.collected[this.head];
76
+ if (dropped === undefined) {
77
+ break;
78
+ }
79
+ this.head += 1;
80
+ const size = Buffer.byteLength(dropped.raw, "utf8") + 1;
81
+ this.bufferedBytes -= size;
82
+ const previous = this.droppedByPid.get(dropped.pid);
83
+ this.droppedByPid.set(dropped.pid, {
84
+ lines: (previous?.lines ?? 0) + 1,
85
+ bytes: (previous?.bytes ?? 0) + size,
86
+ lastDroppedAt: dropped.receivedAt
87
+ });
88
+ }
89
+ // Array#shift is O(n); a saturated buffer would otherwise move every
90
+ // retained line on each append. Compaction is amortized O(1) per line.
91
+ if (this.head >= COMPACT_THRESHOLD
92
+ && this.head * 2 >= this.collected.length) {
93
+ this.collected.splice(0, this.head);
94
+ this.head = 0;
95
+ }
96
+ }
97
+ retained() {
98
+ return this.head === 0 ? this.collected : this.collected.slice(this.head);
99
+ }
100
+ addScopedPids(pids) {
101
+ for (const pid of pids) {
102
+ if (!Number.isInteger(pid) || pid <= 0) {
103
+ throw new Error("Logcat PID must be a positive integer");
104
+ }
105
+ this.scopedPids.add(pid);
106
+ }
107
+ }
108
+ droppedEvidence() {
109
+ const relevant = [
110
+ this.droppedByPid.get(undefined),
111
+ ...[...this.scopedPids].map((pid) => this.droppedByPid.get(pid))
112
+ ].filter((entry) => entry !== undefined);
113
+ if (relevant.length === 0) {
114
+ return undefined;
115
+ }
116
+ return {
117
+ lines: relevant.reduce((total, entry) => total + entry.lines, 0),
118
+ bytes: relevant.reduce((total, entry) => total + entry.bytes, 0),
119
+ lastDroppedAt: Math.max(...relevant.map((entry) => entry.lastDroppedAt))
120
+ };
46
121
  }
47
122
  async start(options) {
48
123
  if (this.running !== undefined) {
49
124
  throw new Error("Logcat collector already started");
50
125
  }
126
+ this.addScopedPids(options.pids ?? []);
51
127
  const logcatOptions = {
52
128
  deviceSerial: options.deviceSerial,
53
129
  onStdoutLine: (line) => {
54
- this.collected.push(parseLine(line, this.clock.now()));
130
+ this.append(line);
55
131
  },
56
132
  onStderrLine: (line) => {
57
133
  this.stderr.push(line);
134
+ if (this.stderr.length > 100) {
135
+ this.stderr.shift();
136
+ }
58
137
  },
59
138
  ...(options.signal === undefined ? {} : { signal: options.signal })
60
139
  };
@@ -62,34 +141,43 @@ export class LogcatCollector {
62
141
  this.streamMetadata = { deviceSerial: options.deviceSerial };
63
142
  const startupResult = await this.running.started;
64
143
  if (startupResult !== undefined) {
65
- throw new Error(startupFailure(startupResult));
144
+ throw new Error(this.stderr.join("\n").trim() || startupFailure(startupResult));
66
145
  }
67
146
  }
68
147
  scopeToPids(pids) {
69
148
  if (this.streamMetadata === undefined) {
70
149
  throw new Error("Logcat collector has not started");
71
150
  }
72
- for (const pid of pids) {
73
- if (!Number.isInteger(pid) || pid <= 0) {
74
- throw new Error("Logcat PID must be a positive integer");
75
- }
76
- this.scopedPids.add(pid);
77
- }
151
+ this.addScopedPids(pids);
78
152
  }
79
153
  metadata() {
80
154
  if (this.streamMetadata === undefined) {
81
155
  throw new Error("Logcat collector has not started");
82
156
  }
157
+ const dropped = this.droppedEvidence();
83
158
  return {
84
159
  deviceSerial: this.streamMetadata.deviceSerial,
85
- pids: [...this.scopedPids].sort((left, right) => left - right)
160
+ pids: [...this.scopedPids].sort((left, right) => left - right),
161
+ ...(dropped === undefined ? {} : {
162
+ droppedLines: dropped.lines,
163
+ droppedBytes: dropped.bytes,
164
+ lastDroppedAtMs: dropped.lastDroppedAt
165
+ })
86
166
  };
87
167
  }
88
168
  lines() {
89
169
  if (this.scopedPids.size === 0) {
90
- return [...this.collected];
170
+ return [];
91
171
  }
92
- return this.collected.filter((line) => line.pid === undefined || this.scopedPids.has(line.pid));
172
+ return this.retained().filter((line) => line.pid !== undefined && this.scopedPids.has(line.pid));
173
+ }
174
+ /** Includes unparsed lines as raw artifacts, within the declared buffer limit. */
175
+ rawLines() {
176
+ return this.retained().filter((line) => line.pid === undefined || this.scopedPids.has(line.pid));
177
+ }
178
+ completeSince(startedAt) {
179
+ const dropped = this.droppedEvidence();
180
+ return dropped === undefined || dropped.lastDroppedAt < startedAt;
93
181
  }
94
182
  diagnosticLines() {
95
183
  return [...this.stderr];
@@ -0,0 +1,8 @@
1
+ import type { EventCapture, LogcatEventExpect } from "../../domain/logcat-event.js";
2
+ import type { LogcatLine } from "./logcat-collector.js";
3
+ /** Events are JSON objects in the message, with an `event` and `fields` object. */
4
+ export declare function matchesLogcatEvent(line: LogcatLine, expect: LogcatEventExpect): boolean;
5
+ /** Read only a declared field from the uniquely matched structured event. */
6
+ export declare function captureLogcatEvent(line: LogcatLine, expect: LogcatEventExpect, capture: EventCapture): string | undefined;
7
+ /** Only a stable, structured app-emitted class is accepted. */
8
+ export declare function requestErrorClassFor(line: LogcatLine): "client" | "auth" | "network" | "server" | undefined;
@@ -0,0 +1,79 @@
1
+ /** Events are JSON objects in the message, with an `event` and `fields` object. */
2
+ export function matchesLogcatEvent(line, expect) {
3
+ if (line.pid === undefined || line.tag !== expect.tag
4
+ || line.message === undefined) {
5
+ return false;
6
+ }
7
+ let value;
8
+ try {
9
+ value = JSON.parse(line.message);
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
15
+ return false;
16
+ }
17
+ const record = value;
18
+ if (record.event !== expect.event) {
19
+ return false;
20
+ }
21
+ const fields = record.fields;
22
+ if (fields === null || typeof fields !== "object" || Array.isArray(fields)) {
23
+ return false;
24
+ }
25
+ const facts = fields;
26
+ return Object.entries(expect.fields).every(([key, item]) => facts[key] === item)
27
+ && (expect.correlation === undefined
28
+ || facts[expect.correlation.key] === expect.correlation.value);
29
+ }
30
+ /** Read only a declared field from the uniquely matched structured event. */
31
+ export function captureLogcatEvent(line, expect, capture) {
32
+ if (!matchesLogcatEvent(line, expect) || line.message === undefined)
33
+ return undefined;
34
+ const event = JSON.parse(line.message);
35
+ const key = capture.field ?? expect.correlation?.key;
36
+ if (key === undefined)
37
+ return undefined;
38
+ const value = event.fields[key];
39
+ if (capture.valueType === "integer") {
40
+ return typeof value === "number" && Number.isSafeInteger(value)
41
+ ? String(value) : undefined;
42
+ }
43
+ if (typeof value !== "string")
44
+ return undefined;
45
+ if (capture.valueType === "identifier") {
46
+ return /^[a-zA-Z0-9_-]{1,64}$/.test(value) ? value : undefined;
47
+ }
48
+ if (value.length === 0 || value.length > 128)
49
+ return undefined;
50
+ for (const character of value) {
51
+ const point = character.codePointAt(0) ?? 0;
52
+ if (point < 32 || point === 127)
53
+ return undefined;
54
+ }
55
+ return value;
56
+ }
57
+ /** Only a stable, structured app-emitted class is accepted. */
58
+ export function requestErrorClassFor(line) {
59
+ if (line.message === undefined)
60
+ return undefined;
61
+ let event;
62
+ try {
63
+ event = JSON.parse(line.message);
64
+ }
65
+ catch {
66
+ return undefined;
67
+ }
68
+ if (event === null || typeof event !== "object" || Array.isArray(event)) {
69
+ return undefined;
70
+ }
71
+ const fields = event.fields;
72
+ if (fields === null || typeof fields !== "object" || Array.isArray(fields)) {
73
+ return undefined;
74
+ }
75
+ const value = fields.errorClass;
76
+ return value === "client" || value === "auth"
77
+ || value === "network" || value === "server"
78
+ ? value : undefined;
79
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandResult } from "../../ports/process-runner.js";
2
+ export declare function logcatStopFailed(result: Pick<CommandResult, "exitCode" | "signal" | "timedOut" | "cancelled" | "terminationRequested" | "spawnError">): boolean;
@@ -0,0 +1,11 @@
1
+ export function logcatStopFailed(result) {
2
+ if (result.timedOut
3
+ || result.cancelled
4
+ || result.spawnError !== undefined) {
5
+ return true;
6
+ }
7
+ return result.exitCode !== 0
8
+ && !(result.terminationRequested === true
9
+ && (result.signal === "SIGTERM"
10
+ || result.signal === "SIGKILL"));
11
+ }
@@ -0,0 +1,45 @@
1
+ import type { ProjectIdentityInspector } from "../../ports/project-identity-inspector.js";
2
+ import type { ProjectModuleDiscoverer } from "../../ports/project-module-discoverer.js";
3
+ import type { ContextDocumentWriter } from "../../ports/context-document-writer.js";
4
+ import type { ProjectFileInspector } from "../../ports/project-file-inspector.js";
5
+ import type { ProjectInventoryInspector } from "../../ports/project-inventory-inspector.js";
6
+ export type ContextGenerateErrorCode = "CONTEXT_INVALID" | "MODULE_DISCOVERY_FAILED" | "IDENTITY_INSPECTION_FAILED" | "NO_EVIDENCE" | "CONTEXT_WRITE_FAILED" | "CONTEXT_ALREADY_EXISTS";
7
+ export declare class ContextGenerateError extends Error {
8
+ readonly code: ContextGenerateErrorCode;
9
+ readonly name = "ContextGenerateError";
10
+ constructor(code: ContextGenerateErrorCode, message: string);
11
+ }
12
+ export interface ContextGenerateInput {
13
+ readonly projectRoot: string;
14
+ readonly contextPath: string;
15
+ readonly force?: boolean;
16
+ }
17
+ export interface ContextGenerateModuleResult {
18
+ readonly id: string;
19
+ readonly projectDir: string;
20
+ readonly kind: string;
21
+ readonly status: "notAnalyzed";
22
+ readonly evidenceCount: number;
23
+ readonly contextPath: string;
24
+ readonly sha256: string;
25
+ }
26
+ export interface ContextGenerateResult {
27
+ readonly status: "generated";
28
+ readonly packageName: string;
29
+ readonly launchActivity: string;
30
+ readonly modules: readonly ContextGenerateModuleResult[];
31
+ readonly indexHash: string;
32
+ readonly contextPath: string;
33
+ }
34
+ export interface ContextGeneratorDependencies {
35
+ readonly discoverer: ProjectModuleDiscoverer;
36
+ readonly identity: ProjectIdentityInspector;
37
+ readonly files: ProjectFileInspector;
38
+ readonly inventory: ProjectInventoryInspector;
39
+ readonly writer: ContextDocumentWriter;
40
+ }
41
+ export declare class ContextGenerator {
42
+ private readonly dependencies;
43
+ constructor(dependencies: ContextGeneratorDependencies);
44
+ readonly generate: (input: ContextGenerateInput) => Promise<ContextGenerateResult>;
45
+ }
@@ -0,0 +1,228 @@
1
+ import { isAbsolute, resolve } from "node:path";
2
+ import { ProjectContextModuleSchema, ProjectContextSchema } from "../../domain/project-context.js";
3
+ import { assertProjectPathUnder, CONTEXT_DIR } from "../../domain/workspace.js";
4
+ import { projectRelativePath } from "../../shared/paths.js";
5
+ import { compareStrings } from "../../shared/strings.js";
6
+ import { MAX_CONTEXT_EVIDENCE_BYTES } from "./context-validator.js";
7
+ import { semanticSha256 } from "./evidence-hash.js";
8
+ export class ContextGenerateError extends Error {
9
+ code;
10
+ name = "ContextGenerateError";
11
+ constructor(code, message) {
12
+ super(message);
13
+ this.code = code;
14
+ }
15
+ }
16
+ const INVENTORY_CATEGORIES = ["manifests", "sources", "layouts", "navigation"];
17
+ const DEFAULT_INTERACTION_POLICY = {
18
+ allowedActions: ["click", "inputText", "back", "wait"],
19
+ confirmationRequiredActions: [],
20
+ forbiddenActions: []
21
+ };
22
+ const ROOT_EVIDENCE_CANDIDATES = [
23
+ "settings.gradle.kts",
24
+ "settings.gradle",
25
+ "build.gradle.kts",
26
+ "build.gradle",
27
+ "gradle.properties",
28
+ "gradle/libs.versions.toml"
29
+ ];
30
+ function moduleIdToContextPath(moduleId) {
31
+ const sanitized = moduleId.replace(/^:/, "").replace(/:/g, "-");
32
+ return `${CONTEXT_DIR}/modules/${sanitized}.json`;
33
+ }
34
+ async function collectEvidence(files, projectRoot, paths) {
35
+ const evidence = [];
36
+ for (const path of paths) {
37
+ const inspection = await files.inspectProjectFile({
38
+ projectRoot,
39
+ relativePath: path,
40
+ maximumBytes: MAX_CONTEXT_EVIDENCE_BYTES
41
+ });
42
+ if (inspection.status === "inspected" && inspection.bytes !== undefined) {
43
+ evidence.push({
44
+ path: inspection.resolvedRelativePath,
45
+ sha256: inspection.sha256,
46
+ semanticSha256: semanticSha256(inspection.bytes)
47
+ });
48
+ }
49
+ }
50
+ return evidence;
51
+ }
52
+ async function collectRootEvidence(files, projectRoot) {
53
+ return collectEvidence(files, projectRoot, ROOT_EVIDENCE_CANDIDATES);
54
+ }
55
+ function buildShardDocument(module, evidence, pathSetSha256) {
56
+ const manifest = {
57
+ version: 1,
58
+ files: evidence.map((record) => ({
59
+ path: record.path,
60
+ sha256: record.sha256,
61
+ semanticSha256: record.semanticSha256,
62
+ confidence: "sourceConfirmed"
63
+ }))
64
+ };
65
+ return {
66
+ version: 2,
67
+ moduleId: module.id,
68
+ projectDir: module.projectDir,
69
+ status: "notAnalyzed",
70
+ inventory: {
71
+ version: 2,
72
+ pathSetSha256,
73
+ categories: [...INVENTORY_CATEGORIES]
74
+ },
75
+ manifest,
76
+ summary: {
77
+ features: [],
78
+ activities: [],
79
+ elements: [],
80
+ transitions: [],
81
+ logcat: []
82
+ }
83
+ };
84
+ }
85
+ function buildModuleReference(module, contextPath, sha256, dependsOn) {
86
+ return {
87
+ id: module.id,
88
+ projectDir: module.projectDir,
89
+ kind: module.kind,
90
+ contextPath,
91
+ sha256,
92
+ features: [],
93
+ activities: [],
94
+ dependsOn: [...dependsOn],
95
+ status: "notAnalyzed"
96
+ };
97
+ }
98
+ async function writeDocument(writer, projectRoot, relativePath, document) {
99
+ const result = await writer.writeContextDocument({
100
+ projectRoot,
101
+ relativePath,
102
+ document
103
+ });
104
+ if (result.status !== "written") {
105
+ throw new ContextGenerateError("CONTEXT_WRITE_FAILED", result.status === "escape"
106
+ ? `Context document resolves outside the project: ${relativePath}`
107
+ : `Context document cannot be written: ${relativePath}${"message" in result ? `: ${result.message}` : ""}`);
108
+ }
109
+ return result.sha256;
110
+ }
111
+ export class ContextGenerator {
112
+ dependencies;
113
+ constructor(dependencies) {
114
+ this.dependencies = dependencies;
115
+ }
116
+ generate = async (input) => {
117
+ const contextRoot = input.projectRoot;
118
+ const contextPath = isAbsolute(input.contextPath)
119
+ ? input.contextPath
120
+ : resolve(contextRoot, input.contextPath);
121
+ const contextRelativePath = projectRelativePath(contextRoot, contextPath, (message) => new ContextGenerateError("CONTEXT_INVALID", message));
122
+ const documentRelativePath = contextRelativePath;
123
+ try {
124
+ assertProjectPathUnder(contextRoot, documentRelativePath, CONTEXT_DIR, "Project Context output");
125
+ }
126
+ catch (error) {
127
+ throw new ContextGenerateError("CONTEXT_INVALID", error instanceof Error ? error.message : String(error));
128
+ }
129
+ if (input.force !== true) {
130
+ const existing = await this.dependencies.files.inspectProjectFile({
131
+ projectRoot: contextRoot,
132
+ relativePath: documentRelativePath,
133
+ maximumBytes: 1
134
+ });
135
+ if (existing.status === "inspected") {
136
+ throw new ContextGenerateError("CONTEXT_ALREADY_EXISTS", `Project Context already exists: ${documentRelativePath} (use --force to overwrite)`);
137
+ }
138
+ }
139
+ const discovery = await this.dependencies.discoverer.discoverModules({
140
+ projectRoot: input.projectRoot
141
+ });
142
+ if (discovery.status !== "discovered") {
143
+ throw new ContextGenerateError("MODULE_DISCOVERY_FAILED", discovery.status === "noApplicationModule"
144
+ ? "No application module found in settings.gradle"
145
+ : discovery.status === "noSettingsFile"
146
+ ? "No settings.gradle or settings.gradle.kts found"
147
+ : `Module discovery failed: ${discovery.status}`);
148
+ }
149
+ const appModule = discovery.modules.find((module) => module.kind === "application");
150
+ if (appModule === undefined) {
151
+ throw new ContextGenerateError("MODULE_DISCOVERY_FAILED", "No application module found");
152
+ }
153
+ const identity = await this.dependencies.identity.inspectIdentity({
154
+ projectRoot: input.projectRoot,
155
+ moduleDir: appModule.projectDir
156
+ });
157
+ if (identity.status !== "inspected") {
158
+ throw new ContextGenerateError("IDENTITY_INSPECTION_FAILED", `Identity inspection failed: ${identity.status}`);
159
+ }
160
+ const moduleResults = [];
161
+ const moduleReferences = [];
162
+ for (const module of discovery.modules) {
163
+ const inventoryResult = await this.dependencies.inventory.inspectProjectInventory({
164
+ projectRoot: input.projectRoot,
165
+ projectDir: module.projectDir,
166
+ categories: [...INVENTORY_CATEGORIES]
167
+ });
168
+ if (inventoryResult.status !== "inspected") {
169
+ throw new ContextGenerateError("MODULE_DISCOVERY_FAILED", `Unable to inspect module inventory: ${module.id}`);
170
+ }
171
+ const evidence = await collectEvidence(this.dependencies.files, input.projectRoot, inventoryResult.paths);
172
+ if (evidence.length === 0) {
173
+ throw new ContextGenerateError("NO_EVIDENCE", `No evidence files collected for module: ${module.id}`);
174
+ }
175
+ const shardPath = moduleIdToContextPath(module.id);
176
+ const shardDocument = buildShardDocument(module, evidence, inventoryResult.pathSetSha256);
177
+ const parsed = ProjectContextModuleSchema.safeParse(shardDocument);
178
+ if (!parsed.success) {
179
+ throw new ContextGenerateError("CONTEXT_INVALID", `Generated shard does not match module schema: ${module.id}`);
180
+ }
181
+ const shardSha256 = await writeDocument(this.dependencies.writer, contextRoot, shardPath, parsed.data);
182
+ moduleResults.push({
183
+ id: module.id,
184
+ projectDir: module.projectDir,
185
+ kind: module.kind,
186
+ status: "notAnalyzed",
187
+ evidenceCount: evidence.length,
188
+ contextPath: shardPath,
189
+ sha256: shardSha256
190
+ });
191
+ moduleReferences.push(buildModuleReference(module, shardPath, shardSha256, module.dependsOn));
192
+ }
193
+ moduleReferences.sort((a, b) => compareStrings(a.id, b.id));
194
+ const rootEvidence = await collectRootEvidence(this.dependencies.files, input.projectRoot);
195
+ if (rootEvidence.length === 0) {
196
+ throw new ContextGenerateError("NO_EVIDENCE", "No root evidence files collected");
197
+ }
198
+ const indexDocument = {
199
+ version: 2,
200
+ packageName: identity.packageName,
201
+ launchActivity: identity.launchActivity,
202
+ manifest: {
203
+ version: 1,
204
+ files: rootEvidence.map((record) => ({
205
+ path: record.path,
206
+ sha256: record.sha256,
207
+ semanticSha256: record.semanticSha256,
208
+ confidence: "sourceConfirmed"
209
+ }))
210
+ },
211
+ interactionPolicy: { ...DEFAULT_INTERACTION_POLICY },
212
+ modules: moduleReferences
213
+ };
214
+ const parsedIndex = ProjectContextSchema.safeParse(indexDocument);
215
+ if (!parsedIndex.success) {
216
+ throw new ContextGenerateError("CONTEXT_INVALID", "Generated index does not match the version 2 schema");
217
+ }
218
+ const indexHash = await writeDocument(this.dependencies.writer, contextRoot, documentRelativePath, parsedIndex.data);
219
+ return {
220
+ status: "generated",
221
+ packageName: identity.packageName,
222
+ launchActivity: identity.launchActivity,
223
+ modules: moduleResults,
224
+ indexHash,
225
+ contextPath: contextRelativePath
226
+ };
227
+ };
228
+ }
@@ -0,0 +1,40 @@
1
+ import { type ProjectContext, type ProjectContextModule, type ResolvedProjectContext } from "../../domain/project-context.js";
2
+ import type { ProjectFileInspector } from "../../ports/project-file-inspector.js";
3
+ import type { ProjectInventoryInspector } from "../../ports/project-inventory-inspector.js";
4
+ export declare const MAX_CONTEXT_SHARD_BYTES: number;
5
+ export type ContextLoadErrorCode = "CONTEXT_INVALID" | "CONTEXT_STALE" | "CONTEXT_MODULE_NOT_FOUND" | "CONTEXT_MODULE_INCOMPLETE";
6
+ export declare class ContextLoadError extends Error {
7
+ readonly code: ContextLoadErrorCode;
8
+ readonly name = "ContextLoadError";
9
+ constructor(code: ContextLoadErrorCode, message: string);
10
+ }
11
+ export interface LoadedProjectContext {
12
+ context: ResolvedProjectContext;
13
+ bundle: ProjectContext;
14
+ modules: ProjectContextModule[];
15
+ }
16
+ export interface LoadedContextIndex {
17
+ bundle: ProjectContext;
18
+ indexHash: string;
19
+ }
20
+ export interface ContextLoadInput {
21
+ projectRoot: string;
22
+ contextPath: string;
23
+ moduleIds?: string[] | undefined;
24
+ allowIncomplete?: boolean | undefined;
25
+ }
26
+ export interface ContextLoaderDependencies {
27
+ files: ProjectFileInspector;
28
+ inventory: ProjectInventoryInspector;
29
+ readJson: (path: string) => Promise<unknown>;
30
+ }
31
+ export declare class ContextLoader {
32
+ private readonly dependencies;
33
+ constructor(dependencies: ContextLoaderDependencies);
34
+ private readonly readStableDocument;
35
+ readonly readIndex: (input: {
36
+ projectRoot: string;
37
+ contextPath: string;
38
+ }) => Promise<LoadedContextIndex>;
39
+ readonly load: (input: ContextLoadInput) => Promise<LoadedProjectContext>;
40
+ }