@dommaker/harness 1.3.0 → 1.5.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 +20 -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 +104 -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 +27 -219
- 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 +31 -25
- 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 +17 -30
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +183 -273
- 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 +69 -59
- 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 +5 -2
- 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 +9 -3
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +56 -61
- 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/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 +68 -117
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +66 -77
- 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 +49 -66
- 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/index.d.ts +2 -2
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +2 -1
- package/dist/core/constraints/checkers/index.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 +43 -4
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +33 -0
- package/dist/core/constraints/checkers/types.js.map +1 -1
- 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 +6 -0
- package/dist/failure/recorder.d.ts.map +1 -1
- package/dist/failure/recorder.js +12 -8
- 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 +2 -1
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +11 -13
- 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 +1 -2
- package/dist/index.d.ts.map +1 -1
- 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 +17 -14
- 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 +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -5
- package/dist/release/index.js.map +1 -1
- 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 +8 -18
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +6 -1
- package/dist/types/constraint.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/types/trace.d.ts +9 -0
- package/dist/types/trace.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 +8 -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__/layering.test.ts +152 -0
- package/src/__tests__/passes-gate-extra.test.ts +0 -145
- package/src/__tests__/passes-gate.test.ts +130 -101
- 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 +23 -8
- 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 +107 -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 +448 -378
- 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 +69 -43
- 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 +231 -0
- package/src/cli/commands/__tests__/registry.test.ts +75 -35
- package/src/cli/commands/__tests__/release.test.ts +209 -80
- 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 +77 -78
- package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
- package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
- 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 +127 -66
- 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 +34 -227
- package/src/cli/commands/failure.ts +33 -26
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +192 -289
- 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 +70 -59
- 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 +5 -2
- 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 +64 -61
- 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/context/session-manager.ts +19 -33
- package/src/core/CONTEXT.md +10 -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 +82 -133
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
- package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -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 +153 -0
- package/src/core/constraints/checkers/capability-sync.ts +75 -96
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +54 -70
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/index.ts +9 -2
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +60 -4
- 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 +12 -10
- package/src/gates/CONTEXT.md +7 -4
- 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__/checker-gate.test.ts +24 -0
- 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 +12 -15
- 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 +0 -4
- 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 +53 -0
- 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 +19 -14
- 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 +1 -0
- package/src/release/__tests__/barrel.test.ts +60 -0
- package/src/release/index.ts +2 -13
- 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 +16 -27
- 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/types/trace.ts +10 -0
- 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
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
|
+
import { captureIO, type CapturingIO } from '../../command-contract';
|
|
6
7
|
import * as path from 'path';
|
|
7
8
|
|
|
9
|
+
let io: CapturingIO;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
io = captureIO();
|
|
12
|
+
});
|
|
13
|
+
|
|
8
14
|
describe('postevalPlan', () => {
|
|
9
15
|
jest.setTimeout(30000); // Retry-based tests with exponential backoff need longer timeout
|
|
10
16
|
const tempDir = path.join(process.cwd(), 'temp-test-posteval');
|
|
11
17
|
const planPath = path.join(tempDir, 'plan.md');
|
|
12
|
-
let consoleErrorSpy: jest.SpyInstance;
|
|
13
|
-
let consoleLogSpy: jest.SpyInstance;
|
|
14
|
-
let mockExit: jest.SpyInstance;
|
|
15
18
|
let originalFetch: typeof fetch;
|
|
16
19
|
let originalEnv: NodeJS.ProcessEnv;
|
|
17
20
|
|
|
@@ -34,19 +37,11 @@ describe('postevalPlan', () => {
|
|
|
34
37
|
originalEnv = { ...process.env };
|
|
35
38
|
delete process.env.API_PORT;
|
|
36
39
|
delete process.env.POSTEVAL_GRACE_MS;
|
|
37
|
-
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
38
|
-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
39
|
-
mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
40
|
-
// Don't actually exit
|
|
41
|
-
}) as any);
|
|
42
40
|
});
|
|
43
41
|
|
|
44
42
|
afterEach(() => {
|
|
45
43
|
global.fetch = originalFetch;
|
|
46
44
|
process.env = originalEnv;
|
|
47
|
-
consoleErrorSpy.mockRestore();
|
|
48
|
-
consoleLogSpy.mockRestore();
|
|
49
|
-
mockExit.mockRestore();
|
|
50
45
|
jest.useRealTimers();
|
|
51
46
|
});
|
|
52
47
|
|
|
@@ -61,12 +56,12 @@ describe('postevalPlan', () => {
|
|
|
61
56
|
}) as any;
|
|
62
57
|
|
|
63
58
|
const { postevalPlan } = await import('../posteval-plan');
|
|
64
|
-
await postevalPlan({ planPath });
|
|
59
|
+
await postevalPlan({ planPath }, io);
|
|
65
60
|
|
|
66
|
-
expect(
|
|
61
|
+
expect(io.outText()).toContain('100%');
|
|
67
62
|
});
|
|
68
63
|
|
|
69
|
-
it('completeness < 1
|
|
64
|
+
it('completeness < 1:fail(覆盖率不足,含缺失项)', async () => {
|
|
70
65
|
global.fetch = jest.fn().mockResolvedValue({
|
|
71
66
|
ok: true,
|
|
72
67
|
json: () => Promise.resolve({
|
|
@@ -77,10 +72,10 @@ describe('postevalPlan', () => {
|
|
|
77
72
|
}) as any;
|
|
78
73
|
|
|
79
74
|
const { postevalPlan } = await import('../posteval-plan');
|
|
80
|
-
await postevalPlan({ planPath });
|
|
75
|
+
const result = await postevalPlan({ planPath }, io);
|
|
81
76
|
|
|
82
|
-
expect(
|
|
83
|
-
expect(
|
|
77
|
+
expect(result).toEqual({ kind: 'fail', reason: expect.stringContaining('plan coverage 50% < 100%') });
|
|
78
|
+
expect(io.errText()).toContain('50%');
|
|
84
79
|
});
|
|
85
80
|
|
|
86
81
|
it('completeness < 1 时应该列出缺失项', async () => {
|
|
@@ -94,10 +89,13 @@ describe('postevalPlan', () => {
|
|
|
94
89
|
}) as any;
|
|
95
90
|
|
|
96
91
|
const { postevalPlan } = await import('../posteval-plan');
|
|
97
|
-
await postevalPlan({ planPath });
|
|
92
|
+
const result = await postevalPlan({ planPath }, io);
|
|
98
93
|
|
|
99
|
-
expect(
|
|
100
|
-
|
|
94
|
+
expect(result).toEqual({
|
|
95
|
+
kind: 'fail',
|
|
96
|
+
reason: 'plan coverage 33% < 100%,缺 2 项: AC-002; AC-003',
|
|
97
|
+
});
|
|
98
|
+
expect(io.errText()).toContain('AC-002');
|
|
101
99
|
});
|
|
102
100
|
|
|
103
101
|
it('4xx 错误应该 exit(1)', async () => {
|
|
@@ -108,13 +106,13 @@ describe('postevalPlan', () => {
|
|
|
108
106
|
}) as any;
|
|
109
107
|
|
|
110
108
|
const { postevalPlan } = await import('../posteval-plan');
|
|
111
|
-
await postevalPlan({ planPath });
|
|
109
|
+
const result = await postevalPlan({ planPath }, io);
|
|
112
110
|
|
|
113
|
-
expect(
|
|
114
|
-
expect(
|
|
111
|
+
expect(result).toEqual({ kind: 'fail', reason: 'PostEval API error: 400 Bad Request' });
|
|
112
|
+
expect(io.errText()).toContain('400');
|
|
115
113
|
});
|
|
116
114
|
|
|
117
|
-
it('5xx
|
|
115
|
+
it('5xx 错误:skip(未判定,允许提交;退出码面 0 不变)', async () => {
|
|
118
116
|
global.fetch = jest.fn().mockResolvedValue({
|
|
119
117
|
ok: false,
|
|
120
118
|
status: 503,
|
|
@@ -122,20 +120,20 @@ describe('postevalPlan', () => {
|
|
|
122
120
|
}) as any;
|
|
123
121
|
|
|
124
122
|
const { postevalPlan } = await import('../posteval-plan');
|
|
125
|
-
await postevalPlan({ planPath });
|
|
123
|
+
const result = await postevalPlan({ planPath }, io);
|
|
126
124
|
|
|
127
|
-
expect(
|
|
128
|
-
expect(
|
|
125
|
+
expect(result).toEqual({ kind: 'skip', reason: expect.stringContaining('服务端错误 503') });
|
|
126
|
+
expect(io.errText()).toContain('unavailable');
|
|
129
127
|
});
|
|
130
128
|
|
|
131
|
-
it('
|
|
129
|
+
it('网络错误重试耗尽:skip(未判定,允许提交)', async () => {
|
|
132
130
|
global.fetch = jest.fn().mockRejectedValue(new Error('ECONNREFUSED'));
|
|
133
131
|
|
|
134
132
|
const { postevalPlan } = await import('../posteval-plan');
|
|
135
|
-
await postevalPlan({ planPath });
|
|
133
|
+
const result = await postevalPlan({ planPath }, io);
|
|
136
134
|
|
|
137
|
-
expect(
|
|
138
|
-
expect(
|
|
135
|
+
expect(result).toEqual({ kind: 'skip', reason: expect.stringContaining('Studio API 不可达') });
|
|
136
|
+
expect(io.errText()).toContain('unreachable');
|
|
139
137
|
});
|
|
140
138
|
|
|
141
139
|
it('应该支持自定义 API_PORT', async () => {
|
|
@@ -150,7 +148,7 @@ describe('postevalPlan', () => {
|
|
|
150
148
|
}) as any;
|
|
151
149
|
|
|
152
150
|
const { postevalPlan } = await import('../posteval-plan');
|
|
153
|
-
await postevalPlan({ planPath });
|
|
151
|
+
await postevalPlan({ planPath }, io);
|
|
154
152
|
|
|
155
153
|
// Verify the fetch was called with port 3999
|
|
156
154
|
const fetchCall = (global.fetch as jest.Mock).mock.calls[0][0];
|
|
@@ -174,12 +172,12 @@ describe('postevalPlan', () => {
|
|
|
174
172
|
global.fetch = mockFetch as any;
|
|
175
173
|
|
|
176
174
|
const { postevalPlan } = await import('../posteval-plan');
|
|
177
|
-
await postevalPlan({ planPath });
|
|
175
|
+
const result = await postevalPlan({ planPath }, io);
|
|
178
176
|
|
|
179
177
|
// Should have been called 3 times
|
|
180
178
|
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
181
|
-
expect(
|
|
182
|
-
expect(
|
|
179
|
+
expect(io.outText()).toContain('100%');
|
|
180
|
+
expect(result.kind).toBe('ok');
|
|
183
181
|
});
|
|
184
182
|
|
|
185
183
|
it('completeness 为 0 时应该正确显示 0%', async () => {
|
|
@@ -193,9 +191,12 @@ describe('postevalPlan', () => {
|
|
|
193
191
|
}) as any;
|
|
194
192
|
|
|
195
193
|
const { postevalPlan } = await import('../posteval-plan');
|
|
196
|
-
await postevalPlan({ planPath });
|
|
194
|
+
const result = await postevalPlan({ planPath }, io);
|
|
197
195
|
|
|
198
|
-
expect(
|
|
199
|
-
|
|
196
|
+
expect(result).toEqual({
|
|
197
|
+
kind: 'fail',
|
|
198
|
+
reason: 'plan coverage 0% < 100%,缺 1 项: AC-001',
|
|
199
|
+
});
|
|
200
|
+
expect(io.errText()).toContain('0%');
|
|
200
201
|
});
|
|
201
202
|
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* -p/--project-path 锚定回归(harness#95)
|
|
3
|
+
*
|
|
4
|
+
* 两条门禁命令都接受 -p,但真正执行/IO 的一侧过去取 process.cwd():不 cd 到目标工程调用,
|
|
5
|
+
* 就会拿 A 工程的命令、在 B 目录跑、把证据写进 B;acceptance 的「无 tasks.yml 即跳过」
|
|
6
|
+
* 本身是 passed:true,于是 -p 失效直接表现为假绿。
|
|
7
|
+
*
|
|
8
|
+
* 既有单测全部 mock fs/exec + 假 projectPath,恰好抹平两种取径的差异。本文件不 mock 任何 IO,
|
|
9
|
+
* 前提统一为 **cwd ≠ projectPath**(cwd = A,-p = B),断言读写位置落在 B。
|
|
10
|
+
* 站点 2 从两面各断言一次:CLI 命令面(`acceptance -p`)与门禁实例面(默认构造 = 注册表单例形状)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { createProjectFixture } from '../../../test-setup/project-fixture';
|
|
16
|
+
import { SpecAcceptanceGate } from '../../../gates/acceptance';
|
|
17
|
+
import { captureIO } from '../../command-contract';
|
|
18
|
+
import { runPassesGate } from '../passes-gate';
|
|
19
|
+
import { acceptance } from '../acceptance';
|
|
20
|
+
|
|
21
|
+
/** 在自身 cwd 落标记文件:哪一侧被真正调用,标记就出现在哪一侧的目录里 */
|
|
22
|
+
function markScript(marker: string): string {
|
|
23
|
+
return [
|
|
24
|
+
'const fs = require("fs");',
|
|
25
|
+
`fs.writeFileSync("${marker}-exec-location.txt", process.cwd());`,
|
|
26
|
+
'console.log("1 passed");',
|
|
27
|
+
'',
|
|
28
|
+
].join('\n');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const PACKAGE_JSON = JSON.stringify({
|
|
32
|
+
name: 'fixture',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
scripts: { test: 'node ./mark.js' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/** acceptance_criteria 形状:checked 决定判定,两侧只差 checked 值 → 读错文件必然改变结论 */
|
|
38
|
+
function tasksYml(checked: boolean): string {
|
|
39
|
+
return [
|
|
40
|
+
'tasks:',
|
|
41
|
+
' - id: TASK-001',
|
|
42
|
+
' title: 锚定用例',
|
|
43
|
+
' acceptance_criteria:',
|
|
44
|
+
' - id: crit-1',
|
|
45
|
+
' description: 需要人工确认的验收条件',
|
|
46
|
+
' type: manual',
|
|
47
|
+
' required: true',
|
|
48
|
+
` checked: ${checked}`,
|
|
49
|
+
'',
|
|
50
|
+
].join('\n');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** passes-gate 两侧夹具:A = 调用方所在目录(cwd),B = -p 指向的目标工程 */
|
|
54
|
+
function createPassesGateSides(): { cwdSide: string; projectSide: string } {
|
|
55
|
+
return {
|
|
56
|
+
cwdSide: createProjectFixture({
|
|
57
|
+
name: 'pganchor-cwd-side',
|
|
58
|
+
files: { 'package.json': PACKAGE_JSON, 'mark.js': markScript('cwd-side') },
|
|
59
|
+
}),
|
|
60
|
+
projectSide: createProjectFixture({
|
|
61
|
+
name: 'pganchor-project-side',
|
|
62
|
+
files: { 'package.json': PACKAGE_JSON, 'mark.js': markScript('project-side') },
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe('-p 锚定:执行与 IO 必须落在 projectPath(cwd ≠ projectPath)', () => {
|
|
68
|
+
const originalCwd = process.cwd();
|
|
69
|
+
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
process.chdir(originalCwd);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('passes-gate(站点 1:执行 + 证据落盘)', () => {
|
|
75
|
+
it('-p 指向 B → B 的 package.json 测试命令在 B 执行,证据落 B/.harness/evidence', async () => {
|
|
76
|
+
const { cwdSide, projectSide } = createPassesGateSides();
|
|
77
|
+
process.chdir(cwdSide);
|
|
78
|
+
|
|
79
|
+
const result = await runPassesGate({ projectPath: projectSide }, captureIO());
|
|
80
|
+
|
|
81
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
82
|
+
expect(fs.readFileSync(path.join(projectSide, 'project-side-exec-location.txt'), 'utf-8'))
|
|
83
|
+
.toBe(projectSide);
|
|
84
|
+
// 跑在 B 的判据同时要求 A 侧什么都没被执行、没被写入
|
|
85
|
+
expect(fs.existsSync(path.join(cwdSide, 'cwd-side-exec-location.txt'))).toBe(false);
|
|
86
|
+
expect(fs.existsSync(path.join(cwdSide, '.harness', 'evidence'))).toBe(false);
|
|
87
|
+
|
|
88
|
+
const evidenceDir = path.join(projectSide, '.harness', 'evidence');
|
|
89
|
+
expect(fs.existsSync(evidenceDir)).toBe(true);
|
|
90
|
+
expect(fs.readdirSync(evidenceDir).filter(f => f.startsWith('test-'))).toHaveLength(1);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('acceptance(站点 2:tasks.yml 解析)', () => {
|
|
95
|
+
it('默认构造的门禁实例(registry / getEffectiveGates 形状)→ 读 B/tasks.yml,不读 cwd 的', async () => {
|
|
96
|
+
const cwdSide = createProjectFixture({
|
|
97
|
+
name: 'acccfg-cwd-side',
|
|
98
|
+
files: { 'tasks.yml': tasksYml(true) },
|
|
99
|
+
});
|
|
100
|
+
const projectSide = createProjectFixture({
|
|
101
|
+
name: 'acccfg-project-side',
|
|
102
|
+
files: { 'tasks.yml': tasksYml(false) },
|
|
103
|
+
});
|
|
104
|
+
process.chdir(cwdSide);
|
|
105
|
+
|
|
106
|
+
// 无 config 构造 = 注册表单例的形状(./tasks.yml 相对默认值在这一支按 cwd 解析)
|
|
107
|
+
const result = await new SpecAcceptanceGate().check({
|
|
108
|
+
projectPath: projectSide,
|
|
109
|
+
taskId: 'TASK-001',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(result.passed).toBe(false);
|
|
113
|
+
expect(result.message).toContain('1 unchecked acceptance criteria');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('-p 指向 B → 读 B/tasks.yml,不因 cwd 无文件而假绿', async () => {
|
|
117
|
+
const cwdSide = createProjectFixture({
|
|
118
|
+
name: 'accanchor-cwd-side',
|
|
119
|
+
files: { 'tasks.yml': tasksYml(true) },
|
|
120
|
+
});
|
|
121
|
+
const projectSide = createProjectFixture({
|
|
122
|
+
name: 'accanchor-project-side',
|
|
123
|
+
files: { 'tasks.yml': tasksYml(false) },
|
|
124
|
+
});
|
|
125
|
+
process.chdir(cwdSide);
|
|
126
|
+
|
|
127
|
+
const result = await acceptance({ projectPath: projectSide, taskId: 'TASK-001' }, captureIO());
|
|
128
|
+
|
|
129
|
+
expect(result).toEqual({
|
|
130
|
+
kind: 'fail',
|
|
131
|
+
reason: expect.stringContaining('1 unchecked acceptance criteria'),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('--tasks-path 相对路径按 projectPath 解析,不按 cwd', async () => {
|
|
136
|
+
const cwdSide = createProjectFixture({
|
|
137
|
+
name: 'accanchorrel-cwd-side',
|
|
138
|
+
files: { 'config/tasks.yml': tasksYml(true) },
|
|
139
|
+
});
|
|
140
|
+
const projectSide = createProjectFixture({
|
|
141
|
+
name: 'accanchorrel-project-side',
|
|
142
|
+
files: { 'config/tasks.yml': tasksYml(false) },
|
|
143
|
+
});
|
|
144
|
+
process.chdir(cwdSide);
|
|
145
|
+
|
|
146
|
+
const result = await acceptance(
|
|
147
|
+
{ projectPath: projectSide, taskId: 'TASK-001', tasksPath: 'config/tasks.yml' },
|
|
148
|
+
captureIO(),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(result).toEqual({
|
|
152
|
+
kind: 'fail',
|
|
153
|
+
reason: expect.stringContaining('1 unchecked acceptance criteria'),
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* projectPath 传递约定守护(harness#95)
|
|
3
|
+
*
|
|
4
|
+
* 约定(正本见本目录 CONTEXT.md「约定」段):**projectPath 只在 CLI 入口做一次 `|| process.cwd()`
|
|
5
|
+
* 兜底,之后必须传到每个 IO/执行点**——下游禁止再取一次 cwd,也禁止用相对路径默认值
|
|
6
|
+
* (两者都会让 `-p` 半失效:读写/执行位置悄悄回到调用方的 cwd)。
|
|
7
|
+
*
|
|
8
|
+
* 本文件是这条约定的机器可检面,三道闸:
|
|
9
|
+
* 1. CLI 入口层:cwd 只能以 `xxx || process.cwd()` 的兜底形状出现,例外逐个点名并记理由
|
|
10
|
+
* 2. 下游层(= src 减 cli,含 core / gates / context / monitoring / hooks 等):cwd 站点**逐行**冻结
|
|
11
|
+
* (harness#98,不再只冻文件键集——豁免文件内新增站点/行变形同样失败),
|
|
12
|
+
* 要么把根传下去,要么在此记下豁免理由
|
|
13
|
+
* 3. 相对路径默认值同理冻结(harness#98 收紧:对象字面量 `xxxPath: '相对'` 之外,
|
|
14
|
+
* 参数默认值形 `xxxPath = '相对'`(含类型标注)与模板字面量同罪;扫描域 = 整个下游层)
|
|
15
|
+
*
|
|
16
|
+
* 冻结集合还要求**每条豁免仍然成立**(站点消失却不删条目 → 同样失败),豁免不会烂成化石。
|
|
17
|
+
* 「根参数已传入却又取 cwd」这类静态看不出的漂移,由 project-path-anchoring.test.ts 的真实 IO 行为用例守。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as fs from 'fs';
|
|
21
|
+
import * as path from 'path';
|
|
22
|
+
|
|
23
|
+
const SRC_ROOT = path.join(__dirname, '..', '..', '..', '..', 'src');
|
|
24
|
+
|
|
25
|
+
/** 注释行不参与匹配:文档里「缺省 process.cwd()」这类描述不是站点 */
|
|
26
|
+
function codeLines(file: string): string[] {
|
|
27
|
+
return fs
|
|
28
|
+
.readFileSync(file, 'utf-8')
|
|
29
|
+
.split('\n')
|
|
30
|
+
.map(line => line.trim())
|
|
31
|
+
.filter(line => !line.startsWith('*') && !line.startsWith('//') && !line.startsWith('/*'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function listTsFiles(dir: string, skipDirs: string[] = []): string[] {
|
|
35
|
+
const found: string[] = [];
|
|
36
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
37
|
+
const full = path.join(dir, entry.name);
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
if (entry.name === '__tests__' || skipDirs.includes(entry.name)) continue;
|
|
40
|
+
found.push(...listTsFiles(full, skipDirs));
|
|
41
|
+
} else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {
|
|
42
|
+
found.push(full);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return found.sort();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 仓库相对路径(豁免表以此为准,跨机器稳定) */
|
|
49
|
+
function repoPath(abs: string): string {
|
|
50
|
+
return path.relative(path.join(SRC_ROOT, '..'), abs).split(path.sep).join('/');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function cwdSites(files: string[]): Map<string, string[]> {
|
|
54
|
+
const sites = new Map<string, string[]>();
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const lines = codeLines(file).filter(line => line.includes('process.cwd()'));
|
|
57
|
+
if (lines.length > 0) sites.set(repoPath(file), lines);
|
|
58
|
+
}
|
|
59
|
+
return sites;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ========================================
|
|
63
|
+
// 闸 1:CLI 入口层的非兜底形状 cwd
|
|
64
|
+
// ========================================
|
|
65
|
+
|
|
66
|
+
/** CLI 层的合法形状:入口对 `-p/--project-path` 做一次性兜底 */
|
|
67
|
+
const ENTRY_FALLBACK_SHAPE = /\|\|\s*process\.cwd\(\)/;
|
|
68
|
+
|
|
69
|
+
/** 兜底形状之外的 CLI cwd 站点:逐个裁决过,理由与站点原文一起冻结 */
|
|
70
|
+
const CLI_CWD_EXEMPTIONS: Record<string, { lines: string[]; reason: string }> = {
|
|
71
|
+
'src/cli/commands/release.ts': {
|
|
72
|
+
lines: ['const pkgPath = process.cwd();'],
|
|
73
|
+
reason:
|
|
74
|
+
'release 定义表里没有 -p/--project-path(只收 --bump/--dry-run),pkgPath 就是该命令唯一的根,' +
|
|
75
|
+
'且已逐个传给每条 run(cmd, pkgPath) 与 verifyReleaseArtifacts(pkgPath)——不构成 -p 半失效。' +
|
|
76
|
+
'给发布流水线新增 -p 属新能力(可指向任意目录做 push/publish),不在 #95 范围。',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// ========================================
|
|
81
|
+
// 闸 2:下游层的 cwd 站点
|
|
82
|
+
// ========================================
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 下游豁免的共同理由:这些是**库层公开 API 的可选根参数默认值**(调用方没给根时的缺省),
|
|
86
|
+
* 不是「根已经传进来了,取 IO 时又绕回 cwd」。core 不能 import cli,兜底只能留在各自入口,
|
|
87
|
+
* 故冻结而非删除;新增站点必须在此逐个点名并单独说明。
|
|
88
|
+
*
|
|
89
|
+
* harness#98:冻结粒度从文件键集收紧到**行内容**——已豁免文件内悄悄新增 cwd 站点
|
|
90
|
+
* (不动键集)曾是绕过通道,现在新增行/行变形都会顶失败。
|
|
91
|
+
*/
|
|
92
|
+
const DOWNSTREAM_CWD_EXEMPTIONS: Record<string, { lines: string[]; reason: string }> = {
|
|
93
|
+
'src/context/session-manager.ts': {
|
|
94
|
+
lines: ['this.basePath = basePath || process.cwd();'],
|
|
95
|
+
reason: '构造参数 basePath 缺省(会话存储根,CLI 已显式传 projectPath)',
|
|
96
|
+
},
|
|
97
|
+
'src/core/constraints/checker.ts': {
|
|
98
|
+
lines: [
|
|
99
|
+
'const projectPath = context.projectPath || process.cwd();',
|
|
100
|
+
'const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());',
|
|
101
|
+
'const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());',
|
|
102
|
+
],
|
|
103
|
+
reason: 'check 上下文缺 projectPath 时的根兜底(3 处同一形状)',
|
|
104
|
+
},
|
|
105
|
+
'src/core/constraints/checkers/types.ts': {
|
|
106
|
+
lines: ['const projectPath = context.projectPath || process.cwd();'],
|
|
107
|
+
reason: 'checker 环境的根兜底(context.projectPath 可选)',
|
|
108
|
+
},
|
|
109
|
+
'src/core/constraints/context-builder.ts': {
|
|
110
|
+
lines: [
|
|
111
|
+
'const projectPath = options.projectPath || process.cwd();',
|
|
112
|
+
'const projectPath = options.projectPath || process.cwd();',
|
|
113
|
+
],
|
|
114
|
+
reason: 'buildCheckEnv 的 options.projectPath 缺省兜底(2 处)',
|
|
115
|
+
},
|
|
116
|
+
'src/core/constraints/usage-report.ts': {
|
|
117
|
+
lines: ['projectRoot: string = process.cwd(),'],
|
|
118
|
+
reason: 'projectRoot 形参默认值(库层可选根)',
|
|
119
|
+
},
|
|
120
|
+
'src/core/effective-constraints.ts': {
|
|
121
|
+
lines: [
|
|
122
|
+
'projectRoot: string = process.cwd(),',
|
|
123
|
+
'projectRoot: string = process.cwd(),',
|
|
124
|
+
'export function lintEffectiveConfig(projectRoot: string = process.cwd()): EffectiveConfigLint {',
|
|
125
|
+
],
|
|
126
|
+
reason: '生效集三函数 projectRoot 形参默认值(库层可选根,JSDoc 已声明)',
|
|
127
|
+
},
|
|
128
|
+
'src/core/project-config-loader.ts': {
|
|
129
|
+
lines: ['this.projectPath = projectPath || process.cwd();'],
|
|
130
|
+
reason: 'config 加载器 projectPath 构造参数缺省兜底',
|
|
131
|
+
},
|
|
132
|
+
'src/core/spec/validator.ts': {
|
|
133
|
+
lines: ['const cwd = projectPath || process.cwd();'],
|
|
134
|
+
reason: 'validateAll 的可选 projectPath 兜底(其相对 schemaPath 默认值见闸 3 豁免)',
|
|
135
|
+
},
|
|
136
|
+
'src/gates/checker-gate.ts': {
|
|
137
|
+
lines: ['const projectPath = ctx.projectPath || process.cwd();'],
|
|
138
|
+
reason: 'GateContext.projectPath 缺省兜底(门禁适配器的根入口)',
|
|
139
|
+
},
|
|
140
|
+
'src/gates/effective-gates.ts': {
|
|
141
|
+
lines: ['export function getEffectiveGates(projectRoot: string = process.cwd()): Gate[] {'],
|
|
142
|
+
reason: 'projectRoot 形参默认值(库层可选根)',
|
|
143
|
+
},
|
|
144
|
+
'src/hooks/bootstrap.ts': {
|
|
145
|
+
lines: [
|
|
146
|
+
'const resolvedPath = projectPath || process.cwd();',
|
|
147
|
+
'const resolvedPath = projectPath || process.cwd();',
|
|
148
|
+
],
|
|
149
|
+
reason: 'bootstrapHarness 的可选 projectPath 兜底(组合根入口,2 处)',
|
|
150
|
+
},
|
|
151
|
+
'src/monitoring/context-tracker.ts': {
|
|
152
|
+
lines: ['const base = basePath || process.cwd();'],
|
|
153
|
+
reason: 'basePath 构造参数缺省兜底',
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// ========================================
|
|
158
|
+
// 闸 3:下游层的相对路径默认值
|
|
159
|
+
// ========================================
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* key 必须 camelCase 以 Path 结尾,值为相对字面量——这类默认值按 cwd 解析,即 #95 的病根形状。
|
|
163
|
+
* harness#98 收紧匹配形状(原为只认对象字面量 `xxxPath: '相对'`):
|
|
164
|
+
* 参数默认值形 `xxxPath = '相对'`、带类型标注的 `xxxPath: string = '相对'`、模板字面量、
|
|
165
|
+
* 双引号形同罪(仓内 lint 不强制引号风格,三种引号都得认)。
|
|
166
|
+
*/
|
|
167
|
+
const RELATIVE_PATH_DEFAULT = /\b\w+Path\s*(?::\s*[^=,)]+?)?[:=]\s*['"`](?!\/)/;
|
|
168
|
+
|
|
169
|
+
const RELATIVE_PATH_DEFAULT_EXEMPTIONS: Record<string, string> = {
|
|
170
|
+
'src/core/spec/validator.ts':
|
|
171
|
+
'schemaPath: "./specs/schemas" 确实按 cwd 解析(同型病灶)。不随 #95 修:validateFile()/loadSchema() ' +
|
|
172
|
+
'签名里没有根,补齐要把根穿透整个 spec 域(属 spec 重构,非本票两门禁)。CLI 侧 `spec -s` 已 ' +
|
|
173
|
+
'path.resolve(projectPath, schema),给了 -s 时口径正确。留待 spec 域单票收口。',
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
describe('projectPath 传递约定(harness#95)', () => {
|
|
177
|
+
const cliFiles = listTsFiles(path.join(SRC_ROOT, 'cli'));
|
|
178
|
+
const downstreamFiles = listTsFiles(SRC_ROOT).filter(f => !f.startsWith(path.join(SRC_ROOT, 'cli')));
|
|
179
|
+
|
|
180
|
+
describe('闸 1:CLI 入口层的 cwd 只能是一次性兜底', () => {
|
|
181
|
+
it('非兜底形状的 cwd 站点 = 冻结豁免表,且每条豁免仍然成立', () => {
|
|
182
|
+
const offenders = new Map<string, string[]>();
|
|
183
|
+
for (const [rel, lines] of cwdSites(cliFiles)) {
|
|
184
|
+
const notFallback = lines.filter(line => !ENTRY_FALLBACK_SHAPE.test(line));
|
|
185
|
+
if (notFallback.length > 0) offenders.set(rel, notFallback);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
expect([...offenders.keys()].sort()).toEqual(Object.keys(CLI_CWD_EXEMPTIONS).sort());
|
|
189
|
+
for (const [rel, exemption] of Object.entries(CLI_CWD_EXEMPTIONS)) {
|
|
190
|
+
expect({ rel, lines: offenders.get(rel) }).toEqual({ rel, lines: exemption.lines });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('闸 2:下游层不得二次取 cwd', () => {
|
|
196
|
+
it('下游 cwd 站点 = 冻结豁免表且逐行一致(新增文件/新增行/行变形/豁免化石都失败)', () => {
|
|
197
|
+
const sites = cwdSites(downstreamFiles);
|
|
198
|
+
|
|
199
|
+
expect([...sites.keys()].sort()).toEqual(Object.keys(DOWNSTREAM_CWD_EXEMPTIONS).sort());
|
|
200
|
+
for (const [rel, exemption] of Object.entries(DOWNSTREAM_CWD_EXEMPTIONS)) {
|
|
201
|
+
expect({ rel, lines: sites.get(rel) }).toEqual({ rel, lines: exemption.lines });
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('PassesGate 执行侧不再取 cwd(站点 1 的收口形状:workDir 由调用方传入)', () => {
|
|
206
|
+
const lines = codeLines(path.join(SRC_ROOT, 'core', 'validators', 'passes-gate.ts'));
|
|
207
|
+
|
|
208
|
+
expect(lines.some(line => line.includes('process.cwd()'))).toBe(false);
|
|
209
|
+
expect(lines.find(line => line.includes('async runTests'))).toContain('workDir');
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('闸 3:相对路径默认值不再按 cwd 解析', () => {
|
|
214
|
+
it('下游层(= src 减 cli)的相对字面量路径默认值 = 冻结豁免表', () => {
|
|
215
|
+
const hits = new Set<string>();
|
|
216
|
+
for (const file of downstreamFiles) {
|
|
217
|
+
if (codeLines(file).some(line => RELATIVE_PATH_DEFAULT.test(line))) hits.add(repoPath(file));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
expect([...hits].sort()).toEqual(Object.keys(RELATIVE_PATH_DEFAULT_EXEMPTIONS).sort());
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('acceptance 的 tasks.yml 默认不再有相对路径常量(站点 2 的收口形状)', () => {
|
|
224
|
+
// 多行调用 → 拼成空白归一的整段文本再断言形状
|
|
225
|
+
const body = codeLines(path.join(SRC_ROOT, 'gates', 'acceptance.ts')).join(' ').replace(/\s+/g, ' ');
|
|
226
|
+
|
|
227
|
+
expect(body).not.toMatch(/tasksPath\s*:\s*'/);
|
|
228
|
+
expect(body).toMatch(/path\.resolve\(\s*context\.projectPath\s*,\s*[^)]*'tasks\.yml'/);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|