@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
package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts
RENAMED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* no_hardcoded_credentials
|
|
2
|
+
* no_hardcoded_credentials 检查器旁测(ADR-0001)
|
|
3
3
|
*
|
|
4
4
|
* 注意:测试夹具中的假凭证一律用字符串拼接构造,
|
|
5
5
|
* 避免本文件自身被凭证扫描(含 harness 自身 staged diff)命中。
|
|
6
|
+
* 测试面 = evaluate(env)(架构评审候选4,自 src/__tests__/ 就近迁入)。
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import { describe, it, expect } from '@jest/globals';
|
|
9
10
|
import {
|
|
10
11
|
noHardcodedCredentials,
|
|
11
12
|
containsHardcodedCredential,
|
|
12
|
-
} from '../
|
|
13
|
-
import type { CheckEnv } from '../
|
|
13
|
+
} from '../no-hardcoded-credentials';
|
|
14
|
+
import type { CheckEnv } from '../types';
|
|
14
15
|
|
|
15
16
|
function makeEnv(stagedDiff: string): CheckEnv {
|
|
16
17
|
return {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* no_test_simplification 检查器旁测(架构评审候选4,ADR-0009 同模式)
|
|
3
|
+
*
|
|
4
|
+
* 测试面 = ConstraintCheck.evaluate(env):判定只吃 stagedDiff 文本,
|
|
5
|
+
* 证据经 providers 注入(旧 facade 测用真实非 git 目录触发 IO 失败,
|
|
6
|
+
* 旁测直接让 provider 抛错表达同一语义)。自 checker-extra.test.ts 迁入。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect } from '@jest/globals';
|
|
10
|
+
import { noTestSimplification } from '../no-test-simplification';
|
|
11
|
+
import { buildCheckEnv } from '../types';
|
|
12
|
+
import type { ConstraintContext } from '../../../../types/constraint';
|
|
13
|
+
|
|
14
|
+
function evaluate(diff: string | (() => Promise<string>)) {
|
|
15
|
+
const context: ConstraintContext = { operation: 'test_creation', projectPath: '/nonexistent' };
|
|
16
|
+
const stagedDiff = typeof diff === 'function' ? diff : async () => diff;
|
|
17
|
+
return noTestSimplification.evaluate(
|
|
18
|
+
buildCheckEnv(context, {
|
|
19
|
+
stagedDiff,
|
|
20
|
+
stagedDiffNames: async () => '',
|
|
21
|
+
srcScan: () => [],
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('no_test_simplification', () => {
|
|
27
|
+
it('删除 test/it/describe → fail', async () => {
|
|
28
|
+
expect(await evaluate('--- a/x.test.ts\n+++ b/x.test.ts\n@@\n- test("gone", () => {});\n')).toBe(false);
|
|
29
|
+
expect(await evaluate('- it("gone", () => {});')).toBe(false);
|
|
30
|
+
expect(await evaluate('-describe("suite", () => {});')).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('删除 expect → fail', async () => {
|
|
34
|
+
expect(await evaluate('- expect(x).toBe(y);')).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('删除注释掉的 test → fail', async () => {
|
|
38
|
+
expect(await evaluate('- // test pending case')).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('仅新增/上下文行 → pass', async () => {
|
|
42
|
+
expect(
|
|
43
|
+
await evaluate('--- a/x.test.ts\n+++ b/x.test.ts\n@@\n+ test("added", () => {});\n expect(1).toBe(1);\n')
|
|
44
|
+
).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('空 diff → pass', async () => {
|
|
48
|
+
expect(await evaluate('')).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('git diff 失败 → 默认通过(fail-open,自 facade 测迁入)', async () => {
|
|
52
|
+
expect(
|
|
53
|
+
await evaluate(async () => {
|
|
54
|
+
throw new Error('not a git repository');
|
|
55
|
+
})
|
|
56
|
+
).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context_files 三态对照测试(工单 84)
|
|
3
|
+
*
|
|
4
|
+
* 同一组 fixture 同时跑 context_doc_sync 与 docs_freshness 两条约束,
|
|
5
|
+
* 钉死 triage 裁决口径:未配置 / enabled 但无目标 → 约束 checker 一律 skip
|
|
6
|
+
* (ADR-0001 存在性探测同构);enabled 且非空 → 两条约束按同一组 dirs
|
|
7
|
+
* 评估且判定一致。
|
|
8
|
+
*
|
|
9
|
+
* 附带 docs_freshness 评估段的行为变更钉子:enabled 但无目标 → skip,
|
|
10
|
+
* 不再静默放行(此前返回 true)。
|
|
11
|
+
* 项目根由 src/test-setup/project-fixture 声明式构造(回收仍走 mkdtemp-cleanup)。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect } from '@jest/globals';
|
|
15
|
+
import { contextDocSync } from '../context-doc-sync';
|
|
16
|
+
import { docsFreshness } from '../docs-freshness';
|
|
17
|
+
import { buildCheckEnv } from '../types';
|
|
18
|
+
import { collectSourceFiles } from '../../capabilities-reconcile';
|
|
19
|
+
import { createProjectFixture } from '../../../../test-setup/project-fixture';
|
|
20
|
+
import type { ConstraintContext } from '../../../../types/constraint';
|
|
21
|
+
|
|
22
|
+
const TABLE_HEAD = '| 模块 | 文件 | 说明 |\n|------|------|------|\n';
|
|
23
|
+
|
|
24
|
+
interface Fixture {
|
|
25
|
+
configYml?: string;
|
|
26
|
+
contextMdDirs?: string[];
|
|
27
|
+
files?: string[];
|
|
28
|
+
capabilitiesBody?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function setupDir(name: string, fixture: Fixture = {}): string {
|
|
32
|
+
return createProjectFixture({
|
|
33
|
+
name: `three-state-${name}`,
|
|
34
|
+
config: fixture.configYml,
|
|
35
|
+
files: {
|
|
36
|
+
...Object.fromEntries((fixture.files ?? []).map(f => [f, 'export const x = 1;'])),
|
|
37
|
+
...Object.fromEntries((fixture.contextMdDirs ?? []).map(d => [`${d}/CONTEXT.md`, `# ${d}\n`])),
|
|
38
|
+
...(fixture.capabilitiesBody === undefined
|
|
39
|
+
? {}
|
|
40
|
+
: { 'CAPABILITIES.md': `# Capabilities\n\n${fixture.capabilitiesBody}` }),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const CTX_FILES = (enabled: boolean, dirs?: string[]) =>
|
|
46
|
+
`governance:\n context_files:\n enabled: ${enabled}\n` +
|
|
47
|
+
(dirs ? ` required_dirs: [${dirs.map(d => `'${d}'`).join(', ')}]\n` : '');
|
|
48
|
+
|
|
49
|
+
function evalContextDocSync(dir: string) {
|
|
50
|
+
const context: ConstraintContext = { operation: 'module_modification', projectPath: dir };
|
|
51
|
+
return contextDocSync.evaluate(buildCheckEnv(context, 'none'));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function evalDocsFreshness(dir: string) {
|
|
55
|
+
const context: ConstraintContext = { operation: 'file_modification', projectPath: dir };
|
|
56
|
+
return docsFreshness.evaluate(
|
|
57
|
+
buildCheckEnv(context, {
|
|
58
|
+
stagedDiff: async () => '',
|
|
59
|
+
stagedDiffNames: async () => '',
|
|
60
|
+
srcScan: (root: string) => collectSourceFiles(dir, [root]),
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** 同一 fixture 上两条约束的判定必须一致(对照断言) */
|
|
66
|
+
async function expectBoth(dir: string, verdict: true | false | 'skip'): Promise<void> {
|
|
67
|
+
expect(await evalContextDocSync(dir)).toBe(verdict);
|
|
68
|
+
expect(await evalDocsFreshness(dir)).toBe(verdict);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe('context_files 三态对照 — context_doc_sync vs docs_freshness(工单 84)', () => {
|
|
72
|
+
it('未配置(无 config.yml)→ 双双 skip', async () => {
|
|
73
|
+
await expectBoth(setupDir('no-config'), 'skip');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('governance.context_files 段缺失 → 双双 skip', async () => {
|
|
77
|
+
await expectBoth(setupDir('no-section', { configYml: 'preset: standard\n' }), 'skip');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('enabled: false(约定未采用)→ 双双 skip', async () => {
|
|
81
|
+
await expectBoth(setupDir('disabled', { configYml: CTX_FILES(false, ['src']) }), 'skip');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('enabled 但 required_dirs 缺失(约定已立但无目标)→ 双双 skip', async () => {
|
|
85
|
+
await expectBoth(setupDir('no-dirs', { configYml: CTX_FILES(true) }), 'skip');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('enabled 但 required_dirs 为空数组 → 双双 skip', async () => {
|
|
89
|
+
await expectBoth(setupDir('empty-dirs', { configYml: CTX_FILES(true, []) }), 'skip');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('enabled 但 required_dirs 含非字符串项(脏配置)→ 双双 skip 而非抛错', async () => {
|
|
93
|
+
await expectBoth(
|
|
94
|
+
setupDir('dirty-dirs', {
|
|
95
|
+
configYml: 'governance:\n context_files:\n enabled: true\n required_dirs: [1, null]\n',
|
|
96
|
+
}),
|
|
97
|
+
'skip'
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('enabled 且非空 + CONTEXT.md 齐全 → 双双 pass(同一组 dirs 同一判定)', async () => {
|
|
102
|
+
await expectBoth(
|
|
103
|
+
setupDir('all-present', {
|
|
104
|
+
configYml: CTX_FILES(true, ['src', 'bin']),
|
|
105
|
+
contextMdDirs: ['src', 'bin'],
|
|
106
|
+
}),
|
|
107
|
+
true
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('enabled 且非空 + CONTEXT.md 缺失 → 双双 fail', async () => {
|
|
112
|
+
await expectBoth(
|
|
113
|
+
setupDir('missing-doc', { configYml: CTX_FILES(true, ['src', 'bin']) }),
|
|
114
|
+
false
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('docs_freshness 评估段 skip 行为变更(工单 84:约定已立但无目标不再静默放行)', () => {
|
|
120
|
+
it('doc_freshness.checks 已配 + enabled 但 required_dirs 缺失 → skip(原为 true)', async () => {
|
|
121
|
+
const dir = setupDir('checks-plus-empty', {
|
|
122
|
+
configYml:
|
|
123
|
+
'governance:\n doc_freshness:\n checks:\n - type: changelog_version\n context_files:\n enabled: true\n',
|
|
124
|
+
});
|
|
125
|
+
expect(await evalDocsFreshness(dir)).toBe('skip');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('enabled 但空 + CAPABILITIES.md 健康 → skip(原为 true)', async () => {
|
|
129
|
+
const dir = setupDir('caps-healthy', {
|
|
130
|
+
configYml: CTX_FILES(true),
|
|
131
|
+
files: ['src/module.ts'],
|
|
132
|
+
capabilitiesBody: `${TABLE_HEAD}| module | src/module.ts | module |`,
|
|
133
|
+
});
|
|
134
|
+
expect(await evalDocsFreshness(dir)).toBe('skip');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('enabled 但空 + CAPABILITIES.md 幽灵条目 → 仍 fail(Step 1 文件表判定不因 context_files 受影响)', async () => {
|
|
138
|
+
const dir = setupDir('caps-ghost', {
|
|
139
|
+
configYml: CTX_FILES(true),
|
|
140
|
+
files: ['src/old.ts'],
|
|
141
|
+
capabilitiesBody: `${TABLE_HEAD}| old | src/old.ts | 活 |\n| 遗魂 | src/gone/ | 已删 |`,
|
|
142
|
+
});
|
|
143
|
+
expect(await evalDocsFreshness(dir)).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* 1. Git diff 增量 — 当前变更的非测试文件是否在文档中有记录
|
|
6
6
|
* 2. 全量扫描 — 源码根下所有源文件是否都在 CAPABILITIES.md 中(T-058)
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* 覆盖/漏登判定不在本文件实现,统一走 capabilities-reconcile(ADR-0009):
|
|
9
|
+
* 目录条目(以 / 结尾)前缀匹配,文件条目精确匹配或路径边界后缀匹配;
|
|
10
|
+
* module 模式下目录条目参与覆盖,未覆盖文件按源码根下第一级子目录聚合。
|
|
11
11
|
*
|
|
12
12
|
* 清单格式(计数行,mode=listing 或嗅探命中)无文件表可核对,直接放行;
|
|
13
|
+
* 「有表格但零条目」不得放行,无表格的散文文档保持历史放行;
|
|
13
14
|
* 检查异常时 fail-open 但输出 console.warn 保留可观测性。
|
|
14
15
|
*
|
|
15
16
|
* ADR-0001 存在性探测:项目根无 CAPABILITIES.md(未采用该约定)时返回 'skip',
|
|
@@ -18,33 +19,12 @@
|
|
|
18
19
|
|
|
19
20
|
import { existsSync, readFileSync } from 'fs';
|
|
20
21
|
import { join } from 'path';
|
|
21
|
-
import {
|
|
22
|
-
aggregateToSourceSubdir,
|
|
23
|
-
isCapabilityListingFormat,
|
|
24
|
-
parseCapabilitiesEntries,
|
|
25
|
-
} from '../capabilities-parser';
|
|
22
|
+
import { isCapabilityListingFormat } from '../capabilities-parser';
|
|
26
23
|
import { getCapabilitiesMode } from '../../project-config-loader';
|
|
27
24
|
import { detectSourceRoots } from '../../../utils/detect-source-roots';
|
|
25
|
+
import { reconcileCapabilities, significantCodeChanges } from '../capabilities-reconcile';
|
|
28
26
|
import type { ConstraintCheck } from './types';
|
|
29
27
|
|
|
30
|
-
/** markdown 表格分隔行(|------|------|):区分「无表格的散文文档」与「有表格但零条目」 */
|
|
31
|
-
const TABLE_SEPARATOR_REGEX = /^\s*\|[\s:|-]+\|\s*$/m;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 变更文件是否被条目覆盖
|
|
35
|
-
*
|
|
36
|
-
* 目录条目(以 / 结尾)前缀匹配;文件条目精确匹配或路径边界后缀匹配
|
|
37
|
-
* (兼容 basename 条目,但拒绝 xfoo.ts 命中 foo.ts、docs/src/foo.tsx 命中 src/foo.ts
|
|
38
|
-
* 这类 endsWith/includes 模糊匹配造成的碰撞)
|
|
39
|
-
*/
|
|
40
|
-
function isCoveredBy(entries: string[], changed: string): boolean {
|
|
41
|
-
return entries.some((listed) =>
|
|
42
|
-
listed.endsWith('/')
|
|
43
|
-
? changed.startsWith(listed)
|
|
44
|
-
: changed === listed || changed.endsWith('/' + listed)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
28
|
export const capabilitySync: ConstraintCheck = {
|
|
49
29
|
id: 'capability_sync',
|
|
50
30
|
async evaluate(env) {
|
|
@@ -55,15 +35,6 @@ export const capabilitySync: ConstraintCheck = {
|
|
|
55
35
|
}
|
|
56
36
|
try {
|
|
57
37
|
const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
|
|
58
|
-
if (!existsSync(capabilitiesPath)) {
|
|
59
|
-
// 检查是否有代码变更,无变更则跳过
|
|
60
|
-
const diff = await env.stagedDiffNames();
|
|
61
|
-
const changedCodeFiles = diff.split('\n').filter(
|
|
62
|
-
(f: string) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js')
|
|
63
|
-
);
|
|
64
|
-
return changedCodeFiles.length === 0;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
38
|
const content = readFileSync(capabilitiesPath, 'utf-8');
|
|
68
39
|
const capabilitiesMode = getCapabilitiesMode(projectPath);
|
|
69
40
|
|
|
@@ -72,64 +43,34 @@ export const capabilitySync: ConstraintCheck = {
|
|
|
72
43
|
return true;
|
|
73
44
|
}
|
|
74
45
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const hasTable = TABLE_SEPARATOR_REGEX.test(content);
|
|
46
|
+
const sourceRoots = detectSourceRoots(projectPath);
|
|
47
|
+
const population: string[] = [];
|
|
48
|
+
for (const root of sourceRoots) {
|
|
49
|
+
if (existsSync(join(projectPath, root))) {
|
|
50
|
+
population.push(...env.srcScan(root));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
83
53
|
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
54
|
+
const diffNames = (await env.stagedDiffNames()).split('\n').filter(Boolean);
|
|
55
|
+
const verdict = reconcileCapabilities({
|
|
56
|
+
content,
|
|
57
|
+
populationFiles: population,
|
|
58
|
+
changedFiles: significantCodeChanges(diffNames),
|
|
59
|
+
sourceRoots,
|
|
60
|
+
});
|
|
92
61
|
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
)
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
62
|
+
// 零条目门槛:有表格但什么都没登记时不得直接放行
|
|
63
|
+
const gateOpen = verdict.coverageEntries.length === 0 && !verdict.hasTable;
|
|
64
|
+
if (gateOpen) return true;
|
|
65
|
+
|
|
66
|
+
// ── Step 1: Git diff 增量检查(每个变更文件都必须被覆盖)──
|
|
67
|
+
if (verdict.uncoveredChanges.length > 0) return false;
|
|
101
68
|
|
|
102
69
|
// ── Step 2: 全量源码根扫描(T-058 修复核心)──
|
|
103
70
|
if (capabilitiesMode === 'module') {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const uncoveredDirs = new Set<string>();
|
|
108
|
-
const sourceRoots = detectSourceRoots(projectPath);
|
|
109
|
-
for (const root of sourceRoots) {
|
|
110
|
-
const srcDir = join(projectPath, root);
|
|
111
|
-
if (existsSync(srcDir)) {
|
|
112
|
-
for (const file of env.srcScan(root)) {
|
|
113
|
-
if (!isCoveredBy(entries, file)) {
|
|
114
|
-
uncoveredDirs.add(aggregateToSourceSubdir(root, file));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (uncoveredDirs.size > 0) return false;
|
|
120
|
-
}
|
|
121
|
-
} else if (listedFiles.length > 0 || hasTable) {
|
|
122
|
-
const sourceRoots = detectSourceRoots(projectPath);
|
|
123
|
-
for (const root of sourceRoots) {
|
|
124
|
-
const srcDir = join(projectPath, root);
|
|
125
|
-
if (existsSync(srcDir)) {
|
|
126
|
-
for (const file of env.srcScan(root)) {
|
|
127
|
-
if (!isCoveredBy(listedFiles, file)) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
71
|
+
if (verdict.uncoveredDirs.length > 0) return false;
|
|
72
|
+
} else if (verdict.uncoveredFiles.length > 0) {
|
|
73
|
+
return false;
|
|
133
74
|
}
|
|
134
75
|
|
|
135
76
|
return true;
|
|
@@ -1,43 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* context_doc_sync:关键目录必须有 CONTEXT.md(工单 21)
|
|
3
3
|
*
|
|
4
|
-
* ADR-0001
|
|
5
|
-
*
|
|
4
|
+
* ADR-0001 存在性探测 + context_files 三态统一口径(工单 84):
|
|
5
|
+
* 未配置 / enabled 但无目标(required_dirs 缺失或空)→ 一律 'skip',
|
|
6
|
+
* 不计 pass/fail,与 docs_freshness 同构;判定只走 resolveContextFiles
|
|
7
|
+
* 访问器,不做 governance 手写钻取。
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { existsSync } from 'fs';
|
|
9
11
|
import { join } from 'path';
|
|
10
|
-
import {
|
|
12
|
+
import { resolveContextFiles } from '../../project-config-loader';
|
|
11
13
|
import type { ConstraintCheck } from './types';
|
|
12
14
|
|
|
13
15
|
export const contextDocSync: ConstraintCheck = {
|
|
14
16
|
id: 'context_doc_sync',
|
|
15
17
|
async evaluate(env) {
|
|
16
18
|
const projectPath = env.projectPath;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (!contextFiles?.enabled || !Array.isArray(contextFiles.required_dirs)) {
|
|
23
|
-
return 'skip'; // 未配置 context_files 约定,跳过评估
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const requiredDirs = contextFiles.required_dirs as string[];
|
|
27
|
-
if (requiredDirs.length === 0) {
|
|
28
|
-
return 'skip'; // 无目标目录,约定未生效
|
|
29
|
-
}
|
|
19
|
+
const resolution = resolveContextFiles(projectPath);
|
|
20
|
+
if (resolution.state !== 'enabled') {
|
|
21
|
+
return 'skip'; // 未配置或约定已立但无目标,跳过评估
|
|
22
|
+
}
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
24
|
+
for (const dir of resolution.dirs) {
|
|
25
|
+
const contextPath = join(projectPath, dir, 'CONTEXT.md');
|
|
26
|
+
if (!existsSync(contextPath)) {
|
|
27
|
+
return false;
|
|
36
28
|
}
|
|
37
|
-
|
|
38
|
-
return true;
|
|
39
|
-
} catch {
|
|
40
|
-
return 'skip'; // 配置不存在或解析失败 = 无法判定约定,跳过
|
|
41
29
|
}
|
|
30
|
+
|
|
31
|
+
return true;
|
|
42
32
|
},
|
|
43
33
|
};
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
import { existsSync, readFileSync } from 'fs';
|
|
11
11
|
import { join } from 'path';
|
|
12
|
-
import {
|
|
12
|
+
import { getGovernanceConfig, resolveContextFiles } from '../../project-config-loader';
|
|
13
13
|
import { FreshnessRunner, type FreshnessCheckResult } from '../doc-freshness/runner';
|
|
14
14
|
import { detectSourceRoots } from '../../../utils/detect-source-roots';
|
|
15
|
-
import
|
|
16
|
-
import type {
|
|
15
|
+
import { reconcileCapabilities } from '../capabilities-reconcile';
|
|
16
|
+
import type { DocFreshnessCheck } from '../../../types/project-config';
|
|
17
|
+
import type { ConstraintCheck, CheckEnv } from './types';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* 内置默认文档新鲜度检查配置
|
|
@@ -30,45 +31,31 @@ function getBuiltInDocFreshnessConfig(): DocFreshnessCheck[] {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
* CAPABILITIES.md
|
|
34
|
-
*
|
|
35
|
-
*
|
|
34
|
+
* CAPABILITIES.md 文件表新鲜度:登记的条目(文件与目录)必须仍存在(ADR-0009 口径从严)。
|
|
35
|
+
* 判定逻辑统一走 capabilities-reconcile;多根查找支持不同项目的源码根
|
|
36
|
+
* (harness=src/, studio=apps/api/src/ 等)。无表格(能力清单格式)时自然零幽灵。
|
|
36
37
|
*/
|
|
37
|
-
function
|
|
38
|
+
function findDeadCapabilityEntries(projectPath: string, env: CheckEnv): string[] {
|
|
38
39
|
try {
|
|
39
40
|
const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
|
|
40
|
-
if (!existsSync(capabilitiesPath)) return
|
|
41
|
+
if (!existsSync(capabilitiesPath)) return [];
|
|
41
42
|
const content = readFileSync(capabilitiesPath, 'utf-8');
|
|
42
43
|
|
|
43
|
-
const listedFiles: string[] = [];
|
|
44
|
-
const tableRowRegex = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/gm;
|
|
45
|
-
let match;
|
|
46
|
-
while ((match = tableRowRegex.exec(content)) !== null) {
|
|
47
|
-
listedFiles.push(match[1].trim());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (listedFiles.length === 0) return true;
|
|
51
|
-
|
|
52
44
|
const sourceRoots = detectSourceRoots(projectPath);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (existsSync(join(projectPath, root, file))) return true;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const missing = listedFiles.filter(f => !fileExists(f));
|
|
62
|
-
if (missing.length > 0) {
|
|
63
|
-
// 报出具体文件名:此前只返回 false,CLI 只能打印通用提示,
|
|
64
|
-
// 幽灵条目 basename 碰撞时 sync-docs 也不剔除,用户无从定位(2026-08-08 studio CI 4 连红)
|
|
65
|
-
console.error(`[docs_freshness] CAPABILITIES.md 列出的文件不存在: ${missing.join(', ')}`);
|
|
66
|
-
return false;
|
|
45
|
+
const population: string[] = [];
|
|
46
|
+
for (const root of sourceRoots) {
|
|
47
|
+
if (existsSync(join(projectPath, root))) population.push(...env.srcScan(root));
|
|
67
48
|
}
|
|
68
49
|
|
|
69
|
-
|
|
50
|
+
const verdict = reconcileCapabilities({
|
|
51
|
+
content,
|
|
52
|
+
populationFiles: population,
|
|
53
|
+
sourceRoots,
|
|
54
|
+
fileExists: (rel) => existsSync(join(projectPath, rel)),
|
|
55
|
+
});
|
|
56
|
+
return verdict.deadEntries;
|
|
70
57
|
} catch {
|
|
71
|
-
return
|
|
58
|
+
return [];
|
|
72
59
|
}
|
|
73
60
|
}
|
|
74
61
|
|
|
@@ -77,7 +64,7 @@ function checkCapabilitiesFreshness(projectPath: string): boolean {
|
|
|
77
64
|
*
|
|
78
65
|
* 判定信号(任一命中即视为采用了文档新鲜度约定):
|
|
79
66
|
* - 配置了 governance.doc_freshness.checks
|
|
80
|
-
* - 配置了 governance.context_files
|
|
67
|
+
* - 配置了 governance.context_files 且约定有效(enabled + 非空 required_dirs)
|
|
81
68
|
* - 项目根存在 CAPABILITIES.md
|
|
82
69
|
* - 项目根存在 CHANGELOG.md / CHANGELOG
|
|
83
70
|
*
|
|
@@ -89,26 +76,12 @@ function hasFreshnessTargets(projectPath: string): boolean {
|
|
|
89
76
|
return true;
|
|
90
77
|
}
|
|
91
78
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const freshnessConfig = governance?.doc_freshness as DocFreshnessConfig | undefined;
|
|
97
|
-
if (freshnessConfig?.checks && freshnessConfig.checks.length > 0) return true;
|
|
98
|
-
|
|
99
|
-
const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
|
|
100
|
-
if (
|
|
101
|
-
contextFiles?.enabled &&
|
|
102
|
-
Array.isArray(contextFiles.required_dirs) &&
|
|
103
|
-
(contextFiles.required_dirs as string[]).length > 0
|
|
104
|
-
) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// 配置不可读视为无配置
|
|
79
|
+
const governance = getGovernanceConfig(projectPath);
|
|
80
|
+
if (governance?.doc_freshness?.checks && governance.doc_freshness.checks.length > 0) {
|
|
81
|
+
return true;
|
|
109
82
|
}
|
|
110
83
|
|
|
111
|
-
return
|
|
84
|
+
return resolveContextFiles(projectPath).state === 'enabled';
|
|
112
85
|
}
|
|
113
86
|
|
|
114
87
|
export const docsFreshness: ConstraintCheck = {
|
|
@@ -119,26 +92,24 @@ export const docsFreshness: ConstraintCheck = {
|
|
|
119
92
|
// ADR-0001 存在性探测:项目无任何 freshness 配置/目标 → skip(不计 pass/fail)
|
|
120
93
|
if (!hasFreshnessTargets(projectPath)) return 'skip';
|
|
121
94
|
|
|
122
|
-
// Step 1: 文件表格式 —
|
|
123
|
-
|
|
95
|
+
// Step 1: 文件表格式 — 登记的条目(文件+目录)是否仍存在(ADR-0009)
|
|
96
|
+
const deadEntries = findDeadCapabilityEntries(projectPath, env);
|
|
97
|
+
if (deadEntries.length > 0) {
|
|
98
|
+
// 报出具体条目:此前只返回 false,CLI 只能打印通用提示,
|
|
99
|
+
// 幽灵条目 basename 碰撞时 sync-docs 也不剔除,用户无从定位(2026-08-08 studio CI 4 连红)
|
|
100
|
+
console.error(`[docs_freshness] CAPABILITIES.md 登记的条目不存在: ${deadEntries.join(', ')}`);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
124
103
|
|
|
125
104
|
// Step 2: 能力清单格式 + CLAUDE.md + CHANGELOG — 通过 FreshnessRunner
|
|
126
105
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
|
|
136
|
-
if (contextFiles?.enabled && Array.isArray(contextFiles.required_dirs)) {
|
|
137
|
-
requiredDirs = contextFiles.required_dirs as string[];
|
|
138
|
-
}
|
|
139
|
-
} catch {
|
|
140
|
-
// 配置解析失败,使用默认
|
|
141
|
-
}
|
|
106
|
+
const freshnessConfig = getGovernanceConfig(projectPath)?.doc_freshness;
|
|
107
|
+
|
|
108
|
+
// context_files 三态统一口径(工单 84):约定已立但无目标(enabled 但
|
|
109
|
+
// required_dirs 缺失/空)→ skip,与 context_doc_sync 同构;不再静默放行
|
|
110
|
+
const contextFiles = resolveContextFiles(projectPath);
|
|
111
|
+
if (contextFiles.state === 'enabled-empty') return 'skip';
|
|
112
|
+
const requiredDirs = contextFiles.state === 'enabled' ? contextFiles.dirs : undefined;
|
|
142
113
|
|
|
143
114
|
const runner = new FreshnessRunner();
|
|
144
115
|
let results: FreshnessCheckResult[];
|
|
@@ -10,42 +10,24 @@
|
|
|
10
10
|
* 不强制迁移;两处都没有才报违规。
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readFileSync } from 'fs';
|
|
14
13
|
import { join } from 'path';
|
|
15
14
|
import { loadRawProjectConfig } from '../../project-config-loader';
|
|
15
|
+
import { hasGovernanceContract, hasPreserveBlock, readIfExists } from '../injection-writer';
|
|
16
16
|
import type { ConstraintCheck } from './types';
|
|
17
17
|
|
|
18
18
|
/** 治理契约 PRESERVE 段名(ADR 落点模型约定) */
|
|
19
19
|
export const GOVERNANCE_PRESERVE_NAME = 'governance';
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/** AGENTS.md 是否存在非空 PRESERVE:governance 块(标记须独占一行,与 preserve-block.ts 同语义) */
|
|
21
|
+
/** AGENTS.md 是否存在非空 PRESERVE:governance 块(切片判定收口 injection-writer.hasPreserveBlock,#83) */
|
|
24
22
|
export function hasGovernancePreserveBlock(agentsMdPath: string): boolean {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
content = readFileSync(agentsMdPath, 'utf-8');
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
const beginMatch = GOVERNANCE_BEGIN_RE.exec(content);
|
|
32
|
-
if (!beginMatch) return false;
|
|
33
|
-
const rest = content.slice(beginMatch.index + beginMatch[0].length);
|
|
34
|
-
const endIdx = rest.indexOf(`<!-- /PRESERVE:${GOVERNANCE_PRESERVE_NAME} -->`);
|
|
35
|
-
if (endIdx === -1) return false;
|
|
36
|
-
// 块体(首尾标记之间)去空白后非空才算「在场」
|
|
37
|
-
return rest.slice(0, endIdx).trim().length > 0;
|
|
23
|
+
const content = readIfExists(agentsMdPath);
|
|
24
|
+
return content !== null && hasPreserveBlock(content, GOVERNANCE_PRESERVE_NAME);
|
|
38
25
|
}
|
|
39
26
|
|
|
40
|
-
/** CLAUDE.md
|
|
27
|
+
/** CLAUDE.md 是否有治理契约在场(判定收口 injection-writer.hasGovernanceContract,#83;旧模型仓豁免) */
|
|
41
28
|
export function hasClaudeGovernance(claudeMdPath: string): boolean {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
content = readFileSync(claudeMdPath, 'utf-8');
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return /^##\s+Governance Rules/m.test(content) || content.includes('HARNESS_CONSTRAINTS_START');
|
|
29
|
+
const content = readIfExists(claudeMdPath);
|
|
30
|
+
return content !== null && hasGovernanceContract(content);
|
|
49
31
|
}
|
|
50
32
|
|
|
51
33
|
export const governancePresence: ConstraintCheck = {
|