@khoavu882/doflow 2.0.0-beta.4 → 2.0.0

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 (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -0,0 +1,617 @@
1
+ 'use strict';
2
+
3
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
+
5
+ /**
6
+ * Impacted test selector (feature 089, IC-009, DD-7, DD-8; feature 090, IC-001, IC-002).
7
+ *
8
+ * Statically discovers tests impacted by changed files through relative import/require graph
9
+ * traversal, non-test helper graph inclusion, CLI hub cutting and verb scoping, wildcard
10
+ * spawn-test reachability, guard directory inclusion, and unknown-file fallback to the full
11
+ * test suite.
12
+ */
13
+
14
+ const path = require('node:path');
15
+ const nodeFs = require('node:fs');
16
+ const { conventionFor, testFilesFor, GUARD_DIR } = require('./test-selection.js');
17
+
18
+ const DISPATCHER_RE = /bin\/doflow|doflow-run(?![a-z0-9-])|(['"])bin\1\s*,\s*(['"])doflow(?:\.js)?\2/;
19
+ const CP_FUNCS = /\b(?:spawn|spawnSync|execSync|execFile|execFileSync|fork)\s*\(/;
20
+ const CP_TOKEN = ['child', 'process'].join('_');
21
+ const CP_RE = new RegExp(CP_TOKEN);
22
+
23
+ /** Normalises a repository-relative path: forward slashes, no leading `./`, no trailing `/`. */
24
+ function normalize(file ) {
25
+ return String(file).replace(/\\/g, '/').replace(/^(?:\.\/)+/, '').replace(/\/+$/, '');
26
+ }
27
+
28
+ function statOf(fsImpl , file ) {
29
+ try {
30
+ return fsImpl.statSync(file);
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ /** Determines whether a test or helper file spawns the CLI / dispatcher. */
37
+ function isSpawnTest(text ) {
38
+ if (!DISPATCHER_RE.test(text)) return false;
39
+ if (CP_FUNCS.test(text)) return true;
40
+ if (CP_RE.test(text) && /\bexec\s*\(/.test(text)) return true;
41
+ if (/(?:^|[^.\w$])exec\s*\(/.test(text)) return true;
42
+ return false;
43
+ }
44
+
45
+ /** Extracts static relative specifiers starting with `.` from file text. */
46
+ function extractRelativeSpecifiers(text ) {
47
+ const specs = new Set ();
48
+ // call forms: require and dynamic import with a literal relative specifier
49
+ const callPattern = /\b(?:require|import)\s*\(\s*(['"`])(\.[^'"`]*)\1\s*\)/g;
50
+ for (const match of text.matchAll(callPattern)) {
51
+ specs.add(match[2]);
52
+ }
53
+ // static import and re-export forms with a from clause
54
+ const fromPattern = /\b(?:import|export)\b(?:(?!import|export)[^;])*?\bfrom\s*(['"`])(\.[^'"`]*)\1/g;
55
+ for (const match of text.matchAll(fromPattern)) {
56
+ specs.add(match[2]);
57
+ }
58
+ // side-effect import with a literal specifier
59
+ const sideImportPattern = /\bimport\s+(['"`])(\.[^'"`]*)\1/g;
60
+ for (const match of text.matchAll(sideImportPattern)) {
61
+ specs.add(match[2]);
62
+ }
63
+ return [...specs];
64
+ }
65
+
66
+ /** Resolves a relative specifier against `fromFile` checking exact, .ts, .js, /index.ts, /index.js. */
67
+ function resolveRelativeSpecifier(fromFile , spec , root , fsImpl ) {
68
+ if (!spec.startsWith('.')) return null;
69
+ const fromDir = path.dirname(fromFile);
70
+ const targetBase = normalize(path.join(fromDir, spec));
71
+
72
+ const candidates = [
73
+ targetBase,
74
+ `${targetBase}.ts`,
75
+ `${targetBase}.js`,
76
+ `${targetBase}/index.ts`,
77
+ `${targetBase}/index.js`,
78
+ ];
79
+ if (targetBase.endsWith('.js')) {
80
+ candidates.push(`${targetBase.slice(0, -3)}.ts`);
81
+ }
82
+
83
+ for (const candidate of candidates) {
84
+ const absPath = path.join(root, candidate);
85
+ try {
86
+ const stat = fsImpl.statSync(absPath);
87
+ if (stat && stat.isFile()) {
88
+ return normalize(candidate);
89
+ }
90
+ } catch {
91
+ // not found
92
+ }
93
+ }
94
+ return null;
95
+ }
96
+
97
+ /** Checks whether a path belongs to the monitored module graph: src/**, bin/**, bench/**, or test/** non-test helper. */
98
+ function isGraphNode(file , convention ) {
99
+ return (
100
+ file.startsWith('src/') ||
101
+ file.startsWith('bin/') ||
102
+ file.startsWith('bench/') ||
103
+ (file.startsWith('test/') && !convention.isTest(file))
104
+ );
105
+ }
106
+
107
+ /** Checks whether a non-code file is guard-covered and should not trigger unknown-file expansion. */
108
+ function isGuardCoveredPath(file , hasGuardDir ) {
109
+ if (!hasGuardDir) return false;
110
+ return (
111
+ file === 'CHANGELOG.md' ||
112
+ file === 'AGENTS.md' ||
113
+ file === 'CLAUDE.md' ||
114
+ file.startsWith('docs/') ||
115
+ file.startsWith('agent-docs/') ||
116
+ file.startsWith('.doflow/')
117
+ );
118
+ }
119
+
120
+ /** Parses CLI dispatch hubs and lazy handler functions to map CLI verbs to their target implementation modules. */
121
+ function parseCliVerbMap(root , fsImpl ) {
122
+ const verbToModules = new Map ();
123
+ const addVerbMod = (v , m ) => {
124
+ if (!m) return;
125
+ if (!verbToModules.has(v)) verbToModules.set(v, new Set());
126
+ verbToModules.get(v) .add(m);
127
+ };
128
+
129
+ for (const hub of ['src/cli/runtime-commands.js', 'src/cli/index.js']) {
130
+ let text = '';
131
+ try {
132
+ text = fsImpl.readFileSync(path.join(root, hub), 'utf8');
133
+ } catch {
134
+ continue;
135
+ }
136
+
137
+ const symToFile = new Map ();
138
+ const reqRe = /(?:const|let|var)\s+(\{[^}]+\}|\w+)\s*=\s*require\(\s*(['"])(\.[^'"]+)\2\s*\)/g;
139
+ for (const m of text.matchAll(reqRe)) {
140
+ const target = resolveRelativeSpecifier(hub, m[3], root, fsImpl);
141
+ if (!target) continue;
142
+ const lhs = m[1].trim();
143
+ if (lhs.startsWith('{')) {
144
+ for (const part of lhs.slice(1, -1).split(',')) {
145
+ const piece = part.trim();
146
+ if (!piece) continue;
147
+ const [orig, alias] = piece.split(':').map((s ) => s.trim());
148
+ symToFile.set(alias || orig, target);
149
+ }
150
+ } else {
151
+ symToFile.set(lhs, target);
152
+ }
153
+ }
154
+
155
+ const fnRe = /function\s+(\w+)\s*\([^)]*\)[^{]*\{\s*return\s+require\(\s*(['"])(\.[^'"]+)\2\s*\)/g;
156
+ for (const m of text.matchAll(fnRe)) {
157
+ const target = resolveRelativeSpecifier(hub, m[3], root, fsImpl);
158
+ if (target) symToFile.set(m[1], target);
159
+ }
160
+
161
+ const caseRe = /case\s+(['"])([a-z0-9-]+)\1\s*:\s*return\s+(\w+)\s*\(/g;
162
+ for (const m of text.matchAll(caseRe)) {
163
+ const verb = m[2];
164
+ const fn = m[3];
165
+ if (symToFile.has(fn)) addVerbMod(verb, symToFile.get(fn) );
166
+ const helperRe = new RegExp('function\\s+' + fn + '\\b[\\s\\S]*?\\n}', 'm');
167
+ const hm = text.match(helperRe);
168
+ if (hm) {
169
+ for (const [sym, f] of symToFile.entries()) {
170
+ if (new RegExp('\\b' + sym + '\\b').test(hm[0])) addVerbMod(verb, f);
171
+ }
172
+ for (const rm of hm[0].matchAll(/require\(\s*(['"])(\.[^'"]+)\1\s*\)/g)) {
173
+ addVerbMod(verb, resolveRelativeSpecifier(hub, rm[2], root, fsImpl));
174
+ }
175
+ }
176
+ }
177
+
178
+ const cmdBlock = text.match(/\bconst\s+COMMANDS\b[\s\S]*?=\s*\{([\s\S]*?)\};/);
179
+ if (cmdBlock) {
180
+ for (const m of cmdBlock[1].matchAll(/(?:['"]([a-z0-9-]+)['"]|([a-z0-9-]+))\s*:\s*(\w+)/g)) {
181
+ const verb = m[1] || m[2];
182
+ const sym = m[3];
183
+ if (symToFile.has(sym)) addVerbMod(verb, symToFile.get(sym) );
184
+ }
185
+ }
186
+ }
187
+
188
+ return verbToModules;
189
+ }
190
+
191
+ /** Strips handle*Command function bodies when extracting general library dependencies of a module that also exports library functions. */
192
+ function stripCommandHandlerBodies(text ) {
193
+ return text.replace(/function\s+handle\w*Command\b[\s\S]*?\n\}/gm, '');
194
+ }
195
+
196
+ /** Extracts statically invoked CLI verbs from test or helper text. */
197
+ function extractInvokedVerbs(text , knownVerbsSet ) {
198
+ const verbs = new Set ();
199
+ const arrRe = /\[\s*(?:[A-Za-z0-9_$.]+\s*,\s*)?['"`]([a-z][a-z0-9-]*)['"`]/g;
200
+ for (const m of text.matchAll(arrRe)) {
201
+ if (knownVerbsSet.has(m[1])) verbs.add(m[1]);
202
+ }
203
+ const runCallRe = /\b(?:run\w*|cli\w*|doflow\w*|exec\w*|spawn\w*)\s*\(\s*(?:[^,()\n]+\s*,\s*)?['"`]([a-z][a-z0-9-]*)['"`]/gi;
204
+ for (const m of text.matchAll(runCallRe)) {
205
+ if (knownVerbsSet.has(m[1])) verbs.add(m[1]);
206
+ }
207
+ const cmdRe = /\bdoflow(?:-run)?(?:\.js)?['"`\s,]+\s*['"`]?([a-z][a-z0-9-]*)/g;
208
+ for (const m of text.matchAll(cmdRe)) {
209
+ if (knownVerbsSet.has(m[1])) verbs.add(m[1]);
210
+ }
211
+ return verbs;
212
+ }
213
+
214
+ /**
215
+ * Resolves all .test.* files that directly or transitively import any of the specified non-test helper files (IC-002).
216
+ *
217
+ * @param {Object} input
218
+ * @param {string} input.root project root directory
219
+ * @param {Object} input.found detected testTargeted entry (from detectCommands)
220
+ * @param {Array<string>} [input.helperFiles] repo-relative non-test helper paths under test/**
221
+ * @param {Object} [input.fsImpl] filesystem implementation (defaults to node:fs)
222
+ * @returns {Array<string>} sorted list of repo-relative test paths
223
+ */
224
+ function resolveTestsImportingHelper({
225
+ root,
226
+ found,
227
+ helperFiles = [],
228
+ fsImpl = nodeFs,
229
+ }
230
+
231
+
232
+
233
+
234
+ ) {
235
+ const convention = conventionFor(found);
236
+ if (!convention) return [];
237
+ const allTests = testFilesFor(found, root, fsImpl);
238
+ if (!allTests || allTests.length === 0 || helperFiles.length === 0) return [];
239
+
240
+ const normalizedHelpers = new Set(helperFiles.map(normalize));
241
+ const testFilesSet = new Set (allTests);
242
+
243
+ const directImporters = new Map ();
244
+ const helperQueue = [];
245
+ const scanned = new Set ();
246
+
247
+ for (const testFile of allTests) {
248
+ let text = '';
249
+ try {
250
+ text = fsImpl.readFileSync(path.join(root, testFile), 'utf8');
251
+ } catch {
252
+ continue;
253
+ }
254
+ for (const spec of extractRelativeSpecifiers(text)) {
255
+ const resolved = resolveRelativeSpecifier(testFile, spec, root, fsImpl);
256
+ if (resolved && (resolved.startsWith('test/') || resolved.startsWith('bench/') || resolved.startsWith('src/'))) {
257
+ if (!directImporters.has(resolved)) directImporters.set(resolved, new Set());
258
+ directImporters.get(resolved) .add(testFile);
259
+ if (resolved.startsWith('test/') && !convention.isTest(resolved) && !scanned.has(resolved)) {
260
+ helperQueue.push(resolved);
261
+ }
262
+ }
263
+ }
264
+ }
265
+
266
+ while (helperQueue.length > 0) {
267
+ const helper = helperQueue.shift() ;
268
+ if (scanned.has(helper)) continue;
269
+ scanned.add(helper);
270
+
271
+ let text = '';
272
+ try {
273
+ text = fsImpl.readFileSync(path.join(root, helper), 'utf8');
274
+ } catch {
275
+ continue;
276
+ }
277
+
278
+ for (const spec of extractRelativeSpecifiers(text)) {
279
+ const resolved = resolveRelativeSpecifier(helper, spec, root, fsImpl);
280
+ if (resolved && (resolved.startsWith('test/') || resolved.startsWith('bench/') || resolved.startsWith('src/'))) {
281
+ if (!directImporters.has(resolved)) directImporters.set(resolved, new Set());
282
+ directImporters.get(resolved) .add(helper);
283
+ if (resolved.startsWith('test/') && !convention.isTest(resolved) && !scanned.has(resolved)) {
284
+ helperQueue.push(resolved);
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ const importingTests = new Set ();
291
+ const visited = new Set ();
292
+ const queue = [...normalizedHelpers];
293
+
294
+ while (queue.length > 0) {
295
+ const current = queue.shift() ;
296
+ if (visited.has(current)) continue;
297
+ visited.add(current);
298
+
299
+ const callers = directImporters.get(current);
300
+ if (!callers) continue;
301
+
302
+ for (const caller of callers) {
303
+ if (testFilesSet.has(caller)) {
304
+ importingTests.add(caller);
305
+ }
306
+ if (!visited.has(caller)) {
307
+ queue.push(caller);
308
+ }
309
+ }
310
+ }
311
+
312
+ return [...importingTests].sort();
313
+ }
314
+
315
+ /**
316
+ * Selects impacted tests for a set of changed files based on static dependency analysis (IC-001, IC-009).
317
+ *
318
+ * @param {Object} input
319
+ * @param {string} input.root project root directory
320
+ * @param {Object} input.found detected testTargeted entry (from detectCommands)
321
+ * @param {Array<string>} [input.changedFiles] changed repo-relative file paths
322
+ * @param {Array<string>} [input.deletedFiles] deleted repo-relative file paths
323
+ * @param {Object} [input.fsImpl] filesystem implementation (defaults to node:fs)
324
+ * @returns {null|{ mode: "selected" | "full", tests: Array<string>, totalCount: number, unknownFiles: Array<string>, spawnTests: number, graphMs: number }}
325
+ */
326
+ function selectImpactedTests({
327
+ root,
328
+ found,
329
+ changedFiles = [],
330
+ deletedFiles = [],
331
+ fsImpl = nodeFs,
332
+ }
333
+
334
+
335
+
336
+
337
+
338
+ ) {
339
+ const convention = conventionFor(found);
340
+ if (!convention) return null;
341
+
342
+ const t0 = process.hrtime.bigint();
343
+
344
+ const allTests = testFilesFor(found, root, fsImpl);
345
+ const totalCount = allTests.length;
346
+ const allTestFiles = new Set (allTests);
347
+
348
+ const guardDir = convention.guardDir && statOf(fsImpl, path.join(root, convention.guardDir))?.isDirectory()
349
+ ? convention.guardDir
350
+ : null;
351
+ const guardTests = guardDir
352
+ ? allTests.filter((file ) => file.startsWith(`${guardDir}/`) || file === guardDir)
353
+ : [];
354
+
355
+ const isGraphNodePath = (file ) => isGraphNode(file, convention);
356
+
357
+ const verbToModules = parseCliVerbMap(root, fsImpl);
358
+ const knownVerbsSet = new Set (verbToModules.keys());
359
+
360
+ const testTexts = new Map ();
361
+ const testToModules = new Map ();
362
+ const moduleQueue = [];
363
+
364
+ for (const testFile of allTests) {
365
+ testToModules.set(testFile, new Set());
366
+ let text = '';
367
+ try {
368
+ text = fsImpl.readFileSync(path.join(root, testFile), 'utf8');
369
+ testTexts.set(testFile, text);
370
+ } catch {
371
+ continue;
372
+ }
373
+ for (const spec of extractRelativeSpecifiers(text)) {
374
+ const resolved = resolveRelativeSpecifier(testFile, spec, root, fsImpl);
375
+ if (resolved && isGraphNodePath(resolved)) {
376
+ testToModules.get(testFile) .add(resolved);
377
+ moduleQueue.push(resolved);
378
+ }
379
+ }
380
+ }
381
+
382
+ // Queue all modules from hubs and verbToModules
383
+ const hubs = new Set (['bin/doflow.js', 'src/cli/index.js', 'src/cli/runtime-commands.js']);
384
+ for (const hub of hubs) {
385
+ if (statOf(fsImpl, path.join(root, hub))) {
386
+ moduleQueue.push(hub);
387
+ }
388
+ }
389
+ for (const mods of verbToModules.values()) {
390
+ for (const m of mods) {
391
+ moduleQueue.push(m);
392
+ }
393
+ }
394
+
395
+ const moduleDependencies = new Map ();
396
+ const scannedModules = new Set ();
397
+ const moduleTexts = new Map ();
398
+
399
+ function drainModuleQueue() {
400
+ while (moduleQueue.length > 0) {
401
+ const mod = moduleQueue.shift() ;
402
+ if (scannedModules.has(mod)) continue;
403
+ scannedModules.add(mod);
404
+
405
+ let text = '';
406
+ try {
407
+ text = fsImpl.readFileSync(path.join(root, mod), 'utf8');
408
+ moduleTexts.set(mod, text);
409
+ } catch {
410
+ continue;
411
+ }
412
+
413
+ if (!moduleDependencies.has(mod)) {
414
+ moduleDependencies.set(mod, new Set());
415
+ }
416
+
417
+ for (const spec of extractRelativeSpecifiers(text)) {
418
+ const resolved = resolveRelativeSpecifier(mod, spec, root, fsImpl);
419
+ if (resolved && isGraphNodePath(resolved)) {
420
+ if (!scannedModules.has(resolved)) {
421
+ moduleQueue.push(resolved);
422
+ }
423
+ }
424
+ }
425
+
426
+ if (hubs.has(mod)) continue;
427
+
428
+ const libText = stripCommandHandlerBodies(text);
429
+ for (const spec of extractRelativeSpecifiers(libText)) {
430
+ const resolved = resolveRelativeSpecifier(mod, spec, root, fsImpl);
431
+ if (resolved && isGraphNodePath(resolved)) {
432
+ moduleDependencies.get(mod) .add(resolved);
433
+ }
434
+ }
435
+ }
436
+ }
437
+
438
+ drainModuleQueue();
439
+
440
+ // Scan lazy requires in handle*Command functions for verbToModules expansion
441
+ for (const [verb, mods] of [...verbToModules.entries()]) {
442
+ for (const mod of [...mods]) {
443
+ const txt = moduleTexts.get(mod) || '';
444
+ for (const fnMatch of txt.matchAll(/function\s+handle\w*Command\b[\s\S]*?\n\}/gm)) {
445
+ for (const s of extractRelativeSpecifiers(fnMatch[0])) {
446
+ const resolved = resolveRelativeSpecifier(mod, s, root, fsImpl);
447
+ if (resolved) {
448
+ mods.add(resolved);
449
+ if (!scannedModules.has(resolved)) {
450
+ moduleQueue.push(resolved);
451
+ }
452
+ }
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+ drainModuleQueue();
459
+
460
+ const allSpawnTests = new Set ();
461
+ const spawnTests = new Set (); // wildcard spawn tests
462
+
463
+ for (const tf of allTests) {
464
+ const tText = testTexts.get(tf) || '';
465
+ let spawns = isSpawnTest(tText);
466
+ let invokedVerbs = extractInvokedVerbs(tText, knownVerbsSet);
467
+
468
+ // Transitive helper reachability from tf to test/** helpers
469
+ const helperQueue = [...testToModules.get(tf) ].filter((m) => m.startsWith('test/'));
470
+ const seenHelpers = new Set (helperQueue);
471
+ while (helperQueue.length > 0) {
472
+ const h = helperQueue.shift() ;
473
+ const hText = moduleTexts.get(h) || '';
474
+ if (isSpawnTest(hText)) spawns = true;
475
+ for (const dep of (moduleDependencies.get(h) || [])) {
476
+ if (dep.startsWith('test/') && !seenHelpers.has(dep)) {
477
+ seenHelpers.add(dep);
478
+ helperQueue.push(dep);
479
+ }
480
+ }
481
+ }
482
+
483
+ if (spawns && invokedVerbs.size === 0) {
484
+ for (const h of seenHelpers) {
485
+ for (const v of extractInvokedVerbs(moduleTexts.get(h) || '', knownVerbsSet)) {
486
+ invokedVerbs.add(v);
487
+ }
488
+ }
489
+ }
490
+
491
+ if (spawns) {
492
+ allSpawnTests.add(tf);
493
+
494
+ for (const hub of hubs) {
495
+ if (scannedModules.has(hub)) {
496
+ testToModules.get(tf) .add(hub);
497
+ }
498
+ }
499
+
500
+ if (invokedVerbs.size > 0) {
501
+ for (const v of invokedVerbs) {
502
+ const mods = verbToModules.get(v);
503
+ if (mods) {
504
+ for (const m of mods) {
505
+ testToModules.get(tf) .add(m);
506
+ }
507
+ }
508
+ }
509
+ } else {
510
+ spawnTests.add(tf);
511
+ }
512
+ }
513
+ }
514
+
515
+ const reverseModuleDeps = new Map ();
516
+ for (const [mod, targets] of moduleDependencies.entries()) {
517
+ for (const target of targets) {
518
+ if (!reverseModuleDeps.has(target)) reverseModuleDeps.set(target, new Set());
519
+ reverseModuleDeps.get(target) .add(mod);
520
+ }
521
+ }
522
+
523
+ const moduleDirectTests = new Map ();
524
+ for (const [t, targets] of testToModules.entries()) {
525
+ for (const target of targets) {
526
+ if (!moduleDirectTests.has(target)) moduleDirectTests.set(target, new Set());
527
+ moduleDirectTests.get(target) .add(t);
528
+ }
529
+ }
530
+
531
+ function testsReachingModule(targetModule ) {
532
+ const reachingTests = new Set ();
533
+ const visitedModules = new Set ([targetModule]);
534
+ const queue = [targetModule];
535
+ while (queue.length > 0) {
536
+ const current = queue.shift() ;
537
+ const direct = moduleDirectTests.get(current);
538
+ if (direct) {
539
+ for (const t of direct) reachingTests.add(t);
540
+ }
541
+ const callers = reverseModuleDeps.get(current);
542
+ if (callers) {
543
+ for (const caller of callers) {
544
+ if (!visitedModules.has(caller)) {
545
+ visitedModules.add(caller);
546
+ queue.push(caller);
547
+ }
548
+ }
549
+ }
550
+ }
551
+ return reachingTests;
552
+ }
553
+
554
+ const normalizedChanged = (changedFiles || []).map(normalize);
555
+ const normalizedDeleted = (deletedFiles || []).map(normalize);
556
+ const candidateFiles = [...new Set([...normalizedChanged, ...normalizedDeleted])];
557
+
558
+ const unknownFiles = new Set ();
559
+ const selectedTests = new Set ();
560
+ let hasReachedModule = false;
561
+
562
+ for (const file of candidateFiles) {
563
+ if (scannedModules.has(file)) {
564
+ if (!file.startsWith('test/')) {
565
+ hasReachedModule = true;
566
+ }
567
+ for (const t of testsReachingModule(file)) {
568
+ selectedTests.add(t);
569
+ }
570
+ } else if (convention.isTest(file)) {
571
+ if (allTestFiles.has(file)) {
572
+ selectedTests.add(file);
573
+ }
574
+ } else if (isGuardCoveredPath(file, guardDir !== null)) {
575
+ // guard-covered: verified by guardTests, does not enter unknownFiles
576
+ } else {
577
+ unknownFiles.add(file);
578
+ }
579
+ }
580
+
581
+ const fullSuite = () => ({
582
+ mode: 'full' ,
583
+ tests: [...allTests].sort(),
584
+ totalCount,
585
+ unknownFiles: [...unknownFiles].sort(),
586
+ spawnTests: allSpawnTests.size,
587
+ graphMs: Number(process.hrtime.bigint() - t0) / 1e6,
588
+ });
589
+
590
+ /* UNKNOWN_EXPANSION */ if (unknownFiles.size > 0) return fullSuite();
591
+
592
+ if (hasReachedModule) {
593
+ /* SPAWN_WILDCARD */ for (const spawnTest of spawnTests) selectedTests.add(spawnTest);
594
+ }
595
+
596
+ for (const guardTest of guardTests) {
597
+ selectedTests.add(guardTest);
598
+ }
599
+
600
+ return {
601
+ mode: 'selected' ,
602
+ tests: [...selectedTests].sort(),
603
+ totalCount,
604
+ unknownFiles: [],
605
+ spawnTests: allSpawnTests.size,
606
+ graphMs: Number(process.hrtime.bigint() - t0) / 1e6,
607
+ };
608
+ }
609
+
610
+ module.exports = {
611
+ selectImpactedTests,
612
+ isSpawnTest,
613
+ resolveRelativeSpecifier,
614
+ extractRelativeSpecifiers,
615
+ resolveTestsImportingHelper,
616
+ GUARD_DIR,
617
+ };