@kontourai/flow-agents 0.1.1

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 (418) hide show
  1. package/.githooks/pre-push +11 -0
  2. package/.github/workflows/ci.yml +210 -0
  3. package/.github/workflows/docs-pages.yml +52 -0
  4. package/.github/workflows/publish-npm.yml +104 -0
  5. package/AGENTS.md +26 -0
  6. package/CHANGELOG.md +66 -0
  7. package/CODE_OF_CONDUCT.md +25 -0
  8. package/CONTEXT.md +300 -0
  9. package/CONTRIBUTING.md +44 -0
  10. package/LICENSE +201 -0
  11. package/README.md +129 -0
  12. package/SECURITY.md +33 -0
  13. package/agent-cards/dev.json +19 -0
  14. package/agents/dev.json +127 -0
  15. package/agents/tool-code-reviewer.json +61 -0
  16. package/agents/tool-dependencies-updater.json +118 -0
  17. package/agents/tool-explore-config.json +92 -0
  18. package/agents/tool-explore-deps.json +92 -0
  19. package/agents/tool-explore-entry.json +92 -0
  20. package/agents/tool-explore-patterns.json +92 -0
  21. package/agents/tool-explore-structure.json +92 -0
  22. package/agents/tool-explore-tests.json +92 -0
  23. package/agents/tool-planner.json +57 -0
  24. package/agents/tool-playwright.json +145 -0
  25. package/agents/tool-security-reviewer.json +56 -0
  26. package/agents/tool-verifier.json +61 -0
  27. package/agents/tool-worker.json +58 -0
  28. package/build/src/cli/console-learning-projection.js +123 -0
  29. package/build/src/cli/docs-preview.js +39 -0
  30. package/build/src/cli/effective-backlog-settings.js +102 -0
  31. package/build/src/cli/export-bookmarks.js +38 -0
  32. package/build/src/cli/fixture-retirement-audit.js +140 -0
  33. package/build/src/cli/flow-kit.js +138 -0
  34. package/build/src/cli/import-bookmarks.js +50 -0
  35. package/build/src/cli/init.js +239 -0
  36. package/build/src/cli/instinct-cli.js +93 -0
  37. package/build/src/cli/promote-workflow-artifact.js +63 -0
  38. package/build/src/cli/publish-change-helper.js +154 -0
  39. package/build/src/cli/pull-work-provider.js +469 -0
  40. package/build/src/cli/runtime-adapter.js +23 -0
  41. package/build/src/cli/telemetry-doctor.js +221 -0
  42. package/build/src/cli/usage-feedback.js +443 -0
  43. package/build/src/cli/validate-hook-influence.js +152 -0
  44. package/build/src/cli/validate-source-tree.js +31 -0
  45. package/build/src/cli/validate-workflow-artifacts.js +486 -0
  46. package/build/src/cli/veritas-governance.js +262 -0
  47. package/build/src/cli/workflow-artifact-cleanup-audit.js +272 -0
  48. package/build/src/cli/workflow-sidecar.js +816 -0
  49. package/build/src/cli.js +89 -0
  50. package/build/src/flow-kit/validate.js +75 -0
  51. package/build/src/lib/args.js +45 -0
  52. package/build/src/lib/fs.js +62 -0
  53. package/build/src/lib/workflow-learning-projection.js +334 -0
  54. package/build/src/runtime-adapters.js +146 -0
  55. package/build/src/tools/build-universal-bundles.js +397 -0
  56. package/build/src/tools/common.js +56 -0
  57. package/build/src/tools/filter-installed-packs.js +132 -0
  58. package/build/src/tools/generate-context-map.js +198 -0
  59. package/build/src/tools/validate-package.js +64 -0
  60. package/build/src/tools/validate-source-tree.js +622 -0
  61. package/console.telemetry.json +176 -0
  62. package/context/base-rules.md +17 -0
  63. package/context/code-review-standards.md +62 -0
  64. package/context/coding-standards.md +42 -0
  65. package/context/common/orchestrators.md +12 -0
  66. package/context/common/subagents.md +28 -0
  67. package/context/contracts/artifact-contract.md +182 -0
  68. package/context/contracts/builder-kit-workflow-state-contract.md +319 -0
  69. package/context/contracts/delivery-contract.md +69 -0
  70. package/context/contracts/execution-contract.md +53 -0
  71. package/context/contracts/governance-adapter-contract.md +67 -0
  72. package/context/contracts/planning-contract.md +85 -0
  73. package/context/contracts/review-contract.md +104 -0
  74. package/context/contracts/sandbox-policy.md +52 -0
  75. package/context/contracts/verification-contract.md +134 -0
  76. package/context/contracts/work-item-contract.md +215 -0
  77. package/context/deferred/demo-mode.md +33 -0
  78. package/context/deferred/languages/go.md +31 -0
  79. package/context/deferred/languages/python.md +31 -0
  80. package/context/deferred/languages/typescript.md +34 -0
  81. package/context/deferred/parallelization.md +35 -0
  82. package/context/deferred/worktree-isolation.md +24 -0
  83. package/context/development-workflow.md +50 -0
  84. package/context/scripts/context-budget/budget-scan.sh +166 -0
  85. package/context/scripts/detect-tools.sh +3 -0
  86. package/context/scripts/discover-agents.sh +28 -0
  87. package/context/scripts/git-status.sh +49 -0
  88. package/context/scripts/hooks/config-protection.js +79 -0
  89. package/context/scripts/hooks/desktop-notify.sh +39 -0
  90. package/context/scripts/hooks/governance-audit.sh +135 -0
  91. package/context/scripts/hooks/lib/audit-transport.sh +40 -0
  92. package/context/scripts/hooks/lib/hook-flags.js +49 -0
  93. package/context/scripts/hooks/lib/patterns.sh +57 -0
  94. package/context/scripts/hooks/lib/resolve-formatter.js +80 -0
  95. package/context/scripts/hooks/post-edit-accumulator.js +66 -0
  96. package/context/scripts/hooks/pre-commit-quality.js +194 -0
  97. package/context/scripts/hooks/quality-gate.js +93 -0
  98. package/context/scripts/hooks/report-only-guard.js +21 -0
  99. package/context/scripts/hooks/run-hook.js +136 -0
  100. package/context/scripts/hooks/stop-format-typecheck.js +141 -0
  101. package/context/scripts/hooks/stop-goal-fit.js +337 -0
  102. package/context/scripts/hooks/workflow-steering.js +250 -0
  103. package/context/scripts/telemetry/console-presets.sh +14 -0
  104. package/context/scripts/telemetry/install-console-config.sh +214 -0
  105. package/context/scripts/telemetry/lib/config.sh +85 -0
  106. package/context/scripts/telemetry/lib/enrich.sh +115 -0
  107. package/context/scripts/telemetry/lib/redact.sh +22 -0
  108. package/context/scripts/telemetry/lib/session.sh +63 -0
  109. package/context/scripts/telemetry/lib/transport.sh +183 -0
  110. package/context/scripts/telemetry/lib/usage.sh +29 -0
  111. package/context/scripts/telemetry/sync-agents.sh +173 -0
  112. package/context/scripts/telemetry/telemetry.conf +23 -0
  113. package/context/scripts/telemetry/telemetry.sh +387 -0
  114. package/context/scripts/validate-package.sh +89 -0
  115. package/context/settings/backlog-provider-settings.json +54 -0
  116. package/context/templates/core/identity.md +26 -0
  117. package/context/templates/core/user.md +15 -0
  118. package/docs/_config.yml +15 -0
  119. package/docs/_layouts/default.html +87 -0
  120. package/docs/adr/0001-flow-agents-consumes-flow.md +77 -0
  121. package/docs/adr/0002-flow-kits-as-extension-unit.md +13 -0
  122. package/docs/adr/0003-flow-agents-coordinates-kits-and-adapters.md +13 -0
  123. package/docs/adr/0004-gates-expect-surface-claims.md +15 -0
  124. package/docs/adr/0005-kubernetes-inspired-resource-contracts.md +48 -0
  125. package/docs/adr/0006-typescript-first-source-policy.md +98 -0
  126. package/docs/agent-system-guidebook.md +391 -0
  127. package/docs/agent-usage-feedback-loop.md +351 -0
  128. package/docs/assets/favicon.svg +13 -0
  129. package/docs/assets/og-image.png +0 -0
  130. package/docs/assets/site.css +774 -0
  131. package/docs/assets/site.js +139 -0
  132. package/docs/configurable-workflow-routing.md +174 -0
  133. package/docs/context-map.md +145 -0
  134. package/docs/developer-architecture.md +145 -0
  135. package/docs/developer-hook-setup.md +61 -0
  136. package/docs/fixture-ownership.md +44 -0
  137. package/docs/flow-kit-repository-contract.md +180 -0
  138. package/docs/index.md +129 -0
  139. package/docs/kontour-resource-contract.md +358 -0
  140. package/docs/migrations.md +64 -0
  141. package/docs/north-star.md +322 -0
  142. package/docs/operating-layers.md +110 -0
  143. package/docs/repository-structure.md +132 -0
  144. package/docs/sandbox-policy.md +56 -0
  145. package/docs/skills-map.md +203 -0
  146. package/docs/standards-register.md +96 -0
  147. package/docs/veritas-integration.md +165 -0
  148. package/docs/work-item-adapters.md +72 -0
  149. package/docs/workflow-artifact-lifecycle.md +141 -0
  150. package/docs/workflow-eval-strategy.md +295 -0
  151. package/docs/workflow-shared-contracts.md +51 -0
  152. package/docs/workflow-usage-guide.md +443 -0
  153. package/evals/ARCHITECTURE.md +143 -0
  154. package/evals/CONVENTIONS.md +58 -0
  155. package/evals/README.md +128 -0
  156. package/evals/acceptance/run.sh +29 -0
  157. package/evals/acceptance/test_claude_harness.sh +242 -0
  158. package/evals/acceptance/test_codex_harness.sh +108 -0
  159. package/evals/acceptance/test_kiro_harness.sh +128 -0
  160. package/evals/cases/dev/404.html +97 -0
  161. package/evals/cases/dev/code-review.yaml +44 -0
  162. package/evals/cases/dev/dashboard.html +300 -0
  163. package/evals/cases/dev/deliver.yaml +66 -0
  164. package/evals/cases/dev/dependency-update.yaml +16 -0
  165. package/evals/cases/dev/explore.yaml +20 -0
  166. package/evals/cases/dev/index.html +370 -0
  167. package/evals/cases/dev/package-lock.json +28 -0
  168. package/evals/cases/dev/package.json +16 -0
  169. package/evals/cases/dev/plan-work.yaml +20 -0
  170. package/evals/cases/dev/promptfooconfig.yaml +666 -0
  171. package/evals/cases/dev/search-first.yaml +20 -0
  172. package/evals/cases/dev/tdd-workflow.yaml +48 -0
  173. package/evals/cases/dev/verify-work.yaml +44 -0
  174. package/evals/cases/dev/workflow.yaml +34 -0
  175. package/evals/ci/run-baseline.sh +283 -0
  176. package/evals/fixtures/backlog-provider-settings/global-default.json +44 -0
  177. package/evals/fixtures/backlog-provider-settings/project-override.json +53 -0
  178. package/evals/fixtures/builder-kit-workflow-state/baseline-freshness-resolution-hint.json +139 -0
  179. package/evals/fixtures/builder-kit-workflow-state/direct-primitive-stop.json +59 -0
  180. package/evals/fixtures/builder-kit-workflow-state/empty-board-route-shape.json +55 -0
  181. package/evals/fixtures/builder-kit-workflow-state/happy-path.json +71 -0
  182. package/evals/fixtures/builder-kit-workflow-state/mid-work-resume.json +80 -0
  183. package/evals/fixtures/builder-kit-workflow-state/missing-prestep-recovery.json +65 -0
  184. package/evals/fixtures/builder-kit-workflow-state/product-build-chaining.json +60 -0
  185. package/evals/fixtures/builder-kit-workflow-state/stale-continuation-requires-new-probe.json +57 -0
  186. package/evals/fixtures/console-learning-projection/artifacts/console-learning-correction/learning.json +50 -0
  187. package/evals/fixtures/console-learning-projection/artifacts/console-learning-open-route/learning.json +41 -0
  188. package/evals/fixtures/flow-kit-repository/invalid-absolute-path/kit.json +8 -0
  189. package/evals/fixtures/flow-kit-repository/invalid-asset-section/flows/review.flow.json +6 -0
  190. package/evals/fixtures/flow-kit-repository/invalid-asset-section/kit.json +11 -0
  191. package/evals/fixtures/flow-kit-repository/invalid-duplicate-flow/flows/review.flow.json +6 -0
  192. package/evals/fixtures/flow-kit-repository/invalid-duplicate-flow/kit.json +9 -0
  193. package/evals/fixtures/flow-kit-repository/invalid-id/flows/review.flow.json +6 -0
  194. package/evals/fixtures/flow-kit-repository/invalid-id/kit.json +8 -0
  195. package/evals/fixtures/flow-kit-repository/invalid-malformed-json/kit.json +8 -0
  196. package/evals/fixtures/flow-kit-repository/invalid-missing-flow/kit.json +8 -0
  197. package/evals/fixtures/flow-kit-repository/invalid-missing-id/flows/review.flow.json +6 -0
  198. package/evals/fixtures/flow-kit-repository/invalid-missing-id/kit.json +7 -0
  199. package/evals/fixtures/flow-kit-repository/invalid-missing-schema-version/flows/review.flow.json +6 -0
  200. package/evals/fixtures/flow-kit-repository/invalid-missing-schema-version/kit.json +7 -0
  201. package/evals/fixtures/flow-kit-repository/invalid-name/flows/review.flow.json +6 -0
  202. package/evals/fixtures/flow-kit-repository/invalid-name/kit.json +8 -0
  203. package/evals/fixtures/flow-kit-repository/invalid-schema-version/flows/review.flow.json +6 -0
  204. package/evals/fixtures/flow-kit-repository/invalid-schema-version/kit.json +8 -0
  205. package/evals/fixtures/flow-kit-repository/invalid-traversal/kit.json +8 -0
  206. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/adapters/example.json +3 -0
  207. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/assets/example.txt +1 -0
  208. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/docs/README.md +3 -0
  209. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/flows/runtime.flow.json +26 -0
  210. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit-evals/example.json +3 -0
  211. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit-skills/mixed/SKILL.md +3 -0
  212. package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit.json +44 -0
  213. package/evals/fixtures/flow-kit-repository/valid-local-kit/docs/README.md +3 -0
  214. package/evals/fixtures/flow-kit-repository/valid-local-kit/flows/review.flow.json +26 -0
  215. package/evals/fixtures/flow-kit-repository/valid-local-kit/kit.json +20 -0
  216. package/evals/fixtures/hook-influence/cases.json +336 -0
  217. package/evals/fixtures/pull-work-provider/github-issues.json +170 -0
  218. package/evals/fixtures/pull-work-wip-shepherding/global-wip-informs.json +43 -0
  219. package/evals/fixtures/pull-work-wip-shepherding/personal-wip-blocks.json +42 -0
  220. package/evals/fixtures/surface-trust/accepted-claim-trust-report.json +31 -0
  221. package/evals/fixtures/surface-trust/artifact-absent.json +19 -0
  222. package/evals/fixtures/surface-trust/integrity-mismatch-trust-report.json +32 -0
  223. package/evals/fixtures/surface-trust/missing-authority-trust-report.json +27 -0
  224. package/evals/fixtures/surface-trust/provider-absent.json +19 -0
  225. package/evals/fixtures/surface-trust/rejected-claim-trust-report.json +30 -0
  226. package/evals/fixtures/surface-trust/stale-claim-trust-snapshot.json +31 -0
  227. package/evals/fixtures/usage-feedback/sample-full.jsonl +11 -0
  228. package/evals/fixtures/usage-feedback/sample-outcomes.jsonl +1 -0
  229. package/evals/fixtures/veritas-governance-adapter/fake-veritas-pass.sh +18 -0
  230. package/evals/fixtures/veritas-governance-adapter/fake-veritas-secret-fail.sh +10 -0
  231. package/evals/fixtures/veritas-governance-adapter/fake-veritas-unconfigured.sh +4 -0
  232. package/evals/integration/test_bundle_install.sh +541 -0
  233. package/evals/integration/test_console_learning_projection.sh +192 -0
  234. package/evals/integration/test_context_map.sh +65 -0
  235. package/evals/integration/test_effective_backlog_settings.sh +58 -0
  236. package/evals/integration/test_fixture_retirement_audit.sh +58 -0
  237. package/evals/integration/test_flow_agents_statusline.sh +93 -0
  238. package/evals/integration/test_flow_kit_repository.sh +90 -0
  239. package/evals/integration/test_goal_fit_hook.sh +482 -0
  240. package/evals/integration/test_hook_category_behaviors.sh +190 -0
  241. package/evals/integration/test_hook_influence_cases.sh +69 -0
  242. package/evals/integration/test_local_flow_kit_install.sh +145 -0
  243. package/evals/integration/test_publish_change_helper.sh +176 -0
  244. package/evals/integration/test_pull_work_provider.sh +140 -0
  245. package/evals/integration/test_runtime_adapter_activation.sh +106 -0
  246. package/evals/integration/test_telemetry.sh +485 -0
  247. package/evals/integration/test_telemetry_doctor.sh +193 -0
  248. package/evals/integration/test_usage_feedback_dashboard.sh +169 -0
  249. package/evals/integration/test_usage_feedback_global.sh +117 -0
  250. package/evals/integration/test_usage_feedback_import.sh +227 -0
  251. package/evals/integration/test_usage_feedback_outcomes.sh +165 -0
  252. package/evals/integration/test_usage_feedback_report.sh +263 -0
  253. package/evals/integration/test_veritas_governance_adapter.sh +235 -0
  254. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +287 -0
  255. package/evals/integration/test_workflow_artifacts.sh +1247 -0
  256. package/evals/integration/test_workflow_sidecar_writer.sh +2112 -0
  257. package/evals/integration/test_workflow_steering_hook.sh +337 -0
  258. package/evals/lib/assertions/delegated-to.js +40 -0
  259. package/evals/lib/assertions/max-tool-calls.js +15 -0
  260. package/evals/lib/assertions/no-write-tools.js +27 -0
  261. package/evals/lib/assertions/pass-at-k.js +39 -0
  262. package/evals/lib/assertions/telemetry-utils.js +105 -0
  263. package/evals/lib/assertions/tool-called.js +39 -0
  264. package/evals/lib/assertions/verify-after-fix.js +61 -0
  265. package/evals/lib/claude-judge.sh +40 -0
  266. package/evals/lib/claude-provider.sh +74 -0
  267. package/evals/lib/codex-judge.sh +39 -0
  268. package/evals/lib/codex-provider.sh +81 -0
  269. package/evals/lib/eval-dev.sh +5 -0
  270. package/evals/lib/eval-judge.sh +22 -0
  271. package/evals/lib/eval-provider.sh +26 -0
  272. package/evals/lib/eval-report.sh +73 -0
  273. package/evals/lib/kiro-dev.sh +4 -0
  274. package/evals/lib/kiro-judge.sh +17 -0
  275. package/evals/lib/kiro-provider.sh +62 -0
  276. package/evals/lib/node.sh +111 -0
  277. package/evals/promptfooconfig.yaml +70 -0
  278. package/evals/run.sh +309 -0
  279. package/evals/static/test_evidence_refs.sh +141 -0
  280. package/evals/static/test_package.sh +407 -0
  281. package/evals/static/test_repo_hooks.sh +68 -0
  282. package/evals/static/test_universal_bundles.sh +274 -0
  283. package/evals/static/test_workflow_skills.sh +1207 -0
  284. package/install.sh +64 -0
  285. package/integrations/veritas/flow-agents.adapter.json +138 -0
  286. package/integrations/veritas/flow-agents.authority-settings.json +26 -0
  287. package/integrations/veritas/flow-agents.repo-standards.json +82 -0
  288. package/kits/builder/flows/build.flow.json +218 -0
  289. package/kits/builder/flows/shape.flow.json +127 -0
  290. package/kits/builder/kit.json +19 -0
  291. package/kits/catalog.json +11 -0
  292. package/package.json +130 -0
  293. package/packaging/README.md +60 -0
  294. package/packaging/manifest.json +173 -0
  295. package/packaging/packs.json +69 -0
  296. package/powers/dependency-checker/POWER.md +20 -0
  297. package/powers/dependency-checker/mcp.json +20 -0
  298. package/powers/playwright/POWER.md +25 -0
  299. package/powers/playwright/mcp.json +12 -0
  300. package/prompts/code-audit.md +123 -0
  301. package/prompts/kcommit.md +88 -0
  302. package/schemas/backlog-provider-settings.schema.json +138 -0
  303. package/schemas/workflow-acceptance.schema.json +216 -0
  304. package/schemas/workflow-critique.schema.json +113 -0
  305. package/schemas/workflow-evidence.schema.json +357 -0
  306. package/schemas/workflow-handoff.schema.json +52 -0
  307. package/schemas/workflow-learning.schema.json +223 -0
  308. package/schemas/workflow-release.schema.json +172 -0
  309. package/schemas/workflow-state.schema.json +80 -0
  310. package/scripts/README.md +111 -0
  311. package/scripts/build-universal-bundles.js +3 -0
  312. package/scripts/check-content-boundary.cjs +99 -0
  313. package/scripts/context-budget/budget-scan.sh +166 -0
  314. package/scripts/detect-tools.sh +3 -0
  315. package/scripts/discover-agents.sh +28 -0
  316. package/scripts/effective-backlog-settings.js +2 -0
  317. package/scripts/filter-installed-packs.js +2 -0
  318. package/scripts/flow-kit.js +2 -0
  319. package/scripts/generate-context-map.js +2 -0
  320. package/scripts/git-status.sh +49 -0
  321. package/scripts/hooks/claude-hook-adapter.js +174 -0
  322. package/scripts/hooks/claude-telemetry-hook.js +115 -0
  323. package/scripts/hooks/codex-hook-adapter.js +176 -0
  324. package/scripts/hooks/codex-telemetry-hook.js +95 -0
  325. package/scripts/hooks/config-protection.js +79 -0
  326. package/scripts/hooks/desktop-notify.sh +39 -0
  327. package/scripts/hooks/governance-audit.sh +135 -0
  328. package/scripts/hooks/lib/audit-transport.sh +40 -0
  329. package/scripts/hooks/lib/hook-flags.js +49 -0
  330. package/scripts/hooks/lib/patterns.sh +57 -0
  331. package/scripts/hooks/lib/resolve-formatter.js +80 -0
  332. package/scripts/hooks/post-edit-accumulator.js +66 -0
  333. package/scripts/hooks/pre-commit-quality.js +194 -0
  334. package/scripts/hooks/quality-gate.js +93 -0
  335. package/scripts/hooks/report-only-guard.js +21 -0
  336. package/scripts/hooks/run-hook.js +136 -0
  337. package/scripts/hooks/stop-format-typecheck.js +141 -0
  338. package/scripts/hooks/stop-goal-fit.js +337 -0
  339. package/scripts/hooks/workflow-steering.js +250 -0
  340. package/scripts/install-codex-home.sh +106 -0
  341. package/scripts/package.json +3 -0
  342. package/scripts/promote-workflow-artifact.js +2 -0
  343. package/scripts/publish-change-helper.js +2 -0
  344. package/scripts/pull-work-provider.js +2 -0
  345. package/scripts/setup-repo-hooks.sh +8 -0
  346. package/scripts/statusline/flow-agents-statusline.js +157 -0
  347. package/scripts/telemetry/console-presets.sh +14 -0
  348. package/scripts/telemetry/install-console-config.sh +214 -0
  349. package/scripts/telemetry/lib/config.sh +85 -0
  350. package/scripts/telemetry/lib/enrich.sh +115 -0
  351. package/scripts/telemetry/lib/redact.sh +22 -0
  352. package/scripts/telemetry/lib/session.sh +63 -0
  353. package/scripts/telemetry/lib/transport.sh +183 -0
  354. package/scripts/telemetry/lib/usage.sh +29 -0
  355. package/scripts/telemetry/sync-agents.sh +173 -0
  356. package/scripts/telemetry/telemetry.conf +23 -0
  357. package/scripts/telemetry/telemetry.sh +387 -0
  358. package/scripts/usage-feedback.js +2 -0
  359. package/scripts/validate-hook-influence-cases.js +2 -0
  360. package/scripts/validate-package.sh +89 -0
  361. package/scripts/validate-source-tree.js +9 -0
  362. package/skills/agentic-engineering/SKILL.md +62 -0
  363. package/skills/browser-test/SKILL.md +51 -0
  364. package/skills/builder-shape/SKILL.md +76 -0
  365. package/skills/context-budget/SKILL.md +40 -0
  366. package/skills/deliver/SKILL.md +241 -0
  367. package/skills/dependency-update/SKILL.md +68 -0
  368. package/skills/design-probe/SKILL.md +107 -0
  369. package/skills/eval-rebuild/SKILL.md +39 -0
  370. package/skills/evidence-gate/SKILL.md +186 -0
  371. package/skills/execute-plan/SKILL.md +110 -0
  372. package/skills/explore/SKILL.md +137 -0
  373. package/skills/feedback-loop/SKILL.md +87 -0
  374. package/skills/fix-bug/SKILL.md +133 -0
  375. package/skills/frontend-design/SKILL.md +80 -0
  376. package/skills/github-cli/SKILL.md +63 -0
  377. package/skills/idea-to-backlog/SKILL.md +267 -0
  378. package/skills/knowledge-capture/SKILL.md +55 -0
  379. package/skills/learning-review/SKILL.md +115 -0
  380. package/skills/pickup-probe/SKILL.md +114 -0
  381. package/skills/plan-work/SKILL.md +176 -0
  382. package/skills/pull-work/SKILL.md +309 -0
  383. package/skills/release-readiness/SKILL.md +121 -0
  384. package/skills/review-work/SKILL.md +161 -0
  385. package/skills/search-first/SKILL.md +66 -0
  386. package/skills/tdd-workflow/SKILL.md +140 -0
  387. package/skills/verify-work/SKILL.md +109 -0
  388. package/src/cli/console-learning-projection.ts +140 -0
  389. package/src/cli/effective-backlog-settings.ts +99 -0
  390. package/src/cli/fixture-retirement-audit.ts +154 -0
  391. package/src/cli/flow-kit.ts +139 -0
  392. package/src/cli/init.ts +248 -0
  393. package/src/cli/promote-workflow-artifact.ts +64 -0
  394. package/src/cli/publish-change-helper.ts +143 -0
  395. package/src/cli/pull-work-provider.ts +481 -0
  396. package/src/cli/runtime-adapter.ts +24 -0
  397. package/src/cli/telemetry-doctor.ts +243 -0
  398. package/src/cli/usage-feedback.ts +418 -0
  399. package/src/cli/validate-hook-influence.ts +119 -0
  400. package/src/cli/validate-source-tree.ts +30 -0
  401. package/src/cli/validate-workflow-artifacts.ts +411 -0
  402. package/src/cli/veritas-governance.ts +322 -0
  403. package/src/cli/workflow-artifact-cleanup-audit.ts +281 -0
  404. package/src/cli/workflow-sidecar.ts +676 -0
  405. package/src/cli.ts +95 -0
  406. package/src/flow-kit/validate.ts +74 -0
  407. package/src/lib/args.ts +43 -0
  408. package/src/lib/fs.ts +62 -0
  409. package/src/lib/workflow-learning-projection.ts +491 -0
  410. package/src/runtime-adapters.ts +154 -0
  411. package/src/tools/build-universal-bundles.ts +366 -0
  412. package/src/tools/common.ts +61 -0
  413. package/src/tools/filter-installed-packs.ts +129 -0
  414. package/src/tools/generate-context-map.ts +199 -0
  415. package/src/tools/validate-package.ts +57 -0
  416. package/src/tools/validate-source-tree.ts +488 -0
  417. package/tsconfig.json +19 -0
  418. package/veritas.claims.json +6 -0
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hook runner — checks profile/disable flags before executing the actual hook.
4
+ *
5
+ * Usage:
6
+ * node run-hook.js <hookId> <scriptRelativePath> [profilesCsv]
7
+ *
8
+ * Exit codes:
9
+ * 0 = allow (pass through)
10
+ * 2 = block (preToolUse only)
11
+ * other = error (non-blocking)
12
+ */
13
+
14
+ 'use strict';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { spawnSync } = require('child_process');
19
+ const { isHookEnabled } = require('./lib/hook-flags');
20
+
21
+ const MAX_STDIN = 1024 * 1024;
22
+
23
+ function readStdinRaw() {
24
+ return new Promise(resolve => {
25
+ let raw = '';
26
+ let truncated = false;
27
+ process.stdin.setEncoding('utf8');
28
+ process.stdin.on('data', chunk => {
29
+ if (raw.length < MAX_STDIN) {
30
+ const remaining = MAX_STDIN - raw.length;
31
+ raw += chunk.substring(0, remaining);
32
+ if (chunk.length > remaining) truncated = true;
33
+ } else {
34
+ truncated = true;
35
+ }
36
+ });
37
+ process.stdin.on('end', () => resolve({ raw, truncated }));
38
+ process.stdin.on('error', () => resolve({ raw, truncated }));
39
+ });
40
+ }
41
+
42
+ function emitHookResult(raw, output) {
43
+ if (typeof output === 'string' || Buffer.isBuffer(output)) {
44
+ process.stdout.write(String(output));
45
+ return 0;
46
+ }
47
+ if (output && typeof output === 'object') {
48
+ if (output.stderr) {
49
+ process.stderr.write(output.stderr.endsWith('\n') ? output.stderr : `${output.stderr}\n`);
50
+ }
51
+ if (Object.prototype.hasOwnProperty.call(output, 'stdout')) {
52
+ process.stdout.write(String(output.stdout ?? ''));
53
+ } else if (!Number.isInteger(output.exitCode) || output.exitCode === 0) {
54
+ process.stdout.write(raw);
55
+ }
56
+ return Number.isInteger(output.exitCode) ? output.exitCode : 0;
57
+ }
58
+ process.stdout.write(raw);
59
+ return 0;
60
+ }
61
+
62
+ async function main() {
63
+ const [, , hookId, relScriptPath, profilesCsv] = process.argv;
64
+ const { raw, truncated } = await readStdinRaw();
65
+
66
+ if (!hookId || !relScriptPath) {
67
+ process.stdout.write(raw);
68
+ process.exit(0);
69
+ }
70
+
71
+ if (!isHookEnabled(hookId, { profiles: profilesCsv })) {
72
+ process.stdout.write(raw);
73
+ process.exit(0);
74
+ }
75
+
76
+ const hooksDir = __dirname;
77
+ const scriptPath = path.resolve(hooksDir, relScriptPath);
78
+
79
+ if (!scriptPath.startsWith(hooksDir + path.sep)) {
80
+ process.stderr.write(`[Hook] Path traversal rejected for ${hookId}: ${scriptPath}\n`);
81
+ process.stdout.write(raw);
82
+ process.exit(0);
83
+ }
84
+
85
+ if (!fs.existsSync(scriptPath)) {
86
+ process.stderr.write(`[Hook] Script not found for ${hookId}: ${scriptPath}\n`);
87
+ process.stdout.write(raw);
88
+ process.exit(0);
89
+ }
90
+
91
+ // Prefer direct require() when the hook exports run() — saves ~50-100ms
92
+ let hookModule;
93
+ const src = fs.readFileSync(scriptPath, 'utf8');
94
+ if (/\bmodule\.exports\b/.test(src) && /\brun\b/.test(src)) {
95
+ try { hookModule = require(scriptPath); } catch (e) {
96
+ process.stderr.write(`[Hook] require() failed for ${hookId}: ${e.message}\n`);
97
+ }
98
+ }
99
+
100
+ if (hookModule && typeof hookModule.run === 'function') {
101
+ try {
102
+ const output = hookModule.run(raw, { truncated, maxStdin: MAX_STDIN });
103
+ process.exit(emitHookResult(raw, output));
104
+ } catch (e) {
105
+ process.stderr.write(`[Hook] run() error for ${hookId}: ${e.message}\n`);
106
+ process.stdout.write(raw);
107
+ process.exit(0);
108
+ }
109
+ }
110
+
111
+ // Legacy fallback: spawn child process
112
+ const result = spawnSync(process.execPath, [scriptPath], {
113
+ input: raw,
114
+ encoding: 'utf8',
115
+ env: { ...process.env, SA_HOOK_INPUT_TRUNCATED: truncated ? '1' : '0', SA_HOOK_INPUT_MAX_BYTES: String(MAX_STDIN) },
116
+ cwd: process.cwd(),
117
+ timeout: 30000,
118
+ });
119
+
120
+ if (result.stdout) process.stdout.write(result.stdout);
121
+ else if (Number.isInteger(result.status) && result.status === 0) process.stdout.write(raw);
122
+ if (result.stderr) process.stderr.write(result.stderr);
123
+
124
+ if (result.error || result.signal || result.status === null) {
125
+ const detail = result.error ? result.error.message : result.signal ? `signal ${result.signal}` : 'missing exit status';
126
+ process.stderr.write(`[Hook] legacy execution failed for ${hookId}: ${detail}\n`);
127
+ process.exit(1);
128
+ }
129
+
130
+ process.exit(Number.isInteger(result.status) ? result.status : 0);
131
+ }
132
+
133
+ main().catch(err => {
134
+ process.stderr.write(`[Hook] run-hook error: ${err.message}\n`);
135
+ process.exit(0);
136
+ });
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stop Hook: Batch format + typecheck all JS/TS files edited this response
4
+ *
5
+ * Reads the accumulator from post-edit-accumulator.js, groups files by
6
+ * project root for formatter and by tsconfig dir for typecheck.
7
+ * Budget is distributed evenly across batches.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const { execFileSync, spawnSync } = require('child_process');
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { findProjectRoot, detectFormatter, resolveFormatterBin } = require('./lib/resolve-formatter');
16
+
17
+ const MAX_STDIN = 1024 * 1024;
18
+ const TOTAL_BUDGET_MS = 270_000;
19
+
20
+ function getAccumFile() {
21
+ // Import from accumulator to share session ID logic
22
+ try {
23
+ return require('./post-edit-accumulator').getAccumFile();
24
+ } catch {
25
+ const crypto = require('crypto');
26
+ const os = require('os');
27
+ const id = crypto.createHash('sha1').update(process.cwd()).digest('hex').slice(0, 12);
28
+ return path.join(os.tmpdir(), `flow-agents-edited-${id}.txt`);
29
+ }
30
+ }
31
+
32
+ function parseAccumulator(raw) {
33
+ return [...new Set(raw.split('\n').map(l => l.trim()).filter(Boolean))];
34
+ }
35
+
36
+ function formatBatch(projectRoot, files, timeoutMs) {
37
+ const formatter = detectFormatter(projectRoot);
38
+ if (!formatter) return;
39
+ const resolved = resolveFormatterBin(projectRoot, formatter);
40
+ if (!resolved) return;
41
+ const existing = files.filter(f => fs.existsSync(f));
42
+ if (existing.length === 0) return;
43
+ const args = formatter === 'biome'
44
+ ? [...resolved.prefix, 'check', '--write', ...existing]
45
+ : [...resolved.prefix, '--write', ...existing];
46
+ try {
47
+ execFileSync(resolved.bin, args, { cwd: projectRoot, stdio: ['pipe', 'pipe', 'pipe'], timeout: timeoutMs });
48
+ } catch { /* non-blocking */ }
49
+ }
50
+
51
+ function findTsConfigDir(filePath) {
52
+ let dir = path.dirname(filePath);
53
+ const root = path.parse(dir).root;
54
+ let depth = 0;
55
+ while (dir !== root && depth < 20) {
56
+ if (fs.existsSync(path.join(dir, 'tsconfig.json'))) return dir;
57
+ dir = path.dirname(dir);
58
+ depth++;
59
+ }
60
+ return null;
61
+ }
62
+
63
+ function typecheckBatch(tsConfigDir, editedFiles, timeoutMs) {
64
+ const args = ['tsc', '--noEmit', '--pretty', 'false'];
65
+ const opts = { cwd: tsConfigDir, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: timeoutMs };
66
+ let stdout = '', stderr = '', failed = false;
67
+ try {
68
+ execFileSync('npx', args, opts);
69
+ } catch (err) {
70
+ stdout = err.stdout || '';
71
+ stderr = err.stderr || '';
72
+ failed = true;
73
+ }
74
+ if (!failed) return;
75
+ const lines = (stdout + stderr).split('\n');
76
+ for (const filePath of editedFiles) {
77
+ const relPath = path.relative(tsConfigDir, filePath);
78
+ const relevant = lines
79
+ .filter(line => line.includes(filePath) || line.includes(relPath))
80
+ .slice(0, 10);
81
+ if (relevant.length > 0) {
82
+ process.stderr.write(`[Hook] TypeScript errors in ${path.basename(filePath)}:\n`);
83
+ relevant.forEach(l => process.stderr.write(l + '\n'));
84
+ }
85
+ }
86
+ }
87
+
88
+ function main() {
89
+ const accumFile = getAccumFile();
90
+ let raw;
91
+ try { raw = fs.readFileSync(accumFile, 'utf8'); } catch { return; }
92
+ try { fs.unlinkSync(accumFile); } catch { /* best-effort */ }
93
+
94
+ const files = parseAccumulator(raw);
95
+ if (files.length === 0) return;
96
+
97
+ const byRoot = new Map();
98
+ const byTsConfig = new Map();
99
+ for (const f of files) {
100
+ if (!/\.(ts|tsx|js|jsx)$/.test(f)) continue;
101
+ const resolved = path.resolve(f);
102
+ if (!fs.existsSync(resolved)) continue;
103
+ const root = findProjectRoot(path.dirname(resolved));
104
+ if (!byRoot.has(root)) byRoot.set(root, []);
105
+ byRoot.get(root).push(resolved);
106
+ if (/\.(ts|tsx)$/.test(f)) {
107
+ const tsDir = findTsConfigDir(resolved);
108
+ if (tsDir) {
109
+ if (!byTsConfig.has(tsDir)) byTsConfig.set(tsDir, []);
110
+ byTsConfig.get(tsDir).push(resolved);
111
+ }
112
+ }
113
+ }
114
+
115
+ const totalBatches = byRoot.size + byTsConfig.size;
116
+ const perBatch = totalBatches > 0 ? Math.floor(TOTAL_BUDGET_MS / totalBatches) : 60_000;
117
+
118
+ for (const [root, batch] of byRoot) formatBatch(root, batch, perBatch);
119
+ for (const [tsDir, batch] of byTsConfig) typecheckBatch(tsDir, batch, perBatch);
120
+ }
121
+
122
+ function run(rawInput) {
123
+ try { main(); } catch (e) {
124
+ process.stderr.write(`[Hook] stop-format-typecheck error: ${e.message}\n`);
125
+ }
126
+ return rawInput;
127
+ }
128
+
129
+ if (require.main === module) {
130
+ let data = '';
131
+ process.stdin.setEncoding('utf8');
132
+ process.stdin.on('data', chunk => {
133
+ if (data.length < MAX_STDIN) data += chunk.substring(0, MAX_STDIN - data.length);
134
+ });
135
+ process.stdin.on('end', () => {
136
+ process.stdout.write(run(data));
137
+ process.exit(0);
138
+ });
139
+ }
140
+
141
+ module.exports = { run, parseAccumulator };
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stop Hook: warn when an active workflow is about to stop short of its goal.
4
+ *
5
+ * The hook reads .flow-agents artifacts, looks for the most recent active
6
+ * delivery/session file, and reports missing Definition Of Done, Goal Fit, or
7
+ * Final Acceptance state. It is warning-only by default. Set
8
+ * FLOW_AGENTS_GOAL_FIT_STRICT=true to return exit code 2 when local goal fit is
9
+ * incomplete.
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const { spawnSync } = require('child_process');
17
+
18
+ const MAX_STDIN = 1024 * 1024;
19
+ const ACTIVE_STATUSES = new Set([
20
+ 'planning',
21
+ 'planned',
22
+ 'executing',
23
+ 'executed',
24
+ 'reviewing',
25
+ 'verifying',
26
+ 'failed',
27
+ 'needs-decision',
28
+ 'in-progress',
29
+ 'blocked',
30
+ 'partial',
31
+ ]);
32
+ const DELIVERY_TYPES = new Set(['deliver', 'delivery', 'fix-bug', 'execute-plan', 'verify-work']);
33
+ const SIDECAR_NAMES = new Set(['state.json', 'acceptance.json', 'evidence.json', 'handoff.json']);
34
+ const OPTIONAL_SIDECAR_NAMES = new Set(['critique.json']);
35
+
36
+ function parseJson(raw) {
37
+ try { return JSON.parse(raw || '{}'); } catch { return {}; }
38
+ }
39
+
40
+ function findRepoRoot(startDir) {
41
+ let dir = path.resolve(startDir || process.cwd());
42
+ const root = path.parse(dir).root;
43
+ for (let depth = 0; dir && depth < 40; depth++) {
44
+ if (fs.existsSync(path.join(dir, '.git')) || fs.existsSync(path.join(dir, 'AGENTS.md'))) return dir;
45
+ if (dir === root) break;
46
+ dir = path.dirname(dir);
47
+ }
48
+ return path.resolve(startDir || process.cwd());
49
+ }
50
+
51
+ function walkMarkdown(dir, out = []) {
52
+ if (!fs.existsSync(dir)) return out;
53
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
54
+ const full = path.join(dir, entry.name);
55
+ if (entry.isDirectory()) {
56
+ if (entry.name === 'archive') continue;
57
+ walkMarkdown(full, out);
58
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
59
+ out.push(full);
60
+ }
61
+ }
62
+ return out;
63
+ }
64
+
65
+ function readArtifact(file) {
66
+ let text = '';
67
+ try { text = fs.readFileSync(file, 'utf8'); } catch { return null; }
68
+ const stat = fs.statSync(file);
69
+ const status = (text.match(/^status:\s*([A-Za-z0-9_-]+)/m) || [])[1] || '';
70
+ const type = (text.match(/^type:\s*([A-Za-z0-9_-]+)/m) || [])[1] || '';
71
+ const role = (text.match(/^role:\s*([A-Za-z0-9_-]+)/m) || [])[1] || '';
72
+ return { file, text, status, type, role, mtimeMs: stat.mtimeMs };
73
+ }
74
+
75
+ function hasSidecars(dir) {
76
+ try {
77
+ return fs.readdirSync(dir).some(name => SIDECAR_NAMES.has(name));
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ function sidecarValidation(root, artifactDir) {
84
+ const requireSidecars = String(process.env.FLOW_AGENTS_REQUIRE_SIDECARS || '').toLowerCase() === 'true';
85
+ const requireCritique = String(process.env.FLOW_AGENTS_REQUIRE_CRITIQUE || '').toLowerCase() === 'true';
86
+ if (!requireSidecars && !requireCritique && !hasSidecars(artifactDir)) return [];
87
+
88
+ const packageRoot = fs.existsSync(path.join(root, 'package.json'))
89
+ ? root
90
+ : path.resolve(__dirname, '..', '..');
91
+ const packageJson = path.join(packageRoot, 'package.json');
92
+ if (!fs.existsSync(packageJson)) return [`${relative(root, artifactDir)} sidecar validation: package.json is missing; cannot run TypeScript workflow validator.`];
93
+
94
+ let sidecarFiles = [];
95
+ try {
96
+ sidecarFiles = fs.readdirSync(artifactDir)
97
+ .filter(name => SIDECAR_NAMES.has(name) || OPTIONAL_SIDECAR_NAMES.has(name))
98
+ .map(name => path.join(artifactDir, name));
99
+ } catch {
100
+ sidecarFiles = [];
101
+ }
102
+
103
+ if (requireSidecars || requireCritique) {
104
+ const present = new Set(sidecarFiles.map(file => path.basename(file)));
105
+ const requiredNames = new Set(requireSidecars ? SIDECAR_NAMES : []);
106
+ if (requireCritique) requiredNames.add('critique.json');
107
+ const missing = [...requiredNames].filter(name => !present.has(name)).sort();
108
+ if (missing.length > 0) {
109
+ return missing.map(name => `${relative(root, path.join(artifactDir, name))} sidecar validation: required sidecar is missing`);
110
+ }
111
+ }
112
+
113
+ if (sidecarFiles.length === 0) return [];
114
+
115
+ const args = ['run', 'workflow:validate-artifacts', '--silent', '--'];
116
+ args.push('--skip-markdown-validation');
117
+ if (requireSidecars) args.push('--require-sidecars');
118
+ if (requireCritique) args.push('--require-critique');
119
+ args.push(artifactDir);
120
+
121
+ const result = spawnSync('npm', args, {
122
+ cwd: packageRoot,
123
+ encoding: 'utf8',
124
+ timeout: 30000,
125
+ });
126
+
127
+ if (result.status === 0) return [];
128
+ const output = `${result.stdout || ''}\n${result.stderr || ''}`
129
+ .split('\n')
130
+ .map(line => line.trim())
131
+ .filter(Boolean)
132
+ .slice(0, 12);
133
+ if (output.length === 0) output.push(`validator exited with status ${result.status ?? 'unknown'}`);
134
+ return output.map(line => `${relative(root, artifactDir)} sidecar validation: ${line}`);
135
+ }
136
+
137
+ function isWorkflowArtifact(artifact) {
138
+ if (!artifact) return false;
139
+ if (artifact.role === 'plan' || artifact.role === 'review') return false;
140
+ if (artifact.file.endsWith('-plan.md') || artifact.file.endsWith('-review.md')) return false;
141
+ if (DELIVERY_TYPES.has(artifact.type)) return true;
142
+ return /--(deliver|fix-bug|execute-plan|verify-work)\b/.test(path.basename(artifact.file));
143
+ }
144
+
145
+ function uncheckedInSection(text, heading) {
146
+ const start = text.indexOf(`## ${heading}`);
147
+ if (start < 0) return [];
148
+ const rest = text.slice(start + heading.length + 3);
149
+ const next = rest.search(/\n##\s+/);
150
+ const section = next >= 0 ? rest.slice(0, next) : rest;
151
+ return section
152
+ .split('\n')
153
+ .filter(line => /^\s*-\s+\[\s\]/.test(line))
154
+ .map(line => line.replace(/^\s*-\s+\[\s\]\s*/, '').trim())
155
+ .filter(Boolean);
156
+ }
157
+
158
+ function hasHeading(text, heading) {
159
+ return new RegExp(`^##\\s+${heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'm').test(text);
160
+ }
161
+
162
+ function relative(root, file) {
163
+ return path.relative(root, file).split(path.sep).join('/');
164
+ }
165
+
166
+ function readJsonFile(file) {
167
+ try {
168
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
169
+ } catch {
170
+ return null;
171
+ }
172
+ }
173
+
174
+ function safeOneLine(value, maxLength = 220) {
175
+ const text = String(value || '').replace(/\s+/g, ' ').trim();
176
+ if (text.length <= maxLength) return text;
177
+ return `${text.slice(0, maxLength - 3)}...`;
178
+ }
179
+
180
+ function normalizedStatus(value) {
181
+ return safeOneLine(value, 80).toLowerCase();
182
+ }
183
+
184
+ function sidecarGuidance(root, artifactDir) {
185
+ const warnings = [];
186
+ const state = readJsonFile(path.join(artifactDir, 'state.json'));
187
+ const evidence = readJsonFile(path.join(artifactDir, 'evidence.json'));
188
+ const critique = readJsonFile(path.join(artifactDir, 'critique.json'));
189
+ const base = relative(root, artifactDir);
190
+
191
+ if (state) {
192
+ const status = normalizedStatus(state.status || 'unknown');
193
+ const phase = normalizedStatus(state.phase || 'unknown');
194
+ const next = state.next_action && typeof state.next_action === 'object' ? state.next_action : null;
195
+ if (!['done', 'delivered', 'archived', 'accepted', 'complete', 'completed'].includes(status)) {
196
+ const nextStatus = next ? normalizedStatus(next.status || 'unknown') : 'unknown';
197
+ const nextSummary = next && next.summary ? `; next_action:${nextStatus} "${safeOneLine(next.summary)}"` : '';
198
+ warnings.push(`${base} workflow state: status:${status} phase:${phase}${nextSummary}`);
199
+ }
200
+ }
201
+
202
+ if (state && state.next_action && normalizedStatus(state.next_action.status) !== 'done') {
203
+ const next = state.next_action;
204
+ warnings.push(`${base} next action: ${safeOneLine(next.summary)}${next.target_phase ? ` (target phase: ${safeOneLine(next.target_phase, 80)})` : ''}`);
205
+ }
206
+
207
+ if (evidence && normalizedStatus(evidence.verdict) && normalizedStatus(evidence.verdict) !== 'pass') {
208
+ warnings.push(`${base} evidence verdict:${safeOneLine(evidence.verdict, 40)}; do not deliver without accepted gap or new evidence.`);
209
+ }
210
+ if (evidence && Array.isArray(evidence.not_verified_gaps) && evidence.not_verified_gaps.length > 0) {
211
+ for (const gap of evidence.not_verified_gaps.slice(0, 3)) {
212
+ warnings.push(`${base} evidence NOT_VERIFIED gap: ${safeOneLine(gap)}`);
213
+ }
214
+ }
215
+ if (evidence && Array.isArray(evidence.checks)) {
216
+ const blockingChecks = evidence.checks.filter(check => {
217
+ const status = normalizedStatus(check && check.status);
218
+ return status === 'fail' || status === 'failed' || status === 'not_verified' || status === 'not-verified';
219
+ });
220
+ for (const check of blockingChecks.slice(0, 4)) {
221
+ const status = safeOneLine(check.status || 'unknown', 40);
222
+ warnings.push(`${base} evidence check ${safeOneLine(check.id || 'unknown', 80)} status:${status}: ${safeOneLine(check.summary)}`);
223
+ }
224
+ }
225
+
226
+ if (critique && critique.required === true && normalizedStatus(critique.status) !== 'pass') {
227
+ warnings.push(`${base} critique status:${safeOneLine(critique.status || 'unknown', 40)}; required critique must pass or findings be accepted.`);
228
+ const critiques = Array.isArray(critique.critiques) ? critique.critiques : [];
229
+ let openCount = 0;
230
+ for (const review of critiques) {
231
+ const findings = Array.isArray(review && review.findings) ? review.findings : [];
232
+ for (const finding of findings) {
233
+ if (!finding || normalizedStatus(finding.status) !== 'open') continue;
234
+ warnings.push(`${base} critique open ${safeOneLine(finding.severity || 'unknown', 40)}: ${safeOneLine(finding.description)}`);
235
+ openCount += 1;
236
+ if (openCount >= 3) break;
237
+ }
238
+ if (openCount >= 3) break;
239
+ }
240
+ }
241
+
242
+ return warnings;
243
+ }
244
+
245
+ function markdownVerdict(text) {
246
+ const verdict = (/###\s+Verdict:\s*([A-Za-z_ -]+)/i.exec(text) || [])[1]
247
+ || (/^Build:\s*\[?([A-Za-z_ -]+)\]?/im.exec(text) || [])[1]
248
+ || '';
249
+ return normalizedStatus(verdict).replace(/[^a-z_ -].*$/, '').trim();
250
+ }
251
+
252
+ function analyze(root, now = Date.now()) {
253
+ const dirs = [path.join(root, '.flow-agents')];
254
+ const artifacts = dirs
255
+ .flatMap(dir => walkMarkdown(dir))
256
+ .map(readArtifact)
257
+ .filter(isWorkflowArtifact)
258
+ .sort((a, b) => b.mtimeMs - a.mtimeMs);
259
+
260
+ if (artifacts.length === 0) return { warnings: [], blocking: false };
261
+
262
+ const latest = artifacts[0];
263
+ const warnings = [];
264
+ const relPath = relative(root, latest.file);
265
+ const status = latest.status || 'unknown';
266
+ const ageMinutes = Math.max(0, Math.round((now - latest.mtimeMs) / 60000));
267
+
268
+ if (ACTIVE_STATUSES.has(status)) {
269
+ warnings.push(`${relPath} is still status:${status} (${ageMinutes}m old). Do not final-answer as complete unless the next step is explicit.`);
270
+ }
271
+
272
+ if (!hasHeading(latest.text, 'Definition Of Done')) {
273
+ warnings.push(`${relPath} is missing ## Definition Of Done, so the user-facing finish line is not explicit.`);
274
+ }
275
+
276
+ if (!hasHeading(latest.text, 'Goal Fit Gate')) {
277
+ warnings.push(`${relPath} is missing ## Goal Fit Gate, so local acceptance has not been checked.`);
278
+ } else {
279
+ for (const item of uncheckedInSection(latest.text, 'Goal Fit Gate').slice(0, 6)) {
280
+ warnings.push(`${relPath} Goal Fit unchecked: ${item}`);
281
+ }
282
+ }
283
+
284
+ if (status === 'delivered' && hasHeading(latest.text, 'Final Acceptance')) {
285
+ const uncheckedFinal = uncheckedInSection(latest.text, 'Final Acceptance');
286
+ if (uncheckedFinal.length > 0) {
287
+ warnings.push(`${relPath} local delivery is marked delivered, but Final Acceptance still has ${uncheckedFinal.length} open item(s) for CI/merge/docs promotion.`);
288
+ }
289
+ }
290
+
291
+ warnings.push(...sidecarValidation(root, path.dirname(latest.file)));
292
+ const evidence = readJsonFile(path.join(path.dirname(latest.file), 'evidence.json'));
293
+ if (evidence && markdownVerdict(latest.text) === 'pass' && normalizedStatus(evidence.verdict) === 'fail') {
294
+ warnings.push(`${relPath} Markdown PASS contradicts evidence.json verdict fail.`);
295
+ }
296
+ warnings.push(...sidecarGuidance(root, path.dirname(latest.file)));
297
+
298
+ const blocking = warnings.some(w => /status:|Definition Of Done|Goal Fit|sidecar validation|contradicts evidence\.json|workflow state|evidence verdict|evidence check|NOT_VERIFIED gap|critique status|critique open|next action/.test(w));
299
+ return { warnings, blocking };
300
+ }
301
+
302
+ function run(rawInput) {
303
+ const input = parseJson(rawInput);
304
+ const root = findRepoRoot(input.cwd || process.cwd());
305
+ const result = analyze(root);
306
+ if (result.warnings.length === 0) return rawInput;
307
+
308
+ const message = [
309
+ '[Hook] Goal Fit warning:',
310
+ ...result.warnings.map(w => ` - ${w}`),
311
+ ].join('\n');
312
+ const strict = String(process.env.FLOW_AGENTS_GOAL_FIT_STRICT || '').toLowerCase() === 'true';
313
+ return {
314
+ stdout: rawInput,
315
+ stderr: message,
316
+ exitCode: strict && result.blocking ? 2 : 0,
317
+ };
318
+ }
319
+
320
+ if (require.main === module) {
321
+ let data = '';
322
+ process.stdin.setEncoding('utf8');
323
+ process.stdin.on('data', chunk => {
324
+ if (data.length < MAX_STDIN) data += chunk.substring(0, MAX_STDIN - data.length);
325
+ });
326
+ process.stdin.on('end', () => {
327
+ const output = run(data);
328
+ if (output && typeof output === 'object') {
329
+ if (output.stderr) process.stderr.write(output.stderr.endsWith('\n') ? output.stderr : `${output.stderr}\n`);
330
+ process.stdout.write(String(output.stdout ?? data));
331
+ process.exit(Number.isInteger(output.exitCode) ? output.exitCode : 0);
332
+ }
333
+ process.stdout.write(String(output));
334
+ });
335
+ }
336
+
337
+ module.exports = { analyze, run, uncheckedInSection, findRepoRoot, sidecarGuidance, safeOneLine };