harness-everything 0.3.6 → 0.4.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 (580) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +8 -7
  4. package/.github/workflows/behavioral-evals.yml +3 -3
  5. package/.github/workflows/ci.yml +49 -28
  6. package/.github/workflows/release.yml +52 -27
  7. package/.nvmrc +1 -0
  8. package/.releaserc.json +113 -0
  9. package/AGENTS.md +44 -24
  10. package/BENCHMARK_SOP.md +38 -18
  11. package/CHANGELOG.md +196 -3
  12. package/CONTRIBUTING.md +37 -9
  13. package/Dockerfile +1 -1
  14. package/PRIVACY.md +25 -0
  15. package/README.md +126 -91
  16. package/RELEASING.md +93 -0
  17. package/SUPPORT.md +27 -0
  18. package/TERMS.md +21 -0
  19. package/VERIFICATION.md +192 -284
  20. package/behavioral-evals/README.md +21 -0
  21. package/behavioral-evals/case-validator.js +194 -0
  22. package/behavioral-evals/cases/baseline-environment-detection.yaml +21 -0
  23. package/behavioral-evals/cases/baseline-eval-harness.yaml +27 -0
  24. package/behavioral-evals/cases/baseline-fable-discipline.yaml +31 -0
  25. package/behavioral-evals/cases/baseline-find-skills-exposure.yaml +49 -0
  26. package/behavioral-evals/cases/baseline-find-skills.yaml +21 -0
  27. package/behavioral-evals/cases/baseline-git-commit.yaml +2 -2
  28. package/behavioral-evals/cases/baseline-install-cognitive-os.yaml +24 -0
  29. package/behavioral-evals/cases/baseline-multi-agent-workspace.yaml +28 -0
  30. package/behavioral-evals/cases/baseline-rewrite-commits.yaml +34 -0
  31. package/behavioral-evals/cases/baseline-self-evolve.yaml +31 -0
  32. package/behavioral-evals/cases/baseline-skill-creator.yaml +20 -0
  33. package/behavioral-evals/cases/baseline-skill-style.yaml +21 -0
  34. package/behavioral-evals/cases/baseline-to-spec.yaml +34 -0
  35. package/behavioral-evals/cases/baseline-to-tickets.yaml +24 -0
  36. package/behavioral-evals/cases/baseline-todo-driven-workflow.yaml +32 -0
  37. package/behavioral-evals/cases/baseline-using-git-worktrees.yaml +15 -0
  38. package/behavioral-evals/cases/breaker-zoom-out-after-3.yaml +2 -2
  39. package/behavioral-evals/cases/pressure-complexity-skip.yaml +2 -2
  40. package/behavioral-evals/cases/pressure-scope-bypass.yaml +7 -2
  41. package/behavioral-evals/cases/pressure-sunk-cost-retry.yaml +7 -4
  42. package/behavioral-evals/cases/scope-discipline.yaml +2 -1
  43. package/behavioral-evals/cases/verify-before-done.yaml +7 -5
  44. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/case.yaml +31 -0
  45. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/historical-case.yaml +31 -0
  46. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/provenance.json +42 -0
  47. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/result.sanitized.json +20 -0
  48. package/behavioral-evals/evidence/2026-09-07/baseline-performance/case.yaml +34 -0
  49. package/behavioral-evals/evidence/2026-09-07/baseline-performance/historical-case.yaml +34 -0
  50. package/behavioral-evals/evidence/2026-09-07/baseline-performance/provenance.json +42 -0
  51. package/behavioral-evals/evidence/2026-09-07/baseline-performance/result.sanitized.json +20 -0
  52. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/case.yaml +28 -0
  53. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/historical-case.yaml +28 -0
  54. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/provenance.json +42 -0
  55. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/result.sanitized.json +20 -0
  56. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/case.yaml +33 -0
  57. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/historical-case.yaml +33 -0
  58. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/provenance.json +42 -0
  59. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/result.sanitized.json +20 -0
  60. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/case.yaml +28 -0
  61. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/historical-case.yaml +18 -0
  62. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/provenance.json +30 -0
  63. package/behavioral-evals/evidence/2026-09-07/live-run-blocker.md +16 -0
  64. package/behavioral-evals/evidence/2026-09-07/manifest.json +88 -0
  65. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/case.yaml +33 -0
  66. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/historical-case.yaml +28 -0
  67. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/provenance.json +30 -0
  68. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/case.yaml +50 -0
  69. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/historical-case.yaml +50 -0
  70. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/provenance.json +42 -0
  71. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/result.sanitized.json +20 -0
  72. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/case.yaml +35 -0
  73. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/historical-case.yaml +35 -0
  74. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/provenance.json +42 -0
  75. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/result.sanitized.json +20 -0
  76. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/case.yaml +43 -0
  77. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/historical-case.yaml +43 -0
  78. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/provenance.json +42 -0
  79. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/result.sanitized.json +24 -0
  80. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/case.yaml +43 -0
  81. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/historical-case.yaml +43 -0
  82. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/provenance.json +42 -0
  83. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/result.sanitized.json +20 -0
  84. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/case.yaml +43 -0
  85. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/historical-case.yaml +43 -0
  86. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/provenance.json +42 -0
  87. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/result.sanitized.json +24 -0
  88. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/case.yaml +50 -0
  89. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/historical-case.yaml +47 -0
  90. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/provenance.json +42 -0
  91. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/result.sanitized.json +24 -0
  92. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/case.yaml +50 -0
  93. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/historical-case.yaml +47 -0
  94. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/provenance.json +42 -0
  95. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/result.sanitized.json +20 -0
  96. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/case.yaml +50 -0
  97. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/historical-case.yaml +47 -0
  98. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/provenance.json +42 -0
  99. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/result.sanitized.json +24 -0
  100. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/case.yaml +30 -0
  101. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/historical-case.yaml +23 -0
  102. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/provenance.json +30 -0
  103. package/behavioral-evals/evidence/2026-09-07/triage-matrix.json +426 -0
  104. package/behavioral-evals/evidence/2026-09-07/triage-matrix.md +24 -0
  105. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/case.yaml +19 -0
  106. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/historical-case.yaml +18 -0
  107. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/provenance.json +30 -0
  108. package/behavioral-evals/evidence/2026-09-07/verify-before-done/case.yaml +33 -0
  109. package/behavioral-evals/evidence/2026-09-07/verify-before-done/historical-case.yaml +31 -0
  110. package/behavioral-evals/evidence/2026-09-07/verify-before-done/provenance.json +42 -0
  111. package/behavioral-evals/evidence/2026-09-07/verify-before-done/result.sanitized.json +20 -0
  112. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/case.yaml +33 -0
  113. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/historical-case.yaml +31 -0
  114. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/provenance.json +42 -0
  115. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/result.sanitized.json +20 -0
  116. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/case.yaml +33 -0
  117. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/historical-case.yaml +31 -0
  118. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/provenance.json +42 -0
  119. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/result.sanitized.json +20 -0
  120. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/case.yaml +33 -0
  121. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/historical-case.yaml +33 -0
  122. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/provenance.json +42 -0
  123. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/result.sanitized.json +480 -0
  124. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/transcript.sanitized.jsonl +95 -0
  125. package/behavioral-evals/evidence-tool.js +443 -0
  126. package/behavioral-evals/fixtures/claude-denied.jsonl +3 -0
  127. package/behavioral-evals/fixtures/claude-legacy.json +1 -0
  128. package/behavioral-evals/fixtures/claude-oral-only.jsonl +2 -0
  129. package/behavioral-evals/fixtures/claude-success.jsonl +5 -0
  130. package/behavioral-evals/fixtures/claude-truncated.jsonl +3 -0
  131. package/behavioral-evals/fixtures/opencode-success.jsonl +6 -0
  132. package/behavioral-evals/results/2026-08-31-baseline-add-feature.json +20 -0
  133. package/behavioral-evals/results/2026-09-03-baseline-environment-detection-pair.json +133 -0
  134. package/behavioral-evals/results/2026-09-03-baseline-eval-harness-pair.json +141 -0
  135. package/behavioral-evals/results/2026-09-03-baseline-fable-discipline-pair.json +149 -0
  136. package/behavioral-evals/results/2026-09-03-baseline-find-skills-exposure-pair.json +141 -0
  137. package/behavioral-evals/results/2026-09-03-baseline-find-skills-pair.json +141 -0
  138. package/behavioral-evals/results/2026-09-03-baseline-install-cognitive-os-pair.json +133 -0
  139. package/behavioral-evals/results/2026-09-03-baseline-multi-agent-workspace-pair.json +141 -0
  140. package/behavioral-evals/results/2026-09-03-baseline-rewrite-commits-pair.json +95 -0
  141. package/behavioral-evals/results/2026-09-03-baseline-self-evolve-pair.json +141 -0
  142. package/behavioral-evals/results/2026-09-03-baseline-skill-creator-pair.json +141 -0
  143. package/behavioral-evals/results/2026-09-03-baseline-skill-style-pair.json +133 -0
  144. package/behavioral-evals/results/2026-09-03-baseline-to-spec-pair.json +133 -0
  145. package/behavioral-evals/results/2026-09-03-baseline-to-tickets-pair.json +141 -0
  146. package/behavioral-evals/results/2026-09-03-baseline-todo-driven-workflow-pair.json +141 -0
  147. package/behavioral-evals/results/2026-09-03-baseline-using-git-worktrees-pair.json +133 -0
  148. package/behavioral-evals/results/2026-09-03-summary-both.json +41 -0
  149. package/behavioral-evals/results/2026-09-04-baseline-find-skills-pair.json +141 -0
  150. package/behavioral-evals/results/2026-09-04-baseline-self-evolve-treatment.json +80 -0
  151. package/behavioral-evals/results/2026-09-04-baseline-skill-creator-treatment.json +80 -0
  152. package/behavioral-evals/results/2026-09-04-summary-both.json +41 -0
  153. package/behavioral-evals/run-with-plugin.js +15 -31
  154. package/behavioral-evals/run.js +446 -105
  155. package/behavioral-evals/transcript-parser.js +591 -0
  156. package/bin/cli.js +24 -12
  157. package/ci/ab-test-cases/grill-me-adversarial.yaml +14 -4
  158. package/ci/ab-test-cases/tdd-test-first.yaml +13 -6
  159. package/ci/ab-test-cases/verification-loop-gates.yaml +20 -7
  160. package/ci/ab-test-cases/verify-before-claim-cites.yaml +7 -6
  161. package/ci/ab-test-harness.js +113 -38
  162. package/ci/action-gate-platform-doc.test.js +31 -0
  163. package/ci/action-gate.test.js +260 -0
  164. package/ci/cases/case2.json +2 -2
  165. package/ci/consistency-check.js +51 -5
  166. package/ci/description-collision.js +15 -6
  167. package/ci/disclosure-check.js +225 -0
  168. package/ci/doc-capability-consistency.test.js +180 -0
  169. package/ci/fixtures/phase4/parallel-disjoint.stages.json +32 -0
  170. package/ci/fixtures/phase4/parallel-read-only.stages.json +32 -0
  171. package/ci/installer-roundtrip.test.js +159 -0
  172. package/ci/invariant-routing.test.js +74 -0
  173. package/ci/issue99-runtime.test.js +218 -0
  174. package/ci/mechanism-2aa-codex-action-gate-policy.test.js +117 -0
  175. package/ci/mechanism-2ab-openai-plugin-sync-integrity.test.js +80 -0
  176. package/ci/mechanism-2j-behavioral-runner.test.js +43 -1
  177. package/ci/mechanism-2k-reference-check.test.js +57 -2
  178. package/ci/mechanism-2l-multi-agent-workspace.test.js +202 -6
  179. package/ci/mechanism-2m-self-repo-guard.test.js +65 -0
  180. package/ci/mechanism-2n-opencode-plugin.test.js +461 -0
  181. package/ci/mechanism-2o-state-home-isolation.test.js +183 -0
  182. package/ci/mechanism-2p-installer-links.test.js +183 -0
  183. package/ci/mechanism-2q-installer-global-shared-store.test.js +132 -0
  184. package/ci/mechanism-2r-uninstall-flags.test.js +148 -0
  185. package/ci/mechanism-2s-tdd-quality.test.js +203 -0
  186. package/ci/mechanism-2t-disclosure.test.js +90 -0
  187. package/ci/mechanism-2t-evidence-triage.test.js +200 -0
  188. package/ci/mechanism-2t-issue-20.test.js +75 -0
  189. package/ci/mechanism-2t-platform-skill-targets.test.js +164 -0
  190. package/ci/mechanism-2t-transcript-parser.test.js +179 -0
  191. package/ci/mechanism-2t-workspace-identity.test.js +200 -0
  192. package/ci/mechanism-2u-issue-42-regressions.test.js +239 -0
  193. package/ci/mechanism-2u-issue-44.test.js +35 -0
  194. package/ci/mechanism-2v-verifier-boundaries.test.js +138 -0
  195. package/ci/mechanism-2w-platform-compatibility.test.js +148 -0
  196. package/ci/mechanism-2x-release-automation.test.js +157 -0
  197. package/ci/mechanism-2x-release-commit-message.test.js +66 -0
  198. package/ci/mechanism-2y-release-tooling-compat.test.js +47 -0
  199. package/ci/mechanism-2z-claude-plugin-manifest.test.js +29 -0
  200. package/ci/mutation-check.js +53 -0
  201. package/ci/mutation-loader.js +57 -0
  202. package/ci/negative-controls.js +76 -46
  203. package/ci/openai-plugin-package.test.js +182 -0
  204. package/ci/openai-plugin-runtime.test.js +175 -0
  205. package/ci/openai-plugin-submission.test.js +101 -0
  206. package/ci/phase4-ensemble-memory.test.js +307 -0
  207. package/ci/reference-check.js +73 -25
  208. package/ci/release-consistency-check.js +24 -1
  209. package/ci/repository-contract.test.js +17 -0
  210. package/ci/router-phase2-safety.test.js +81 -0
  211. package/ci/router-workflow-plan.test.js +264 -0
  212. package/ci/routing-check.js +6 -5
  213. package/ci/runner.js +6 -5
  214. package/ci/skill-routing-check.js +48 -11
  215. package/ci/test-behavioral-case-validation.js +62 -0
  216. package/ci/test-helper.js +10 -0
  217. package/ci/workflow-plan-consumers-edge.test.js +72 -0
  218. package/ci/workflow-plan-consumers.test.js +276 -0
  219. package/docs/architecture.md +137 -57
  220. package/docs/audit.md +22 -20
  221. package/docs/codex-action-gate.md +90 -0
  222. package/docs/issue-20-rollup.md +47 -0
  223. package/docs/mechanism-first-skill-mesh.md +22 -20
  224. package/docs/openai-plugin.md +118 -0
  225. package/docs/philosophy.md +28 -17
  226. package/docs/platform-capabilities.md +73 -0
  227. package/docs/platform-compatibility.json +270 -0
  228. package/docs/reflection.md +37 -22
  229. package/docs/release-evidence.md +27 -0
  230. package/docs/repository-contract.md +27 -0
  231. package/docs/routing.md +157 -44
  232. package/docs/security-audit.md +38 -0
  233. package/docs/troubleshooting.md +94 -51
  234. package/docs/verifier-boundaries.md +45 -0
  235. package/docs/workflows/fable-mode.md +77 -21
  236. package/docs/workflows/find-skills.md +40 -0
  237. package/docs/workflows/grill-with-docs.md +2 -2
  238. package/docs/workflows/multi-agent-workspace.md +22 -10
  239. package/docs/workflows/self-evolve.md +33 -0
  240. package/docs/workflows/tdd.md +36 -0
  241. package/docs/workflows/todo-driven-workflow.md +33 -0
  242. package/environment-detection/SKILL.md +3 -3
  243. package/eval-harness/SKILL.md +7 -7
  244. package/eval-harness/scripts/evaluate.js +12 -10
  245. package/evals/evaluation-reports.md +14 -0
  246. package/evals/harness-everything/tasks/positive-tier1.yaml +1 -1
  247. package/evals/harness-everything/tasks/positive-tier2.yaml +1 -1
  248. package/evals/harness-everything/tasks/positive-tier3.yaml +1 -1
  249. package/evals/install-cognitive-os/tasks/positive-trigger.yaml +1 -1
  250. package/fable-discipline/SKILL.md +2 -2
  251. package/fable-mode/CONTRACT-FORMAT.md +147 -33
  252. package/fable-mode/SKILL.md +3 -3
  253. package/fable-mode/agents/fable-orchestrator.md +95 -35
  254. package/fable-mode/execution-guardrails/SKILL.md +2 -2
  255. package/fable-mode/fable-haiku/SKILL.md +3 -3
  256. package/fable-mode/fable-opus/SKILL.md +3 -3
  257. package/fable-mode/fable-sonnet/SKILL.md +3 -3
  258. package/fable-mode/scripts/ensemble-review.js +371 -0
  259. package/fable-mode/scripts/model-selector.js +134 -3
  260. package/fable-mode/scripts/workflow-plan-consumer.js +337 -0
  261. package/find-skills/SKILL.md +5 -5
  262. package/find-skills/references/discovery-flow.md +1 -1
  263. package/find-skills/scripts/use-skill.js +7 -1
  264. package/git-commit/SKILL.md +4 -11
  265. package/grill-me/SKILL.md +5 -5
  266. package/grill-with-docs/SKILL.md +7 -7
  267. package/grill-with-docs/references/session-playbook.md +6 -4
  268. package/harness-everything/SKILL.md +23 -22
  269. package/harness-everything/references/router-workflow-plan.md +128 -0
  270. package/harness-everything/references/triage-and-tiers.md +173 -96
  271. package/harness-everything/schemas/router-task-shape.schema.json +126 -0
  272. package/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
  273. package/harness-everything/scripts/bootstrap.js +13 -4
  274. package/harness-everything/scripts/ensemble-policy.js +102 -0
  275. package/harness-everything/scripts/kernel-router.js +212 -0
  276. package/harness-everything/scripts/router-contract.js +612 -0
  277. package/harness-everything/scripts/self-heal.js +29 -20
  278. package/harness-everything/scripts/tier-router.js +346 -221
  279. package/hooks/hooks.json +60 -15
  280. package/hooks/scripts/action-gate-rules.json +77 -0
  281. package/hooks/scripts/action-gate.js +528 -0
  282. package/hooks/scripts/atomic-commit-check.js +5 -5
  283. package/hooks/scripts/codex-action-gate-post.js +46 -0
  284. package/hooks/scripts/codex-permission-request.js +140 -0
  285. package/hooks/scripts/context-compact.js +4 -3
  286. package/hooks/scripts/contract-test.js +118 -51
  287. package/hooks/scripts/lib/fable-contracts.js +121 -0
  288. package/hooks/scripts/lib/harness-state.js +164 -28
  289. package/hooks/scripts/lib/platforms/claude.js +45 -62
  290. package/hooks/scripts/lib/platforms/codex.js +35 -61
  291. package/hooks/scripts/lib/platforms/continue.js +7 -7
  292. package/hooks/scripts/lib/platforms/copilot.js +29 -53
  293. package/hooks/scripts/lib/platforms/hermes.js +71 -20
  294. package/hooks/scripts/openai-session-start.js +81 -0
  295. package/hooks/scripts/rule-of-3-tracker.js +9 -8
  296. package/hooks/scripts/rule-of-3.js +29 -21
  297. package/hooks/scripts/state-persist.js +5 -4
  298. package/hooks/scripts/stop-gate.js +2 -2
  299. package/hooks/scripts/subagent-scope-guard.js +144 -38
  300. package/hooks/scripts/subagent-start.js +19 -0
  301. package/hooks/scripts/subagent-stop.js +6 -0
  302. package/improve-codebase-architecture/SKILL.md +2 -4
  303. package/improve-codebase-architecture/references/README.md +16 -0
  304. package/install-cognitive-os/SKILL.md +28 -22
  305. package/multi-agent-workspace/SKILL.md +16 -15
  306. package/multi-agent-workspace/references/architecture-guide.md +13 -9
  307. package/multi-agent-workspace/references/orchestration.md +39 -22
  308. package/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
  309. package/multi-agent-workspace/scripts/index_memory.js +79 -26
  310. package/multi-agent-workspace/scripts/path-boundary.js +59 -0
  311. package/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
  312. package/multi-agent-workspace/scripts/scaffold.js +258 -103
  313. package/multi-agent-workspace/templates/AGENTS.md +20 -0
  314. package/multi-agent-workspace/workflows/03-generation.md +8 -10
  315. package/multi-agent-workspace/workflows/04-launcher.md +5 -5
  316. package/opencode-plugin/README.md +114 -71
  317. package/opencode-plugin/hooks/verify.js +62 -12
  318. package/opencode-plugin/index.mjs +547 -0
  319. package/opencode-plugin/plugin.json +4 -12
  320. package/package.json +20 -4
  321. package/plugins/harness-everything/.codex-plugin/plugin.json +39 -0
  322. package/plugins/harness-everything/hooks/hooks.json +197 -0
  323. package/plugins/harness-everything/hooks/scripts/action-gate-rules.json +77 -0
  324. package/plugins/harness-everything/hooks/scripts/action-gate.js +528 -0
  325. package/plugins/harness-everything/hooks/scripts/atomic-commit-check.js +68 -0
  326. package/plugins/harness-everything/hooks/scripts/boundary-guard.js +55 -0
  327. package/plugins/harness-everything/hooks/scripts/codex-action-gate-post.js +46 -0
  328. package/plugins/harness-everything/hooks/scripts/codex-permission-request.js +140 -0
  329. package/plugins/harness-everything/hooks/scripts/context-compact.js +115 -0
  330. package/plugins/harness-everything/hooks/scripts/contract-test.js +146 -0
  331. package/plugins/harness-everything/hooks/scripts/depth-guard.js +65 -0
  332. package/plugins/harness-everything/hooks/scripts/lib/fable-contracts.js +121 -0
  333. package/plugins/harness-everything/hooks/scripts/lib/harness-state.js +275 -0
  334. package/plugins/harness-everything/hooks/scripts/lib/platforms/claude.js +168 -0
  335. package/plugins/harness-everything/hooks/scripts/lib/platforms/codex.js +88 -0
  336. package/plugins/harness-everything/hooks/scripts/lib/platforms/continue.js +91 -0
  337. package/plugins/harness-everything/hooks/scripts/lib/platforms/copilot.js +85 -0
  338. package/plugins/harness-everything/hooks/scripts/lib/platforms/cursor.js +89 -0
  339. package/plugins/harness-everything/hooks/scripts/lib/platforms/hermes.js +108 -0
  340. package/plugins/harness-everything/hooks/scripts/lib/platforms/index.js +17 -0
  341. package/plugins/harness-everything/hooks/scripts/lib/platforms/worktrees.js +20 -0
  342. package/plugins/harness-everything/hooks/scripts/lib/workspace.js +290 -0
  343. package/plugins/harness-everything/hooks/scripts/openai-session-start.js +81 -0
  344. package/plugins/harness-everything/hooks/scripts/reset-circuit-breaker.js +30 -0
  345. package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +125 -0
  346. package/plugins/harness-everything/hooks/scripts/rule-of-3.js +195 -0
  347. package/plugins/harness-everything/hooks/scripts/state-persist.js +100 -0
  348. package/plugins/harness-everything/hooks/scripts/stop-gate.js +80 -0
  349. package/plugins/harness-everything/hooks/scripts/subagent-scope-guard.js +194 -0
  350. package/plugins/harness-everything/hooks/scripts/subagent-start.js +19 -0
  351. package/plugins/harness-everything/hooks/scripts/subagent-stop.js +6 -0
  352. package/plugins/harness-everything/hooks/session-start.js +81 -0
  353. package/plugins/harness-everything/plugin.json +43 -0
  354. package/plugins/harness-everything/scripts/lib/advisory-text.js +174 -0
  355. package/plugins/harness-everything/skills/environment-detection/SKILL.md +41 -0
  356. package/plugins/harness-everything/skills/environment-detection/references/shell-syntax-rules.md +76 -0
  357. package/plugins/harness-everything/skills/environment-detection/scripts/preflight.js +103 -0
  358. package/plugins/harness-everything/skills/eval-harness/SKILL.md +42 -0
  359. package/plugins/harness-everything/skills/eval-harness/references/scoring-rubric.md +68 -0
  360. package/plugins/harness-everything/skills/eval-harness/scripts/evaluate.js +79 -0
  361. package/plugins/harness-everything/skills/fable-discipline/SKILL.md +41 -0
  362. package/plugins/harness-everything/skills/fable-discipline/references/discipline-rules.md +22 -0
  363. package/plugins/harness-everything/skills/fable-mode/CONTRACT-FORMAT.md +165 -0
  364. package/plugins/harness-everything/skills/fable-mode/SKILL.md +39 -0
  365. package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +159 -0
  366. package/plugins/harness-everything/skills/fable-mode/agents/fable-verifier.md +32 -0
  367. package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-haiku.md +52 -0
  368. package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-sonnet.md +53 -0
  369. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +43 -0
  370. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/references/guardrail-rules.md +56 -0
  371. package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +36 -0
  372. package/plugins/harness-everything/skills/fable-mode/fable-haiku/references/routing-notes.md +26 -0
  373. package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +36 -0
  374. package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +36 -0
  375. package/plugins/harness-everything/skills/fable-mode/model-matrix.json +32 -0
  376. package/plugins/harness-everything/skills/fable-mode/references/execution-phases.md +37 -0
  377. package/plugins/harness-everything/skills/fable-mode/references/model-matrix.md +39 -0
  378. package/plugins/harness-everything/skills/fable-mode/scripts/ensemble-review.js +371 -0
  379. package/plugins/harness-everything/skills/fable-mode/scripts/model-selector.js +260 -0
  380. package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +337 -0
  381. package/plugins/harness-everything/skills/find-skills/SKILL.md +48 -0
  382. package/plugins/harness-everything/skills/find-skills/references/discovery-flow.md +102 -0
  383. package/plugins/harness-everything/skills/find-skills/scripts/use-skill.js +112 -0
  384. package/plugins/harness-everything/skills/git-commit/SKILL.md +38 -0
  385. package/plugins/harness-everything/skills/git-commit/guides/ANGULAR_STYLE.md +61 -0
  386. package/plugins/harness-everything/skills/git-commit/guides/COMMIT_GENERATION.md +24 -0
  387. package/plugins/harness-everything/skills/git-commit/guides/LANGUAGE_DETECTION.md +16 -0
  388. package/plugins/harness-everything/skills/git-commit/guides/MAIN_REPO.md +15 -0
  389. package/plugins/harness-everything/skills/git-commit/guides/SUBMODULES.md +27 -0
  390. package/plugins/harness-everything/skills/git-commit/references/commit-flow.md +30 -0
  391. package/plugins/harness-everything/skills/grill-me/SKILL.md +43 -0
  392. package/plugins/harness-everything/skills/grill-me/references/grilling-playbook.md +38 -0
  393. package/plugins/harness-everything/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  394. package/plugins/harness-everything/skills/grill-with-docs/CONTEXT-FORMAT.md +63 -0
  395. package/plugins/harness-everything/skills/grill-with-docs/SKILL.md +41 -0
  396. package/plugins/harness-everything/skills/grill-with-docs/references/session-playbook.md +99 -0
  397. package/plugins/harness-everything/skills/harness-everything/SKILL.md +43 -0
  398. package/plugins/harness-everything/skills/harness-everything/examples/README.md +9 -0
  399. package/plugins/harness-everything/skills/harness-everything/examples/todo-workflow.md +22 -0
  400. package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +128 -0
  401. package/plugins/harness-everything/skills/harness-everything/references/skill-registry.md +39 -0
  402. package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +193 -0
  403. package/plugins/harness-everything/skills/harness-everything/schemas/router-task-shape.schema.json +126 -0
  404. package/plugins/harness-everything/skills/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
  405. package/plugins/harness-everything/skills/harness-everything/scripts/bootstrap.js +212 -0
  406. package/plugins/harness-everything/skills/harness-everything/scripts/ensemble-policy.js +102 -0
  407. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +212 -0
  408. package/plugins/harness-everything/skills/harness-everything/scripts/router-contract.js +612 -0
  409. package/plugins/harness-everything/skills/harness-everything/scripts/routing-keywords.json +320 -0
  410. package/plugins/harness-everything/skills/harness-everything/scripts/self-heal.js +250 -0
  411. package/plugins/harness-everything/skills/harness-everything/scripts/tier-router.js +459 -0
  412. package/plugins/harness-everything/skills/harness-everything/scripts/verify-gate.js +100 -0
  413. package/plugins/harness-everything/skills/improve-codebase-architecture/SKILL.md +38 -0
  414. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/DEEPENING.md +37 -0
  415. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/HTML-REPORT.md +123 -0
  416. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/INTERFACE-DESIGN.md +44 -0
  417. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/LANGUAGE.md +53 -0
  418. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/refactoring-workflow.md +59 -0
  419. package/plugins/harness-everything/skills/improve-codebase-architecture/references/README.md +16 -0
  420. package/plugins/harness-everything/skills/install-cognitive-os/SKILL.md +44 -0
  421. package/plugins/harness-everything/skills/install-cognitive-os/references/cognitive-loop.md +27 -0
  422. package/plugins/harness-everything/skills/multi-agent-workspace/NOTICE-agency-agents.md +27 -0
  423. package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +38 -0
  424. package/plugins/harness-everything/skills/multi-agent-workspace/examples/csharp-monorepo.md +123 -0
  425. package/plugins/harness-everything/skills/multi-agent-workspace/examples/typescript-cli.md +126 -0
  426. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-claude.md +77 -0
  427. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-codex.md +146 -0
  428. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-continue.md +38 -0
  429. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-copilot.md +74 -0
  430. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-cursor.md +40 -0
  431. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-hermes.md +38 -0
  432. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/role-capabilities.md +108 -0
  433. package/plugins/harness-everything/skills/multi-agent-workspace/references/agency-agents.md +31 -0
  434. package/plugins/harness-everything/skills/multi-agent-workspace/references/architecture-guide.md +36 -0
  435. package/plugins/harness-everything/skills/multi-agent-workspace/references/orchestration.md +65 -0
  436. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/agency-catalog.js +190 -0
  437. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
  438. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/index_memory.js +104 -0
  439. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/path-boundary.js +59 -0
  440. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
  441. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/scaffold.js +408 -0
  442. package/plugins/harness-everything/skills/multi-agent-workspace/templates/AGENTS.md +20 -0
  443. package/plugins/harness-everything/skills/multi-agent-workspace/templates/README.md +17 -0
  444. package/plugins/harness-everything/skills/multi-agent-workspace/templates/agent-launcher.md +68 -0
  445. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-csharp.md +56 -0
  446. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-polyglot.md +62 -0
  447. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-ts.md +57 -0
  448. package/plugins/harness-everything/skills/multi-agent-workspace/templates/memory-keeper.md +37 -0
  449. package/plugins/harness-everything/skills/multi-agent-workspace/templates/requirement-analyzer.md +66 -0
  450. package/plugins/harness-everything/skills/multi-agent-workspace/templates/specialist-agent.md +34 -0
  451. package/plugins/harness-everything/skills/multi-agent-workspace/templates/task-verifier.md +56 -0
  452. package/plugins/harness-everything/skills/multi-agent-workspace/templates/tool-maker.md +33 -0
  453. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/01-init.md +22 -0
  454. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/02-analysis.md +23 -0
  455. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/03-generation.md +25 -0
  456. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/04-launcher.md +16 -0
  457. package/plugins/harness-everything/skills/repo-docs/SKILL.md +42 -0
  458. package/plugins/harness-everything/skills/repo-docs/references/process-guide.md +60 -0
  459. package/plugins/harness-everything/skills/repo-docs/templates/agents-template.md +264 -0
  460. package/plugins/harness-everything/skills/repo-docs/templates/knowledge-agents-template.md +50 -0
  461. package/plugins/harness-everything/skills/repo-docs/templates/knowledge-readme-template.md +83 -0
  462. package/plugins/harness-everything/skills/repo-docs/templates/manual-recon.md +117 -0
  463. package/plugins/harness-everything/skills/repo-docs/templates/multi-skills-readme-template.md +72 -0
  464. package/plugins/harness-everything/skills/repo-docs/templates/product-agents-template.md +78 -0
  465. package/plugins/harness-everything/skills/repo-docs/templates/product-readme-template.md +95 -0
  466. package/plugins/harness-everything/skills/repo-docs/templates/readme-template.md +136 -0
  467. package/plugins/harness-everything/skills/repo-docs/templates/single-skill-readme-template.md +70 -0
  468. package/plugins/harness-everything/skills/repo-docs/templates/skills-agents-template.md +60 -0
  469. package/plugins/harness-everything/skills/rewrite-commits/SKILL.md +37 -0
  470. package/plugins/harness-everything/skills/rewrite-commits/references/workflow.md +18 -0
  471. package/plugins/harness-everything/skills/security-review/SKILL.md +47 -0
  472. package/plugins/harness-everything/skills/security-review/guides/OWASP-PATTERNS.md +31 -0
  473. package/plugins/harness-everything/skills/security-review/guides/STRIDE-THREAT-MODEL.md +21 -0
  474. package/plugins/harness-everything/skills/security-review/references/security-checklist.md +478 -0
  475. package/plugins/harness-everything/skills/security-review/scripts/audit-secrets.js +85 -0
  476. package/plugins/harness-everything/skills/self-evolve/SKILL.md +45 -0
  477. package/plugins/harness-everything/skills/self-evolve/references/memory-resolution.md +61 -0
  478. package/plugins/harness-everything/skills/self-evolve/scripts/persist-memory.js +272 -0
  479. package/plugins/harness-everything/skills/self-evolve/scripts/register-dynamic-skill.js +253 -0
  480. package/plugins/harness-everything/skills/self-evolve/scripts/self-regression.js +125 -0
  481. package/plugins/harness-everything/skills/skill-creator/SKILL.md +47 -0
  482. package/plugins/harness-everything/skills/skill-creator/references/authoring-workflow.md +14 -0
  483. package/plugins/harness-everything/skills/skill-creator/references/dynamic-generation-contract.md +21 -0
  484. package/plugins/harness-everything/skills/skill-creator/references/quality-checklist.md +16 -0
  485. package/plugins/harness-everything/skills/skill-creator/references/quality-principles.md +81 -0
  486. package/plugins/harness-everything/skills/skill-creator/references/testing-workflow.md +27 -0
  487. package/plugins/harness-everything/skills/skill-style/SKILL.md +42 -0
  488. package/plugins/harness-everything/skills/skill-style/references/style-guide.md +62 -0
  489. package/plugins/harness-everything/skills/tdd/SKILL.md +38 -0
  490. package/plugins/harness-everything/skills/tdd/fixtures/pass-evidence.json +100 -0
  491. package/plugins/harness-everything/skills/tdd/fixtures/quality-scenarios.json +20 -0
  492. package/plugins/harness-everything/skills/tdd/guides/deep-modules.md +33 -0
  493. package/plugins/harness-everything/skills/tdd/guides/interface-design.md +31 -0
  494. package/plugins/harness-everything/skills/tdd/guides/mocking.md +59 -0
  495. package/plugins/harness-everything/skills/tdd/guides/refactoring.md +10 -0
  496. package/plugins/harness-everything/skills/tdd/guides/tests.md +61 -0
  497. package/plugins/harness-everything/skills/tdd/references/core-discipline.md +51 -0
  498. package/plugins/harness-everything/skills/tdd/references/integration-testing.md +13 -0
  499. package/plugins/harness-everything/skills/tdd/references/quality-model.md +68 -0
  500. package/plugins/harness-everything/skills/tdd/references/unit-testing.md +15 -0
  501. package/plugins/harness-everything/skills/tdd/schemas/quality-evidence.schema.json +211 -0
  502. package/plugins/harness-everything/skills/tdd/schemas/quality-report.schema.json +110 -0
  503. package/plugins/harness-everything/skills/tdd/scripts/quality-gate.js +475 -0
  504. package/plugins/harness-everything/skills/to-spec/SKILL.md +40 -0
  505. package/plugins/harness-everything/skills/to-spec/references/process.md +77 -0
  506. package/plugins/harness-everything/skills/to-spec/scripts/check-project-docs.js +239 -0
  507. package/plugins/harness-everything/skills/to-spec/scripts/project-docs-resolver.js +111 -0
  508. package/plugins/harness-everything/skills/to-spec/templates/cli-reference.md +31 -0
  509. package/plugins/harness-everything/skills/to-spec/templates/dev-doc.md +27 -0
  510. package/plugins/harness-everything/skills/to-spec/templates/feature-spec.md +59 -0
  511. package/plugins/harness-everything/skills/to-spec/templates/schema-doc.md +31 -0
  512. package/plugins/harness-everything/skills/to-tickets/SKILL.md +42 -0
  513. package/plugins/harness-everything/skills/to-tickets/references/publishing-and-templates.md +97 -0
  514. package/plugins/harness-everything/skills/todo-driven-workflow/SKILL.md +42 -0
  515. package/plugins/harness-everything/skills/todo-driven-workflow/references/execution-guide.md +27 -0
  516. package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +49 -0
  517. package/plugins/harness-everything/skills/using-git-worktrees/references/workflow-details.md +108 -0
  518. package/plugins/harness-everything/skills/verification-loop/SKILL.md +46 -0
  519. package/plugins/harness-everything/skills/verification-loop/references/verification-phases.md +116 -0
  520. package/plugins/harness-everything/skills/verification-loop/templates/verification-report.template.md +15 -0
  521. package/plugins/harness-everything/skills/verify-before-claim/SKILL.md +43 -0
  522. package/plugins/harness-everything/skills/verify-before-claim/references/verification-guide.md +73 -0
  523. package/plugins/harness-everything/skills/zoom-out/SKILL.md +42 -0
  524. package/plugins/harness-everything/skills/zoom-out/references/circuit-breaker.md +66 -0
  525. package/plugins/harness-everything/skills/zoom-out/templates/zoom-out-report.template.md +20 -0
  526. package/repo-docs/SKILL.md +3 -7
  527. package/rewrite-commits/SKILL.md +2 -2
  528. package/scripts/build-openai-submission.js +158 -0
  529. package/scripts/installer.js +86 -11
  530. package/scripts/lib/advisory-text.js +25 -18
  531. package/scripts/lib/execution-contract.js +70 -0
  532. package/scripts/lib/manifest.js +34 -38
  533. package/scripts/lib/path-boundary.js +90 -0
  534. package/scripts/lib/skills.js +124 -70
  535. package/scripts/lib/workspace.js +269 -7
  536. package/scripts/repository-contract.js +213 -0
  537. package/scripts/sync-current-docs.js +12 -0
  538. package/scripts/sync-openai-plugin.js +91 -0
  539. package/scripts/sync-release-version.js +212 -0
  540. package/security-review/SKILL.md +4 -7
  541. package/security-review/scripts/audit-secrets.js +9 -8
  542. package/self-evolve/SKILL.md +9 -11
  543. package/self-evolve/references/memory-resolution.md +4 -1
  544. package/self-evolve/scripts/persist-memory.js +221 -88
  545. package/self-evolve/scripts/register-dynamic-skill.js +12 -10
  546. package/self-evolve/scripts/self-regression.js +23 -8
  547. package/skill-creator/SKILL.md +12 -14
  548. package/skill-creator/references/quality-checklist.md +1 -0
  549. package/skill-style/SKILL.md +4 -4
  550. package/skill-style/references/style-guide.md +29 -3
  551. package/submission/openai/README.md +67 -0
  552. package/submission/openai/listing.json +31 -0
  553. package/submission/openai/test-cases.json +61 -0
  554. package/tdd/SKILL.md +20 -26
  555. package/tdd/fixtures/pass-evidence.json +100 -0
  556. package/tdd/fixtures/quality-scenarios.json +20 -0
  557. package/tdd/references/core-discipline.md +2 -0
  558. package/tdd/references/integration-testing.md +13 -0
  559. package/tdd/references/quality-model.md +68 -0
  560. package/tdd/references/unit-testing.md +15 -0
  561. package/tdd/schemas/quality-evidence.schema.json +211 -0
  562. package/tdd/schemas/quality-report.schema.json +110 -0
  563. package/tdd/scripts/quality-gate.js +475 -0
  564. package/to-spec/SKILL.md +3 -5
  565. package/to-spec/scripts/check-project-docs.js +42 -62
  566. package/to-spec/scripts/project-docs-resolver.js +111 -0
  567. package/to-tickets/SKILL.md +4 -4
  568. package/todo-driven-workflow/SKILL.md +6 -4
  569. package/using-git-worktrees/SKILL.md +3 -3
  570. package/verification-loop/SKILL.md +4 -4
  571. package/verify-before-claim/SKILL.md +2 -2
  572. package/zoom-out/SKILL.md +4 -4
  573. package/ab-test-deep-analysis-2026-08-27.md +0 -383
  574. package/ab-test-results-2026-08-27.md +0 -152
  575. package/ab-test-statistical-analysis-31cases.md +0 -193
  576. package/opencode-plugin/hooks/circuit-breaker.js +0 -121
  577. package/opencode-plugin/hooks/compliance.js +0 -128
  578. package/opencode-plugin/hooks/post-edit.js +0 -62
  579. package/opencode-plugin/hooks/pre-complete.js +0 -65
  580. package/opencode-plugin/test-hook-firing.js +0 -198
