@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
|
@@ -3,9 +3,15 @@
|
|
|
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
|
import { syncDocs } from '../sync-docs';
|
|
8
9
|
|
|
10
|
+
let io: CapturingIO;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
io = captureIO();
|
|
13
|
+
});
|
|
14
|
+
|
|
9
15
|
describe('sync-docs command', () => {
|
|
10
16
|
const tempDir = path.join(process.cwd(), 'temp-test-sync-docs');
|
|
11
17
|
|
|
@@ -21,15 +27,8 @@ describe('sync-docs command', () => {
|
|
|
21
27
|
}
|
|
22
28
|
});
|
|
23
29
|
|
|
24
|
-
let consoleSpy: jest.SpyInstance;
|
|
25
|
-
|
|
26
30
|
beforeEach(() => {
|
|
27
31
|
jest.clearAllMocks();
|
|
28
|
-
consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
consoleSpy.mockRestore();
|
|
33
32
|
});
|
|
34
33
|
|
|
35
34
|
describe('generateModuleTable', () => {
|
|
@@ -38,11 +37,11 @@ describe('sync-docs command', () => {
|
|
|
38
37
|
fs.mkdirSync(testDir, { recursive: true });
|
|
39
38
|
|
|
40
39
|
// No src dir → no modules → nothing to report
|
|
41
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
40
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
42
41
|
|
|
43
|
-
expect(result).
|
|
42
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
44
43
|
// When no modules and no changes, all docs are current
|
|
45
|
-
expect(
|
|
44
|
+
expect(io.outText()).toContain('所有文档');
|
|
46
45
|
|
|
47
46
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
48
47
|
});
|
|
@@ -55,7 +54,7 @@ describe('sync-docs command', () => {
|
|
|
55
54
|
// Create a source file with JSDoc comment
|
|
56
55
|
fs.writeFileSync(path.join(srcDir, 'mymodule.ts'), '/**\n * My test module\n */\nexport const x = 1;');
|
|
57
56
|
|
|
58
|
-
await syncDocs({ projectPath: testDir });
|
|
57
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
59
58
|
|
|
60
59
|
const capPath = path.join(testDir, 'CAPABILITIES.md');
|
|
61
60
|
const content = fs.readFileSync(capPath, 'utf-8');
|
|
@@ -75,7 +74,7 @@ describe('sync-docs command', () => {
|
|
|
75
74
|
|
|
76
75
|
fs.writeFileSync(path.join(srcDir, 'jsdoc-mod.ts'), '/**\n * JSDoc module description\n */\nexport const y = 2;');
|
|
77
76
|
|
|
78
|
-
await syncDocs({ projectPath: testDir });
|
|
77
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
79
78
|
|
|
80
79
|
const capPath = path.join(testDir, 'CAPABILITIES.md');
|
|
81
80
|
const content = fs.readFileSync(capPath, 'utf-8');
|
|
@@ -93,7 +92,7 @@ describe('sync-docs command', () => {
|
|
|
93
92
|
const filePath = path.join(srcDir, 'line-mod.ts');
|
|
94
93
|
fs.writeFileSync(filePath, '// Line comment module\nexport const z = 3;');
|
|
95
94
|
|
|
96
|
-
await syncDocs({ projectPath: testDir });
|
|
95
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
97
96
|
|
|
98
97
|
const capPath = path.join(testDir, 'CAPABILITIES.md');
|
|
99
98
|
const content = fs.readFileSync(capPath, 'utf-8');
|
|
@@ -109,7 +108,7 @@ describe('sync-docs command', () => {
|
|
|
109
108
|
|
|
110
109
|
fs.writeFileSync(path.join(srcDir, 'bare.ts'), 'export const a = 1;');
|
|
111
110
|
|
|
112
|
-
await syncDocs({ projectPath: testDir });
|
|
111
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
113
112
|
|
|
114
113
|
const capPath = path.join(testDir, 'CAPABILITIES.md');
|
|
115
114
|
const content = fs.readFileSync(capPath, 'utf-8');
|
|
@@ -120,16 +119,15 @@ describe('sync-docs command', () => {
|
|
|
120
119
|
});
|
|
121
120
|
});
|
|
122
121
|
|
|
123
|
-
|
|
124
122
|
describe('syncDocs', () => {
|
|
125
123
|
it('无 src/ 目录应该跳过模块扫描', async () => {
|
|
126
124
|
const emptyDir = path.join(tempDir, 'empty');
|
|
127
125
|
fs.mkdirSync(emptyDir, { recursive: true });
|
|
128
126
|
|
|
129
|
-
const result = await syncDocs({ projectPath: emptyDir });
|
|
130
|
-
expect(result).
|
|
127
|
+
const result = await syncDocs({ projectPath: emptyDir }, io);
|
|
128
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
131
129
|
// 无 src/ 目录,模块扫描返回空,无差异
|
|
132
|
-
expect(
|
|
130
|
+
expect(io.outText()).toContain('所有文档都是最新的');
|
|
133
131
|
|
|
134
132
|
fs.rmSync(emptyDir, { recursive: true, force: true });
|
|
135
133
|
});
|
|
@@ -142,8 +140,8 @@ describe('sync-docs command', () => {
|
|
|
142
140
|
// 创建 CAPABILITIES.md,无表格
|
|
143
141
|
fs.writeFileSync(path.join(testDir, 'CAPABILITIES.md'), '# Capabilities\n\nNo table.');
|
|
144
142
|
|
|
145
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
146
|
-
expect(result).
|
|
143
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
144
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
147
145
|
|
|
148
146
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
149
147
|
});
|
|
@@ -162,9 +160,9 @@ describe('sync-docs command', () => {
|
|
|
162
160
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| old | src/old.ts | old |'
|
|
163
161
|
);
|
|
164
162
|
|
|
165
|
-
const result = await syncDocs({ projectPath: testDir, check: true });
|
|
166
|
-
expect(result).
|
|
167
|
-
expect(
|
|
163
|
+
const result = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
164
|
+
expect(result).toEqual({ kind: 'fail', reason: expect.stringContaining('文档不是最新') });
|
|
165
|
+
expect(io.outText()).toContain('文档不是最新的');
|
|
168
166
|
|
|
169
167
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
170
168
|
});
|
|
@@ -183,15 +181,15 @@ describe('sync-docs command', () => {
|
|
|
183
181
|
);
|
|
184
182
|
|
|
185
183
|
// 第一轮:生成 CAPABILITIES.md(描述行以 / 结尾)
|
|
186
|
-
await syncDocs({ projectPath: testDir });
|
|
184
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
187
185
|
const cap = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
188
186
|
expect(cap).toContain('workspace.ts');
|
|
189
187
|
expect(cap).toMatch(/gitRepo\s*\/\s*\|/);
|
|
190
188
|
|
|
191
189
|
// 第二轮:生成后立即 --check 必须收敛(修复前此处必 false)
|
|
192
|
-
|
|
193
|
-
const check = await syncDocs({ projectPath: testDir, check: true });
|
|
194
|
-
expect(check).
|
|
190
|
+
io = captureIO();
|
|
191
|
+
const check = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
192
|
+
expect(check).toEqual({ kind: 'ok' });
|
|
195
193
|
|
|
196
194
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
197
195
|
});
|
|
@@ -210,8 +208,8 @@ describe('sync-docs command', () => {
|
|
|
210
208
|
);
|
|
211
209
|
|
|
212
210
|
// src/ 目录条目覆盖 mymodule.ts → 无 added,check 通过
|
|
213
|
-
const result = await syncDocs({ projectPath: testDir, check: true });
|
|
214
|
-
expect(result).
|
|
211
|
+
const result = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
212
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
215
213
|
|
|
216
214
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
217
215
|
});
|
|
@@ -239,9 +237,9 @@ describe('sync-docs command', () => {
|
|
|
239
237
|
|
|
240
238
|
// 不创建 CONTEXT.md
|
|
241
239
|
|
|
242
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
243
|
-
expect(result).
|
|
244
|
-
expect(
|
|
240
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
241
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
242
|
+
expect(io.outText()).toContain('缺少 CONTEXT.md');
|
|
245
243
|
|
|
246
244
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
247
245
|
});
|
|
@@ -269,8 +267,8 @@ describe('sync-docs command', () => {
|
|
|
269
267
|
// 创建 CONTEXT.md
|
|
270
268
|
fs.writeFileSync(path.join(srcDir, 'CONTEXT.md'), '# src\n\nTest context');
|
|
271
269
|
|
|
272
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
273
|
-
expect(result).
|
|
270
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
271
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
274
272
|
|
|
275
273
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
276
274
|
});
|
|
@@ -281,8 +279,8 @@ describe('sync-docs command', () => {
|
|
|
281
279
|
|
|
282
280
|
// 无 .harness/config.yml
|
|
283
281
|
|
|
284
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
285
|
-
expect(result).
|
|
282
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
283
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
286
284
|
|
|
287
285
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
288
286
|
});
|
|
@@ -307,7 +305,7 @@ describe('sync-docs command', () => {
|
|
|
307
305
|
})
|
|
308
306
|
);
|
|
309
307
|
|
|
310
|
-
await syncDocs({ projectPath: testDir });
|
|
308
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
311
309
|
|
|
312
310
|
// 验证 CONTEXT.md 被创建
|
|
313
311
|
const contextPath = path.join(srcDir, 'CONTEXT.md');
|
|
@@ -326,7 +324,7 @@ describe('sync-docs command', () => {
|
|
|
326
324
|
// 创建源文件
|
|
327
325
|
fs.writeFileSync(path.join(srcDir, 'module.ts'), 'export const x = 1;');
|
|
328
326
|
|
|
329
|
-
await syncDocs({ projectPath: testDir });
|
|
327
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
330
328
|
|
|
331
329
|
// 验证 CAPABILITIES.md 被创建
|
|
332
330
|
const capPath = path.join(testDir, 'CAPABILITIES.md');
|
|
@@ -346,11 +344,11 @@ describe('sync-docs command', () => {
|
|
|
346
344
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| old | src/old.ts | old |'
|
|
347
345
|
);
|
|
348
346
|
|
|
349
|
-
const result = await syncDocs({ projectPath: testDir, check: true, json: true });
|
|
350
|
-
expect(result).
|
|
347
|
+
const result = await syncDocs({ projectPath: testDir, check: true, json: true }, io);
|
|
348
|
+
expect(result).toEqual({ kind: 'fail', reason: expect.stringContaining('文档不是最新') });
|
|
351
349
|
|
|
352
350
|
// 验证 console.log 被调用了 JSON
|
|
353
|
-
const jsonCall =
|
|
351
|
+
const jsonCall = io.outRecords().map(chunk => [chunk] as string[]).find(
|
|
354
352
|
(call: unknown[]) => typeof call[0] === 'string' && call[0].startsWith('{')
|
|
355
353
|
);
|
|
356
354
|
expect(jsonCall).toBeDefined();
|
|
@@ -366,10 +364,10 @@ describe('sync-docs command', () => {
|
|
|
366
364
|
fs.mkdirSync(testDir, { recursive: true });
|
|
367
365
|
fs.writeFileSync(path.join(testDir, 'CAPABILITIES.md'), '# Capabilities\n\nNo table.');
|
|
368
366
|
|
|
369
|
-
const result = await syncDocs({ projectPath: testDir, check: true, json: true });
|
|
370
|
-
expect(result).
|
|
367
|
+
const result = await syncDocs({ projectPath: testDir, check: true, json: true }, io);
|
|
368
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
371
369
|
|
|
372
|
-
const jsonCall =
|
|
370
|
+
const jsonCall = io.outRecords().map(chunk => [chunk] as string[]).find(
|
|
373
371
|
(call: unknown[]) => typeof call[0] === 'string' && call[0].startsWith('{')
|
|
374
372
|
);
|
|
375
373
|
expect(jsonCall).toBeDefined();
|
|
@@ -389,7 +387,7 @@ describe('sync-docs command', () => {
|
|
|
389
387
|
fs.writeFileSync(path.join(srcDir, 'removed.ts'), 'export const removed = 1;');
|
|
390
388
|
|
|
391
389
|
// 先让 syncDocs 创建初始 CAPABILITIES.md(包含两个文件)
|
|
392
|
-
await syncDocs({ projectPath: testDir });
|
|
390
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
393
391
|
let content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
394
392
|
expect(content).toContain('kept.ts');
|
|
395
393
|
expect(content).toContain('removed.ts');
|
|
@@ -398,7 +396,7 @@ describe('sync-docs command', () => {
|
|
|
398
396
|
fs.unlinkSync(path.join(srcDir, 'removed.ts'));
|
|
399
397
|
|
|
400
398
|
// 重新运行 syncDocs(写入模式)
|
|
401
|
-
await syncDocs({ projectPath: testDir });
|
|
399
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
402
400
|
content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
403
401
|
expect(content).toContain('kept.ts');
|
|
404
402
|
expect(content).not.toContain('removed.ts');
|
|
@@ -430,14 +428,14 @@ describe('sync-docs command', () => {
|
|
|
430
428
|
].join('\n')
|
|
431
429
|
);
|
|
432
430
|
|
|
433
|
-
await syncDocs({ projectPath: testDir });
|
|
431
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
434
432
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
435
433
|
expect(content).toContain('DistillProposalCard.tsx');
|
|
436
434
|
|
|
437
435
|
// 修复前:--check 每跑必报「包含已删除的模块」不收敛
|
|
438
|
-
|
|
439
|
-
const check = await syncDocs({ projectPath: testDir, check: true });
|
|
440
|
-
expect(check).
|
|
436
|
+
io = captureIO();
|
|
437
|
+
const check = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
438
|
+
expect(check).toEqual({ kind: 'ok' });
|
|
441
439
|
|
|
442
440
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
443
441
|
});
|
|
@@ -454,11 +452,11 @@ describe('sync-docs command', () => {
|
|
|
454
452
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| util | src/util.ts | util |'
|
|
455
453
|
);
|
|
456
454
|
|
|
457
|
-
const check = await syncDocs({ projectPath: testDir, check: true });
|
|
458
|
-
expect(check).
|
|
459
|
-
expect(
|
|
455
|
+
const check = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
456
|
+
expect(check).toEqual({ kind: 'fail', reason: expect.stringContaining('文档不是最新') });
|
|
457
|
+
expect(io.outText()).toContain('Card.tsx');
|
|
460
458
|
|
|
461
|
-
await syncDocs({ projectPath: testDir });
|
|
459
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
462
460
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
463
461
|
expect(content).toContain('Card.tsx');
|
|
464
462
|
|
|
@@ -484,14 +482,14 @@ describe('sync-docs command', () => {
|
|
|
484
482
|
].join('\n')
|
|
485
483
|
);
|
|
486
484
|
|
|
487
|
-
await syncDocs({ projectPath: testDir });
|
|
485
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
488
486
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
489
487
|
expect(content).toContain('src/helper.js');
|
|
490
488
|
expect(content).toContain('src/Helper.jsx');
|
|
491
489
|
|
|
492
|
-
|
|
493
|
-
const check = await syncDocs({ projectPath: testDir, check: true });
|
|
494
|
-
expect(check).
|
|
490
|
+
io = captureIO();
|
|
491
|
+
const check = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
492
|
+
expect(check).toEqual({ kind: 'ok' });
|
|
495
493
|
|
|
496
494
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
497
495
|
});
|
|
@@ -518,7 +516,7 @@ describe('sync-docs command', () => {
|
|
|
518
516
|
].join('\n'),
|
|
519
517
|
);
|
|
520
518
|
|
|
521
|
-
await syncDocs({ projectPath: testDir });
|
|
519
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
522
520
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
523
521
|
expect(content).toContain('src/a/routes.ts');
|
|
524
522
|
expect(content).not.toContain('src/ghost/routes.ts');
|
|
@@ -551,9 +549,9 @@ describe('sync-docs command', () => {
|
|
|
551
549
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| 核心 | src/core/ | 核心模块 |'
|
|
552
550
|
);
|
|
553
551
|
|
|
554
|
-
const result = await syncDocs({ projectPath: testDir });
|
|
552
|
+
const result = await syncDocs({ projectPath: testDir }, io);
|
|
555
553
|
// 有未覆盖目录,仍报不同步
|
|
556
|
-
expect(result).
|
|
554
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
557
555
|
// 但不自动给 b.ts 加表格行
|
|
558
556
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
559
557
|
expect(content).not.toContain('b.ts');
|
|
@@ -575,10 +573,10 @@ describe('sync-docs command', () => {
|
|
|
575
573
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| 核心 | src/core/ | 核心模块 |'
|
|
576
574
|
);
|
|
577
575
|
|
|
578
|
-
const result = await syncDocs({ projectPath: testDir, check: true });
|
|
579
|
-
expect(result).
|
|
580
|
-
expect(
|
|
581
|
-
expect(
|
|
576
|
+
const result = await syncDocs({ projectPath: testDir, check: true }, io);
|
|
577
|
+
expect(result).toEqual({ kind: 'fail', reason: expect.stringContaining('文档不是最新') });
|
|
578
|
+
expect(io.outText()).toContain('未登记以下模块(目录)');
|
|
579
|
+
expect(io.outText()).toContain('src/newdir/');
|
|
582
580
|
|
|
583
581
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
584
582
|
});
|
|
@@ -596,10 +594,10 @@ describe('sync-docs command', () => {
|
|
|
596
594
|
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| 核心 | src/core/ | 核心模块 |'
|
|
597
595
|
);
|
|
598
596
|
|
|
599
|
-
const result = await syncDocs({ projectPath: testDir, check: true, json: true });
|
|
600
|
-
expect(result).
|
|
597
|
+
const result = await syncDocs({ projectPath: testDir, check: true, json: true }, io);
|
|
598
|
+
expect(result).toEqual({ kind: 'fail', reason: expect.stringContaining('文档不是最新') });
|
|
601
599
|
|
|
602
|
-
const jsonCall =
|
|
600
|
+
const jsonCall = io.outRecords().map(chunk => [chunk] as string[]).find(
|
|
603
601
|
(call: unknown[]) => typeof call[0] === 'string' && call[0].startsWith('{')
|
|
604
602
|
);
|
|
605
603
|
expect(jsonCall).toBeDefined();
|
|
@@ -628,7 +626,7 @@ describe('sync-docs command', () => {
|
|
|
628
626
|
].join('\n')
|
|
629
627
|
);
|
|
630
628
|
|
|
631
|
-
await syncDocs({ projectPath: testDir });
|
|
629
|
+
await syncDocs({ projectPath: testDir }, io);
|
|
632
630
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
633
631
|
expect(content).toContain('src/a/kept.ts');
|
|
634
632
|
expect(content).not.toContain('ghost.ts');
|
|
@@ -658,8 +656,8 @@ describe('sync-docs command', () => {
|
|
|
658
656
|
].join('\n')
|
|
659
657
|
);
|
|
660
658
|
|
|
661
|
-
const result = await syncDocs({ projectPath: testDir, compact: true });
|
|
662
|
-
expect(result).
|
|
659
|
+
const result = await syncDocs({ projectPath: testDir, compact: true }, io);
|
|
660
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
663
661
|
|
|
664
662
|
const content = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
665
663
|
// 折叠为目录条目(说明取组内第一行)
|
|
@@ -672,7 +670,7 @@ describe('sync-docs command', () => {
|
|
|
672
670
|
expect(content).toContain('手工说明');
|
|
673
671
|
|
|
674
672
|
// 幂等:再跑一遍内容不变
|
|
675
|
-
await syncDocs({ projectPath: testDir, compact: true });
|
|
673
|
+
await syncDocs({ projectPath: testDir, compact: true }, io);
|
|
676
674
|
const content2 = fs.readFileSync(path.join(testDir, 'CAPABILITIES.md'), 'utf-8');
|
|
677
675
|
expect(content2).toBe(content);
|
|
678
676
|
|
|
@@ -683,8 +681,8 @@ describe('sync-docs command', () => {
|
|
|
683
681
|
const testDir = path.join(tempDir, 'compact-missing');
|
|
684
682
|
fs.mkdirSync(testDir, { recursive: true });
|
|
685
683
|
|
|
686
|
-
const result = await syncDocs({ projectPath: testDir, compact: true });
|
|
687
|
-
expect(result).
|
|
684
|
+
const result = await syncDocs({ projectPath: testDir, compact: true }, io);
|
|
685
|
+
expect(result).toEqual({ kind: 'ok' });
|
|
688
686
|
|
|
689
687
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
690
688
|
});
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import * as fs from 'fs';
|
|
11
|
+
import { captureIO, lastJsonOutput, type CapturingIO } from '../../command-contract';
|
|
11
12
|
import * as path from 'path';
|
|
12
13
|
import { updateUserModel } from '../update-user-model';
|
|
13
14
|
import { readTranscriptSessions, type MinedSession } from '../../session-mining';
|
|
@@ -72,33 +73,30 @@ function mkSession(partial: Partial<MinedSession> = {}): MinedSession {
|
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
76
|
+
let io: CapturingIO;
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
io = captureIO();
|
|
79
|
+
});
|
|
79
80
|
|
|
80
81
|
describe('update-user-model command', () => {
|
|
81
|
-
let consoleSpy: jest.SpyInstance;
|
|
82
82
|
|
|
83
83
|
beforeEach(() => {
|
|
84
84
|
jest.clearAllMocks();
|
|
85
85
|
fs.rmSync(TEST_HOME, { recursive: true, force: true });
|
|
86
86
|
fs.mkdirSync(path.join(TEST_HOME, '.claude', 'projects', '-root-projects', 'memory'), { recursive: true });
|
|
87
87
|
process.env.CLAUDE_TRANSCRIPTS_DIR = path.join(TEST_HOME, 'transcripts');
|
|
88
|
-
consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
89
88
|
});
|
|
90
89
|
|
|
91
90
|
afterEach(() => {
|
|
92
|
-
consoleSpy.mockRestore();
|
|
93
91
|
delete process.env.CLAUDE_TRANSCRIPTS_DIR;
|
|
94
92
|
});
|
|
95
93
|
|
|
96
94
|
test('无新会话:提示 No new sessions to process', async () => {
|
|
97
95
|
mockReadTranscriptSessions.mockReturnValue([]);
|
|
98
96
|
|
|
99
|
-
await updateUserModel({});
|
|
97
|
+
await updateUserModel({}, io);
|
|
100
98
|
|
|
101
|
-
expect(
|
|
99
|
+
expect(io.outText()).toContain('No new sessions to process');
|
|
102
100
|
expect(fs.existsSync(STATE_FILE)).toBe(false);
|
|
103
101
|
});
|
|
104
102
|
|
|
@@ -108,9 +106,9 @@ describe('update-user-model command', () => {
|
|
|
108
106
|
mkSession({ id: 'session-b' }),
|
|
109
107
|
]);
|
|
110
108
|
|
|
111
|
-
await updateUserModel({ json: true, dryRun: true });
|
|
109
|
+
await updateUserModel({ json: true, dryRun: true }, io);
|
|
112
110
|
|
|
113
|
-
const output = lastJsonOutput(
|
|
111
|
+
const output = lastJsonOutput(io);
|
|
114
112
|
expect(output.newSessions).toBe(2);
|
|
115
113
|
expect(output.changes).toEqual(
|
|
116
114
|
expect.arrayContaining([
|
|
@@ -125,23 +123,37 @@ describe('update-user-model command', () => {
|
|
|
125
123
|
test('--dry-run:只展示变化,不写 state 文件', async () => {
|
|
126
124
|
mockReadTranscriptSessions.mockReturnValue([mkSession({ id: 'session-a' })]);
|
|
127
125
|
|
|
128
|
-
await updateUserModel({ dryRun: true });
|
|
126
|
+
await updateUserModel({ dryRun: true }, io);
|
|
129
127
|
|
|
130
|
-
expect(
|
|
128
|
+
expect(io.outText()).toContain('Processed 1 new sessions');
|
|
131
129
|
expect(fs.existsSync(STATE_FILE)).toBe(false);
|
|
132
130
|
});
|
|
133
131
|
|
|
134
132
|
test('默认(非 dry-run):落盘 state 并记录已处理会话', async () => {
|
|
135
133
|
mockReadTranscriptSessions.mockReturnValue([mkSession({ id: 'session-a' })]);
|
|
136
134
|
|
|
137
|
-
await updateUserModel({});
|
|
135
|
+
await updateUserModel({}, io);
|
|
138
136
|
|
|
139
137
|
expect(fs.existsSync(STATE_FILE)).toBe(true);
|
|
140
138
|
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
141
139
|
expect(state.sessionsProcessed).toContain('session-a');
|
|
142
140
|
});
|
|
143
141
|
|
|
144
|
-
test('--days 1
|
|
142
|
+
test('--days 1:since 过滤下推到 seam(自然日窗口,含今天)', async () => {
|
|
143
|
+
mockReadTranscriptSessions.mockReturnValue([mkSession({ id: 'today' })]);
|
|
144
|
+
|
|
145
|
+
await updateUserModel({ json: true, dryRun: true, days: 1 }, io);
|
|
146
|
+
|
|
147
|
+
const output = lastJsonOutput(io);
|
|
148
|
+
expect(output.newSessions).toBe(1);
|
|
149
|
+
// date >= 今日 ⟺ mtimeMs >= 今日 UTC 零点,过滤在 seam 内 stat 级完成
|
|
150
|
+
expect(mockReadTranscriptSessions).toHaveBeenCalledWith(
|
|
151
|
+
process.env.CLAUDE_TRANSCRIPTS_DIR,
|
|
152
|
+
{ excludeIds: [], since: Date.parse(todayStr()) },
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('缺省 --days:处理全部未处理会话(向后兼容)', async () => {
|
|
145
157
|
mockReadTranscriptSessions.mockReturnValue([
|
|
146
158
|
mkSession({ id: 'today' }),
|
|
147
159
|
mkSession({
|
|
@@ -154,32 +166,48 @@ describe('update-user-model command', () => {
|
|
|
154
166
|
}),
|
|
155
167
|
]);
|
|
156
168
|
|
|
157
|
-
await updateUserModel({ json: true, dryRun: true,
|
|
169
|
+
await updateUserModel({ json: true, dryRun: true }, io);
|
|
158
170
|
|
|
159
|
-
const output = lastJsonOutput(
|
|
160
|
-
expect(output.newSessions).toBe(
|
|
171
|
+
const output = lastJsonOutput(io);
|
|
172
|
+
expect(output.newSessions).toBe(2);
|
|
173
|
+
// 缺省 days:不下推 since(向后兼容全量)
|
|
174
|
+
expect(mockReadTranscriptSessions).toHaveBeenCalledWith(
|
|
175
|
+
process.env.CLAUDE_TRANSCRIPTS_DIR,
|
|
176
|
+
{ excludeIds: [] },
|
|
177
|
+
);
|
|
161
178
|
});
|
|
162
179
|
|
|
163
|
-
test('
|
|
180
|
+
test('同一 concept 只计一次:occurrences 等于 merged 聚合值(#113 双计 bug)', async () => {
|
|
181
|
+
mockReadTranscriptSessions.mockReturnValue([mkSession({ id: 'session-a' })]);
|
|
182
|
+
|
|
183
|
+
await updateUserModel({}, io);
|
|
184
|
+
|
|
185
|
+
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
186
|
+
// userText 整条中文序列恰为一个 concept(count=1);聚合后只应出现一次,
|
|
187
|
+
// 双计 bug 下会被 merged 循环 + per-session 循环各加一次变成 2
|
|
188
|
+
expect(state.patterns['数据库迁移方案需要执行'].occurrences).toBe(1);
|
|
189
|
+
expect(state.patterns['数据库迁移方案需要执行'].sessions).toEqual(['session-a']);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('correction phrase 的 ×3 加权不受影响(buildMergedConcepts 内)', async () => {
|
|
164
193
|
mockReadTranscriptSessions.mockReturnValue([
|
|
165
|
-
mkSession({ id: 'today' }),
|
|
166
194
|
mkSession({
|
|
167
|
-
id: '
|
|
168
|
-
date: todayStr(3),
|
|
195
|
+
id: 'session-a',
|
|
169
196
|
turns: [
|
|
170
|
-
{ role: 'user', content: '
|
|
197
|
+
{ role: 'user', content: '这种问题反复出现' },
|
|
171
198
|
{ role: 'assistant', content: '' },
|
|
172
199
|
],
|
|
173
200
|
}),
|
|
174
201
|
]);
|
|
175
202
|
|
|
176
|
-
await updateUserModel({
|
|
203
|
+
await updateUserModel({}, io);
|
|
177
204
|
|
|
178
|
-
const
|
|
179
|
-
|
|
205
|
+
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
206
|
+
// 纠正语句提取的 concept 按 ×3 计入(裁决:权重在 buildMergedConcepts,删循环不影响)
|
|
207
|
+
expect(state.patterns['这种问题'].occurrences).toBe(3);
|
|
180
208
|
});
|
|
181
209
|
|
|
182
|
-
test('sessionsProcessed
|
|
210
|
+
test('sessionsProcessed 去重:已处理会话经 excludeIds 下推排除', async () => {
|
|
183
211
|
fs.writeFileSync(
|
|
184
212
|
STATE_FILE,
|
|
185
213
|
JSON.stringify({
|
|
@@ -192,14 +220,15 @@ describe('update-user-model command', () => {
|
|
|
192
220
|
}),
|
|
193
221
|
'utf-8',
|
|
194
222
|
);
|
|
195
|
-
mockReadTranscriptSessions.mockReturnValue([
|
|
196
|
-
mkSession({ id: 'session-a' }),
|
|
197
|
-
mkSession({ id: 'session-b' }),
|
|
198
|
-
]);
|
|
223
|
+
mockReadTranscriptSessions.mockReturnValue([mkSession({ id: 'session-b' })]);
|
|
199
224
|
|
|
200
|
-
await updateUserModel({ json: true, dryRun: true, days: 7 });
|
|
225
|
+
await updateUserModel({ json: true, dryRun: true, days: 7 }, io);
|
|
201
226
|
|
|
202
|
-
const output = lastJsonOutput(
|
|
227
|
+
const output = lastJsonOutput(io);
|
|
203
228
|
expect(output.newSessions).toBe(1);
|
|
229
|
+
expect(mockReadTranscriptSessions).toHaveBeenCalledWith(
|
|
230
|
+
process.env.CLAUDE_TRANSCRIPTS_DIR,
|
|
231
|
+
{ excludeIds: ['session-a'], since: expect.any(Number) },
|
|
232
|
+
);
|
|
204
233
|
});
|
|
205
234
|
});
|