@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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
|
|
7
|
+
## [0.13.0] - 2026-05-26
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
- **prompt-injection 迁移**: `formatConstraintsForPrompt()` + `AgentRole` + `ROLE_TRIGGERS` 迁至 `@dommaker/studio-shared`。harness 保留 deprecated re-export。
|
|
11
|
+
- **`buildConstraintPrompt()` 移除**: 孤儿函数从未消费,且截断 80 字符。已删除。
|
|
12
|
+
- **死亡代码清理**: `changelog_freshness` 孤儿约束、`changelog_missing` DiffType、`sync-docs --changelog`、`auto_append` config。
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`detectSourceRoots()`**: 统一源码目录发现。支持 monorepo (packages/*, apps/*) 和单 repo (src/, lib/)。替代 5 种分散硬编码。
|
|
16
|
+
- **`harness constraints --json`**: 约束元数据导出(version, hash, counts, textSize)。
|
|
17
|
+
- **`harness init` → CLAUDE.md**: 写入标记段(HARNESS_CONSTRAINTS),含约束列表和版本号。
|
|
18
|
+
- **`module_creation` 触发**: `detectTrigger()` 识别新目录文件变更。
|
|
19
|
+
- **11 条约束补 `promptInjection`**: `no_code_without_test` 等从不可见变为 CLAUDE.md + Agent prompt 可见。
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **内置 Freshness 泛化**: 10 项 harness 特化 → 2 项通用(CONTEXT.md + CHANGELOG 版本)。
|
|
23
|
+
- **`findSourceFiles` 跳过 `index.ts`**: 与 `scanSourceModules` 一致。
|
|
24
|
+
- **管线运行时去重**: CLAUDE.md 已有约束段时注入引用而非全量文本。
|
|
25
|
+
- **预设 `required_dirs` 自动发现**: 不硬编码 `['src']`。
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `@jest/globals` 缺失 → 安装后 119/119 测试通过。
|
|
29
|
+
- monorepo 工程 `harness init` 后全部检测盲过。
|
|
30
|
+
- `index.ts` 导致 `docs_freshness` 误报。
|
|
31
|
+
|
|
32
|
+
## [0.12.2] - 2026-05-19
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **fix_the_problem_not_the_gate guideline**: 质量门阻断时修复代码,不修复门禁
|
|
36
|
+
|
|
37
|
+
## [0.12.1] - 2026-05-19
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **first_principles_first guideline**:第一性优先分析方法论。injectPrompt=true。
|
|
41
|
+
- **5 behavioral guidelines**:surgical_changes_only / no_model_for_deterministic / no_conflict_blending / read_before_write / follow_conventions。全部 injectPrompt=true。
|
|
42
|
+
- **2 增强 promptInjection**:no_performative_agreement / simplest_solution_first 补充 prompt 注入文本。
|
|
43
|
+
- **interceptor 收敛**:无 executor 时 fallback 到 constraint.check(ctx)。
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- **docs_freshness 升级为 iron_law**:guideline → iron_law (blocking)。
|
|
47
|
+
- **CONTEXT.md 删除**:17 个文件。目录描述集中在 CLAUDE.md Key Subsystems 表。
|
|
48
|
+
- 约束总数:13 Iron Laws + 13 Guidelines + 2 Tips = 28 条。
|
|
49
|
+
- promptInjection 优化:357→80 tokens (75% 缩减)。
|
|
50
|
+
- **约束生命周期修正**:退化基于拦截率(≥10 次检查 + 拦截率 < 30%),不基于日历时间。
|
|
51
|
+
|
|
52
|
+
## [0.11.0] - 2026-05-03
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
- **6 条新约束**:must_use_worktree / no_fuzzy_completion_claim / no_performative_agreement / two_stage_review_required(Iron Law)+ no_excuse_patterns / yagni_check(Guideline)
|
|
56
|
+
- **meeting_decision_check trigger**:会议决策质量检查
|
|
57
|
+
- **buildConstraintPrompt()**:收集约束 promptInjection 格式化为 Agent system prompt 片段
|
|
58
|
+
- **knowledge/failure CLI**:harness knowledge / harness failure 命令
|
|
59
|
+
- **sync-docs 命令**:文档新鲜度检查 + JSON 输出
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
- 约束总数:8 Iron Laws → 12,13 Guidelines → 15,共 29 条
|
|
63
|
+
- AI 治理简化:移除冗余 hook/apply,harness 只检测不修复
|
|
64
|
+
- interceptor 修复 + 覆盖率 85.4% + JSDoc
|
|
65
|
+
- `autoEvolve()` 纯计算 API + `evolution/auto-evolve.ts` 新模块
|
|
66
|
+
- `checkConstraints()` 新增 `onTrace` 回调参数
|
|
67
|
+
|
|
68
|
+
## [0.9.0] - 2026-05-01
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
#### Phase 1: 知识引擎核心
|
|
73
|
+
- KnowledgeStore: 知识条目 CRUD + 结构化存储
|
|
74
|
+
- KnowledgeQuery: 语义搜索 + 类型/标签过滤
|
|
75
|
+
- ReferenceTracker: 知识引用关系图谱
|
|
76
|
+
- KnowledgeLinter: 知识质量检查 (完整性/一致性/时效性)
|
|
77
|
+
|
|
78
|
+
#### Phase 2: 上下文管理
|
|
79
|
+
- TokenBudget: 多级 token 预算分配 (system/user/tool/reserve)
|
|
80
|
+
- SessionCompaction: 会话压缩策略 (摘要/截断/滑动窗口)
|
|
81
|
+
- AgentLifecycle: Agent 状态机 (init→running→paused→completed→failed)
|
|
82
|
+
|
|
83
|
+
#### Phase 3: 安全护栏
|
|
84
|
+
- InputGuardrail: 输入内容安全检查 (注入检测/敏感信息/格式校验)
|
|
85
|
+
- OutputGuardrail: 输出内容安全检查 (泄露检测/有害内容/格式合规)
|
|
86
|
+
- ToolGuardrail: 工具调用安全检查 (权限验证/参数校验/速率限制)
|
|
87
|
+
- Sandbox: 沙箱执行环境管理 (级别 L1-L4/资源限制/隔离策略)
|
|
88
|
+
|
|
89
|
+
#### Phase 4: 知识引擎集成
|
|
90
|
+
- KnowledgeService: 统一入口 (Store + Query + Tracker + Linter)
|
|
91
|
+
- 知识生命周期: draft → candidate → validated → canonical → archived
|
|
92
|
+
- 跨项目知识迁移: 模式识别 + 最佳实践提炼
|
|
93
|
+
|
|
94
|
+
#### Phase 5: 约束重构
|
|
95
|
+
- ConstraintContext 扩展: 新增 isExternalDependency/isExplicitInstruction/isEmergencyFix/isExistingDesign
|
|
96
|
+
- 自定义约束配置: .harness/config.yml 支持 extend_exceptions
|
|
97
|
+
- 约束进化提案: 基于 trace 分析自动生成优化建议
|
|
98
|
+
|
|
99
|
+
#### Phase 6: 冷启动
|
|
100
|
+
- progressive-loader.ts: 渐进式加载 + worker pool 并发
|
|
101
|
+
- cross-project-checker.ts: 跨项目依赖检查 (异步化)
|
|
102
|
+
- project-config-loader.ts: 项目配置加载 + 约束合并
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
- SafetyService/ContextService/AgentService 单例导出
|
|
106
|
+
- KnowledgeService 单例导出
|
|
107
|
+
- CLI 新增 harness flow --auto-apply 自动应用低风险提案
|
|
108
|
+
|
|
109
|
+
## [0.8.4] - 2026-05-01
|
|
110
|
+
|
|
111
|
+
### Changed
|
|
112
|
+
|
|
113
|
+
#### 重复代码消除
|
|
114
|
+
- 统一 `execAsync` 到 `utils/exec`:15 个文件的重复定义合并为单一来源
|
|
115
|
+
- 新增 `normalizeTriggers()` 泛型工具函数,消除 10+ 处 `Array.isArray` 重复模式
|
|
116
|
+
- 新增 `delay()` 公共函数,替换 3 处私有 `sleep/delay` 方法
|
|
117
|
+
|
|
118
|
+
#### 逻辑简化
|
|
119
|
+
- `checker.ts`:60 行 `switch` 例外匹配 → `EXCEPTION_FIELD_MAP` 映射表 + `some()` 一行
|
|
120
|
+
- `checker.ts`:3 个近似循环 → 提取 `matchesTrigger()` + `recordTrace()` 公共方法
|
|
121
|
+
- `interceptor.ts`:触发器规范化 → 复用 `normalizeTriggers`
|
|
122
|
+
- `trace-analyzer.ts` / `performance-analyzer.ts`:5 次/3 次遍历统计 → 单次遍历
|
|
123
|
+
- `failure/recorder.ts`:`getByType`/`getByLevel` 重复过滤 → 提取 `getFiltered()`
|
|
124
|
+
|
|
125
|
+
#### 健壮性修复
|
|
126
|
+
- 修复 `checker.ts` 中 Guidelines 循环直接引用 `GUIDELINES` 常量的 bug(未使用自定义约束配置)
|
|
127
|
+
- 修复 `project-config-loader.ts` 中 `mergeConstraints()` 的 for 循环缩进错误(方法体脱离类作用域)
|
|
128
|
+
- 修复 `progressive-loader.ts` 中 `delay` 参数名与导入函数冲突
|
|
129
|
+
- 补充 `ConstraintContext` 缺失字段:`isExternalDependency`、`isExplicitInstruction`、`isEmergencyFix`、`isExistingDesign`
|
|
130
|
+
|
|
131
|
+
#### 性能优化
|
|
132
|
+
- `cross-project-checker.ts`:`execSync`(阻塞式)→ 异步 `runCommand`
|
|
133
|
+
- `progressive-loader.ts` `processBatch`:并发结果顺序不保证 → worker pool 模式保证输入顺序
|
|
134
|
+
|
|
135
|
+
#### 代码规范
|
|
136
|
+
- `cli/commands/status.ts`:`any` 类型 → `TraceSummary` / `TraceAnomaly`
|
|
137
|
+
- `cross-project-checker.test.ts`:更新 mock 从 `child_process` → `utils/exec`
|
|
138
|
+
- 合并 10+ 处分散的 `import { exec } + promisify(exec)` 为统一导入
|
|
139
|
+
|
|
140
|
+
> 净减少约 157 行代码,零编译错误,零测试回归
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Recent Commits
|
|
145
|
+
|
|
146
|
+
- feat: add command CLI for blacklist checking (2026-04-29 23:24:07 +0800)
|
|
147
|
+
- feat: add CommandGate for command blacklist (SEC-006) (2026-04-29 23:09:44 +0800)
|
|
148
|
+
- fix: remove deprecated command tests (propose, diagnose, traces) (2026-04-29 01:10:46 +0800)
|
|
149
|
+
- chore: release v0.8.0 (2026-04-28 23:41:32 +0800)
|
|
150
|
+
- docs: decouple Trace section from business logic (2026-04-28 23:39:12 +0800)
|
|
151
|
+
- chore: remove docs and specs directories (moved to .gitignore) (2026-04-28 23:37:35 +0800)
|
|
152
|
+
- chore: ignore docs directory (2026-04-28 23:36:39 +0800)
|
|
153
|
+
- docs: remove deprecated note from README (2026-04-28 23:34:30 +0800)
|
|
154
|
+
- refactor(cli): remove deprecated commands (traces, diagnose, propose) (2026-04-28 23:32:26 +0800)
|
|
155
|
+
- docs: sync CLI commands to README (2026-04-28 23:23:47 +0800)
|
|
156
|
+
- feat(cli): add 5 gate commands - acceptance, performance, security, contract, review (2026-04-28 23:04:33 +0800)
|
|
157
|
+
- chore: ignore specs directory in gitignore (2026-04-28 22:56:59 +0800)
|
|
158
|
+
- chore: ignore specs/templates 目录 (2026-04-28 22:52:51 +0800)
|
|
159
|
+
- feat: 新增覆盖率约束机制 (2026-04-28 22:50:15 +0800)
|
|
160
|
+
- test: 覆盖率达标 85.43%! (2026-04-28 22:39:48 +0800)
|
|
161
|
+
- test: 覆盖率提升至 84.8% (2026-04-28 22:34:31 +0800)
|
|
162
|
+
- test: 覆盖率提升至 83.93% (2026-04-28 22:29:51 +0800)
|
|
163
|
+
- chore: 清理临时测试文件 (2026-04-28 22:21:01 +0800)
|
|
164
|
+
- test: 覆盖率提升至 84.17% (2026-04-28 22:20:54 +0800)
|
|
165
|
+
- init (2026-04-28 22:11:12 +0800)
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
> 自动生成于 2026-04-30
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Harness Knowledge Capture Hook
|
|
4
|
+
*
|
|
5
|
+
* Runs as an afterTurn hook in Claude Code.
|
|
6
|
+
* Detects deep analysis (≥3 source files read) without knowledge-doc output,
|
|
7
|
+
* and warns the user that knowledge may need to be captured.
|
|
8
|
+
*
|
|
9
|
+
* Usage (in settings.json):
|
|
10
|
+
* "hooks": {
|
|
11
|
+
* "afterTurn": [{
|
|
12
|
+
* "command": "node ~/projects/harness/bin/harness-knowledge-capture.js"
|
|
13
|
+
* }]
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
|
|
20
|
+
// Read turn data from stdin
|
|
21
|
+
let input = '';
|
|
22
|
+
process.stdin.setEncoding('utf-8');
|
|
23
|
+
process.stdin.on('data', (chunk) => input += chunk);
|
|
24
|
+
|
|
25
|
+
process.stdin.on('end', () => {
|
|
26
|
+
try {
|
|
27
|
+
const turn = JSON.parse(input);
|
|
28
|
+
const result = checkTurn(turn);
|
|
29
|
+
if (result.shouldWarn) {
|
|
30
|
+
process.stderr.write(`\n${'='.repeat(60)}\n`);
|
|
31
|
+
process.stderr.write(' ⚠️ 可能遗漏了知识沉淀\n');
|
|
32
|
+
process.stderr.write(`${'='.repeat(60)}\n`);
|
|
33
|
+
process.stderr.write(` 本回合读取了 ${result.fileReads} 个文件\n`);
|
|
34
|
+
process.stderr.write(` 但未写入 .harness/knowledge-docs/\n`);
|
|
35
|
+
process.stderr.write(`\n`);
|
|
36
|
+
process.stderr.write(` 如果这是深度分析,请执行:\n`);
|
|
37
|
+
process.stderr.write(` npx harness knowledge upsert --scope <scope> --file <file> --source claude\n`);
|
|
38
|
+
process.stderr.write(`${'='.repeat(60)}\n\n`);
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {
|
|
41
|
+
// Silently ignore parse errors — non-JSON input is fine
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function checkTurn(turn) {
|
|
46
|
+
let fileReads = 0;
|
|
47
|
+
let knowledgeWrites = 0;
|
|
48
|
+
|
|
49
|
+
// Walk through messages looking for tool calls
|
|
50
|
+
const messages = turn.messages || [turn];
|
|
51
|
+
for (const msg of messages) {
|
|
52
|
+
// Claude Code format: tool_uses array
|
|
53
|
+
if (msg.role === 'assistant' && msg.tool_uses) {
|
|
54
|
+
for (const tool of msg.tool_uses) {
|
|
55
|
+
if (isFileRead(tool)) fileReads++;
|
|
56
|
+
if (isKnowledgeWrite(tool)) knowledgeWrites++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Plain tool_calls format
|
|
60
|
+
if (msg.tool_calls) {
|
|
61
|
+
for (const tool of msg.tool_calls) {
|
|
62
|
+
if (isFileRead(tool)) fileReads++;
|
|
63
|
+
if (isKnowledgeWrite(tool)) knowledgeWrites++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Messages content with tool use markers
|
|
67
|
+
if (msg.content && typeof msg.content === 'string') {
|
|
68
|
+
const readMatches = msg.content.match(/\bRead\b.*/g);
|
|
69
|
+
if (readMatches) fileReads += readMatches.length;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
fileReads,
|
|
75
|
+
knowledgeWrites,
|
|
76
|
+
shouldWarn: fileReads >= 3 && knowledgeWrites === 0,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isFileRead(tool) {
|
|
81
|
+
const name = (tool.name || tool.function?.name || '').toLowerCase();
|
|
82
|
+
const isReadTool = ['read', 'glob', 'grep', 'agent'].includes(name);
|
|
83
|
+
if (!isReadTool) return false;
|
|
84
|
+
|
|
85
|
+
const params = tool.parameters || tool.function?.arguments || {};
|
|
86
|
+
const filePath = params.file_path || params.path || params.pattern || '';
|
|
87
|
+
// Only count actual source file reads, not config/memory/docs
|
|
88
|
+
const isSource = /\/(src|packages|apps)\/|\.(ts|tsx|js|jsx|py|go|rs)$/.test(filePath);
|
|
89
|
+
return isSource;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isKnowledgeWrite(tool) {
|
|
93
|
+
const name = (tool.name || tool.function?.name || '').toLowerCase();
|
|
94
|
+
if (name !== 'write') return false;
|
|
95
|
+
|
|
96
|
+
const params = tool.parameters || tool.function?.arguments || {};
|
|
97
|
+
const filePath = params.file_path || '';
|
|
98
|
+
return filePath.includes('.harness/knowledge-docs/') || filePath.includes('.harness/knowledge/');
|
|
99
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stop hook — check if deep analysis happened without knowledge capture
|
|
4
|
+
*
|
|
5
|
+
* Reads state file written by harness-knowledge-track.js.
|
|
6
|
+
* If EnterPlanMode was called, or Agent(Explore) was spawned, or 10+ unique
|
|
7
|
+
* directories were Read — and no knowledge files were Written — warn.
|
|
8
|
+
*
|
|
9
|
+
* Output: JSON with systemMessage (shown to user)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
const STATE_FILE = '/tmp/claude-knowledge-capture-state.json';
|
|
16
|
+
const LOG_FILE = '/tmp/claude-knowledge-hooks.log';
|
|
17
|
+
const EVENTS_FILE = path.join(os.homedir(), 'events', 'studio.jsonl');
|
|
18
|
+
const UNIQUE_DIR_THRESHOLD = 10;
|
|
19
|
+
|
|
20
|
+
function log(level, message, data) {
|
|
21
|
+
try {
|
|
22
|
+
const entry = JSON.stringify({ ts: new Date().toISOString(), level, message, ...data }) + '\n';
|
|
23
|
+
fs.appendFileSync(LOG_FILE, entry, 'utf-8');
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(STATE_FILE)) process.exit(0);
|
|
29
|
+
|
|
30
|
+
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
31
|
+
const deepAnalysis = state.planned || state.explored || state.readDirs.length >= UNIQUE_DIR_THRESHOLD;
|
|
32
|
+
const missingCapture = !state.captured;
|
|
33
|
+
|
|
34
|
+
log('info', 'stop-check', {
|
|
35
|
+
planned: state.planned, explored: state.explored,
|
|
36
|
+
readDirsCount: state.readDirs.length, captured: state.captured,
|
|
37
|
+
deepAnalysis, missingCapture,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Check 1: deep analysis without knowledge capture
|
|
41
|
+
if (deepAnalysis && missingCapture) {
|
|
42
|
+
const signals = [];
|
|
43
|
+
if (state.planned) signals.push('EnterPlanMode called');
|
|
44
|
+
if (state.explored) signals.push('Agent(Explore) spawned');
|
|
45
|
+
if (state.readDirs.length >= UNIQUE_DIR_THRESHOLD) signals.push(`${state.readDirs.length} unique directories Read`);
|
|
46
|
+
|
|
47
|
+
log('warn', 'missing-capture', { signals });
|
|
48
|
+
|
|
49
|
+
const message = [
|
|
50
|
+
'⚠️ Deep analysis detected but no knowledge captured.',
|
|
51
|
+
` Signals: ${signals.join(', ')}`,
|
|
52
|
+
'',
|
|
53
|
+
' To capture:',
|
|
54
|
+
' 1. Write .harness/knowledge-docs/<scope>.md',
|
|
55
|
+
' 2. npx harness knowledge upsert --scope <scope> --file <file> --source claude',
|
|
56
|
+
'',
|
|
57
|
+
' Or run `harness knowledge sync-status` to check staleness.',
|
|
58
|
+
].join('\n');
|
|
59
|
+
|
|
60
|
+
console.log(JSON.stringify({ systemMessage: message }));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check 2: sensitive file operations without prior Read
|
|
64
|
+
const sensitiveOps = (state.sensitiveOps || []).filter(op => !op.verified);
|
|
65
|
+
if (sensitiveOps.length > 0) {
|
|
66
|
+
log('warn', 'unverified-sensitive-ops', { sensitiveOps });
|
|
67
|
+
|
|
68
|
+
const opsList = sensitiveOps.map(op => ` - ${op.tool}: ${op.file}`).join('\n');
|
|
69
|
+
const message = [
|
|
70
|
+
'⚠️ File operations on sensitive paths without prior verification.',
|
|
71
|
+
` Operations:`,
|
|
72
|
+
opsList,
|
|
73
|
+
'',
|
|
74
|
+
' These files were moved/edited/written without being Read first.',
|
|
75
|
+
' Verify the changes were intentional and correct.',
|
|
76
|
+
'',
|
|
77
|
+
' 📋 Rule: feedback_verify_before_move.md — Read before acting on file classification.',
|
|
78
|
+
].join('\n');
|
|
79
|
+
|
|
80
|
+
console.log(JSON.stringify({ systemMessage: message }));
|
|
81
|
+
}
|
|
82
|
+
// Emit session summary event → events-daemon → knowledge extraction pipeline
|
|
83
|
+
try {
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
const durationMs = state.startTime ? now - state.startTime : 0;
|
|
86
|
+
const durationMin = Math.round(durationMs / 60000);
|
|
87
|
+
const event = {
|
|
88
|
+
type: 'session:summary',
|
|
89
|
+
sessionType: 'development',
|
|
90
|
+
tool: state.tool || 'unknown', // claude | codex | opencode | etc
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
durationMs,
|
|
93
|
+
durationMin,
|
|
94
|
+
deepAnalysis: state.planned || state.explored || state.readDirs.length >= UNIQUE_DIR_THRESHOLD,
|
|
95
|
+
knowledgeCaptured: !!state.captured,
|
|
96
|
+
readDirsCount: state.readDirs.length,
|
|
97
|
+
planned: state.planned || false,
|
|
98
|
+
explored: state.explored || false,
|
|
99
|
+
sensitiveOpsCount: (state.sensitiveOps || []).filter(op => !op.verified).length,
|
|
100
|
+
turnCount: state.turnCount || 0,
|
|
101
|
+
};
|
|
102
|
+
const dir = path.dirname(EVENTS_FILE);
|
|
103
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
104
|
+
fs.appendFileSync(EVENTS_FILE, JSON.stringify(event) + '\n', 'utf-8');
|
|
105
|
+
log('info', 'session-summary-emitted', event);
|
|
106
|
+
} catch {}
|
|
107
|
+
|
|
108
|
+
// Auto-ingest: scan memory files with ingest:true → call local-rag API
|
|
109
|
+
// PostToolUse hooks don't fire in interactive mode, so Stop hook handles it
|
|
110
|
+
try {
|
|
111
|
+
const MEMORY_DIR = path.join(os.homedir(), '.claude', 'projects', '-root-projects', 'memory');
|
|
112
|
+
if (fs.existsSync(MEMORY_DIR)) {
|
|
113
|
+
const files = fs.readdirSync(MEMORY_DIR).filter(f => f.endsWith('.md'));
|
|
114
|
+
const ingested = [];
|
|
115
|
+
for (const f of files) {
|
|
116
|
+
const fp = path.join(MEMORY_DIR, f);
|
|
117
|
+
const head = fs.readFileSync(fp, 'utf-8').slice(0, 500);
|
|
118
|
+
if (/^---[\s\S]*?ingest:\s*true[\s\S]*?---/.test(head)) {
|
|
119
|
+
// Check if already ingested recently (skip if unchanged in last hour)
|
|
120
|
+
const stat = fs.statSync(fp);
|
|
121
|
+
const hourAgo = Date.now() - 3600_000;
|
|
122
|
+
if (stat.mtimeMs > hourAgo) {
|
|
123
|
+
ingested.push(fp);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (ingested.length > 0) {
|
|
128
|
+
log('info', 'auto-ingest-start', { count: ingested.length, files: ingested });
|
|
129
|
+
const { execSync } = require('child_process');
|
|
130
|
+
const syncScript = '/root/projects/studio/bin/memory-knowledge-sync.js';
|
|
131
|
+
let successCount = 0;
|
|
132
|
+
for (const fp of ingested) {
|
|
133
|
+
try {
|
|
134
|
+
execSync(`node "${syncScript}" "${fp}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
135
|
+
successCount++;
|
|
136
|
+
} catch (e) {
|
|
137
|
+
log('warn', 'auto-ingest-failed', { file: fp, error: (e.message || String(e)).slice(0, 100) });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
log('info', 'auto-ingest-done', { success: successCount, total: ingested.length });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch {}
|
|
144
|
+
} catch (e) {
|
|
145
|
+
// Silently ignore errors
|
|
146
|
+
} finally {
|
|
147
|
+
// Clean up state file for next session
|
|
148
|
+
try { fs.unlinkSync(STATE_FILE); } catch {}
|
|
149
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PostToolUse hook — track deep analysis signals
|
|
4
|
+
*
|
|
5
|
+
* Updates state file with:
|
|
6
|
+
* - planned: EnterPlanMode was called
|
|
7
|
+
* - explored: Agent(Explore) was spawned
|
|
8
|
+
* - readDirs: Set of unique directories Read was called on
|
|
9
|
+
* - captured: Write to .harness/knowledge-docs/ or .harness/knowledge/
|
|
10
|
+
* - turnCount: session turn counter
|
|
11
|
+
*
|
|
12
|
+
* Usage: PostToolUse hook with matcher "EnterPlanMode|Agent|Read|Write|Write"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const STATE_FILE = '/tmp/claude-knowledge-capture-state.json';
|
|
19
|
+
const LOG_FILE = '/tmp/claude-knowledge-hooks.log';
|
|
20
|
+
|
|
21
|
+
function log(level, message, data) {
|
|
22
|
+
try {
|
|
23
|
+
const entry = JSON.stringify({ ts: new Date().toISOString(), level, message, ...data }) + '\n';
|
|
24
|
+
fs.appendFileSync(LOG_FILE, entry, 'utf-8');
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Read hook input from stdin
|
|
29
|
+
let input = '';
|
|
30
|
+
process.stdin.setEncoding('utf-8');
|
|
31
|
+
process.stdin.on('data', (chunk) => input += chunk);
|
|
32
|
+
|
|
33
|
+
process.stdin.on('end', () => {
|
|
34
|
+
try {
|
|
35
|
+
const event = JSON.parse(input);
|
|
36
|
+
const state = loadState();
|
|
37
|
+
updateState(state, event);
|
|
38
|
+
saveState(state);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// Silently ignore parse errors
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function loadState() {
|
|
45
|
+
try {
|
|
46
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
47
|
+
return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
48
|
+
}
|
|
49
|
+
} catch {}
|
|
50
|
+
return { planned: false, explored: false, readDirs: [], captured: false };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function updateState(state, event) {
|
|
54
|
+
const toolName = event.tool_name || '';
|
|
55
|
+
|
|
56
|
+
if (toolName === 'EnterPlanMode') {
|
|
57
|
+
state.planned = true;
|
|
58
|
+
log('info', 'planned', { tool: toolName });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (toolName === 'Agent') {
|
|
62
|
+
const input = event.tool_input || {};
|
|
63
|
+
if (input.subagent_type === 'Explore') {
|
|
64
|
+
state.explored = true;
|
|
65
|
+
log('info', 'explored', { tool: toolName, subagent_type: input.subagent_type });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (toolName === 'Read') {
|
|
70
|
+
const input = event.tool_input || {};
|
|
71
|
+
const filePath = input.file_path || '';
|
|
72
|
+
const dir = path.dirname(filePath);
|
|
73
|
+
if (dir && dir !== '.' && dir !== '/' && !state.readDirs.includes(dir)) {
|
|
74
|
+
state.readDirs.push(dir);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (toolName === 'Write') {
|
|
79
|
+
const input = event.tool_input || {};
|
|
80
|
+
const filePath = input.file_path || '';
|
|
81
|
+
if (filePath.includes('.harness/knowledge-docs/') || filePath.includes('.harness/knowledge/')) {
|
|
82
|
+
state.captured = true;
|
|
83
|
+
log('info', 'captured', { file: filePath });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function saveState(state) {
|
|
89
|
+
try {
|
|
90
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(state), 'utf-8');
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse hook — track deep analysis + session metrics
|
|
3
|
+
# Matcher: EnterPlanMode|Agent|Read|Write|Edit|Bash (broad coverage)
|
|
4
|
+
# DailyReflection: enriched session:summary events for behavioral analysis
|
|
5
|
+
|
|
6
|
+
STATE_FILE=/tmp/claude-knowledge-capture-state.json
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
tool_name=$(echo "$INPUT" | jq -r '.tool_name // ""')
|
|
10
|
+
file_path=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
11
|
+
|
|
12
|
+
# Init state file if missing (tool: claude|codex|opencode|etc)
|
|
13
|
+
_tool=$(echo "${CLAUDE_CODE_TOOL_NAME:-claude}" | tr '[:upper:]' '[:lower:]')
|
|
14
|
+
[ -f "$STATE_FILE" ] || echo "{\"planned\":false,\"explored\":false,\"readDirs\":[],\"captured\":false,\"turnCount\":0,\"startTime\":$(date +%s)000,\"tool\":\"$_tool\"}" > "$STATE_FILE"
|
|
15
|
+
|
|
16
|
+
# Always increment turn counter on substantive tools
|
|
17
|
+
case "$tool_name" in
|
|
18
|
+
EnterPlanMode)
|
|
19
|
+
jq '.planned = true | .turnCount += 1' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
20
|
+
;;
|
|
21
|
+
Agent)
|
|
22
|
+
# Agent(Explore) spawned → deep analysis signal
|
|
23
|
+
_agent_type=$(echo "$INPUT" | jq -r '.tool_input.subagent_type // ""')
|
|
24
|
+
if [ "$_agent_type" = "Explore" ]; then
|
|
25
|
+
jq '.explored = true | .turnCount += 1' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
26
|
+
fi
|
|
27
|
+
;;
|
|
28
|
+
Read)
|
|
29
|
+
if [ -n "$file_path" ]; then
|
|
30
|
+
dir=$(dirname "$file_path")
|
|
31
|
+
if [ "$dir" != "." ] && [ "$dir" != "/" ]; then
|
|
32
|
+
jq --arg d "$dir" '.readDirs += [$d] | .readDirs |= unique | .turnCount += 1' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
;;
|
|
36
|
+
Write|Edit)
|
|
37
|
+
jq '.turnCount += 1' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
38
|
+
case "$file_path" in
|
|
39
|
+
*.harness/knowledge-docs/*|*.harness/knowledge/*|*/memory/*.md|*/docs/*.md)
|
|
40
|
+
jq '.captured = true' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
;;
|
|
44
|
+
Bash)
|
|
45
|
+
jq '.turnCount += 1' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
46
|
+
;;
|
|
47
|
+
esac
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse hook — check for operations on sensitive files without prior Read
|
|
3
|
+
#
|
|
4
|
+
# Detects: Bash(mv/rm), Edit, or Write targeting files in bin/, .harness/, or
|
|
5
|
+
# package.json — and checks whether those files were Read earlier in this session.
|
|
6
|
+
#
|
|
7
|
+
# State file is maintained by harness-knowledge-track.sh which tracks all Read calls.
|
|
8
|
+
|
|
9
|
+
STATE_FILE=/tmp/claude-knowledge-capture-state.json
|
|
10
|
+
SENSITIVE_DIRS="bin/ .harness/"
|
|
11
|
+
|
|
12
|
+
INPUT=$(cat)
|
|
13
|
+
tool_name=$(echo "$INPUT" | jq -r '.tool_name // ""')
|
|
14
|
+
file_path=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
15
|
+
content=$(echo "$INPUT" | jq -r '.tool_input.content // ""')
|
|
16
|
+
command=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
|
|
17
|
+
|
|
18
|
+
# Check if this operation targets a sensitive file
|
|
19
|
+
is_sensitive=false
|
|
20
|
+
for dir in $SENSITIVE_DIRS; do
|
|
21
|
+
case "$file_path" in
|
|
22
|
+
*$dir*) is_sensitive=true; break ;;
|
|
23
|
+
esac
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
# For Bash, check if the command involves mv/rm on sensitive paths
|
|
27
|
+
if [ "$tool_name" = "Bash" ] && [ -n "$command" ]; then
|
|
28
|
+
for dir in $SENSITIVE_DIRS; do
|
|
29
|
+
if echo "$command" | grep -qE "(mv|rm|cp|git rm).*$dir"; then
|
|
30
|
+
is_sensitive=true
|
|
31
|
+
# Extract target from command for checking
|
|
32
|
+
file_path=$(echo "$command" | grep -oE "$dir[^ ]*" | head -1)
|
|
33
|
+
break
|
|
34
|
+
fi
|
|
35
|
+
done
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Only check sensitive operations
|
|
39
|
+
if [ "$is_sensitive" != "true" ] || [ -z "$file_path" ]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Check if this file was Read earlier in the session
|
|
44
|
+
if [ -f "$STATE_FILE" ]; then
|
|
45
|
+
read_dirs=$(jq -r '.readDirs // [] | join(" ")' "$STATE_FILE" 2>/dev/null || echo "")
|
|
46
|
+
|
|
47
|
+
# Check if any read_dir is an ancestor of file_path
|
|
48
|
+
verified=false
|
|
49
|
+
file_dir=$(dirname "$file_path")
|
|
50
|
+
for dir in $read_dirs; do
|
|
51
|
+
case "$file_dir" in
|
|
52
|
+
"$dir"|"$dir/"*) verified=true; break ;;
|
|
53
|
+
esac
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
if [ "$verified" != "true" ]; then
|
|
57
|
+
# Also check if the file itself was explicitly Read (file_path matches a read path)
|
|
58
|
+
# The track hook only records directories, not individual files — conservative check
|
|
59
|
+
|
|
60
|
+
# Emit warning via state file for Stop hook to pick up
|
|
61
|
+
jq --arg op "$tool_name" --arg fp "$file_path" \
|
|
62
|
+
'.sensitiveOps += [{"tool":$op,"file":$fp,"verified":false}]' \
|
|
63
|
+
"$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
exit 0
|
|
@@ -496,6 +496,36 @@ custom_constraints:
|
|
|
496
496
|
* - 如果存在 HARNESS_CONSTRAINTS_START/END 标记,替换标记间内容
|
|
497
497
|
* - 如果不存在标记,在文件末尾追加约束段
|
|
498
498
|
*
|
|
499
|
+
/**
|
|
500
|
+
* 在 CLAUDE.md 顶部写入 Output Style 段(仅首次创建,后续不覆盖)
|
|
501
|
+
*/
|
|
502
|
+
const OUTPUT_STYLE_SECTION = [
|
|
503
|
+
'## Output Style',
|
|
504
|
+
'',
|
|
505
|
+
'Terse like caveman. Technical substance exact. Only fluff die.',
|
|
506
|
+
'Drop: articles, filler (just/really/basically), pleasantries (sure/certainly/happy to), hedging.',
|
|
507
|
+
'Fragments OK. Short synonyms. Code blocks unchanged. Error messages quoted exact.',
|
|
508
|
+
'Pattern: [thing] [action] [reason]. [next step].',
|
|
509
|
+
'No sycophantic openers/closing fluff. No emojis or em-dashes.',
|
|
510
|
+
'Read existing files before writing. Don\'t re-read unless changed.',
|
|
511
|
+
'Skip files over 100KB unless required.',
|
|
512
|
+
'Don\'t guess APIs, versions, flags, commit SHAs, or package names. Verify before asserting.',
|
|
513
|
+
'',
|
|
514
|
+
].join('\n');
|
|
515
|
+
async function setupClaudeMdOutputStyle(projectPath) {
|
|
516
|
+
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
517
|
+
try {
|
|
518
|
+
const content = await fs.readFile(claudeMdPath, 'utf-8');
|
|
519
|
+
if (content.includes('## Output Style'))
|
|
520
|
+
return; // 已存在,不覆盖
|
|
521
|
+
const newContent = OUTPUT_STYLE_SECTION + '\n' + content;
|
|
522
|
+
await fs.writeFile(claudeMdPath, newContent, 'utf-8');
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
525
|
+
// CLAUDE.md 不存在——setupClaudeMdConstraints 会创建它
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
499
529
|
* 只写入包含 promptInjection 文本的约束
|
|
500
530
|
*/
|
|
501
531
|
async function setupClaudeMdConstraints(projectPath) {
|
|
@@ -589,9 +619,11 @@ async function setupGovernance(projectPath, level) {
|
|
|
589
619
|
console.log(chalk_1.default.blue('📋 设置治理文件...'));
|
|
590
620
|
// 1. 生成 CHANGELOG.md
|
|
591
621
|
await createChangelog(projectPath, governance);
|
|
592
|
-
// 2. 在 CLAUDE.md
|
|
622
|
+
// 2. 在 CLAUDE.md 中写入 Output Style 段(仅在不存在时创建)
|
|
623
|
+
await setupClaudeMdOutputStyle(projectPath);
|
|
624
|
+
// 3. 在 CLAUDE.md 中写入/更新 Governance Rules 约束段
|
|
593
625
|
await setupClaudeMdConstraints(projectPath);
|
|
594
|
-
//
|
|
626
|
+
// 4. 生成 CONTEXT.md 文件
|
|
595
627
|
const contextConfig = governance.context_files;
|
|
596
628
|
if (contextConfig?.enabled) {
|
|
597
629
|
let requiredDirs = contextConfig.required_dirs || [];
|