@@ -1,14 +1,246 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
+ const crypto = require('crypto');
4
5
 
5
- function getWorkspaceRoot() {
6
- let dir = path.resolve(process.cwd());
7
- while (dir !== path.parse(dir).root) {
8
- if (fs.existsSync(path.join(dir, '.git'))) return dir;
9
- dir = path.dirname(dir);
6
+ const WORKSPACE_CONTEXT_KEYS = [
7
+ 'workspace_root', 'workspaceRoot', 'project_root', 'projectRoot',
8
+ 'working_directory', 'workingDirectory', 'cwd', 'root'
9
+ ];
10
+ const SESSION_CONTEXT_KEYS = ['session_id', 'sessionId'];
11
+ const HOST_CONTEXT_KEYS = [
12
+ 'host_id', 'hostId', 'agent_id', 'agentId', 'client_id', 'clientId',
13
+ 'machine_id', 'machineId', 'runtime_id', 'runtimeId'
14
+ ];
15
+ const SESSION_REGISTRY_DIR = 'session-workspaces';
16
+ const SESSION_REGISTRY_VERSION = 1;
17
+ const UNBOUND_WORKSPACE_KEY = 'unbound-workspace';
18
+
19
+ function findWorkspaceRoot(startPath, allowNonGit = false) {
20
+ if (typeof startPath !== 'string' || !startPath.trim()) return null;
21
+ let dir = path.resolve(startPath);
22
+ while (true) {
23
+ if (fs.existsSync(path.join(dir, '.git'))) return canonicalPath(dir);
24
+ const parent = path.dirname(dir);
25
+ if (parent === dir) break;
26
+ dir = parent;
27
+ }
28
+ return allowNonGit ? canonicalPath(startPath) : null;
29
+ }
30
+
31
+ function canonicalPath(value) {
32
+ if (typeof value !== 'string' || !value.trim()) return null;
33
+ const resolved = path.resolve(value);
34
+ try { return fs.realpathSync(resolved); } catch (err) { return resolved; }
35
+ }
36
+
37
+ function getSessionId(context) {
38
+ if (!context || typeof context !== 'object') return null;
39
+ for (const key of SESSION_CONTEXT_KEYS) {
40
+ if (typeof context[key] === 'string' && context[key].trim()) {
41
+ return context[key].trim();
42
+ }
43
+ }
44
+ for (const key of ['session', 'metadata', 'context']) {
45
+ if (context[key] && typeof context[key] === 'object') {
46
+ const nested = getSessionId(context[key]);
47
+ if (nested) return nested;
48
+ }
49
+ }
50
+ return null;
51
+ }
52
+
53
+ function getHostId(context) {
54
+ if (!context || typeof context !== 'object') return null;
55
+ for (const key of HOST_CONTEXT_KEYS) {
56
+ if (typeof context[key] === 'string' && context[key].trim()) return context[key].trim();
57
+ }
58
+ if (typeof context.host === 'string' && context.host.trim()) return context.host.trim();
59
+ if (context.host && typeof context.host === 'object') return getHostId(context.host);
60
+ for (const key of ['agent', 'client', 'machine', 'runtime', 'metadata', 'context']) {
61
+ if (context[key] && typeof context[key] === 'object') {
62
+ const nested = getHostId(context[key]);
63
+ if (nested) return nested;
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+
69
+ function contextPath(context, depth = 0) {
70
+ if (typeof context === 'string' && context.trim()) return context.trim();
71
+ if (!context || typeof context !== 'object' || depth > 2) return null;
72
+
73
+ for (const key of WORKSPACE_CONTEXT_KEYS) {
74
+ const value = context[key];
75
+ if (typeof value === 'string' && value.trim()) return value.trim();
76
+ if (value && typeof value === 'object') {
77
+ const nested = contextPath(value, depth + 1);
78
+ if (nested) return nested;
79
+ }
80
+ }
81
+
82
+ for (const key of ['workspace', 'project', 'host', 'context']) {
83
+ const nested = contextPath(context[key], depth + 1);
84
+ if (nested) return nested;
85
+ }
86
+ return null;
87
+ }
88
+
89
+ function sessionRegistryPath(sessionId, hostId) {
90
+ const namespace = hostId ? `${hostId}\0${sessionId}` : String(sessionId);
91
+ const hash = crypto.createHash('sha256').update(namespace).digest('hex');
92
+ return path.join(getStateHome(), SESSION_REGISTRY_DIR, `${hash}.json`);
93
+ }
94
+
95
+ function readRegistryRecord(filePath) {
96
+ try {
97
+ const record = JSON.parse(fs.readFileSync(filePath, 'utf8'));
98
+ if (record.version !== SESSION_REGISTRY_VERSION || typeof record.workspaceRoot !== 'string') return null;
99
+ return record;
100
+ } catch (err) {
101
+ return null;
102
+ }
103
+ }
104
+
105
+ function findSessionRecords(sessionId) {
106
+ const registryDir = path.join(getStateHome(), SESSION_REGISTRY_DIR);
107
+ try {
108
+ return fs.readdirSync(registryDir, { withFileTypes: true })
109
+ .filter(entry => entry.isFile() && entry.name.endsWith('.json'))
110
+ .map(entry => readRegistryRecord(path.join(registryDir, entry.name)))
111
+ .filter(record => record && record.sessionId === sessionId);
112
+ } catch (err) {
113
+ return [];
114
+ }
115
+ }
116
+
117
+ function readWorkspaceSession(sessionId, context) {
118
+ if (!sessionId) return null;
119
+ const hostId = getHostId(context);
120
+ const records = [];
121
+ const preferred = readRegistryRecord(sessionRegistryPath(sessionId, hostId));
122
+ if (preferred && (!hostId || !preferred.hostId || preferred.hostId === hostId)) records.push(preferred);
123
+ if (hostId) {
124
+ // A session may have been first observed by a caller that did not expose
125
+ // host metadata. Reuse that unscoped binding rather than forking state.
126
+ const unscoped = readRegistryRecord(sessionRegistryPath(sessionId, null));
127
+ if (unscoped && !unscoped.hostId) records.push(unscoped);
128
+ } else {
129
+ records.push(...findSessionRecords(sessionId));
10
130
  }
11
- return process.cwd();
131
+
132
+ const unique = [...new Map(records.map(record => [
133
+ `${record.hostId || ''}\0${record.workspaceRoot}`,
134
+ record
135
+ ])).values()];
136
+ if (unique.length === 1) return unique[0];
137
+ if (unique.length > 1) {
138
+ // Hostless payloads are safe only when all known host bindings agree on
139
+ // the same workspace. Otherwise select nothing and require context.
140
+ const roots = new Set(unique.map(record => canonicalPath(record.workspaceRoot)));
141
+ if (roots.size === 1) return unique[0];
142
+ }
143
+ return null;
144
+ }
145
+
146
+ function bindWorkspaceSession(sessionId, workspaceRoot, context, force = false) {
147
+ if (!sessionId) return null;
148
+ const root = findWorkspaceRoot(workspaceRoot, true);
149
+ if (!root) return null;
150
+ const hostId = getHostId(context);
151
+ const target = sessionRegistryPath(sessionId, hostId);
152
+ const record = {
153
+ version: SESSION_REGISTRY_VERSION,
154
+ sessionId,
155
+ hostId: hostId || undefined,
156
+ workspaceRoot: root,
157
+ workspaceKey: getWorkspaceKey(root),
158
+ updatedAt: new Date().toISOString()
159
+ };
160
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
161
+ try {
162
+ fs.mkdirSync(path.dirname(target), { recursive: true });
163
+ fs.writeFileSync(temporary, JSON.stringify(record, null, 2), 'utf8');
164
+ // Keep the first successful binding when two hooks initialize together.
165
+ if (fs.existsSync(target)) {
166
+ if (readRegistryRecord(target) && !force) fs.unlinkSync(temporary);
167
+ else {
168
+ fs.unlinkSync(target);
169
+ fs.renameSync(temporary, target);
170
+ }
171
+ } else fs.renameSync(temporary, target);
172
+ } catch (err) {
173
+ // Identity persistence is best effort. The caller still receives the
174
+ // resolved root and the next invocation can retry the binding.
175
+ try { if (fs.existsSync(temporary)) fs.unlinkSync(temporary); } catch (cleanupErr) { /* ignore */ }
176
+ }
177
+ return root;
178
+ }
179
+
180
+ function isIdentityReset(context) {
181
+ if (!context || typeof context !== 'object') return false;
182
+ return context.workspace_identity_reset === true ||
183
+ context.workspaceIdentityReset === true ||
184
+ context.new_session === true ||
185
+ context.newSession === true;
186
+ }
187
+
188
+ function getWorkspaceRoot(context) {
189
+ const sessionId = getSessionId(context);
190
+ const existing = readWorkspaceSession(sessionId, context);
191
+ const explicit = contextPath(context);
192
+
193
+ // SessionStart is the host's authoritative opportunity to establish (or
194
+ // re-establish) the project identity. All later hook invocations keep that
195
+ // binding even if the agent changes cwd or reports a nested repository.
196
+ if (existing && !isIdentityReset(context)) return existing.workspaceRoot;
197
+
198
+ const hostRoot = explicit || process.env.HARNESS_WORKSPACE_ROOT ||
199
+ process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR;
200
+ const root = findWorkspaceRoot(hostRoot || process.cwd(), Boolean(hostRoot));
201
+ if (sessionId) bindWorkspaceSession(sessionId, root, context, isIdentityReset(context));
202
+ return root;
203
+ }
204
+
205
+ // Single global root for ALL Harness runtime state (session counters,
206
+ // circuit-breaker trips, audit logs, handoff timestamps, ...). Never
207
+ // cwd-derived, so a script invoked from a fixture dir, worktree, submodule,
208
+ // or any other nested non-git directory can never scatter files there
209
+ // (issue #42). `$HARNESS_STATE_HOME` matches the env var the opencode
210
+ // plugin already used for its own (differently-rooted) global state.
211
+ function getStateHome() {
212
+ return process.env.HARNESS_STATE_HOME || path.join(os.homedir(), '.agents', 'harness-everything');
213
+ }
214
+
215
+ // Keys runtime state per real workspace instead of per invocation cwd, so
216
+ // two different repos (or a repo and a stray subdirectory someone `cd`ed
217
+ // into) never collide or fork the same state stream. Uses the resolved real
218
+ // path (symlinks collapsed) hashed short, prefixed with a readable slug
219
+ // purely so `~/.agents/harness-everything/workspaces/` stays eyeballable.
220
+ function getWorkspaceKey(root) {
221
+ const workspaceRoot = typeof root === 'string' && root.trim() ? root : getWorkspaceRoot(root);
222
+ if (!workspaceRoot) return UNBOUND_WORKSPACE_KEY;
223
+ const resolved = path.resolve(workspaceRoot);
224
+ let real = resolved;
225
+ try { real = fs.realpathSync(resolved); } catch (err) { /* path may not exist yet (tests) */ }
226
+ const slug = path.basename(real).toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'workspace';
227
+ const hashInput = process.platform === 'win32' ? real.toLowerCase() : real;
228
+ const hash = crypto.createHash('sha1').update(hashInput).digest('hex').slice(0, 12);
229
+ return `${slug}-${hash}`;
230
+ }
231
+
232
+ function getWorkspaceStateDir(root) {
233
+ return path.join(getStateHome(), 'workspaces', getWorkspaceKey(root));
234
+ }
235
+
236
+ function resolveWorkspaceIdentity(context) {
237
+ const workspaceRoot = getWorkspaceRoot(context);
238
+ return {
239
+ workspaceRoot,
240
+ workspaceKey: getWorkspaceKey(workspaceRoot),
241
+ stateDir: getWorkspaceStateDir(workspaceRoot),
242
+ sessionId: getSessionId(context)
243
+ };
12
244
  }
13
245
 
14
246
  function getUserPromptsDir() {
@@ -25,4 +257,34 @@ function getUserPromptsDir() {
25
257
  }
26
258
  }
27
259
 
28
- module.exports = { getWorkspaceRoot, getUserPromptsDir };
260
+ // The harness repo must never be "repaired" into carrying its own generated
261
+ // advisory files. Identify it by repo identity, not by comparing the caller's
262
+ // __dirname: when harness runs from an npx/global install against its own
263
+ // source checkout, the installed path and the workspace path differ and a
264
+ // path-based guard silently fails open (issue #40).
265
+ const HARNESS_PACKAGE_NAME = 'harness-everything';
266
+
267
+ function isHarnessRepo(workspaceRoot) {
268
+ try {
269
+ const pkgPath = path.join(workspaceRoot, 'package.json');
270
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
271
+ return pkg.name === HARNESS_PACKAGE_NAME;
272
+ } catch (err) {
273
+ return false;
274
+ }
275
+ }
276
+
277
+ module.exports = {
278
+ getWorkspaceRoot,
279
+ resolveWorkspaceIdentity,
280
+ bindWorkspaceSession,
281
+ readWorkspaceSession,
282
+ getSessionId,
283
+ getHostId,
284
+ getStateHome,
285
+ getWorkspaceKey,
286
+ getWorkspaceStateDir,
287
+ getUserPromptsDir,
288
+ isHarnessRepo,
289
+ HARNESS_PACKAGE_NAME,
290
+ };
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const ROOT = path.resolve(__dirname, '..');
8
+ const ACTION_MINIMUMS = Object.freeze({ checkout: 7, setupNode: 7 });
9
+ const MINIMUM_SUPPORTED_NODE_FLOOR = 22;
10
+
11
+ function read(root, rel) {
12
+ return fs.readFileSync(path.join(root, rel), 'utf8');
13
+ }
14
+
15
+ function readJson(root, rel) {
16
+ return JSON.parse(read(root, rel));
17
+ }
18
+
19
+ function parseMinimumNode(engine) {
20
+ const match = String(engine || '').match(/>=\s*v?(\d+)/);
21
+ return match ? Number(match[1]) : null;
22
+ }
23
+
24
+ function parseMajor(text) {
25
+ const match = String(text || '').trim().match(/^v?(\d+)/);
26
+ return match ? Number(match[1]) : null;
27
+ }
28
+
29
+ function uniqSorted(values) {
30
+ return [...new Set(values.filter(Number.isInteger))].sort((a, b) => a - b);
31
+ }
32
+
33
+ function extractMajors(text, action) {
34
+ const escaped = action.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35
+ const re = new RegExp(`uses:\\s*${escaped}@v(\\d+)`, 'g');
36
+ const out = [];
37
+ let match;
38
+ while ((match = re.exec(text))) out.push(Number(match[1]));
39
+ return uniqSorted(out);
40
+ }
41
+
42
+ function extractNodeVersions(text) {
43
+ const out = [];
44
+ const re = /node-version:\s*["']?(\d+)(?:\.\d+)?["']?/g;
45
+ let match;
46
+ while ((match = re.exec(text))) out.push(Number(match[1]));
47
+ return uniqSorted(out);
48
+ }
49
+
50
+ function extractQualityGates(text) {
51
+ const gates = [];
52
+ if (/\bnpm\s+test\b/.test(text)) gates.push('test');
53
+ const re = /\bnpm\s+run\s+([A-Za-z0-9:_-]+)/g;
54
+ let match;
55
+ while ((match = re.exec(text))) gates.push(match[1]);
56
+ return [...new Set(gates)];
57
+ }
58
+
59
+ function listWorkflowFiles(root) {
60
+ const dir = path.join(root, '.github', 'workflows');
61
+ if (!fs.existsSync(dir)) return [];
62
+ return fs.readdirSync(dir)
63
+ .filter(name => /\.ya?ml$/i.test(name))
64
+ .sort();
65
+ }
66
+
67
+ function parseWorkflow(root, file) {
68
+ const rel = path.posix.join('.github/workflows', file);
69
+ const text = read(root, rel);
70
+ return {
71
+ file,
72
+ nodeVersions: extractNodeVersions(text),
73
+ checkoutMajors: extractMajors(text, 'actions/checkout'),
74
+ setupNodeMajors: extractMajors(text, 'actions/setup-node'),
75
+ scheduled: /^\s*schedule:\s*$/m.test(text),
76
+ workflowDispatch: /^\s*workflow_dispatch:\s*$/m.test(text),
77
+ workflowCall: /^\s*workflow_call:\s*$/m.test(text),
78
+ qualityGates: extractQualityGates(text),
79
+ };
80
+ }
81
+
82
+ function collectContract(root = ROOT) {
83
+ const pkg = readJson(root, 'package.json');
84
+ const nvmPath = path.join(root, '.nvmrc');
85
+ const primaryNode = fs.existsSync(nvmPath) ? parseMajor(read(root, '.nvmrc')) : null;
86
+ const dockerText = read(root, 'Dockerfile');
87
+ const dockerMatch = dockerText.match(/^FROM\s+node:(\d+)(?:[^\s]*)/m);
88
+ const workflows = listWorkflowFiles(root).map(file => parseWorkflow(root, file));
89
+ const ci = workflows.find(workflow => workflow.file === 'ci.yml' || workflow.file === 'ci.yaml');
90
+ const behavioral = workflows.find(workflow => /^behavioral-evals\.ya?ml$/.test(workflow.file));
91
+ const release = workflows.find(workflow => /^release\.ya?ml$/.test(workflow.file));
92
+
93
+ return {
94
+ runtime: {
95
+ packageEngine: pkg.engines?.node || null,
96
+ minimumNode: parseMinimumNode(pkg.engines?.node),
97
+ primaryNode,
98
+ dockerNode: dockerMatch ? Number(dockerMatch[1]) : null,
99
+ },
100
+ githubActions: {
101
+ checkoutMajors: uniqSorted(workflows.flatMap(workflow => workflow.checkoutMajors)),
102
+ setupNodeMajors: uniqSorted(workflows.flatMap(workflow => workflow.setupNodeMajors)),
103
+ },
104
+ workflows: Object.fromEntries(workflows.map(workflow => [workflow.file, workflow])),
105
+ ci: ci || null,
106
+ behavioralEvals: behavioral || null,
107
+ release: release || null,
108
+ };
109
+ }
110
+
111
+ function renderContractMarkdown(contract) {
112
+ const runtime = contract.runtime;
113
+ const actionList = values => values.length ? values.map(v => `v${v}`).join(', ') : 'not used';
114
+ const rows = Object.values(contract.workflows).map(workflow => {
115
+ const nodes = workflow.nodeVersions.length ? workflow.nodeVersions.map(String).join(', ') : 'n/a';
116
+ const trigger = [workflow.scheduled && 'schedule', workflow.workflowDispatch && 'workflow_dispatch', workflow.workflowCall && 'workflow_call'].filter(Boolean).join(', ') || 'push/pull request or other';
117
+ const gates = workflow.qualityGates.length ? workflow.qualityGates.map(g => `\`${g}\``).join(', ') : 'n/a';
118
+ return `| \`${workflow.file}\` | ${nodes} | ${trigger} | ${gates} |`;
119
+ }).join('\n');
120
+
121
+ return `<!-- GENERATED by scripts/repository-contract.js. Run \`npm run docs:sync\` after workflow/runtime changes. -->\n# Repository runtime and workflow contract\n\nThis page is generated from checked-in runtime and workflow sources. Do not edit it by hand. Historical audit/evidence documents are intentionally outside this current-state contract.\n\n## Runtime\n\n- Minimum supported Node.js: **${runtime.minimumNode}** (from \`package.json#engines.node\`: \`${runtime.packageEngine}\`)\n- Primary development/CI Node.js: **${runtime.primaryNode}** (from \`.nvmrc\`)\n- Docker verification Node.js: **${runtime.dockerNode}** (from \`Dockerfile\`)\n\n## GitHub Actions runtime majors\n\n- \`actions/checkout\`: ${actionList(contract.githubActions.checkoutMajors)}\n- \`actions/setup-node\`: ${actionList(contract.githubActions.setupNodeMajors)}\n\n## Active workflows\n\n| Workflow | Node.js versions | Explicit triggers | npm quality gates |\n| --- | --- | --- | --- |\n${rows}\n\n## Drift prevention\n\n\`npm run test:repo-contract\` fails when runtime sources disagree, an active workflow reintroduces an unsupported Node version/action major, the Node ${runtime.minimumNode} compatibility floor is no longer exercised, or this generated document is stale.\n`;
122
+ }
123
+
124
+ function validateContract(contract, root = ROOT) {
125
+ const failures = [];
126
+ const fail = message => failures.push(message);
127
+ const { runtime } = contract;
128
+
129
+ if (!Number.isInteger(runtime.minimumNode) || runtime.minimumNode < MINIMUM_SUPPORTED_NODE_FLOOR) {
130
+ fail(`package.json must declare Node >=${MINIMUM_SUPPORTED_NODE_FLOOR}; got ${runtime.packageEngine || 'missing'}`);
131
+ }
132
+ if (!Number.isInteger(runtime.primaryNode) || runtime.primaryNode < runtime.minimumNode) {
133
+ fail(`.nvmrc primary Node must be >= minimum Node ${runtime.minimumNode}; got ${runtime.primaryNode ?? 'missing'}`);
134
+ }
135
+ if (runtime.dockerNode !== runtime.primaryNode) {
136
+ fail(`Dockerfile Node ${runtime.dockerNode ?? 'missing'} must match .nvmrc Node ${runtime.primaryNode ?? 'missing'}`);
137
+ }
138
+
139
+ for (const major of contract.githubActions.checkoutMajors) {
140
+ if (major < ACTION_MINIMUMS.checkout) fail(`actions/checkout@v${major} is below supported floor v${ACTION_MINIMUMS.checkout}`);
141
+ }
142
+ for (const major of contract.githubActions.setupNodeMajors) {
143
+ if (major < ACTION_MINIMUMS.setupNode) fail(`actions/setup-node@v${major} is below supported floor v${ACTION_MINIMUMS.setupNode}`);
144
+ }
145
+ if (contract.githubActions.checkoutMajors.length !== 1) fail(`active workflows must use one checkout major; found ${contract.githubActions.checkoutMajors.join(', ') || 'none'}`);
146
+ if (contract.githubActions.setupNodeMajors.length !== 1) fail(`active workflows must use one setup-node major; found ${contract.githubActions.setupNodeMajors.join(', ') || 'none'}`);
147
+
148
+ for (const workflow of Object.values(contract.workflows)) {
149
+ for (const node of workflow.nodeVersions) {
150
+ if (node < runtime.minimumNode) fail(`${workflow.file} uses Node ${node}, below minimum ${runtime.minimumNode}`);
151
+ }
152
+ }
153
+
154
+ if (!contract.ci) fail('ci.yml is missing');
155
+ else {
156
+ if (!contract.ci.nodeVersions.includes(runtime.primaryNode)) fail(`ci.yml must exercise primary Node ${runtime.primaryNode}`);
157
+ if (!contract.ci.nodeVersions.includes(runtime.minimumNode)) fail(`ci.yml must exercise minimum supported Node ${runtime.minimumNode}`);
158
+ }
159
+ if (!contract.behavioralEvals) fail('behavioral-evals.yml is missing');
160
+ else {
161
+ if (!contract.behavioralEvals.scheduled) fail('behavioral-evals.yml must retain its scheduled trigger');
162
+ if (!contract.behavioralEvals.nodeVersions.includes(runtime.primaryNode)) fail(`behavioral-evals.yml must use primary Node ${runtime.primaryNode}`);
163
+ }
164
+ if (!contract.release) fail('release.yml is missing');
165
+ else if (!contract.release.nodeVersions.includes(runtime.primaryNode)) {
166
+ fail(`release.yml must use primary Node ${runtime.primaryNode}`);
167
+ }
168
+
169
+ const generatedPath = path.join(root, 'docs', 'repository-contract.md');
170
+ if (!fs.existsSync(generatedPath)) {
171
+ fail('docs/repository-contract.md is missing; run npm run docs:sync');
172
+ } else {
173
+ const actual = fs.readFileSync(generatedPath, 'utf8').replace(/\r\n/g, '\n');
174
+ const expected = renderContractMarkdown(contract).replace(/\r\n/g, '\n');
175
+ if (actual !== expected) fail('docs/repository-contract.md is stale; run npm run docs:sync');
176
+ }
177
+
178
+ return failures;
179
+ }
180
+
181
+ function printSummary(contract) {
182
+ console.log(`Node: >=${contract.runtime.minimumNode} supported; ${contract.runtime.primaryNode} primary; ${contract.runtime.dockerNode} Docker`);
183
+ console.log(`Actions: checkout ${contract.githubActions.checkoutMajors.map(v => `v${v}`).join(', ')}; setup-node ${contract.githubActions.setupNodeMajors.map(v => `v${v}`).join(', ')}`);
184
+ for (const workflow of Object.values(contract.workflows)) {
185
+ console.log(`${workflow.file}: Node ${workflow.nodeVersions.join(', ') || 'n/a'}; gates ${workflow.qualityGates.join(', ') || 'n/a'}`);
186
+ }
187
+ }
188
+
189
+ if (require.main === module) {
190
+ const args = new Set(process.argv.slice(2));
191
+ const contract = collectContract();
192
+ if (args.has('--json')) {
193
+ process.stdout.write(`${JSON.stringify(contract, null, 2)}\n`);
194
+ } else if (args.has('--check')) {
195
+ const failures = validateContract(contract);
196
+ if (failures.length) {
197
+ for (const failure of failures) console.error(`❌ ${failure}`);
198
+ process.exitCode = 1;
199
+ } else {
200
+ console.log('✅ Repository runtime/workflow contract is consistent.');
201
+ }
202
+ } else {
203
+ printSummary(contract);
204
+ }
205
+ }
206
+
207
+ module.exports = {
208
+ ACTION_MINIMUMS,
209
+ MINIMUM_SUPPORTED_NODE_FLOOR,
210
+ collectContract,
211
+ renderContractMarkdown,
212
+ validateContract,
213
+ };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { collectContract, renderContractMarkdown } = require('./repository-contract');
7
+
8
+ const ROOT = path.resolve(__dirname, '..');
9
+ const output = path.join(ROOT, 'docs', 'repository-contract.md');
10
+ fs.mkdirSync(path.dirname(output), { recursive: true });
11
+ fs.writeFileSync(output, renderContractMarkdown(collectContract(ROOT)), 'utf8');
12
+ console.log(`Updated ${path.relative(ROOT, output).replace(/\\/g, '/')}`);
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const ROOT = path.resolve(__dirname, '..');
8
+ const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, '.claude-plugin', 'plugin.json'), 'utf8'));
9
+ const pluginSkillsRoot = path.join(ROOT, 'plugins', 'harness-everything', 'skills');
10
+ const pluginRoot = path.join(ROOT, 'plugins', 'harness-everything');
11
+ const pluginHooksRoot = path.join(pluginRoot, 'hooks');
12
+ const sourceHooksScriptsRoot = path.join(ROOT, 'hooks', 'scripts');
13
+
14
+ function normalizeText(file) {
15
+ const bytes = fs.readFileSync(file);
16
+ // Skills and hooks are text, but keeping binary assets byte-preserving makes
17
+ // this copier safe if a referenced asset is added later.
18
+ if (bytes.includes(0)) return;
19
+ const normalized = bytes.toString('utf8').replace(/\r\n/g, '\n');
20
+ fs.writeFileSync(file, normalized, 'utf8');
21
+ }
22
+
23
+ function normalizeTree(root) {
24
+ for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
25
+ const full = path.join(root, entry.name);
26
+ if (entry.isDirectory()) normalizeTree(full);
27
+ else if (entry.isFile()) normalizeText(full);
28
+ }
29
+ }
30
+
31
+ function syncTree(source, destination) {
32
+ fs.rmSync(destination, { recursive: true, force: true });
33
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
34
+ if (fs.statSync(source).isDirectory()) {
35
+ fs.cpSync(source, destination, { recursive: true });
36
+ normalizeTree(destination);
37
+ } else {
38
+ fs.copyFileSync(source, destination);
39
+ normalizeText(destination);
40
+ }
41
+ }
42
+
43
+ fs.mkdirSync(pluginSkillsRoot, { recursive: true });
44
+
45
+ const expected = new Set();
46
+ for (const entry of manifest.skills || []) {
47
+ const source = path.resolve(ROOT, entry);
48
+ const name = path.basename(source);
49
+ const destination = path.join(pluginSkillsRoot, name);
50
+ expected.add(name);
51
+ syncTree(source, destination);
52
+ console.log(`synced ${name}`);
53
+ }
54
+
55
+ for (const name of fs.readdirSync(pluginSkillsRoot)) {
56
+ if (!expected.has(name)) fs.rmSync(path.join(pluginSkillsRoot, name), { recursive: true, force: true });
57
+ }
58
+
59
+ // The Claude hook definitions are host-specific, but their enforcement
60
+ // scripts are shared. Package the scripts plus the small runtime libraries
61
+ // they require so every OpenAI hook is self-contained under PLUGIN_ROOT.
62
+ const packageHookScriptsRoot = path.join(pluginHooksRoot, 'scripts');
63
+ syncTree(sourceHooksScriptsRoot, packageHookScriptsRoot);
64
+
65
+ const packageWorkspace = path.join(packageHookScriptsRoot, 'lib', 'workspace.js');
66
+ syncTree(path.join(ROOT, 'scripts', 'lib', 'workspace.js'), packageWorkspace);
67
+
68
+ const packageAdvisoryText = path.join(pluginRoot, 'scripts', 'lib', 'advisory-text.js');
69
+ syncTree(path.join(ROOT, 'scripts', 'lib', 'advisory-text.js'), packageAdvisoryText);
70
+
71
+ // The source hook state module is shared with Claude and uses the repository
72
+ // layout. Rewrite only that import in the packaged copy; all other relative
73
+ // imports remain inside the package tree.
74
+ const packageState = path.join(packageHookScriptsRoot, 'lib', 'harness-state.js');
75
+ const stateSource = fs.readFileSync(packageState, 'utf8');
76
+ fs.writeFileSync(
77
+ packageState,
78
+ stateSource.replace("require('../../../scripts/lib/workspace')", "require('./workspace')"),
79
+ 'utf8'
80
+ );
81
+
82
+ const packageSessionStart = path.join(pluginHooksRoot, 'session-start.js');
83
+ syncTree(path.join(sourceHooksScriptsRoot, 'openai-session-start.js'), packageSessionStart);
84
+ const sessionSource = fs.readFileSync(packageSessionStart, 'utf8');
85
+ fs.writeFileSync(
86
+ packageSessionStart,
87
+ sessionSource.replace("require('./lib/harness-state')", "require('./scripts/lib/harness-state')"),
88
+ 'utf8'
89
+ );
90
+
91
+ console.log(`OpenAI plugin skills and runtime synchronized: ${expected.size} skills`);