@dommaker/harness 1.7.0 → 1.8.1
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 +44 -0
- package/bin/harness.js +17 -1
- package/dist/agents/index.d.ts +6 -2
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -16
- package/dist/agents/index.js.map +1 -1
- package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
- package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/gate-decision.js +26 -0
- package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +17 -28
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/check.d.ts +19 -3
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +36 -22
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +0 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +8 -6
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +36 -57
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +36 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +2 -0
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +11 -6
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +16 -2
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +14 -8
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +172 -364
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge-view.d.ts +90 -0
- package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
- package/dist/cli/commands/knowledge-view.js +198 -0
- package/dist/cli/commands/knowledge-view.js.map +1 -0
- package/dist/cli/commands/knowledge.d.ts +137 -52
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +534 -400
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +4 -1
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +11 -2
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +19 -31
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +2 -1
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +13 -25
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/scaffold-templates.d.ts +73 -0
- package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
- package/dist/cli/commands/scaffold-templates.js +424 -0
- package/dist/cli/commands/scaffold-templates.js.map +1 -0
- package/dist/cli/commands/scaffold.d.ts +105 -0
- package/dist/cli/commands/scaffold.d.ts.map +1 -0
- package/dist/cli/commands/scaffold.js +263 -0
- package/dist/cli/commands/scaffold.js.map +1 -0
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +22 -24
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +109 -34
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/status.d.ts +8 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +5 -7
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +86 -27
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +33 -7
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +0 -16
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +2 -97
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/gate-command.d.ts +37 -0
- package/dist/cli/gate-command.d.ts.map +1 -0
- package/dist/cli/gate-command.js +64 -0
- package/dist/cli/gate-command.js.map +1 -0
- package/dist/cli/state-io.d.ts +34 -0
- package/dist/cli/state-io.d.ts.map +1 -0
- package/dist/cli/state-io.js +71 -0
- package/dist/cli/state-io.js.map +1 -0
- package/dist/completion-checkers/index.d.ts +1 -1
- package/dist/completion-checkers/index.d.ts.map +1 -1
- package/dist/completion-checkers/index.js +0 -15
- package/dist/completion-checkers/index.js.map +1 -1
- package/dist/context/knowledge-injector.d.ts +4 -2
- package/dist/context/knowledge-injector.d.ts.map +1 -1
- package/dist/context/knowledge-injector.js +13 -6
- package/dist/context/knowledge-injector.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +2 -2
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.js +26 -4
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
- package/dist/core/constraints/check-cache.d.ts +1 -1
- package/dist/core/constraints/check-cache.js +1 -1
- package/dist/core/constraints/checker.d.ts +8 -3
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +30 -19
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +17 -24
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
- 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 +24 -30
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +10 -4
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +10 -6
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +7 -3
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/context-builder.d.ts +11 -10
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +31 -27
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/context-reconcile.d.ts +75 -0
- package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/context-reconcile.js +161 -0
- package/dist/core/constraints/context-reconcile.js.map +1 -0
- package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +8 -3
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.js +1 -1
- package/dist/core/constraints/git-evidence.js.map +1 -1
- package/dist/core/constraints/injection-drift.d.ts +7 -2
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +13 -7
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/run-env.d.ts +92 -0
- package/dist/core/constraints/run-env.d.ts.map +1 -0
- package/dist/core/constraints/run-env.js +175 -0
- package/dist/core/constraints/run-env.js.map +1 -0
- package/dist/core/constraints/triggers.d.ts +22 -0
- package/dist/core/constraints/triggers.d.ts.map +1 -0
- package/dist/core/constraints/triggers.js +31 -0
- package/dist/core/constraints/triggers.js.map +1 -0
- package/dist/core/effective-constraints.d.ts +13 -4
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +16 -6
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/effective-set.d.ts +8 -15
- package/dist/core/effective-set.d.ts.map +1 -1
- package/dist/core/effective-set.js +7 -12
- package/dist/core/effective-set.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +39 -17
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +51 -122
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/check-handlers/http.d.ts +2 -2
- package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
- package/dist/core/validators/check-handlers/http.js +12 -7
- package/dist/core/validators/check-handlers/http.js.map +1 -1
- package/dist/failure/classifier.d.ts +1 -1
- package/dist/failure/classifier.d.ts.map +1 -1
- package/dist/failure/classifier.js +8 -8
- package/dist/failure/classifier.js.map +1 -1
- package/dist/failure/index.d.ts +2 -1
- package/dist/failure/index.d.ts.map +1 -1
- package/dist/failure/index.js +9 -17
- package/dist/failure/index.js.map +1 -1
- package/dist/failure/recorder.d.ts +1 -1
- package/dist/failure/recorder.d.ts.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 +3 -2
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts +10 -4
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +36 -62
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +0 -4
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/definitions.d.ts +2 -1
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +6 -5
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/index.d.ts +0 -4
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js +1 -6
- package/dist/gates/index.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +0 -4
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/runner.d.ts +1 -1
- package/dist/gates/runner.js +1 -1
- package/dist/gates/security.d.ts +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +5 -6
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +14 -17
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +6 -4
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +25 -13
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/hooks/config.d.ts +6 -2
- package/dist/hooks/config.d.ts.map +1 -1
- package/dist/hooks/config.js +5 -1
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -15
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/pipeline.d.ts +19 -1
- package/dist/hooks/pipeline.d.ts.map +1 -1
- package/dist/hooks/pipeline.js +42 -4
- package/dist/hooks/pipeline.js.map +1 -1
- package/dist/hooks/registry.d.ts +11 -8
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/registry.js +22 -7
- package/dist/hooks/registry.js.map +1 -1
- package/dist/hooks/types.d.ts +25 -7
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit-scoring.d.ts +87 -0
- package/dist/knowledge/audit-scoring.d.ts.map +1 -0
- package/dist/knowledge/audit-scoring.js +470 -0
- package/dist/knowledge/audit-scoring.js.map +1 -0
- package/dist/knowledge/audit.d.ts +11 -59
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +47 -522
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +2 -0
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +4 -5
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/index.d.ts +3 -2
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/index.js +3 -16
- package/dist/knowledge/index.js.map +1 -1
- package/dist/knowledge/ingest.js +1 -1
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/lifecycle.d.ts.map +1 -1
- package/dist/knowledge/lifecycle.js +4 -2
- package/dist/knowledge/lifecycle.js.map +1 -1
- package/dist/knowledge/migration.d.ts +3 -0
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +8 -2
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/query.d.ts +6 -0
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +8 -2
- package/dist/knowledge/query.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +4 -6
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +22 -16
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +53 -12
- package/dist/knowledge/store.js.map +1 -1
- package/dist/knowledge/tree-walker.d.ts +19 -0
- package/dist/knowledge/tree-walker.d.ts.map +1 -0
- package/dist/knowledge/tree-walker.js +30 -0
- package/dist/knowledge/tree-walker.js.map +1 -0
- package/dist/knowledge/types.d.ts +16 -0
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/monitoring/traces.d.ts +5 -3
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +19 -5
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
- package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
- package/dist/test-setup/jsonl-fake-fs.js +49 -0
- package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -15
- package/dist/tools/index.js.map +1 -1
- package/dist/types/checkpoint.d.ts +5 -0
- package/dist/types/checkpoint.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +18 -0
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/trace.d.ts +13 -4
- package/dist/types/trace.d.ts.map +1 -1
- package/dist/types/trace.js +4 -3
- package/dist/types/trace.js.map +1 -1
- package/dist/utils/exec.d.ts +4 -27
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +4 -94
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/jsonl.d.ts +17 -7
- package/dist/utils/jsonl.d.ts.map +1 -1
- package/dist/utils/jsonl.js +144 -17
- package/dist/utils/jsonl.js.map +1 -1
- package/dist/utils/numeric-flag.d.ts +44 -0
- package/dist/utils/numeric-flag.d.ts.map +1 -0
- package/dist/utils/numeric-flag.js +62 -0
- package/dist/utils/numeric-flag.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +5 -2
- package/src/__tests__/acceptance-gate.test.ts +7 -4
- package/src/__tests__/checker-extra.test.ts +3 -2
- package/src/__tests__/checker.test.ts +4 -3
- package/src/__tests__/checkpoint.test.ts +26 -9
- package/src/__tests__/context-files-resolution.test.ts +29 -15
- package/src/__tests__/contract-gate.test.ts +19 -40
- package/src/__tests__/error-classifier.test.ts +1 -1
- package/src/__tests__/exec.test.ts +45 -107
- package/src/__tests__/failure-recorder.test.ts +7 -5
- package/src/__tests__/hooks-pipeline.test.ts +34 -47
- package/src/__tests__/layering.test.ts +217 -25
- package/src/__tests__/passes-gate.test.ts +9 -4
- package/src/__tests__/performance-gate.test.ts +3 -15
- package/src/__tests__/project-config-loader-extra.test.ts +31 -57
- package/src/__tests__/project-config-loader.test.ts +6 -3
- package/src/__tests__/public-exports.test.ts +0 -1
- package/src/__tests__/public-type-surface.test.ts +5 -4
- package/src/__tests__/public-value-surface.test.ts +182 -0
- package/src/__tests__/review-gate.test.ts +4 -6
- package/src/__tests__/security-gate.test.ts +5 -20
- package/src/__tests__/skip-semantics.test.ts +5 -3
- package/src/__tests__/spec-validator.test.ts +3 -2
- package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
- package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
- package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
- package/src/__tests__/trace-analyzer.test.ts +5 -3
- package/src/__tests__/trace-collector.test.ts +5 -3
- package/src/agents/index.ts +13 -2
- package/src/cli/__tests__/gate-command.test.ts +162 -0
- package/src/cli/__tests__/state-io.test.ts +50 -0
- package/src/cli/commands/CONTEXT.md +30 -5
- package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
- package/src/cli/commands/__tests__/check-read-count.test.ts +170 -0
- package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
- package/src/cli/commands/__tests__/check.test.ts +63 -44
- package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
- package/src/cli/commands/__tests__/command.test.ts +33 -17
- package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
- package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
- package/src/cli/commands/__tests__/contract.test.ts +20 -20
- package/src/cli/commands/__tests__/failure.test.ts +5 -4
- package/src/cli/commands/__tests__/gate-decision.ts +30 -0
- package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
- package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
- package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
- package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
- package/src/cli/commands/__tests__/init.test.ts +82 -6
- package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
- package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
- package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
- package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
- package/src/cli/commands/__tests__/performance.test.ts +19 -21
- package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
- package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
- package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
- package/src/cli/commands/__tests__/registry.test.ts +2 -0
- package/src/cli/commands/__tests__/report.test.ts +23 -1
- package/src/cli/commands/__tests__/review.test.ts +10 -17
- package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
- package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
- package/src/cli/commands/__tests__/security.test.ts +21 -24
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
- package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
- package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
- package/src/cli/commands/__tests__/status.test.ts +46 -18
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
- package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
- package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
- package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
- package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
- package/src/cli/commands/__tests__/validate.test.ts +1 -48
- package/src/cli/commands/acceptance.ts +24 -29
- package/src/cli/commands/check.ts +60 -35
- package/src/cli/commands/command.ts +9 -8
- package/src/cli/commands/constraints-retire.ts +57 -70
- package/src/cli/commands/contract.ts +44 -47
- package/src/cli/commands/definitions.ts +12 -6
- package/src/cli/commands/failure.ts +16 -3
- package/src/cli/commands/init.ts +242 -389
- package/src/cli/commands/knowledge-view.ts +224 -0
- package/src/cli/commands/knowledge.ts +643 -448
- package/src/cli/commands/passes-gate.ts +12 -3
- package/src/cli/commands/performance.ts +31 -38
- package/src/cli/commands/report.ts +3 -2
- package/src/cli/commands/review.ts +22 -28
- package/src/cli/commands/scaffold-templates.ts +406 -0
- package/src/cli/commands/scaffold.ts +302 -0
- package/src/cli/commands/security.ts +27 -23
- package/src/cli/commands/spec-baseline-check.ts +158 -33
- package/src/cli/commands/status.ts +12 -7
- package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
- package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
- package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
- package/src/cli/commands/sync-docs/index.ts +103 -28
- package/src/cli/commands/sync-docs/project-reader.ts +51 -7
- package/src/cli/commands/validate.ts +1 -104
- package/src/cli/gate-command.ts +87 -0
- package/src/cli/state-io.ts +53 -0
- package/src/completion-checkers/index.ts +10 -1
- package/src/context/CONTEXT.md +2 -1
- package/src/context/__tests__/knowledge-injector.test.ts +27 -0
- package/src/context/__tests__/session-manager.test.ts +19 -12
- package/src/context/knowledge-injector.ts +14 -7
- package/src/core/CONTEXT.md +10 -7
- package/src/core/__tests__/effective-set.test.ts +36 -60
- package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
- package/src/core/constraints/__tests__/run-env.test.ts +377 -0
- package/src/core/constraints/__tests__/triggers.test.ts +70 -0
- package/src/core/constraints/agent-prompt-renderer.ts +1 -1
- package/src/core/constraints/capabilities-reconcile.ts +28 -4
- package/src/core/constraints/check-cache.ts +1 -1
- package/src/core/constraints/checker.ts +30 -14
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
- package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
- package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
- package/src/core/constraints/checkers/capability-sync.ts +27 -28
- package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
- package/src/core/constraints/checkers/docs-freshness.ts +28 -33
- package/src/core/constraints/checkers/governance-presence.ts +10 -6
- package/src/core/constraints/checkers/types.ts +14 -8
- package/src/core/constraints/context-builder.ts +35 -26
- package/src/core/constraints/context-reconcile.ts +200 -0
- package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
- package/src/core/constraints/doc-freshness/runner.ts +18 -4
- package/src/core/constraints/git-evidence.ts +1 -1
- package/src/core/constraints/injection-drift.ts +19 -8
- package/src/core/constraints/run-env.ts +207 -0
- package/src/core/constraints/triggers.ts +33 -0
- package/src/core/effective-constraints.ts +17 -6
- package/src/core/effective-set.ts +8 -24
- package/src/core/index.ts +2 -0
- package/src/core/project-config-loader.ts +54 -102
- package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
- package/src/core/validators/check-handlers/http.ts +18 -7
- package/src/failure/CONTEXT.md +2 -1
- package/src/failure/classifier.ts +2 -2
- package/src/failure/index.ts +14 -2
- package/src/failure/recorder.ts +1 -1
- package/src/gates/CONTEXT.md +13 -7
- package/src/gates/__tests__/checker-gate.test.ts +1 -1
- package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
- package/src/gates/__tests__/command.test.ts +8 -15
- package/src/gates/__tests__/contract.test.ts +5 -5
- package/src/gates/__tests__/gate-interface.test.ts +0 -17
- package/src/gates/__tests__/performance.test.ts +0 -13
- package/src/gates/__tests__/review.test.ts +0 -1
- package/src/gates/__tests__/runner.test.ts +1 -1
- package/src/gates/__tests__/security-default-scan.test.ts +97 -0
- package/src/gates/__tests__/security.test.ts +0 -13
- package/src/gates/checker-gate.ts +3 -2
- package/src/gates/command.ts +51 -74
- package/src/gates/contract.ts +0 -5
- package/src/gates/definitions.ts +6 -5
- package/src/gates/index.ts +0 -5
- package/src/gates/performance.ts +1 -6
- package/src/gates/runner.ts +1 -1
- package/src/gates/security.ts +9 -11
- package/src/gates/types.ts +20 -23
- package/src/hooks/CONTEXT.md +10 -9
- package/src/hooks/__tests__/bootstrap.test.ts +29 -6
- package/src/hooks/__tests__/pipeline.test.ts +133 -17
- package/src/hooks/__tests__/registry.test.ts +51 -3
- package/src/hooks/bootstrap.ts +35 -15
- package/src/hooks/config.ts +6 -2
- package/src/hooks/index.ts +10 -1
- package/src/hooks/pipeline.ts +51 -6
- package/src/hooks/registry.ts +31 -12
- package/src/hooks/types.ts +26 -7
- package/src/index.ts +1 -2
- package/src/knowledge/CONTEXT.md +14 -7
- package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
- package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
- package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
- package/src/knowledge/__tests__/audit.test.ts +291 -208
- package/src/knowledge/__tests__/doctor.test.ts +3 -2
- package/src/knowledge/__tests__/ingest.test.ts +3 -2
- package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
- package/src/knowledge/__tests__/migration.test.ts +35 -6
- package/src/knowledge/__tests__/query.test.ts +3 -2
- package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
- package/src/knowledge/__tests__/store.test.ts +149 -4
- package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
- package/src/knowledge/audit-scoring.ts +589 -0
- package/src/knowledge/audit.ts +55 -599
- package/src/knowledge/import.ts +2 -0
- package/src/knowledge/index-generator.ts +4 -6
- package/src/knowledge/index.ts +27 -2
- package/src/knowledge/ingest.ts +1 -1
- package/src/knowledge/lifecycle.ts +5 -2
- package/src/knowledge/migration.ts +8 -2
- package/src/knowledge/query.ts +8 -1
- package/src/knowledge/reference-tracker.ts +5 -7
- package/src/knowledge/store.ts +75 -16
- package/src/knowledge/tree-walker.ts +29 -0
- package/src/knowledge/types.ts +19 -0
- package/src/monitoring/CONTEXT.md +5 -2
- package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
- package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
- package/src/monitoring/traces.ts +19 -5
- package/src/release/CONTEXT.md +1 -1
- package/src/release/__tests__/integrity.test.ts +21 -12
- package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
- package/src/test-setup/jsonl-fake-fs.ts +59 -0
- package/src/tools/index.ts +5 -1
- package/src/types/checkpoint.ts +6 -0
- package/src/types/project-config.ts +21 -0
- package/src/types/trace.ts +14 -4
- package/src/utils/__tests__/file-walk.test.ts +3 -2
- package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
- package/src/utils/__tests__/jsonl.test.ts +61 -14
- package/src/utils/__tests__/numeric-flag.test.ts +80 -0
- package/src/utils/__tests__/package-version.test.ts +2 -2
- package/src/utils/exec.ts +4 -64
- package/src/utils/jsonl.ts +159 -20
- package/src/utils/numeric-flag.ts +64 -0
- package/dist/failure/types.d.ts +0 -9
- package/dist/failure/types.d.ts.map +0 -1
- package/dist/failure/types.js +0 -25
- package/dist/failure/types.js.map +0 -1
- package/dist/gates/effective-gates.d.ts +0 -30
- package/dist/gates/effective-gates.d.ts.map +0 -1
- package/dist/gates/effective-gates.js +0 -81
- package/dist/gates/effective-gates.js.map +0 -1
- package/src/failure/types.ts +0 -9
- package/src/gates/__tests__/effective-gates.test.ts +0 -77
- package/src/gates/effective-gates.ts +0 -99
package/src/cli/commands/init.ts
CHANGED
|
@@ -8,11 +8,11 @@ import chalk from 'chalk';
|
|
|
8
8
|
import * as fs from 'fs/promises';
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import * as yaml from 'js-yaml';
|
|
11
|
-
import { createExampleCheckpoint, createExampleResolutions } from './validate';
|
|
12
11
|
import { detectSourceRoots } from '../../utils/detect-source-roots';
|
|
13
12
|
import { getHarnessPackageVersion } from '../../utils/package-version';
|
|
14
13
|
import { getEffectiveConstraints } from '../../core/effective-constraints';
|
|
15
|
-
import
|
|
14
|
+
import { loadRawProjectConfig } from '../../core/project-config-loader';
|
|
15
|
+
import type { CiConfig, CiPlatform, GovernanceConfig } from '../../types/project-config';
|
|
16
16
|
import {
|
|
17
17
|
CONSTRAINTS_START_MARKER,
|
|
18
18
|
CONSTRAINTS_END_MARKER,
|
|
@@ -25,25 +25,111 @@ import {
|
|
|
25
25
|
resolveGovernanceLanding,
|
|
26
26
|
GOVERNANCE_HEADING,
|
|
27
27
|
} from '../../core/constraints/injection-writer';
|
|
28
|
-
import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
28
|
+
import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
29
|
+
import {
|
|
30
|
+
runPlan,
|
|
31
|
+
nodeScaffoldFs,
|
|
32
|
+
preCommitHookFile,
|
|
33
|
+
prePushHookFile,
|
|
34
|
+
harnessCheckCiFile,
|
|
35
|
+
customConstraintsFile,
|
|
36
|
+
changelogFile,
|
|
37
|
+
contextDocFile,
|
|
38
|
+
governanceWorkflowFile,
|
|
39
|
+
checkpointsFile,
|
|
40
|
+
resolutionsFile,
|
|
41
|
+
type ManagedFile,
|
|
42
|
+
} from './scaffold';
|
|
43
|
+
import {
|
|
44
|
+
GITHUB_ACTIONS_SNIPPET,
|
|
45
|
+
renderGitLabCiJobs,
|
|
46
|
+
PRE_COMMIT_SNIPPET,
|
|
47
|
+
PRE_PUSH_SNIPPET,
|
|
48
|
+
} from './scaffold-templates';
|
|
29
49
|
|
|
30
50
|
export interface InitOptions {
|
|
31
51
|
/** 项目路径 */
|
|
32
52
|
projectPath?: string;
|
|
33
53
|
/** 预设名称 */
|
|
34
54
|
preset: 'strict' | 'standard' | 'relaxed';
|
|
35
|
-
/**
|
|
55
|
+
/** 治理级别(值域 = `GOVERNANCE_PRESETS` 键集合,非法值在命令入口判 usage-error、零落盘,harness#156) */
|
|
36
56
|
governance?: 'minimal' | 'standard' | 'strict';
|
|
37
|
-
/** 项目类型 */
|
|
38
|
-
type?: 'node-api' | 'nextjs-app' | 'python-api' | 'custom';
|
|
39
57
|
/** 是否创建 Git hooks */
|
|
40
58
|
gitHooks?: boolean;
|
|
41
|
-
/** 是否创建 GitHub Actions */
|
|
59
|
+
/** 是否创建 GitHub Actions(`--no-github-actions`:已废弃,`--ci none` 的别名) */
|
|
42
60
|
githubActions?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* 服务端 CI 接线平台(`--ci`,harness#143)
|
|
63
|
+
*
|
|
64
|
+
* 值域校验在命令层(bin 把用户敲的字符串原样递进来);缺省时回落 config.yml
|
|
65
|
+
* 的 `ci.platform`,再缺省即 `github`。
|
|
66
|
+
*/
|
|
67
|
+
ci?: CiPlatform | 'none';
|
|
43
68
|
/** 只输出代码片段,不创建文件 */
|
|
44
69
|
printSnippets?: boolean;
|
|
45
70
|
}
|
|
46
71
|
|
|
72
|
+
/** `--ci` 的可取值域(`none` = 不创建任何服务端 CI 文件,治理 CI 面亦不建,即旧 `--no-github-actions`) */
|
|
73
|
+
const CI_FLAG_VALUES: Array<CiPlatform | 'none'> = ['github', 'gitlab', 'none'];
|
|
74
|
+
|
|
75
|
+
/** CI 平台解析结果(`error` 属用法错误,命令层直接非零退出,不落任何文件) */
|
|
76
|
+
type CiResolution =
|
|
77
|
+
| { kind: 'ok'; platform: CiPlatform | 'none'; warning?: string }
|
|
78
|
+
| { kind: 'error'; reason: string };
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 解析 CI 平台(harness#143 决议 ①④):flag > config.yml 的 `ci.platform` > `github`
|
|
82
|
+
*
|
|
83
|
+
* 不做 remote URL 自动检测:init 常跑在首次 push 之前无 remote 可测,而检测错的代价是
|
|
84
|
+
* 静默写错文件。`--no-github-actions` 保留为 `--ci none` 的废弃别名;它与显式
|
|
85
|
+
* `--ci <非 none>` 同时出现时不猜用户意图,判用法错误。
|
|
86
|
+
*/
|
|
87
|
+
function resolveCiPlatform(
|
|
88
|
+
options: InitOptions,
|
|
89
|
+
configured: CiPlatform | 'none' | undefined,
|
|
90
|
+
): CiResolution {
|
|
91
|
+
const flag = options.ci;
|
|
92
|
+
if (flag !== undefined && !CI_FLAG_VALUES.includes(flag)) {
|
|
93
|
+
return {
|
|
94
|
+
kind: 'error',
|
|
95
|
+
reason: `--ci 取值非法: ${String(flag)}(可取 ${CI_FLAG_VALUES.join(' | ')})`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (options.githubActions === false) {
|
|
99
|
+
if (flag !== undefined && flag !== 'none') {
|
|
100
|
+
return {
|
|
101
|
+
kind: 'error',
|
|
102
|
+
reason: `--ci ${flag} 与 --no-github-actions(即 --ci none 的废弃别名)冲突,二选一`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
kind: 'ok',
|
|
107
|
+
platform: 'none',
|
|
108
|
+
warning: '⚠️ --no-github-actions 已废弃,请改用 --ci none',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return { kind: 'ok', platform: flag ?? configured ?? 'github' };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 读 config.yml 已持久化的 `ci.platform`(解析链第二级)
|
|
116
|
+
*
|
|
117
|
+
* 缺失 / 解析失败 / 形状不符一律按未配置处理(与 `getGovernanceConfig` 同一口径:
|
|
118
|
+
* 脏配置不替调用方做决定)。
|
|
119
|
+
*/
|
|
120
|
+
function readConfiguredCiPlatform(projectPath: string): CiPlatform | 'none' | undefined {
|
|
121
|
+
let raw: Record<string, unknown> | undefined;
|
|
122
|
+
try {
|
|
123
|
+
raw = loadRawProjectConfig(projectPath);
|
|
124
|
+
} catch {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const ci = raw?.ci;
|
|
128
|
+
if (ci === null || typeof ci !== 'object') return undefined;
|
|
129
|
+
const platform = (ci as CiConfig).platform;
|
|
130
|
+
return platform !== undefined && CI_FLAG_VALUES.includes(platform) ? platform : undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
47
133
|
/**
|
|
48
134
|
* 默认配置
|
|
49
135
|
*
|
|
@@ -145,15 +231,35 @@ const GOVERNANCE_PRESETS: Record<string, GovernanceConfig> = {
|
|
|
145
231
|
* 初始化项目
|
|
146
232
|
*/
|
|
147
233
|
export async function init(options: InitOptions, io: CommandIO = processIO): Promise<CommandResult> {
|
|
234
|
+
const projectPath = options.projectPath || process.cwd();
|
|
235
|
+
|
|
236
|
+
// CI 平台先解析:用法错误不落任何盘,且 `--print-snippets` 也要按解析出的平台出形
|
|
237
|
+
const ci = resolveCiPlatform(options, readConfiguredCiPlatform(projectPath));
|
|
238
|
+
if (ci.kind === 'error') {
|
|
239
|
+
logError(io, chalk.red(`❌ 用法错误: ${ci.reason}`));
|
|
240
|
+
return { kind: 'usage-error', reason: ci.reason };
|
|
241
|
+
}
|
|
242
|
+
if (ci.warning) log(io, chalk.yellow(ci.warning));
|
|
243
|
+
|
|
244
|
+
// `-g` 值域校验在命令入口(harness#156 裁决 F2,与 #152 脏输入 fail-loud 同判据):
|
|
245
|
+
// 非法值 usage-error、先于任何落盘;合法值域与装配共用同一份 GOVERNANCE_PRESETS 表,
|
|
246
|
+
// github / gitlab / none 三平台同判(bin 把用户敲的字符串原样递进来)。
|
|
247
|
+
// 用 Object.hasOwn 而非 `in`(harness#164):`in` 走原型链,`-g constructor`/`toString`
|
|
248
|
+
// 会穿透校验、把 Object 构造函数写进 configData 并在 yaml.dump 炸成 YAMLException。
|
|
249
|
+
if (options.governance !== undefined && !Object.hasOwn(GOVERNANCE_PRESETS, options.governance)) {
|
|
250
|
+
const reason = `-g/--governance 取值非法: ${String(options.governance)}(可取 ${Object.keys(GOVERNANCE_PRESETS).join(' | ')})`;
|
|
251
|
+
logError(io, chalk.red(`❌ 用法错误: ${reason}`));
|
|
252
|
+
return { kind: 'usage-error', reason };
|
|
253
|
+
}
|
|
254
|
+
|
|
148
255
|
// 只输出代码片段
|
|
149
256
|
if (options.printSnippets) {
|
|
150
|
-
printSnippets(io);
|
|
257
|
+
printSnippets(io, ci.platform, options.governance);
|
|
151
258
|
return { kind: 'ok' };
|
|
152
259
|
}
|
|
153
260
|
|
|
154
261
|
log(io, chalk.blue('🚀 初始化 harness 配置...'));
|
|
155
262
|
|
|
156
|
-
const projectPath = options.projectPath || process.cwd();
|
|
157
263
|
const configDir = path.join(projectPath, '.harness');
|
|
158
264
|
|
|
159
265
|
// 创建配置目录
|
|
@@ -171,6 +277,13 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
|
|
|
171
277
|
log(io, chalk.gray(`治理级别: ${options.governance}`));
|
|
172
278
|
}
|
|
173
279
|
|
|
280
|
+
// 非默认平台才持久化:缺省即 github(旧配置零迁移),裸 init 重写 config.yml 时
|
|
281
|
+
// 也因此不会丢掉已选定的平台
|
|
282
|
+
if (ci.platform !== 'github') {
|
|
283
|
+
configData.ci = { platform: ci.platform };
|
|
284
|
+
log(io, chalk.gray(`CI 平台: ${ci.platform}`));
|
|
285
|
+
}
|
|
286
|
+
|
|
174
287
|
// 写入 harness 版本
|
|
175
288
|
const pkgVersion = getHarnessPackageVersion();
|
|
176
289
|
configData.harness = { version: pkgVersion };
|
|
@@ -181,14 +294,11 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
|
|
|
181
294
|
await fs.writeFile(configPath, configContent, 'utf-8');
|
|
182
295
|
log(io, chalk.green(`✅ 已创建配置文件: ${configPath} (v${pkgVersion})`));
|
|
183
296
|
|
|
184
|
-
//
|
|
185
|
-
await
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
// 创建自定义约束示例
|
|
191
|
-
await createCustomConstraintsExample(projectPath, io);
|
|
297
|
+
// 受管示例文件:检查点 / Resolutions(RKB 狗粮)/ 自定义约束
|
|
298
|
+
await runPlan(
|
|
299
|
+
[checkpointsFile(projectPath), resolutionsFile(projectPath), customConstraintsFile(projectPath)],
|
|
300
|
+
io,
|
|
301
|
+
);
|
|
192
302
|
|
|
193
303
|
// CAPABILITIES.md / CHANGELOG.md 由 sync-docs(AI 治理)管理,init 不创建
|
|
194
304
|
|
|
@@ -197,14 +307,14 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
|
|
|
197
307
|
await setupGitHooks(projectPath, io);
|
|
198
308
|
}
|
|
199
309
|
|
|
200
|
-
//
|
|
201
|
-
if (
|
|
202
|
-
await
|
|
310
|
+
// 服务端 CI 门禁接线(平台维度):`none` = CI 站点干脆不进 plan
|
|
311
|
+
if (ci.platform !== 'none') {
|
|
312
|
+
await setupCiWiring(projectPath, ci.platform, options.governance, io);
|
|
203
313
|
}
|
|
204
314
|
|
|
205
315
|
// 治理相关文件生成
|
|
206
316
|
if (options.governance) {
|
|
207
|
-
await setupGovernance(projectPath, options.governance, io);
|
|
317
|
+
await setupGovernance(projectPath, options.governance, io, ci.platform);
|
|
208
318
|
}
|
|
209
319
|
|
|
210
320
|
log(io);
|
|
@@ -213,7 +323,7 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
|
|
|
213
323
|
log(io, chalk.gray('下一步:'));
|
|
214
324
|
log(io, chalk.gray(' 1. 编辑 .harness/config.yml 自定义配置'));
|
|
215
325
|
log(io, chalk.gray(' 2. 编辑 .harness/custom-constraints.yml 添加项目约束'));
|
|
216
|
-
log(io, chalk.gray(' 3.
|
|
326
|
+
log(io, chalk.gray(' 3. 正常开发:每次 git commit 查暂存的(增量快反馈),每次 git push 查整仓的(全量兜底)——重复是设计使然'));
|
|
217
327
|
log(io, chalk.gray(' 4. 运行 harness status 查看状态'));
|
|
218
328
|
log(io);
|
|
219
329
|
log(io, chalk.blue('💡 提示: 使用 harness init --print-snippets 查看配置代码片段'));
|
|
@@ -221,169 +331,81 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
|
|
|
221
331
|
}
|
|
222
332
|
|
|
223
333
|
/**
|
|
224
|
-
*
|
|
334
|
+
* 输出代码片段(CI 片段按解析出的平台出形,harness#143)
|
|
335
|
+
*
|
|
336
|
+
* gitlab 形打 `renderGitLabCiJobs(governanceLevel)`——与落盘 / 冲突分支同一个函数
|
|
337
|
+
* 的正本(harness#157:曾打无 level 的 GITLAB_CI_SNIPPET,`-g` 档照抄的用户少拿
|
|
338
|
+
* 治理与 docs 新鲜度两个任务)。
|
|
225
339
|
*/
|
|
226
|
-
function printSnippets(
|
|
340
|
+
function printSnippets(
|
|
341
|
+
io: CommandIO,
|
|
342
|
+
platform: CiPlatform | 'none',
|
|
343
|
+
governanceLevel: string | undefined,
|
|
344
|
+
): void {
|
|
227
345
|
log(io, chalk.blue('📄 Harness 配置代码片段'));
|
|
228
346
|
log(io);
|
|
229
|
-
|
|
347
|
+
|
|
230
348
|
log(io, chalk.yellow('Git pre-commit hook:'));
|
|
231
349
|
log(io, chalk.gray('添加到 .git/hooks/pre-commit'));
|
|
232
350
|
log(io);
|
|
233
351
|
log(io, chalk.cyan(PRE_COMMIT_SNIPPET));
|
|
234
|
-
|
|
235
|
-
log(io, chalk.yellow('GitHub Actions:'));
|
|
236
|
-
log(io, chalk.gray('添加到 .github/workflows/*.yml 的 jobs 中'));
|
|
237
|
-
log(io);
|
|
238
|
-
log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
|
|
239
|
-
|
|
240
|
-
log(io, chalk.blue('💡 提示: 运行 npx @dommaker/harness init 自动创建配置文件'));
|
|
241
|
-
}
|
|
242
352
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const PRE_COMMIT_SNIPPET = `
|
|
248
|
-
echo "🔍 Running harness checks..."
|
|
249
|
-
|
|
250
|
-
STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
|
|
251
|
-
|
|
252
|
-
# Harness 约束检查
|
|
253
|
-
npx @dommaker/harness check --staged
|
|
254
|
-
if [ $? -ne 0 ]; then
|
|
255
|
-
echo "❌ Iron law check failed"
|
|
256
|
-
exit 1
|
|
257
|
-
fi
|
|
258
|
-
|
|
259
|
-
# Plan coverage check (via PostEval)
|
|
260
|
-
if command -v npx > /dev/null 2>&1; then
|
|
261
|
-
PLAN_FILES=$(echo "$STAGED" | grep -E 'plans/.*\\.md$|\\.plan\\.md$' || true)
|
|
262
|
-
if [ -n "$PLAN_FILES" ]; then
|
|
263
|
-
echo "📋 Checking plan coverage..."
|
|
264
|
-
for plan in $PLAN_FILES; do
|
|
265
|
-
npx @dommaker/harness posteval-plan "$plan" || {
|
|
266
|
-
echo "🛑 Plan coverage incomplete. See above for missed items."
|
|
267
|
-
exit 1
|
|
268
|
-
}
|
|
269
|
-
done
|
|
270
|
-
fi
|
|
271
|
-
fi
|
|
353
|
+
log(io, chalk.yellow('Git pre-push hook:'));
|
|
354
|
+
log(io, chalk.gray('添加到 .git/hooks/pre-push(pre-commit 查暂存的、快反馈,这道查整仓的、全量兜底——重复是设计使然)'));
|
|
355
|
+
log(io);
|
|
356
|
+
log(io, chalk.cyan(PRE_PUSH_SNIPPET));
|
|
272
357
|
|
|
273
|
-
|
|
274
|
-
|
|
358
|
+
if (platform === 'gitlab') {
|
|
359
|
+
log(io, chalk.yellow('GitLab CI:'));
|
|
360
|
+
log(io, chalk.gray('添加到 .gitlab-ci.yml'));
|
|
361
|
+
log(io);
|
|
362
|
+
log(io, chalk.cyan(renderGitLabCiJobs(governanceLevel)));
|
|
363
|
+
} else {
|
|
364
|
+
log(io, chalk.yellow('GitHub Actions:'));
|
|
365
|
+
log(io, chalk.gray('添加到 .github/workflows/*.yml 的 jobs 下(以下正文取自 harness-check.yml 的 job 段)'));
|
|
366
|
+
log(io);
|
|
367
|
+
log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
|
|
368
|
+
}
|
|
275
369
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
*/
|
|
279
|
-
const GITHUB_ACTIONS_SNIPPET = `
|
|
280
|
-
harness-check:
|
|
281
|
-
runs-on: ubuntu-latest
|
|
282
|
-
steps:
|
|
283
|
-
- uses: actions/checkout@v4
|
|
284
|
-
- uses: actions/setup-node@v4
|
|
285
|
-
with:
|
|
286
|
-
node-version: '20'
|
|
287
|
-
- run: npm ci
|
|
288
|
-
- run: npx @dommaker/harness check
|
|
289
|
-
`;
|
|
370
|
+
log(io, chalk.blue('💡 提示: 运行 npx @dommaker/harness init 自动创建配置文件'));
|
|
371
|
+
}
|
|
290
372
|
|
|
291
373
|
/**
|
|
292
|
-
* 设置 Git hooks
|
|
374
|
+
* 设置 Git hooks(无 .git 即整站跳过;落盘语义在 scaffold plan)
|
|
375
|
+
*
|
|
376
|
+
* 两道:pre-commit 查暂存的(增量、快反馈),pre-push 查整仓的(全量、兜底,
|
|
377
|
+
* harness#144)。跳过旗帜 `--no-git-hooks` 在命令层翻成「本站点不进 plan」。
|
|
293
378
|
*/
|
|
294
379
|
async function setupGitHooks(projectPath: string, io: CommandIO): Promise<void> {
|
|
295
|
-
|
|
296
|
-
const hooksDir = path.join(gitDir, 'hooks');
|
|
297
|
-
const preCommitPath = path.join(hooksDir, 'pre-commit');
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
await fs.access(gitDir);
|
|
301
|
-
} catch {
|
|
380
|
+
if (!(await nodeScaffoldFs.exists(path.join(projectPath, '.git')))) {
|
|
302
381
|
log(io, chalk.yellow('⚠️ 未检测到 Git 仓库,跳过 Git hooks'));
|
|
303
382
|
log(io, chalk.gray('💡 初始化 Git 后可运行 npx @dommaker/harness init --print-snippets 查看配置'));
|
|
304
383
|
return;
|
|
305
384
|
}
|
|
306
|
-
|
|
307
|
-
await fs.mkdir(hooksDir, { recursive: true });
|
|
308
|
-
|
|
309
|
-
// 检查 pre-commit 是否已存在
|
|
310
|
-
try {
|
|
311
|
-
await fs.access(preCommitPath);
|
|
312
|
-
// 已存在,输出代码片段
|
|
313
|
-
log(io, chalk.yellow('⚠️ .git/hooks/pre-commit 已存在'));
|
|
314
|
-
log(io, chalk.gray('💡 请手动添加以下内容到文件末尾:'));
|
|
315
|
-
log(io);
|
|
316
|
-
log(io, chalk.cyan(PRE_COMMIT_SNIPPET));
|
|
317
|
-
} catch {
|
|
318
|
-
// 不存在,创建文件:shebang 头 + 共享片段(#103 同源,无第二份文本)
|
|
319
|
-
const preCommitContent = `#!/bin/sh
|
|
320
|
-
# Harness pre-commit hook
|
|
321
|
-
${PRE_COMMIT_SNIPPET}`;
|
|
322
|
-
await fs.writeFile(preCommitPath, preCommitContent, 'utf-8');
|
|
323
|
-
await fs.chmod(preCommitPath, 0o755);
|
|
324
|
-
log(io, chalk.green(`✅ 已创建 .git/hooks/pre-commit`));
|
|
325
|
-
}
|
|
385
|
+
await runPlan([preCommitHookFile(projectPath), prePushHookFile(projectPath)], io);
|
|
326
386
|
}
|
|
327
387
|
|
|
328
388
|
/**
|
|
329
|
-
*
|
|
389
|
+
* 设置服务端 CI 接线(站点形状与冲突面由 scaffold 按平台给)
|
|
390
|
+
*
|
|
391
|
+
* gitlab 只有一个 `.gitlab-ci.yml`,治理任务已在正文里(`governanceLevel` 传给工厂);
|
|
392
|
+
* github 的冲突判定宽到整个 workflows 目录,需先扫一遍。
|
|
330
393
|
*/
|
|
331
|
-
async function
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// 已有 CI 配置,输出代码片段
|
|
340
|
-
log(io, chalk.yellow('⚠️ 检测到已存在的 CI 配置:'));
|
|
341
|
-
existingFiles.forEach(f => {
|
|
342
|
-
log(io, chalk.gray(` - .github/workflows/${f}`));
|
|
343
|
-
});
|
|
344
|
-
log(io, chalk.gray('💡 请手动添加以下内容到 jobs 中:'));
|
|
345
|
-
log(io);
|
|
346
|
-
log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
|
|
394
|
+
async function setupCiWiring(
|
|
395
|
+
projectPath: string,
|
|
396
|
+
platform: CiPlatform,
|
|
397
|
+
governanceLevel: string | undefined,
|
|
398
|
+
io: CommandIO,
|
|
399
|
+
): Promise<void> {
|
|
400
|
+
if (platform === 'gitlab') {
|
|
401
|
+
await runPlan([harnessCheckCiFile(projectPath, 'gitlab', [], governanceLevel)], io);
|
|
347
402
|
return;
|
|
348
403
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
on:
|
|
355
|
-
push:
|
|
356
|
-
branches: [main, master]
|
|
357
|
-
pull_request:
|
|
358
|
-
branches: [main, master]
|
|
359
|
-
|
|
360
|
-
jobs:
|
|
361
|
-
harness-check:
|
|
362
|
-
runs-on: ubuntu-latest
|
|
363
|
-
|
|
364
|
-
steps:
|
|
365
|
-
- uses: actions/checkout@v4
|
|
366
|
-
|
|
367
|
-
- name: Setup Node.js
|
|
368
|
-
uses: actions/setup-node@v4
|
|
369
|
-
with:
|
|
370
|
-
node-version: '20'
|
|
371
|
-
|
|
372
|
-
- name: Install dependencies
|
|
373
|
-
run: npm ci
|
|
374
|
-
|
|
375
|
-
- name: Run harness check
|
|
376
|
-
run: npx @dommaker/harness check
|
|
377
|
-
|
|
378
|
-
- name: Run harness validate
|
|
379
|
-
run: npx @dommaker/harness validate
|
|
380
|
-
|
|
381
|
-
- name: Run harness passes-gate
|
|
382
|
-
run: npx @dommaker/harness passes-gate
|
|
383
|
-
`;
|
|
384
|
-
|
|
385
|
-
await fs.writeFile(workflowPath, workflowContent, 'utf-8');
|
|
386
|
-
log(io, chalk.green(`✅ 已创建 .github/workflows/harness-check.yml`));
|
|
404
|
+
const workflowsDir = path.join(projectPath, '.github', 'workflows');
|
|
405
|
+
await runPlan(
|
|
406
|
+
[harnessCheckCiFile(projectPath, 'github', await findCiWorkflows(workflowsDir))],
|
|
407
|
+
io,
|
|
408
|
+
);
|
|
387
409
|
}
|
|
388
410
|
|
|
389
411
|
/**
|
|
@@ -402,61 +424,6 @@ async function findCiWorkflows(workflowsDir: string): Promise<string[]> {
|
|
|
402
424
|
}
|
|
403
425
|
}
|
|
404
426
|
|
|
405
|
-
/**
|
|
406
|
-
* 创建自定义约束示例
|
|
407
|
-
*/
|
|
408
|
-
async function createCustomConstraintsExample(projectPath: string, io: CommandIO): Promise<void> {
|
|
409
|
-
const configDir = path.join(projectPath, '.harness');
|
|
410
|
-
const customConstraintsPath = path.join(configDir, 'custom-constraints.yml');
|
|
411
|
-
|
|
412
|
-
// 如果已存在,不覆盖
|
|
413
|
-
try {
|
|
414
|
-
await fs.access(customConstraintsPath);
|
|
415
|
-
log(io, chalk.gray(`custom-constraints.yml 已存在`));
|
|
416
|
-
return;
|
|
417
|
-
} catch {
|
|
418
|
-
// 文件不存在,创建
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const content = `# 自定义约束配置
|
|
422
|
-
#
|
|
423
|
-
# 此文件定义项目特定的约束,扩展或覆盖 harness 内置约束
|
|
424
|
-
|
|
425
|
-
# ========================================
|
|
426
|
-
# 自定义约束示例
|
|
427
|
-
# ========================================
|
|
428
|
-
|
|
429
|
-
custom_constraints:
|
|
430
|
-
# 示例 1:禁止 console.log
|
|
431
|
-
# my_project_no_console_log:
|
|
432
|
-
# id: my_project_no_console_log
|
|
433
|
-
# level: guideline
|
|
434
|
-
# rule: "NO CONSOLE.LOG IN PRODUCTION CODE"
|
|
435
|
-
# message: "生产代码禁止使用 console.log,请使用 logger 模块"
|
|
436
|
-
# trigger: ["code_implementation"]
|
|
437
|
-
# description: "使用项目统一的 logger 模块代替 console.log"
|
|
438
|
-
|
|
439
|
-
# 示例 2:禁止特定的导入
|
|
440
|
-
# my_project_no_moment_js:
|
|
441
|
-
# id: my_project_no_moment_js
|
|
442
|
-
# level: guideline
|
|
443
|
-
# rule: "NO MOMENT.JS IMPORTS"
|
|
444
|
-
# message: "禁止使用 moment.js,请使用 date-fns 或 dayjs"
|
|
445
|
-
# trigger: ["code_implementation"]
|
|
446
|
-
|
|
447
|
-
# 示例 3:要求特定的文件命名
|
|
448
|
-
# my_project_component_naming:
|
|
449
|
-
# id: my_project_component_naming
|
|
450
|
-
# level: tip
|
|
451
|
-
# rule: "REACT COMPONENTS SHOULD BE PASCAL CASE"
|
|
452
|
-
# message: "React 组件文件名应使用 PascalCase"
|
|
453
|
-
# trigger: ["file_creation"]
|
|
454
|
-
`;
|
|
455
|
-
|
|
456
|
-
await fs.writeFile(customConstraintsPath, content, 'utf-8');
|
|
457
|
-
log(io, chalk.green(`✅ 已创建自定义约束示例: custom-constraints.yml`));
|
|
458
|
-
}
|
|
459
|
-
|
|
460
427
|
/**
|
|
461
428
|
* Output Style 段标记(ADR-0001:init 只写标记区间内,标记外只读)
|
|
462
429
|
*/
|
|
@@ -490,7 +457,7 @@ function renderOutputStyleSection(): string {
|
|
|
490
457
|
* - 无标记且 `## Output Style` 段为用户自写(特征串不匹配):跳过并提示,不重复追加
|
|
491
458
|
* - 完全没有该段:在文件顶部插入标记版
|
|
492
459
|
*/
|
|
493
|
-
export async function setupClaudeMdOutputStyle(projectPath: string, io: CommandIO
|
|
460
|
+
export async function setupClaudeMdOutputStyle(projectPath: string, io: CommandIO): Promise<void> {
|
|
494
461
|
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
495
462
|
let content: string;
|
|
496
463
|
try {
|
|
@@ -563,7 +530,7 @@ const GOVERNANCE_PRESERVE_END = '<!-- /PRESERVE:governance -->';
|
|
|
563
530
|
* - 无该段:在文件末尾追加
|
|
564
531
|
* - 段标记残缺(外层或段内 HARNESS_CONSTRAINTS 单边/乱序):不写入,告警交由人工修复(防二次损坏)
|
|
565
532
|
*/
|
|
566
|
-
export async function setupAgentsMdConstraints(projectPath: string, io: CommandIO
|
|
533
|
+
export async function setupAgentsMdConstraints(projectPath: string, io: CommandIO): Promise<void> {
|
|
567
534
|
const agentsMdPath = path.join(projectPath, 'AGENTS.md');
|
|
568
535
|
const version = getHarnessPackageVersion();
|
|
569
536
|
|
|
@@ -640,7 +607,7 @@ export async function setupAgentsMdConstraints(projectPath: string, io: CommandI
|
|
|
640
607
|
* - 如果存在 HARNESS_CONSTRAINTS_START/END 标记,替换标记间内容
|
|
641
608
|
* - 如果不存在标记,在文件末尾追加约束段
|
|
642
609
|
*/
|
|
643
|
-
export async function setupClaudeMdConstraints(projectPath: string, io: CommandIO
|
|
610
|
+
export async function setupClaudeMdConstraints(projectPath: string, io: CommandIO): Promise<void> {
|
|
644
611
|
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
645
612
|
|
|
646
613
|
const version = getHarnessPackageVersion();
|
|
@@ -691,17 +658,22 @@ export async function setupClaudeMdConstraints(projectPath: string, io: CommandI
|
|
|
691
658
|
* 继续写 CLAUDE.md——init 幂等重跑不破坏既有仓,不制造双份约束正本
|
|
692
659
|
* - 其余(新仓初始化):写 AGENTS.md PRESERVE:governance 段(入库公共面正本)
|
|
693
660
|
*/
|
|
694
|
-
export async function setupGovernanceConstraints(projectPath: string): Promise<void> {
|
|
661
|
+
export async function setupGovernanceConstraints(projectPath: string, io: CommandIO): Promise<void> {
|
|
695
662
|
const { target } = resolveGovernanceLanding(projectPath);
|
|
696
663
|
return target === 'claude-md'
|
|
697
|
-
? setupClaudeMdConstraints(projectPath)
|
|
698
|
-
: setupAgentsMdConstraints(projectPath);
|
|
664
|
+
? setupClaudeMdConstraints(projectPath, io)
|
|
665
|
+
: setupAgentsMdConstraints(projectPath, io);
|
|
699
666
|
}
|
|
700
667
|
|
|
701
668
|
/**
|
|
702
669
|
* 设置治理相关文件
|
|
703
670
|
*/
|
|
704
|
-
async function setupGovernance(
|
|
671
|
+
async function setupGovernance(
|
|
672
|
+
projectPath: string,
|
|
673
|
+
level: string,
|
|
674
|
+
io: CommandIO,
|
|
675
|
+
platform: CiPlatform | 'none',
|
|
676
|
+
): Promise<void> {
|
|
705
677
|
const governance = GOVERNANCE_PRESETS[level];
|
|
706
678
|
if (!governance) return;
|
|
707
679
|
|
|
@@ -709,129 +681,48 @@ async function setupGovernance(projectPath: string, level: string, io: CommandIO
|
|
|
709
681
|
log(io, chalk.blue('📋 设置治理文件...'));
|
|
710
682
|
|
|
711
683
|
// 1. 生成 CHANGELOG.md
|
|
712
|
-
await
|
|
684
|
+
await runPlan([changelogFile(projectPath, governance.changelog?.format || 'keep-a-changelog')], io);
|
|
713
685
|
|
|
714
686
|
// 2. 在 CLAUDE.md 中写入 Output Style 段(仅在不存在时创建)
|
|
715
|
-
await setupClaudeMdOutputStyle(projectPath);
|
|
687
|
+
await setupClaudeMdOutputStyle(projectPath, io);
|
|
716
688
|
|
|
717
689
|
// 3. 写入/更新 Governance Rules 约束段(新仓 → AGENTS.md PRESERVE:governance;
|
|
718
690
|
// 旧模型仓 → CLAUDE.md,落点路由见 setupGovernanceConstraints)
|
|
719
|
-
await setupGovernanceConstraints(projectPath);
|
|
691
|
+
await setupGovernanceConstraints(projectPath, io);
|
|
720
692
|
|
|
721
693
|
// 4. 生成 CONTEXT.md 文件(预设形状即 GovernanceConfig,无需再 cast)
|
|
722
|
-
|
|
723
|
-
if (contextConfig?.enabled) {
|
|
724
|
-
let requiredDirs = contextConfig.required_dirs ?? [];
|
|
725
|
-
if (requiredDirs.length === 0) {
|
|
726
|
-
requiredDirs = detectSourceRoots(projectPath);
|
|
727
|
-
}
|
|
728
|
-
for (const dir of requiredDirs) {
|
|
729
|
-
await createContextMd(projectPath, dir, io);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// 4. 生成治理 CI workflow
|
|
734
|
-
await setupGovernanceWorkflow(projectPath, level, io);
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* 创建 CHANGELOG.md
|
|
739
|
-
*/
|
|
740
|
-
async function createChangelog(projectPath: string, governance: GovernanceConfig, io: CommandIO): Promise<void> {
|
|
741
|
-
const changelogPath = path.join(projectPath, 'CHANGELOG.md');
|
|
742
|
-
|
|
743
|
-
try {
|
|
744
|
-
await fs.access(changelogPath);
|
|
745
|
-
log(io, chalk.gray(`CHANGELOG.md 已存在`));
|
|
746
|
-
return;
|
|
747
|
-
} catch {
|
|
748
|
-
// 文件不存在,创建
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const format = governance.changelog?.format || 'keep-a-changelog';
|
|
752
|
-
|
|
753
|
-
let content: string;
|
|
754
|
-
if (format === 'keep-a-changelog') {
|
|
755
|
-
content = `# Changelog
|
|
756
|
-
|
|
757
|
-
All notable changes to this project will be documented in this file.
|
|
758
|
-
|
|
759
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
760
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
761
|
-
|
|
762
|
-
## [Unreleased]
|
|
763
|
-
|
|
764
|
-
### Added
|
|
765
|
-
- Initial project setup with harness governance
|
|
694
|
+
await runPlan(await contextDocPlan(projectPath, governance, io), io);
|
|
766
695
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
> 此文件可由 \`harness sync-docs\` 辅助维护
|
|
770
|
-
`;
|
|
771
|
-
} else {
|
|
772
|
-
content = `# Changelog
|
|
773
|
-
|
|
774
|
-
## [Unreleased]
|
|
775
|
-
|
|
776
|
-
- Initial project setup with harness governance
|
|
777
|
-
|
|
778
|
-
---
|
|
779
|
-
|
|
780
|
-
> 此文件可由 \`harness sync-docs\` 辅助维护
|
|
781
|
-
`;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
await fs.writeFile(changelogPath, content, 'utf-8');
|
|
785
|
-
log(io, chalk.green(`✅ 已创建 CHANGELOG.md`));
|
|
696
|
+
// 5. 生成治理 CI 面(仅 github 形;gitlab 已并入 .gitlab-ci.yml 正文,none 不建,harness#156)
|
|
697
|
+
await setupGovernanceWorkflow(projectPath, level, io, platform);
|
|
786
698
|
}
|
|
787
699
|
|
|
788
700
|
/**
|
|
789
|
-
*
|
|
701
|
+
* 目录 CONTEXT.md 骨架的 plan:required_dirs 缺省时按源码根探测,
|
|
702
|
+
* 探测出来的目录不在场就不进 plan(告知由本函数负责)
|
|
790
703
|
*/
|
|
791
|
-
async function
|
|
792
|
-
|
|
704
|
+
async function contextDocPlan(
|
|
705
|
+
projectPath: string,
|
|
706
|
+
governance: GovernanceConfig,
|
|
707
|
+
io: CommandIO,
|
|
708
|
+
): Promise<ManagedFile[]> {
|
|
709
|
+
const contextConfig = governance.context_files;
|
|
710
|
+
if (!contextConfig?.enabled) return [];
|
|
793
711
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
return;
|
|
798
|
-
} catch {
|
|
799
|
-
// 文件不存在,创建
|
|
712
|
+
let requiredDirs = contextConfig.required_dirs ?? [];
|
|
713
|
+
if (requiredDirs.length === 0) {
|
|
714
|
+
requiredDirs = detectSourceRoots(projectPath);
|
|
800
715
|
}
|
|
801
716
|
|
|
802
|
-
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
717
|
+
const plan: ManagedFile[] = [];
|
|
718
|
+
for (const dir of requiredDirs) {
|
|
719
|
+
if (!(await nodeScaffoldFs.exists(path.join(projectPath, dir)))) {
|
|
720
|
+
log(io, chalk.yellow(`⚠️ 目录 ${dir} 不存在,跳过 CONTEXT.md`));
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
plan.push(contextDocFile(projectPath, dir));
|
|
809
724
|
}
|
|
810
|
-
|
|
811
|
-
const dirName = path.basename(dir);
|
|
812
|
-
const content = `# ${dirName}
|
|
813
|
-
|
|
814
|
-
> 此文件描述 ${dir} 目录的职责和上下文
|
|
815
|
-
|
|
816
|
-
## 职责
|
|
817
|
-
|
|
818
|
-
<!-- 本目录的核心职责是什么 -->
|
|
819
|
-
|
|
820
|
-
## 核心导出
|
|
821
|
-
|
|
822
|
-
<!-- 本目录对外暴露的主要模块/函数 -->
|
|
823
|
-
|
|
824
|
-
## 依赖关系
|
|
825
|
-
|
|
826
|
-
<!-- 本目录依赖哪些其他模块,谁依赖本目录 -->
|
|
827
|
-
|
|
828
|
-
## 注意事项
|
|
829
|
-
|
|
830
|
-
<!-- 开发时需要注意的约束或约定 -->
|
|
831
|
-
`;
|
|
832
|
-
|
|
833
|
-
await fs.writeFile(contextPath, content, 'utf-8');
|
|
834
|
-
log(io, chalk.green(`✅ 已创建 ${dir}/CONTEXT.md`));
|
|
725
|
+
return plan;
|
|
835
726
|
}
|
|
836
727
|
|
|
837
728
|
/**
|
|
@@ -855,68 +746,30 @@ async function findGovernanceCoverage(workflowsDir: string): Promise<string | un
|
|
|
855
746
|
}
|
|
856
747
|
|
|
857
748
|
/**
|
|
858
|
-
* 设置治理 CI workflow
|
|
749
|
+
* 设置治理 CI workflow(目标已在场,或已有 workflow 覆盖治理命令时不新建 CI 面)
|
|
750
|
+
*
|
|
751
|
+
* 仅 github 形有本站点:gitlab 的治理任务已并入 `.gitlab-ci.yml` 正文(一个平台一份
|
|
752
|
+
* CI 文件,harness#143);`none` = 不创建任何 CI 文件,治理 CI 面随之不建
|
|
753
|
+
* (harness#156 裁决 F1;治理文档面不受影响,见 setupGovernance 1–4)。
|
|
859
754
|
*/
|
|
860
|
-
async function setupGovernanceWorkflow(
|
|
861
|
-
|
|
862
|
-
|
|
755
|
+
async function setupGovernanceWorkflow(
|
|
756
|
+
projectPath: string,
|
|
757
|
+
level: string,
|
|
758
|
+
io: CommandIO,
|
|
759
|
+
platform: CiPlatform | 'none',
|
|
760
|
+
): Promise<void> {
|
|
761
|
+
if (platform !== 'github') return;
|
|
863
762
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
await fs.access(workflowPath);
|
|
867
|
-
log(io, chalk.gray(`harness-governance.yml 已存在`));
|
|
868
|
-
return;
|
|
869
|
-
} catch {
|
|
870
|
-
// 不存在,继续创建
|
|
871
|
-
}
|
|
763
|
+
const workflowsDir = path.join(projectPath, '.github', 'workflows');
|
|
764
|
+
const file = governanceWorkflowFile(projectPath, level);
|
|
872
765
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
766
|
+
if (!(await nodeScaffoldFs.exists(file.target))) {
|
|
767
|
+
const coveredBy = await findGovernanceCoverage(workflowsDir);
|
|
768
|
+
if (coveredBy) {
|
|
769
|
+
log(io, chalk.gray(`治理检查已由 ${coveredBy} 覆盖,跳过创建 harness-governance.yml`));
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
878
772
|
}
|
|
879
773
|
|
|
880
|
-
await
|
|
881
|
-
|
|
882
|
-
const docsCheckStep = level !== 'minimal'
|
|
883
|
-
? `
|
|
884
|
-
- name: Check docs freshness
|
|
885
|
-
run: npx @dommaker/harness sync-docs --check
|
|
886
|
-
continue-on-error: true`
|
|
887
|
-
: '';
|
|
888
|
-
|
|
889
|
-
const workflowContent = `name: Harness Governance
|
|
890
|
-
|
|
891
|
-
on:
|
|
892
|
-
push:
|
|
893
|
-
branches: [main, master]
|
|
894
|
-
pull_request:
|
|
895
|
-
branches: [main, master]
|
|
896
|
-
|
|
897
|
-
jobs:
|
|
898
|
-
governance:
|
|
899
|
-
runs-on: ubuntu-latest
|
|
900
|
-
|
|
901
|
-
steps:
|
|
902
|
-
- uses: actions/checkout@v4
|
|
903
|
-
|
|
904
|
-
- name: Setup Node.js
|
|
905
|
-
uses: actions/setup-node@v4
|
|
906
|
-
with:
|
|
907
|
-
node-version: '20'
|
|
908
|
-
|
|
909
|
-
- name: Install dependencies
|
|
910
|
-
run: npm ci
|
|
911
|
-
|
|
912
|
-
- name: Constraint check
|
|
913
|
-
run: npx @dommaker/harness check
|
|
914
|
-
|
|
915
|
-
- name: Quality gate
|
|
916
|
-
run: npx @dommaker/harness passes-gate
|
|
917
|
-
${docsCheckStep}
|
|
918
|
-
`;
|
|
919
|
-
|
|
920
|
-
await fs.writeFile(workflowPath, workflowContent, 'utf-8');
|
|
921
|
-
log(io, chalk.green(`✅ 已创建 .github/workflows/harness-governance.yml`));
|
|
774
|
+
await runPlan([file], io);
|
|
922
775
|
}
|