@dommaker/harness 0.19.0 → 1.1.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 +22 -9
- package/bin/harness.js +136 -557
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +2 -13
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +90 -0
- package/dist/cli/commands/definitions.d.ts.map +1 -0
- package/dist/cli/commands/definitions.js +519 -0
- package/dist/cli/commands/definitions.js.map +1 -0
- package/dist/cli/commands/knowledge.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 +25 -4
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +3 -25
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.js +3 -93
- package/dist/cli/commands/sync-docs/capabilities-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 +4 -4
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/completion-checkers/classify.d.ts +23 -0
- package/dist/completion-checkers/classify.d.ts.map +1 -0
- package/dist/completion-checkers/classify.js +37 -0
- package/dist/completion-checkers/classify.js.map +1 -0
- package/dist/completion-checkers/contract-presence.d.ts +12 -0
- package/dist/completion-checkers/contract-presence.d.ts.map +1 -0
- package/dist/completion-checkers/contract-presence.js +36 -0
- package/dist/completion-checkers/contract-presence.js.map +1 -0
- package/dist/completion-checkers/glob-match.d.ts +13 -0
- package/dist/completion-checkers/glob-match.d.ts.map +1 -0
- package/dist/completion-checkers/glob-match.js +58 -0
- package/dist/completion-checkers/glob-match.js.map +1 -0
- package/dist/completion-checkers/index.d.ts +19 -0
- package/dist/completion-checkers/index.d.ts.map +1 -0
- package/dist/completion-checkers/index.js +47 -0
- package/dist/completion-checkers/index.js.map +1 -0
- package/dist/completion-checkers/phase-format.d.ts +15 -0
- package/dist/completion-checkers/phase-format.d.ts.map +1 -0
- package/dist/completion-checkers/phase-format.js +42 -0
- package/dist/completion-checkers/phase-format.js.map +1 -0
- package/dist/completion-checkers/tdd-chain.d.ts +16 -0
- package/dist/completion-checkers/tdd-chain.d.ts.map +1 -0
- package/dist/completion-checkers/tdd-chain.js +57 -0
- package/dist/completion-checkers/tdd-chain.js.map +1 -0
- package/dist/completion-checkers/types.d.ts +77 -0
- package/dist/completion-checkers/types.d.ts.map +1 -0
- package/dist/completion-checkers/types.js +10 -0
- package/dist/completion-checkers/types.js.map +1 -0
- package/dist/context/index.d.ts +1 -5
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +1 -5
- package/dist/context/index.js.map +1 -1
- package/dist/context/knowledge-injector.d.ts +3 -3
- package/dist/context/knowledge-injector.d.ts.map +1 -1
- package/dist/context/knowledge-injector.js +1 -1
- package/dist/context/session-manager.d.ts +1 -12
- package/dist/context/session-manager.d.ts.map +1 -1
- package/dist/context/session-manager.js +0 -63
- package/dist/context/session-manager.js.map +1 -1
- package/dist/context/types.d.ts +1 -39
- package/dist/context/types.d.ts.map +1 -1
- package/dist/context/types.js +2 -15
- package/dist/context/types.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.d.ts +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +17 -2
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +84 -2
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +3 -17
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +7 -47
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/definitions.d.ts +0 -7
- package/dist/core/constraints/definitions.d.ts.map +1 -1
- package/dist/core/constraints/definitions.js +1 -8
- package/dist/core/constraints/definitions.js.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.d.ts +0 -2
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/index.d.ts +1 -1
- package/dist/core/constraints/index.d.ts.map +1 -1
- package/dist/core/constraints/index.js +2 -3
- package/dist/core/constraints/index.js.map +1 -1
- package/dist/core/constraints/interceptor.d.ts.map +1 -1
- package/dist/core/constraints/interceptor.js +1 -5
- package/dist/core/constraints/interceptor.js.map +1 -1
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +0 -1
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +1 -8
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/dashboard/stats.d.ts.map +1 -1
- package/dist/dashboard/stats.js.map +1 -1
- package/dist/dashboard/types.d.ts +2 -2
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/failure/constraint-handler.d.ts.map +1 -1
- package/dist/failure/constraint-handler.js +0 -2
- package/dist/failure/constraint-handler.js.map +1 -1
- package/dist/gates/acceptance.d.ts +9 -1
- package/dist/gates/acceptance.d.ts.map +1 -1
- package/dist/gates/acceptance.js +21 -0
- package/dist/gates/acceptance.js.map +1 -1
- package/dist/gates/checker-gate.d.ts +23 -0
- package/dist/gates/checker-gate.d.ts.map +1 -0
- package/dist/gates/checker-gate.js +53 -0
- package/dist/gates/checker-gate.js.map +1 -0
- package/dist/gates/command.d.ts +9 -2
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +10 -0
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts +8 -2
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +9 -0
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/decision.d.ts +17 -0
- package/dist/gates/decision.d.ts.map +1 -0
- package/dist/gates/decision.js +25 -0
- package/dist/gates/decision.js.map +1 -0
- package/dist/gates/definitions.d.ts +63 -0
- package/dist/gates/definitions.d.ts.map +1 -0
- package/dist/gates/definitions.js +160 -0
- package/dist/gates/definitions.js.map +1 -0
- package/dist/gates/effective-gates.d.ts +30 -0
- package/dist/gates/effective-gates.d.ts.map +1 -0
- package/dist/gates/effective-gates.js +85 -0
- package/dist/gates/effective-gates.js.map +1 -0
- package/dist/gates/index.d.ts +25 -1
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js +37 -1
- package/dist/gates/index.js.map +1 -1
- package/dist/gates/performance.d.ts +8 -2
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +9 -0
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/registry.d.ts +32 -0
- package/dist/gates/registry.d.ts.map +1 -0
- package/dist/gates/registry.js +90 -0
- package/dist/gates/registry.js.map +1 -0
- package/dist/gates/review.d.ts +8 -2
- package/dist/gates/review.d.ts.map +1 -1
- package/dist/gates/review.js +9 -0
- package/dist/gates/review.js.map +1 -1
- package/dist/gates/runner.d.ts +30 -0
- package/dist/gates/runner.d.ts.map +1 -0
- package/dist/gates/runner.js +38 -0
- package/dist/gates/runner.js.map +1 -0
- package/dist/gates/security.d.ts +8 -2
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +9 -0
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +41 -1
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +0 -2
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/hooks/config.d.ts +26 -0
- package/dist/hooks/config.d.ts.map +1 -0
- package/dist/hooks/config.js +30 -0
- package/dist/hooks/config.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/registry.d.ts +18 -1
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/registry.js +45 -0
- package/dist/hooks/registry.js.map +1 -1
- package/dist/hooks/types.d.ts +20 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -20
- package/dist/index.js.map +1 -1
- package/dist/knowledge/import.d.ts +2 -2
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/lifecycle-hooks.d.ts +2 -2
- package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
- package/dist/knowledge/types.d.ts +5 -7
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/knowledge/types.js +1 -1
- package/dist/knowledge/types.js.map +1 -1
- package/dist/monitoring/constraint-doctor.d.ts +4 -22
- package/dist/monitoring/constraint-doctor.d.ts.map +1 -1
- package/dist/monitoring/constraint-doctor.js +7 -94
- package/dist/monitoring/constraint-doctor.js.map +1 -1
- package/dist/presets/standard.d.ts +1 -1
- package/dist/presets/standard.d.ts.map +1 -1
- package/dist/presets/standard.js +1 -2
- package/dist/presets/standard.js.map +1 -1
- package/dist/pretool-use-hook.d.ts +16 -0
- package/dist/pretool-use-hook.d.ts.map +1 -0
- package/dist/pretool-use-hook.js +68 -0
- package/dist/pretool-use-hook.js.map +1 -0
- package/dist/spec/annotation-checker.d.ts.map +1 -1
- package/dist/spec/annotation-checker.js +6 -26
- package/dist/spec/annotation-checker.js.map +1 -1
- package/dist/tools/index.d.ts +0 -4
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +0 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/types/constraint.d.ts +1 -12
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +0 -3
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/project-config.d.ts +0 -2
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/utils/file-walk.d.ts +2 -2
- package/dist/utils/file-walk.js +2 -2
- package/package.json +6 -1
- package/src/CONTEXT.md +15 -0
- package/src/__tests__/checker-extra.test.ts +2 -59
- package/src/__tests__/constraint-doctor.test.ts +1 -140
- package/src/__tests__/constraint-handler.test.ts +0 -4
- package/src/__tests__/pretool-use-hook.test.ts +82 -0
- package/src/__tests__/project-config-loader-extra.test.ts +0 -20
- package/src/__tests__/project-config-loader.test.ts +0 -1
- package/src/cli/commands/CONTEXT.md +15 -7
- package/src/cli/commands/__tests__/check-drift.test.ts +0 -3
- package/src/cli/commands/__tests__/check-skip-output.test.ts +0 -5
- package/src/cli/commands/__tests__/check.test.ts +7 -75
- package/src/cli/commands/__tests__/registry.test.ts +201 -0
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +55 -0
- package/src/cli/commands/check.ts +2 -14
- package/src/cli/commands/definitions.ts +593 -0
- package/src/cli/commands/knowledge.ts +3 -3
- package/src/cli/commands/sync-docs/agents-syncer.ts +26 -6
- package/src/cli/commands/sync-docs/capabilities-syncer.ts +4 -110
- package/src/cli/commands/sync-docs/index.ts +8 -5
- package/src/completion-checkers/CONTEXT.md +25 -0
- package/src/completion-checkers/__tests__/contract-presence.test.ts +44 -0
- package/src/completion-checkers/__tests__/phase-format.test.ts +60 -0
- package/src/completion-checkers/__tests__/tdd-chain.test.ts +99 -0
- package/src/completion-checkers/classify.ts +47 -0
- package/src/completion-checkers/contract-presence.ts +40 -0
- package/src/completion-checkers/glob-match.ts +54 -0
- package/src/completion-checkers/index.ts +19 -0
- package/src/completion-checkers/phase-format.ts +48 -0
- package/src/completion-checkers/tdd-chain.ts +63 -0
- package/src/completion-checkers/types.ts +84 -0
- package/src/context/CONTEXT.md +2 -7
- package/src/context/__tests__/session-manager.test.ts +0 -91
- package/src/context/index.ts +1 -5
- package/src/context/knowledge-injector.ts +3 -3
- package/src/context/session-manager.ts +0 -74
- package/src/context/types.ts +2 -63
- package/src/core/constraints/__tests__/interceptor.test.ts +0 -2
- package/src/core/constraints/agent-prompt-renderer.ts +1 -1
- package/src/core/constraints/capabilities-parser.ts +95 -2
- package/src/core/constraints/checker.ts +8 -53
- package/src/core/constraints/definitions.ts +0 -8
- package/src/core/constraints/doc-freshness/runner.ts +1 -2
- package/src/core/constraints/index.ts +1 -2
- package/src/core/constraints/interceptor.ts +1 -6
- package/src/core/effective-constraints.ts +0 -1
- package/src/core/project-config-loader.ts +1 -7
- package/src/dashboard/stats.ts +2 -2
- package/src/dashboard/types.ts +2 -2
- package/src/failure/constraint-handler.ts +0 -2
- package/src/gates/CONTEXT.md +16 -13
- package/src/gates/__tests__/checker-gate.test.ts +45 -0
- package/src/gates/__tests__/contract.test.ts +73 -0
- package/src/gates/__tests__/effective-gates.test.ts +82 -0
- package/src/gates/__tests__/gate-interface.test.ts +202 -0
- package/src/gates/__tests__/registry.test.ts +87 -0
- package/src/gates/__tests__/runner.test.ts +81 -0
- package/src/gates/acceptance.ts +24 -1
- package/src/gates/checker-gate.ts +54 -0
- package/src/gates/command.ts +13 -2
- package/src/gates/contract.ts +12 -2
- package/src/gates/decision.ts +27 -0
- package/src/gates/definitions.ts +207 -0
- package/src/gates/effective-gates.ts +106 -0
- package/src/gates/index.ts +38 -0
- package/src/gates/performance.ts +12 -2
- package/src/gates/registry.ts +107 -0
- package/src/gates/review.ts +12 -2
- package/src/gates/runner.ts +57 -0
- package/src/gates/security.ts +12 -2
- package/src/gates/types.ts +48 -1
- package/src/hooks/CONTEXT.md +12 -2
- package/src/hooks/__tests__/bootstrap.test.ts +0 -1
- package/src/hooks/__tests__/config.test.ts +19 -0
- package/src/hooks/__tests__/pipeline.test.ts +79 -0
- package/src/hooks/__tests__/registry.test.ts +67 -0
- package/src/hooks/bootstrap.ts +0 -2
- package/src/hooks/config.ts +29 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/registry.ts +60 -1
- package/src/hooks/types.ts +21 -0
- package/src/index.ts +11 -21
- package/src/knowledge/import.ts +3 -3
- package/src/knowledge/ingest.ts +4 -4
- package/src/knowledge/lifecycle-hooks.ts +3 -3
- package/src/knowledge/types.ts +5 -8
- package/src/monitoring/constraint-doctor.ts +7 -106
- package/src/presets/__tests__/standard.test.ts +0 -2
- package/src/presets/standard.ts +1 -2
- package/src/pretool-use-hook.ts +68 -0
- package/src/spec/__tests__/annotation-checker.test.ts +9 -3
- package/src/spec/annotation-checker.ts +7 -29
- package/src/tools/CONTEXT.md +7 -14
- package/src/tools/index.ts +0 -4
- package/src/types/constraint.ts +1 -14
- package/src/types/project-config.ts +0 -3
- package/src/utils/file-walk.ts +2 -2
- package/dist/architecture/constraint-engine.d.ts +0 -67
- package/dist/architecture/constraint-engine.d.ts.map +0 -1
- package/dist/architecture/constraint-engine.js +0 -295
- package/dist/architecture/constraint-engine.js.map +0 -1
- package/dist/architecture/cross-project-checker.d.ts +0 -54
- package/dist/architecture/cross-project-checker.d.ts.map +0 -1
- package/dist/architecture/cross-project-checker.js +0 -467
- package/dist/architecture/cross-project-checker.js.map +0 -1
- package/dist/cli/commands/index.d.ts +0 -30
- package/dist/cli/commands/index.d.ts.map +0 -1
- package/dist/cli/commands/index.js +0 -91
- package/dist/cli/commands/index.js.map +0 -1
- package/dist/context/file-budget.d.ts +0 -40
- package/dist/context/file-budget.d.ts.map +0 -1
- package/dist/context/file-budget.js +0 -147
- package/dist/context/file-budget.js.map +0 -1
- package/dist/context/progressive-loader.d.ts +0 -109
- package/dist/context/progressive-loader.d.ts.map +0 -1
- package/dist/context/progressive-loader.js +0 -166
- package/dist/context/progressive-loader.js.map +0 -1
- package/dist/context/token-pipeline.d.ts +0 -55
- package/dist/context/token-pipeline.d.ts.map +0 -1
- package/dist/context/token-pipeline.js +0 -220
- package/dist/context/token-pipeline.js.map +0 -1
- package/dist/context/tool-output-budget.d.ts +0 -59
- package/dist/context/tool-output-budget.d.ts.map +0 -1
- package/dist/context/tool-output-budget.js +0 -177
- package/dist/context/tool-output-budget.js.map +0 -1
- package/dist/core/constraints/default-executors.d.ts +0 -10
- package/dist/core/constraints/default-executors.d.ts.map +0 -1
- package/dist/core/constraints/default-executors.js +0 -120
- package/dist/core/constraints/default-executors.js.map +0 -1
- package/dist/llm/adapter.d.ts +0 -36
- package/dist/llm/adapter.d.ts.map +0 -1
- package/dist/llm/adapter.js +0 -118
- package/dist/llm/adapter.js.map +0 -1
- package/dist/llm/index.d.ts +0 -3
- package/dist/llm/index.d.ts.map +0 -1
- package/dist/llm/index.js +0 -19
- package/dist/llm/index.js.map +0 -1
- package/dist/llm/types.d.ts +0 -62
- package/dist/llm/types.d.ts.map +0 -1
- package/dist/llm/types.js +0 -8
- package/dist/llm/types.js.map +0 -1
- package/dist/tools/core/index.d.ts +0 -13
- package/dist/tools/core/index.d.ts.map +0 -1
- package/dist/tools/core/index.js +0 -198
- package/dist/tools/core/index.js.map +0 -1
- package/dist/tools/loader.d.ts +0 -21
- package/dist/tools/loader.d.ts.map +0 -1
- package/dist/tools/loader.js +0 -199
- package/dist/tools/loader.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -59
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/registry.js +0 -115
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/types.d.ts +0 -38
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/types.js +0 -6
- package/dist/tools/types.js.map +0 -1
- package/src/__tests__/architecture-engine.test.ts +0 -619
- package/src/__tests__/context/progressive-loader.test.ts +0 -131
- package/src/__tests__/cross-project-checker.test.ts +0 -318
- package/src/architecture/CONTEXT.md +0 -22
- package/src/architecture/constraint-engine.ts +0 -351
- package/src/architecture/cross-project-checker.ts +0 -545
- package/src/cli/commands/index.ts +0 -30
- package/src/context/__tests__/file-budget.test.ts +0 -142
- package/src/context/__tests__/progressive-loader.test.ts +0 -264
- package/src/context/__tests__/token-pipeline.test.ts +0 -178
- package/src/context/__tests__/tool-output-budget.test.ts +0 -95
- package/src/context/file-budget.ts +0 -142
- package/src/context/progressive-loader.ts +0 -260
- package/src/context/token-pipeline.ts +0 -265
- package/src/context/tool-output-budget.ts +0 -178
- package/src/core/constraints/__tests__/default-executors.test.ts +0 -57
- package/src/core/constraints/default-executors.ts +0 -92
- package/src/llm/CONTEXT.md +0 -21
- package/src/llm/__tests__/adapter.test.ts +0 -172
- package/src/llm/adapter.ts +0 -149
- package/src/llm/index.ts +0 -2
- package/src/llm/types.ts +0 -81
- package/src/tools/__tests__/loader.test.ts +0 -252
- package/src/tools/__tests__/registry.test.ts +0 -157
- package/src/tools/core/__tests__/core.test.ts +0 -122
- package/src/tools/core/index.ts +0 -201
- package/src/tools/loader.ts +0 -216
- package/src/tools/registry.ts +0 -128
- package/src/tools/types.ts +0 -46
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令注册表闭环测试(H5:命令定义即注册 + per-command 懒加载)
|
|
3
|
+
*
|
|
4
|
+
* - 定义表内每个实现引用(module+export)都必须可解析(构建/测试期断言,
|
|
5
|
+
* 取代 commands barrel 的编译期保护——R6 消灭手工同步后的闭环兜底)
|
|
6
|
+
* - definitions 是纯数据模块:require 它不加载任何命令实现(保 --help/--version 懒加载)
|
|
7
|
+
* - 命令面与 CAPABILITIES.md 的 24 顶层命令一致(防误删回归)
|
|
8
|
+
* - bin/harness.js 端到端冒烟(dist 存在时):--version/--help 零命令实现模块,
|
|
9
|
+
* 单命令执行只加载该命令模块(O2 per-command 懒加载)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as os from 'os';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { spawnSync } from 'child_process';
|
|
16
|
+
import { COMMAND_DEFINITIONS, type CommandDefinition, type CommandImplRef } from '../definitions';
|
|
17
|
+
import { GATE_DEFINITIONS } from '../../../gates/definitions';
|
|
18
|
+
|
|
19
|
+
function collectRefs(defs: CommandDefinition[]): CommandImplRef[] {
|
|
20
|
+
const refs: CommandImplRef[] = [];
|
|
21
|
+
const walk = (def: CommandDefinition) => {
|
|
22
|
+
if (def.action) refs.push(def.action);
|
|
23
|
+
if (def.subcommands) {
|
|
24
|
+
for (const entry of Object.values(def.subcommands)) refs.push(entry.impl);
|
|
25
|
+
}
|
|
26
|
+
if (def.optionRoutes) {
|
|
27
|
+
for (const route of def.optionRoutes) refs.push(route.impl);
|
|
28
|
+
}
|
|
29
|
+
for (const child of def.children || []) walk(child);
|
|
30
|
+
};
|
|
31
|
+
for (const def of defs) walk(def);
|
|
32
|
+
return refs;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const EXPECTED_TOP_LEVEL_COMMANDS = [
|
|
36
|
+
'check', 'validate', 'passes-gate', 'init', 'report', 'status', 'spec',
|
|
37
|
+
'sync-docs', 'knowledge', 'sdd', 'failure', 'posteval-plan',
|
|
38
|
+
'update-user-model', 'release', 'analyze-sessions', 'constraints',
|
|
39
|
+
'doc-freshness-check', 'spec-baseline-check',
|
|
40
|
+
// 6 门禁命令(GATE_DEFINITIONS 驱动)
|
|
41
|
+
'acceptance', 'command', 'contract', 'performance', 'review', 'security',
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
describe('命令注册表闭环', () => {
|
|
45
|
+
it('definitions 是纯数据模块:加载时不引入任何命令实现', () => {
|
|
46
|
+
const loaded = Object.keys(require.cache)
|
|
47
|
+
.filter(k => k.includes('/cli/commands/') && k.endsWith('.ts') && !k.includes('__tests__'));
|
|
48
|
+
expect(loaded).toEqual([
|
|
49
|
+
expect.stringContaining('/cli/commands/definitions.ts'),
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('全部实现引用可解析(module 存在且 export 是函数)', () => {
|
|
54
|
+
const refs = collectRefs(COMMAND_DEFINITIONS);
|
|
55
|
+
for (const def of GATE_DEFINITIONS) {
|
|
56
|
+
refs.push(def.cli.action);
|
|
57
|
+
for (const entry of Object.values(def.cli.subcommands || {})) refs.push(entry);
|
|
58
|
+
}
|
|
59
|
+
expect(refs.length).toBeGreaterThan(0);
|
|
60
|
+
|
|
61
|
+
for (const ref of refs) {
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
63
|
+
const mod = require('../' + ref.module);
|
|
64
|
+
if (typeof mod[ref.export] !== 'function') {
|
|
65
|
+
throw new Error(`实现引用 ${ref.module}.${ref.export} 不存在或不是函数`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('顶层命令面与预期 24 命令一致(含 6 门禁)', () => {
|
|
71
|
+
const names = [
|
|
72
|
+
...COMMAND_DEFINITIONS.map(d => d.command.split(' ')[0]),
|
|
73
|
+
...GATE_DEFINITIONS.map(d => d.cli.command.split(' ')[0]),
|
|
74
|
+
];
|
|
75
|
+
expect(new Set(names).size).toBe(names.length);
|
|
76
|
+
expect(names.sort()).toEqual([...EXPECTED_TOP_LEVEL_COMMANDS].sort());
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('命令定义无重复注册名', () => {
|
|
80
|
+
const names = COMMAND_DEFINITIONS.map(d => d.command);
|
|
81
|
+
expect(new Set(names).size).toBe(names.length);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('全部命令定义的路由构造可执行(mapActionArgs/subcommands.args/optionRoutes.args/afterRun 冒烟)', () => {
|
|
85
|
+
const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never);
|
|
86
|
+
try {
|
|
87
|
+
const walk = (def: CommandDefinition) => {
|
|
88
|
+
if (def.mapActionArgs) {
|
|
89
|
+
def.mapActionArgs(['positional'], {});
|
|
90
|
+
def.mapActionArgs([], {});
|
|
91
|
+
}
|
|
92
|
+
for (const entry of Object.values(def.subcommands || {})) {
|
|
93
|
+
if (entry.args) {
|
|
94
|
+
entry.args(['positional'], {});
|
|
95
|
+
entry.args([], {});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const route of def.optionRoutes || []) {
|
|
99
|
+
if (route.args) {
|
|
100
|
+
route.args([], {});
|
|
101
|
+
route.args(['positional'], {});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (def.afterRun) {
|
|
105
|
+
def.afterRun(true, {});
|
|
106
|
+
def.afterRun(false, { check: true });
|
|
107
|
+
}
|
|
108
|
+
for (const child of def.children || []) walk(child);
|
|
109
|
+
};
|
|
110
|
+
for (const def of COMMAND_DEFINITIONS) walk(def);
|
|
111
|
+
// sync-docs --check 失败路径确实会请求退出
|
|
112
|
+
expect(exitSpy).toHaveBeenCalled();
|
|
113
|
+
} finally {
|
|
114
|
+
exitSpy.mockRestore();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const repoRoot = path.join(__dirname, '..', '..', '..', '..');
|
|
120
|
+
const distBin = path.join(repoRoot, 'bin', 'harness.js');
|
|
121
|
+
const distCommands = path.join(repoRoot, 'dist', 'cli', 'commands');
|
|
122
|
+
const hasDist = fs.existsSync(distCommands);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 经 NODE_OPTIONS=--require 预加载探针 spawn bin(进程退出时打印加载的
|
|
126
|
+
* 命令实现模块清单)。不用 node -e(commander 在 -e 下走 eval 分支,
|
|
127
|
+
* argv 解析不同,会误判位置参数)。
|
|
128
|
+
*/
|
|
129
|
+
function runWithModuleProbe(argv: string[]): { status: number | null; implModules: string[]; stdout: string; stderr: string } {
|
|
130
|
+
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-lazy-probe-'));
|
|
131
|
+
const probeFile = path.join(probeDir, 'probe.js');
|
|
132
|
+
fs.writeFileSync(probeFile, [
|
|
133
|
+
`process.on('exit', () => {`,
|
|
134
|
+
` const impls = Object.keys(require.cache).filter(k => /dist[\\\\/]cli[\\\\/]commands[\\\\/]/.test(k) && !/definitions\\.js/.test(k)).sort();`,
|
|
135
|
+
` console.error('IMPL_MODULES=' + impls.join(','));`,
|
|
136
|
+
`});`,
|
|
137
|
+
].join('\n'));
|
|
138
|
+
try {
|
|
139
|
+
const r = spawnSync(process.execPath, [distBin, ...argv], {
|
|
140
|
+
cwd: repoRoot,
|
|
141
|
+
encoding: 'utf-8',
|
|
142
|
+
timeout: 30000,
|
|
143
|
+
env: { ...process.env, NODE_OPTIONS: `--require ${probeFile}` },
|
|
144
|
+
});
|
|
145
|
+
const match = r.stderr.match(/IMPL_MODULES=(.*)/);
|
|
146
|
+
return {
|
|
147
|
+
status: r.status,
|
|
148
|
+
implModules: match && match[1] ? match[1].split(',').filter(Boolean) : [],
|
|
149
|
+
stdout: r.stdout,
|
|
150
|
+
stderr: r.stderr,
|
|
151
|
+
};
|
|
152
|
+
} finally {
|
|
153
|
+
fs.rmSync(probeDir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const smoke = hasDist ? describe : describe.skip;
|
|
158
|
+
|
|
159
|
+
smoke('bin/harness.js 端到端(dist 存在时)', () => {
|
|
160
|
+
it('--version:退出 0,零命令实现模块加载', () => {
|
|
161
|
+
const r = runWithModuleProbe(['--version']);
|
|
162
|
+
expect(r.status).toBe(0);
|
|
163
|
+
expect(r.implModules).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('--help:退出 0,零命令实现模块加载', () => {
|
|
167
|
+
const r = runWithModuleProbe(['--help']);
|
|
168
|
+
expect(r.status).toBe(0);
|
|
169
|
+
expect(r.implModules).toEqual([]);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('harness constraints --json:只加载 constraints 命令模块', () => {
|
|
173
|
+
const r = runWithModuleProbe(['constraints', '--json']);
|
|
174
|
+
expect(r.status).toBe(0);
|
|
175
|
+
expect(r.implModules).toEqual([
|
|
176
|
+
expect.stringContaining('/dist/cli/commands/constraints.js'),
|
|
177
|
+
]);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('harness check --list:只加载 check 命令模块(optionRoutes)', () => {
|
|
181
|
+
const r = runWithModuleProbe(['check', '--list']);
|
|
182
|
+
expect(r.status).toBe(0);
|
|
183
|
+
expect(r.implModules).toEqual([
|
|
184
|
+
expect.stringContaining('/dist/cli/commands/check.js'),
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('harness acceptance:只加载 acceptance 命令模块(门禁注册表)', () => {
|
|
189
|
+
const r = runWithModuleProbe(['acceptance', '--check-all']);
|
|
190
|
+
expect(r.status).toBe(0);
|
|
191
|
+
expect(r.implModules).toEqual([
|
|
192
|
+
expect.stringContaining('/dist/cli/commands/acceptance.js'),
|
|
193
|
+
]);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('未知子命令报错退出(knowledge 兜底行为保留)', () => {
|
|
197
|
+
const r = runWithModuleProbe(['knowledge', 'bogus']);
|
|
198
|
+
expect(r.status).toBe(1);
|
|
199
|
+
expect(r.stderr).toContain('未知子命令: bogus');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -242,6 +242,61 @@ describe('sync-docs --agents', () => {
|
|
|
242
242
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
243
243
|
});
|
|
244
244
|
|
|
245
|
+
describe('知识入口行:.studio/CONTEXT.md 正本模型(studio #188)', () => {
|
|
246
|
+
it('.studio/CONTEXT.md 存在时生成正本行,替代散置指引(散置文件同时在场也一样),--check 无漂移', async () => {
|
|
247
|
+
const testDir = path.join(tempDir, 'studio-context-model');
|
|
248
|
+
createFixture(testDir, { pnpm: true, withCapabilities: true });
|
|
249
|
+
// 夹具已带散置 src/CONTEXT.md:正本在场时整行替代,与是否残留散置文件无关
|
|
250
|
+
fs.mkdirSync(path.join(testDir, '.studio'), { recursive: true });
|
|
251
|
+
fs.writeFileSync(path.join(testDir, '.studio', 'CONTEXT.md'), '# 模块上下文\n\n## src\n\n职责:夹具\n');
|
|
252
|
+
|
|
253
|
+
await syncDocs({ projectPath: testDir, agents: true });
|
|
254
|
+
|
|
255
|
+
const content = fs.readFileSync(path.join(testDir, 'AGENTS.md'), 'utf-8');
|
|
256
|
+
expect(content).toContain('模块上下文正本:`.studio/CONTEXT.md`(模块锚点组织),改动代码时同步更新');
|
|
257
|
+
expect(content).not.toContain('各源码目录的 `CONTEXT.md`');
|
|
258
|
+
expect(content).not.toContain('缺失目录可由 `harness sync-docs` 生成模板');
|
|
259
|
+
// 知识库行不受影响
|
|
260
|
+
expect(content).toContain('项目知识库,用 `harness knowledge` 查询');
|
|
261
|
+
|
|
262
|
+
// 幂等 + --check 通过(正本模型下无漂移)
|
|
263
|
+
const second = await syncDocs({ projectPath: testDir, agents: true });
|
|
264
|
+
expect(second).toBe(true);
|
|
265
|
+
expect(await syncDocs({ projectPath: testDir, agents: true, check: true })).toBe(true);
|
|
266
|
+
|
|
267
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('.studio/CONTEXT.md 不存在时保持散置模型行,--check 无漂移', async () => {
|
|
271
|
+
const testDir = path.join(tempDir, 'scattered-context-model');
|
|
272
|
+
createFixture(testDir, { pnpm: true, withCapabilities: true });
|
|
273
|
+
|
|
274
|
+
await syncDocs({ projectPath: testDir, agents: true });
|
|
275
|
+
|
|
276
|
+
const content = fs.readFileSync(path.join(testDir, 'AGENTS.md'), 'utf-8');
|
|
277
|
+
expect(content).toContain('各源码目录的 `CONTEXT.md` 是权威模块文档(现有 1 个),改动代码时同步更新');
|
|
278
|
+
expect(content).not.toContain('模块上下文正本');
|
|
279
|
+
|
|
280
|
+
expect(await syncDocs({ projectPath: testDir, agents: true, check: true })).toBe(true);
|
|
281
|
+
|
|
282
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('.studio/CONTEXT.md 是目录而非文件时不视为正本', async () => {
|
|
286
|
+
const testDir = path.join(tempDir, 'studio-context-dir');
|
|
287
|
+
createFixture(testDir, { pnpm: true, withCapabilities: true });
|
|
288
|
+
fs.mkdirSync(path.join(testDir, '.studio', 'CONTEXT.md'), { recursive: true });
|
|
289
|
+
|
|
290
|
+
await syncDocs({ projectPath: testDir, agents: true });
|
|
291
|
+
|
|
292
|
+
const content = fs.readFileSync(path.join(testDir, 'AGENTS.md'), 'utf-8');
|
|
293
|
+
expect(content).toContain('各源码目录的 `CONTEXT.md` 是权威模块文档');
|
|
294
|
+
expect(content).not.toContain('模块上下文正本');
|
|
295
|
+
|
|
296
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
245
300
|
it('空项目应该生成兜底内容(无 package.json、无治理配置、无知识库)', async () => {
|
|
246
301
|
const testDir = path.join(tempDir, 'empty-project');
|
|
247
302
|
// 只放应被跳过的目录:依赖/构建产物/隐藏目录
|
|
@@ -49,7 +49,6 @@ export async function check(options: CheckOptions): Promise<void> {
|
|
|
49
49
|
const merged = configLoader.hasCustomConfig()
|
|
50
50
|
? configLoader.mergeConstraints()
|
|
51
51
|
: configLoader.mergeConstraints({ preset: options.preset || 'standard' });
|
|
52
|
-
constraintChecker.setCustomConfig(merged);
|
|
53
52
|
if (merged.custom.length > 0) {
|
|
54
53
|
console.log(chalk.gray(`自定义约束: ${merged.custom.length} 条`));
|
|
55
54
|
}
|
|
@@ -73,8 +72,8 @@ export async function check(options: CheckOptions): Promise<void> {
|
|
|
73
72
|
}
|
|
74
73
|
console.log(chalk.gray(`触发条件: ${[context.operation, ...(context.extraTriggers ?? [])].join(', ')}`));
|
|
75
74
|
|
|
76
|
-
//
|
|
77
|
-
const result = await constraintChecker.checkConstraints(context);
|
|
75
|
+
// 执行三层检查(per-request 传 customConfig,避免单例状态污染)
|
|
76
|
+
const result = await constraintChecker.checkConstraints(context, merged);
|
|
78
77
|
|
|
79
78
|
// 输出结果
|
|
80
79
|
console.log();
|
|
@@ -83,7 +82,6 @@ export async function check(options: CheckOptions): Promise<void> {
|
|
|
83
82
|
const skippedResults = [
|
|
84
83
|
...result.ironLaws,
|
|
85
84
|
...result.guidelines,
|
|
86
|
-
...result.tips,
|
|
87
85
|
].filter(r => r.skipped);
|
|
88
86
|
|
|
89
87
|
// Iron Laws
|
|
@@ -118,16 +116,6 @@ export async function check(options: CheckOptions): Promise<void> {
|
|
|
118
116
|
console.log(chalk.green(`✅ 指导原则: ${passedGuidelines}/${evaluatedGuidelines.length} 通过`));
|
|
119
117
|
}
|
|
120
118
|
|
|
121
|
-
// Tips
|
|
122
|
-
if (result.tipCount > 0) {
|
|
123
|
-
console.log(chalk.blue(`💡 提示: ${result.tipCount} 条`));
|
|
124
|
-
result.tips.filter(r => !r.satisfied).forEach(r => {
|
|
125
|
-
if (r.constraint) {
|
|
126
|
-
console.log(chalk.blue(` - ${r.constraint.id}: ${r.constraint.message}`));
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
119
|
// Skipped:约定未采用 / 证据未接线,未评估(不计通过/失败)
|
|
132
120
|
if (skippedResults.length > 0) {
|
|
133
121
|
console.log(chalk.gray(`⏭️ 跳过评估: ${skippedResults.length} 条(约定未采用或证据未接线,不计通过/失败)`));
|