@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
|
@@ -12,10 +12,13 @@ import { FileKnowledgeStore as KnowledgeStore } from '../../knowledge/store';
|
|
|
12
12
|
import { KnowledgeQuery } from '../../knowledge/query';
|
|
13
13
|
import { KnowledgeLifecycle } from '../../knowledge/lifecycle';
|
|
14
14
|
import { ColdStartImporter } from '../../knowledge/import';
|
|
15
|
-
import { KnowledgeAudit } from '../../knowledge/audit';
|
|
15
|
+
import { KnowledgeAudit, AUDIT_RULE_LABELS } from '../../knowledge/audit';
|
|
16
|
+
import type { AuditReport, AuditRuleName } from '../../knowledge/audit';
|
|
17
|
+
import { evaluateFlywheel } from '../../knowledge/flywheel-metrics';
|
|
16
18
|
import { migrateKnowledgeEntries } from '../../knowledge/migration';
|
|
17
19
|
import { KnowledgeIndexGenerator } from '../../knowledge/index-generator';
|
|
18
20
|
import type { KnowledgeSubsystem, MaturityLevel, QueryFilter } from '../../knowledge/types';
|
|
21
|
+
import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
19
22
|
|
|
20
23
|
export interface KnowledgeOptions {
|
|
21
24
|
/** 项目路径 */
|
|
@@ -31,8 +34,8 @@ export async function knowledgeList(options: KnowledgeOptions & {
|
|
|
31
34
|
type?: string;
|
|
32
35
|
maturity?: string;
|
|
33
36
|
tag?: string;
|
|
34
|
-
}): Promise<
|
|
35
|
-
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
37
|
+
}, io: CommandIO = processIO): Promise<CommandResult> {
|
|
38
|
+
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
|
|
36
39
|
|
|
37
40
|
const filter: QueryFilter = { excludeArchived: false };
|
|
38
41
|
if (options.type) {
|
|
@@ -48,27 +51,28 @@ export async function knowledgeList(options: KnowledgeOptions & {
|
|
|
48
51
|
const entries = store.list(filter);
|
|
49
52
|
|
|
50
53
|
if (options.json) {
|
|
51
|
-
|
|
52
|
-
return;
|
|
54
|
+
log(io, JSON.stringify({ total: entries.length, entries }, null, 2));
|
|
55
|
+
return { kind: 'ok' };
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
if (entries.length === 0) {
|
|
56
|
-
|
|
57
|
-
return;
|
|
59
|
+
log(io, chalk.yellow('知识库为空'));
|
|
60
|
+
return { kind: 'ok' };
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
log(io, chalk.blue(`📚 知识库 (${entries.length} 条)\n`));
|
|
61
64
|
for (const entry of entries) {
|
|
62
65
|
const maturityColor = entry.maturity === 'proven' ? chalk.green
|
|
63
66
|
: entry.maturity === 'verified' ? chalk.cyan
|
|
64
67
|
: entry.maturity === 'archived' ? chalk.gray
|
|
65
68
|
: chalk.yellow;
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
log(io, ` ${maturityColor(`[${entry.maturity}]`)} ${chalk.bold(entry.title)}`);
|
|
70
|
+
log(io, ` ${chalk.gray(`id: ${entry.id} | type: ${entry.type} | layer: ${entry.layer}`)}`);
|
|
68
71
|
if (entry.tags.length > 0) {
|
|
69
|
-
|
|
72
|
+
log(io, ` ${chalk.gray(`tags: ${entry.tags.join(', ')}`)}`);
|
|
70
73
|
}
|
|
71
74
|
}
|
|
75
|
+
return { kind: 'ok' };
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
/**
|
|
@@ -77,28 +81,51 @@ export async function knowledgeList(options: KnowledgeOptions & {
|
|
|
77
81
|
export async function knowledgeSearch(
|
|
78
82
|
query: string,
|
|
79
83
|
options: KnowledgeOptions & { limit?: number },
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
io: CommandIO = processIO,
|
|
85
|
+
): Promise<CommandResult> {
|
|
86
|
+
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
|
|
82
87
|
const queryEngine = new KnowledgeQuery(store);
|
|
83
88
|
|
|
84
89
|
const matched = queryEngine.search(query, { limit: options.limit || 20 });
|
|
85
90
|
|
|
86
91
|
if (options.json) {
|
|
87
|
-
|
|
88
|
-
return;
|
|
92
|
+
log(io, JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
|
|
93
|
+
return { kind: 'ok' };
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
if (matched.length === 0) {
|
|
92
|
-
|
|
93
|
-
return;
|
|
97
|
+
log(io, chalk.yellow(`未找到匹配 "${query}" 的知识条目`));
|
|
98
|
+
return { kind: 'ok' };
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
log(io, chalk.blue(`🔍 搜索 "${query}" (${matched.length} 条结果)\n`));
|
|
97
102
|
for (const entry of matched) {
|
|
98
|
-
|
|
103
|
+
log(io, ` ${chalk.bold(entry.title)} ${chalk.gray(`[${entry.maturity}]`)}`);
|
|
99
104
|
const preview = entry.content.slice(0, 100).replace(/\n/g, ' ');
|
|
100
|
-
|
|
105
|
+
log(io, ` ${chalk.gray(preview)}${entry.content.length > 100 ? '...' : ''}`);
|
|
101
106
|
}
|
|
107
|
+
return { kind: 'ok' };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* knowledge search 子命令入口(候选7):缺参闸门 + limit 强转编组,
|
|
112
|
+
* 自 definitions.ts 的 args 复印块移回命令模块(interface/测试面所在)。
|
|
113
|
+
*/
|
|
114
|
+
export async function knowledgeSearchCommand(
|
|
115
|
+
positionals: (string | undefined)[],
|
|
116
|
+
options: Record<string, unknown>,
|
|
117
|
+
io: CommandIO = processIO,
|
|
118
|
+
): Promise<CommandResult> {
|
|
119
|
+
const query = positionals[0];
|
|
120
|
+
if (!query) {
|
|
121
|
+
logError(io, '请提供搜索关键词');
|
|
122
|
+
return { kind: 'usage-error', reason: 'knowledge search 缺少关键词位置参数' };
|
|
123
|
+
}
|
|
124
|
+
return knowledgeSearch(String(query), {
|
|
125
|
+
projectPath: options.projectPath as string | undefined,
|
|
126
|
+
json: options.json as boolean | undefined,
|
|
127
|
+
limit: parseInt(String(options.limit), 10),
|
|
128
|
+
});
|
|
102
129
|
}
|
|
103
130
|
|
|
104
131
|
/**
|
|
@@ -106,9 +133,10 @@ export async function knowledgeSearch(
|
|
|
106
133
|
*/
|
|
107
134
|
export async function knowledgeImport(
|
|
108
135
|
options: KnowledgeOptions & { sources?: string; reset?: boolean },
|
|
109
|
-
|
|
136
|
+
io: CommandIO = processIO,
|
|
137
|
+
): Promise<CommandResult> {
|
|
110
138
|
const projectPath = options.projectPath || process.cwd();
|
|
111
|
-
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
139
|
+
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
|
|
112
140
|
|
|
113
141
|
const sources = options.sources
|
|
114
142
|
? options.sources.split(',') as Array<'code' | 'git' | 'docs' | 'manual'>
|
|
@@ -123,12 +151,12 @@ export async function knowledgeImport(
|
|
|
123
151
|
if (options.reset) {
|
|
124
152
|
importer.resetState();
|
|
125
153
|
if (!options.json) {
|
|
126
|
-
|
|
154
|
+
log(io, chalk.yellow('🔄 已重置导入状态'));
|
|
127
155
|
}
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
if (!options.json) {
|
|
131
|
-
|
|
159
|
+
log(io, chalk.blue(`📥 开始导入知识 (源: ${sources.join(', ')})...`));
|
|
132
160
|
}
|
|
133
161
|
|
|
134
162
|
const results = await importer.importAll();
|
|
@@ -137,59 +165,61 @@ export async function knowledgeImport(
|
|
|
137
165
|
const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
|
|
138
166
|
|
|
139
167
|
if (options.json) {
|
|
140
|
-
|
|
141
|
-
return;
|
|
168
|
+
log(io, JSON.stringify({ totalImported, totalErrors, results }, null, 2));
|
|
169
|
+
return { kind: 'ok' };
|
|
142
170
|
}
|
|
143
171
|
|
|
144
172
|
for (const result of results) {
|
|
145
173
|
if (result.entries.length > 0) {
|
|
146
|
-
|
|
174
|
+
log(io, chalk.green(` ✅ ${result.source.type}: ${result.entries.length} 条`));
|
|
147
175
|
}
|
|
148
176
|
if (result.errors.length > 0) {
|
|
149
177
|
for (const err of result.errors) {
|
|
150
|
-
|
|
178
|
+
log(io, chalk.red(` ❌ ${result.source.type}: ${err.message}`));
|
|
151
179
|
}
|
|
152
180
|
}
|
|
153
181
|
}
|
|
154
182
|
|
|
155
|
-
|
|
183
|
+
log(io, chalk.green(`\n✅ 导入完成: ${totalImported} 条,${totalErrors} 个错误`));
|
|
184
|
+
return { kind: 'ok' };
|
|
156
185
|
}
|
|
157
186
|
|
|
158
187
|
/**
|
|
159
188
|
* 知识库衰减周期
|
|
160
189
|
*/
|
|
161
|
-
export async function knowledgeDecay(options: KnowledgeOptions): Promise<
|
|
162
|
-
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
190
|
+
export async function knowledgeDecay(options: KnowledgeOptions, io: CommandIO = processIO): Promise<CommandResult> {
|
|
191
|
+
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
|
|
163
192
|
const lifecycle = new KnowledgeLifecycle(store);
|
|
164
193
|
|
|
165
194
|
if (!options.json) {
|
|
166
|
-
|
|
195
|
+
log(io, chalk.blue('🔄 运行衰减周期...'));
|
|
167
196
|
}
|
|
168
197
|
|
|
169
198
|
const changes = lifecycle.runDecayCycle();
|
|
170
199
|
|
|
171
200
|
if (options.json) {
|
|
172
|
-
|
|
173
|
-
return;
|
|
201
|
+
log(io, JSON.stringify({ changes }, null, 2));
|
|
202
|
+
return { kind: 'ok' };
|
|
174
203
|
}
|
|
175
204
|
|
|
176
205
|
if (changes.length === 0) {
|
|
177
|
-
|
|
178
|
-
return;
|
|
206
|
+
log(io, chalk.green('✅ 没有需要衰减的知识条目'));
|
|
207
|
+
return { kind: 'ok' };
|
|
179
208
|
}
|
|
180
209
|
|
|
181
|
-
|
|
210
|
+
log(io, chalk.yellow(`📉 ${changes.length} 条知识发生衰减:\n`));
|
|
182
211
|
for (const change of changes) {
|
|
183
|
-
|
|
184
|
-
|
|
212
|
+
log(io, ` ${change.entryId}: ${chalk.red(change.from)} → ${chalk.green(change.to)}`);
|
|
213
|
+
log(io, ` ${chalk.gray(change.reason)}`);
|
|
185
214
|
}
|
|
215
|
+
return { kind: 'ok' };
|
|
186
216
|
}
|
|
187
217
|
|
|
188
218
|
/**
|
|
189
219
|
* 知识库统计
|
|
190
220
|
*/
|
|
191
|
-
export async function knowledgeStats(options: KnowledgeOptions): Promise<
|
|
192
|
-
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
221
|
+
export async function knowledgeStats(options: KnowledgeOptions, io: CommandIO = processIO): Promise<CommandResult> {
|
|
222
|
+
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
|
|
193
223
|
const entries = store.list({ excludeArchived: false });
|
|
194
224
|
const active = entries.filter(e => e.maturity !== 'archived');
|
|
195
225
|
|
|
@@ -203,207 +233,91 @@ export async function knowledgeStats(options: KnowledgeOptions): Promise<void> {
|
|
|
203
233
|
byLayer[entry.layer] = (byLayer[entry.layer] || 0) + 1;
|
|
204
234
|
}
|
|
205
235
|
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
const refCoverage = active.length > 0 ? Math.round(withRefs / active.length * 100) : 0;
|
|
209
|
-
const avgRefs = active.length > 0
|
|
210
|
-
? Math.round(active.reduce((sum, e) => sum + e.referencedBy.length, 0) / active.length * 10) / 10
|
|
211
|
-
: 0;
|
|
212
|
-
let consumptionHitRate = 0;
|
|
236
|
+
// 飞轮指标:计算唯一实现在 knowledge/flywheel-metrics,此处只做 fs 读取 + 展示层单位映射
|
|
237
|
+
let dailyConsumptionEvents = 0;
|
|
213
238
|
try {
|
|
214
239
|
const statsPath = path.join(store.getBaseDir(), '.consumption-stats.json');
|
|
215
240
|
if (fs.existsSync(statsPath)) {
|
|
216
241
|
const stats = JSON.parse(fs.readFileSync(statsPath, 'utf-8'));
|
|
217
|
-
|
|
218
|
-
consumptionHitRate = active.length > 0 ? Math.min(Math.round(dailyEvents / active.length * 100), 100) : 0;
|
|
242
|
+
dailyConsumptionEvents = stats.dailyEvents || 0;
|
|
219
243
|
}
|
|
220
244
|
} catch { /* best-effort */ }
|
|
221
245
|
|
|
246
|
+
const metrics = evaluateFlywheel({ entries: active, dailyConsumptionEvents });
|
|
247
|
+
const refCoverage = Math.round(metrics.refCoverage * 100);
|
|
248
|
+
const avgRefs = Math.round(metrics.avgRefs * 10) / 10;
|
|
249
|
+
const consumptionHitRate = Math.round(metrics.consumptionHitRate * 100);
|
|
250
|
+
|
|
222
251
|
const flywheel = { refCoverage, avgRefs, consumptionHitRate };
|
|
223
252
|
|
|
224
253
|
if (options.json) {
|
|
225
|
-
|
|
226
|
-
return;
|
|
254
|
+
log(io, JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
|
|
255
|
+
return { kind: 'ok' };
|
|
227
256
|
}
|
|
228
257
|
|
|
229
|
-
|
|
230
|
-
|
|
258
|
+
log(io, chalk.blue(`📊 知识库统计\n`));
|
|
259
|
+
log(io, chalk.bold(` 总计: ${entries.length} 条 (活跃: ${active.length})\n`));
|
|
231
260
|
|
|
232
|
-
|
|
261
|
+
log(io, chalk.bold(' 按类型:'));
|
|
233
262
|
for (const [type, count] of Object.entries(byType)) {
|
|
234
|
-
|
|
263
|
+
log(io, ` ${type}: ${count}`);
|
|
235
264
|
}
|
|
236
265
|
|
|
237
|
-
|
|
266
|
+
log(io, chalk.bold('\n 按成熟度:'));
|
|
238
267
|
for (const [maturity, count] of Object.entries(byMaturity)) {
|
|
239
268
|
const color = maturity === 'proven' ? chalk.green : maturity === 'archived' ? chalk.gray : chalk.yellow;
|
|
240
|
-
|
|
269
|
+
log(io, ` ${color(maturity)}: ${count}`);
|
|
241
270
|
}
|
|
242
271
|
|
|
243
|
-
|
|
272
|
+
log(io, chalk.bold('\n 按层级:'));
|
|
244
273
|
for (const [layer, count] of Object.entries(byLayer)) {
|
|
245
|
-
|
|
274
|
+
log(io, ` ${layer}: ${count}`);
|
|
246
275
|
}
|
|
247
276
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export interface KnowledgeUpsertOptions {
|
|
255
|
-
scope: string;
|
|
256
|
-
title: string;
|
|
257
|
-
content?: string;
|
|
258
|
-
file?: string;
|
|
259
|
-
type?: string;
|
|
260
|
-
source?: string;
|
|
277
|
+
log(io, chalk.bold('\n 飞轮指标:'));
|
|
278
|
+
log(io, ` 引用覆盖: ${refCoverage}%`);
|
|
279
|
+
log(io, ` 平均引用: ${avgRefs}`);
|
|
280
|
+
log(io, ` 消费命中率: ${consumptionHitRate}%`);
|
|
281
|
+
return { kind: 'ok' };
|
|
261
282
|
}
|
|
262
283
|
|
|
263
|
-
/**
|
|
264
|
-
* 设计时知识沉淀:写入 KnowledgeStore + 同步 Prisma Document(Studio UI 可见)
|
|
265
|
-
*
|
|
266
|
-
* 调用 Studio API POST /api/knowledge/upsert(内部端点,无 auth)
|
|
267
|
-
*/
|
|
268
|
-
export async function knowledgeUpsert(options: KnowledgeUpsertOptions): Promise<void> {
|
|
269
|
-
const apiPort = process.env.API_PORT || '3001';
|
|
270
|
-
const url = `http://localhost:${apiPort}/api/knowledge/upsert`;
|
|
271
|
-
|
|
272
|
-
// Read content from file if --file specified
|
|
273
|
-
let content = options.content || '';
|
|
274
|
-
if (options.file && !content) {
|
|
275
|
-
try {
|
|
276
|
-
content = fs.readFileSync(options.file, 'utf-8');
|
|
277
|
-
} catch (e: any) {
|
|
278
|
-
console.error(chalk.red(`Failed to read file: ${options.file}`));
|
|
279
|
-
console.error(chalk.red(String(e)));
|
|
280
|
-
process.exit(1);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (!options.scope || !options.title || !content) {
|
|
285
|
-
console.error(chalk.red('--scope, --title, and --content (or --file) are required'));
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
try {
|
|
290
|
-
const res = await fetch(url, {
|
|
291
|
-
method: 'POST',
|
|
292
|
-
headers: { 'Content-Type': 'application/json' },
|
|
293
|
-
body: JSON.stringify({
|
|
294
|
-
scope: options.scope,
|
|
295
|
-
title: options.title,
|
|
296
|
-
content,
|
|
297
|
-
type: options.type || 'architecture',
|
|
298
|
-
source: options.source || 'cli',
|
|
299
|
-
}),
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
if (!res.ok) {
|
|
303
|
-
const err: any = await res.json().catch(() => ({ error: res.statusText }));
|
|
304
|
-
console.error(chalk.red(`API error ${res.status}: ${err.error || res.statusText}`));
|
|
305
|
-
process.exit(1);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const result: any = await res.json();
|
|
309
|
-
console.log(chalk.green(`✅ Knowledge upserted`));
|
|
310
|
-
console.log(` KnowledgeStore: ${result.knowledgeStore?.action} → ${result.knowledgeStore?.entryId}`);
|
|
311
|
-
console.log(` Studio UI: ${result.prismaDocument?.action} → ${result.prismaDocument?.docId || 'skipped'}`);
|
|
312
|
-
} catch (e: any) {
|
|
313
|
-
if (e?.code === 'ECONNREFUSED') {
|
|
314
|
-
console.error(chalk.red(`Cannot reach Studio API at ${url}. Is the API running?`));
|
|
315
|
-
} else {
|
|
316
|
-
console.error(chalk.red(`Upsert failed: ${e.message}`));
|
|
317
|
-
}
|
|
318
|
-
process.exit(1);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
284
|
/**
|
|
324
285
|
* RAG 同步:扫描 .harness/knowledge-docs/ 输出需要 ingest 的文件列表
|
|
325
286
|
*/
|
|
326
|
-
export async function knowledgeSyncRag(options: KnowledgeOptions): Promise<
|
|
287
|
+
export async function knowledgeSyncRag(options: KnowledgeOptions, io: CommandIO = processIO): Promise<CommandResult> {
|
|
327
288
|
const projectPath = options.projectPath || process.cwd();
|
|
328
289
|
const docsDir = `${projectPath}/.harness/knowledge-docs`;
|
|
329
290
|
|
|
330
291
|
if (!fs.existsSync(docsDir)) {
|
|
331
|
-
|
|
332
|
-
return;
|
|
292
|
+
log(io, chalk.yellow('No .harness/knowledge-docs/ directory'));
|
|
293
|
+
return { kind: 'ok' };
|
|
333
294
|
}
|
|
334
295
|
|
|
335
296
|
const files = fs.readdirSync(docsDir).filter(f => f.endsWith('.md'));
|
|
336
297
|
if (files.length === 0) {
|
|
337
|
-
|
|
338
|
-
return;
|
|
298
|
+
log(io, chalk.gray('No knowledge docs found'));
|
|
299
|
+
return { kind: 'ok' };
|
|
339
300
|
}
|
|
340
301
|
|
|
341
302
|
if (options.json) {
|
|
342
|
-
|
|
343
|
-
return;
|
|
303
|
+
log(io, JSON.stringify({ directory: docsDir, files }, null, 2));
|
|
304
|
+
return { kind: 'ok' };
|
|
344
305
|
}
|
|
345
306
|
|
|
346
|
-
|
|
307
|
+
log(io, chalk.blue(`📄 RAG sync candidates: ${files.length} files in ${docsDir}\n`));
|
|
347
308
|
for (const file of files) {
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
console.log();
|
|
351
|
-
console.log(chalk.gray('Run `mcp__local-rag__ingest_file` for each to sync to RAG'));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* 知识同步状态:检测所有 tracked scope 的新鲜度
|
|
356
|
-
*/
|
|
357
|
-
export async function knowledgeSyncStatus(options: KnowledgeOptions): Promise<void> {
|
|
358
|
-
const apiPort = process.env.API_PORT || '3001';
|
|
359
|
-
const url = `http://localhost:${apiPort}/api/knowledge/sync-status`;
|
|
360
|
-
|
|
361
|
-
try {
|
|
362
|
-
const res = await fetch(url);
|
|
363
|
-
if (!res.ok) {
|
|
364
|
-
const err: any = await res.json().catch(() => ({ error: res.statusText }));
|
|
365
|
-
console.error(chalk.red(`API error ${res.status}: ${err.error || res.statusText}`));
|
|
366
|
-
process.exit(1);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const data: any = await res.json();
|
|
370
|
-
|
|
371
|
-
if (options.json) {
|
|
372
|
-
console.log(JSON.stringify(data, null, 2));
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
console.log(chalk.blue(`🔄 KnowledgeSync Status\n`));
|
|
377
|
-
console.log(chalk.bold(`Tracked scopes: ${data.trackedScopes?.join(', ') || 'none'}`));
|
|
378
|
-
console.log(chalk.bold(`Stale entries: ${data.stale?.length || 0}`));
|
|
379
|
-
|
|
380
|
-
if (data.stale?.length > 0) {
|
|
381
|
-
console.log(chalk.yellow(`\n⚠️ Stale knowledge:\n`));
|
|
382
|
-
for (const s of data.stale) {
|
|
383
|
-
console.log(chalk.yellow(` ${s.scope} (${s.title}): ${s.stalenessHours}h old, files changed: ${s.changedFiles.join(', ')}`));
|
|
384
|
-
}
|
|
385
|
-
} else {
|
|
386
|
-
console.log(chalk.green('\n✅ All knowledge fresh'));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (data.healed?.length > 0) {
|
|
390
|
-
console.log(chalk.cyan(`\n🩹 Auto-healed: ${data.healed.join(', ')}`));
|
|
391
|
-
}
|
|
392
|
-
} catch (e: any) {
|
|
393
|
-
if (e?.code === 'ECONNREFUSED') {
|
|
394
|
-
console.error(chalk.red(`Cannot reach Studio API at ${url}`));
|
|
395
|
-
} else {
|
|
396
|
-
console.error(chalk.red(`Sync check failed: ${e.message}`));
|
|
397
|
-
}
|
|
398
|
-
process.exit(1);
|
|
309
|
+
log(io, chalk.cyan(` ${file}`));
|
|
399
310
|
}
|
|
311
|
+
log(io);
|
|
312
|
+
log(io, chalk.gray('Run `mcp__local-rag__ingest_file` for each to sync to RAG'));
|
|
313
|
+
return { kind: 'ok' };
|
|
400
314
|
}
|
|
401
315
|
|
|
402
316
|
/**
|
|
403
317
|
* 飞轮健康检查 — 零 token 检测知识飞轮数据流状态
|
|
404
318
|
*/
|
|
405
|
-
export async function knowledgeHealth(options: KnowledgeOptions & { dir?: string }): Promise<
|
|
406
|
-
const baseDir = options.dir || getKnowledgeDir(options.projectPath);
|
|
319
|
+
export async function knowledgeHealth(options: KnowledgeOptions & { dir?: string }, io: CommandIO = processIO): Promise<CommandResult> {
|
|
320
|
+
const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
|
|
407
321
|
const store = new KnowledgeStore({ baseDir });
|
|
408
322
|
const entries = store.list({ excludeArchived: true });
|
|
409
323
|
|
|
@@ -439,12 +353,10 @@ export async function knowledgeHealth(options: KnowledgeOptions & { dir?: string
|
|
|
439
353
|
issues.push({ severity: 'info', entry: '-', detail: `消费追踪数据不存在(${statsPath})` });
|
|
440
354
|
}
|
|
441
355
|
|
|
442
|
-
// D4:
|
|
443
|
-
const
|
|
444
|
-
const refCoverage =
|
|
445
|
-
const avgRefs =
|
|
446
|
-
? Math.round(entries.reduce((sum, e) => sum + e.referencedBy.length, 0) / entries.length * 10) / 10
|
|
447
|
-
: 0;
|
|
356
|
+
// D4: 飞轮指标(计算唯一实现在 knowledge/flywheel-metrics;人口为本命令的 excludeArchived 切片)
|
|
357
|
+
const metrics = evaluateFlywheel({ entries });
|
|
358
|
+
const refCoverage = Math.round(metrics.refCoverage * 100);
|
|
359
|
+
const avgRefs = Math.round(metrics.avgRefs * 10) / 10;
|
|
448
360
|
|
|
449
361
|
// 健康分计算
|
|
450
362
|
const totalIssues = issues.filter(i => i.severity === 'error').length * 3
|
|
@@ -452,7 +364,7 @@ export async function knowledgeHealth(options: KnowledgeOptions & { dir?: string
|
|
|
452
364
|
const healthScore = Math.max(0, 100 - totalIssues);
|
|
453
365
|
|
|
454
366
|
if (options.json) {
|
|
455
|
-
|
|
367
|
+
log(io, JSON.stringify({
|
|
456
368
|
healthScore,
|
|
457
369
|
summary: {
|
|
458
370
|
total: entries.length,
|
|
@@ -464,39 +376,40 @@ export async function knowledgeHealth(options: KnowledgeOptions & { dir?: string
|
|
|
464
376
|
},
|
|
465
377
|
issues: issues.slice(0, 50),
|
|
466
378
|
}, null, 2));
|
|
467
|
-
return;
|
|
379
|
+
return { kind: 'ok' };
|
|
468
380
|
}
|
|
469
381
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
382
|
+
log(io, chalk.blue('🏥 飞轮健康检查\n'));
|
|
383
|
+
log(io, chalk.bold(` 健康分: ${healthScore >= 80 ? chalk.green(healthScore) : healthScore >= 60 ? chalk.yellow(healthScore) : chalk.red(healthScore)}/100`));
|
|
384
|
+
log(io, chalk.bold(` 活跃条目: ${entries.length}`));
|
|
385
|
+
log(io);
|
|
474
386
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
387
|
+
log(io, chalk.bold(' 数据流状态:'));
|
|
388
|
+
log(io, ` 引用密度: ${lowRefEntries === 0 ? chalk.green('✓') : chalk.yellow(`⚠ ${lowRefEntries} 个零引用 verified`)}`);
|
|
389
|
+
log(io, ` 新鲜度: ${staleEntries === 0 ? chalk.green('✓') : chalk.yellow(`⚠ ${staleEntries} 个过期 draft`)}`);
|
|
390
|
+
log(io, ` 消费追踪: ${consumptionData ? chalk.green('✓') : chalk.gray('○ 未启用')}`);
|
|
391
|
+
log(io);
|
|
480
392
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
393
|
+
log(io, chalk.bold(' 飞轮指标:'));
|
|
394
|
+
log(io, ` 引用覆盖: ${refCoverage}%`);
|
|
395
|
+
log(io, ` 平均引用: ${avgRefs}`);
|
|
396
|
+
log(io);
|
|
485
397
|
|
|
486
398
|
if (issues.length > 0) {
|
|
487
|
-
|
|
399
|
+
log(io, chalk.bold(` 问题 (前 20):`));
|
|
488
400
|
for (const issue of issues.slice(0, 20)) {
|
|
489
401
|
const sevColor = issue.severity === 'error' ? chalk.red
|
|
490
402
|
: issue.severity === 'warn' ? chalk.yellow
|
|
491
403
|
: chalk.gray;
|
|
492
|
-
|
|
404
|
+
log(io, ` ${sevColor(`[${issue.severity}]`)} ${issue.entry}: ${issue.detail}`);
|
|
493
405
|
}
|
|
494
406
|
if (issues.length > 20) {
|
|
495
|
-
|
|
407
|
+
log(io, chalk.gray(` ... 还有 ${issues.length - 20} 条`));
|
|
496
408
|
}
|
|
497
409
|
} else {
|
|
498
|
-
|
|
410
|
+
log(io, chalk.green(' ✓ 无问题'));
|
|
499
411
|
}
|
|
412
|
+
return { kind: 'ok' };
|
|
500
413
|
}
|
|
501
414
|
|
|
502
415
|
/** 缺省知识库数据根(相对用户 home) */
|
|
@@ -514,7 +427,7 @@ function hasKnowledgeData(dir: string): boolean {
|
|
|
514
427
|
}
|
|
515
428
|
}
|
|
516
429
|
|
|
517
|
-
function getKnowledgeDir(projectPath
|
|
430
|
+
function getKnowledgeDir(projectPath: string | undefined, io: CommandIO): string {
|
|
518
431
|
if (projectPath) return `${projectPath}/.harness/knowledge`;
|
|
519
432
|
if (process.env.KNOWLEDGE_BASE_DIR) return process.env.KNOWLEDGE_BASE_DIR;
|
|
520
433
|
const defaultDir = path.join(os.homedir(), KNOWLEDGE_DATA_DIR);
|
|
@@ -523,7 +436,7 @@ function getKnowledgeDir(projectPath?: string): string {
|
|
|
523
436
|
if (!legacyKnowledgeDirNotified) {
|
|
524
437
|
legacyKnowledgeDirNotified = true;
|
|
525
438
|
// stderr:不污染 --json 的 stdout 输出
|
|
526
|
-
|
|
439
|
+
logError(io, chalk.yellow(`⚠ 缺省知识库根已改为 ${defaultDir};旧目录 ${legacyDir} 仍有数据,本次沿用(免迁移,可用 KNOWLEDGE_BASE_DIR 覆盖)`));
|
|
527
440
|
}
|
|
528
441
|
return legacyDir;
|
|
529
442
|
}
|
|
@@ -538,154 +451,143 @@ export async function knowledgeAudit(options: KnowledgeOptions & {
|
|
|
538
451
|
dryRun?: boolean;
|
|
539
452
|
threshold?: number;
|
|
540
453
|
dir?: string;
|
|
541
|
-
}): Promise<
|
|
454
|
+
}, io: CommandIO = processIO): Promise<CommandResult> {
|
|
542
455
|
const audit = new KnowledgeAudit({
|
|
543
|
-
baseDir: options.dir || getKnowledgeDir(options.projectPath),
|
|
456
|
+
baseDir: options.dir || getKnowledgeDir(options.projectPath, io),
|
|
544
457
|
shortContentThreshold: options.threshold ? parseInt(options.threshold as any, 10) : undefined,
|
|
545
458
|
});
|
|
546
459
|
|
|
547
460
|
const isDryRun = options.dryRun && !options.fix;
|
|
548
461
|
|
|
549
462
|
if (!options.json && !isDryRun) {
|
|
550
|
-
|
|
463
|
+
log(io, chalk.blue('🔍 知识库质量审计...\n'));
|
|
551
464
|
}
|
|
552
465
|
|
|
553
466
|
const report = audit.run({ autoFix: options.fix && !isDryRun });
|
|
554
467
|
|
|
555
468
|
if (options.json) {
|
|
556
|
-
|
|
557
|
-
return;
|
|
469
|
+
log(io, JSON.stringify(report, null, 2));
|
|
470
|
+
return { kind: 'ok' };
|
|
558
471
|
}
|
|
559
472
|
|
|
560
473
|
// Summary
|
|
561
|
-
|
|
562
|
-
|
|
474
|
+
log(io, chalk.bold(` 总条目: ${report.totalEntries}`));
|
|
475
|
+
log(io, chalk.bold(` 健康分: ${report.healthScore.before}/100`));
|
|
563
476
|
if (report.autoFixed > 0) {
|
|
564
|
-
|
|
565
|
-
|
|
477
|
+
log(io, chalk.green(` 自动修复: ${report.autoFixed} 条`));
|
|
478
|
+
log(io, chalk.bold(` 修复后: ${report.healthScore.after}/100`));
|
|
566
479
|
}
|
|
567
|
-
|
|
480
|
+
log(io);
|
|
568
481
|
|
|
569
|
-
// Dimension scores
|
|
570
|
-
const dimLabels: Record<
|
|
482
|
+
// Dimension scores(Record 全键标注 → 编译期闭环,#109)
|
|
483
|
+
const dimLabels: Record<keyof AuditReport['dimensions'], string> = {
|
|
571
484
|
structure: 'D1 结构完整性',
|
|
572
485
|
content: 'D2 内容质量',
|
|
573
486
|
dedup: 'D3 去重有效性',
|
|
574
487
|
maturity: 'D4 成熟度健康',
|
|
575
488
|
freshness: 'D5 新鲜度',
|
|
576
489
|
flywheel: 'D6 飞轮验证',
|
|
490
|
+
incremental: 'D7 增量存活',
|
|
577
491
|
};
|
|
578
|
-
|
|
492
|
+
log(io, chalk.bold(' 维度评分:'));
|
|
579
493
|
for (const [key, dim] of Object.entries(report.dimensions)) {
|
|
580
|
-
const label = dimLabels[key
|
|
494
|
+
const label = dimLabels[key as keyof AuditReport['dimensions']];
|
|
581
495
|
const scoreColor = dim.score >= 80 ? chalk.green : dim.score >= 60 ? chalk.yellow : chalk.red;
|
|
582
|
-
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
// Issues by rule
|
|
587
|
-
const ruleLabels: Record<string, string> = {
|
|
588
|
-
'frontmatter-missing': 'frontmatter 缺失',
|
|
589
|
-
'test-data-pollution': '测试数据污染',
|
|
590
|
-
'daily-audit-noise': '每日审计噪音',
|
|
591
|
-
'zero-content-proven': '零内容 proven',
|
|
592
|
-
'short-content': '短内容',
|
|
593
|
-
'maturity-inflation': '成熟度虚高',
|
|
594
|
-
'title-duplicate': '标题重复',
|
|
595
|
-
'source-refs-bloat': 'sourceReferences 膨胀',
|
|
596
|
-
'fragment-cluster': '碎片集群',
|
|
597
|
-
'promotion-blocked': 'promotion 受阻',
|
|
598
|
-
'orphan-draft': '孤儿 draft',
|
|
599
|
-
'stale-entry': '过期条目',
|
|
600
|
-
};
|
|
496
|
+
log(io, ` ${label}: ${scoreColor(`${dim.score}/100`)} (${dim.issues} 问题)`);
|
|
497
|
+
}
|
|
498
|
+
log(io);
|
|
601
499
|
|
|
500
|
+
// Issues by rule(label 正本在 audit.ts 规则定义,AUDIT_RULE_LABELS 编译期闭环,#109)
|
|
602
501
|
for (const [rule, count] of Object.entries(report.summary)) {
|
|
603
502
|
if (count === 0) continue;
|
|
604
|
-
const label =
|
|
605
|
-
|
|
503
|
+
const label = AUDIT_RULE_LABELS[rule as AuditRuleName];
|
|
504
|
+
log(io, ` ${chalk.red(`${label}: ${count}`)}`);
|
|
606
505
|
}
|
|
607
506
|
|
|
608
507
|
// Detail (first 20)
|
|
609
508
|
if (report.issues.length > 0) {
|
|
610
|
-
|
|
509
|
+
log(io, chalk.bold(`\n 问题详情 (前 20 条):\n`));
|
|
611
510
|
for (const issue of report.issues.slice(0, 20)) {
|
|
612
511
|
const severityColor = issue.severity === 'critical' ? chalk.red
|
|
613
512
|
: issue.severity === 'high' ? chalk.yellow
|
|
614
513
|
: chalk.gray;
|
|
615
|
-
|
|
616
|
-
|
|
514
|
+
log(io, ` ${severityColor(`[${issue.severity}]`)} ${issue.entryId}: ${issue.title}`);
|
|
515
|
+
log(io, ` ${chalk.gray(issue.detail)} → ${issue.action}`);
|
|
617
516
|
}
|
|
618
517
|
if (report.issues.length > 20) {
|
|
619
|
-
|
|
518
|
+
log(io, chalk.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
|
|
620
519
|
}
|
|
621
520
|
}
|
|
622
521
|
|
|
623
522
|
if (!options.fix && report.issues.length > 0) {
|
|
624
|
-
|
|
523
|
+
log(io, chalk.yellow(`\n 使用 --fix 自动修复`));
|
|
625
524
|
}
|
|
626
525
|
|
|
627
526
|
// Auto-rebuild index after audit (files may have changed)
|
|
628
|
-
const baseDir = options.dir || getKnowledgeDir(options.projectPath);
|
|
527
|
+
const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
|
|
629
528
|
const idxGen = new KnowledgeIndexGenerator(baseDir);
|
|
630
529
|
idxGen.regenerate();
|
|
631
530
|
if (!options.json) {
|
|
632
|
-
|
|
531
|
+
log(io, chalk.gray(` 📇 索引已重建`));
|
|
633
532
|
}
|
|
533
|
+
return { kind: 'ok' };
|
|
634
534
|
}
|
|
635
535
|
|
|
636
536
|
/**
|
|
637
537
|
* 知识库快照(KR4 存活率追踪)
|
|
638
538
|
*/
|
|
639
|
-
export function knowledgeSnapshot(options: KnowledgeOptions & { dir?: string }):
|
|
640
|
-
const store = new KnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath) });
|
|
539
|
+
export function knowledgeSnapshot(options: KnowledgeOptions & { dir?: string }, io: CommandIO = processIO): CommandResult {
|
|
540
|
+
const store = new KnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath, io) });
|
|
641
541
|
const snapPath = store.snapshot();
|
|
642
542
|
|
|
643
543
|
if (options.json) {
|
|
644
|
-
|
|
645
|
-
return;
|
|
544
|
+
log(io, JSON.stringify({ snapshotPath: snapPath }));
|
|
545
|
+
return { kind: 'ok' };
|
|
646
546
|
}
|
|
647
547
|
|
|
648
|
-
|
|
548
|
+
log(io, chalk.green(`✅ 快照已保存: ${snapPath}`));
|
|
549
|
+
return { kind: 'ok' };
|
|
649
550
|
}
|
|
650
551
|
|
|
651
552
|
/**
|
|
652
553
|
* 知识库迁移 — 为现有条目添加 AS-021 新字段
|
|
653
554
|
*/
|
|
654
|
-
export function knowledgeMigrate(options: KnowledgeOptions & { dir?: string }):
|
|
655
|
-
const baseDir = options.dir || getKnowledgeDir(options.projectPath);
|
|
555
|
+
export function knowledgeMigrate(options: KnowledgeOptions & { dir?: string }, io: CommandIO = processIO): CommandResult {
|
|
556
|
+
const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
|
|
656
557
|
|
|
657
558
|
if (options.json) {
|
|
658
559
|
const result = migrateKnowledgeEntries(baseDir);
|
|
659
|
-
|
|
660
|
-
return;
|
|
560
|
+
log(io, JSON.stringify(result, null, 2));
|
|
561
|
+
return { kind: 'ok' };
|
|
661
562
|
}
|
|
662
563
|
|
|
663
|
-
|
|
564
|
+
log(io, chalk.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
|
|
664
565
|
const result = migrateKnowledgeEntries(baseDir);
|
|
665
566
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
567
|
+
log(io, chalk.green(` 总计: ${result.total} 条`));
|
|
568
|
+
log(io, chalk.green(` 已迁移: ${result.migrated} 条`));
|
|
569
|
+
log(io, chalk.gray(` 已跳过: ${result.skipped} 条`));
|
|
669
570
|
|
|
670
571
|
if (result.errors.length > 0) {
|
|
671
|
-
|
|
572
|
+
log(io, chalk.red(`\n 错误: ${result.errors.length} 条`));
|
|
672
573
|
for (const err of result.errors.slice(0, 5)) {
|
|
673
|
-
|
|
574
|
+
log(io, chalk.red(` ${err}`));
|
|
674
575
|
}
|
|
675
576
|
}
|
|
676
577
|
|
|
677
578
|
if (result.migrated === 0 && result.errors.length === 0) {
|
|
678
|
-
|
|
579
|
+
log(io, chalk.green('\n✅ 所有条目已是最新,无需迁移'));
|
|
679
580
|
} else if (result.migrated > 0) {
|
|
680
|
-
|
|
581
|
+
log(io, chalk.green(`\n✅ 迁移完成`));
|
|
681
582
|
}
|
|
583
|
+
return { kind: 'ok' };
|
|
682
584
|
}
|
|
683
585
|
|
|
684
586
|
/**
|
|
685
587
|
* 知识库索引重建 — 生成 _index.md 供 Agent grep 使用,同时同步 index.json
|
|
686
588
|
*/
|
|
687
|
-
export function knowledgeIndex(options: KnowledgeOptions & { dir?: string }):
|
|
688
|
-
const baseDir = options.dir || getKnowledgeDir(options.projectPath);
|
|
589
|
+
export function knowledgeIndex(options: KnowledgeOptions & { dir?: string }, io: CommandIO = processIO): CommandResult {
|
|
590
|
+
const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
|
|
689
591
|
const gen = new KnowledgeIndexGenerator(baseDir);
|
|
690
592
|
|
|
691
593
|
const beforeSize = (() => {
|
|
@@ -703,20 +605,21 @@ export function knowledgeIndex(options: KnowledgeOptions & { dir?: string }): vo
|
|
|
703
605
|
const lineCount = output.split('\n').filter(l => !l.startsWith('#')).length;
|
|
704
606
|
|
|
705
607
|
if (options.json) {
|
|
706
|
-
|
|
608
|
+
log(io, JSON.stringify({
|
|
707
609
|
path: path.join(baseDir, '_index.md'),
|
|
708
610
|
entries: lineCount,
|
|
709
611
|
size: afterSize,
|
|
710
612
|
previousSize: beforeSize,
|
|
711
613
|
}));
|
|
712
|
-
return;
|
|
614
|
+
return { kind: 'ok' };
|
|
713
615
|
}
|
|
714
616
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
617
|
+
log(io, chalk.blue(`📇 索引已重建`));
|
|
618
|
+
log(io, chalk.gray(` 路径: ${path.join(baseDir, '_index.md')}`));
|
|
619
|
+
log(io, chalk.green(` 条目: ${lineCount}`));
|
|
620
|
+
log(io, chalk.green(` 大小: ${(afterSize / 1024).toFixed(1)} KB`));
|
|
719
621
|
if (beforeSize > 0) {
|
|
720
|
-
|
|
622
|
+
log(io, chalk.gray(` 旧大小: ${(beforeSize / 1024).toFixed(1)} KB`));
|
|
721
623
|
}
|
|
624
|
+
return { kind: 'ok' };
|
|
722
625
|
}
|