@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,248 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { createInterface } from "node:readline/promises";
6
+ import { stdin as input, stdout as output } from "node:process";
7
+ import { parseArgs, flagBool, flagList, flagString } from "../lib/args.js";
8
+ import { activateCodexLocal } from "../runtime-adapters.js";
9
+ import { main as buildBundles } from "../tools/build-universal-bundles.js";
10
+ import { root } from "../tools/common.js";
11
+
12
+ type Runtime = "base" | "codex" | "claude-code" | "kiro";
13
+ type TelemetrySink = "local-files" | "local-kontour-console" | "kontour-hosted-console" | "user-hosted-console" | "kontour-cloud" | "hosted-kontour-console";
14
+
15
+ type InitOptions = {
16
+ runtime: Runtime;
17
+ dest: string;
18
+ consoleUrl?: string;
19
+ consoleEndpoint?: string;
20
+ consoleTokenFile?: string;
21
+ consoleTokenValue?: string;
22
+ consoleTenant?: string;
23
+ telemetrySinks: TelemetrySink[];
24
+ packs?: string;
25
+ activateKits: boolean;
26
+ };
27
+
28
+ const runtimeBundles: Record<Runtime, string> = {
29
+ base: "base",
30
+ codex: "codex",
31
+ "claude-code": "claude-code",
32
+ kiro: "kiro",
33
+ };
34
+
35
+ function usage(): void {
36
+ console.error(`usage: flow-agents init [options]
37
+
38
+ Options:
39
+ --runtime base|codex|claude-code|kiro
40
+ --dest PATH
41
+ --telemetry-sink local-files|local-kontour-console|kontour-hosted-console|user-hosted-console
42
+ --console-url URL
43
+ --console-endpoint URL
44
+ --console-token-file PATH
45
+ --console-tenant ID
46
+ --packs LIST
47
+ --activate-kits
48
+ --yes, --headless
49
+ `);
50
+ }
51
+
52
+ function normalizeRuntime(value: string | undefined): Runtime | undefined {
53
+ if (!value) return undefined;
54
+ if (value === "claude") return "claude-code";
55
+ if (value === "base" || value === "codex" || value === "claude-code" || value === "kiro") return value;
56
+ throw new Error(`unknown runtime '${value}'; expected base, codex, claude-code, or kiro`);
57
+ }
58
+
59
+ function normalizeTelemetrySink(value: string): TelemetrySink {
60
+ if (value === "local-files" || value === "local-kontour-console" || value === "kontour-hosted-console" || value === "user-hosted-console" || value === "kontour-cloud" || value === "hosted-kontour-console") return value;
61
+ throw new Error(`unknown telemetry sink '${value}'`);
62
+ }
63
+
64
+ function telemetrySinksFromValues(values: string[]): TelemetrySink[] {
65
+ const sinks = values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean).map(normalizeTelemetrySink);
66
+ return sinks.length ? Array.from(new Set(sinks)) : ["local-files"];
67
+ }
68
+
69
+ function telemetrySinksFromFlags(flags: ReturnType<typeof parseArgs>["flags"]): TelemetrySink[] {
70
+ return telemetrySinksFromValues(flagList(flags, "telemetry-sink").concat(flagList(flags, "telemetry-sinks")));
71
+ }
72
+
73
+ function needsConsoleCredentials(sinks: TelemetrySink[]): boolean {
74
+ return sinks.some((sink) => sink !== "local-files");
75
+ }
76
+
77
+ async function questionHidden(prompt: string): Promise<string> {
78
+ if (!process.stdin.isTTY) return "";
79
+ return await new Promise((resolve) => {
80
+ const stdin = process.stdin;
81
+ const stdout = process.stdout;
82
+ const wasRaw = stdin.isRaw;
83
+ stdout.write(prompt);
84
+ stdin.setRawMode(true);
85
+ stdin.resume();
86
+ let value = "";
87
+ const onData = (buffer: Buffer) => {
88
+ const text = buffer.toString("utf8");
89
+ if (text === "\u0003") {
90
+ stdout.write("\n");
91
+ process.exit(130);
92
+ }
93
+ if (text === "\r" || text === "\n") {
94
+ stdout.write("\n");
95
+ stdin.setRawMode(wasRaw);
96
+ stdin.off("data", onData);
97
+ resolve(value);
98
+ return;
99
+ }
100
+ if (text === "\u007f") {
101
+ value = value.slice(0, -1);
102
+ return;
103
+ }
104
+ value += text;
105
+ };
106
+ stdin.on("data", onData);
107
+ });
108
+ }
109
+
110
+ function defaultDest(runtime: Runtime): string {
111
+ if (runtime === "kiro") return path.join(os.homedir(), ".flow-agents");
112
+ return process.cwd();
113
+ }
114
+
115
+ function parseYesNo(value: string, fallback: boolean): boolean {
116
+ const normalized = value.trim().toLowerCase();
117
+ if (!normalized) return fallback;
118
+ if (["y", "yes", "true", "1"].includes(normalized)) return true;
119
+ if (["n", "no", "false", "0"].includes(normalized)) return false;
120
+ return fallback;
121
+ }
122
+
123
+ async function interactiveOptions(argv: string[]): Promise<InitOptions> {
124
+ const args = parseArgs(argv);
125
+ const rl = createInterface({ input, output });
126
+ try {
127
+ const runtimeDefault = normalizeRuntime(flagString(args.flags, "runtime")) ?? "base";
128
+ const runtimeAnswer = flagString(args.flags, "runtime") ?? await rl.question(`Runtime [${runtimeDefault}]: `);
129
+ const runtime = normalizeRuntime(runtimeAnswer.trim() || runtimeDefault) ?? runtimeDefault;
130
+ const destDefault = flagString(args.flags, "dest", defaultDest(runtime)) ?? defaultDest(runtime);
131
+ const destAnswer = flagString(args.flags, "dest") ?? await rl.question(`Install destination [${destDefault}]: `);
132
+ const sinkDefault = telemetrySinksFromFlags(args.flags);
133
+ const sinkAnswer = flagList(args.flags, "telemetry-sink").length || flagList(args.flags, "telemetry-sinks").length
134
+ ? sinkDefault.join(",")
135
+ : await rl.question(`Telemetry sinks [${sinkDefault.join(",")}]: `);
136
+ const telemetrySinks = telemetrySinksFromValues([sinkAnswer || sinkDefault.join(",")]);
137
+ const needsUserHostedUrl = telemetrySinks.includes("user-hosted-console") || telemetrySinks.includes("hosted-kontour-console");
138
+ const consoleUrl = flagString(args.flags, "console-url") ?? (needsUserHostedUrl ? await rl.question("User-hosted Console URL: ") : undefined);
139
+ const consoleEndpoint = flagString(args.flags, "console-endpoint") ?? flagString(args.flags, "console-endpoint-url");
140
+ const consoleTokenFile = flagString(args.flags, "console-token-file");
141
+ const consoleTokenValue = consoleTokenFile ? undefined : (needsConsoleCredentials(telemetrySinks) ? await questionHidden("Console telemetry token (blank to skip): ") : undefined);
142
+ const consoleTenant = flagString(args.flags, "console-tenant") ?? flagString(args.flags, "console-tenant-id") ?? (needsConsoleCredentials(telemetrySinks) ? await rl.question("Console tenant ID (blank to skip): ") : undefined);
143
+ const activateDefault = false;
144
+ const activateAnswer = flagBool(args.flags, "activate-kits")
145
+ ? "yes"
146
+ : runtime === "codex"
147
+ ? await rl.question(`Activate local Builder Kit runtime assets [${activateDefault ? "Y/n" : "y/N"}]: `)
148
+ : "no";
149
+ return {
150
+ runtime,
151
+ dest: path.resolve(destAnswer.trim() || destDefault),
152
+ consoleUrl: consoleUrl?.trim() || undefined,
153
+ consoleEndpoint: consoleEndpoint?.trim() || undefined,
154
+ consoleTokenFile: consoleTokenFile?.trim() || undefined,
155
+ consoleTokenValue: consoleTokenValue?.trim() || undefined,
156
+ consoleTenant: consoleTenant?.trim() || undefined,
157
+ telemetrySinks,
158
+ packs: flagString(args.flags, "packs"),
159
+ activateKits: runtime === "codex" && parseYesNo(activateAnswer, activateDefault),
160
+ };
161
+ } finally {
162
+ rl.close();
163
+ }
164
+ }
165
+
166
+ function headlessOptions(argv: string[]): InitOptions {
167
+ const args = parseArgs(argv);
168
+ const runtime = normalizeRuntime(flagString(args.flags, "runtime")) ?? "base";
169
+ return {
170
+ runtime,
171
+ dest: path.resolve(flagString(args.flags, "dest", defaultDest(runtime)) ?? defaultDest(runtime)),
172
+ consoleUrl: flagString(args.flags, "console-url"),
173
+ consoleEndpoint: flagString(args.flags, "console-endpoint") ?? flagString(args.flags, "console-endpoint-url"),
174
+ consoleTokenFile: flagString(args.flags, "console-token-file"),
175
+ consoleTenant: flagString(args.flags, "console-tenant") ?? flagString(args.flags, "console-tenant-id"),
176
+ telemetrySinks: telemetrySinksFromFlags(args.flags),
177
+ packs: flagString(args.flags, "packs"),
178
+ activateKits: runtime === "codex" && flagBool(args.flags, "activate-kits"),
179
+ };
180
+ }
181
+
182
+ function ensureBundle(runtime: Runtime): string {
183
+ const bundle = path.join(root, "dist", runtimeBundles[runtime]);
184
+ if (!fs.existsSync(path.join(bundle, "install.sh"))) {
185
+ const rc = buildBundles();
186
+ if (rc !== 0) throw new Error(`bundle build failed with exit code ${rc}`);
187
+ }
188
+ if (!fs.existsSync(path.join(bundle, "install.sh"))) throw new Error(`bundle installer missing: ${bundle}`);
189
+ return bundle;
190
+ }
191
+
192
+ function installBundle(bundle: string, options: InitOptions): number {
193
+ const args = ["install.sh", options.dest];
194
+ for (const sink of options.telemetrySinks) args.push("--telemetry-sink", sink);
195
+ if (options.consoleUrl) args.push("--console-url", options.consoleUrl);
196
+ if (options.consoleEndpoint) args.push("--console-endpoint", options.consoleEndpoint);
197
+ let tempTokenFile: string | undefined;
198
+ const consoleTokenFile = options.consoleTokenFile ?? (() => {
199
+ if (!options.consoleTokenValue) return undefined;
200
+ const file = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "flow-agents-token-")), "console-token");
201
+ fs.writeFileSync(file, options.consoleTokenValue, { encoding: "utf8", mode: 0o600 });
202
+ tempTokenFile = file;
203
+ return file;
204
+ })();
205
+ if (consoleTokenFile) args.push("--console-token-file", consoleTokenFile);
206
+ if (options.consoleTenant) args.push("--console-tenant", options.consoleTenant);
207
+ const env = { ...process.env };
208
+ if (options.packs) env.FLOW_AGENTS_PACKS = options.packs;
209
+ const result = spawnSync("bash", args, { cwd: bundle, env, encoding: "utf8", stdio: "inherit" });
210
+ if (tempTokenFile) fs.rmSync(path.dirname(tempTokenFile), { recursive: true, force: true });
211
+ if (result.error) {
212
+ console.error(`flow-agents init: unable to run bundle installer: ${result.error.message}`);
213
+ return 1;
214
+ }
215
+ return result.status ?? 1;
216
+ }
217
+
218
+ function activateKits(options: InitOptions): number {
219
+ if (!options.activateKits) return 0;
220
+ const result = activateCodexLocal(options.dest, options.dest);
221
+ if (Array.isArray(result.errors) && result.errors.length > 0) {
222
+ console.error(JSON.stringify(result, null, 2));
223
+ return 1;
224
+ }
225
+ const generated = Array.isArray(result.generated_runtime_files) ? result.generated_runtime_files : [];
226
+ console.log(`Activated ${generated.length} Codex local runtime asset(s)`);
227
+ return 0;
228
+ }
229
+
230
+ export async function main(argv = process.argv.slice(2)): Promise<number> {
231
+ if (argv.includes("--help") || argv.includes("-h")) {
232
+ usage();
233
+ return 0;
234
+ }
235
+ const headless = argv.includes("--yes") || argv.includes("--headless") || !process.stdin.isTTY;
236
+ try {
237
+ const options = headless ? headlessOptions(argv) : await interactiveOptions(argv);
238
+ const bundle = ensureBundle(options.runtime);
239
+ const installed = installBundle(bundle, options);
240
+ if (installed !== 0) return installed;
241
+ return activateKits(options);
242
+ } catch (error) {
243
+ console.error(`flow-agents init: ${(error as Error).message}`);
244
+ return 2;
245
+ }
246
+ }
247
+
248
+ if (import.meta.url === `file://${process.argv[1]}`) process.exit(await main());
@@ -0,0 +1,64 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { parseArgs, flagString } from "../lib/args.js";
4
+ import { isoNow, relPath } from "../lib/fs.js";
5
+
6
+ function slugify(value: string): string {
7
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "delivery";
8
+ }
9
+
10
+ function repoRootFor(file: string): string {
11
+ let current = path.dirname(path.resolve(file));
12
+ for (let i = 0; i < 40; i += 1) {
13
+ if (fs.existsSync(path.join(current, ".git")) || fs.existsSync(path.join(current, "AGENTS.md"))) return current;
14
+ const parent = path.dirname(current);
15
+ if (parent === current) break;
16
+ current = parent;
17
+ }
18
+ return process.cwd();
19
+ }
20
+
21
+ function firstHeading(text: string): string {
22
+ return text.split(/\r?\n/).find((line) => line.startsWith("# "))?.slice(2).trim() || "Delivery";
23
+ }
24
+
25
+ function field(text: string, name: string): string {
26
+ return text.match(new RegExp(`^${name}:\\s*(.+)$`, "m"))?.[1].trim() ?? "";
27
+ }
28
+
29
+ function section(text: string, heading: string): string {
30
+ const match = new RegExp(`^##\\s+${heading}\\s*$`, "m").exec(text);
31
+ if (!match) return "";
32
+ const start = match.index + match[0].length;
33
+ const rest = text.slice(start);
34
+ const next = /^##\s+/m.exec(rest);
35
+ return rest.slice(0, next ? next.index : undefined).trim();
36
+ }
37
+
38
+ export function main(argv = process.argv.slice(2)): number {
39
+ const args = parseArgs(argv);
40
+ const artifact = path.resolve(args.positionals[0] ?? "");
41
+ if (!artifact || !fs.existsSync(artifact)) throw new Error(`artifact not found: ${artifact}`);
42
+ const root = repoRootFor(artifact);
43
+ const text = fs.readFileSync(artifact, "utf8");
44
+ const title = flagString(args.flags, "title") ?? firstHeading(text);
45
+ const docsDir = path.resolve(root, flagString(args.flags, "docs-dir", "docs/delivery") ?? "docs/delivery");
46
+ const date = isoNow().slice(0, 10);
47
+ const archiveBase = flagString(args.flags, "archive-dir") ? path.resolve(root, flagString(args.flags, "archive-dir") ?? "") : path.join(path.dirname(artifact), "archive");
48
+ const archive = path.join(archiveBase, date, path.basename(artifact));
49
+ const doc = path.join(docsDir, `${slugify(title)}.md`);
50
+ fs.mkdirSync(path.dirname(archive), { recursive: true });
51
+ fs.mkdirSync(path.dirname(doc), { recursive: true });
52
+ fs.copyFileSync(artifact, archive);
53
+ const pieces = ["---", `title: "${title}"`, `created: ${isoNow()}`, `source_artifact: ${relPath(root, artifact)}`, `archived_artifact: ${relPath(root, archive)}`, `delivery_status: ${field(text, "status") || "unknown"}`, "---", "", `# ${title}`, "", "This document was promoted from a delivery artifact after final acceptance.", "", "## Source", "", `- Working artifact: \`${relPath(root, artifact)}\``, `- Archived artifact: \`${relPath(root, archive)}\``, `- Status at promotion: \`${field(text, "status") || "unknown"}\``, ""];
54
+ for (const heading of ["Definition Of Done", "Plan", "Verification Report", "Goal Fit Gate", "Final Acceptance", "History"]) {
55
+ const body = section(text, heading);
56
+ if (body) pieces.push(`## ${heading}`, "", body, "");
57
+ }
58
+ fs.writeFileSync(doc, `${pieces.join("\n").trimEnd()}\n`, "utf8");
59
+ console.log(`promoted_doc=${doc}`);
60
+ console.log(`archived_artifact=${archive}`);
61
+ return 0;
62
+ }
63
+
64
+ if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
@@ -0,0 +1,143 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { parseArgs, flagString } from "../lib/args.js";
4
+ import { readJson } from "../lib/fs.js";
5
+
6
+ const CLOSING_KEYWORD_RE = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+(?<refs>(?:(?:[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)?#\d+|https:\/\/github\.com\/[^\s)]+\/(?:issues|pull)\/\d+)(?:\s*(?:,|and)\s*(?:(?:[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)?#\d+|https:\/\/github\.com\/[^\s)]+\/(?:issues|pull)\/\d+))*)/gi;
7
+ const GITHUB_REF_RE = /(?<url>https:\/\/github\.com\/(?<url_owner>[^/\s)]+)\/(?<url_repo>[^/\s)]+)\/(?:issues|pull)\/(?<url_number>\d+))|(?:(?<owner>[A-Za-z0-9_.-]+)\/(?<repo>[A-Za-z0-9_.-]+))?#(?<number>\d+)/g;
8
+ const DOC_EXTENSIONS = new Set([".md", ".mdx", ".txt", ".adoc", ".rst"]);
9
+ const PACKAGE_FILES = new Set(["package.json", "package-lock.json", "pnpm-lock.yaml", "yarn.lock", "pyproject.toml", "uv.lock", "poetry.lock", "requirements.txt", "Cargo.toml", "Cargo.lock", "go.mod", "go.sum"]);
10
+
11
+ function loadJson(file: string): Record<string, unknown> {
12
+ return (file === "-" ? JSON.parse(fs.readFileSync(0, "utf8")) : readJson(file)) as Record<string, unknown>;
13
+ }
14
+
15
+ function normalizeRef(ref: string, defaultOwner?: string, defaultRepo?: string): string {
16
+ const matches = Array.from(ref.trim().replace(/[.,]+$/, "").matchAll(GITHUB_REF_RE));
17
+ const match = matches.length === 1 && matches[0][0] === ref.trim().replace(/[.,]+$/, "") ? matches[0] : null;
18
+ if (!match?.groups) throw new Error(`unsupported closing reference: ${ref}`);
19
+ if (match.groups.url) return `github:${match.groups.url_owner}/${match.groups.url_repo}#${Number(match.groups.url_number)}`;
20
+ const owner = match.groups.owner ?? defaultOwner;
21
+ const repo = match.groups.repo ?? defaultRepo;
22
+ if (!owner || !repo) throw new Error(`unqualified reference needs default owner/repo: ${ref}`);
23
+ return `github:${owner}/${repo}#${Number(match.groups.number)}`;
24
+ }
25
+
26
+ function extractClosingRefs(text: string, defaultOwner?: string, defaultRepo?: string): string[] {
27
+ const refs: string[] = [];
28
+ const seen = new Set<string>();
29
+ for (const keyword of text.matchAll(CLOSING_KEYWORD_RE)) {
30
+ for (const ref of String(keyword.groups?.refs ?? "").matchAll(GITHUB_REF_RE)) {
31
+ const normalized = normalizeRef(ref[0], defaultOwner, defaultRepo);
32
+ if (!seen.has(normalized)) {
33
+ seen.add(normalized);
34
+ refs.push(normalized);
35
+ }
36
+ }
37
+ }
38
+ return refs;
39
+ }
40
+
41
+ function renderBody(spec: Record<string, unknown>): string {
42
+ if (typeof spec.body_file === "string") return fs.readFileSync(spec.body_file, "utf8");
43
+ if (spec.body !== undefined) return String(spec.body);
44
+ if (Array.isArray(spec.sections)) {
45
+ return spec.sections.map((section) => {
46
+ const record = section as Record<string, unknown>;
47
+ const title = String(record.title ?? "").trim();
48
+ const body = String(record.body ?? "").trimEnd();
49
+ return body ? `## ${title}\n\n${body}` : `## ${title}`;
50
+ }).join("\n\n").trimEnd() + "\n";
51
+ }
52
+ throw new Error("publish input must include body_file, body, or sections");
53
+ }
54
+
55
+ function render(argv: string[]): number {
56
+ const args = parseArgs(argv);
57
+ const input = flagString(args.flags, "input-json");
58
+ if (!input) throw new Error("--input-json is required");
59
+ const spec = loadJson(input);
60
+ const body = renderBody(spec);
61
+ const bodyOut = flagString(args.flags, "body-out");
62
+ if (bodyOut) fs.writeFileSync(bodyOut, body, "utf8");
63
+ console.log(JSON.stringify({ role: "PublishChangeRequest", provider: spec.provider ?? "github", change_provider: spec.change_provider ?? { kind: spec.provider ?? "github" }, title: spec.title, body, expected_closing_refs: spec.expected_closing_refs ?? [] }, null, 2));
64
+ return 0;
65
+ }
66
+
67
+ function validateClosingRefs(argv: string[]): number {
68
+ const input = flagString(parseArgs(argv).flags, "input-json");
69
+ if (!input) throw new Error("--input-json is required");
70
+ const spec = loadJson(input);
71
+ const defaultOwner = typeof spec.default_owner === "string" ? spec.default_owner : undefined;
72
+ const defaultRepo = typeof spec.default_repo === "string" ? spec.default_repo : undefined;
73
+ const expected = (Array.isArray(spec.expected_closing_refs) ? spec.expected_closing_refs : []).map((ref) => normalizeRef(String(ref), defaultOwner, defaultRepo));
74
+ const provider = (spec.provider_output ?? {}) as Record<string, unknown>;
75
+ const recognized = Array.isArray(provider.recognized_closing_refs)
76
+ ? provider.recognized_closing_refs.map((ref) => normalizeRef(String(ref), defaultOwner, defaultRepo))
77
+ : extractClosingRefs(String(provider.body ?? ""), defaultOwner, defaultRepo);
78
+ const missing = expected.filter((ref) => !recognized.includes(ref));
79
+ console.log(JSON.stringify({ role: "ClosingReferenceCheck", provider: spec.provider ?? "github", status: missing.length ? "fail" : "pass", expected_closing_refs: expected, recognized_closing_refs: recognized, missing_closing_refs: missing }, null, 2));
80
+ if (missing.length) {
81
+ console.error(`missing recognized closing refs: ${missing.join(", ")}`);
82
+ return 2;
83
+ }
84
+ return 0;
85
+ }
86
+
87
+ function riskForPath(value: string): string {
88
+ const parts = new Set(value.split(/[\\/]+/));
89
+ const name = path.basename(value);
90
+ const ext = path.extname(value).toLowerCase();
91
+ if (parts.has("schemas")) return "schema";
92
+ if (parts.has("hooks")) return "hook";
93
+ if (parts.has("scripts")) return "runtime";
94
+ if (PACKAGE_FILES.has(name)) return "package";
95
+ if (parts.has("security") || name.toLowerCase().startsWith("security")) return "security";
96
+ if (parts.has("docs") || DOC_EXTENSIONS.has(ext)) return "docs";
97
+ return "runtime";
98
+ }
99
+
100
+ function evaluateProviderChecks(argv: string[]): number {
101
+ const args = parseArgs(argv);
102
+ const filesDoc = loadJson(flagString(args.flags, "change-files-json") ?? "");
103
+ const checksPath = flagString(args.flags, "provider-checks-json");
104
+ const checks = checksPath ? loadJson(checksPath) : [];
105
+ const files = Array.isArray(filesDoc) ? filesDoc : (filesDoc.files as unknown[] ?? []);
106
+ const risks = Array.from(new Set(files.map((file) => riskForPath(String(file))))).sort();
107
+ const checksPresent = Array.isArray(checks) ? checks.length > 0 : Object.keys(checks).length > 0;
108
+ const risky = risks.some((risk) => ["runtime", "schema", "package", "hook", "security"].includes(risk));
109
+ const status = checksPresent ? "pass" : risky ? "not_verified" : "skip";
110
+ const release = checksPresent ? "pass" : risky ? "hold" : "not_required";
111
+ console.log(JSON.stringify({ role: "ProviderCheckPolicy", risk_classes: risks.length ? risks : ["unknown"], provider_checks_present: checksPresent, evidence_status: status, release_gate_status: release, summary: checksPresent ? "Provider checks are present." : risky ? "Missing provider checks for risky change classes." : "Provider checks skipped for docs-only change." }, null, 2));
112
+ return status === "not_verified" ? 3 : 0;
113
+ }
114
+
115
+ function reconcile(argv: string[]): number {
116
+ const root = argv[0];
117
+ if (!root) throw new Error("artifact_root is required");
118
+ const evidence = readJson(path.join(root, "evidence.json")) as Record<string, unknown>;
119
+ const release = readJson(path.join(root, "release.json")) as Record<string, unknown>;
120
+ const mismatches: string[] = [];
121
+ if (evidence.verdict !== "pass") mismatches.push("evidence verdict is not pass");
122
+ const gates = Array.isArray(release.gates) ? release.gates as Record<string, unknown>[] : [];
123
+ if (["merge", "release", "deploy"].includes(String(release.decision)) && gates.filter((gate) => gate.required !== false).some((gate) => gate.status !== "pass")) mismatches.push("positive release decision has non-pass required gate");
124
+ console.log(JSON.stringify({ role: "FinalStateReconciliation", status: mismatches.length ? "fail" : "pass", authoritative_refs: [path.join(root, "evidence.json"), path.join(root, "release.json")], mismatches }, null, 2));
125
+ return mismatches.length ? 4 : 0;
126
+ }
127
+
128
+ export function main(argv = process.argv.slice(2)): number {
129
+ try {
130
+ const [command, ...rest] = argv;
131
+ if (command === "render") return render(rest);
132
+ if (command === "validate-closing-refs") return validateClosingRefs(rest);
133
+ if (command === "evaluate-provider-checks") return evaluateProviderChecks(rest);
134
+ if (command === "reconcile-final-state") return reconcile(rest);
135
+ console.error("usage: publish-change-helper <render|validate-closing-refs|evaluate-provider-checks|reconcile-final-state>");
136
+ return 2;
137
+ } catch (error) {
138
+ console.error(`publish-change-helper: ${(error as Error).message}`);
139
+ return 1;
140
+ }
141
+ }
142
+
143
+ if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());