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
|
@@ -15,7 +15,7 @@ const advisoryInstructions = [
|
|
|
15
15
|
``,
|
|
16
16
|
`## 🚦 MANDATORY ENTRY TRIAGE & ROUTING (ALWAYS RUN FIRST)`,
|
|
17
17
|
`Every time you receive a new prompt, you MUST load the \`harness-everything\` skill and immediately do the following:`,
|
|
18
|
-
`1. Run
|
|
18
|
+
`1. Run \`npx github:dyphn1/Harness-everything next "<Brief summary of user's prompt>"\` (this prints the same routing recommendation tier-router.js produces - it works from any directory and does not depend on where a local copy of the skill was installed). If the terminal is not available yet, simulate its routing logic from the rules below instead of skipping this step.`,
|
|
19
19
|
`2. Output a clear, stylized routing checkpoint block at the VERY BEGINNING of your response to the user:`,
|
|
20
20
|
` \`\`\`markdown`,
|
|
21
21
|
` ## 🚦 Harness OS Routing Checkpoint`,
|
|
@@ -28,7 +28,8 @@ const advisoryInstructions = [
|
|
|
28
28
|
`## 🤖 COGNITIVE COMPLIANCE (NO SILENT DEGRADES FOR NEW FEATURES)`,
|
|
29
29
|
`- **Newly Added Features / Extensions**: Copilot is highly prone to treating new feature requests as Tier 1 direct edits. If a task introduces *any* new logic, a new API endpoint, or a new file/module, you **MUST NOT** treat it as Tier 1. It **MUST** be treated as a **Tier 2 (Standard Task)** or **Tier 3 (Macro Task)**.`,
|
|
30
30
|
`- **Tier 2 Activation**: Initialize the \`todo-driven-workflow\` checklist first. Summon Domain Experts based on tech stack. Load and execute the \`tdd\` (Test-Driven Development) skill (write tests first, implement, refactor).`,
|
|
31
|
-
`- **Tier 3 Activation**: Initialize the \`todo-driven-workflow\` checklist, load \`fable-mode\` and \`fable-discipline\`, run sub-agents via \`
|
|
31
|
+
`- **Tier 3 Activation**: Initialize the \`todo-driven-workflow\` checklist, load \`fable-mode\` and \`fable-discipline\`, run sub-agents via \`multi-agent-workspace\`, and write global docs using \`repo-docs\`.`,
|
|
32
|
+
`- **Pre-Completion Verification Gate**: Before telling the human the task is done, run \`npx github:dyphn1/Harness-everything verify\` in the project root. If it exits non-zero, fix the failures and run it again before declaring completion. On Claude Code this same check is mechanically enforced by a stop hook; here nothing blocks you from skipping it, so treat it as a real requirement, not a suggestion.`,
|
|
32
33
|
`- **Memory Summarization (Self-Evolve)**: Upon task completion, you **MUST** run the \`self-evolve\` skill (running \`node self-evolve/scripts/self-regression.js\` or writing memories) to record key insights, lessons learned, and error boundaries so your context builds across sessions.`,
|
|
33
34
|
`- **Environment Discovery**: Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
|
|
34
35
|
`- **Rule of 3**: If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the human for direction instead of continuing to guess.`,
|
|
@@ -142,8 +143,11 @@ function buildCodexGlobalContent() {
|
|
|
142
143
|
`these as strong defaults, not guarantees.`,
|
|
143
144
|
``,
|
|
144
145
|
`- Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
|
|
145
|
-
`- Triage tasks:
|
|
146
|
-
`
|
|
146
|
+
`- Triage tasks: run \`npx github:dyphn1/Harness-everything next "<summary>"\` for a routing recommendation`,
|
|
147
|
+
` (trivial fixes need no plan; standard features need tests; large refactors need an explicit plan`,
|
|
148
|
+
` reviewed with the human before implementation).`,
|
|
149
|
+
`- Before declaring a task done, run \`npx github:dyphn1/Harness-everything verify\` and fix any failures`,
|
|
150
|
+
` it reports - nothing here blocks you from skipping this, so treat it as a real requirement.`,
|
|
147
151
|
`- If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the`,
|
|
148
152
|
` human for direction instead of continuing to guess.`,
|
|
149
153
|
`- Prefer editing over rewriting; commit logically complete chunks rather than one giant diff.`,
|
|
@@ -3,12 +3,25 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
|
|
5
5
|
// Every hook this package ships is namespaced "harness:<phase>:<name>" (see
|
|
6
|
-
// hooks/hooks.json) specifically so removal can match on that prefix alone
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// or
|
|
6
|
+
// hooks/hooks.json) specifically so removal can match on that prefix alone.
|
|
7
|
+
// To handle legacy installations (pre-0.3.0 or older) where hooks were installed
|
|
8
|
+
// without an "id" field, we also check if any command contains keywords like
|
|
9
|
+
// "harness-everything" or "harness-skills".
|
|
10
10
|
function isHarnessHook(hook) {
|
|
11
|
-
|
|
11
|
+
if (!hook) return false;
|
|
12
|
+
if (hook.id && hook.id.startsWith('harness:')) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(hook.hooks)) {
|
|
16
|
+
return hook.hooks.some(h => {
|
|
17
|
+
return h && typeof h.command === 'string' && (
|
|
18
|
+
h.command.includes('harness-everything') ||
|
|
19
|
+
h.command.includes('harness-skills') ||
|
|
20
|
+
h.command.includes('harness-state')
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
12
25
|
}
|
|
13
26
|
|
|
14
27
|
function mergeHarnessHooks(claudeConfig, resolvedHooks) {
|
package/scripts/lib/gitignore.js
CHANGED
|
@@ -1,80 +1,199 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
} catch (e) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a target pattern is already covered by a line in an ignore file.
|
|
6
|
+
* Handles exact matches, trailing slash differences, and parent directory subsumption
|
|
7
|
+
* (e.g. `.claude/` or `.claude` subsumes `.claude/harness-everything/state/`).
|
|
8
|
+
*/
|
|
9
|
+
function isPatternCoveredByLine(pattern, gitignoreLine) {
|
|
10
|
+
const normPattern = pattern.trim().replace(/\\/g, '/');
|
|
11
|
+
const normLine = gitignoreLine.trim().replace(/\\/g, '/');
|
|
12
|
+
|
|
13
|
+
if (!normLine || normLine.startsWith('#') || normLine.startsWith('!')) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const cleanLine = normLine.endsWith('/') ? normLine.slice(0, -1) : normLine;
|
|
18
|
+
const cleanPattern = normPattern.endsWith('/') ? normPattern.slice(0, -1) : normPattern;
|
|
19
|
+
|
|
20
|
+
// Exact match or slash variant (e.g. '.claude' vs '.claude/')
|
|
21
|
+
if (cleanLine === cleanPattern) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Parent directory check: e.g. '.claude' covers '.claude/harness-everything/'
|
|
26
|
+
if (cleanPattern.startsWith(cleanLine + '/')) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the real git directory for a workspace. `.git` is usually a
|
|
35
|
+
* directory, but in submodules and worktrees it is a FILE containing
|
|
36
|
+
* `gitdir: <path>` - resolve that pointer so info/exclude lands in the right
|
|
37
|
+
* place. Returns null when the workspace has no git repository.
|
|
38
|
+
*/
|
|
39
|
+
function resolveGitDir(wsRoot) {
|
|
40
|
+
const dotGit = path.join(wsRoot, '.git');
|
|
41
|
+
if (!fs.existsSync(dotGit)) return null;
|
|
42
|
+
try {
|
|
43
|
+
if (fs.statSync(dotGit).isDirectory()) return dotGit;
|
|
44
|
+
const content = fs.readFileSync(dotGit, 'utf8');
|
|
45
|
+
const m = content.match(/gitdir:\s*(.+)/);
|
|
46
|
+
if (!m) return null;
|
|
47
|
+
let gitdir = m[1].trim();
|
|
48
|
+
if (!path.isAbsolute(gitdir)) gitdir = path.resolve(wsRoot, gitdir);
|
|
49
|
+
return fs.existsSync(gitdir) ? gitdir : null;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const EXCLUDE_BANNER_BEGIN = '# --- Harness OS state (auto-managed; local only) ---';
|
|
56
|
+
const EXCLUDE_BANNER_END = '# --- end Harness OS state ---';
|
|
57
|
+
// Legacy marker written by older installers straight into .gitignore.
|
|
58
|
+
const LEGACY_GITIGNORE_BANNER = '# Harness OS Auto-generated Ignore Rules';
|
|
59
|
+
|
|
60
|
+
function readExcludeLines(gitDir) {
|
|
61
|
+
try {
|
|
62
|
+
return fs.readFileSync(path.join(gitDir, 'info', 'exclude'), 'utf8').split(/\r?\n/);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return null; // no exclude file yet - treat as empty but writable
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function writeExcludeSection(gitDir, patterns) {
|
|
69
|
+
const infoDir = path.join(gitDir, 'info');
|
|
70
|
+
fs.mkdirSync(infoDir, { recursive: true });
|
|
71
|
+
const excludePath = path.join(infoDir, 'exclude');
|
|
72
|
+
let lines = [];
|
|
73
|
+
try {
|
|
74
|
+
lines = fs.readFileSync(excludePath, 'utf8').split(/\r?\n/);
|
|
75
|
+
} catch (e) {}
|
|
76
|
+
|
|
77
|
+
// Drop our previous section (if any), then rebuild it from the requested
|
|
78
|
+
// patterns - so removals from getIgnorePatterns() propagate on reinstall.
|
|
79
|
+
const beginIdx = lines.indexOf(EXCLUDE_BANNER_BEGIN);
|
|
80
|
+
const endIdx = lines.indexOf(EXCLUDE_BANNER_END);
|
|
81
|
+
if (beginIdx !== -1 && endIdx !== -1) {
|
|
82
|
+
lines.splice(beginIdx, endIdx - beginIdx + 1);
|
|
83
|
+
}
|
|
84
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();
|
|
85
|
+
|
|
86
|
+
const section = ['', EXCLUDE_BANNER_BEGIN, ...patterns, EXCLUDE_BANNER_END, ''];
|
|
87
|
+
fs.writeFileSync(excludePath, lines.concat(section).join('\n'), 'utf8');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Idempotently records Harness state directories as LOCAL-ONLY ignores.
|
|
92
|
+
*
|
|
93
|
+
* Patterns go to `<gitdir>/info/exclude`, never the working tree's
|
|
94
|
+
* .gitignore - installing or self-healing must not produce a diff in the
|
|
95
|
+
* user's project. Also migrates away the legacy banner block that old
|
|
96
|
+
* versions appended to .gitignore.
|
|
97
|
+
*/
|
|
98
|
+
function ensureWorkspaceGitignorePatterns(wsRoot, patterns) {
|
|
99
|
+
const wanted = (patterns || []).filter(Boolean);
|
|
100
|
+
|
|
101
|
+
// Migration: strip the legacy banner + its pattern lines from .gitignore.
|
|
102
|
+
const gitignorePath = path.join(wsRoot, '.gitignore');
|
|
103
|
+
try {
|
|
104
|
+
if (fs.existsSync(gitignorePath)) {
|
|
105
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
106
|
+
if (content.includes(LEGACY_GITIGNORE_BANNER)) {
|
|
107
|
+
const lines = content.split(/\r?\n/);
|
|
108
|
+
const start = lines.findIndex(l => l.trim() === LEGACY_GITIGNORE_BANNER);
|
|
109
|
+
let end = start;
|
|
110
|
+
// The legacy block ran until the first non-pattern line (blank/comment/other rule).
|
|
111
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
112
|
+
const t = lines[i].trim();
|
|
113
|
+
if (t === '' || t.startsWith('#')) break;
|
|
114
|
+
end = i;
|
|
115
|
+
}
|
|
116
|
+
lines.splice(start, end - start + 1);
|
|
117
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();
|
|
118
|
+
fs.writeFileSync(gitignorePath, lines.join('\n') + '\n', 'utf8');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.warn(` ⚠️ Failed to migrate legacy .gitignore entries: ${err.message}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const gitDir = resolveGitDir(wsRoot);
|
|
126
|
+
if (!gitDir) {
|
|
127
|
+
// No git repo -> nothing local-only to write into. State dirs are gated
|
|
128
|
+
// elsewhere (bootstrap refuses unmanaged workspaces), so this is fine.
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const existing = readExcludeLines(gitDir) || [];
|
|
134
|
+
// Skip the write entirely when every wanted pattern is already inside our
|
|
135
|
+
// managed section OR covered by any ignore line (user's own broader rule).
|
|
136
|
+
const outside = existing.filter(
|
|
137
|
+
l => l !== EXCLUDE_BANNER_BEGIN && l !== EXCLUDE_BANNER_END
|
|
138
|
+
);
|
|
139
|
+
const missing = wanted.filter(p => !outside.some(line => isPatternCoveredByLine(p, line)));
|
|
140
|
+
const currentSection =
|
|
141
|
+
beginEnd(existing).start === -1
|
|
142
|
+
? []
|
|
143
|
+
: existing.slice(beginEnd(existing).start + 1, beginEnd(existing).end);
|
|
144
|
+
const sameSet =
|
|
145
|
+
currentSection.filter(l => l.trim() && !l.trim().startsWith('#')).join('\n') ===
|
|
146
|
+
wanted.join('\n');
|
|
147
|
+
if (missing.length === 0 && sameSet) return;
|
|
148
|
+
|
|
149
|
+
writeExcludeSection(gitDir, wanted);
|
|
150
|
+
console.log(` ✅ Recorded local-only ignore rules in .git/info/exclude: ${wanted.join(', ')}`);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
console.warn(` ⚠️ Failed to update .git/info/exclude: ${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function beginEnd(lines) {
|
|
157
|
+
return { start: lines.indexOf(EXCLUDE_BANNER_BEGIN), end: lines.indexOf(EXCLUDE_BANNER_END) };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Removes Harness's section from .git/info/exclude (uninstall cleanup).
|
|
162
|
+
* Never touches user-authored exclude rules.
|
|
163
|
+
*/
|
|
164
|
+
function removeWorkspaceExcludePatterns(wsRoot) {
|
|
165
|
+
const gitDir = resolveGitDir(wsRoot);
|
|
166
|
+
if (!gitDir) return;
|
|
167
|
+
try {
|
|
168
|
+
const excludePath = path.join(gitDir, 'info', 'exclude');
|
|
169
|
+
const lines = fs.readFileSync(excludePath, 'utf8').split(/\r?\n/);
|
|
170
|
+
const { start, end } = beginEnd(lines);
|
|
171
|
+
if (start === -1 || end === -1) return;
|
|
172
|
+
lines.splice(start, end - start + 1);
|
|
173
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();
|
|
174
|
+
fs.writeFileSync(excludePath, lines.join('\n') + '\n', 'utf8');
|
|
175
|
+
} catch (err) {
|
|
176
|
+
// Best-effort
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Only ever deletes a directory that is genuinely empty, and never recurses
|
|
181
|
+
// past one of `stopDirs` (workspace root / user home / filesystem root) - so
|
|
182
|
+
// this can only ever tidy up directories Harness itself just emptied out,
|
|
183
|
+
// never reach into a parent that still holds unrelated content.
|
|
184
|
+
function cleanEmptyDirs(dir, stopDirs) {
|
|
185
|
+
if (!fs.existsSync(dir)) return;
|
|
186
|
+
if ((stopDirs || []).includes(dir) || dir === path.parse(dir).root) return;
|
|
187
|
+
try {
|
|
188
|
+
const files = fs.readdirSync(dir);
|
|
189
|
+
if (files.length === 0) {
|
|
190
|
+
fs.rmdirSync(dir);
|
|
191
|
+
console.log(` ✅ Cleaned up empty directory: ${dir}`);
|
|
192
|
+
cleanEmptyDirs(path.dirname(dir), stopDirs);
|
|
193
|
+
}
|
|
194
|
+
} catch (e) {
|
|
195
|
+
// ignore
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = { ensureWorkspaceGitignorePatterns, removeWorkspaceExcludePatterns, resolveGitDir, cleanEmptyDirs };
|
package/scripts/lib/manifest.js
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
// hold content from other tools, the user's own manual additions, or
|
|
4
4
|
// self-evolve's locally-generated skills.
|
|
5
5
|
//
|
|
6
|
+
// Deliberately does NOT track find-skills' third-party downloads the same
|
|
7
|
+
// way: generated[] works because Harness owns the full lifecycle (authored,
|
|
8
|
+
// quality-gated, and status-tracked by self-evolve/skill-creator). A skill
|
|
9
|
+
// fetched via `npx skills add` is unaudited content Harness doesn't own or
|
|
10
|
+
// control the lifecycle of - the `skills` CLI's own lock file is already the
|
|
11
|
+
// live record of what's installed, so find-skills queries that directly
|
|
12
|
+
// (`npx skills list`) instead of caching a second, driftable copy here.
|
|
13
|
+
//
|
|
6
14
|
// The manifest always lives at <platform-home>/harness-everything/manifest.json
|
|
7
15
|
// - e.g. .claude/harness-everything/manifest.json, .cursor/harness-everything/
|
|
8
16
|
// manifest.json, or (global scope) ~/.agents/harness-everything/manifest.json.
|
|
@@ -15,7 +23,7 @@ const fs = require('fs');
|
|
|
15
23
|
const path = require('path');
|
|
16
24
|
|
|
17
25
|
const PACKAGE_NAME = 'harness-everything';
|
|
18
|
-
const HARNESS_AUTHOR = 'Miya Daniel
|
|
26
|
+
const HARNESS_AUTHOR = 'Miya Daniel';
|
|
19
27
|
const HARNESS_DIR_NAME = 'harness-everything';
|
|
20
28
|
|
|
21
29
|
function getHarnessDir(homeDir) {
|
|
@@ -28,14 +36,15 @@ function getManifestPath(homeDir) {
|
|
|
28
36
|
|
|
29
37
|
function readManifest(manifestPath) {
|
|
30
38
|
if (!fs.existsSync(manifestPath)) {
|
|
31
|
-
return { package: PACKAGE_NAME, skills: [] };
|
|
39
|
+
return { package: PACKAGE_NAME, skills: [], agents: [] };
|
|
32
40
|
}
|
|
33
41
|
try {
|
|
34
42
|
const data = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
35
43
|
if (!Array.isArray(data.skills)) data.skills = [];
|
|
44
|
+
if (!Array.isArray(data.agents)) data.agents = [];
|
|
36
45
|
return data;
|
|
37
46
|
} catch (e) {
|
|
38
|
-
return { package: PACKAGE_NAME, skills: [] };
|
|
47
|
+
return { package: PACKAGE_NAME, skills: [], agents: [] };
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
50
|
|
|
@@ -56,13 +65,64 @@ function recordSkillInstall(manifestPath, packageVersion, skillId, dirPath) {
|
|
|
56
65
|
writeManifest(manifestPath, data);
|
|
57
66
|
}
|
|
58
67
|
|
|
68
|
+
function recordAgentInstall(manifestPath, packageVersion, agentId, filePath) {
|
|
69
|
+
const data = readManifest(manifestPath);
|
|
70
|
+
data.package = PACKAGE_NAME;
|
|
71
|
+
data.version = packageVersion;
|
|
72
|
+
data.updatedAt = new Date().toISOString();
|
|
73
|
+
const idx = data.agents.findIndex(agent => agent.filePath === filePath);
|
|
74
|
+
const entry = { id: agentId, filePath, installedAt: new Date().toISOString() };
|
|
75
|
+
if (idx !== -1) data.agents[idx] = entry;
|
|
76
|
+
else data.agents.push(entry);
|
|
77
|
+
writeManifest(manifestPath, data);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function recordGeneratedSkill(manifestPath, skillId, dirPath, description, triggers = []) {
|
|
81
|
+
const data = readManifest(manifestPath);
|
|
82
|
+
if (!Array.isArray(data.generated)) data.generated = [];
|
|
83
|
+
|
|
84
|
+
data.updatedAt = new Date().toISOString();
|
|
85
|
+
const idx = data.generated.findIndex(s => s.dirPath === dirPath || s.id === skillId);
|
|
86
|
+
const entry = {
|
|
87
|
+
id: skillId,
|
|
88
|
+
dirPath,
|
|
89
|
+
description,
|
|
90
|
+
triggers: Array.isArray(triggers) ? triggers : [],
|
|
91
|
+
generatedAt: new Date().toISOString()
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (idx !== -1) data.generated[idx] = { ...data.generated[idx], ...entry };
|
|
95
|
+
else data.generated.push(entry);
|
|
96
|
+
|
|
97
|
+
writeManifest(manifestPath, data);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function removeGeneratedSkill(manifestPath, dirPath) {
|
|
101
|
+
if (!fs.existsSync(manifestPath)) return;
|
|
102
|
+
const data = readManifest(manifestPath);
|
|
103
|
+
if (!Array.isArray(data.generated)) return;
|
|
104
|
+
data.generated = data.generated.filter(s => s.dirPath !== dirPath);
|
|
105
|
+
writeManifest(manifestPath, data);
|
|
106
|
+
}
|
|
107
|
+
|
|
59
108
|
// Removes one skill entry, and - once no skills remain in it - deletes the
|
|
60
109
|
// manifest file itself rather than leaving an empty bookkeeping file behind.
|
|
61
110
|
function removeSkillFromManifest(manifestPath, dirPath) {
|
|
62
111
|
if (!fs.existsSync(manifestPath)) return;
|
|
63
112
|
const data = readManifest(manifestPath);
|
|
64
113
|
data.skills = data.skills.filter(s => s.dirPath !== dirPath);
|
|
65
|
-
if (data.skills.length === 0) {
|
|
114
|
+
if (data.skills.length === 0 && (!data.generated || data.generated.length === 0) && (!data.agents || data.agents.length === 0)) {
|
|
115
|
+
fs.unlinkSync(manifestPath);
|
|
116
|
+
} else {
|
|
117
|
+
writeManifest(manifestPath, data);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function removeAgentFromManifest(manifestPath, filePath) {
|
|
122
|
+
if (!fs.existsSync(manifestPath)) return;
|
|
123
|
+
const data = readManifest(manifestPath);
|
|
124
|
+
data.agents = data.agents.filter(agent => agent.filePath !== filePath);
|
|
125
|
+
if (data.skills.length === 0 && (!data.generated || data.generated.length === 0) && data.agents.length === 0) {
|
|
66
126
|
fs.unlinkSync(manifestPath);
|
|
67
127
|
} else {
|
|
68
128
|
writeManifest(manifestPath, data);
|
|
@@ -78,5 +138,9 @@ module.exports = {
|
|
|
78
138
|
readManifest,
|
|
79
139
|
writeManifest,
|
|
80
140
|
recordSkillInstall,
|
|
141
|
+
recordAgentInstall,
|
|
142
|
+
recordGeneratedSkill,
|
|
143
|
+
removeGeneratedSkill,
|
|
81
144
|
removeSkillFromManifest,
|
|
145
|
+
removeAgentFromManifest,
|
|
82
146
|
};
|
package/scripts/lib/prompts.js
CHANGED
|
@@ -159,7 +159,7 @@ function interactiveSingleSelect(items) {
|
|
|
159
159
|
readline.cursorTo(process.stdout, 0);
|
|
160
160
|
for (let i = 0; i < items.length; i++) {
|
|
161
161
|
const item = items[i];
|
|
162
|
-
const isSelected = item.checked ? '
|
|
162
|
+
const isSelected = item.checked ? '[x]' : '[ ]';
|
|
163
163
|
const isCurrent = i === cursor ? '> ' : ' ';
|
|
164
164
|
readline.clearLine(process.stdout, 0);
|
|
165
165
|
process.stdout.write(`${isCurrent}${isSelected} ${item.name}\n`);
|
package/scripts/lib/skills.js
CHANGED
|
@@ -42,7 +42,21 @@ function parseFrontmatter(skillMdPath) {
|
|
|
42
42
|
const m = yaml.match(new RegExp(`^${key}:\\s*(.*)$`, 'm'));
|
|
43
43
|
return m ? m[1].trim().replace(/^['"]|['"]$/g, '') : '';
|
|
44
44
|
};
|
|
45
|
-
|
|
45
|
+
// Spec-compliant skills carry author/version under `metadata:`; older
|
|
46
|
+
// installs (pre-0.3.4 copies already sitting in user workspaces) keep
|
|
47
|
+
// them at the top level, so read both and prefer the nested form.
|
|
48
|
+
const getMeta = (key) => {
|
|
49
|
+
// Only keys nested under `metadata:` are indented in frontmatter,
|
|
50
|
+
// so matching the indented key directly is unambiguous.
|
|
51
|
+
const m = yaml.match(new RegExp(`^[ \\t]+${key}:\\s*(.*)$`, 'm'));
|
|
52
|
+
return m ? m[1].trim().replace(/^['"]|['"]$/g, '') : '';
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
name: get('name'),
|
|
56
|
+
description: get('description'),
|
|
57
|
+
author: getMeta('author') || get('author'),
|
|
58
|
+
version: getMeta('version') || get('version'),
|
|
59
|
+
};
|
|
46
60
|
} catch (e) {
|
|
47
61
|
return null;
|
|
48
62
|
}
|
|
@@ -70,6 +84,15 @@ function isHarnessSkillDir(dirPath) {
|
|
|
70
84
|
function installSkillsToTargets({ chosenSkills, targetDirs, harnessSourceDir, packageVersion }) {
|
|
71
85
|
for (const target of targetDirs) {
|
|
72
86
|
fs.mkdirSync(target.path, { recursive: true });
|
|
87
|
+
|
|
88
|
+
// Copy references directory
|
|
89
|
+
const refSrc = path.join(harnessSourceDir, 'references');
|
|
90
|
+
if (fs.existsSync(refSrc)) {
|
|
91
|
+
const refDest = path.join(path.dirname(target.manifestPath), 'references');
|
|
92
|
+
if (fs.existsSync(refDest)) fs.rmSync(refDest, { recursive: true, force: true });
|
|
93
|
+
copyDir(refSrc, refDest);
|
|
94
|
+
}
|
|
95
|
+
|
|
73
96
|
for (const skillName of chosenSkills) {
|
|
74
97
|
const src = path.join(harnessSourceDir, skillName);
|
|
75
98
|
const dest = path.join(target.path, skillName);
|
|
@@ -83,6 +106,39 @@ function installSkillsToTargets({ chosenSkills, targetDirs, harnessSourceDir, pa
|
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
108
|
|
|
109
|
+
function installAgentsToTarget({ target, harnessSourceDir, packageVersion }) {
|
|
110
|
+
const sourceDir = path.join(harnessSourceDir, 'fable-mode', 'agents');
|
|
111
|
+
if (!fs.existsSync(sourceDir) || !target || !target.path || !target.manifestPath) return;
|
|
112
|
+
|
|
113
|
+
fs.mkdirSync(target.path, { recursive: true });
|
|
114
|
+
const trackedPaths = new Set(
|
|
115
|
+
(manifest.readManifest(target.manifestPath).agents || []).map(agent => agent.filePath)
|
|
116
|
+
);
|
|
117
|
+
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
118
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
119
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
120
|
+
const destPath = path.join(target.path, entry.name);
|
|
121
|
+
if (fs.existsSync(destPath)) {
|
|
122
|
+
const source = fs.readFileSync(sourcePath, 'utf8');
|
|
123
|
+
const existing = fs.readFileSync(destPath, 'utf8');
|
|
124
|
+
if (source !== existing) {
|
|
125
|
+
console.warn(` ⚠️ Preserved existing agent without overwrite: ${destPath}`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (!trackedPaths.has(destPath)) {
|
|
129
|
+
console.warn(` ⚠️ Preserved pre-existing identical agent without claiming ownership: ${destPath}`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
134
|
+
console.log(` ✅ Installed agent: ${target.label}${entry.name}`);
|
|
135
|
+
}
|
|
136
|
+
const agentInfo = parseFrontmatter(sourcePath);
|
|
137
|
+
const agentName = (agentInfo && agentInfo.name) || entry.name.replace(/\.md$/i, '');
|
|
138
|
+
manifest.recordAgentInstall(target.manifestPath, packageVersion, agentName, destPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
86
142
|
function manifestTrackedSkills(manifestPath, scopeLabel) {
|
|
87
143
|
const data = manifest.readManifest(manifestPath);
|
|
88
144
|
const results = [];
|
|
@@ -154,6 +210,24 @@ function getInstalledSkills(workspaceRoot, userHome) {
|
|
|
154
210
|
return results;
|
|
155
211
|
}
|
|
156
212
|
|
|
213
|
+
function getInstalledAgents(workspaceRoot, userHome) {
|
|
214
|
+
const homes = [
|
|
215
|
+
{ home: path.join(workspaceRoot, '.claude'), scope: 'local (Claude)' },
|
|
216
|
+
{ home: path.join(userHome, '.claude'), scope: 'global (Claude)' },
|
|
217
|
+
];
|
|
218
|
+
const results = [];
|
|
219
|
+
for (const { home, scope } of homes) {
|
|
220
|
+
const manifestPath = manifest.getManifestPath(home);
|
|
221
|
+
const data = manifest.readManifest(manifestPath);
|
|
222
|
+
for (const entry of data.agents || []) {
|
|
223
|
+
if (entry.filePath && fs.existsSync(entry.filePath)) {
|
|
224
|
+
results.push({ ...entry, scope, manifestPath });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return results;
|
|
229
|
+
}
|
|
230
|
+
|
|
157
231
|
function removeSkill(entry) {
|
|
158
232
|
if (fs.existsSync(entry.dirPath)) {
|
|
159
233
|
fs.rmSync(entry.dirPath, { recursive: true, force: true });
|
|
@@ -163,12 +237,24 @@ function removeSkill(entry) {
|
|
|
163
237
|
}
|
|
164
238
|
}
|
|
165
239
|
|
|
240
|
+
function removeAgent(entry) {
|
|
241
|
+
if (entry.filePath && fs.existsSync(entry.filePath)) {
|
|
242
|
+
fs.unlinkSync(entry.filePath);
|
|
243
|
+
}
|
|
244
|
+
if (entry.manifestPath) {
|
|
245
|
+
manifest.removeAgentFromManifest(entry.manifestPath, entry.filePath);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
166
249
|
module.exports = {
|
|
167
250
|
copyDir,
|
|
168
251
|
getAvailableSkills,
|
|
169
252
|
getSkillInfo,
|
|
170
253
|
isHarnessSkillDir,
|
|
171
254
|
installSkillsToTargets,
|
|
255
|
+
installAgentsToTarget,
|
|
172
256
|
getInstalledSkills,
|
|
257
|
+
getInstalledAgents,
|
|
173
258
|
removeSkill,
|
|
259
|
+
removeAgent,
|
|
174
260
|
};
|