@dommaker/harness 1.2.3 → 1.4.0
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 +15 -0
- package/README.md +0 -2
- package/bin/harness.js +86 -32
- package/dist/cli/command-contract.d.ts +83 -0
- package/dist/cli/command-contract.d.ts.map +1 -0
- package/dist/cli/command-contract.js +66 -0
- package/dist/cli/command-contract.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts +3 -2
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +28 -24
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/analyze-sessions.d.ts +2 -1
- package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
- package/dist/cli/commands/analyze-sessions.js +25 -24
- package/dist/cli/commands/analyze-sessions.js.map +1 -1
- package/dist/cli/commands/check.d.ts +14 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +76 -61
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +5 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +26 -17
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +2 -1
- package/dist/cli/commands/constraints-report.d.ts.map +1 -1
- package/dist/cli/commands/constraints-report.js +37 -33
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +6 -5
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +50 -52
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/constraints.d.ts +2 -1
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +10 -27
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +3 -2
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +45 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +11 -11
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +30 -215
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts +5 -4
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +33 -26
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -5
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +147 -211
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +21 -15
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +237 -199
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +8 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +44 -66
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +2 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +20 -18
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/posteval-plan.d.ts +5 -1
- package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
- package/dist/cli/commands/posteval-plan.js +26 -15
- package/dist/cli/commands/posteval-plan.js.map +1 -1
- package/dist/cli/commands/release.d.ts +6 -1
- package/dist/cli/commands/release.d.ts.map +1 -1
- package/dist/cli/commands/release.js +73 -77
- package/dist/cli/commands/release.js.map +1 -1
- package/dist/cli/commands/report.d.ts +2 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +9 -5
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts +3 -2
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +33 -29
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/sdd.d.ts +2 -1
- package/dist/cli/commands/sdd.d.ts.map +1 -1
- package/dist/cli/commands/sdd.js +7 -5
- package/dist/cli/commands/sdd.js.map +1 -1
- package/dist/cli/commands/security.d.ts +3 -2
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +29 -26
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +15 -11
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +7 -2
- package/dist/cli/commands/spec.d.ts.map +1 -1
- package/dist/cli/commands/spec.js +61 -51
- package/dist/cli/commands/spec.js.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +57 -53
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.js +31 -16
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +2 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +68 -88
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +14 -16
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/update-user-model.d.ts +2 -1
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +31 -45
- package/dist/cli/commands/update-user-model.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +4 -3
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +28 -26
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/session-mining/transcript.d.ts +7 -1
- package/dist/cli/session-mining/transcript.d.ts.map +1 -1
- package/dist/cli/session-mining/transcript.js +21 -14
- package/dist/cli/session-mining/transcript.js.map +1 -1
- package/dist/completion-checkers/index.d.ts +3 -3
- package/dist/completion-checkers/index.js +3 -3
- package/dist/completion-checkers/phase-format.d.ts +1 -1
- package/dist/completion-checkers/phase-format.js +2 -2
- package/dist/completion-checkers/phase-format.js.map +1 -1
- package/dist/completion-checkers/tdd-chain.d.ts +1 -1
- package/dist/completion-checkers/tdd-chain.js +2 -2
- package/dist/completion-checkers/tdd-chain.js.map +1 -1
- package/dist/completion-checkers/types.d.ts +5 -5
- package/dist/completion-checkers/types.d.ts.map +1 -1
- package/dist/completion-checkers/types.js +2 -2
- package/dist/context/session-manager.d.ts.map +1 -1
- package/dist/context/session-manager.js +19 -32
- package/dist/context/session-manager.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +1 -4
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +24 -7
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +32 -28
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/capabilities-reconcile.js +105 -0
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
- package/dist/core/constraints/checker.d.ts +21 -43
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +64 -115
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +4 -3
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +29 -69
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
- package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +37 -63
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +7 -28
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
- package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +2 -2
- package/dist/core/constraints/context-builder.d.ts +15 -14
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +32 -96
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +2 -1
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +60 -0
- package/dist/core/constraints/git-evidence.d.ts.map +1 -0
- package/dist/core/constraints/git-evidence.js +88 -0
- package/dist/core/constraints/git-evidence.js.map +1 -0
- package/dist/core/constraints/injection-drift.d.ts +3 -20
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +10 -57
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/injection-writer.d.ts +113 -0
- package/dist/core/constraints/injection-writer.d.ts.map +1 -0
- package/dist/core/constraints/injection-writer.js +228 -0
- package/dist/core/constraints/injection-writer.js.map +1 -0
- package/dist/core/constraints/usage-report.d.ts +22 -1
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +27 -20
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +32 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +39 -9
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +15 -64
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +84 -222
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/core/validators/test-output.d.ts +58 -0
- package/dist/core/validators/test-output.d.ts.map +1 -0
- package/dist/core/validators/test-output.js +109 -0
- package/dist/core/validators/test-output.js.map +1 -0
- package/dist/failure/recorder.d.ts +7 -1
- package/dist/failure/recorder.d.ts.map +1 -1
- package/dist/failure/recorder.js +13 -9
- package/dist/failure/recorder.js.map +1 -1
- package/dist/gates/acceptance.d.ts +1 -48
- package/dist/gates/acceptance.d.ts.map +1 -1
- package/dist/gates/acceptance.js +6 -38
- package/dist/gates/acceptance.js.map +1 -1
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +6 -11
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +10 -22
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +22 -61
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +13 -31
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/review.d.ts.map +1 -1
- package/dist/gates/review.js +21 -53
- package/dist/gates/review.js.map +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +14 -32
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +28 -5
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js +38 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +2 -0
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +5 -2
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit.d.ts +7 -2
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +59 -79
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/flywheel-metrics.d.ts +39 -0
- package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
- package/dist/knowledge/flywheel-metrics.js +47 -0
- package/dist/knowledge/flywheel-metrics.js.map +1 -0
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +4 -14
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +18 -15
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/ingest.d.ts.map +1 -1
- package/dist/knowledge/ingest.js +9 -4
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +11 -8
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +12 -9
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +15 -0
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +59 -10
- package/dist/knowledge/store.js.map +1 -1
- package/dist/monitoring/context-tracker.d.ts.map +1 -1
- package/dist/monitoring/context-tracker.js +11 -20
- package/dist/monitoring/context-tracker.js.map +1 -1
- package/dist/monitoring/index.d.ts +1 -1
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +1 -2
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +15 -0
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +19 -2
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +21 -2
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +38 -29
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +7 -0
- package/dist/release/index.js.map +1 -0
- package/dist/release/integrity.d.ts +65 -0
- package/dist/release/integrity.d.ts.map +1 -0
- package/dist/release/integrity.js +151 -0
- package/dist/release/integrity.js.map +1 -0
- package/dist/sdd/index-generator.js +10 -11
- package/dist/sdd/index-generator.js.map +1 -1
- package/dist/test-setup/project-fixture.d.ts +48 -0
- package/dist/test-setup/project-fixture.d.ts.map +1 -0
- package/dist/test-setup/project-fixture.js +106 -0
- package/dist/test-setup/project-fixture.js.map +1 -0
- package/dist/types/constraint.d.ts +0 -18
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/failure.d.ts +7 -0
- package/dist/types/failure.d.ts.map +1 -1
- package/dist/types/failure.js +8 -1
- package/dist/types/failure.js.map +1 -1
- package/dist/types/passes-gate.d.ts +10 -25
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +1 -1
- package/dist/types/session.d.ts +6 -5
- package/dist/types/session.d.ts.map +1 -1
- package/dist/utils/exec.d.ts +10 -0
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +12 -0
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/file-walk.d.ts +9 -1
- package/dist/utils/file-walk.d.ts.map +1 -1
- package/dist/utils/file-walk.js +10 -1
- package/dist/utils/file-walk.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +73 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +141 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/jsonl.d.ts +92 -0
- package/dist/utils/jsonl.d.ts.map +1 -0
- package/dist/utils/jsonl.js +166 -0
- package/dist/utils/jsonl.js.map +1 -0
- package/dist/utils/package-version.d.ts +16 -0
- package/dist/utils/package-version.d.ts.map +1 -0
- package/dist/utils/package-version.js +63 -0
- package/dist/utils/package-version.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +7 -2
- package/src/__tests__/acceptance-gate.test.ts +3 -1
- package/src/__tests__/checker-extra.test.ts +7 -1218
- package/src/__tests__/context-files-resolution.test.ts +116 -0
- package/src/__tests__/effective-constraints.test.ts +10 -13
- package/src/__tests__/exec.test.ts +35 -1
- package/src/__tests__/failure-recorder.test.ts +9 -0
- package/src/__tests__/layering.test.ts +152 -0
- package/src/__tests__/passes-gate-extra.test.ts +0 -145
- package/src/__tests__/passes-gate.test.ts +142 -106
- package/src/__tests__/public-exports.test.ts +3 -0
- package/src/__tests__/skip-semantics.test.ts +5 -9
- package/src/cli/__tests__/command-contract.test.ts +170 -0
- package/src/cli/command-contract.ts +108 -0
- package/src/cli/commands/CONTEXT.md +22 -7
- package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +101 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
- package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
- package/src/cli/commands/__tests__/check.test.ts +378 -382
- package/src/cli/commands/__tests__/command.test.ts +85 -70
- package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
- package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
- package/src/cli/commands/__tests__/contract.test.ts +27 -34
- package/src/cli/commands/__tests__/failure.test.ts +31 -34
- package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
- package/src/cli/commands/__tests__/init.test.ts +77 -48
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +96 -38
- package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
- package/src/cli/commands/__tests__/performance.test.ts +22 -23
- package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
- package/src/cli/commands/__tests__/project-path-convention.test.ts +169 -0
- package/src/cli/commands/__tests__/registry.test.ts +69 -35
- package/src/cli/commands/__tests__/release.test.ts +224 -74
- package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
- package/src/cli/commands/__tests__/report.test.ts +25 -25
- package/src/cli/commands/__tests__/review.test.ts +33 -31
- package/src/cli/commands/__tests__/security.test.ts +23 -27
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
- package/src/cli/commands/__tests__/spec.test.ts +41 -29
- package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
- package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
- package/src/cli/commands/__tests__/status.test.ts +34 -34
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +108 -86
- package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
- package/src/cli/commands/__tests__/update-user-model.test.ts +62 -33
- package/src/cli/commands/__tests__/validate.test.ts +27 -29
- package/src/cli/commands/acceptance.ts +35 -24
- package/src/cli/commands/analyze-sessions.ts +25 -24
- package/src/cli/commands/check.ts +88 -65
- package/src/cli/commands/command.ts +30 -17
- package/src/cli/commands/constraints-report.ts +37 -34
- package/src/cli/commands/constraints-retire.ts +58 -55
- package/src/cli/commands/constraints.ts +10 -27
- package/src/cli/commands/contract.ts +51 -42
- package/src/cli/commands/definitions.ts +37 -223
- package/src/cli/commands/failure.ts +35 -27
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +250 -203
- package/src/cli/commands/passes-gate.ts +58 -68
- package/src/cli/commands/performance.ts +23 -18
- package/src/cli/commands/posteval-plan.ts +29 -15
- package/src/cli/commands/release.ts +75 -78
- package/src/cli/commands/report.ts +9 -5
- package/src/cli/commands/review.ts +39 -29
- package/src/cli/commands/sdd.ts +7 -5
- package/src/cli/commands/security.ts +35 -26
- package/src/cli/commands/spec-baseline-check.ts +16 -11
- package/src/cli/commands/spec.ts +66 -53
- package/src/cli/commands/status.ts +59 -53
- package/src/cli/commands/sync-docs/agents-syncer.ts +31 -15
- package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
- package/src/cli/commands/sync-docs/index.ts +73 -100
- package/src/cli/commands/sync-docs/project-reader.ts +17 -18
- package/src/cli/commands/update-user-model.ts +33 -45
- package/src/cli/commands/validate.ts +31 -25
- package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
- package/src/cli/session-mining/transcript.ts +26 -8
- package/src/completion-checkers/CONTEXT.md +1 -1
- package/src/completion-checkers/__tests__/contract-presence.test.ts +1 -1
- package/src/completion-checkers/__tests__/phase-format.test.ts +1 -1
- package/src/completion-checkers/__tests__/tdd-chain.test.ts +2 -2
- package/src/completion-checkers/index.ts +3 -3
- package/src/completion-checkers/phase-format.ts +2 -2
- package/src/completion-checkers/tdd-chain.ts +2 -2
- package/src/completion-checkers/types.ts +5 -5
- package/src/context/session-manager.ts +19 -33
- package/src/core/CONTEXT.md +9 -6
- package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
- package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
- package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
- package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
- package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
- package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
- package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
- package/src/core/constraints/agent-prompt-renderer.ts +2 -6
- package/src/core/constraints/capabilities-parser.ts +53 -35
- package/src/core/constraints/capabilities-reconcile.ts +166 -0
- package/src/core/constraints/checker.ts +75 -130
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +214 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +117 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
- package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
- package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
- package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
- package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +145 -0
- package/src/core/constraints/checkers/capability-sync.ts +29 -88
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +40 -69
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +2 -2
- package/src/core/constraints/context-builder.ts +39 -91
- package/src/core/constraints/doc-freshness/runner.ts +2 -1
- package/src/core/constraints/git-evidence.ts +120 -0
- package/src/core/constraints/injection-drift.ts +13 -60
- package/src/core/constraints/injection-writer.ts +212 -0
- package/src/core/constraints/usage-report.ts +36 -17
- package/src/core/index.ts +4 -2
- package/src/core/project-config-loader.ts +49 -9
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
- package/src/core/validators/__tests__/test-output.test.ts +372 -0
- package/src/core/validators/passes-gate.ts +86 -248
- package/src/core/validators/test-output.ts +128 -0
- package/src/failure/__tests__/recorder.test.ts +168 -0
- package/src/failure/recorder.ts +13 -11
- package/src/gates/CONTEXT.md +6 -3
- package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
- package/src/gates/__tests__/acceptance.test.ts +4 -86
- package/src/gates/__tests__/effective-gates.test.ts +3 -8
- package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
- package/src/gates/acceptance.ts +19 -84
- package/src/gates/checker-gate.ts +8 -7
- package/src/gates/command.ts +10 -16
- package/src/gates/contract.ts +22 -61
- package/src/gates/performance.ts +10 -22
- package/src/gates/review.ts +21 -41
- package/src/gates/security.ts +10 -22
- package/src/gates/types.ts +70 -5
- package/src/hooks/CONTEXT.md +1 -1
- package/src/hooks/bootstrap.ts +5 -2
- package/src/index.ts +11 -6
- package/src/knowledge/CONTEXT.md +8 -3
- package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
- package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
- package/src/knowledge/__tests__/import.test.ts +44 -0
- package/src/knowledge/__tests__/index-generator.test.ts +55 -2
- package/src/knowledge/__tests__/ingest.test.ts +85 -0
- package/src/knowledge/__tests__/migration.test.ts +47 -0
- package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
- package/src/knowledge/__tests__/store.test.ts +194 -0
- package/src/knowledge/audit.ts +67 -71
- package/src/knowledge/flywheel-metrics.ts +71 -0
- package/src/knowledge/import.ts +4 -18
- package/src/knowledge/index-generator.ts +20 -15
- package/src/knowledge/ingest.ts +9 -4
- package/src/knowledge/migration.ts +11 -8
- package/src/knowledge/reference-tracker.ts +12 -8
- package/src/knowledge/store.ts +64 -11
- package/src/monitoring/CONTEXT.md +8 -3
- package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
- package/src/monitoring/__tests__/traces.test.ts +57 -0
- package/src/monitoring/context-tracker.ts +11 -23
- package/src/monitoring/index.ts +1 -1
- package/src/monitoring/trace-analyzer.ts +21 -2
- package/src/monitoring/traces.ts +39 -36
- package/src/release/CONTEXT.md +24 -0
- package/src/release/__tests__/barrel.test.ts +60 -0
- package/src/release/__tests__/integrity.test.ts +157 -0
- package/src/release/index.ts +2 -0
- package/src/release/integrity.ts +141 -0
- package/src/sdd/__tests__/index-generator.test.ts +71 -0
- package/src/sdd/index-generator.ts +9 -9
- package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
- package/src/test-setup/project-fixture.ts +87 -0
- package/src/tools/CONTEXT.md +6 -0
- package/src/tools/__tests__/registry.test.ts +221 -0
- package/src/types/__tests__/types.test.ts +4 -5
- package/src/types/constraint.ts +0 -25
- package/src/types/failure.ts +8 -0
- package/src/types/passes-gate.ts +10 -30
- package/src/types/project-config.ts +1 -1
- package/src/types/session.ts +5 -5
- package/src/utils/__tests__/frontmatter.test.ts +206 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
- package/src/utils/__tests__/jsonl.test.ts +187 -0
- package/src/utils/__tests__/package-version.test.ts +97 -0
- package/src/utils/exec.ts +15 -0
- package/src/utils/file-walk.ts +11 -2
- package/src/utils/frontmatter.ts +121 -0
- package/src/utils/jsonl.ts +167 -0
- package/src/utils/package-version.ts +27 -0
- package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
- package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
- package/dist/cli/commands/doc-freshness-check.js +0 -352
- package/dist/cli/commands/doc-freshness-check.js.map +0 -1
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -39
- package/dist/types/index.js.map +0 -1
- package/src/__tests__/long-running.test.ts +0 -17
- package/src/__tests__/passes-gate-extension.test.ts +0 -151
- package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
- package/src/cli/commands/doc-freshness-check.ts +0 -386
- package/src/spec/CONTEXT.md +0 -11
- package/src/types/index.ts +0 -47
|
@@ -5,26 +5,18 @@
|
|
|
5
5
|
* 各持一份正则,收敛到此处。H2 起能力清单计数(checkCapabilityCounts /
|
|
6
6
|
* updateCapabilityCounts)也从 sync-docs/capabilities-syncer 收敛到此,
|
|
7
7
|
* 使本模块成为 CAPABILITIES.md 解析 + 计数唯一入口。
|
|
8
|
+
*
|
|
9
|
+
* 计数所需的命令/门禁定义由调用方注入(harness#88:core 不值导入上层定义表)。
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import * as fs from 'fs';
|
|
11
13
|
import { IRON_LAWS, GUIDELINES } from './definitions';
|
|
12
|
-
import { COMMAND_DEFINITIONS } from '../../cli/commands/definitions';
|
|
13
|
-
import { GATE_DEFINITIONS } from '../../gates/definitions';
|
|
14
14
|
import { FreshnessRunner } from './doc-freshness/runner';
|
|
15
15
|
import type { DocFreshnessCheck } from '../../types/project-config';
|
|
16
16
|
|
|
17
|
-
/** CLI 命令数 = 非门禁命令定义 + 门禁命令定义(ADR-0002:定义表是命令形状单一来源) */
|
|
18
|
-
function cliCommandCount(): number {
|
|
19
|
-
return COMMAND_DEFINITIONS.length + GATE_DEFINITIONS.filter(g => g.cli).length;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
17
|
/** 匹配表格单元格中的源码文件条目(如 `src/foo.ts`、`foo.tsx`) */
|
|
23
18
|
const FILE_CELL_REGEX = /\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/g;
|
|
24
19
|
|
|
25
|
-
/** 仅匹配表格第二列的文件条目(checker 的历史语义:第一列为模块名,第二列为文件) */
|
|
26
|
-
const FILE_SECOND_COLUMN_REGEX = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/gm;
|
|
27
|
-
|
|
28
20
|
/**
|
|
29
21
|
* 匹配表格单元格中的目录条目(如 `agents/`)。
|
|
30
22
|
*
|
|
@@ -35,26 +27,25 @@ const FILE_SECOND_COLUMN_REGEX = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/
|
|
|
35
27
|
const DIR_CELL_REGEX = /\|\s*([\w][\w@./-]*\/)\s*\|/g;
|
|
36
28
|
|
|
37
29
|
export interface CapabilitiesParseOptions {
|
|
38
|
-
/**
|
|
30
|
+
/** 是否同时收集目录条目,默认 false */
|
|
39
31
|
includeDirs?: boolean;
|
|
40
|
-
/** 只取表格第二列的文件条目(checker 的历史严格语义),默认 false */
|
|
41
|
-
secondColumnOnly?: boolean;
|
|
42
32
|
}
|
|
43
33
|
|
|
44
34
|
/**
|
|
45
35
|
* 从 CAPABILITIES.md 内容中提取表格列出的条目
|
|
46
36
|
*
|
|
37
|
+
* 解析口径(ADR-0009):表格所有单元格收集;「只看第二列」的历史读法废弃。
|
|
38
|
+
*
|
|
47
39
|
* @param content markdown 内容
|
|
48
40
|
* @returns 文件路径原样 + (可选)目录条目,按出现顺序去重
|
|
49
41
|
*/
|
|
50
42
|
export function parseCapabilitiesEntries(content: string, options: CapabilitiesParseOptions = {}): string[] {
|
|
51
|
-
const { includeDirs = false
|
|
43
|
+
const { includeDirs = false } = options;
|
|
52
44
|
const entries: string[] = [];
|
|
53
45
|
|
|
54
|
-
const fileRegex = secondColumnOnly ? FILE_SECOND_COLUMN_REGEX : FILE_CELL_REGEX;
|
|
55
46
|
let match: RegExpExecArray | null;
|
|
56
|
-
|
|
57
|
-
while ((match =
|
|
47
|
+
FILE_CELL_REGEX.lastIndex = 0;
|
|
48
|
+
while ((match = FILE_CELL_REGEX.exec(content)) !== null) {
|
|
58
49
|
const raw = match[1].trim();
|
|
59
50
|
if (!entries.includes(raw)) entries.push(raw);
|
|
60
51
|
}
|
|
@@ -111,6 +102,20 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
|
|
|
111
102
|
|
|
112
103
|
// ── 能力清单计数 ────────────────────────────────────────────
|
|
113
104
|
|
|
105
|
+
/**
|
|
106
|
+
* 调用方注入的定义源(harness#88)
|
|
107
|
+
*
|
|
108
|
+
* core 只消费计数所需的最小形状,不 require 命令表:
|
|
109
|
+
* - commands:非门禁 CLI 命令定义(仅取长度)
|
|
110
|
+
* - gates:门禁定义(仅取长度与「是否带 cli 元数据」)
|
|
111
|
+
*
|
|
112
|
+
* ADR-0002「定义表是命令形状单一来源」不变,只是表的引用方从 core 移到 cli。
|
|
113
|
+
*/
|
|
114
|
+
export interface CapabilityDefinitionSource {
|
|
115
|
+
commands: readonly unknown[];
|
|
116
|
+
gates: readonly { cli?: unknown }[];
|
|
117
|
+
}
|
|
118
|
+
|
|
114
119
|
/**
|
|
115
120
|
* 能力清单统计规则单份定义(ADR-0008:check/write 两方向共用,
|
|
116
121
|
* 此前 label+pattern 在 buildCapabilityChecks 与 updateCapabilityCounts 各写一遍)
|
|
@@ -119,31 +124,40 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
|
|
|
119
124
|
* write 的替换文本前缀,如 `Quality Gates (6)`)
|
|
120
125
|
* - pattern:同时供 check(doc_regex_count 字符串 pattern,捕获组为文档计数)
|
|
121
126
|
* 与 write(编译为替换 regex)
|
|
122
|
-
* - actual
|
|
127
|
+
* - actual:实际计数——命令/门禁来自注入源,约束来自 core 自身定义表
|
|
123
128
|
*/
|
|
124
129
|
interface CapabilityCountRule {
|
|
125
130
|
label: string;
|
|
126
131
|
pattern: string;
|
|
127
|
-
actual:
|
|
132
|
+
actual: number;
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
/**
|
|
136
|
+
* 能力清单统计规则(CLI Commands 计数 = 非门禁命令数 + 带 cli 元数据的门禁数)
|
|
137
|
+
*/
|
|
138
|
+
function capabilityCountRules(source: CapabilityDefinitionSource): CapabilityCountRule[] {
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
141
|
+
label: 'CLI Commands',
|
|
142
|
+
pattern: 'CLI Commands\\s*\\((\\d+)\\)',
|
|
143
|
+
actual: source.commands.length + source.gates.filter(g => g.cli).length,
|
|
144
|
+
},
|
|
145
|
+
{ label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: source.gates.length },
|
|
146
|
+
{ label: 'Iron Laws', pattern: 'Iron Laws?\\s*\\((\\d+)\\)', actual: Object.keys(IRON_LAWS).length },
|
|
147
|
+
{ label: 'Guidelines', pattern: 'Guidelines?\\s*\\((\\d+)\\)', actual: Object.keys(GUIDELINES).length },
|
|
148
|
+
];
|
|
149
|
+
}
|
|
136
150
|
|
|
137
151
|
/**
|
|
138
152
|
* 构建 CAPABILITIES.md 能力清单格式的检查配置
|
|
139
153
|
*/
|
|
140
|
-
function buildCapabilityChecks(): DocFreshnessCheck[] {
|
|
141
|
-
return
|
|
154
|
+
function buildCapabilityChecks(source: CapabilityDefinitionSource): DocFreshnessCheck[] {
|
|
155
|
+
return capabilityCountRules(source).map(rule => ({
|
|
142
156
|
type: 'doc_regex_count' as const,
|
|
143
157
|
doc: 'CAPABILITIES.md',
|
|
144
158
|
label: rule.label,
|
|
145
159
|
pattern: rule.pattern,
|
|
146
|
-
actual: { kind: 'const_count' as const, value: rule.actual
|
|
160
|
+
actual: { kind: 'const_count' as const, value: rule.actual },
|
|
147
161
|
}));
|
|
148
162
|
}
|
|
149
163
|
|
|
@@ -151,10 +165,11 @@ function buildCapabilityChecks(): DocFreshnessCheck[] {
|
|
|
151
165
|
* 使用 FreshnessRunner 检查能力清单计数是否与代码一致(--check 模式)
|
|
152
166
|
*/
|
|
153
167
|
export function checkCapabilityCounts(
|
|
154
|
-
projectPath: string
|
|
168
|
+
projectPath: string,
|
|
169
|
+
source: CapabilityDefinitionSource
|
|
155
170
|
): { match: boolean; mismatches: string[] } {
|
|
156
171
|
const runner = new FreshnessRunner();
|
|
157
|
-
const checks = buildCapabilityChecks();
|
|
172
|
+
const checks = buildCapabilityChecks(source);
|
|
158
173
|
const results = runner.runAll({ checks }, projectPath);
|
|
159
174
|
|
|
160
175
|
const mismatches: string[] = [];
|
|
@@ -170,14 +185,17 @@ export function checkCapabilityCounts(
|
|
|
170
185
|
/**
|
|
171
186
|
* 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
|
|
172
187
|
*
|
|
173
|
-
*
|
|
174
|
-
* 规则与 check 方向共用
|
|
188
|
+
* 命令/门禁计数取自注入的定义源(ADR-0002 单一来源在调用方),regex 替换文档计数行;
|
|
189
|
+
* 规则与 check 方向共用 capabilityCountRules(ADR-0008)。
|
|
175
190
|
*/
|
|
176
|
-
export function updateCapabilityCounts(
|
|
177
|
-
|
|
191
|
+
export function updateCapabilityCounts(
|
|
192
|
+
content: string,
|
|
193
|
+
source: CapabilityDefinitionSource
|
|
194
|
+
): string {
|
|
195
|
+
for (const rule of capabilityCountRules(source)) {
|
|
178
196
|
const regex = new RegExp(rule.pattern);
|
|
179
197
|
if (regex.test(content)) {
|
|
180
|
-
content = content.replace(regex, `${rule.label} (${rule.actual
|
|
198
|
+
content = content.replace(regex, `${rule.label} (${rule.actual})`);
|
|
181
199
|
}
|
|
182
200
|
}
|
|
183
201
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAPABILITIES.md 声明与代码实况的对照判定(ADR-0009)
|
|
3
|
+
*
|
|
4
|
+
* 纯判定 module:吃「文档内容 + 实际文件清单(+ 增量清单)」,一次产出全部判定结果;
|
|
5
|
+
* 不做任何 fs/git IO(存在性可选注入)。此前同一套覆盖/幽灵规则在
|
|
6
|
+
* capability_sync / docs_freshness / sync-docs 三处独立实现,靠「同规则」注释人工同步,
|
|
7
|
+
* 同一 bug(basename 碰撞、后缀误配)在多处各修一遍——此处为唯一真相源。
|
|
8
|
+
*
|
|
9
|
+
* 方向:
|
|
10
|
+
* 代码→文档 uncoveredChanges / uncoveredFiles / uncoveredDirs(漏登记)
|
|
11
|
+
* 文档→代码 deadEntries(幽灵:文档登记的路径既不在代码实况中、文件系统中也不存在)
|
|
12
|
+
*
|
|
13
|
+
* 解析口径(ADR-0009):表格所有单元格收集,文件条目与目录条目都参与覆盖;
|
|
14
|
+
* 「只看第二列」的历史读法废弃。幽灵判定同样覆盖文件与目录条目(口径从严)。
|
|
15
|
+
* mode=module / file 的差异不在判定层,而是调用方取哪份输出形状:
|
|
16
|
+
* module 读 uncoveredDirs(目录聚合),file 读 uncoveredFiles(逐文件)。
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { join, relative } from 'path';
|
|
20
|
+
import {
|
|
21
|
+
aggregateToSourceSubdir,
|
|
22
|
+
isCapabilityListingFormat,
|
|
23
|
+
parseCapabilitiesEntries,
|
|
24
|
+
} from './capabilities-parser';
|
|
25
|
+
import { findTsSourceFiles } from '../../utils/file-walk';
|
|
26
|
+
|
|
27
|
+
/** markdown 表格分隔行(|------|------|):区分「无表格的散文文档」与「有表格但零条目」 */
|
|
28
|
+
const TABLE_SEPARATOR_REGEX = /^\s*\|[\s:|-]+\|\s*$/m;
|
|
29
|
+
|
|
30
|
+
export interface ReconcileInput {
|
|
31
|
+
/** CAPABILITIES.md 内容 */
|
|
32
|
+
content: string;
|
|
33
|
+
/** 代码实况全集:项目相对路径的源文件清单(由调用方收集,见 collectSourceFiles) */
|
|
34
|
+
populationFiles: string[];
|
|
35
|
+
/** 增量变更文件(项目相对路径);无 git 概念的消费方传空/不传 */
|
|
36
|
+
changedFiles?: string[];
|
|
37
|
+
/** 存在性 oracle(项目相对路径 → 是否存在);缺省退化为「代码实况兜底」 */
|
|
38
|
+
fileExists?: (relPath: string) => boolean;
|
|
39
|
+
/** 源码根(如 'src'、'apps/api/src'):未覆盖聚合与条目多根相对路径解析用 */
|
|
40
|
+
sourceRoots?: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CapabilityVerdict {
|
|
44
|
+
/** 文档中的文件条目(原样路径,可能为全路径或裸文件名) */
|
|
45
|
+
fileEntries: string[];
|
|
46
|
+
/** 文档中的目录条目(以 / 结尾) */
|
|
47
|
+
dirEntries: string[];
|
|
48
|
+
/** 参与覆盖判定的条目集 = 文件条目 + 目录条目 */
|
|
49
|
+
coverageEntries: string[];
|
|
50
|
+
/** 文档含 markdown 表格(区分「散文文档」与「有表格零条目」) */
|
|
51
|
+
hasTable: boolean;
|
|
52
|
+
/** 能力清单格式(计数行文档):无文件表可核对,调用方据此短路 */
|
|
53
|
+
listingFormat: boolean;
|
|
54
|
+
/** 增量文件中未被覆盖的(capability_sync Step1) */
|
|
55
|
+
uncoveredChanges: string[];
|
|
56
|
+
/** 代码实况中未被文档登记的 */
|
|
57
|
+
uncoveredFiles: string[];
|
|
58
|
+
/** 未覆盖文件按源码根下第一级子目录聚合(module 模式的 added 形状) */
|
|
59
|
+
uncoveredDirs: string[];
|
|
60
|
+
/** 幽灵条目(文件 + 目录):文档登记但代码实况与文件系统均不存在 */
|
|
61
|
+
deadEntries: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 变更文件是否被条目覆盖(ADR-0009 唯一覆盖规则)
|
|
66
|
+
*
|
|
67
|
+
* 目录条目(以 / 结尾)前缀匹配;文件条目精确匹配或路径边界后缀匹配
|
|
68
|
+
* (兼容 basename 条目,但拒绝 xfoo.ts 命中 foo.ts、docs/src/foo.tsx 命中 src/foo.ts
|
|
69
|
+
* 这类 endsWith/includes 模糊匹配造成的碰撞)
|
|
70
|
+
*/
|
|
71
|
+
function isCoveredBy(entries: string[], file: string): boolean {
|
|
72
|
+
return entries.some((listed) =>
|
|
73
|
+
listed.endsWith('/')
|
|
74
|
+
? file.startsWith(listed)
|
|
75
|
+
: file === listed || file.endsWith('/' + listed)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 条目多根相对路径的存在性:项目根直查 + 各源码根前缀(docs_freshness/sync-docs 历史同语义) */
|
|
80
|
+
function entryExistsOnDisk(
|
|
81
|
+
entry: string,
|
|
82
|
+
fileExists: (rel: string) => boolean,
|
|
83
|
+
sourceRoots: string[]
|
|
84
|
+
): boolean {
|
|
85
|
+
if (fileExists(entry)) return true;
|
|
86
|
+
return sourceRoots.some((root) => fileExists(`${root}/${entry}`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function reconcileCapabilities(input: ReconcileInput): CapabilityVerdict {
|
|
90
|
+
const {
|
|
91
|
+
content,
|
|
92
|
+
populationFiles,
|
|
93
|
+
changedFiles = [],
|
|
94
|
+
fileExists = () => false,
|
|
95
|
+
sourceRoots = [],
|
|
96
|
+
} = input;
|
|
97
|
+
|
|
98
|
+
const allEntries = parseCapabilitiesEntries(content, { includeDirs: true });
|
|
99
|
+
const fileEntries = allEntries.filter((e) => !e.endsWith('/'));
|
|
100
|
+
const dirEntries = allEntries.filter((e) => e.endsWith('/'));
|
|
101
|
+
const coverageEntries = [...fileEntries, ...dirEntries];
|
|
102
|
+
|
|
103
|
+
const uncoveredFiles = populationFiles.filter((f) => !isCoveredBy(coverageEntries, f));
|
|
104
|
+
const uncoveredDirs = [...new Set(
|
|
105
|
+
uncoveredFiles.map((file) => {
|
|
106
|
+
// 与 sync-docs 历史聚合同语义:归属第一个能前缀匹配的来源根,兜底首根
|
|
107
|
+
const root = sourceRoots.find((d) => file.startsWith(d + '/')) || sourceRoots[0] || '';
|
|
108
|
+
return aggregateToSourceSubdir(root, file);
|
|
109
|
+
})
|
|
110
|
+
)];
|
|
111
|
+
|
|
112
|
+
// 条目在代码实况中仍有对应文件即算活(裸文件名条目无法做存在性判定的兜底)
|
|
113
|
+
const aliveByPopulation = (entry: string): boolean =>
|
|
114
|
+
populationFiles.some((f) => isCoveredBy([entry], f));
|
|
115
|
+
|
|
116
|
+
const deadEntries = allEntries.filter((entry) => {
|
|
117
|
+
if (entryExistsOnDisk(entry, fileExists, sourceRoots)) return false;
|
|
118
|
+
return !aliveByPopulation(entry);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
fileEntries,
|
|
123
|
+
dirEntries,
|
|
124
|
+
coverageEntries,
|
|
125
|
+
hasTable: TABLE_SEPARATOR_REGEX.test(content),
|
|
126
|
+
listingFormat: isCapabilityListingFormat(content),
|
|
127
|
+
uncoveredChanges: changedFiles.filter((f) => !isCoveredBy(coverageEntries, f)),
|
|
128
|
+
uncoveredFiles,
|
|
129
|
+
uncoveredDirs,
|
|
130
|
+
deadEntries,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 变更清单中的「有意义的代码变更」:仅 .ts/.tsx/.js 且非测试文件
|
|
136
|
+
* (capability_sync Step1 的历史过滤规则,收口于此)
|
|
137
|
+
*/
|
|
138
|
+
export function significantCodeChanges(diffNames: string[]): string[] {
|
|
139
|
+
return diffNames
|
|
140
|
+
.filter((f) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js'))
|
|
141
|
+
.filter((f) => !f.includes('__tests__') && !f.includes('.test.') && !f.includes('.spec.'));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 收集源码根下的实际文件清单(项目相对路径)
|
|
146
|
+
*
|
|
147
|
+
* 对 utils/file-walk 的统一封装,替代各调用方自拼 join/relative。
|
|
148
|
+
* 扩展名口径保持各调用方现状(checker 不含 .tsx;sync-docs 的模块扫描需
|
|
149
|
+
* ModuleInfo 元数据,继续走 scanSourceModules)——统一扩展名口径属行为变更,
|
|
150
|
+
* 不在本次纯重构范围(ADR-0009 记录在案)。
|
|
151
|
+
*/
|
|
152
|
+
export function collectSourceFiles(
|
|
153
|
+
projectPath: string,
|
|
154
|
+
roots: string[],
|
|
155
|
+
options: { includeTsx?: boolean } = {}
|
|
156
|
+
): string[] {
|
|
157
|
+
const files: string[] = [];
|
|
158
|
+
for (const root of roots) {
|
|
159
|
+
const found = findTsSourceFiles(join(projectPath, root), {
|
|
160
|
+
skipIndex: true,
|
|
161
|
+
includeTsx: options.includeTsx,
|
|
162
|
+
});
|
|
163
|
+
files.push(...found.map((f) => relative(projectPath, f)));
|
|
164
|
+
}
|
|
165
|
+
return files;
|
|
166
|
+
}
|
|
@@ -12,32 +12,33 @@ import {
|
|
|
12
12
|
ConstraintContext,
|
|
13
13
|
ConstraintResult,
|
|
14
14
|
ConstraintCheckResult,
|
|
15
|
-
ConstraintTrigger,
|
|
16
15
|
ConstraintLevel,
|
|
17
16
|
ConstraintViolationError,
|
|
18
17
|
} from '../../types/constraint';
|
|
19
18
|
import type { ExecutionTrace } from '../../types/trace';
|
|
20
|
-
import { getTraceCollector } from '../../monitoring/traces';
|
|
21
19
|
import { IRON_LAWS, GUIDELINES, PROMPTS } from './definitions';
|
|
22
20
|
import type { MergedConstraintsConfig } from '../../types/project-config';
|
|
23
|
-
import {
|
|
24
|
-
import { runCommand } from '../../utils/exec';
|
|
21
|
+
import { matchesTrigger } from '../../utils/exec';
|
|
25
22
|
import { join, relative } from 'path';
|
|
26
23
|
import { CheckCache } from './check-cache';
|
|
27
24
|
import { findTsSourceFiles } from '../../utils/file-walk';
|
|
28
25
|
import { getConstraintCheck, buildCheckEnv, type CheckOutcome } from './checkers';
|
|
26
|
+
import { createGitEvidence, type GitEvidence } from './git-evidence';
|
|
29
27
|
|
|
30
28
|
/**
|
|
31
|
-
* trace
|
|
32
|
-
* 不反向依赖 core,方向单向、无环,checker 可直接值引用 getTraceCollector)
|
|
29
|
+
* trace 记录器最小接口(工单 15 decycle 收尾,harness#88)
|
|
33
30
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* core 不上行依赖 monitoring:记录器经**构造参数**注入,未注入 = no-op
|
|
32
|
+
* (默认无副作用)。真实收集器由组合根接线——CLI check/report 与 bootstrap
|
|
33
|
+
* 各自 `new ConstraintChecker(getTraceCollector())`。
|
|
36
34
|
*/
|
|
37
35
|
export interface TraceRecorder {
|
|
38
36
|
record(trace: ExecutionTrace): void;
|
|
39
37
|
}
|
|
40
38
|
|
|
39
|
+
/** 未注入时的默认记录器:不记录 */
|
|
40
|
+
const NOOP_TRACE_RECORDER: TraceRecorder = { record: () => undefined };
|
|
41
|
+
|
|
41
42
|
/**
|
|
42
43
|
* 约束检查器
|
|
43
44
|
*/
|
|
@@ -47,60 +48,15 @@ export class ConstraintChecker {
|
|
|
47
48
|
/** 检查结果缓存(S7:src 扫描等重复 I/O,TTL=1s 防跨测试污染) */
|
|
48
49
|
private cache: CheckCache = new CheckCache({ ttlMs: 1000 });
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
* git diff 等命令只执行一次;run 外直接调用私有检查方法时不 memo(恒新鲜)。
|
|
53
|
-
*/
|
|
54
|
-
private runCache: Map<string, Promise<string>> | null = null;
|
|
55
|
-
|
|
56
|
-
/** trace 记录器(注入式;null = 未显式注入,首次记录时惰性接线全局收集器) */
|
|
57
|
-
private traceRecorder: TraceRecorder | null = null;
|
|
51
|
+
/** trace 记录器(构造注入;缺省 no-op) */
|
|
52
|
+
private readonly traceRecorder: TraceRecorder;
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 取 trace 记录器:未显式注入时惰性接线全局收集器(幂等,ADR-0003 副作用收敛)
|
|
63
|
-
*/
|
|
64
|
-
private getRecorder(): TraceRecorder {
|
|
65
|
-
if (!this.traceRecorder) {
|
|
66
|
-
this.traceRecorder = getTraceCollector();
|
|
67
|
-
}
|
|
68
|
-
return this.traceRecorder;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* run 内 memoize;无活动 run 时直接执行(工单 18)
|
|
73
|
-
*/
|
|
74
|
-
private memoRun(key: string, fn: () => Promise<string>): Promise<string> {
|
|
75
|
-
if (!this.runCache) return fn();
|
|
76
|
-
let pending = this.runCache.get(key);
|
|
77
|
-
if (!pending) {
|
|
78
|
-
pending = fn();
|
|
79
|
-
this.runCache.set(key, pending);
|
|
80
|
-
}
|
|
81
|
-
return pending;
|
|
54
|
+
constructor(traceRecorder: TraceRecorder = NOOP_TRACE_RECORDER) {
|
|
55
|
+
this.traceRecorder = traceRecorder;
|
|
82
56
|
}
|
|
83
57
|
|
|
84
58
|
/**
|
|
85
|
-
*
|
|
86
|
-
*/
|
|
87
|
-
private getStagedDiff(projectPath: string): Promise<string> {
|
|
88
|
-
return this.memoRun(`git_diff_staged:${projectPath}`, () =>
|
|
89
|
-
runCommand('git diff --cached', projectPath)
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* staged 变更文件名列表(同一次 run 内只执行一次 git 命令,工单 18)
|
|
95
|
-
*/
|
|
96
|
-
private getStagedDiffNames(projectPath: string): Promise<string> {
|
|
97
|
-
return this.memoRun(`git_diff_staged_names:${projectPath}`, () =>
|
|
98
|
-
runCommand('git diff --cached --name-only', projectPath)
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 获取单例实例
|
|
59
|
+
* 获取单例实例(未接线记录器的默认实例:不写 trace)
|
|
104
60
|
*/
|
|
105
61
|
static getInstance(): ConstraintChecker {
|
|
106
62
|
if (!ConstraintChecker.instance) {
|
|
@@ -109,13 +65,6 @@ export class ConstraintChecker {
|
|
|
109
65
|
return ConstraintChecker.instance;
|
|
110
66
|
}
|
|
111
67
|
|
|
112
|
-
/**
|
|
113
|
-
* 注入 trace 记录器(测试/定制场景;不调用则首次记录时惰性接线全局收集器)
|
|
114
|
-
*/
|
|
115
|
-
setTraceRecorder(recorder: TraceRecorder): void {
|
|
116
|
-
this.traceRecorder = recorder;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
68
|
/**
|
|
120
69
|
* 获取当前的约束集合(内置 + 自定义)
|
|
121
70
|
*
|
|
@@ -143,10 +92,13 @@ export class ConstraintChecker {
|
|
|
143
92
|
|
|
144
93
|
/**
|
|
145
94
|
* 检查单个约束
|
|
95
|
+
*
|
|
96
|
+
* @param evidence 可选,本 run 的 git 证据实例(#87);不传 = 本次调用独占一份真 git 证据
|
|
146
97
|
*/
|
|
147
98
|
async check(
|
|
148
99
|
constraint: Constraint,
|
|
149
|
-
context: ConstraintContext
|
|
100
|
+
context: ConstraintContext,
|
|
101
|
+
evidence?: GitEvidence
|
|
150
102
|
): Promise<ConstraintResult> {
|
|
151
103
|
// prompt 类约束不参与 checker 执行(ADR-0001:仅参与注入)
|
|
152
104
|
if (constraint.kind === 'prompt') {
|
|
@@ -160,7 +112,7 @@ export class ConstraintChecker {
|
|
|
160
112
|
}
|
|
161
113
|
|
|
162
114
|
// 检查前置条件('skip' = 约定未采用/证据未接线:satisfied 置 true 但不计 pass/fail)
|
|
163
|
-
const outcome = await this.checkPrecondition(constraint, context);
|
|
115
|
+
const outcome = await this.checkPrecondition(constraint, context, evidence);
|
|
164
116
|
|
|
165
117
|
if (outcome === 'skip') {
|
|
166
118
|
return {
|
|
@@ -203,28 +155,15 @@ export class ConstraintChecker {
|
|
|
203
155
|
}
|
|
204
156
|
}
|
|
205
157
|
|
|
206
|
-
/**
|
|
207
|
-
* 判断约束是否匹配当前触发条件
|
|
208
|
-
*
|
|
209
|
-
* context.operation 为主触发条件,context.extraTriggers 为次级推断
|
|
210
|
-
* (ADR-0001:pre-commit 代码变更附加 code_implementation),任一命中即匹配。
|
|
211
|
-
*/
|
|
212
|
-
private matchesTrigger(constraint: Constraint, context: ConstraintContext): boolean {
|
|
213
|
-
const triggers = normalizeTriggers<ConstraintTrigger>(constraint.trigger);
|
|
214
|
-
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
215
|
-
return operations.some(op => triggers.includes(op));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
158
|
/**
|
|
219
159
|
* 记录约束检查的 trace
|
|
220
160
|
*/
|
|
221
161
|
private recordTrace(
|
|
222
|
-
collector: TraceRecorder,
|
|
223
162
|
constraint: Constraint,
|
|
224
163
|
checkResult: ConstraintResult,
|
|
225
164
|
context: ConstraintContext
|
|
226
165
|
): void {
|
|
227
|
-
|
|
166
|
+
this.traceRecorder.record({
|
|
228
167
|
constraintId: constraint.id,
|
|
229
168
|
level: constraint.level,
|
|
230
169
|
timestamp: Date.now(),
|
|
@@ -241,10 +180,14 @@ export class ConstraintChecker {
|
|
|
241
180
|
*
|
|
242
181
|
* 注册表闭环(ADR-0001):kind='check' 未注册 checker 直接抛错,
|
|
243
182
|
* 不再有"未注册默认通过"路径;kind='prompt' 在 check() 入口已短路。
|
|
183
|
+
*
|
|
184
|
+
* git 证据(stagedDiff/stagedDiffNames)单一来源 = GitEvidence adapter(#87):
|
|
185
|
+
* 一次 run 内调用方传同一实例即至多取证一次,run 外调用独占一份。
|
|
244
186
|
*/
|
|
245
187
|
private async checkPrecondition(
|
|
246
188
|
constraint: Constraint,
|
|
247
|
-
context: ConstraintContext
|
|
189
|
+
context: ConstraintContext,
|
|
190
|
+
evidence?: GitEvidence
|
|
248
191
|
): Promise<CheckOutcome> {
|
|
249
192
|
const impl = getConstraintCheck(constraint.id);
|
|
250
193
|
if (!impl) {
|
|
@@ -255,9 +198,10 @@ export class ConstraintChecker {
|
|
|
255
198
|
}
|
|
256
199
|
|
|
257
200
|
const projectPath = context.projectPath || process.cwd();
|
|
201
|
+
const git = evidence ?? createGitEvidence(projectPath);
|
|
258
202
|
const env = buildCheckEnv(context, {
|
|
259
|
-
stagedDiff: () =>
|
|
260
|
-
stagedDiffNames: () =>
|
|
203
|
+
stagedDiff: async () => git.stagedDiff(),
|
|
204
|
+
stagedDiffNames: async () => git.changedFileNames(true),
|
|
261
205
|
srcScan: (root: string) =>
|
|
262
206
|
this.cache.getSync(`src_scan_${root}`, projectPath, () =>
|
|
263
207
|
findTsSourceFiles(join(projectPath, root), { skipIndex: true }).map((f) =>
|
|
@@ -287,12 +231,9 @@ export class ConstraintChecker {
|
|
|
287
231
|
const constraints = this.getConstraints(customConfig);
|
|
288
232
|
|
|
289
233
|
const filterByTrigger = (constraintSet: Record<string, Constraint>): Constraint[] => {
|
|
290
|
-
return Object.values(constraintSet).filter(constraint =>
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
: [constraint.trigger];
|
|
294
|
-
return operations.some(op => triggers.includes(op));
|
|
295
|
-
});
|
|
234
|
+
return Object.values(constraintSet).filter(constraint =>
|
|
235
|
+
matchesTrigger(constraint, operations)
|
|
236
|
+
);
|
|
296
237
|
};
|
|
297
238
|
|
|
298
239
|
return {
|
|
@@ -310,57 +251,58 @@ export class ConstraintChecker {
|
|
|
310
251
|
*
|
|
311
252
|
* @param context 约束上下文
|
|
312
253
|
* @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
|
|
254
|
+
* @param evidence 可选,本 run 的 git 证据 adapter(#87)。调用方(CLI check)与
|
|
255
|
+
* buildConstraintContext 传同一实例 → 一次 run 内 git 取证单一来源;
|
|
256
|
+
* 不传则本 run 自建一份,run 级 memo 照样生效(memo 在实例层,非隐式全局)。
|
|
313
257
|
*/
|
|
314
258
|
async checkConstraints(
|
|
315
259
|
context: ConstraintContext,
|
|
316
|
-
customConfig?: MergedConstraintsConfig | null
|
|
260
|
+
customConfig?: MergedConstraintsConfig | null,
|
|
261
|
+
evidence?: GitEvidence
|
|
317
262
|
): Promise<ConstraintCheckResult> {
|
|
318
|
-
// run 起始:重置
|
|
263
|
+
// run 起始:重置 src 扫描缓存(S7);git 证据 = 本 run 独占的 adapter 实例(工单 18 → #87)
|
|
319
264
|
this.cache.invalidate();
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
try {
|
|
323
|
-
const result: ConstraintCheckResult = {
|
|
324
|
-
ironLaws: [],
|
|
325
|
-
guidelines: [],
|
|
326
|
-
passed: true,
|
|
327
|
-
warningCount: 0,
|
|
328
|
-
};
|
|
265
|
+
const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
|
|
329
266
|
|
|
330
|
-
|
|
331
|
-
|
|
267
|
+
const result: ConstraintCheckResult = {
|
|
268
|
+
ironLaws: [],
|
|
269
|
+
guidelines: [],
|
|
270
|
+
passed: true,
|
|
271
|
+
warningCount: 0,
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const constraints = this.getConstraints(customConfig);
|
|
275
|
+
// context.operation 为主触发条件,extraTriggers 为次级推断(ADR-0001),任一命中即匹配
|
|
276
|
+
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
332
277
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
278
|
+
// 1. Iron Laws: 必须全部通过
|
|
279
|
+
for (const constraint of Object.values(constraints.ironLaws)) {
|
|
280
|
+
if (!matchesTrigger(constraint, operations)) continue;
|
|
336
281
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
282
|
+
const checkResult = await this.check(constraint, context, run);
|
|
283
|
+
result.ironLaws.push(checkResult);
|
|
284
|
+
this.recordTrace(constraint, checkResult, context);
|
|
340
285
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
286
|
+
if (!checkResult.satisfied) {
|
|
287
|
+
result.passed = false;
|
|
288
|
+
throw new ConstraintViolationError(checkResult);
|
|
345
289
|
}
|
|
290
|
+
}
|
|
346
291
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
292
|
+
// 2. Guidelines: 记录警告
|
|
293
|
+
for (const constraint of Object.values(constraints.guidelines)) {
|
|
294
|
+
if (!matchesTrigger(constraint, operations)) continue;
|
|
350
295
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
296
|
+
const checkResult = await this.check(constraint, context, run);
|
|
297
|
+
result.guidelines.push(checkResult);
|
|
298
|
+
this.recordTrace(constraint, checkResult, context);
|
|
354
299
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
300
|
+
if (!checkResult.satisfied) {
|
|
301
|
+
result.warningCount++;
|
|
358
302
|
}
|
|
359
|
-
|
|
360
|
-
return result;
|
|
361
|
-
} finally {
|
|
362
|
-
this.runCache = null;
|
|
363
303
|
}
|
|
304
|
+
|
|
305
|
+
return result;
|
|
364
306
|
}
|
|
365
307
|
|
|
366
308
|
/**
|
|
@@ -368,19 +310,22 @@ export class ConstraintChecker {
|
|
|
368
310
|
*
|
|
369
311
|
* @param context 约束上下文
|
|
370
312
|
* @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
|
|
313
|
+
* @param evidence 可选,本次检查共用的 git 证据 adapter(#87,同 checkConstraints)
|
|
371
314
|
* @throws ConstraintViolationError 如果有铁律违规
|
|
372
315
|
*/
|
|
373
316
|
async beforeExecution(
|
|
374
317
|
context: ConstraintContext,
|
|
375
|
-
customConfig?: MergedConstraintsConfig | null
|
|
318
|
+
customConfig?: MergedConstraintsConfig | null,
|
|
319
|
+
evidence?: GitEvidence
|
|
376
320
|
): Promise<void> {
|
|
321
|
+
const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
|
|
377
322
|
const constraints = this.getConstraints(customConfig);
|
|
378
323
|
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
379
324
|
|
|
380
325
|
for (const constraint of Object.values(constraints.ironLaws)) {
|
|
381
|
-
if (!
|
|
326
|
+
if (!matchesTrigger(constraint, operations)) continue;
|
|
382
327
|
|
|
383
|
-
const result = await this.check(constraint, context);
|
|
328
|
+
const result = await this.check(constraint, context, run);
|
|
384
329
|
if (!result.satisfied) {
|
|
385
330
|
throw new ConstraintViolationError(result);
|
|
386
331
|
}
|
|
@@ -465,5 +410,5 @@ export async function checkBeforeExecution(
|
|
|
465
410
|
return ConstraintChecker.getInstance().beforeExecution(context, customConfig);
|
|
466
411
|
}
|
|
467
412
|
|
|
468
|
-
//
|
|
413
|
+
// 导出单例(未接线记录器:只评估约束,不写 trace;写 trace 由组合根自行 new)
|
|
469
414
|
export const constraintChecker = ConstraintChecker.getInstance();
|