harness-everything 0.2.1 → 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 +63 -63
- package/docs/workflows/eval-harness.md +64 -57
- package/docs/workflows/fable-discipline.md +59 -59
- package/docs/workflows/fable-mode.md +12 -15
- package/docs/workflows/find-skills.md +36 -0
- package/docs/workflows/git-commit.md +71 -62
- package/docs/workflows/grill-me.md +62 -62
- package/docs/workflows/grill-with-docs.md +69 -62
- package/docs/workflows/harness-everything.md +95 -92
- package/docs/workflows/improve-codebase-architecture.md +68 -60
- package/docs/workflows/install-cognitive-os.md +60 -60
- package/docs/workflows/multi-agent-workspace.md +42 -0
- package/docs/workflows/repo-docs.md +64 -59
- package/docs/workflows/rewrite-commits.md +60 -60
- package/docs/workflows/security-review.md +77 -58
- package/docs/workflows/self-evolve.md +42 -59
- package/docs/workflows/skill-creator.md +80 -75
- package/docs/workflows/skill-style.md +64 -64
- package/docs/workflows/tdd.md +7 -4
- package/docs/workflows/to-spec.md +83 -0
- package/docs/workflows/to-tickets.md +80 -0
- package/docs/workflows/todo-driven-workflow.md +28 -30
- package/docs/workflows/using-git-worktrees.md +67 -63
- package/docs/workflows/verification-loop.md +71 -69
- package/docs/workflows/verify-before-claim.md +64 -60
- package/docs/workflows/zoom-out.md +74 -62
- package/environment-detection/SKILL.md +41 -77
- 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 +42 -59
- 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 +41 -38
- package/fable-discipline/references/discipline-rules.md +22 -0
- package/fable-mode/CONTRACT-FORMAT.md +51 -51
- package/fable-mode/SKILL.md +39 -51
- 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 +45 -55
- 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 +43 -36
- 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 +41 -99
- package/grill-with-docs/references/session-playbook.md +97 -0
- package/harness-everything/SKILL.md +42 -141
- 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 +87 -18
- package/hooks/hooks.json +155 -155
- package/hooks/scripts/boundary-guard.js +55 -55
- 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 +185 -42
- package/hooks/scripts/lib/platforms/codex.js +114 -46
- package/hooks/scripts/lib/platforms/continue.js +91 -41
- package/hooks/scripts/lib/platforms/copilot.js +109 -41
- package/hooks/scripts/lib/platforms/cursor.js +89 -41
- package/hooks/scripts/lib/platforms/hermes.js +57 -32
- 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 +14 -3
- 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 +40 -44
- 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 +38 -95
- 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 +46 -45
- 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 +37 -32
- package/rewrite-commits/references/workflow.md +18 -0
- package/scripts/installer.js +546 -649
- package/scripts/lib/advisory-text.js +167 -163
- package/scripts/lib/claude-hooks.js +84 -71
- package/scripts/lib/gitignore.js +199 -80
- package/scripts/lib/manifest.js +146 -82
- package/scripts/lib/prompts.js +241 -241
- package/scripts/lib/skills.js +260 -172
- package/scripts/lib/workspace.js +28 -28
- package/scripts/verify-install.js +147 -0
- package/security-review/SKILL.md +50 -511
- 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 +47 -54
- 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 +49 -91
- 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 +20 -25
- package/skill-style/SKILL.md +42 -48
- package/skill-style/references/style-guide.md +36 -0
- package/tdd/SKILL.md +44 -53
- 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 +40 -54
- package/todo-driven-workflow/references/execution-guide.md +27 -0
- package/using-git-worktrees/SKILL.md +49 -161
- package/using-git-worktrees/references/workflow-details.md +108 -0
- package/verification-loop/SKILL.md +46 -138
- 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 +43 -86
- package/verify-before-claim/references/verification-guide.md +73 -0
- package/zoom-out/SKILL.md +42 -90
- 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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
|
|
5
|
+
console.log('\n[2a] Rule of 3 circuit breaker...');
|
|
6
|
+
|
|
7
|
+
helper.writeState('rule-of-3-state.json', { count: 3, lastHash: 'mech-test', zoomOutResolved: false });
|
|
8
|
+
const tripResult = helper.runHook('rule-of-3.js', { session_id: helper.SESSION_ID });
|
|
9
|
+
helper.check(
|
|
10
|
+
'2a. Trips at count=3 (exit=2, CRITICAL banner)',
|
|
11
|
+
tripResult.code === 2 && tripResult.stderr.includes('RULE OF 3 CIRCUIT BREAKER TRIGGERED'),
|
|
12
|
+
`Got exit=${tripResult.code}, stderr="${tripResult.stderr.slice(0, 200)}"`
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
helper.writeState('rule-of-3-state.json', {
|
|
16
|
+
count: 3, lastHash: 'mech-test', zoomOutResolved: false, lastFailureAt: 0, zoomOutCycles: 0,
|
|
17
|
+
});
|
|
18
|
+
fs.writeFileSync(
|
|
19
|
+
path.join(helper.sessionDir, 'zoom-out-report.md'),
|
|
20
|
+
'## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: new approach\n',
|
|
21
|
+
'utf8'
|
|
22
|
+
);
|
|
23
|
+
const releaseResult = helper.runHook('rule-of-3.js', { session_id: helper.SESSION_ID });
|
|
24
|
+
const releasedState = helper.readState('rule-of-3-state.json');
|
|
25
|
+
helper.check(
|
|
26
|
+
'2a-bis. Valid zoom-out report releases the breaker (exit=0, count reset)',
|
|
27
|
+
releaseResult.code === 0 &&
|
|
28
|
+
releaseResult.stdout.includes('breaker released') &&
|
|
29
|
+
releasedState.count === 0 &&
|
|
30
|
+
releasedState.zoomOutResolved === true &&
|
|
31
|
+
releasedState.zoomOutCycles === 1,
|
|
32
|
+
`Got exit=${releaseResult.code}, state=${JSON.stringify(releasedState)}`
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
helper.writeState('rule-of-3-state.json', {
|
|
36
|
+
count: 3, lastHash: 'mech-test', zoomOutResolved: false,
|
|
37
|
+
lastFailureAt: Date.now() + 60000, zoomOutCycles: 1,
|
|
38
|
+
});
|
|
39
|
+
const hardLockResult = helper.runHook('rule-of-3.js', { session_id: helper.SESSION_ID });
|
|
40
|
+
helper.check(
|
|
41
|
+
'2a-ter. Second trip on same signature hard-locks (exit=2, repeat trip)',
|
|
42
|
+
hardLockResult.code === 2 && hardLockResult.stderr.includes('repeat trip - hard lock'),
|
|
43
|
+
`Got exit=${hardLockResult.code}, stderr="${hardLockResult.stderr.slice(0, 200)}"`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
helper.finish();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const helper = require('./test-helper');
|
|
3
|
+
|
|
4
|
+
console.log('\n[2b] Boundary guard...');
|
|
5
|
+
|
|
6
|
+
const bigFile = helper.tempFile('.mechanism-test-big.tmp');
|
|
7
|
+
fs.writeFileSync(bigFile, 'x'.repeat(600 * 1024));
|
|
8
|
+
const boundaryResult = helper.runHook('boundary-guard.js', { tool_name: 'Read', tool_input: { file_path: bigFile } });
|
|
9
|
+
helper.check(
|
|
10
|
+
'2b. Blocks a 600KB Read without limit/offset (exit=2, BLOCKED)',
|
|
11
|
+
boundaryResult.code === 2 && boundaryResult.stderr.includes('[Boundary Guard] BLOCKED'),
|
|
12
|
+
`Got exit=${boundaryResult.code}, stderr="${boundaryResult.stderr.slice(0, 200)}"`
|
|
13
|
+
);
|
|
14
|
+
fs.unlinkSync(bigFile);
|
|
15
|
+
|
|
16
|
+
helper.finish();
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const helper = require('./test-helper');
|
|
2
|
+
|
|
3
|
+
console.log('\n[2c] State persistence (WAL)...');
|
|
4
|
+
|
|
5
|
+
helper.runHook('state-persist.js', {
|
|
6
|
+
session_id: helper.SESSION_ID,
|
|
7
|
+
tool_name: 'Bash',
|
|
8
|
+
tool_response: { stdout: '', stderr: 'npm ERR! mech-test failure' },
|
|
9
|
+
});
|
|
10
|
+
const failedHandoff = helper.readState('handoff-state.json');
|
|
11
|
+
helper.check(
|
|
12
|
+
'2c. Failing Bash call is recorded as status=failed',
|
|
13
|
+
failedHandoff.status === 'failed' && failedHandoff.errorSummary.includes('mech-test failure'),
|
|
14
|
+
`Got ${JSON.stringify(failedHandoff)}`
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
helper.runHook('state-persist.js', {
|
|
18
|
+
session_id: helper.SESSION_ID,
|
|
19
|
+
tool_name: 'Bash',
|
|
20
|
+
tool_response: { stdout: 'ok', exitCode: 0 },
|
|
21
|
+
});
|
|
22
|
+
const resolvedHandoff = helper.readState('handoff-state.json');
|
|
23
|
+
helper.check(
|
|
24
|
+
'2c. A subsequent successful command clears status back to idle',
|
|
25
|
+
resolvedHandoff.status === 'idle' && !!resolvedHandoff.lastResolved,
|
|
26
|
+
`Got ${JSON.stringify(resolvedHandoff)}`
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
helper.finish();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
|
|
5
|
+
console.log('\n[2d] Fact-audit reminder...');
|
|
6
|
+
|
|
7
|
+
const tierRouterPath = path.join(helper.root, 'harness-everything', 'scripts', 'tier-router.js');
|
|
8
|
+
const factAuditOut = execSync(`node "${tierRouterPath}"`, {
|
|
9
|
+
encoding: 'utf8',
|
|
10
|
+
input: JSON.stringify({ prompt: 'what exit code does this hook use by default and is it documented' }),
|
|
11
|
+
});
|
|
12
|
+
helper.check(
|
|
13
|
+
'2d. tier-router.js reads {"prompt":...} from stdin and emits FACT-AUDIT REMINDER',
|
|
14
|
+
factAuditOut.includes('FACT-AUDIT REMINDER'),
|
|
15
|
+
`Output was:\n${factAuditOut.slice(0, 300)}`
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
helper.finish();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
|
|
5
|
+
console.log('\n[2e] Subagent scope guard...');
|
|
6
|
+
|
|
7
|
+
helper.runHook('subagent-scope-guard.js', {
|
|
8
|
+
session_id: helper.SESSION_ID, tool_name: 'Task', hook_event_name: 'PreToolUse', tool_input: {},
|
|
9
|
+
});
|
|
10
|
+
const scopeFile = helper.tempFile('.mechanism-test-scope.tmp');
|
|
11
|
+
fs.writeFileSync(scopeFile, 'unexpected change');
|
|
12
|
+
const scopeResult = helper.runHook('subagent-scope-guard.js', {
|
|
13
|
+
session_id: helper.SESSION_ID, tool_name: 'Task', hook_event_name: 'PostToolUse', tool_input: {},
|
|
14
|
+
});
|
|
15
|
+
helper.check(
|
|
16
|
+
'2e. Flags the newly-created file after a Task burst (exit=2, lists filename)',
|
|
17
|
+
scopeResult.code === 2 &&
|
|
18
|
+
scopeResult.stderr.includes('Subagent Scope Guard') &&
|
|
19
|
+
scopeResult.stderr.includes(path.basename(scopeFile)),
|
|
20
|
+
`Got exit=${scopeResult.code}, stderr="${scopeResult.stderr.slice(0, 300)}"`
|
|
21
|
+
);
|
|
22
|
+
fs.unlinkSync(scopeFile);
|
|
23
|
+
|
|
24
|
+
helper.finish();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const helper = require('./test-helper');
|
|
3
|
+
|
|
4
|
+
console.log('\n[2f] Stop gate...');
|
|
5
|
+
|
|
6
|
+
helper.writeState('handoff-state.json', { status: 'idle', lastEditAt: Date.now(), lastVerifyAt: 0 });
|
|
7
|
+
const dirtyFile = helper.tempFile('.mechanism-test-dirty.tmp');
|
|
8
|
+
fs.writeFileSync(dirtyFile, 'dirty');
|
|
9
|
+
const firstStop = helper.runHook('stop-gate.js', { session_id: helper.SESSION_ID });
|
|
10
|
+
helper.check(
|
|
11
|
+
'2f. First stop after an unverified edit bounces (exit=2)',
|
|
12
|
+
firstStop.code === 2 && firstStop.stderr.includes('[Stop Gate]'),
|
|
13
|
+
`Got exit=${firstStop.code}, stderr="${firstStop.stderr.slice(0, 200)}"`
|
|
14
|
+
);
|
|
15
|
+
const secondStop = helper.runHook('stop-gate.js', { session_id: helper.SESSION_ID });
|
|
16
|
+
helper.check(
|
|
17
|
+
'2f. Same edit batch does not bounce twice (exit=0)',
|
|
18
|
+
secondStop.code === 0,
|
|
19
|
+
`Got exit=${secondStop.code}`
|
|
20
|
+
);
|
|
21
|
+
fs.unlinkSync(dirtyFile);
|
|
22
|
+
|
|
23
|
+
helper.finish();
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
|
|
5
|
+
console.log('\n[2g] Platform ignore patterns / Gitignore matching...');
|
|
6
|
+
|
|
7
|
+
const mockWs = helper.tempDir('.mechanism-test-mock-ws');
|
|
8
|
+
fs.mkdirSync(mockWs, { recursive: true });
|
|
9
|
+
|
|
10
|
+
const platforms = require('../hooks/scripts/lib/platforms');
|
|
11
|
+
const claudePlatform = platforms.find(p => p.name === 'claude');
|
|
12
|
+
const cursorPlatform = platforms.find(p => p.name === 'cursor');
|
|
13
|
+
|
|
14
|
+
// 1. Claude platform ignore pattern with mixed skills
|
|
15
|
+
const claudeSkillsDir = path.join(mockWs, '.claude', 'skills');
|
|
16
|
+
fs.mkdirSync(path.join(claudeSkillsDir, 'harness-skill'), { recursive: true });
|
|
17
|
+
fs.mkdirSync(path.join(claudeSkillsDir, 'custom-skill'), { recursive: true });
|
|
18
|
+
|
|
19
|
+
fs.writeFileSync(
|
|
20
|
+
path.join(claudeSkillsDir, 'harness-skill', 'SKILL.md'),
|
|
21
|
+
'---\nauthor: Miya Daniel\n---\n',
|
|
22
|
+
'utf8'
|
|
23
|
+
);
|
|
24
|
+
fs.writeFileSync(
|
|
25
|
+
path.join(claudeSkillsDir, 'custom-skill', 'SKILL.md'),
|
|
26
|
+
'---\nauthor: Someone Else\n---\n',
|
|
27
|
+
'utf8'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const claudePatterns = claudePlatform.getIgnorePatterns(mockWs);
|
|
31
|
+
helper.check(
|
|
32
|
+
'2g. getIgnorePatterns returns ONLY Harness skills',
|
|
33
|
+
claudePatterns.includes('.claude/harness-everything/') &&
|
|
34
|
+
claudePatterns.includes('.claude/skills/harness-skill/') &&
|
|
35
|
+
!claudePatterns.includes('.claude/skills/custom-skill/'),
|
|
36
|
+
`Got patterns: ${JSON.stringify(claudePatterns)}`
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// 2. test isMatch for claude parent matching to avoid double appending
|
|
40
|
+
helper.check(
|
|
41
|
+
'2g. isMatch returns true for parent folder match (Claude)',
|
|
42
|
+
claudePlatform.isMatch('.claude/harness-everything/', '.claude') === true &&
|
|
43
|
+
claudePlatform.isMatch('.claude/harness-everything/', '.claude/') === true,
|
|
44
|
+
`isMatch for .claude failed`
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
helper.check(
|
|
48
|
+
'2g. isMatch returns true for exact match of harness skill (Claude)',
|
|
49
|
+
claudePlatform.isMatch('.claude/skills/harness-skill/', '.claude/skills/harness-skill/') === true &&
|
|
50
|
+
claudePlatform.isMatch('.claude/skills/harness-skill/', '.claude/skills/harness-skill') === true,
|
|
51
|
+
`isMatch for exact skill path failed`
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// 3. Cursor platform ignore pattern with mixed skills
|
|
55
|
+
const cursorSkillsDir = path.join(mockWs, '.cursor', 'skills');
|
|
56
|
+
fs.mkdirSync(path.join(cursorSkillsDir, 'harness-skill'), { recursive: true });
|
|
57
|
+
fs.mkdirSync(path.join(cursorSkillsDir, 'custom-skill'), { recursive: true });
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(
|
|
60
|
+
path.join(cursorSkillsDir, 'harness-skill', 'SKILL.md'),
|
|
61
|
+
'---\nauthor: Miya Daniel\n---\n',
|
|
62
|
+
'utf8'
|
|
63
|
+
);
|
|
64
|
+
fs.writeFileSync(
|
|
65
|
+
path.join(cursorSkillsDir, 'custom-skill', 'SKILL.md'),
|
|
66
|
+
'---\nauthor: Someone Else\n---\n',
|
|
67
|
+
'utf8'
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const cursorPatterns = cursorPlatform.getIgnorePatterns(mockWs);
|
|
71
|
+
helper.check(
|
|
72
|
+
'2g. getIgnorePatterns returns ONLY Harness skills (Cursor)',
|
|
73
|
+
cursorPatterns.includes('.cursor/harness-everything/') &&
|
|
74
|
+
cursorPatterns.includes('.cursor/skills/harness-skill/') &&
|
|
75
|
+
!cursorPatterns.includes('.cursor/skills/custom-skill/'),
|
|
76
|
+
`Got patterns: ${JSON.stringify(cursorPatterns)}`
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
helper.check(
|
|
80
|
+
'2g. isMatch returns true for parent folder match (Cursor)',
|
|
81
|
+
cursorPlatform.isMatch('.cursor/harness-everything/', '.cursor') === true &&
|
|
82
|
+
cursorPlatform.isMatch('.cursor/harness-everything/', '.cursor/') === true,
|
|
83
|
+
`isMatch for .cursor failed`
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
fs.rmSync(mockWs, { recursive: true, force: true });
|
|
87
|
+
|
|
88
|
+
helper.finish();
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
|
|
5
|
+
console.log('\n[2h] Installer manifest and skill bookkeeping...');
|
|
6
|
+
|
|
7
|
+
const manifestMockWs = helper.tempDir('.mechanism-test-manifest-ws');
|
|
8
|
+
fs.mkdirSync(manifestMockWs, { recursive: true });
|
|
9
|
+
|
|
10
|
+
const manifestHelper = require('../scripts/lib/manifest');
|
|
11
|
+
const skillsHelper = require('../scripts/lib/skills');
|
|
12
|
+
const testManifestPath = path.join(manifestMockWs, 'manifest.json');
|
|
13
|
+
|
|
14
|
+
// 1. Verify readManifest of non-existent path
|
|
15
|
+
const initialManifest = manifestHelper.readManifest(testManifestPath);
|
|
16
|
+
helper.check(
|
|
17
|
+
'2h. readManifest returns fallback structure when file does not exist',
|
|
18
|
+
initialManifest.package === 'harness-everything' && Array.isArray(initialManifest.skills) && initialManifest.skills.length === 0,
|
|
19
|
+
`Got: ${JSON.stringify(initialManifest)}`
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// 2. Verify recordSkillInstall writes and serializes correctly
|
|
23
|
+
manifestHelper.recordSkillInstall(testManifestPath, '1.0.0', 'test-skill', '/path/to/test-skill');
|
|
24
|
+
const writtenManifest = manifestHelper.readManifest(testManifestPath);
|
|
25
|
+
helper.check(
|
|
26
|
+
'2h. recordSkillInstall successfully records skill information',
|
|
27
|
+
writtenManifest.version === '1.0.0' &&
|
|
28
|
+
writtenManifest.skills.length === 1 &&
|
|
29
|
+
writtenManifest.skills[0].id === 'test-skill' &&
|
|
30
|
+
writtenManifest.skills[0].dirPath === '/path/to/test-skill',
|
|
31
|
+
`Got: ${JSON.stringify(writtenManifest)}`
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// 3. Verify recordGeneratedSkill and removeGeneratedSkill
|
|
35
|
+
manifestHelper.recordGeneratedSkill(testManifestPath, 'gen-skill', '/path/to/gen-skill', 'desc', ['trigger']);
|
|
36
|
+
const withGenerated = manifestHelper.readManifest(testManifestPath);
|
|
37
|
+
helper.check(
|
|
38
|
+
'2h. recordGeneratedSkill successfully records generated skill with triggers',
|
|
39
|
+
withGenerated.generated &&
|
|
40
|
+
withGenerated.generated.length === 1 &&
|
|
41
|
+
withGenerated.generated[0].id === 'gen-skill' &&
|
|
42
|
+
withGenerated.generated[0].triggers.includes('trigger'),
|
|
43
|
+
`Got: ${JSON.stringify(withGenerated)}`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
manifestHelper.removeGeneratedSkill(testManifestPath, '/path/to/gen-skill');
|
|
47
|
+
const afterRemoveGen = manifestHelper.readManifest(testManifestPath);
|
|
48
|
+
helper.check(
|
|
49
|
+
'2h. removeGeneratedSkill removes generated skill correctly',
|
|
50
|
+
afterRemoveGen.generated && afterRemoveGen.generated.length === 0,
|
|
51
|
+
`Got: ${JSON.stringify(afterRemoveGen)}`
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// 4. Verify isHarnessSkillDir matches correct author
|
|
55
|
+
const mockSkillPath = path.join(manifestMockWs, 'mock-skill-folder');
|
|
56
|
+
fs.mkdirSync(mockSkillPath, { recursive: true });
|
|
57
|
+
const mockSkillMdPath = path.join(mockSkillPath, 'SKILL.md');
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(mockSkillMdPath, '---\nauthor: Miya Daniel\n---\n', 'utf8');
|
|
60
|
+
const isHarness = skillsHelper.isHarnessSkillDir(mockSkillPath);
|
|
61
|
+
helper.check(
|
|
62
|
+
'2h. isHarnessSkillDir detects Harness author correctly',
|
|
63
|
+
isHarness === true,
|
|
64
|
+
`Expected true but got false`
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Regression: spec-compliant frontmatter (author nested under metadata:) must
|
|
68
|
+
// also be recognized. Guards the getMeta parser in scripts/lib/skills.js.
|
|
69
|
+
fs.writeFileSync(mockSkillMdPath, '---\nname: spec-skill\ndescription: x\nlicense: Apache-2.0\nmetadata:\n author: Miya Daniel\n version: 0.3.3\n---\n', 'utf8');
|
|
70
|
+
const isHarnessSpec = skillsHelper.isHarnessSkillDir(mockSkillPath);
|
|
71
|
+
helper.check(
|
|
72
|
+
'2h. isHarnessSkillDir detects author under metadata: (spec format)',
|
|
73
|
+
isHarnessSpec === true,
|
|
74
|
+
`Expected true but got false`
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
fs.writeFileSync(mockSkillMdPath, '---\nauthor: Outsider\n---\n', 'utf8');
|
|
78
|
+
const isNotHarness = skillsHelper.isHarnessSkillDir(mockSkillPath);
|
|
79
|
+
helper.check(
|
|
80
|
+
'2h. isHarnessSkillDir returns false for foreign authors',
|
|
81
|
+
isNotHarness === false,
|
|
82
|
+
`Expected false but got true`
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// 5. Verify removeSkillFromManifest removes skill and deletes empty manifest
|
|
86
|
+
manifestHelper.removeSkillFromManifest(testManifestPath, '/path/to/test-skill');
|
|
87
|
+
helper.check(
|
|
88
|
+
'2h. removeSkillFromManifest cleans up or unlinks empty manifest',
|
|
89
|
+
!fs.existsSync(testManifestPath),
|
|
90
|
+
`Manifest file still exists after removing all entries!`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// 6. Verify Fable agent definitions install into the native Claude agent
|
|
94
|
+
// directory, preserve a conflicting user file, and are manifest tracked.
|
|
95
|
+
const agentTargetDir = path.join(manifestMockWs, 'agents');
|
|
96
|
+
const agentManifestPath = path.join(manifestMockWs, 'agent-manifest.json');
|
|
97
|
+
fs.mkdirSync(agentTargetDir, { recursive: true });
|
|
98
|
+
const conflictPath = path.join(agentTargetDir, 'fable-orchestrator.md');
|
|
99
|
+
fs.writeFileSync(conflictPath, '---\nname: fable-orchestrator\n---\nuser-owned\n', 'utf8');
|
|
100
|
+
skillsHelper.installAgentsToTarget({
|
|
101
|
+
target: { path: agentTargetDir, label: 'test-agents/', manifestPath: agentManifestPath },
|
|
102
|
+
harnessSourceDir: path.join(__dirname, '..'),
|
|
103
|
+
packageVersion: '1.0.0'
|
|
104
|
+
});
|
|
105
|
+
const installedAgents = manifestHelper.readManifest(agentManifestPath).agents;
|
|
106
|
+
helper.check(
|
|
107
|
+
'2h. Fable agents are manifest tracked without overwriting a conflicting file',
|
|
108
|
+
installedAgents.length === 3 &&
|
|
109
|
+
fs.readFileSync(conflictPath, 'utf8').includes('user-owned') &&
|
|
110
|
+
fs.existsSync(path.join(agentTargetDir, 'fable-verifier.md')),
|
|
111
|
+
`Got: ${JSON.stringify(installedAgents)}`
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
for (const agent of [...installedAgents]) {
|
|
115
|
+
skillsHelper.removeAgent({ ...agent, manifestPath: agentManifestPath });
|
|
116
|
+
}
|
|
117
|
+
helper.check(
|
|
118
|
+
'2h. Removing Fable agents removes only tracked files and manifest state',
|
|
119
|
+
fs.existsSync(conflictPath) && !fs.existsSync(agentManifestPath),
|
|
120
|
+
`Agent conflict or manifest was removed unexpectedly`
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const identicalPath = path.join(agentTargetDir, 'fable-verifier.md');
|
|
124
|
+
fs.copyFileSync(path.join(__dirname, '..', 'fable-mode', 'agents', 'fable-verifier.md'), identicalPath);
|
|
125
|
+
skillsHelper.installAgentsToTarget({
|
|
126
|
+
target: { path: agentTargetDir, label: 'test-agents/', manifestPath: agentManifestPath },
|
|
127
|
+
harnessSourceDir: path.join(__dirname, '..'),
|
|
128
|
+
packageVersion: '1.0.0'
|
|
129
|
+
});
|
|
130
|
+
const secondInstall = manifestHelper.readManifest(agentManifestPath).agents;
|
|
131
|
+
helper.check(
|
|
132
|
+
'2h. Pre-existing identical agent is not claimed as Harness-owned',
|
|
133
|
+
secondInstall.length === 2,
|
|
134
|
+
`Got: ${JSON.stringify(secondInstall)}`
|
|
135
|
+
);
|
|
136
|
+
for (const agent of [...secondInstall]) {
|
|
137
|
+
skillsHelper.removeAgent({ ...agent, manifestPath: agentManifestPath });
|
|
138
|
+
}
|
|
139
|
+
helper.check(
|
|
140
|
+
'2h. Pre-existing identical agent survives tracked-agent removal',
|
|
141
|
+
fs.existsSync(conflictPath) && fs.existsSync(identicalPath),
|
|
142
|
+
`A pre-existing agent was removed unexpectedly`
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
fs.rmSync(manifestMockWs, { recursive: true, force: true });
|
|
146
|
+
|
|
147
|
+
helper.finish();
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* [2i] CRLF frontmatter immunity for quality gates.
|
|
4
|
+
*
|
|
5
|
+
* Regression guard for issue #5: every frontmatter parser in eval-framework
|
|
6
|
+
* must tolerate CRLF line endings. A Windows clone (core.autocrlf=true) used
|
|
7
|
+
* to produce 83 spurious consistency failures AND — worse — made the
|
|
8
|
+
* collision check silently compare 27 empty descriptions and pass as a no-op.
|
|
9
|
+
*
|
|
10
|
+
* Method: copy the repo to a temp dir, convert every SKILL.md to CRLF, then:
|
|
11
|
+
* (a) consistency-check must PASS on the converted tree;
|
|
12
|
+
* (b) collision check must PASS unmodified;
|
|
13
|
+
* (c) negative control: plant a duplicated description pair -> collision
|
|
14
|
+
* check must FAIL. If parsing ever regresses to empty strings again,
|
|
15
|
+
* jaccard(NaN) trips nothing and this control goes red.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const { spawnSync } = require('child_process');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
24
|
+
let tmpRoot = null;
|
|
25
|
+
|
|
26
|
+
function check(name, condition, detail) {
|
|
27
|
+
if (condition) {
|
|
28
|
+
console.log(`✅ ${name}`);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
console.error(`❌ ${name}`);
|
|
32
|
+
if (detail) console.error(` ${detail}`);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function listSkillMdFiles(dir) {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
39
|
+
if (entry.name.startsWith('.') || !entry.isDirectory()) continue;
|
|
40
|
+
const skillMd = path.join(dir, entry.name, 'SKILL.md');
|
|
41
|
+
if (fs.existsSync(skillMd)) out.push(skillMd);
|
|
42
|
+
const subDir = path.join(dir, entry.name);
|
|
43
|
+
for (const sub of fs.readdirSync(subDir, { withFileTypes: true })) {
|
|
44
|
+
if (!sub.isDirectory()) continue;
|
|
45
|
+
const nested = path.join(subDir, sub.name, 'SKILL.md');
|
|
46
|
+
if (fs.existsSync(nested)) out.push(nested);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function toCrlf(file) {
|
|
53
|
+
const raw = fs.readFileSync(file, 'utf8');
|
|
54
|
+
fs.writeFileSync(file, raw.replace(/\r?\n/g, '\r\n'), 'utf8');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function setDescription(file, newDesc) {
|
|
58
|
+
const lines = fs.readFileSync(file, 'utf8').split('\n');
|
|
59
|
+
const idx = lines.findIndex(l => l.replace(/\r$/, '').startsWith('description:'));
|
|
60
|
+
if (idx === -1) throw new Error(`no description line in ${file}`);
|
|
61
|
+
lines[idx] = `description: ${newDesc}`;
|
|
62
|
+
fs.writeFileSync(file, lines.join('\n'), 'utf8');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getDescription(file) {
|
|
66
|
+
const raw = fs.readFileSync(file, 'utf8');
|
|
67
|
+
const fm = (raw.match(/^---\r?\n([\s\S]*?)\r?\n---/) || [])[1] || '';
|
|
68
|
+
return ((fm.match(/^description:\s*(.+)$/m) || [])[1] || '').trim();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runGate(cwd, script) {
|
|
72
|
+
const r = spawnSync(process.execPath, [path.join('ci', script)], {
|
|
73
|
+
cwd,
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
});
|
|
76
|
+
return { code: r.status, stdout: r.stdout || '', stderr: r.stderr || '' };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let failures = 0;
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Hermetic workspace: full repo copy minus VCS.
|
|
83
|
+
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-crlf-test-'));
|
|
84
|
+
fs.cpSync(projectRoot, tmpRoot, {
|
|
85
|
+
recursive: true,
|
|
86
|
+
filter: (src) => {
|
|
87
|
+
const rel = path.relative(projectRoot, src);
|
|
88
|
+
const first = rel.split(path.sep)[0];
|
|
89
|
+
return first !== '.git' && first !== 'node_modules';
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Copy node_modules separately to preserve symlinks
|
|
94
|
+
fs.cpSync(path.join(projectRoot, 'node_modules'), path.join(tmpRoot, 'node_modules'), {
|
|
95
|
+
recursive: true,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const skillMdFiles = listSkillMdFiles(tmpRoot);
|
|
99
|
+
if (!check(
|
|
100
|
+
'2i-pre. Found enough SKILL.md fixtures in copied tree',
|
|
101
|
+
skillMdFiles.length >= 20,
|
|
102
|
+
`Got ${skillMdFiles.length}`
|
|
103
|
+
)) failures++;
|
|
104
|
+
skillMdFiles.forEach(toCrlf);
|
|
105
|
+
|
|
106
|
+
// (a) Consistency gate must survive a fully-CRLF working tree.
|
|
107
|
+
const consistency = runGate(tmpRoot, 'consistency-check.js');
|
|
108
|
+
if (!check(
|
|
109
|
+
'2i-a. consistency-check passes on all-CRLF tree',
|
|
110
|
+
consistency.code === 0 && consistency.stdout.includes('ALL CONSISTENCY CHECKS PASSED'),
|
|
111
|
+
`exit=${consistency.code}, tail="${(consistency.stdout + consistency.stderr).trim().slice(-200)}"`
|
|
112
|
+
)) failures++;
|
|
113
|
+
|
|
114
|
+
// (b) Collision gate must pass unmodified...
|
|
115
|
+
const collisionClean = runGate(tmpRoot, 'description-collision.js');
|
|
116
|
+
if (!check(
|
|
117
|
+
'2i-b. description-collision passes on all-CRLF tree',
|
|
118
|
+
collisionClean.code === 0,
|
|
119
|
+
`exit=${collisionClean.code}, tail="${(collisionClean.stdout + collisionClean.stderr).trim().slice(-200)}"`
|
|
120
|
+
)) failures++;
|
|
121
|
+
|
|
122
|
+
// (c) ...and must still be comparing REAL descriptions. Plant a duplicate:
|
|
123
|
+
// if parsing regressed to empty strings, similarity would be NaN/0 and this
|
|
124
|
+
// would silently pass — exactly the pre-fix failure mode.
|
|
125
|
+
const donor = path.join(tmpRoot, 'tdd', 'SKILL.md');
|
|
126
|
+
const target = path.join(tmpRoot, 'zoom-out', 'SKILL.md');
|
|
127
|
+
setDescription(target, getDescription(donor));
|
|
128
|
+
const collisionDup = runGate(tmpRoot, 'description-collision.js');
|
|
129
|
+
if (!check(
|
|
130
|
+
'2i-c. Negative control: planted CRLF duplicate FAILS collision check',
|
|
131
|
+
collisionDup.code !== 0,
|
|
132
|
+
`exit=${collisionDup.code} (a silent no-op parses empty descriptions and passes here), tail="${(collisionDup.stdout + collisionDup.stderr).trim().slice(-200)}"`
|
|
133
|
+
)) failures++;
|
|
134
|
+
} catch (err) {
|
|
135
|
+
failures++;
|
|
136
|
+
console.error(`❌ 2i-setup. Test harness error: ${err.message}`);
|
|
137
|
+
} finally {
|
|
138
|
+
if (tmpRoot) {
|
|
139
|
+
try { fs.rmSync(tmpRoot, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (failures > 0) process.exit(1);
|
|
144
|
+
console.log('\n[2i] CRLF frontmatter immunity: all checks passed.');
|
|
145
|
+
process.exit(0);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
const manifest = require('../scripts/lib/manifest');
|
|
5
|
+
const { verifyManifest } = require('../scripts/verify-install');
|
|
6
|
+
|
|
7
|
+
console.log('\n[2i] Installed version and skill-tree verification...');
|
|
8
|
+
const root = helper.tempDir('.mechanism-test-install-verification');
|
|
9
|
+
const installedRoot = path.join(root, 'skills');
|
|
10
|
+
const installedSkill = path.join(installedRoot, 'tdd');
|
|
11
|
+
const manifestPath = path.join(root, 'harness-everything', 'manifest.json');
|
|
12
|
+
fs.mkdirSync(installedRoot, { recursive: true });
|
|
13
|
+
fs.cpSync(path.join(__dirname, '..', 'tdd'), installedSkill, { recursive: true });
|
|
14
|
+
manifest.recordSkillInstall(manifestPath, require('../package.json').version, 'tdd', installedSkill);
|
|
15
|
+
|
|
16
|
+
let result = verifyManifest(manifestPath, installedRoot);
|
|
17
|
+
helper.check('2i. matching version and tree pass', result.failures.length === 0, result.failures.join('; '));
|
|
18
|
+
|
|
19
|
+
fs.appendFileSync(path.join(installedSkill, 'SKILL.md'), '\nlocal drift\n');
|
|
20
|
+
result = verifyManifest(manifestPath, installedRoot);
|
|
21
|
+
helper.check('2i. modified installed skill is reported stale', result.failures.some(f => f.includes('STALE tree: tdd')), JSON.stringify(result.failures));
|
|
22
|
+
|
|
23
|
+
const data = manifest.readManifest(manifestPath);
|
|
24
|
+
data.version = '0.3.3';
|
|
25
|
+
manifest.writeManifest(manifestPath, data);
|
|
26
|
+
result = verifyManifest(manifestPath, installedRoot);
|
|
27
|
+
helper.check('2i. old package version is reported stale', result.failures.some(f => f.includes('STALE version')), JSON.stringify(result.failures));
|
|
28
|
+
|
|
29
|
+
fs.rmSync(manifestPath, { force: true });
|
|
30
|
+
result = verifyManifest(manifestPath, installedRoot);
|
|
31
|
+
helper.check('2i. legacy install without a manifest is reported stale', result.failures.some(f => f.includes('STALE untracked installation')), JSON.stringify(result.failures));
|
|
32
|
+
|
|
33
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
34
|
+
helper.finish();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const helper = require('./test-helper');
|
|
2
|
+
const { buildEngineInvocation } = require('../behavioral-evals/run');
|
|
3
|
+
|
|
4
|
+
console.log('\n[2j] Behavioral runner argv integrity...');
|
|
5
|
+
const prompt = "Add punctuation stripping to slug.js, then run npm test. Do not truncate this request.";
|
|
6
|
+
for (const engine of ['opencode', 'claude']) {
|
|
7
|
+
const invocation = buildEngineInvocation(engine, prompt, 'C:/fixture with spaces', 16);
|
|
8
|
+
helper.check(
|
|
9
|
+
`2j. ${engine} receives the complete prompt as one argv value`,
|
|
10
|
+
invocation.args.includes(prompt),
|
|
11
|
+
JSON.stringify(invocation.args)
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const baseline = buildEngineInvocation('claude', prompt, 'C:/fixture with spaces', 16, 'baseline');
|
|
16
|
+
helper.check('2j. Claude baseline excludes user customizations', baseline.args.includes('--safe-mode') && baseline.args.includes('--setting-sources') && baseline.args.includes('project,local'), JSON.stringify(baseline.args));
|
|
17
|
+
const treatment = buildEngineInvocation('claude', prompt, 'C:/fixture with spaces', 16, 'treatment');
|
|
18
|
+
helper.check('2j. Claude treatment keeps only project/local customizations', treatment.args.includes('--setting-sources') && treatment.args.includes('project,local') && !treatment.args.includes('--safe-mode'), JSON.stringify(treatment.args));
|
|
19
|
+
|
|
20
|
+
helper.finish();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
const { checkSkillReferences } = require('./reference-check');
|
|
5
|
+
|
|
6
|
+
console.log('\n[2k] Skill reference checker negative control...');
|
|
7
|
+
const root = helper.tempDir('.mechanism-test-reference-check');
|
|
8
|
+
const skill = path.join(root, 'fixture-skill');
|
|
9
|
+
fs.mkdirSync(skill, { recursive: true });
|
|
10
|
+
fs.writeFileSync(path.join(skill, 'SKILL.md'), 'Run `scripts/missing.js` before editing.\n');
|
|
11
|
+
let result = checkSkillReferences(root, ['fixture-skill']);
|
|
12
|
+
helper.check('2k. dangling executable reference fails', result.failures.length === 1 && result.failures[0].reference === 'scripts/missing.js', JSON.stringify(result.failures));
|
|
13
|
+
|
|
14
|
+
fs.mkdirSync(path.join(skill, 'scripts'), { recursive: true });
|
|
15
|
+
fs.writeFileSync(path.join(skill, 'scripts', 'missing.js'), '');
|
|
16
|
+
result = checkSkillReferences(root, ['fixture-skill']);
|
|
17
|
+
helper.check('2k. existing executable reference passes', result.failures.length === 0, JSON.stringify(result.failures));
|
|
18
|
+
|
|
19
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
20
|
+
helper.finish();
|