harness-everything 0.2.2 → 0.3.6
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.
- package/.claude-plugin/marketplace.json +27 -0
- package/.claude-plugin/plugin.json +51 -0
- package/.gitattributes +1 -0
- package/.github/workflows/behavioral-evals.yml +36 -0
- package/.github/workflows/ci.yml +117 -0
- package/.github/workflows/release.yml +45 -0
- package/.husky/commit-msg +1 -0
- package/.waza.yaml +22 -0
- package/AGENTS.md +60 -2
- package/BENCHMARK_SOP.md +62 -62
- package/CHANGELOG.md +297 -114
- package/CODE_OF_CONDUCT.md +24 -0
- package/CONTRIBUTING.md +47 -0
- package/Dockerfile +18 -18
- package/LICENSE +201 -201
- package/README.md +279 -197
- package/SECURITY.md +33 -0
- package/VERIFICATION.md +394 -347
- package/ab-test-deep-analysis-2026-08-27.md +383 -0
- package/ab-test-results-2026-08-27.md +152 -0
- package/ab-test-statistical-analysis-31cases.md +193 -0
- package/behavioral-evals/README.md +85 -0
- package/behavioral-evals/analyze-plugin-results.js +110 -0
- package/behavioral-evals/cases/baseline-add-feature.yaml +34 -0
- package/behavioral-evals/cases/baseline-api-design.yaml +32 -0
- package/behavioral-evals/cases/baseline-debugging.yaml +31 -0
- package/behavioral-evals/cases/baseline-dependency.yaml +24 -0
- package/behavioral-evals/cases/baseline-documentation.yaml +34 -0
- package/behavioral-evals/cases/baseline-error-handling.yaml +31 -0
- package/behavioral-evals/cases/baseline-git-commit.yaml +33 -0
- package/behavioral-evals/cases/baseline-performance-monitoring.yaml +28 -0
- package/behavioral-evals/cases/baseline-performance.yaml +34 -0
- package/behavioral-evals/cases/baseline-refactor-with-tests.yaml +35 -0
- package/behavioral-evals/cases/baseline-refactor.yaml +27 -0
- package/behavioral-evals/cases/baseline-security-review.yaml +28 -0
- package/behavioral-evals/cases/baseline-simple-bugfix.yaml +33 -0
- package/behavioral-evals/cases/baseline-tdd-workflow.yaml +28 -0
- package/behavioral-evals/cases/breaker-zoom-out-after-3.yaml +50 -0
- package/behavioral-evals/cases/pressure-budget-skip-review.yaml +27 -0
- package/behavioral-evals/cases/pressure-bypass-review.yaml +27 -0
- package/behavioral-evals/cases/pressure-complexity-skip.yaml +37 -0
- package/behavioral-evals/cases/pressure-expert-skip-testing.yaml +31 -0
- package/behavioral-evals/cases/pressure-fatigue-skip.yaml +33 -0
- package/behavioral-evals/cases/pressure-management-skip-all.yaml +28 -0
- package/behavioral-evals/cases/pressure-scope-bypass.yaml +28 -0
- package/behavioral-evals/cases/pressure-skip-docs.yaml +50 -0
- package/behavioral-evals/cases/pressure-skip-error-handling.yaml +35 -0
- package/behavioral-evals/cases/pressure-skip-security.yaml +32 -0
- package/behavioral-evals/cases/pressure-skip-tests.yaml +27 -0
- package/behavioral-evals/cases/pressure-skip-verification.yaml +43 -0
- package/behavioral-evals/cases/pressure-social-skip-review.yaml +28 -0
- package/behavioral-evals/cases/pressure-sunk-cost-retry.yaml +47 -0
- package/behavioral-evals/cases/scope-discipline.yaml +32 -0
- package/behavioral-evals/cases/tier1-no-overplan.yaml +26 -0
- package/behavioral-evals/cases/verify-before-done.yaml +31 -0
- package/behavioral-evals/results/.gitkeep +0 -0
- package/behavioral-evals/results/2026-08-23-breaker-zoom-out-after-3.json +20 -0
- package/behavioral-evals/results/2026-08-23-pressure-skip-verification.json +20 -0
- package/behavioral-evals/results/2026-08-23-pressure-sunk-cost-retry.json +20 -0
- package/behavioral-evals/results/2026-08-23-scope-discipline.json +16 -0
- package/behavioral-evals/results/2026-08-23-tier1-no-overplan.json +20 -0
- package/behavioral-evals/results/2026-08-23-verify-before-done.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-add-feature.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-api-design.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-debugging.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-dependency.json +16 -0
- package/behavioral-evals/results/2026-08-27-baseline-documentation.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-error-handling.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-git-commit.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-performance-monitoring.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-performance.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-refactor-with-tests.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-refactor.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-security-review.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-simple-bugfix.json +20 -0
- package/behavioral-evals/results/2026-08-27-baseline-tdd-workflow.json +24 -0
- package/behavioral-evals/results/2026-08-27-breaker-zoom-out-after-3.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-budget-skip-review.json +16 -0
- package/behavioral-evals/results/2026-08-27-pressure-bypass-review.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-complexity-skip.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-expert-skip-testing.json +16 -0
- package/behavioral-evals/results/2026-08-27-pressure-fatigue-skip.json +16 -0
- package/behavioral-evals/results/2026-08-27-pressure-management-skip-all.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-skip-docs.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-skip-error-handling.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-skip-security.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-skip-tests.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-skip-verification.json +24 -0
- package/behavioral-evals/results/2026-08-27-pressure-social-skip-review.json +20 -0
- package/behavioral-evals/results/2026-08-27-pressure-sunk-cost-retry.json +24 -0
- package/behavioral-evals/results/2026-08-27-scope-discipline.json +16 -0
- package/behavioral-evals/results/2026-08-27-tier1-no-overplan.json +20 -0
- package/behavioral-evals/results/2026-08-27-verify-before-done.json +20 -0
- package/behavioral-evals/results/run-20260827-115509.log +287 -0
- package/behavioral-evals/run-with-plugin.js +316 -0
- package/behavioral-evals/run.js +587 -0
- package/benchmarks/README.md +63 -0
- package/benchmarks/ab-test-2026-08-26/results.json +55 -0
- package/benchmarks/results/logs/.gitkeep +0 -0
- package/benchmarks/results/logs/test-a-harness.md +31 -0
- package/benchmarks/results/logs/test-a-vanilla.md +28 -0
- package/benchmarks/results/logs/test-b-micro-loop-harness.md +48 -0
- package/benchmarks/results/logs/test-b-micro-loop-vanilla.md +36 -0
- package/benchmarks/results/logs/test-c-attention-loss-harness.md +40 -0
- package/benchmarks/results/logs/test-c-attention-loss-vanilla.md +63 -0
- package/benchmarks/results/logs/test-d-knowledge-boundary-harness.md +24 -0
- package/benchmarks/results/logs/test-d-knowledge-boundary-vanilla.md +29 -0
- package/benchmarks/results/logs/test-e-shell-awareness-harness.md +20 -0
- package/benchmarks/results/logs/test-e-shell-awareness-vanilla.md +20 -0
- package/benchmarks/results/logs/test-f-fact-audit-harness.md +16 -0
- package/benchmarks/results/logs/test-f-fact-audit-vanilla.md +16 -0
- package/benchmarks/results/results.json +158 -0
- package/benchmarks/run.js +220 -0
- package/benchmarks/schema.json +44 -0
- package/bin/cli.js +152 -97
- package/ci/ab-test-cases/grill-me-adversarial.yaml +18 -0
- package/ci/ab-test-cases/tdd-test-first.yaml +23 -0
- package/ci/ab-test-cases/verification-loop-gates.yaml +25 -0
- package/ci/ab-test-cases/verify-before-claim-cites.yaml +18 -0
- package/ci/ab-test-harness.js +410 -0
- package/{eval-framework → ci}/cases/case1.json +5 -5
- package/ci/cases/case10-small-feature.json +5 -0
- package/ci/cases/case11-readme-typo-update.json +5 -0
- package/ci/cases/case12-chinese-macro-audit.json +5 -0
- package/{eval-framework → ci}/cases/case2.json +5 -5
- package/{eval-framework → ci}/cases/case3.json +5 -5
- package/{eval-framework → ci}/cases/case4-zh-tier2.json +5 -5
- package/{eval-framework → ci}/cases/case5-zh-tier3.json +5 -5
- package/ci/cases/case6-macro-skill-audit.json +5 -0
- package/ci/cases/case7-macro-reference-audit.json +5 -0
- package/ci/cases/case8-controlled-ab-benchmark.json +5 -0
- package/ci/cases/case9-four-issue-audit.json +5 -0
- package/ci/consistency-check.js +347 -0
- package/ci/description-collision.js +109 -0
- package/ci/fable-mode-test.js +120 -0
- package/ci/fixtures/agency-agents/divisions.json +6 -0
- package/ci/fixtures/agency-agents/engineering/code-reviewer.md +11 -0
- package/ci/fixtures/agency-agents/testing/reality-checker.md +11 -0
- package/ci/fixtures/bad-frontmatter-colon/SKILL.md +16 -0
- package/ci/fixtures/duplicate-description/skill-a/SKILL.md +16 -0
- package/ci/fixtures/duplicate-description/skill-b/SKILL.md +16 -0
- package/ci/mechanism-2a-rule-of-3.test.js +46 -0
- package/ci/mechanism-2b-boundary-guard.test.js +16 -0
- package/ci/mechanism-2c-state-persist.test.js +29 -0
- package/ci/mechanism-2d-fact-audit.test.js +18 -0
- package/ci/mechanism-2e-scope-guard.test.js +24 -0
- package/ci/mechanism-2f-stop-gate.test.js +23 -0
- package/ci/mechanism-2g-platform-ignore.test.js +88 -0
- package/ci/mechanism-2h-installer-manifest.test.js +147 -0
- package/ci/mechanism-2i-crlf-frontmatter.test.js +145 -0
- package/ci/mechanism-2i-install-verification.test.js +34 -0
- package/ci/mechanism-2j-behavioral-runner.test.js +20 -0
- package/ci/mechanism-2k-reference-check.test.js +20 -0
- package/ci/mechanism-2l-multi-agent-workspace.test.js +105 -0
- package/ci/mechanism-test.js +71 -0
- package/ci/negative-controls.js +84 -0
- package/ci/reference-check.js +112 -0
- package/ci/release-consistency-check.js +123 -0
- package/ci/routing-check.js +90 -0
- package/{eval-framework → ci}/runner.js +56 -56
- package/ci/skill-routing-check.js +98 -0
- package/ci/test-helper.js +104 -0
- package/ci/test-negative-controls.js +148 -0
- package/commitlint.config.js +25 -0
- package/docker-verify.sh +266 -266
- package/docs/architecture.md +99 -95
- package/docs/audit.md +53 -0
- package/docs/mechanism-first-skill-mesh.md +163 -0
- package/docs/philosophy.md +47 -45
- package/docs/reflection.md +48 -34
- package/docs/routing.md +58 -45
- package/docs/troubleshooting.md +284 -0
- package/docs/workflows/environment-detection.md +10 -10
- package/docs/workflows/eval-harness.md +13 -6
- package/docs/workflows/fable-discipline.md +9 -9
- package/docs/workflows/fable-mode.md +29 -32
- package/docs/workflows/find-skills.md +36 -0
- package/docs/workflows/git-commit.md +18 -9
- package/docs/workflows/grill-me.md +11 -11
- package/docs/workflows/grill-with-docs.md +14 -7
- package/docs/workflows/harness-everything.md +95 -92
- package/docs/workflows/improve-codebase-architecture.md +15 -7
- package/docs/workflows/install-cognitive-os.md +60 -60
- package/docs/workflows/multi-agent-workspace.md +42 -0
- package/docs/workflows/repo-docs.md +12 -7
- package/docs/workflows/security-review.md +26 -7
- package/docs/workflows/self-evolve.md +27 -44
- package/docs/workflows/skill-creator.md +80 -75
- package/docs/workflows/skill-style.md +64 -64
- package/docs/workflows/tdd.md +42 -39
- package/docs/workflows/to-spec.md +83 -0
- package/docs/workflows/to-tickets.md +80 -0
- package/docs/workflows/todo-driven-workflow.md +34 -36
- package/docs/workflows/using-git-worktrees.md +12 -8
- package/docs/workflows/verification-loop.md +16 -14
- package/docs/workflows/verify-before-claim.md +12 -8
- package/docs/workflows/zoom-out.md +22 -10
- package/environment-detection/SKILL.md +25 -61
- package/environment-detection/references/shell-syntax-rules.md +76 -0
- package/environment-detection/scripts/preflight.js +103 -93
- package/eval-framework/fixtures/bad-frontmatter-colon/SKILL.md +14 -0
- package/eval-framework/fixtures/duplicate-desc-skill-a/SKILL.md +14 -0
- package/eval-framework/fixtures/duplicate-desc-skill-b/SKILL.md +14 -0
- package/eval-framework/fixtures/missing-delimiter/SKILL.md +13 -0
- package/eval-framework/fixtures/over-budget-skill/SKILL.md +36 -0
- package/eval-harness/SKILL.md +34 -51
- package/eval-harness/references/scoring-rubric.md +68 -0
- package/eval-harness/scripts/evaluate.js +77 -61
- package/evals/environment-detection/eval.yaml +26 -0
- package/evals/environment-detection/tasks/negative-trigger.yaml +16 -0
- package/evals/environment-detection/tasks/positive-trigger.yaml +15 -0
- package/evals/eval-harness/eval.yaml +26 -0
- package/evals/eval-harness/tasks/negative-trigger.yaml +16 -0
- package/evals/eval-harness/tasks/positive-trigger.yaml +15 -0
- package/evals/fable-discipline/eval.yaml +26 -0
- package/evals/fable-discipline/tasks/negative-trigger.yaml +16 -0
- package/evals/fable-discipline/tasks/positive-trigger.yaml +15 -0
- package/evals/fable-mode/eval.yaml +26 -0
- package/evals/fable-mode/tasks/negative-tier2-no-model.yaml +18 -0
- package/evals/fable-mode/tasks/negative-trigger.yaml +16 -0
- package/evals/fable-mode/tasks/positive-haiku-mode.yaml +16 -0
- package/evals/fable-mode/tasks/positive-opus-mode.yaml +16 -0
- package/evals/fable-mode/tasks/positive-sonnet-mode.yaml +16 -0
- package/evals/fable-mode/tasks/positive-trigger.yaml +15 -0
- package/evals/find-skills/eval.yaml +26 -0
- package/evals/find-skills/tasks/negative-trigger.yaml +16 -0
- package/evals/find-skills/tasks/positive-trigger.yaml +15 -0
- package/evals/git-commit/eval.yaml +26 -0
- package/evals/git-commit/tasks/negative-trigger.yaml +16 -0
- package/evals/git-commit/tasks/positive-trigger.yaml +15 -0
- package/evals/grill-me/eval.yaml +26 -0
- package/evals/grill-me/tasks/negative-trigger.yaml +16 -0
- package/evals/grill-me/tasks/positive-trigger.yaml +15 -0
- package/evals/grill-with-docs/eval.yaml +26 -0
- package/evals/grill-with-docs/tasks/negative-trigger.yaml +16 -0
- package/evals/grill-with-docs/tasks/positive-trigger.yaml +15 -0
- package/evals/harness-everything/eval.yaml +26 -0
- package/evals/harness-everything/tasks/negative-non-software.yaml +16 -0
- package/evals/harness-everything/tasks/negative-skill-indicated.yaml +15 -0
- package/evals/harness-everything/tasks/positive-tier1.yaml +16 -0
- package/evals/harness-everything/tasks/positive-tier2.yaml +16 -0
- package/evals/harness-everything/tasks/positive-tier3.yaml +16 -0
- package/evals/improve-codebase-architecture/eval.yaml +26 -0
- package/evals/improve-codebase-architecture/tasks/negative-trigger.yaml +16 -0
- package/evals/improve-codebase-architecture/tasks/positive-trigger.yaml +15 -0
- package/evals/install-cognitive-os/eval.yaml +26 -0
- package/evals/install-cognitive-os/tasks/negative-trigger.yaml +16 -0
- package/evals/install-cognitive-os/tasks/positive-trigger.yaml +15 -0
- package/evals/multi-agent-workspace/eval.yaml +26 -0
- package/evals/multi-agent-workspace/tasks/negative-trigger.yaml +15 -0
- package/evals/multi-agent-workspace/tasks/positive-trigger.yaml +15 -0
- package/evals/repo-docs/eval.yaml +26 -0
- package/evals/repo-docs/tasks/negative-trigger.yaml +16 -0
- package/evals/repo-docs/tasks/positive-trigger.yaml +15 -0
- package/evals/rewrite-commits/eval.yaml +26 -0
- package/evals/rewrite-commits/tasks/negative-trigger.yaml +16 -0
- package/evals/rewrite-commits/tasks/positive-trigger.yaml +15 -0
- package/evals/security-review/eval.yaml +26 -0
- package/evals/security-review/tasks/negative-trigger.yaml +16 -0
- package/evals/security-review/tasks/positive-trigger.yaml +15 -0
- package/evals/self-evolve/eval.yaml +26 -0
- package/evals/self-evolve/tasks/negative-trigger.yaml +16 -0
- package/evals/self-evolve/tasks/positive-trigger.yaml +15 -0
- package/evals/skill-creator/eval.yaml +26 -0
- package/evals/skill-creator/tasks/negative-trigger.yaml +16 -0
- package/evals/skill-creator/tasks/positive-trigger.yaml +15 -0
- package/evals/skill-style/eval.yaml +26 -0
- package/evals/skill-style/tasks/negative-trigger.yaml +16 -0
- package/evals/skill-style/tasks/positive-trigger.yaml +15 -0
- package/evals/tdd/eval.yaml +26 -0
- package/evals/tdd/tasks/negative-trivia.yaml +16 -0
- package/evals/tdd/tasks/positive-bugfix.yaml +15 -0
- package/evals/tdd/tasks/positive-feature.yaml +16 -0
- package/evals/tdd/tasks/positive-refactor.yaml +15 -0
- package/evals/to-spec/eval.yaml +26 -0
- package/evals/to-spec/tasks/negative-trigger.yaml +16 -0
- package/evals/to-spec/tasks/positive-trigger.yaml +15 -0
- package/evals/to-tickets/eval.yaml +26 -0
- package/evals/to-tickets/tasks/negative-trigger.yaml +15 -0
- package/evals/to-tickets/tasks/positive-trigger.yaml +15 -0
- package/evals/todo-driven-workflow/eval.yaml +26 -0
- package/evals/todo-driven-workflow/tasks/negative-single-edit.yaml +16 -0
- package/evals/todo-driven-workflow/tasks/positive-multi-step.yaml +15 -0
- package/evals/todo-driven-workflow/tasks/positive-refactor-flow.yaml +15 -0
- package/evals/using-git-worktrees/eval.yaml +26 -0
- package/evals/using-git-worktrees/tasks/negative-trigger.yaml +15 -0
- package/evals/using-git-worktrees/tasks/positive-trigger.yaml +15 -0
- package/evals/verification-loop/eval.yaml +26 -0
- package/evals/verification-loop/tasks/negative-discussion.yaml +16 -0
- package/evals/verification-loop/tasks/positive-pre-ship.yaml +15 -0
- package/evals/verify-before-claim/eval.yaml +26 -0
- package/evals/verify-before-claim/tasks/negative-trigger.yaml +16 -0
- package/evals/verify-before-claim/tasks/positive-trigger.yaml +15 -0
- package/evals/zoom-out/eval.yaml +26 -0
- package/evals/zoom-out/tasks/negative-trivial-edit.yaml +16 -0
- package/evals/zoom-out/tasks/positive-repeated-failure.yaml +15 -0
- package/fable-discipline/SKILL.md +31 -28
- package/fable-discipline/references/discipline-rules.md +22 -0
- package/fable-mode/CONTRACT-FORMAT.md +51 -51
- package/fable-mode/SKILL.md +31 -43
- package/fable-mode/agents/fable-orchestrator.md +99 -92
- package/fable-mode/agents/fable-verifier.md +32 -32
- package/fable-mode/agents/fable-worker-haiku.md +52 -48
- package/fable-mode/agents/fable-worker-sonnet.md +53 -49
- package/fable-mode/execution-guardrails/SKILL.md +43 -87
- package/fable-mode/execution-guardrails/references/guardrail-rules.md +56 -0
- package/fable-mode/fable-haiku/SKILL.md +36 -48
- package/fable-mode/fable-haiku/references/routing-notes.md +26 -0
- package/fable-mode/fable-opus/SKILL.md +36 -0
- package/fable-mode/fable-sonnet/SKILL.md +36 -0
- package/fable-mode/model-matrix.json +32 -0
- package/fable-mode/references/execution-phases.md +37 -0
- package/fable-mode/references/model-matrix.md +39 -0
- package/fable-mode/scripts/model-selector.js +129 -0
- package/find-skills/SKILL.md +48 -0
- package/find-skills/references/discovery-flow.md +102 -0
- package/find-skills/scripts/use-skill.js +106 -0
- package/git-commit/SKILL.md +35 -45
- package/git-commit/guides/ANGULAR_STYLE.md +60 -60
- package/git-commit/guides/COMMIT_GENERATION.md +23 -23
- package/git-commit/guides/LANGUAGE_DETECTION.md +16 -16
- package/git-commit/guides/MAIN_REPO.md +14 -14
- package/git-commit/guides/SUBMODULES.md +27 -27
- package/git-commit/references/commit-flow.md +30 -0
- package/grill-me/SKILL.md +34 -27
- package/grill-me/references/grilling-playbook.md +38 -0
- package/grill-with-docs/ADR-FORMAT.md +47 -47
- package/grill-with-docs/CONTEXT-FORMAT.md +63 -63
- package/grill-with-docs/SKILL.md +33 -91
- package/grill-with-docs/references/session-playbook.md +97 -0
- package/harness-everything/SKILL.md +29 -128
- package/harness-everything/examples/README.md +9 -9
- package/harness-everything/examples/todo-workflow.md +22 -22
- package/harness-everything/references/skill-registry.md +39 -0
- package/harness-everything/references/triage-and-tiers.md +116 -0
- package/harness-everything/scripts/bootstrap.js +203 -140
- package/harness-everything/scripts/routing-keywords.json +320 -0
- package/harness-everything/scripts/self-heal.js +241 -189
- package/harness-everything/scripts/tier-router.js +334 -219
- package/harness-everything/scripts/verify-gate.js +100 -31
- package/hooks/hooks.json +155 -155
- package/hooks/scripts/atomic-commit-check.js +68 -68
- package/hooks/scripts/boundary-guard.js +55 -55
- package/hooks/scripts/context-compact.js +114 -114
- package/hooks/scripts/contract-test.js +79 -79
- package/hooks/scripts/depth-guard.js +65 -65
- package/hooks/scripts/lib/harness-state.js +139 -228
- package/hooks/scripts/lib/platforms/claude.js +72 -19
- package/hooks/scripts/lib/platforms/codex.js +24 -6
- package/hooks/scripts/lib/platforms/continue.js +23 -5
- package/hooks/scripts/lib/platforms/copilot.js +23 -5
- package/hooks/scripts/lib/platforms/cursor.js +23 -5
- package/hooks/scripts/lib/platforms/hermes.js +57 -57
- package/hooks/scripts/lib/platforms/index.js +17 -17
- package/hooks/scripts/lib/platforms/worktrees.js +20 -20
- package/hooks/scripts/reset-circuit-breaker.js +30 -30
- package/hooks/scripts/rule-of-3-tracker.js +124 -91
- package/hooks/scripts/rule-of-3.js +187 -176
- package/hooks/scripts/state-persist.js +99 -99
- package/hooks/scripts/stop-gate.js +80 -80
- package/hooks/scripts/subagent-scope-guard.js +88 -88
- package/improve-codebase-architecture/SKILL.md +31 -35
- package/improve-codebase-architecture/guides/DEEPENING.md +37 -37
- package/improve-codebase-architecture/guides/HTML-REPORT.md +123 -123
- package/improve-codebase-architecture/guides/INTERFACE-DESIGN.md +44 -44
- package/improve-codebase-architecture/guides/LANGUAGE.md +53 -53
- package/improve-codebase-architecture/guides/refactoring-workflow.md +59 -0
- package/install-cognitive-os/SKILL.md +23 -80
- package/install-cognitive-os/references/cognitive-loop.md +27 -0
- package/multi-agent-workspace/NOTICE-agency-agents.md +27 -0
- package/multi-agent-workspace/SKILL.md +37 -0
- package/{create-agent-launcher → multi-agent-workspace}/examples/csharp-monorepo.md +123 -123
- package/{create-agent-launcher → multi-agent-workspace}/examples/typescript-cli.md +126 -126
- package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-claude.md +77 -77
- package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-codex.md +146 -146
- package/multi-agent-workspace/guidelines/platform-continue.md +38 -0
- package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-copilot.md +74 -74
- package/multi-agent-workspace/guidelines/platform-cursor.md +40 -0
- package/multi-agent-workspace/guidelines/platform-hermes.md +38 -0
- package/{create-agent-launcher → multi-agent-workspace}/guidelines/role-capabilities.md +108 -108
- package/multi-agent-workspace/references/agency-agents.md +31 -0
- package/multi-agent-workspace/references/architecture-guide.md +32 -0
- package/multi-agent-workspace/references/orchestration.md +48 -0
- package/multi-agent-workspace/scripts/agency-catalog.js +190 -0
- package/multi-agent-workspace/scripts/index_memory.js +51 -0
- package/multi-agent-workspace/scripts/scaffold.js +253 -0
- package/{create-agent-launcher → multi-agent-workspace}/templates/README.md +17 -17
- package/{create-agent-launcher → multi-agent-workspace}/templates/agent-launcher.md +67 -67
- package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-csharp.md +55 -55
- package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-polyglot.md +61 -61
- package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-ts.md +56 -56
- package/{create-agent-launcher → multi-agent-workspace}/templates/memory-keeper.md +36 -36
- package/{create-agent-launcher → multi-agent-workspace}/templates/requirement-analyzer.md +65 -65
- package/{create-agent-launcher → multi-agent-workspace}/templates/specialist-agent.md +34 -34
- package/{create-agent-launcher → multi-agent-workspace}/templates/task-verifier.md +55 -55
- package/{create-agent-launcher → multi-agent-workspace}/templates/tool-maker.md +32 -32
- package/multi-agent-workspace/workflows/01-init.md +22 -0
- package/multi-agent-workspace/workflows/02-analysis.md +23 -0
- package/multi-agent-workspace/workflows/03-generation.md +27 -0
- package/multi-agent-workspace/workflows/04-launcher.md +16 -0
- package/opencode-plugin/README.md +94 -0
- package/opencode-plugin/hooks/circuit-breaker.js +121 -0
- package/opencode-plugin/hooks/compliance.js +128 -0
- package/opencode-plugin/hooks/post-edit.js +62 -0
- package/opencode-plugin/hooks/pre-complete.js +65 -0
- package/opencode-plugin/hooks/verify.js +140 -0
- package/opencode-plugin/plugin.json +17 -0
- package/opencode-plugin/test-hook-firing.js +198 -0
- package/package.json +50 -22
- package/references/definition-of-done.md +67 -0
- package/references/performance-checklist.md +153 -0
- package/references/platform-advisory-template.md +58 -0
- package/references/security-checklist.md +205 -0
- package/repo-docs/SKILL.md +38 -37
- package/repo-docs/references/process-guide.md +60 -0
- package/repo-docs/templates/agents-template.md +264 -264
- package/repo-docs/templates/knowledge-agents-template.md +50 -50
- package/repo-docs/templates/knowledge-readme-template.md +83 -83
- package/repo-docs/templates/manual-recon.md +117 -117
- package/repo-docs/templates/multi-skills-readme-template.md +72 -72
- package/repo-docs/templates/product-agents-template.md +78 -78
- package/repo-docs/templates/product-readme-template.md +95 -95
- package/repo-docs/templates/readme-template.md +136 -136
- package/repo-docs/templates/single-skill-readme-template.md +70 -70
- package/repo-docs/templates/skills-agents-template.md +60 -60
- package/rewrite-commits/SKILL.md +22 -17
- package/rewrite-commits/references/workflow.md +18 -0
- package/scripts/installer.js +546 -506
- package/scripts/lib/advisory-text.js +8 -4
- package/scripts/lib/claude-hooks.js +18 -5
- package/scripts/lib/gitignore.js +199 -80
- package/scripts/lib/manifest.js +68 -4
- package/scripts/lib/prompts.js +1 -1
- package/scripts/lib/skills.js +87 -1
- package/scripts/verify-install.js +147 -0
- package/security-review/SKILL.md +35 -496
- package/security-review/guides/OWASP-PATTERNS.md +31 -0
- package/security-review/guides/STRIDE-THREAT-MODEL.md +21 -0
- package/security-review/references/security-checklist.md +478 -0
- package/security-review/scripts/audit-secrets.js +84 -0
- package/self-evolve/SKILL.md +38 -45
- package/self-evolve/references/memory-resolution.md +58 -0
- package/self-evolve/scripts/persist-memory.js +139 -40
- package/self-evolve/scripts/register-dynamic-skill.js +251 -0
- package/self-evolve/scripts/self-regression.js +110 -113
- package/skill-creator/SKILL.md +34 -76
- package/skill-creator/references/authoring-workflow.md +14 -0
- package/skill-creator/references/dynamic-generation-contract.md +21 -0
- package/skill-creator/references/quality-checklist.md +15 -0
- package/skill-creator/references/quality-principles.md +81 -81
- package/skill-creator/references/testing-workflow.md +27 -32
- package/skill-style/SKILL.md +33 -39
- package/skill-style/references/style-guide.md +36 -0
- package/tdd/SKILL.md +34 -43
- package/tdd/guides/deep-modules.md +33 -33
- package/tdd/guides/interface-design.md +31 -31
- package/tdd/guides/mocking.md +59 -59
- package/tdd/guides/refactoring.md +10 -10
- package/tdd/guides/tests.md +61 -61
- package/tdd/references/core-discipline.md +49 -0
- package/to-spec/SKILL.md +42 -0
- package/to-spec/references/process.md +77 -0
- package/to-spec/scripts/check-project-docs.js +259 -0
- package/to-spec/templates/cli-reference.md +31 -0
- package/to-spec/templates/dev-doc.md +27 -0
- package/to-spec/templates/feature-spec.md +59 -0
- package/to-spec/templates/schema-doc.md +31 -0
- package/to-tickets/SKILL.md +42 -0
- package/to-tickets/references/publishing-and-templates.md +97 -0
- package/todo-driven-workflow/SKILL.md +27 -41
- package/todo-driven-workflow/references/execution-guide.md +27 -0
- package/using-git-worktrees/SKILL.md +29 -141
- package/using-git-worktrees/references/workflow-details.md +108 -0
- package/verification-loop/SKILL.md +29 -121
- package/verification-loop/references/verification-phases.md +116 -0
- package/verification-loop/templates/verification-report.template.md +15 -0
- package/verify-before-claim/SKILL.md +27 -70
- package/verify-before-claim/references/verification-guide.md +73 -0
- package/zoom-out/SKILL.md +28 -76
- package/zoom-out/references/circuit-breaker.md +66 -0
- package/zoom-out/templates/zoom-out-report.template.md +20 -0
- package/build-multi-agent-system/AGENTS.md +0 -50
- package/build-multi-agent-system/README.md +0 -63
- package/build-multi-agent-system/SKILL.md +0 -68
- package/create-agent-launcher/SKILL.md +0 -48
- package/create-agent-launcher/guidelines/platform-gemini.md +0 -101
- package/create-agent-launcher/workflows/01-init.md +0 -22
- package/create-agent-launcher/workflows/02-analysis.md +0 -26
- package/create-agent-launcher/workflows/03-generation.md +0 -29
- package/create-agent-launcher/workflows/04-launcher.md +0 -20
- package/docs/workflows/build-multi-agent-system.md +0 -62
- package/docs/workflows/create-agent-launcher.md +0 -62
- package/eval-framework/behavioral-test.js +0 -105
- package/eval-framework/mechanism-test.js +0 -251
- package/harness-everything/scripts/todo-cli.js +0 -157
- package/skill-style/STYLE.md +0 -37
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Boundary Guard (PreToolUse: Grep|Glob|Read)
|
|
4
|
-
* Hard-blocks two concrete sources of context bloat / hallucination risk:
|
|
5
|
-
* 1. Reading a large file whole instead of a scoped chunk (offset/limit).
|
|
6
|
-
* 2. Searching inside known noise directories (node_modules, .git, build
|
|
7
|
-
* output, etc.) that produce huge, low-signal result sets.
|
|
8
|
-
* Fails open on any parse/lookup error - never blocks due to a bug here.
|
|
9
|
-
*/
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
|
|
12
|
-
const MAX_BYTES_WITHOUT_LIMIT = 512 * 1024; // 512KB
|
|
13
|
-
const NOISE_DIRS = ['node_modules', '.git', 'dist', 'build', 'out', '.next', 'target', 'vendor', '__pycache__', '.venv', 'coverage'];
|
|
14
|
-
|
|
15
|
-
let inputData = '';
|
|
16
|
-
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
17
|
-
process.stdin.on('end', () => {
|
|
18
|
-
try {
|
|
19
|
-
const payload = JSON.parse(inputData);
|
|
20
|
-
const toolName = payload.tool_name;
|
|
21
|
-
const input = payload.tool_input || {};
|
|
22
|
-
|
|
23
|
-
if (toolName === 'Read') {
|
|
24
|
-
const filePath = input.file_path;
|
|
25
|
-
if (filePath && !input.limit && fs.existsSync(filePath)) {
|
|
26
|
-
const stat = fs.statSync(filePath);
|
|
27
|
-
if (stat.isFile() && stat.size > MAX_BYTES_WITHOUT_LIMIT) {
|
|
28
|
-
console.error(`[Boundary Guard] BLOCKED: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
|
|
29
|
-
console.error(`Reading a file this large in one call risks context bloat and "lost in the middle" degradation.`);
|
|
30
|
-
console.error(`Re-issue the Read with an explicit "offset"/"limit" to pull a targeted slice, or use Grep to locate the relevant section first.`);
|
|
31
|
-
process.exit(2);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (toolName === 'Grep' || toolName === 'Glob') {
|
|
37
|
-
const searchPath = input.path || '';
|
|
38
|
-
const pattern = input.pattern || '';
|
|
39
|
-
const hitsNoiseDir = NOISE_DIRS.some(dir => {
|
|
40
|
-
const asPathSegment = new RegExp(`(^|[\\\\/])${dir}($|[\\\\/])`);
|
|
41
|
-
return asPathSegment.test(searchPath) || asPathSegment.test(pattern);
|
|
42
|
-
});
|
|
43
|
-
if (hitsNoiseDir) {
|
|
44
|
-
console.error(`[Boundary Guard] BLOCKED: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
|
|
45
|
-
console.error(`These produce huge, low-signal result sets and rarely contain what you're actually looking for.`);
|
|
46
|
-
console.error(`Scope the search to source directories instead, or state explicitly why this directory must be searched.`);
|
|
47
|
-
process.exit(2);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
process.exit(0);
|
|
52
|
-
} catch (err) {
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Boundary Guard (PreToolUse: Grep|Glob|Read)
|
|
4
|
+
* Hard-blocks two concrete sources of context bloat / hallucination risk:
|
|
5
|
+
* 1. Reading a large file whole instead of a scoped chunk (offset/limit).
|
|
6
|
+
* 2. Searching inside known noise directories (node_modules, .git, build
|
|
7
|
+
* output, etc.) that produce huge, low-signal result sets.
|
|
8
|
+
* Fails open on any parse/lookup error - never blocks due to a bug here.
|
|
9
|
+
*/
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
const MAX_BYTES_WITHOUT_LIMIT = 512 * 1024; // 512KB
|
|
13
|
+
const NOISE_DIRS = ['node_modules', '.git', 'dist', 'build', 'out', '.next', 'target', 'vendor', '__pycache__', '.venv', 'coverage'];
|
|
14
|
+
|
|
15
|
+
let inputData = '';
|
|
16
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
17
|
+
process.stdin.on('end', () => {
|
|
18
|
+
try {
|
|
19
|
+
const payload = JSON.parse(inputData);
|
|
20
|
+
const toolName = payload.tool_name;
|
|
21
|
+
const input = payload.tool_input || {};
|
|
22
|
+
|
|
23
|
+
if (toolName === 'Read') {
|
|
24
|
+
const filePath = input.file_path;
|
|
25
|
+
if (filePath && !input.limit && fs.existsSync(filePath)) {
|
|
26
|
+
const stat = fs.statSync(filePath);
|
|
27
|
+
if (stat.isFile() && stat.size > MAX_BYTES_WITHOUT_LIMIT) {
|
|
28
|
+
console.error(`[Boundary Guard] BLOCKED: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
|
|
29
|
+
console.error(`Reading a file this large in one call risks context bloat and "lost in the middle" degradation.`);
|
|
30
|
+
console.error(`Re-issue the Read with an explicit "offset"/"limit" to pull a targeted slice, or use Grep to locate the relevant section first.`);
|
|
31
|
+
process.exit(2);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (toolName === 'Grep' || toolName === 'Glob') {
|
|
37
|
+
const searchPath = input.path || '';
|
|
38
|
+
const pattern = input.pattern || '';
|
|
39
|
+
const hitsNoiseDir = NOISE_DIRS.some(dir => {
|
|
40
|
+
const asPathSegment = new RegExp(`(^|[\\\\/])${dir}($|[\\\\/])`);
|
|
41
|
+
return asPathSegment.test(searchPath) || asPathSegment.test(pattern);
|
|
42
|
+
});
|
|
43
|
+
if (hitsNoiseDir) {
|
|
44
|
+
console.error(`[Boundary Guard] BLOCKED: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
|
|
45
|
+
console.error(`These produce huge, low-signal result sets and rarely contain what you're actually looking for.`);
|
|
46
|
+
console.error(`Scope the search to source directories instead, or state explicitly why this directory must be searched.`);
|
|
47
|
+
process.exit(2);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
process.exit(0);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { execSync } = require('child_process');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { getWorkspaceRoot, getSessionDir } = require('./lib/harness-state');
|
|
6
|
-
|
|
7
|
-
function main(payload) {
|
|
8
|
-
try {
|
|
9
|
-
// Let's run a quick Git check to estimate context size from modified files
|
|
10
|
-
const statusRaw = execSync('git status --porcelain', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
11
|
-
if (!statusRaw) {
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const lines = statusRaw.split('\n').filter(Boolean);
|
|
16
|
-
const modifiedCount = lines.length;
|
|
17
|
-
|
|
18
|
-
let totalDiffLines = 0;
|
|
19
|
-
try {
|
|
20
|
-
const diffStat = execSync('git diff --numstat', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
21
|
-
if (diffStat) {
|
|
22
|
-
diffStat.split('\n').forEach(line => {
|
|
23
|
-
const [added, deleted] = line.split('\t');
|
|
24
|
-
if (added && added !== '-' && deleted && deleted !== '-') {
|
|
25
|
-
totalDiffLines += parseInt(added) + parseInt(deleted);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
} catch (err) {
|
|
30
|
-
// Ignore git errors
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Thresholds for warning
|
|
34
|
-
const HIGH_FILE_LIMIT = 6;
|
|
35
|
-
const HIGH_LINE_LIMIT = 400;
|
|
36
|
-
|
|
37
|
-
const overThreshold = modifiedCount >= HIGH_FILE_LIMIT || totalDiffLines >= HIGH_LINE_LIMIT;
|
|
38
|
-
|
|
39
|
-
// Throttle: this hook fires on EVERY Bash/Edit/Write call, and a warning
|
|
40
|
-
// about context bloat that repeats on every call becomes context bloat
|
|
41
|
-
// itself (and trains the model to ignore hook output). Warn on the first
|
|
42
|
-
// crossing, then only every 10th call while still over - or when the diff
|
|
43
|
-
// has grown another 50% since the last warning.
|
|
44
|
-
const stateFile = path.join(getSessionDir(getWorkspaceRoot(), payload && payload.session_id), 'context-compact-state.json');
|
|
45
|
-
let state = { overCount: 0, lastWarnedLines: 0 };
|
|
46
|
-
try {
|
|
47
|
-
if (fs.existsSync(stateFile)) state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
48
|
-
} catch (err) { /* use default */ }
|
|
49
|
-
|
|
50
|
-
if (!overThreshold) {
|
|
51
|
-
if (state.overCount > 0) {
|
|
52
|
-
try {
|
|
53
|
-
fs.writeFileSync(stateFile, JSON.stringify({ overCount: 0, lastWarnedLines: 0 }), 'utf8');
|
|
54
|
-
} catch (err) { /* ignore */ }
|
|
55
|
-
}
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
state.overCount += 1;
|
|
60
|
-
const onBeat = state.overCount === 1 || state.overCount % 10 === 0;
|
|
61
|
-
const grewALot = totalDiffLines >= (state.lastWarnedLines || 0) * 1.5 && totalDiffLines > state.lastWarnedLines;
|
|
62
|
-
const shouldWarn = onBeat || grewALot;
|
|
63
|
-
if (shouldWarn) state.lastWarnedLines = totalDiffLines;
|
|
64
|
-
try {
|
|
65
|
-
fs.writeFileSync(stateFile, JSON.stringify(state), 'utf8');
|
|
66
|
-
} catch (err) { /* ignore */ }
|
|
67
|
-
|
|
68
|
-
if (shouldWarn) {
|
|
69
|
-
// Plain stdout on exit 0 is only surfaced to Claude for UserPromptSubmit/
|
|
70
|
-
// SessionStart - for PreToolUse it's written to a debug log Claude never
|
|
71
|
-
// sees. To actually get an advisory (non-blocking) message in front of
|
|
72
|
-
// Claude here, it has to go through hookSpecificOutput.additionalContext.
|
|
73
|
-
const message = [
|
|
74
|
-
`Harness OS - Context Bloat Warning`,
|
|
75
|
-
`- Modified Files: ${modifiedCount}`,
|
|
76
|
-
`- Accumulated Diff: ${totalDiffLines} lines`,
|
|
77
|
-
``,
|
|
78
|
-
`Caution: Large number of modified files or big diffs will bloat the Agent context window, leading to:`,
|
|
79
|
-
` 1. "Lost in the Middle" reasoning degradation`,
|
|
80
|
-
` 2. Rapidly inflating token costs`,
|
|
81
|
-
``,
|
|
82
|
-
`Recommended Action:`,
|
|
83
|
-
` - Run atomic commits or stage completed files.`,
|
|
84
|
-
` - Use targeted sub-folders rather than broad searches.`,
|
|
85
|
-
` - Ask user to run '/compact' or '/clear' if supported.`
|
|
86
|
-
].join('\n');
|
|
87
|
-
|
|
88
|
-
console.log(JSON.stringify({
|
|
89
|
-
hookSpecificOutput: {
|
|
90
|
-
hookEventName: "PreToolUse",
|
|
91
|
-
additionalContext: message
|
|
92
|
-
}
|
|
93
|
-
}));
|
|
94
|
-
}
|
|
95
|
-
} catch (err) {
|
|
96
|
-
// Fail open - never block user execution on compaction checker
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
process.exit(0);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
let inputData = '';
|
|
103
|
-
const timeout = setTimeout(() => { main(null); }, 200);
|
|
104
|
-
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
105
|
-
process.stdin.on('end', () => {
|
|
106
|
-
clearTimeout(timeout);
|
|
107
|
-
let payload = null;
|
|
108
|
-
try { payload = JSON.parse(inputData.trim()); } catch (err) { /* no payload */ }
|
|
109
|
-
main(payload);
|
|
110
|
-
});
|
|
111
|
-
process.stdin.on('error', () => {
|
|
112
|
-
clearTimeout(timeout);
|
|
113
|
-
main(null);
|
|
114
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { getWorkspaceRoot, getSessionDir } = require('./lib/harness-state');
|
|
6
|
+
|
|
7
|
+
function main(payload) {
|
|
8
|
+
try {
|
|
9
|
+
// Let's run a quick Git check to estimate context size from modified files
|
|
10
|
+
const statusRaw = execSync('git status --porcelain', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
11
|
+
if (!statusRaw) {
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const lines = statusRaw.split('\n').filter(Boolean);
|
|
16
|
+
const modifiedCount = lines.length;
|
|
17
|
+
|
|
18
|
+
let totalDiffLines = 0;
|
|
19
|
+
try {
|
|
20
|
+
const diffStat = execSync('git diff --numstat', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
21
|
+
if (diffStat) {
|
|
22
|
+
diffStat.split('\n').forEach(line => {
|
|
23
|
+
const [added, deleted] = line.split('\t');
|
|
24
|
+
if (added && added !== '-' && deleted && deleted !== '-') {
|
|
25
|
+
totalDiffLines += parseInt(added) + parseInt(deleted);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// Ignore git errors
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Thresholds for warning
|
|
34
|
+
const HIGH_FILE_LIMIT = 6;
|
|
35
|
+
const HIGH_LINE_LIMIT = 400;
|
|
36
|
+
|
|
37
|
+
const overThreshold = modifiedCount >= HIGH_FILE_LIMIT || totalDiffLines >= HIGH_LINE_LIMIT;
|
|
38
|
+
|
|
39
|
+
// Throttle: this hook fires on EVERY Bash/Edit/Write call, and a warning
|
|
40
|
+
// about context bloat that repeats on every call becomes context bloat
|
|
41
|
+
// itself (and trains the model to ignore hook output). Warn on the first
|
|
42
|
+
// crossing, then only every 10th call while still over - or when the diff
|
|
43
|
+
// has grown another 50% since the last warning.
|
|
44
|
+
const stateFile = path.join(getSessionDir(getWorkspaceRoot(), payload && payload.session_id), 'context-compact-state.json');
|
|
45
|
+
let state = { overCount: 0, lastWarnedLines: 0 };
|
|
46
|
+
try {
|
|
47
|
+
if (fs.existsSync(stateFile)) state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
48
|
+
} catch (err) { /* use default */ }
|
|
49
|
+
|
|
50
|
+
if (!overThreshold) {
|
|
51
|
+
if (state.overCount > 0) {
|
|
52
|
+
try {
|
|
53
|
+
fs.writeFileSync(stateFile, JSON.stringify({ overCount: 0, lastWarnedLines: 0 }), 'utf8');
|
|
54
|
+
} catch (err) { /* ignore */ }
|
|
55
|
+
}
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
state.overCount += 1;
|
|
60
|
+
const onBeat = state.overCount === 1 || state.overCount % 10 === 0;
|
|
61
|
+
const grewALot = totalDiffLines >= (state.lastWarnedLines || 0) * 1.5 && totalDiffLines > state.lastWarnedLines;
|
|
62
|
+
const shouldWarn = onBeat || grewALot;
|
|
63
|
+
if (shouldWarn) state.lastWarnedLines = totalDiffLines;
|
|
64
|
+
try {
|
|
65
|
+
fs.writeFileSync(stateFile, JSON.stringify(state), 'utf8');
|
|
66
|
+
} catch (err) { /* ignore */ }
|
|
67
|
+
|
|
68
|
+
if (shouldWarn) {
|
|
69
|
+
// Plain stdout on exit 0 is only surfaced to Claude for UserPromptSubmit/
|
|
70
|
+
// SessionStart - for PreToolUse it's written to a debug log Claude never
|
|
71
|
+
// sees. To actually get an advisory (non-blocking) message in front of
|
|
72
|
+
// Claude here, it has to go through hookSpecificOutput.additionalContext.
|
|
73
|
+
const message = [
|
|
74
|
+
`Harness OS - Context Bloat Warning`,
|
|
75
|
+
`- Modified Files: ${modifiedCount}`,
|
|
76
|
+
`- Accumulated Diff: ${totalDiffLines} lines`,
|
|
77
|
+
``,
|
|
78
|
+
`Caution: Large number of modified files or big diffs will bloat the Agent context window, leading to:`,
|
|
79
|
+
` 1. "Lost in the Middle" reasoning degradation`,
|
|
80
|
+
` 2. Rapidly inflating token costs`,
|
|
81
|
+
``,
|
|
82
|
+
`Recommended Action:`,
|
|
83
|
+
` - Run atomic commits or stage completed files.`,
|
|
84
|
+
` - Use targeted sub-folders rather than broad searches.`,
|
|
85
|
+
` - Ask user to run '/compact' or '/clear' if supported.`
|
|
86
|
+
].join('\n');
|
|
87
|
+
|
|
88
|
+
console.log(JSON.stringify({
|
|
89
|
+
hookSpecificOutput: {
|
|
90
|
+
hookEventName: "PreToolUse",
|
|
91
|
+
additionalContext: message
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
// Fail open - never block user execution on compaction checker
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let inputData = '';
|
|
103
|
+
const timeout = setTimeout(() => { main(null); }, 200);
|
|
104
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
105
|
+
process.stdin.on('end', () => {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
let payload = null;
|
|
108
|
+
try { payload = JSON.parse(inputData.trim()); } catch (err) { /* no payload */ }
|
|
109
|
+
main(payload);
|
|
110
|
+
});
|
|
111
|
+
process.stdin.on('error', () => {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
main(null);
|
|
114
|
+
});
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Contract Test (PostToolUse: Bash|PowerShell)
|
|
4
|
-
* Resolves fable-mode stage contracts. fable-orchestrator's discipline says
|
|
5
|
-
* every stage check must be "re-run or spot-checked... before building on
|
|
6
|
-
* its output" - but a verbal claim of "I re-ran it" isn't auditable. So the
|
|
7
|
-
* orchestrator now writes .claude/harness-state/contracts/<stageId>.json with
|
|
8
|
-
* status:"pending" and the exact checkCommand BEFORE running it. This hook
|
|
9
|
-
* watches every shell call; when the command matches a pending contract's
|
|
10
|
-
* checkCommand verbatim, it records pass/fail into that manifest using the
|
|
11
|
-
* same exitCode-or-stderr heuristic as rule-of-3-tracker.js.
|
|
12
|
-
* Contracts are shared across sessions, not scoped to one - the orchestrator
|
|
13
|
-
* writes them proactively (not in response to a hook message) and has no
|
|
14
|
-
* clean way to learn its own session_id, so a collision only matters if two
|
|
15
|
-
* fable-mode orchestrations run in the same repo at once.
|
|
16
|
-
* Contracts are audit trail, not synchronous enforcement - EXCEPT when a
|
|
17
|
-
* check this hook just resolved comes back FAILED, it surfaces that loudly
|
|
18
|
-
* (exit 2) so silently building on a failed stage doesn't slip through.
|
|
19
|
-
* Fails open on any parse/lookup error.
|
|
20
|
-
*/
|
|
21
|
-
const fs = require('fs');
|
|
22
|
-
const path = require('path');
|
|
23
|
-
const { getWorkspaceRoot, getStateRoot } = require('./lib/harness-state');
|
|
24
|
-
|
|
25
|
-
let inputData = '';
|
|
26
|
-
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
27
|
-
process.stdin.on('end', () => {
|
|
28
|
-
try {
|
|
29
|
-
const payload = JSON.parse(inputData);
|
|
30
|
-
if (payload.tool_name !== 'Bash' && payload.tool_name !== 'PowerShell') process.exit(0);
|
|
31
|
-
|
|
32
|
-
const command = ((payload.tool_input && payload.tool_input.command) || '').trim();
|
|
33
|
-
if (!command) process.exit(0);
|
|
34
|
-
|
|
35
|
-
const contractsDir = path.join(getStateRoot(getWorkspaceRoot()), 'contracts');
|
|
36
|
-
if (!fs.existsSync(contractsDir)) process.exit(0);
|
|
37
|
-
|
|
38
|
-
const toolResponse = payload.tool_response || {};
|
|
39
|
-
const stdout = toolResponse.stdout ?? payload.stdout ?? '';
|
|
40
|
-
const stderr = toolResponse.stderr ?? payload.stderr ?? '';
|
|
41
|
-
const rawExitCode = toolResponse.exitCode ?? toolResponse.exit_code ?? payload.exitCode;
|
|
42
|
-
const exitCode = typeof rawExitCode === 'number' ? rawExitCode : undefined;
|
|
43
|
-
const stderrSignal = typeof stderr === 'string' && stderr.trim().length > 0;
|
|
44
|
-
const failed = (exitCode !== undefined && exitCode !== 0) || (exitCode === undefined && stderrSignal);
|
|
45
|
-
|
|
46
|
-
const files = fs.readdirSync(contractsDir).filter(f => f.endsWith('.json'));
|
|
47
|
-
let firstFailure = null;
|
|
48
|
-
|
|
49
|
-
for (const file of files) {
|
|
50
|
-
const manifestPath = path.join(contractsDir, file);
|
|
51
|
-
let manifest;
|
|
52
|
-
try {
|
|
53
|
-
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
54
|
-
} catch (e) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (manifest.status !== 'pending') continue;
|
|
58
|
-
if (!manifest.checkCommand || manifest.checkCommand.trim() !== command) continue;
|
|
59
|
-
|
|
60
|
-
manifest.status = failed ? 'fail' : 'pass';
|
|
61
|
-
manifest.evidence = ((stderrSignal ? stderr : stdout) || '').slice(-500).trim();
|
|
62
|
-
manifest.verifiedAt = new Date().toISOString();
|
|
63
|
-
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
64
|
-
|
|
65
|
-
if (failed && !firstFailure) firstFailure = manifest;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (firstFailure) {
|
|
69
|
-
console.error(`[Contract Test] Stage "${firstFailure.stageId}" FAILED its named check: ${firstFailure.checkCommand}`);
|
|
70
|
-
console.error(`Evidence: ${firstFailure.evidence || '(no output captured)'}`);
|
|
71
|
-
console.error(`Do not build on this stage's output until it passes. Artifact: ${firstFailure.outputPath || '(no path recorded)'}`);
|
|
72
|
-
process.exit(2);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
process.exit(0);
|
|
76
|
-
} catch (err) {
|
|
77
|
-
process.exit(0);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Contract Test (PostToolUse: Bash|PowerShell)
|
|
4
|
+
* Resolves fable-mode stage contracts. fable-orchestrator's discipline says
|
|
5
|
+
* every stage check must be "re-run or spot-checked... before building on
|
|
6
|
+
* its output" - but a verbal claim of "I re-ran it" isn't auditable. So the
|
|
7
|
+
* orchestrator now writes .claude/harness-everything/state/contracts/<stageId>.json with
|
|
8
|
+
* status:"pending" and the exact checkCommand BEFORE running it. This hook
|
|
9
|
+
* watches every shell call; when the command matches a pending contract's
|
|
10
|
+
* checkCommand verbatim, it records pass/fail into that manifest using the
|
|
11
|
+
* same exitCode-or-stderr heuristic as rule-of-3-tracker.js.
|
|
12
|
+
* Contracts are shared across sessions, not scoped to one - the orchestrator
|
|
13
|
+
* writes them proactively (not in response to a hook message) and has no
|
|
14
|
+
* clean way to learn its own session_id, so a collision only matters if two
|
|
15
|
+
* fable-mode orchestrations run in the same repo at once.
|
|
16
|
+
* Contracts are audit trail, not synchronous enforcement - EXCEPT when a
|
|
17
|
+
* check this hook just resolved comes back FAILED, it surfaces that loudly
|
|
18
|
+
* (exit 2) so silently building on a failed stage doesn't slip through.
|
|
19
|
+
* Fails open on any parse/lookup error.
|
|
20
|
+
*/
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const { getWorkspaceRoot, getStateRoot } = require('./lib/harness-state');
|
|
24
|
+
|
|
25
|
+
let inputData = '';
|
|
26
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
27
|
+
process.stdin.on('end', () => {
|
|
28
|
+
try {
|
|
29
|
+
const payload = JSON.parse(inputData);
|
|
30
|
+
if (payload.tool_name !== 'Bash' && payload.tool_name !== 'PowerShell') process.exit(0);
|
|
31
|
+
|
|
32
|
+
const command = ((payload.tool_input && payload.tool_input.command) || '').trim();
|
|
33
|
+
if (!command) process.exit(0);
|
|
34
|
+
|
|
35
|
+
const contractsDir = path.join(getStateRoot(getWorkspaceRoot()), 'contracts');
|
|
36
|
+
if (!fs.existsSync(contractsDir)) process.exit(0);
|
|
37
|
+
|
|
38
|
+
const toolResponse = payload.tool_response || {};
|
|
39
|
+
const stdout = toolResponse.stdout ?? payload.stdout ?? '';
|
|
40
|
+
const stderr = toolResponse.stderr ?? payload.stderr ?? '';
|
|
41
|
+
const rawExitCode = toolResponse.exitCode ?? toolResponse.exit_code ?? payload.exitCode;
|
|
42
|
+
const exitCode = typeof rawExitCode === 'number' ? rawExitCode : undefined;
|
|
43
|
+
const stderrSignal = typeof stderr === 'string' && stderr.trim().length > 0;
|
|
44
|
+
const failed = (exitCode !== undefined && exitCode !== 0) || (exitCode === undefined && stderrSignal);
|
|
45
|
+
|
|
46
|
+
const files = fs.readdirSync(contractsDir).filter(f => f.endsWith('.json'));
|
|
47
|
+
let firstFailure = null;
|
|
48
|
+
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const manifestPath = path.join(contractsDir, file);
|
|
51
|
+
let manifest;
|
|
52
|
+
try {
|
|
53
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (manifest.status !== 'pending') continue;
|
|
58
|
+
if (!manifest.checkCommand || manifest.checkCommand.trim() !== command) continue;
|
|
59
|
+
|
|
60
|
+
manifest.status = failed ? 'fail' : 'pass';
|
|
61
|
+
manifest.evidence = ((stderrSignal ? stderr : stdout) || '').slice(-500).trim();
|
|
62
|
+
manifest.verifiedAt = new Date().toISOString();
|
|
63
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
64
|
+
|
|
65
|
+
if (failed && !firstFailure) firstFailure = manifest;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (firstFailure) {
|
|
69
|
+
console.error(`[Contract Test] Stage "${firstFailure.stageId}" FAILED its named check: ${firstFailure.checkCommand}`);
|
|
70
|
+
console.error(`Evidence: ${firstFailure.evidence || '(no output captured)'}`);
|
|
71
|
+
console.error(`Do not build on this stage's output until it passes. Artifact: ${firstFailure.outputPath || '(no path recorded)'}`);
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
process.exit(0);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Depth Guard (PreToolUse: Edit|Write)
|
|
4
|
-
* Claude Code already refuses to Edit a file that wasn't Read first in the
|
|
5
|
-
* same session - that's native behavior, not something this hook needs to
|
|
6
|
-
* re-check. The gap is Write: it happily overwrites an existing file with
|
|
7
|
-
* no prior Read at all. This hook closes that gap: blocks Write on a file
|
|
8
|
-
* that already exists on disk unless a Read of that exact path shows up
|
|
9
|
-
* earlier in this session's transcript.
|
|
10
|
-
* Fails open on any parse/lookup error - never blocks due to a bug here.
|
|
11
|
-
*/
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
let inputData = '';
|
|
16
|
-
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
17
|
-
process.stdin.on('end', () => {
|
|
18
|
-
try {
|
|
19
|
-
const payload = JSON.parse(inputData);
|
|
20
|
-
if (payload.tool_name !== 'Write') {
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const filePath = payload.tool_input && payload.tool_input.file_path;
|
|
25
|
-
if (!filePath || !fs.existsSync(filePath)) {
|
|
26
|
-
// New file - nothing to have read first.
|
|
27
|
-
process.exit(0);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const transcriptPath = payload.transcript_path;
|
|
31
|
-
if (!transcriptPath || !fs.existsSync(transcriptPath)) {
|
|
32
|
-
// Can't verify either way - fail open.
|
|
33
|
-
process.exit(0);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const target = path.resolve(filePath).toLowerCase();
|
|
37
|
-
const lines = fs.readFileSync(transcriptPath, 'utf8').split('\n').filter(Boolean);
|
|
38
|
-
|
|
39
|
-
const wasRead = lines.some(line => {
|
|
40
|
-
try {
|
|
41
|
-
const entry = JSON.parse(line);
|
|
42
|
-
const content = entry && entry.message && entry.message.content;
|
|
43
|
-
if (!Array.isArray(content)) return false;
|
|
44
|
-
return content.some(block => {
|
|
45
|
-
if (!block || block.type !== 'tool_use' || block.name !== 'Read') return false;
|
|
46
|
-
const readPath = block.input && block.input.file_path;
|
|
47
|
-
return readPath && path.resolve(readPath).toLowerCase() === target;
|
|
48
|
-
});
|
|
49
|
-
} catch (e) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
if (!wasRead) {
|
|
55
|
-
console.error(`[Depth Guard] BLOCKED: "${filePath}" already exists but hasn't been Read in this session.`);
|
|
56
|
-
console.error(`Write() overwrites the whole file - doing that blind risks destroying content you never looked at.`);
|
|
57
|
-
console.error(`Read the file first (even a quick pass), then retry the Write, or use Edit for a targeted change.`);
|
|
58
|
-
process.exit(2);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
process.exit(0);
|
|
62
|
-
} catch (err) {
|
|
63
|
-
process.exit(0);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Depth Guard (PreToolUse: Edit|Write)
|
|
4
|
+
* Claude Code already refuses to Edit a file that wasn't Read first in the
|
|
5
|
+
* same session - that's native behavior, not something this hook needs to
|
|
6
|
+
* re-check. The gap is Write: it happily overwrites an existing file with
|
|
7
|
+
* no prior Read at all. This hook closes that gap: blocks Write on a file
|
|
8
|
+
* that already exists on disk unless a Read of that exact path shows up
|
|
9
|
+
* earlier in this session's transcript.
|
|
10
|
+
* Fails open on any parse/lookup error - never blocks due to a bug here.
|
|
11
|
+
*/
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
let inputData = '';
|
|
16
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
17
|
+
process.stdin.on('end', () => {
|
|
18
|
+
try {
|
|
19
|
+
const payload = JSON.parse(inputData);
|
|
20
|
+
if (payload.tool_name !== 'Write') {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const filePath = payload.tool_input && payload.tool_input.file_path;
|
|
25
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
26
|
+
// New file - nothing to have read first.
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const transcriptPath = payload.transcript_path;
|
|
31
|
+
if (!transcriptPath || !fs.existsSync(transcriptPath)) {
|
|
32
|
+
// Can't verify either way - fail open.
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const target = path.resolve(filePath).toLowerCase();
|
|
37
|
+
const lines = fs.readFileSync(transcriptPath, 'utf8').split('\n').filter(Boolean);
|
|
38
|
+
|
|
39
|
+
const wasRead = lines.some(line => {
|
|
40
|
+
try {
|
|
41
|
+
const entry = JSON.parse(line);
|
|
42
|
+
const content = entry && entry.message && entry.message.content;
|
|
43
|
+
if (!Array.isArray(content)) return false;
|
|
44
|
+
return content.some(block => {
|
|
45
|
+
if (!block || block.type !== 'tool_use' || block.name !== 'Read') return false;
|
|
46
|
+
const readPath = block.input && block.input.file_path;
|
|
47
|
+
return readPath && path.resolve(readPath).toLowerCase() === target;
|
|
48
|
+
});
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!wasRead) {
|
|
55
|
+
console.error(`[Depth Guard] BLOCKED: "${filePath}" already exists but hasn't been Read in this session.`);
|
|
56
|
+
console.error(`Write() overwrites the whole file - doing that blind risks destroying content you never looked at.`);
|
|
57
|
+
console.error(`Read the file first (even a quick pass), then retry the Write, or use Edit for a targeted change.`);
|
|
58
|
+
process.exit(2);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
process.exit(0);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
});
|