@dommaker/harness 0.13.0 → 0.13.2
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/CHANGELOG.md +169 -0
- package/bin/harness-knowledge-capture.js +99 -0
- package/bin/harness-knowledge-check.js +149 -0
- package/bin/harness-knowledge-track.js +92 -0
- package/bin/harness-knowledge-track.sh +47 -0
- package/bin/harness-sensitive-check.sh +67 -0
- package/dist/cli/commands/init.js +34 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/package.json +6 -3
- package/src/CONTEXT.md +34 -0
- package/src/__tests__/acceptance-gate.test.ts +364 -0
- package/src/__tests__/annotation-checker.test.ts +183 -0
- package/src/__tests__/architecture-engine.test.ts +619 -0
- package/src/__tests__/checker-extra.test.ts +1627 -0
- package/src/__tests__/checker.test.ts +1268 -0
- package/src/__tests__/checkpoint.test.ts +697 -0
- package/src/__tests__/clean-state-extra.test.ts +301 -0
- package/src/__tests__/clean-state.test.ts +169 -0
- package/src/__tests__/constraint-doctor.test.ts +410 -0
- package/src/__tests__/constraint-evolver.test.ts +404 -0
- package/src/__tests__/constraint-handler.test.ts +136 -0
- package/src/__tests__/context/progressive-loader.test.ts +131 -0
- package/src/__tests__/contract-gate.test.ts +321 -0
- package/src/__tests__/cross-project-checker.test.ts +318 -0
- package/src/__tests__/cso-validator.test.ts +205 -0
- package/src/__tests__/detect-source-roots.test.ts +98 -0
- package/src/__tests__/doctor-evolver.test.ts +381 -0
- package/src/__tests__/error-classifier.test.ts +304 -0
- package/src/__tests__/exec.test.ts +83 -0
- package/src/__tests__/extend-exceptions.test.ts +149 -0
- package/src/__tests__/failure-recorder.test.ts +335 -0
- package/src/__tests__/hooks-pipeline.test.ts +214 -0
- package/src/__tests__/interceptor.test.ts +89 -0
- package/src/__tests__/iron-laws.test.ts +246 -0
- package/src/__tests__/long-running.test.ts +17 -0
- package/src/__tests__/passes-gate-check.test.ts +138 -0
- package/src/__tests__/passes-gate-extension.test.ts +151 -0
- package/src/__tests__/passes-gate-extra.test.ts +238 -0
- package/src/__tests__/passes-gate.test.ts +231 -0
- package/src/__tests__/performance-analyzer.test.ts +501 -0
- package/src/__tests__/performance-collector.test.ts +276 -0
- package/src/__tests__/performance-gate.test.ts +74 -0
- package/src/__tests__/presets.test.ts +104 -0
- package/src/__tests__/project-config-loader-extra.test.ts +269 -0
- package/src/__tests__/project-config-loader.test.ts +127 -0
- package/src/__tests__/review-gate.test.ts +92 -0
- package/src/__tests__/security-gate.test.ts +100 -0
- package/src/__tests__/session-startup.test.ts +334 -0
- package/src/__tests__/spec-validator.test.ts +57 -0
- package/src/__tests__/token-budget.test.ts +252 -0
- package/src/__tests__/trace-analyzer-extra.test.ts +307 -0
- package/src/__tests__/trace-analyzer.test.ts +131 -0
- package/src/__tests__/trace-collector.test.ts +258 -0
- package/src/__tests__/traces.test.ts +347 -0
- package/src/agents/CONTEXT.md +21 -0
- package/src/agents/__tests__/lifecycle.test.ts +248 -0
- package/src/agents/index.ts +2 -0
- package/src/agents/lifecycle.ts +201 -0
- package/src/agents/types.ts +46 -0
- package/src/architecture/CONTEXT.md +22 -0
- package/src/architecture/constraint-engine.ts +356 -0
- package/src/architecture/cross-project-checker.ts +563 -0
- package/src/cli/commands/CONTEXT.md +24 -0
- package/src/cli/commands/__tests__/acceptance.test.ts +180 -0
- package/src/cli/commands/__tests__/check.test.ts +598 -0
- package/src/cli/commands/__tests__/command.test.ts +149 -0
- package/src/cli/commands/__tests__/contract.test.ts +151 -0
- package/src/cli/commands/__tests__/failure.test.ts +199 -0
- package/src/cli/commands/__tests__/flow.test.ts +343 -0
- package/src/cli/commands/__tests__/init.test.ts +306 -0
- package/src/cli/commands/__tests__/passes-gate.test.ts +256 -0
- package/src/cli/commands/__tests__/performance.test.ts +116 -0
- package/src/cli/commands/__tests__/posteval-plan.test.ts +201 -0
- package/src/cli/commands/__tests__/report-extra.test.ts +98 -0
- package/src/cli/commands/__tests__/report.test.ts +109 -0
- package/src/cli/commands/__tests__/review.test.ts +153 -0
- package/src/cli/commands/__tests__/security.test.ts +147 -0
- package/src/cli/commands/__tests__/spec.test.ts +193 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +223 -0
- package/src/cli/commands/__tests__/status.test.ts +306 -0
- package/src/cli/commands/__tests__/sync-docs.test.ts +335 -0
- package/src/cli/commands/__tests__/validate.test.ts +139 -0
- package/src/cli/commands/acceptance.ts +111 -0
- package/src/cli/commands/analyze-sessions.ts +488 -0
- package/src/cli/commands/check.ts +441 -0
- package/src/cli/commands/command.ts +90 -0
- package/src/cli/commands/constraints.ts +86 -0
- package/src/cli/commands/contract.ts +168 -0
- package/src/cli/commands/failure.ts +117 -0
- package/src/cli/commands/flow.ts +275 -0
- package/src/cli/commands/index.ts +26 -0
- package/src/cli/commands/init.ts +832 -0
- package/src/cli/commands/knowledge.ts +391 -0
- package/src/cli/commands/passes-gate.ts +158 -0
- package/src/cli/commands/performance.ts +108 -0
- package/src/cli/commands/posteval-plan.ts +85 -0
- package/src/cli/commands/release.ts +159 -0
- package/src/cli/commands/report.ts +198 -0
- package/src/cli/commands/review.ts +118 -0
- package/src/cli/commands/security.ts +122 -0
- package/src/cli/commands/spec.ts +158 -0
- package/src/cli/commands/status.ts +169 -0
- package/src/cli/commands/sync-docs.ts +743 -0
- package/src/cli/commands/update-user-model.ts +527 -0
- package/src/cli/commands/validate.ts +222 -0
- package/src/constraints/__tests__/lifecycle-runner.test.ts +246 -0
- package/src/constraints/__tests__/registry.test.ts +196 -0
- package/src/constraints/index.ts +3 -0
- package/src/constraints/lifecycle-runner.ts +184 -0
- package/src/constraints/registry.ts +134 -0
- package/src/constraints/types.ts +59 -0
- package/src/context/CONTEXT.md +28 -0
- package/src/context/__tests__/compaction.test.ts +169 -0
- package/src/context/__tests__/file-budget.test.ts +142 -0
- package/src/context/__tests__/knowledge-injector.test.ts +148 -0
- package/src/context/__tests__/progressive-loader.test.ts +264 -0
- package/src/context/__tests__/session-manager.test.ts +300 -0
- package/src/context/__tests__/token-budget.test.ts +338 -0
- package/src/context/__tests__/token-pipeline.test.ts +178 -0
- package/src/context/__tests__/tool-output-budget.test.ts +95 -0
- package/src/context/compaction.ts +202 -0
- package/src/context/file-budget.ts +142 -0
- package/src/context/index.ts +15 -0
- package/src/context/knowledge-injector.ts +168 -0
- package/src/context/progressive-loader.ts +260 -0
- package/src/context/session-manager.ts +343 -0
- package/src/context/token-budget.ts +295 -0
- package/src/context/token-pipeline.ts +265 -0
- package/src/context/tool-output-budget.ts +178 -0
- package/src/context/types.ts +160 -0
- package/src/core/CONTEXT.md +26 -0
- package/src/core/constraints/__tests__/default-executors.test.ts +57 -0
- package/src/core/constraints/__tests__/interceptor.test.ts +251 -0
- package/src/core/constraints/__tests__/prompt-injection.test.ts +89 -0
- package/src/core/constraints/check-cache.ts +96 -0
- package/src/core/constraints/checker.ts +1169 -0
- package/src/core/constraints/default-executors.ts +92 -0
- package/src/core/constraints/definitions.ts +1119 -0
- package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +551 -0
- package/src/core/constraints/doc-freshness/auto-fix.ts +69 -0
- package/src/core/constraints/doc-freshness/runner.ts +486 -0
- package/src/core/constraints/index.ts +78 -0
- package/src/core/constraints/interceptor.ts +220 -0
- package/src/core/constraints/prompt-injection.ts +73 -0
- package/src/core/index.ts +23 -0
- package/src/core/project-config-loader.ts +252 -0
- package/src/core/session/__tests__/startup.test.ts +281 -0
- package/src/core/session/clean-state.ts +178 -0
- package/src/core/session/index.ts +15 -0
- package/src/core/session/startup.ts +253 -0
- package/src/core/spec/__tests__/validator.test.ts +379 -0
- package/src/core/spec/index.ts +7 -0
- package/src/core/spec/validator.ts +383 -0
- package/src/core/validators/__tests__/passes-gate.test.ts +131 -0
- package/src/core/validators/checkpoint.ts +547 -0
- package/src/core/validators/cso.ts +124 -0
- package/src/core/validators/index.ts +25 -0
- package/src/core/validators/passes-gate.ts +613 -0
- package/src/dashboard/CONTEXT.md +21 -0
- package/src/dashboard/__tests__/data.test.ts +115 -0
- package/src/dashboard/__tests__/stats.test.ts +156 -0
- package/src/dashboard/data.ts +113 -0
- package/src/dashboard/index.ts +3 -0
- package/src/dashboard/stats.ts +127 -0
- package/src/dashboard/types.ts +113 -0
- package/src/evolution/CONTEXT.md +22 -0
- package/src/evolution/__tests__/auto-evolve.test.ts +320 -0
- package/src/evolution/auto-evolve.ts +98 -0
- package/src/evolution/index.ts +1 -0
- package/src/failure/CONTEXT.md +24 -0
- package/src/failure/classifier.ts +156 -0
- package/src/failure/constraint-handler.ts +173 -0
- package/src/failure/index.ts +35 -0
- package/src/failure/recorder.ts +201 -0
- package/src/failure/types.ts +165 -0
- package/src/gates/CONTEXT.md +27 -0
- package/src/gates/__tests__/acceptance.test.ts +608 -0
- package/src/gates/__tests__/command.test.ts +206 -0
- package/src/gates/__tests__/performance.test.ts +381 -0
- package/src/gates/__tests__/review.test.ts +302 -0
- package/src/gates/__tests__/security.test.ts +332 -0
- package/src/gates/acceptance.ts +493 -0
- package/src/gates/command.ts +444 -0
- package/src/gates/contract.ts +260 -0
- package/src/gates/index.ts +67 -0
- package/src/gates/performance.ts +359 -0
- package/src/gates/review.ts +169 -0
- package/src/gates/security.ts +244 -0
- package/src/gates/types.ts +159 -0
- package/src/governance/CONTEXT.md +22 -0
- package/src/governance/__tests__/executor.test.ts +249 -0
- package/src/governance/executor.ts +229 -0
- package/src/governance/index.ts +13 -0
- package/src/governance/types.ts +53 -0
- package/src/hooks/CONTEXT.md +23 -0
- package/src/hooks/__tests__/bootstrap.test.ts +184 -0
- package/src/hooks/bootstrap.ts +144 -0
- package/src/hooks/index.ts +15 -0
- package/src/hooks/pipeline.ts +157 -0
- package/src/hooks/registry.ts +88 -0
- package/src/hooks/types.ts +80 -0
- package/src/index.ts +198 -0
- package/src/knowledge/CONTEXT.md +29 -0
- package/src/knowledge/__tests__/doctor.test.ts +272 -0
- package/src/knowledge/__tests__/import.test.ts +376 -0
- package/src/knowledge/__tests__/ingest.test.ts +125 -0
- package/src/knowledge/__tests__/lifecycle-hooks.test.ts +137 -0
- package/src/knowledge/__tests__/lifecycle.test.ts +248 -0
- package/src/knowledge/__tests__/lint.test.ts +401 -0
- package/src/knowledge/__tests__/query.test.ts +185 -0
- package/src/knowledge/__tests__/reference-tracker.test.ts +129 -0
- package/src/knowledge/__tests__/store.test.ts +238 -0
- package/src/knowledge/doctor.ts +104 -0
- package/src/knowledge/import.ts +505 -0
- package/src/knowledge/index.ts +16 -0
- package/src/knowledge/ingest.ts +126 -0
- package/src/knowledge/lifecycle-hooks.ts +199 -0
- package/src/knowledge/lifecycle.ts +175 -0
- package/src/knowledge/lint.ts +360 -0
- package/src/knowledge/query.ts +150 -0
- package/src/knowledge/reference-tracker.ts +99 -0
- package/src/knowledge/store.ts +264 -0
- package/src/knowledge/types.ts +139 -0
- package/src/llm/CONTEXT.md +21 -0
- package/src/llm/__tests__/adapter.test.ts +172 -0
- package/src/llm/adapter.ts +149 -0
- package/src/llm/index.ts +2 -0
- package/src/llm/types.ts +81 -0
- package/src/monitoring/CONTEXT.md +29 -0
- package/src/monitoring/__tests__/context-tracker.test.ts +172 -0
- package/src/monitoring/__tests__/knowledge-doctor.test.ts +276 -0
- package/src/monitoring/__tests__/knowledge-evolver.test.ts +365 -0
- package/src/monitoring/__tests__/performance-analyzer.test.ts +137 -0
- package/src/monitoring/__tests__/performance-collector.test.ts +332 -0
- package/src/monitoring/__tests__/traces.test.ts +190 -0
- package/src/monitoring/constraint-doctor.ts +499 -0
- package/src/monitoring/constraint-evolver.ts +573 -0
- package/src/monitoring/context-tracker.ts +148 -0
- package/src/monitoring/index.ts +23 -0
- package/src/monitoring/knowledge-doctor.ts +323 -0
- package/src/monitoring/knowledge-evolver.ts +289 -0
- package/src/monitoring/performance-analyzer.ts +450 -0
- package/src/monitoring/performance-collector.ts +348 -0
- package/src/monitoring/trace-analyzer.ts +470 -0
- package/src/monitoring/traces.ts +339 -0
- package/src/presets/__tests__/standard.test.ts +104 -0
- package/src/presets/index.ts +16 -0
- package/src/presets/standard.ts +163 -0
- package/src/safety/CONTEXT.md +23 -0
- package/src/safety/__tests__/input-guardrail.test.ts +105 -0
- package/src/safety/__tests__/output-guardrail.test.ts +108 -0
- package/src/safety/__tests__/sandbox.test.ts +158 -0
- package/src/safety/__tests__/tool-guardrail.test.ts +127 -0
- package/src/safety/index.ts +5 -0
- package/src/safety/input-guardrail.ts +133 -0
- package/src/safety/output-guardrail.ts +174 -0
- package/src/safety/sandbox.ts +148 -0
- package/src/safety/tool-guardrail.ts +176 -0
- package/src/safety/types.ts +124 -0
- package/src/spec/CONTEXT.md +19 -0
- package/src/spec/__tests__/annotation-checker.test.ts +289 -0
- package/src/spec/annotation-checker.ts +342 -0
- package/src/tools/CONTEXT.md +25 -0
- package/src/tools/__tests__/loader.test.ts +252 -0
- package/src/tools/__tests__/registry.test.ts +157 -0
- package/src/tools/core/__tests__/core.test.ts +122 -0
- package/src/tools/core/index.ts +201 -0
- package/src/tools/core/package.json +7 -0
- package/src/tools/core/pnpm-lock.yaml +232 -0
- package/src/tools/definitions/core/code/fingerprint.sh +273 -0
- package/src/tools/definitions/core/code/fingerprint.yml +72 -0
- package/src/tools/definitions/core/code/parse.yml +68 -0
- package/src/tools/definitions/core/code/register-language.sh +475 -0
- package/src/tools/definitions/core/code/register-language.yml +74 -0
- package/src/tools/definitions/core/docker/build.yml +73 -0
- package/src/tools/definitions/core/docker/run.yml +81 -0
- package/src/tools/definitions/core/file/copy.yml +88 -0
- package/src/tools/definitions/core/file/read.yml +69 -0
- package/src/tools/definitions/core/file/write.yml +75 -0
- package/src/tools/definitions/core/git/branch.yml +61 -0
- package/src/tools/definitions/core/git/cleanup-worktree.yml +50 -0
- package/src/tools/definitions/core/git/clone.yml +69 -0
- package/src/tools/definitions/core/git/commit.yml +65 -0
- package/src/tools/definitions/core/git/push.yml +79 -0
- package/src/tools/definitions/core/git/worktree.yml +96 -0
- package/src/tools/definitions/core/notification/notify.sh +152 -0
- package/src/tools/definitions/core/notification/notify.yml +60 -0
- package/src/tools/definitions/core/npm/build.yml +75 -0
- package/src/tools/definitions/core/npm/install.yml +58 -0
- package/src/tools/definitions/core/npm/test.yml +75 -0
- package/src/tools/definitions/core/validation/check-reuse.yml +170 -0
- package/src/tools/definitions/core/validation/validate-handlers.yml +118 -0
- package/src/tools/definitions/core/validation/validate-readme-stats.yml +155 -0
- package/src/tools/definitions/core/validation/validate-yaml-syntax.yml +134 -0
- package/src/tools/definitions/ext/browser/browser-automate.sh +255 -0
- package/src/tools/definitions/ext/browser/browser-automate.yml +166 -0
- package/src/tools/definitions/ext/browser/browser-close.sh +104 -0
- package/src/tools/definitions/ext/browser/browser-close.yml +55 -0
- package/src/tools/definitions/ext/browser/browser-mcp-debug.sh +682 -0
- package/src/tools/definitions/ext/browser/browser-mcp-debug.yml +167 -0
- package/src/tools/definitions/ext/browser/browser-start.sh +101 -0
- package/src/tools/definitions/ext/browser/browser-start.yml +62 -0
- package/src/tools/definitions/registry.json +795 -0
- package/src/tools/definitions/std/README.md +350 -0
- package/src/tools/definitions/std/analysis/analyze-codebase.yml +72 -0
- package/src/tools/definitions/std/analysis/analyze-diff.yml +182 -0
- package/src/tools/definitions/std/analysis/analyze-git-diff.yml +70 -0
- package/src/tools/definitions/std/analysis/analyze-impact.yml +78 -0
- package/src/tools/definitions/std/analysis/analyze-requirements.yml +105 -0
- package/src/tools/definitions/std/analysis/brainstorm-options.yml +106 -0
- package/src/tools/definitions/std/analysis/build-graph.yml +154 -0
- package/src/tools/definitions/std/analysis/clarify-requirements.yml +90 -0
- package/src/tools/definitions/std/analysis/detect-context.yml +109 -0
- package/src/tools/definitions/std/analysis/detect-layers.yml +125 -0
- package/src/tools/definitions/std/analysis/generate-tour.yml +102 -0
- package/src/tools/definitions/std/analysis/search-enhance.yml +105 -0
- package/src/tools/definitions/std/backlog/add.yml +51 -0
- package/src/tools/definitions/std/backlog/decide.yml +39 -0
- package/src/tools/definitions/std/backlog/github-sync.yml +161 -0
- package/src/tools/definitions/std/backlog/list.yml +53 -0
- package/src/tools/definitions/std/backlog/load.yml +46 -0
- package/src/tools/definitions/std/backlog/resolve.yml +37 -0
- package/src/tools/definitions/std/backlog/update.yml +42 -0
- package/src/tools/definitions/std/bugfix/diagnose.yml +68 -0
- package/src/tools/definitions/std/bugfix/fix.yml +66 -0
- package/src/tools/definitions/std/bugfix/verify.yml +69 -0
- package/src/tools/definitions/std/constraint/check-decomposition.yml +103 -0
- package/src/tools/definitions/std/constraint/check-feature-list.yml +77 -0
- package/src/tools/definitions/std/constraint/check-progress.yml +97 -0
- package/src/tools/definitions/std/constraint/generate-report.yml +147 -0
- package/src/tools/definitions/std/deploy/commit-push.yml +33 -0
- package/src/tools/definitions/std/deploy/deploy-backend.yml +37 -0
- package/src/tools/definitions/std/deploy/deploy-frontend.yml +37 -0
- package/src/tools/definitions/std/deploy/rollback.yml +148 -0
- package/src/tools/definitions/std/design/analyze-architecture-impact.yml +113 -0
- package/src/tools/definitions/std/design/design-api.yml +55 -0
- package/src/tools/definitions/std/design/design-architecture.yml +97 -0
- package/src/tools/definitions/std/design/design-db.yml +81 -0
- package/src/tools/definitions/std/design/generate-spec.yml +182 -0
- package/src/tools/definitions/std/development/develop-api.yml +85 -0
- package/src/tools/definitions/std/development/develop-backend.yml +88 -0
- package/src/tools/definitions/std/development/develop-frontend.yml +87 -0
- package/src/tools/definitions/std/development/develop-shared-types.yml +74 -0
- package/src/tools/definitions/std/development/develop-task.yml +122 -0
- package/src/tools/definitions/std/development/develop-tests.yml +76 -0
- package/src/tools/definitions/std/development/execute-batch.yml +152 -0
- package/src/tools/definitions/std/development/fix-issues.yml +100 -0
- package/src/tools/definitions/std/development/implement-task.yml +124 -0
- package/src/tools/definitions/std/development/review-fix-cycle.yml +232 -0
- package/src/tools/definitions/std/evolution/implement.yml +125 -0
- package/src/tools/definitions/std/evolution/prioritize.yml +112 -0
- package/src/tools/definitions/std/evolution/report-gap.yml +166 -0
- package/src/tools/definitions/std/file/read.yml +21 -0
- package/src/tools/definitions/std/governance/aggregate-opinions.sh +201 -0
- package/src/tools/definitions/std/governance/aggregate-opinions.yml +79 -0
- package/src/tools/definitions/std/governance/audit-task.yml +178 -0
- package/src/tools/definitions/std/governance/cast-vote.yml +129 -0
- package/src/tools/definitions/std/governance/collect-issues.yml +16 -0
- package/src/tools/definitions/std/governance/create-signed-document.yml +23 -0
- package/src/tools/definitions/std/governance/create-voting-session.yml +101 -0
- package/src/tools/definitions/std/governance/define-stance.sh +243 -0
- package/src/tools/definitions/std/governance/define-stance.yml +82 -0
- package/src/tools/definitions/std/governance/generate-review-report.yml +23 -0
- package/src/tools/definitions/std/governance/impeach.yml +179 -0
- package/src/tools/definitions/std/governance/multi-stance-review.yml +154 -0
- package/src/tools/definitions/std/governance/prepare-artifact.yml +20 -0
- package/src/tools/definitions/std/governance/review-spec-approval.yml +262 -0
- package/src/tools/definitions/std/governance/rollback.yml +186 -0
- package/src/tools/definitions/std/governance/stance-review.yml +149 -0
- package/src/tools/definitions/std/governance/track-effect.yml +199 -0
- package/src/tools/definitions/std/governance/vote-tally.yml +144 -0
- package/src/tools/definitions/std/patch/execute.yml +51 -0
- package/src/tools/definitions/std/planning/generate-tasks.yml +36 -0
- package/src/tools/definitions/std/planning/load-tasks.yml +44 -0
- package/src/tools/definitions/std/planning/split-batch.yml +481 -0
- package/src/tools/definitions/std/planning/split-tasks.yml +359 -0
- package/src/tools/definitions/std/planning/update-tasks.yml +51 -0
- package/src/tools/definitions/std/planning/validate-tasks.yml +46 -0
- package/src/tools/definitions/std/project/decide-next-workflow.yml +38 -0
- package/src/tools/definitions/std/project/load-state.yml +31 -0
- package/src/tools/definitions/std/project/save-state.yml +32 -0
- package/src/tools/definitions/std/quality/check-quality.yml +241 -0
- package/src/tools/definitions/std/quality/debug-systematic.yml +163 -0
- package/src/tools/definitions/std/quality/handle-feedback.yml +108 -0
- package/src/tools/definitions/std/quality/review-code.yml +128 -0
- package/src/tools/definitions/std/quality/review-spec.yml +140 -0
- package/src/tools/definitions/std/quality/review-task.yml +190 -0
- package/src/tools/definitions/std/quality/run-tests.yml +80 -0
- package/src/tools/definitions/std/quick/analyze.yml +56 -0
- package/src/tools/definitions/std/quick/implement.yml +67 -0
- package/src/tools/definitions/std/quick/verify.yml +71 -0
- package/src/tools/definitions/std/verification/verify_completion.yml +113 -0
- package/src/tools/definitions/std/verification/wait-condition.yml +107 -0
- package/src/tools/index.ts +5 -0
- package/src/tools/loader.ts +216 -0
- package/src/tools/paths.ts +15 -0
- package/src/tools/registry.ts +128 -0
- package/src/tools/types.ts +46 -0
- package/src/types/__tests__/types.test.ts +86 -0
- package/src/types/checkpoint.ts +174 -0
- package/src/types/constraint.ts +335 -0
- package/src/types/cso.ts +37 -0
- package/src/types/enforcement.ts +48 -0
- package/src/types/index.ts +59 -0
- package/src/types/iron-law.ts +50 -0
- package/src/types/passes-gate.ts +185 -0
- package/src/types/performance.ts +295 -0
- package/src/types/project-config.ts +251 -0
- package/src/types/session.ts +132 -0
- package/src/types/spec.ts +91 -0
- package/src/types/trace.ts +228 -0
- package/src/utils/detect-source-roots.ts +114 -0
- package/src/utils/exec.ts +61 -0
- package/src/verification/CONTEXT.md +23 -0
- package/src/verification/__tests__/loop.test.ts +303 -0
- package/src/verification/__tests__/rules-based.test.ts +240 -0
- package/src/verification/index.ts +3 -0
- package/src/verification/loop.ts +137 -0
- package/src/verification/rules-based.ts +153 -0
- package/src/verification/types.ts +81 -0
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* harness init 命令
|
|
3
|
+
*
|
|
4
|
+
* 初始化项目的 harness 配置
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { readFileSync } from 'fs';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as yaml from 'js-yaml';
|
|
12
|
+
import { createExampleCheckpoint, createExampleResolutions } from './validate';
|
|
13
|
+
import { detectSourceRoots } from '../../utils/detect-source-roots';
|
|
14
|
+
import { IRON_LAWS, GUIDELINES, TIPS, getAllConstraints } from '../../core/constraints/definitions';
|
|
15
|
+
|
|
16
|
+
export interface InitOptions {
|
|
17
|
+
/** 项目路径 */
|
|
18
|
+
projectPath?: string;
|
|
19
|
+
/** 预设名称 */
|
|
20
|
+
preset: 'strict' | 'standard' | 'relaxed';
|
|
21
|
+
/** 治理级别 */
|
|
22
|
+
governance?: 'minimal' | 'standard' | 'strict';
|
|
23
|
+
/** 项目类型 */
|
|
24
|
+
type?: 'node-api' | 'nextjs-app' | 'python-api' | 'custom';
|
|
25
|
+
/** 是否创建 Git hooks */
|
|
26
|
+
gitHooks?: boolean;
|
|
27
|
+
/** 是否创建 GitHub Actions */
|
|
28
|
+
githubActions?: boolean;
|
|
29
|
+
/** 只输出代码片段,不创建文件 */
|
|
30
|
+
printSnippets?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 默认配置
|
|
35
|
+
*/
|
|
36
|
+
const DEFAULT_CONFIG = {
|
|
37
|
+
preset: 'standard',
|
|
38
|
+
enabled: true,
|
|
39
|
+
ironLaws: {
|
|
40
|
+
enforceErrors: true,
|
|
41
|
+
warnWarnings: true,
|
|
42
|
+
},
|
|
43
|
+
validators: {
|
|
44
|
+
checkpoint: true,
|
|
45
|
+
passesGate: true,
|
|
46
|
+
cso: false,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 预设配置
|
|
52
|
+
*/
|
|
53
|
+
const PRESETS = {
|
|
54
|
+
strict: {
|
|
55
|
+
...DEFAULT_CONFIG,
|
|
56
|
+
preset: 'strict',
|
|
57
|
+
ironLaws: {
|
|
58
|
+
enforceErrors: true,
|
|
59
|
+
warnWarnings: true,
|
|
60
|
+
},
|
|
61
|
+
validators: {
|
|
62
|
+
checkpoint: true,
|
|
63
|
+
passesGate: true,
|
|
64
|
+
cso: true,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
standard: {
|
|
68
|
+
...DEFAULT_CONFIG,
|
|
69
|
+
preset: 'standard',
|
|
70
|
+
},
|
|
71
|
+
relaxed: {
|
|
72
|
+
...DEFAULT_CONFIG,
|
|
73
|
+
preset: 'relaxed',
|
|
74
|
+
ironLaws: {
|
|
75
|
+
enforceErrors: true,
|
|
76
|
+
warnWarnings: false,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 治理预设
|
|
83
|
+
*/
|
|
84
|
+
const GOVERNANCE_PRESETS: Record<string, Record<string, unknown>> = {
|
|
85
|
+
minimal: {
|
|
86
|
+
level: 'minimal',
|
|
87
|
+
docs: {
|
|
88
|
+
sync_command: 'harness sync-docs',
|
|
89
|
+
check_on_ci: false,
|
|
90
|
+
files: ['CAPABILITIES.md'],
|
|
91
|
+
},
|
|
92
|
+
context_files: {
|
|
93
|
+
enabled: false,
|
|
94
|
+
required_dirs: [],
|
|
95
|
+
},
|
|
96
|
+
changelog: {
|
|
97
|
+
format: 'keep-a-changelog',
|
|
98
|
+
},
|
|
99
|
+
testing: {
|
|
100
|
+
test_first: true,
|
|
101
|
+
coverage_threshold: 85,
|
|
102
|
+
incremental_coverage: false,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
standard: {
|
|
106
|
+
level: 'standard',
|
|
107
|
+
docs: {
|
|
108
|
+
sync_command: 'harness sync-docs',
|
|
109
|
+
check_on_ci: true,
|
|
110
|
+
files: ['CAPABILITIES.md', 'README.md'],
|
|
111
|
+
},
|
|
112
|
+
context_files: {
|
|
113
|
+
enabled: true,
|
|
114
|
+
required_dirs: [],
|
|
115
|
+
},
|
|
116
|
+
changelog: {
|
|
117
|
+
format: 'keep-a-changelog',
|
|
118
|
+
},
|
|
119
|
+
testing: {
|
|
120
|
+
test_first: true,
|
|
121
|
+
coverage_threshold: 85,
|
|
122
|
+
incremental_coverage: false,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
strict: {
|
|
126
|
+
level: 'strict',
|
|
127
|
+
docs: {
|
|
128
|
+
sync_command: 'harness sync-docs',
|
|
129
|
+
check_on_ci: true,
|
|
130
|
+
files: ['CAPABILITIES.md', 'README.md', 'CHANGELOG.md'],
|
|
131
|
+
},
|
|
132
|
+
context_files: {
|
|
133
|
+
enabled: true,
|
|
134
|
+
required_dirs: [],
|
|
135
|
+
},
|
|
136
|
+
changelog: {
|
|
137
|
+
format: 'keep-a-changelog',
|
|
138
|
+
},
|
|
139
|
+
testing: {
|
|
140
|
+
test_first: true,
|
|
141
|
+
coverage_threshold: 85,
|
|
142
|
+
incremental_coverage: true,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 初始化项目
|
|
149
|
+
*/
|
|
150
|
+
export async function init(options: InitOptions): Promise<void> {
|
|
151
|
+
// 只输出代码片段
|
|
152
|
+
if (options.printSnippets) {
|
|
153
|
+
printSnippets();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log(chalk.blue('🚀 初始化 harness 配置...'));
|
|
158
|
+
|
|
159
|
+
const projectPath = options.projectPath || process.cwd();
|
|
160
|
+
const configDir = path.join(projectPath, '.harness');
|
|
161
|
+
|
|
162
|
+
// 创建配置目录
|
|
163
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
164
|
+
console.log(chalk.gray(`配置目录: ${configDir}`));
|
|
165
|
+
|
|
166
|
+
// 选择预设
|
|
167
|
+
const preset = PRESETS[options.preset];
|
|
168
|
+
console.log(chalk.gray(`预设: ${options.preset}`));
|
|
169
|
+
|
|
170
|
+
// 合并治理配置
|
|
171
|
+
const configData: Record<string, unknown> = { ...preset };
|
|
172
|
+
if (options.governance) {
|
|
173
|
+
configData.governance = GOVERNANCE_PRESETS[options.governance];
|
|
174
|
+
console.log(chalk.gray(`治理级别: ${options.governance}`));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 写入 harness 版本
|
|
178
|
+
const pkgVersion = getPackageVersion();
|
|
179
|
+
configData.harness = { version: pkgVersion };
|
|
180
|
+
|
|
181
|
+
// 写入配置文件(harness 管理的配置,始终重新生成)
|
|
182
|
+
const configPath = path.join(configDir, 'config.yml');
|
|
183
|
+
const configContent = yaml.dump(configData, { indent: 2 });
|
|
184
|
+
await fs.writeFile(configPath, configContent, 'utf-8');
|
|
185
|
+
console.log(chalk.green(`✅ 已创建配置文件: ${configPath} (v${pkgVersion})`));
|
|
186
|
+
|
|
187
|
+
// 创建检查点示例
|
|
188
|
+
await createExampleCheckpoint(projectPath);
|
|
189
|
+
|
|
190
|
+
// 创建 Resolutions(RKB 狗粮 — 约束 → 已知解法映射)
|
|
191
|
+
await createExampleResolutions(projectPath);
|
|
192
|
+
|
|
193
|
+
// 创建自定义约束示例
|
|
194
|
+
await createCustomConstraintsExample(projectPath);
|
|
195
|
+
|
|
196
|
+
// CAPABILITIES.md / CHANGELOG.md 由 sync-docs(AI 治理)管理,init 不创建
|
|
197
|
+
|
|
198
|
+
// 创建 Git hooks
|
|
199
|
+
if (options.gitHooks !== false) {
|
|
200
|
+
await setupGitHooks(projectPath);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 创建 GitHub Actions
|
|
204
|
+
if (options.githubActions !== false) {
|
|
205
|
+
await setupGitHubActions(projectPath, options.preset);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 治理相关文件生成
|
|
209
|
+
if (options.governance) {
|
|
210
|
+
await setupGovernance(projectPath, options.governance);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log();
|
|
214
|
+
console.log(chalk.green('✅ harness 初始化完成!'));
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(chalk.gray('下一步:'));
|
|
217
|
+
console.log(chalk.gray(' 1. 编辑 .harness/config.yml 自定义配置'));
|
|
218
|
+
console.log(chalk.gray(' 2. 编辑 .harness/custom-constraints.yml 添加项目约束'));
|
|
219
|
+
console.log(chalk.gray(' 3. 正常开发,每次 git commit 会自动检查约束'));
|
|
220
|
+
console.log(chalk.gray(' 4. 运行 harness status 查看状态'));
|
|
221
|
+
console.log();
|
|
222
|
+
console.log(chalk.blue('💡 提示: 使用 harness init --print-snippets 查看配置代码片段'));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 获取 harness 包版本
|
|
227
|
+
*/
|
|
228
|
+
function getPackageVersion(): string {
|
|
229
|
+
try {
|
|
230
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
231
|
+
return require('../../../package.json').version;
|
|
232
|
+
} catch {
|
|
233
|
+
return 'unknown';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 输出代码片段
|
|
239
|
+
*/
|
|
240
|
+
function printSnippets(): void {
|
|
241
|
+
console.log(chalk.blue('📄 Harness 配置代码片段'));
|
|
242
|
+
console.log();
|
|
243
|
+
|
|
244
|
+
console.log(chalk.yellow('Git pre-commit hook:'));
|
|
245
|
+
console.log(chalk.gray('添加到 .git/hooks/pre-commit'));
|
|
246
|
+
console.log();
|
|
247
|
+
console.log(chalk.cyan(PRE_COMMIT_SNIPPET));
|
|
248
|
+
|
|
249
|
+
console.log(chalk.yellow('GitHub Actions:'));
|
|
250
|
+
console.log(chalk.gray('添加到 .github/workflows/*.yml 的 jobs 中'));
|
|
251
|
+
console.log();
|
|
252
|
+
console.log(chalk.cyan(GITHUB_ACTIONS_SNIPPET));
|
|
253
|
+
|
|
254
|
+
console.log(chalk.blue('💡 提示: 运行 harness init 自动创建配置文件'));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Git pre-commit 代码片段
|
|
259
|
+
*/
|
|
260
|
+
const PRE_COMMIT_SNIPPET = `
|
|
261
|
+
# Harness 约束检查
|
|
262
|
+
npx harness check --staged
|
|
263
|
+
if [ $? -ne 0 ]; then
|
|
264
|
+
echo "❌ Iron law check failed"
|
|
265
|
+
exit 1
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
# Plan coverage check (via PostEval)
|
|
269
|
+
STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
|
|
270
|
+
if command -v npx > /dev/null 2>&1; then
|
|
271
|
+
PLAN_FILES=$(echo "$STAGED" | grep -E 'plans/.*\.md$|\.plan\.md$' || true)
|
|
272
|
+
if [ -n "$PLAN_FILES" ]; then
|
|
273
|
+
echo "📋 Checking plan coverage..."
|
|
274
|
+
for plan in $PLAN_FILES; do
|
|
275
|
+
npx harness posteval-plan "$plan" || {
|
|
276
|
+
echo "🛑 Plan coverage incomplete. See above for missed items."
|
|
277
|
+
exit 1
|
|
278
|
+
}
|
|
279
|
+
done
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
`;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* GitHub Actions 代码片段
|
|
286
|
+
*/
|
|
287
|
+
const GITHUB_ACTIONS_SNIPPET = `
|
|
288
|
+
harness-check:
|
|
289
|
+
runs-on: ubuntu-latest
|
|
290
|
+
steps:
|
|
291
|
+
- uses: actions/checkout@v4
|
|
292
|
+
- uses: actions/setup-node@v4
|
|
293
|
+
with:
|
|
294
|
+
node-version: '20'
|
|
295
|
+
- run: npm ci
|
|
296
|
+
- run: npx harness check
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* 设置 Git hooks
|
|
301
|
+
*/
|
|
302
|
+
async function setupGitHooks(projectPath: string): Promise<void> {
|
|
303
|
+
const gitDir = path.join(projectPath, '.git');
|
|
304
|
+
const hooksDir = path.join(gitDir, 'hooks');
|
|
305
|
+
const preCommitPath = path.join(hooksDir, 'pre-commit');
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
await fs.access(gitDir);
|
|
309
|
+
} catch {
|
|
310
|
+
console.log(chalk.yellow('⚠️ 未检测到 Git 仓库,跳过 Git hooks'));
|
|
311
|
+
console.log(chalk.gray('💡 初始化 Git 后可运行 harness init --print-snippets 查看配置'));
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
await fs.mkdir(hooksDir, { recursive: true });
|
|
316
|
+
|
|
317
|
+
// 检查 pre-commit 是否已存在
|
|
318
|
+
try {
|
|
319
|
+
await fs.access(preCommitPath);
|
|
320
|
+
// 已存在,输出代码片段
|
|
321
|
+
console.log(chalk.yellow('⚠️ .git/hooks/pre-commit 已存在'));
|
|
322
|
+
console.log(chalk.gray('💡 请手动添加以下内容到文件末尾:'));
|
|
323
|
+
console.log();
|
|
324
|
+
console.log(chalk.cyan(PRE_COMMIT_SNIPPET));
|
|
325
|
+
} catch {
|
|
326
|
+
// 不存在,创建文件
|
|
327
|
+
const preCommitContent = `#!/bin/sh
|
|
328
|
+
# Harness pre-commit hook
|
|
329
|
+
|
|
330
|
+
echo "🔍 Running harness checks..."
|
|
331
|
+
|
|
332
|
+
STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
|
|
333
|
+
|
|
334
|
+
# 铁律检查
|
|
335
|
+
npx harness check --staged
|
|
336
|
+
if [ $? -ne 0 ]; then
|
|
337
|
+
echo "❌ Iron law check failed"
|
|
338
|
+
exit 1
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
# Plan coverage check (via PostEval)
|
|
342
|
+
if command -v npx > /dev/null 2>&1; then
|
|
343
|
+
PLAN_FILES=$(echo "$STAGED" | grep -E 'plans/.*\\.md$|\\.plan\\.md$' || true)
|
|
344
|
+
if [ -n "$PLAN_FILES" ]; then
|
|
345
|
+
echo "📋 Checking plan coverage..."
|
|
346
|
+
for plan in $PLAN_FILES; do
|
|
347
|
+
npx harness posteval-plan "$plan" || {
|
|
348
|
+
echo "🛑 Plan coverage incomplete. See above for missed items."
|
|
349
|
+
exit 1
|
|
350
|
+
}
|
|
351
|
+
done
|
|
352
|
+
fi
|
|
353
|
+
fi
|
|
354
|
+
|
|
355
|
+
echo "✅ All checks passed"
|
|
356
|
+
`;
|
|
357
|
+
await fs.writeFile(preCommitPath, preCommitContent, 'utf-8');
|
|
358
|
+
await fs.chmod(preCommitPath, 0o755);
|
|
359
|
+
console.log(chalk.green(`✅ 已创建 .git/hooks/pre-commit`));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* 设置 GitHub Actions
|
|
365
|
+
*/
|
|
366
|
+
async function setupGitHubActions(projectPath: string, preset: string): Promise<void> {
|
|
367
|
+
const workflowsDir = path.join(projectPath, '.github', 'workflows');
|
|
368
|
+
const workflowPath = path.join(workflowsDir, 'harness-check.yml');
|
|
369
|
+
|
|
370
|
+
// 检查是否已有 CI 配置
|
|
371
|
+
const existingFiles = await findCiWorkflows(workflowsDir);
|
|
372
|
+
|
|
373
|
+
if (existingFiles.length > 0) {
|
|
374
|
+
// 已有 CI 配置,输出代码片段
|
|
375
|
+
console.log(chalk.yellow('⚠️ 检测到已存在的 CI 配置:'));
|
|
376
|
+
existingFiles.forEach(f => {
|
|
377
|
+
console.log(chalk.gray(` - .github/workflows/${f}`));
|
|
378
|
+
});
|
|
379
|
+
console.log(chalk.gray('💡 请手动添加以下内容到 jobs 中:'));
|
|
380
|
+
console.log();
|
|
381
|
+
console.log(chalk.cyan(GITHUB_ACTIONS_SNIPPET));
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// 没有现有 CI 配置,创建文件
|
|
386
|
+
await fs.mkdir(workflowsDir, { recursive: true });
|
|
387
|
+
const workflowContent = `name: Harness Check
|
|
388
|
+
|
|
389
|
+
on:
|
|
390
|
+
push:
|
|
391
|
+
branches: [main, master]
|
|
392
|
+
pull_request:
|
|
393
|
+
branches: [main, master]
|
|
394
|
+
|
|
395
|
+
jobs:
|
|
396
|
+
harness-check:
|
|
397
|
+
runs-on: ubuntu-latest
|
|
398
|
+
|
|
399
|
+
steps:
|
|
400
|
+
- uses: actions/checkout@v4
|
|
401
|
+
|
|
402
|
+
- name: Setup Node.js
|
|
403
|
+
uses: actions/setup-node@v4
|
|
404
|
+
with:
|
|
405
|
+
node-version: '20'
|
|
406
|
+
|
|
407
|
+
- name: Install dependencies
|
|
408
|
+
run: npm ci
|
|
409
|
+
|
|
410
|
+
- name: Run harness check
|
|
411
|
+
run: npx harness check
|
|
412
|
+
|
|
413
|
+
- name: Run harness validate
|
|
414
|
+
run: npx harness validate
|
|
415
|
+
|
|
416
|
+
- name: Run harness passes-gate
|
|
417
|
+
run: npx harness passes-gate
|
|
418
|
+
`;
|
|
419
|
+
|
|
420
|
+
await fs.writeFile(workflowPath, workflowContent, 'utf-8');
|
|
421
|
+
console.log(chalk.green(`✅ 已创建 .github/workflows/harness-check.yml`));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 查找已存在的 CI 工作流文件
|
|
426
|
+
*/
|
|
427
|
+
async function findCiWorkflows(workflowsDir: string): Promise<string[]> {
|
|
428
|
+
try {
|
|
429
|
+
await fs.access(workflowsDir);
|
|
430
|
+
const files = await fs.readdir(workflowsDir);
|
|
431
|
+
// 过滤出可能是 CI 配置的文件
|
|
432
|
+
return files.filter(f =>
|
|
433
|
+
f.endsWith('.yml') || f.endsWith('.yaml')
|
|
434
|
+
);
|
|
435
|
+
} catch {
|
|
436
|
+
return [];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* 创建自定义约束示例
|
|
442
|
+
*/
|
|
443
|
+
async function createCustomConstraintsExample(projectPath: string): Promise<void> {
|
|
444
|
+
const configDir = path.join(projectPath, '.harness');
|
|
445
|
+
const customConstraintsPath = path.join(configDir, 'custom-constraints.yml');
|
|
446
|
+
|
|
447
|
+
// 如果已存在,不覆盖
|
|
448
|
+
try {
|
|
449
|
+
await fs.access(customConstraintsPath);
|
|
450
|
+
console.log(chalk.gray(`custom-constraints.yml 已存在`));
|
|
451
|
+
return;
|
|
452
|
+
} catch {
|
|
453
|
+
// 文件不存在,创建
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const content = `# 自定义约束配置
|
|
457
|
+
#
|
|
458
|
+
# 此文件定义项目特定的约束,扩展或覆盖 harness 内置约束
|
|
459
|
+
|
|
460
|
+
# ========================================
|
|
461
|
+
# 自定义约束示例
|
|
462
|
+
# ========================================
|
|
463
|
+
|
|
464
|
+
custom_constraints:
|
|
465
|
+
# 示例 1:禁止 console.log
|
|
466
|
+
# my_project_no_console_log:
|
|
467
|
+
# id: my_project_no_console_log
|
|
468
|
+
# level: guideline
|
|
469
|
+
# rule: "NO CONSOLE.LOG IN PRODUCTION CODE"
|
|
470
|
+
# message: "生产代码禁止使用 console.log,请使用 logger 模块"
|
|
471
|
+
# trigger: ["code_implementation"]
|
|
472
|
+
# description: "使用项目统一的 logger 模块代替 console.log"
|
|
473
|
+
|
|
474
|
+
# 示例 2:禁止特定的导入
|
|
475
|
+
# my_project_no_moment_js:
|
|
476
|
+
# id: my_project_no_moment_js
|
|
477
|
+
# level: guideline
|
|
478
|
+
# rule: "NO MOMENT.JS IMPORTS"
|
|
479
|
+
# message: "禁止使用 moment.js,请使用 date-fns 或 dayjs"
|
|
480
|
+
# trigger: ["code_implementation"]
|
|
481
|
+
# exceptions: ["legacy_migration"]
|
|
482
|
+
|
|
483
|
+
# 示例 3:要求特定的文件命名
|
|
484
|
+
# my_project_component_naming:
|
|
485
|
+
# id: my_project_component_naming
|
|
486
|
+
# level: tip
|
|
487
|
+
# rule: "REACT COMPONENTS SHOULD BE PASCAL CASE"
|
|
488
|
+
# message: "React 组件文件名应使用 PascalCase"
|
|
489
|
+
# trigger: ["file_creation"]
|
|
490
|
+
|
|
491
|
+
# ========================================
|
|
492
|
+
# 扩展内置约束的例外
|
|
493
|
+
# ========================================
|
|
494
|
+
|
|
495
|
+
# 如果需要为内置约束添加项目特定的例外,
|
|
496
|
+
# 可以在 .harness/config.yml 中配置:
|
|
497
|
+
|
|
498
|
+
# constraints:
|
|
499
|
+
# no_fix_without_root_cause:
|
|
500
|
+
# # 添加项目特定的例外
|
|
501
|
+
# exceptions:
|
|
502
|
+
# - my_custom_exception
|
|
503
|
+
`;
|
|
504
|
+
|
|
505
|
+
await fs.writeFile(customConstraintsPath, content, 'utf-8');
|
|
506
|
+
console.log(chalk.green(`✅ 已创建自定义约束示例: custom-constraints.yml`));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* 在 CLAUDE.md 中写入/更新 Governance Rules 约束段
|
|
511
|
+
*
|
|
512
|
+
* - 如果 CLAUDE.md 不存在,创建并写入完整约束段
|
|
513
|
+
* - 如果存在 HARNESS_CONSTRAINTS_START/END 标记,替换标记间内容
|
|
514
|
+
* - 如果不存在标记,在文件末尾追加约束段
|
|
515
|
+
*
|
|
516
|
+
/**
|
|
517
|
+
* 在 CLAUDE.md 顶部写入 Output Style 段(仅首次创建,后续不覆盖)
|
|
518
|
+
*/
|
|
519
|
+
const OUTPUT_STYLE_SECTION = [
|
|
520
|
+
'## Output Style',
|
|
521
|
+
'',
|
|
522
|
+
'Terse like caveman. Technical substance exact. Only fluff die.',
|
|
523
|
+
'Drop: articles, filler (just/really/basically), pleasantries (sure/certainly/happy to), hedging.',
|
|
524
|
+
'Fragments OK. Short synonyms. Code blocks unchanged. Error messages quoted exact.',
|
|
525
|
+
'Pattern: [thing] [action] [reason]. [next step].',
|
|
526
|
+
'No sycophantic openers/closing fluff. No emojis or em-dashes.',
|
|
527
|
+
'Read existing files before writing. Don\'t re-read unless changed.',
|
|
528
|
+
'Skip files over 100KB unless required.',
|
|
529
|
+
'Don\'t guess APIs, versions, flags, commit SHAs, or package names. Verify before asserting.',
|
|
530
|
+
'',
|
|
531
|
+
].join('\n');
|
|
532
|
+
|
|
533
|
+
async function setupClaudeMdOutputStyle(projectPath: string): Promise<void> {
|
|
534
|
+
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
535
|
+
try {
|
|
536
|
+
const content = await fs.readFile(claudeMdPath, 'utf-8');
|
|
537
|
+
if (content.includes('## Output Style')) return; // 已存在,不覆盖
|
|
538
|
+
const newContent = OUTPUT_STYLE_SECTION + '\n' + content;
|
|
539
|
+
await fs.writeFile(claudeMdPath, newContent, 'utf-8');
|
|
540
|
+
} catch {
|
|
541
|
+
// CLAUDE.md 不存在——setupClaudeMdConstraints 会创建它
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* 只写入包含 promptInjection 文本的约束
|
|
547
|
+
*/
|
|
548
|
+
async function setupClaudeMdConstraints(projectPath: string): Promise<void> {
|
|
549
|
+
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
550
|
+
|
|
551
|
+
// 读取 harness 版本
|
|
552
|
+
let version = 'unknown';
|
|
553
|
+
try {
|
|
554
|
+
const pkgPath = path.join(__dirname, '../../../package.json');
|
|
555
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
556
|
+
version = pkg.version;
|
|
557
|
+
} catch {
|
|
558
|
+
// fallback to 'unknown'
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// 构建约束段正文(不含 ## Governance Rules 标题,因为替换时标题已在外部)
|
|
562
|
+
const bodyLines: string[] = [];
|
|
563
|
+
bodyLines.push('<!-- HARNESS_CONSTRAINTS_START -->');
|
|
564
|
+
bodyLines.push(`<!-- version: ${version} -->`);
|
|
565
|
+
|
|
566
|
+
// Iron Laws
|
|
567
|
+
const ironLawItems = Object.entries(IRON_LAWS).filter(([, c]) => c.promptInjection);
|
|
568
|
+
if (ironLawItems.length > 0) {
|
|
569
|
+
bodyLines.push('### Iron Laws (违反将阻断)');
|
|
570
|
+
for (const [id, c] of ironLawItems) {
|
|
571
|
+
bodyLines.push(`- **${id}**: ${c.promptInjection}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Guidelines
|
|
576
|
+
const guidelineItems = Object.entries(GUIDELINES).filter(([, c]) => c.promptInjection);
|
|
577
|
+
if (guidelineItems.length > 0) {
|
|
578
|
+
bodyLines.push('');
|
|
579
|
+
bodyLines.push('### Guidelines (应遵循)');
|
|
580
|
+
for (const [id, c] of guidelineItems) {
|
|
581
|
+
bodyLines.push(`- **${id}**: ${c.promptInjection}`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Tips
|
|
586
|
+
const tipItems = Object.entries(TIPS).filter(([, c]) => c.promptInjection);
|
|
587
|
+
if (tipItems.length > 0) {
|
|
588
|
+
bodyLines.push('');
|
|
589
|
+
bodyLines.push('### Tips');
|
|
590
|
+
for (const [id, c] of tipItems) {
|
|
591
|
+
bodyLines.push(`- **${id}**: ${c.promptInjection}`);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
bodyLines.push('<!-- HARNESS_CONSTRAINTS_END -->');
|
|
596
|
+
|
|
597
|
+
const fullSection = '## Governance Rules\n' + bodyLines.join('\n') + '\n';
|
|
598
|
+
const bodyOnly = bodyLines.join('\n') + '\n';
|
|
599
|
+
|
|
600
|
+
// 检查 CLAUDE.md 是否存在
|
|
601
|
+
let existingContent: string;
|
|
602
|
+
let fileExists = false;
|
|
603
|
+
try {
|
|
604
|
+
existingContent = await fs.readFile(claudeMdPath, 'utf-8');
|
|
605
|
+
fileExists = true;
|
|
606
|
+
} catch {
|
|
607
|
+
existingContent = '';
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const startMarker = '<!-- HARNESS_CONSTRAINTS_START -->';
|
|
611
|
+
const endMarker = '<!-- HARNESS_CONSTRAINTS_END -->';
|
|
612
|
+
|
|
613
|
+
if (!fileExists) {
|
|
614
|
+
// 创建新文件
|
|
615
|
+
await fs.writeFile(claudeMdPath, fullSection, 'utf-8');
|
|
616
|
+
console.log(chalk.green(`✅ 已创建 CLAUDE.md 并写入治理约束 (v${version})`));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const startIdx = existingContent.indexOf(startMarker);
|
|
621
|
+
const endIdx = existingContent.indexOf(endMarker);
|
|
622
|
+
|
|
623
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
624
|
+
// 替换标记间内容(标记本身也替换,保持包括最新版本号)
|
|
625
|
+
const before = existingContent.slice(0, startIdx);
|
|
626
|
+
const after = existingContent.slice(endIdx + endMarker.length);
|
|
627
|
+
const newContent = before + bodyOnly + after;
|
|
628
|
+
await fs.writeFile(claudeMdPath, newContent, 'utf-8');
|
|
629
|
+
console.log(chalk.green(`✅ 已更新 CLAUDE.md 治理约束 (v${version})`));
|
|
630
|
+
} else {
|
|
631
|
+
// 在文件末尾追加完整段
|
|
632
|
+
const newContent = existingContent.trimEnd() + '\n\n' + fullSection;
|
|
633
|
+
await fs.writeFile(claudeMdPath, newContent, 'utf-8');
|
|
634
|
+
console.log(chalk.green(`✅ 已追加治理约束到 CLAUDE.md (v${version})`));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* 设置治理相关文件
|
|
640
|
+
*/
|
|
641
|
+
async function setupGovernance(projectPath: string, level: string): Promise<void> {
|
|
642
|
+
const governance = GOVERNANCE_PRESETS[level] as Record<string, unknown>;
|
|
643
|
+
if (!governance) return;
|
|
644
|
+
|
|
645
|
+
console.log();
|
|
646
|
+
console.log(chalk.blue('📋 设置治理文件...'));
|
|
647
|
+
|
|
648
|
+
// 1. 生成 CHANGELOG.md
|
|
649
|
+
await createChangelog(projectPath, governance);
|
|
650
|
+
|
|
651
|
+
// 2. 在 CLAUDE.md 中写入 Output Style 段(仅在不存在时创建)
|
|
652
|
+
await setupClaudeMdOutputStyle(projectPath);
|
|
653
|
+
|
|
654
|
+
// 3. 在 CLAUDE.md 中写入/更新 Governance Rules 约束段
|
|
655
|
+
await setupClaudeMdConstraints(projectPath);
|
|
656
|
+
|
|
657
|
+
// 4. 生成 CONTEXT.md 文件
|
|
658
|
+
const contextConfig = governance.context_files as Record<string, unknown> | undefined;
|
|
659
|
+
if (contextConfig?.enabled) {
|
|
660
|
+
let requiredDirs = (contextConfig.required_dirs as string[]) || [];
|
|
661
|
+
if (requiredDirs.length === 0) {
|
|
662
|
+
requiredDirs = detectSourceRoots(projectPath);
|
|
663
|
+
}
|
|
664
|
+
for (const dir of requiredDirs) {
|
|
665
|
+
await createContextMd(projectPath, dir);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// 4. 生成治理 CI workflow
|
|
670
|
+
await setupGovernanceWorkflow(projectPath, level);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* 创建 CHANGELOG.md
|
|
675
|
+
*/
|
|
676
|
+
async function createChangelog(projectPath: string, governance: Record<string, unknown>): Promise<void> {
|
|
677
|
+
const changelogPath = path.join(projectPath, 'CHANGELOG.md');
|
|
678
|
+
|
|
679
|
+
try {
|
|
680
|
+
await fs.access(changelogPath);
|
|
681
|
+
console.log(chalk.gray(`CHANGELOG.md 已存在`));
|
|
682
|
+
return;
|
|
683
|
+
} catch {
|
|
684
|
+
// 文件不存在,创建
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const changelogConfig = governance.changelog as Record<string, unknown> | undefined;
|
|
688
|
+
const format = (changelogConfig?.format as string) || 'keep-a-changelog';
|
|
689
|
+
|
|
690
|
+
let content: string;
|
|
691
|
+
if (format === 'keep-a-changelog') {
|
|
692
|
+
content = `# Changelog
|
|
693
|
+
|
|
694
|
+
All notable changes to this project will be documented in this file.
|
|
695
|
+
|
|
696
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
697
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
698
|
+
|
|
699
|
+
## [Unreleased]
|
|
700
|
+
|
|
701
|
+
### Added
|
|
702
|
+
- Initial project setup with harness governance
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
> 此文件可由 \`harness sync-docs\` 辅助维护
|
|
707
|
+
`;
|
|
708
|
+
} else {
|
|
709
|
+
content = `# Changelog
|
|
710
|
+
|
|
711
|
+
## [Unreleased]
|
|
712
|
+
|
|
713
|
+
- Initial project setup with harness governance
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
> 此文件可由 \`harness sync-docs\` 辅助维护
|
|
718
|
+
`;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
await fs.writeFile(changelogPath, content, 'utf-8');
|
|
722
|
+
console.log(chalk.green(`✅ 已创建 CHANGELOG.md`));
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* 在指定目录创建 CONTEXT.md
|
|
727
|
+
*/
|
|
728
|
+
async function createContextMd(projectPath: string, dir: string): Promise<void> {
|
|
729
|
+
const contextPath = path.join(projectPath, dir, 'CONTEXT.md');
|
|
730
|
+
|
|
731
|
+
try {
|
|
732
|
+
await fs.access(contextPath);
|
|
733
|
+
console.log(chalk.gray(`${dir}/CONTEXT.md 已存在`));
|
|
734
|
+
return;
|
|
735
|
+
} catch {
|
|
736
|
+
// 文件不存在,创建
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// 检查目录是否存在
|
|
740
|
+
const dirPath = path.join(projectPath, dir);
|
|
741
|
+
try {
|
|
742
|
+
await fs.access(dirPath);
|
|
743
|
+
} catch {
|
|
744
|
+
console.log(chalk.yellow(`⚠️ 目录 ${dir} 不存在,跳过 CONTEXT.md`));
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const dirName = path.basename(dir);
|
|
749
|
+
const content = `# ${dirName}
|
|
750
|
+
|
|
751
|
+
> 此文件描述 ${dir} 目录的职责和上下文
|
|
752
|
+
|
|
753
|
+
## 职责
|
|
754
|
+
|
|
755
|
+
<!-- 本目录的核心职责是什么 -->
|
|
756
|
+
|
|
757
|
+
## 核心导出
|
|
758
|
+
|
|
759
|
+
<!-- 本目录对外暴露的主要模块/函数 -->
|
|
760
|
+
|
|
761
|
+
## 依赖关系
|
|
762
|
+
|
|
763
|
+
<!-- 本目录依赖哪些其他模块,谁依赖本目录 -->
|
|
764
|
+
|
|
765
|
+
## 注意事项
|
|
766
|
+
|
|
767
|
+
<!-- 开发时需要注意的约束或约定 -->
|
|
768
|
+
`;
|
|
769
|
+
|
|
770
|
+
await fs.writeFile(contextPath, content, 'utf-8');
|
|
771
|
+
console.log(chalk.green(`✅ 已创建 ${dir}/CONTEXT.md`));
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* 设置治理 CI workflow
|
|
776
|
+
*/
|
|
777
|
+
async function setupGovernanceWorkflow(projectPath: string, level: string): Promise<void> {
|
|
778
|
+
const workflowsDir = path.join(projectPath, '.github', 'workflows');
|
|
779
|
+
const workflowPath = path.join(workflowsDir, 'harness-governance.yml');
|
|
780
|
+
|
|
781
|
+
// 检查是否已存在
|
|
782
|
+
try {
|
|
783
|
+
await fs.access(workflowPath);
|
|
784
|
+
console.log(chalk.gray(`harness-governance.yml 已存在`));
|
|
785
|
+
return;
|
|
786
|
+
} catch {
|
|
787
|
+
// 不存在,继续创建
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
await fs.mkdir(workflowsDir, { recursive: true });
|
|
791
|
+
|
|
792
|
+
const docsCheckStep = level !== 'minimal'
|
|
793
|
+
? `
|
|
794
|
+
- name: Check docs freshness
|
|
795
|
+
run: npx harness sync-docs --check
|
|
796
|
+
continue-on-error: true`
|
|
797
|
+
: '';
|
|
798
|
+
|
|
799
|
+
const workflowContent = `name: Harness Governance
|
|
800
|
+
|
|
801
|
+
on:
|
|
802
|
+
push:
|
|
803
|
+
branches: [main, master]
|
|
804
|
+
pull_request:
|
|
805
|
+
branches: [main, master]
|
|
806
|
+
|
|
807
|
+
jobs:
|
|
808
|
+
governance:
|
|
809
|
+
runs-on: ubuntu-latest
|
|
810
|
+
|
|
811
|
+
steps:
|
|
812
|
+
- uses: actions/checkout@v4
|
|
813
|
+
|
|
814
|
+
- name: Setup Node.js
|
|
815
|
+
uses: actions/setup-node@v4
|
|
816
|
+
with:
|
|
817
|
+
node-version: '20'
|
|
818
|
+
|
|
819
|
+
- name: Install dependencies
|
|
820
|
+
run: npm ci
|
|
821
|
+
|
|
822
|
+
- name: Constraint check
|
|
823
|
+
run: npx harness check
|
|
824
|
+
|
|
825
|
+
- name: Quality gate
|
|
826
|
+
run: npx harness passes-gate
|
|
827
|
+
${docsCheckStep}
|
|
828
|
+
`;
|
|
829
|
+
|
|
830
|
+
await fs.writeFile(workflowPath, workflowContent, 'utf-8');
|
|
831
|
+
console.log(chalk.green(`✅ 已创建 .github/workflows/harness-governance.yml`));
|
|
832
|
+
}
|