@dommaker/harness 0.19.0 → 1.0.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 +14 -0
- 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/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/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 +4 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -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/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 +14 -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__/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/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/capabilities-syncer.ts +4 -110
- package/src/cli/commands/sync-docs/index.ts +8 -5
- 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 +5 -22
- 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/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
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CAPABILITIES.md
|
|
2
|
+
* CAPABILITIES.md 文件表格同步器(工单 22)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* - 能力清单格式:计数行(CLI Commands (N) 等),FreshnessRunner 校验与刷新
|
|
4
|
+
* 只负责文件表格格式:模块/文件/说明三列表格,增删行维护。
|
|
5
|
+
* 能力清单格式(计数行)的解析与计数已收敛到 core/constraints/capabilities-parser(H2 O10-R3)。
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import * as fs from 'fs/promises';
|
|
10
9
|
import * as path from 'path';
|
|
11
|
-
import {
|
|
12
|
-
import { isCapabilityListingFormat, readCapabilitiesEntries } from '../../../core/constraints/capabilities-parser';
|
|
13
|
-
import { FreshnessRunner } from '../../../core/constraints/doc-freshness/runner';
|
|
10
|
+
import { readCapabilitiesEntries } from '../../../core/constraints/capabilities-parser';
|
|
14
11
|
import type { CapabilitiesMode } from '../../../core/project-config-loader';
|
|
15
|
-
import type { DocFreshnessCheck } from '../../../types/project-config';
|
|
16
12
|
import type { ModuleInfo, SyncResult } from './project-reader';
|
|
17
13
|
|
|
18
14
|
/**
|
|
@@ -33,108 +29,6 @@ export async function parseCapabilitiesFiles(capabilitiesPath: string): Promise<
|
|
|
33
29
|
return files;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
/**
|
|
37
|
-
* 检测 CAPABILITIES.md 是否使用能力清单格式(计数行),而非文件表格格式
|
|
38
|
-
*
|
|
39
|
-
* @deprecated 实现已收敛到 core/constraints/capabilities-parser(与工单 19-B 同方向),
|
|
40
|
-
* 此处保留 re-export 兼容现有调用方
|
|
41
|
-
*/
|
|
42
|
-
export { isCapabilityListingFormat };
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 构建 CAPABILITIES.md 能力清单格式的检查配置
|
|
46
|
-
*/
|
|
47
|
-
function buildCapabilityChecks(): DocFreshnessCheck[] {
|
|
48
|
-
return [
|
|
49
|
-
{
|
|
50
|
-
type: 'doc_regex_count',
|
|
51
|
-
doc: 'CAPABILITIES.md',
|
|
52
|
-
label: 'CLI Commands',
|
|
53
|
-
pattern: 'CLI Commands\\s*\\((\\d+)\\)',
|
|
54
|
-
actual: { kind: 'dir_count', path: 'src/cli/commands', extension: '.ts', exclude: ['index.ts'] },
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
type: 'doc_regex_count',
|
|
58
|
-
doc: 'CAPABILITIES.md',
|
|
59
|
-
label: 'Quality Gates',
|
|
60
|
-
pattern: 'Quality Gates?\\s*\\((\\d+)\\)',
|
|
61
|
-
actual: { kind: 'dir_count', path: 'src/gates', extension: '.ts', exclude: ['index.ts', 'types.ts'] },
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
type: 'doc_regex_count',
|
|
65
|
-
doc: 'CAPABILITIES.md',
|
|
66
|
-
label: 'Iron Laws',
|
|
67
|
-
pattern: 'Iron Laws?\\s*\\((\\d+)\\)',
|
|
68
|
-
actual: { kind: 'const_count', value: Object.keys(IRON_LAWS).length },
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
type: 'doc_regex_count',
|
|
72
|
-
doc: 'CAPABILITIES.md',
|
|
73
|
-
label: 'Guidelines',
|
|
74
|
-
pattern: 'Guidelines?\\s*\\((\\d+)\\)',
|
|
75
|
-
actual: { kind: 'const_count', value: Object.keys(GUIDELINES).length },
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: 'doc_regex_count',
|
|
79
|
-
doc: 'CAPABILITIES.md',
|
|
80
|
-
label: 'Tips',
|
|
81
|
-
pattern: 'Tips?\\s*\\((\\d+)\\)',
|
|
82
|
-
actual: { kind: 'const_count', value: Object.keys(TIPS).length },
|
|
83
|
-
},
|
|
84
|
-
];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 使用 FreshnessRunner 检查能力清单计数是否与代码一致(--check 模式)
|
|
89
|
-
*/
|
|
90
|
-
export function checkCapabilityCounts(
|
|
91
|
-
projectPath: string
|
|
92
|
-
): { match: boolean; mismatches: string[] } {
|
|
93
|
-
const runner = new FreshnessRunner();
|
|
94
|
-
const checks = buildCapabilityChecks();
|
|
95
|
-
const results = runner.runAll({ checks }, projectPath);
|
|
96
|
-
|
|
97
|
-
const mismatches: string[] = [];
|
|
98
|
-
for (const r of results) {
|
|
99
|
-
if (!r.pass && r.message) {
|
|
100
|
-
mismatches.push(r.message);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return { match: mismatches.length === 0, mismatches };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
|
|
109
|
-
*
|
|
110
|
-
* 使用 FreshnessRunner 获取实际计数,然后 regex 替换文档计数行。
|
|
111
|
-
*/
|
|
112
|
-
export function updateCapabilityCounts(content: string, projectPath: string): string {
|
|
113
|
-
const runner = new FreshnessRunner();
|
|
114
|
-
|
|
115
|
-
const cliCount = runner.countFromDir('src/cli/commands', '.ts', ['index.ts'], projectPath);
|
|
116
|
-
const gateCount = runner.countFromDir('src/gates', '.ts', ['index.ts', 'types.ts'], projectPath);
|
|
117
|
-
const ironCount = Object.keys(IRON_LAWS).length;
|
|
118
|
-
const guideCount = Object.keys(GUIDELINES).length;
|
|
119
|
-
const tipsCount = Object.keys(TIPS).length;
|
|
120
|
-
|
|
121
|
-
const replacements: [RegExp, string][] = [
|
|
122
|
-
[/CLI Commands\s*\(\d+\)/, `CLI Commands (${cliCount})`],
|
|
123
|
-
[/Quality Gates?\s*\(\d+\)/, `Quality Gates (${gateCount})`],
|
|
124
|
-
[/Iron Laws?\s*\(\d+\)/, `Iron Laws (${ironCount})`],
|
|
125
|
-
[/Guidelines?\s*\(\d+\)/, `Guidelines (${guideCount})`],
|
|
126
|
-
[/Tips?\s*\(\d+\)/, `Tips (${tipsCount})`],
|
|
127
|
-
];
|
|
128
|
-
|
|
129
|
-
for (const [regex, replacement] of replacements) {
|
|
130
|
-
if (regex.test(content)) {
|
|
131
|
-
content = content.replace(regex, replacement);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return content;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
32
|
/**
|
|
139
33
|
* 更新 CAPABILITIES.md 文件
|
|
140
34
|
*
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 实现拆分:
|
|
8
8
|
* - project-reader.ts 项目信息读取(package.json/config.yml/源码扫描)
|
|
9
|
-
* - capabilities-syncer.ts CAPABILITIES.md
|
|
9
|
+
* - capabilities-syncer.ts CAPABILITIES.md 文件表格格式的对比与维护(能力清单格式解析/计数走 core/constraints/capabilities-parser)
|
|
10
10
|
* - context-syncer.ts CONTEXT.md 模板生成/发现/过时判定
|
|
11
11
|
* - agents-syncer.ts AGENTS.md 生成
|
|
12
12
|
* - preserve-block.ts PRESERVE 标记块提取与组合
|
|
@@ -16,16 +16,19 @@ import chalk from 'chalk';
|
|
|
16
16
|
import * as fs from 'fs/promises';
|
|
17
17
|
import { existsSync } from 'fs';
|
|
18
18
|
import * as path from 'path';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
aggregateToSourceSubdir,
|
|
21
|
+
readCapabilitiesEntries,
|
|
22
|
+
isCapabilityListingFormat,
|
|
23
|
+
checkCapabilityCounts,
|
|
24
|
+
updateCapabilityCounts,
|
|
25
|
+
} from '../../../core/constraints/capabilities-parser';
|
|
20
26
|
import { detectSourceRoots } from '../../../utils/detect-source-roots';
|
|
21
27
|
import { getCapabilitiesMode } from '../../../core/project-config-loader';
|
|
22
28
|
import { getSourceDirs, scanSourceModules, getRequiredContextDirs } from './project-reader';
|
|
23
29
|
import type { ModuleInfo, SyncResult } from './project-reader';
|
|
24
30
|
import {
|
|
25
31
|
parseCapabilitiesFiles,
|
|
26
|
-
isCapabilityListingFormat,
|
|
27
|
-
checkCapabilityCounts,
|
|
28
|
-
updateCapabilityCounts,
|
|
29
32
|
updateCapabilitiesFile,
|
|
30
33
|
compactCapabilitiesContent,
|
|
31
34
|
} from './capabilities-syncer';
|
package/src/context/CONTEXT.md
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# context/
|
|
2
2
|
|
|
3
3
|
## 职责
|
|
4
|
-
上下文管理:Token 预算(多级分配)
|
|
4
|
+
上下文管理:Token 预算(多级分配)、会话压缩、会话管理、知识注入。
|
|
5
5
|
|
|
6
6
|
## 核心导出
|
|
7
7
|
- `TokenBudget` — 多级 token 预算(system/user/tool/reserve)
|
|
8
|
-
- `ProgressiveLoader` — 渐进式加载 + worker pool 并发
|
|
9
|
-
- `FileBudget` — 文件级 token 预算
|
|
10
|
-
- `ToolOutputBudget` — 工具输出 token 预算
|
|
11
8
|
- `Compaction` — 会话压缩(摘要/截断/滑动窗口)
|
|
12
|
-
- `TokenPipeline` — Token 流水线
|
|
13
9
|
- `SessionManager` — 会话管理
|
|
14
10
|
- `KnowledgeInjector` — 知识注入引擎
|
|
15
11
|
|
|
@@ -20,9 +16,8 @@
|
|
|
20
16
|
|
|
21
17
|
## 约定
|
|
22
18
|
- Token 预算策略由配置文件控制
|
|
23
|
-
- 渐进式加载保证输入顺序(worker pool 模式)
|
|
24
19
|
- 会话压缩策略可组合
|
|
25
20
|
|
|
26
21
|
## 注意事项
|
|
27
|
-
- Phase 2 实现的 Token 流水线 + 预算 + 压缩
|
|
28
22
|
- 零 Token 成本:纯计算,不调用 LLM
|
|
23
|
+
- Phase 2 前瞻的渐进式加载/Token 流水线/文件与工具输出预算已随 H1(#40)删除
|
|
@@ -81,50 +81,6 @@ describe('SessionManager', () => {
|
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
describe('getWindowView', () => {
|
|
85
|
-
it('应该生成窗口视图', () => {
|
|
86
|
-
manager.createSession('session-1');
|
|
87
|
-
manager.appendToSession('session-1', {
|
|
88
|
-
type: 'system',
|
|
89
|
-
id: 'sys-1',
|
|
90
|
-
content: 'You are helpful.',
|
|
91
|
-
timestamp: 't1',
|
|
92
|
-
});
|
|
93
|
-
manager.appendToSession('session-1', {
|
|
94
|
-
type: 'user_message',
|
|
95
|
-
id: 'msg-1',
|
|
96
|
-
content: 'Hello',
|
|
97
|
-
timestamp: 't2',
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
const output = manager.getWindowView('session-1', {
|
|
101
|
-
total: 8000,
|
|
102
|
-
systemPrompt: 1000,
|
|
103
|
-
toolDefinitions: 500,
|
|
104
|
-
knowledge: 600,
|
|
105
|
-
notes: 300,
|
|
106
|
-
history: 5600,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
expect(output.prompt).toContain('You are helpful.');
|
|
110
|
-
expect(output.prompt).toContain('Hello');
|
|
111
|
-
expect(output.snapshot).toBeDefined();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('应该抛出当会话不存在', () => {
|
|
115
|
-
expect(() => {
|
|
116
|
-
manager.getWindowView('nonexistent', {
|
|
117
|
-
total: 8000,
|
|
118
|
-
systemPrompt: 1000,
|
|
119
|
-
toolDefinitions: 500,
|
|
120
|
-
knowledge: 600,
|
|
121
|
-
notes: 300,
|
|
122
|
-
history: 5600,
|
|
123
|
-
});
|
|
124
|
-
}).toThrow('不存在');
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
84
|
describe('checkpointSession', () => {
|
|
129
85
|
it('应该生成 checkpoint', () => {
|
|
130
86
|
manager.createSession('session-1');
|
|
@@ -250,51 +206,4 @@ describe('SessionManager', () => {
|
|
|
250
206
|
});
|
|
251
207
|
});
|
|
252
208
|
|
|
253
|
-
describe('getWindowView with all event types', () => {
|
|
254
|
-
it('handles all event types through eventsToSources', () => {
|
|
255
|
-
manager.createSession('session-event-types');
|
|
256
|
-
manager.appendToSession('session-event-types', {
|
|
257
|
-
type: 'system',
|
|
258
|
-
id: 'sys-1',
|
|
259
|
-
content: 'System prompt',
|
|
260
|
-
timestamp: 't1',
|
|
261
|
-
});
|
|
262
|
-
manager.appendToSession('session-event-types', {
|
|
263
|
-
type: 'assistant_message',
|
|
264
|
-
id: 'asst-1',
|
|
265
|
-
content: 'I will help',
|
|
266
|
-
timestamp: 't2',
|
|
267
|
-
});
|
|
268
|
-
manager.appendToSession('session-event-types', {
|
|
269
|
-
type: 'tool_call',
|
|
270
|
-
id: 'tool-1',
|
|
271
|
-
content: 'run test',
|
|
272
|
-
timestamp: 't3',
|
|
273
|
-
});
|
|
274
|
-
manager.appendToSession('session-event-types', {
|
|
275
|
-
type: 'tool_result',
|
|
276
|
-
id: 'tool-2',
|
|
277
|
-
content: 'test output',
|
|
278
|
-
timestamp: 't4',
|
|
279
|
-
});
|
|
280
|
-
manager.appendToSession('session-event-types', {
|
|
281
|
-
type: 'checkpoint',
|
|
282
|
-
id: 'cp-1',
|
|
283
|
-
content: 'session summary',
|
|
284
|
-
timestamp: 't5',
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
const output = manager.getWindowView('session-event-types', {
|
|
288
|
-
total: 8000,
|
|
289
|
-
systemPrompt: 1000,
|
|
290
|
-
toolDefinitions: 500,
|
|
291
|
-
knowledge: 600,
|
|
292
|
-
notes: 300,
|
|
293
|
-
history: 5600,
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
expect(output).toBeDefined();
|
|
297
|
-
expect(output.prompt).toBeDefined();
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
209
|
});
|
package/src/context/index.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 上下文管理模块
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Token 预算 + 会话压缩 + 知识注入
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export * from './types';
|
|
8
8
|
export * from './token-budget';
|
|
9
|
-
export * from './progressive-loader';
|
|
10
|
-
export * from './file-budget';
|
|
11
|
-
export * from './tool-output-budget';
|
|
12
9
|
export * from './compaction';
|
|
13
|
-
export * from './token-pipeline';
|
|
14
10
|
export * from './session-manager';
|
|
15
11
|
export * from './knowledge-injector';
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 知识注入器
|
|
3
3
|
*
|
|
4
|
-
* 将知识条目转换为 ContextSource
|
|
4
|
+
* 将知识条目转换为 ContextSource,供上层上下文组装消费
|
|
5
5
|
* 支持按阶段预算、类型过滤、去重
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { KnowledgeQuery } from '../knowledge/query';
|
|
9
9
|
import { TokenEstimator } from './token-budget';
|
|
10
|
-
import type { KnowledgeEntry,
|
|
10
|
+
import type { KnowledgeEntry, KnowledgeSubsystem } from '../knowledge/types';
|
|
11
11
|
import type { ContextSource } from './types';
|
|
12
12
|
|
|
13
13
|
export interface InjectionConfig {
|
|
14
14
|
/** Token 预算(默认 800) */
|
|
15
15
|
budget: number;
|
|
16
16
|
/** 关注的知识类型 */
|
|
17
|
-
focusTypes?:
|
|
17
|
+
focusTypes?: KnowledgeSubsystem[];
|
|
18
18
|
/** 当前阶段 */
|
|
19
19
|
phase?: string;
|
|
20
20
|
/** 已注入的条目 ID(去重) */
|
|
@@ -8,26 +8,20 @@
|
|
|
8
8
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
|
-
import { TokenPipeline } from './token-pipeline';
|
|
12
11
|
import { ContextTracker } from '../monitoring/context-tracker';
|
|
13
12
|
import type {
|
|
14
13
|
SessionEvent,
|
|
15
14
|
SessionHandle,
|
|
16
15
|
SessionCheckpoint,
|
|
17
|
-
TokenBudgetAllocation,
|
|
18
|
-
PipelineOutput,
|
|
19
|
-
ContextSource,
|
|
20
16
|
} from './types';
|
|
21
17
|
|
|
22
18
|
export class SessionManager {
|
|
23
19
|
private basePath: string;
|
|
24
20
|
private sessions: Map<string, SessionHandle> = new Map();
|
|
25
|
-
private pipeline: TokenPipeline;
|
|
26
21
|
private tracker: ContextTracker;
|
|
27
22
|
|
|
28
23
|
constructor(basePath?: string) {
|
|
29
24
|
this.basePath = basePath || process.cwd();
|
|
30
|
-
this.pipeline = new TokenPipeline();
|
|
31
25
|
this.tracker = new ContextTracker(this.basePath);
|
|
32
26
|
}
|
|
33
27
|
|
|
@@ -139,29 +133,6 @@ export class SessionManager {
|
|
|
139
133
|
this.appendEvent(id, event);
|
|
140
134
|
}
|
|
141
135
|
|
|
142
|
-
/**
|
|
143
|
-
* 获取当前轮窗口视图(自动从磁盘加载,S2)
|
|
144
|
-
*
|
|
145
|
-
* 将 session 事件转换为 ContextSource,通过 TokenPipeline 生成 prompt
|
|
146
|
-
*/
|
|
147
|
-
getWindowView(id: string, budget: TokenBudgetAllocation): PipelineOutput {
|
|
148
|
-
const handle = this.getSession(id);
|
|
149
|
-
if (!handle) {
|
|
150
|
-
throw new Error(`会话 ${id} 不存在`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 将事件转换为 ContextSource
|
|
154
|
-
const sources = this.eventsToSources(handle.events);
|
|
155
|
-
|
|
156
|
-
// 通过 pipeline 生成窗口视图
|
|
157
|
-
const output = this.pipeline.run({ sources, budget });
|
|
158
|
-
|
|
159
|
-
// 记录快照
|
|
160
|
-
this.tracker.record(output.snapshot);
|
|
161
|
-
|
|
162
|
-
return output;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
136
|
/**
|
|
166
137
|
* 生成 checkpoint(自动从磁盘加载,S2)
|
|
167
138
|
*/
|
|
@@ -242,51 +213,6 @@ export class SessionManager {
|
|
|
242
213
|
return this.tracker;
|
|
243
214
|
}
|
|
244
215
|
|
|
245
|
-
/**
|
|
246
|
-
* 将事件转换为 ContextSource
|
|
247
|
-
*/
|
|
248
|
-
private eventsToSources(events: SessionEvent[]): ContextSource[] {
|
|
249
|
-
return events.map(event => {
|
|
250
|
-
let priority: number;
|
|
251
|
-
let type: ContextSource['type'];
|
|
252
|
-
|
|
253
|
-
switch (event.type) {
|
|
254
|
-
case 'system':
|
|
255
|
-
priority = 1;
|
|
256
|
-
type = 'system_prompt';
|
|
257
|
-
break;
|
|
258
|
-
case 'user_message':
|
|
259
|
-
priority = 6;
|
|
260
|
-
type = 'user_message';
|
|
261
|
-
break;
|
|
262
|
-
case 'assistant_message':
|
|
263
|
-
priority = 5;
|
|
264
|
-
type = 'session_event';
|
|
265
|
-
break;
|
|
266
|
-
case 'tool_call':
|
|
267
|
-
case 'tool_result':
|
|
268
|
-
priority = 5;
|
|
269
|
-
type = 'tool_output';
|
|
270
|
-
break;
|
|
271
|
-
case 'checkpoint':
|
|
272
|
-
priority = 4;
|
|
273
|
-
type = 'session_event';
|
|
274
|
-
break;
|
|
275
|
-
default:
|
|
276
|
-
priority = 5;
|
|
277
|
-
type = 'session_event';
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
type,
|
|
282
|
-
id: event.id,
|
|
283
|
-
content: event.content,
|
|
284
|
-
priority,
|
|
285
|
-
metadata: event.metadata,
|
|
286
|
-
};
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
216
|
/**
|
|
291
217
|
* 生成 checkpoint 摘要
|
|
292
218
|
*/
|
package/src/context/types.ts
CHANGED
|
@@ -1,49 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 上下文管理类型定义
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Token 预算 + 会话压缩 + 会话管理 + 知识注入
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { QueryResult } from '../knowledge/types';
|
|
8
|
-
|
|
9
|
-
// ========================================
|
|
10
|
-
// 文件读取预算
|
|
11
|
-
// ========================================
|
|
12
|
-
|
|
13
|
-
export interface FileBudgetConfig {
|
|
14
|
-
maxLines: number; // 默认 2000
|
|
15
|
-
maxBytes: number; // 默认 50KB (51200)
|
|
16
|
-
maxTokenEstimate: number; // 默认 8000
|
|
17
|
-
continuationHint: boolean; // 默认 true
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const DEFAULT_FILE_BUDGET: FileBudgetConfig = {
|
|
21
|
-
maxLines: 2000,
|
|
22
|
-
maxBytes: 51200,
|
|
23
|
-
maxTokenEstimate: 8000,
|
|
24
|
-
continuationHint: true,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// ========================================
|
|
28
|
-
// 工具输出预算
|
|
29
|
-
// ========================================
|
|
30
|
-
|
|
31
|
-
export interface ToolOutputBudgetConfig {
|
|
32
|
-
maxChars: number; // 默认 16000
|
|
33
|
-
maxTokenRatio: number; // 默认 0.3 (占总预算 30%)
|
|
34
|
-
previewLines: number; // 默认 50
|
|
35
|
-
overflowToDisk: boolean; // 默认 false
|
|
36
|
-
dedup: boolean; // 默认 true
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const DEFAULT_TOOL_OUTPUT_BUDGET: ToolOutputBudgetConfig = {
|
|
40
|
-
maxChars: 16000,
|
|
41
|
-
maxTokenRatio: 0.3,
|
|
42
|
-
previewLines: 50,
|
|
43
|
-
overflowToDisk: false,
|
|
44
|
-
dedup: true,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
7
|
// ========================================
|
|
48
8
|
// 会话压缩
|
|
49
9
|
// ========================================
|
|
@@ -76,7 +36,7 @@ export interface SessionMessage {
|
|
|
76
36
|
}
|
|
77
37
|
|
|
78
38
|
// ========================================
|
|
79
|
-
//
|
|
39
|
+
// 上下文来源
|
|
80
40
|
// ========================================
|
|
81
41
|
|
|
82
42
|
export type ContextSourceType = 'session_event' | 'tool_output' | 'knowledge' | 'user_message' | 'system_prompt' | 'tool_definition';
|
|
@@ -89,27 +49,6 @@ export interface ContextSource {
|
|
|
89
49
|
metadata?: Record<string, any>;
|
|
90
50
|
}
|
|
91
51
|
|
|
92
|
-
export interface TokenBudgetAllocation {
|
|
93
|
-
total: number;
|
|
94
|
-
systemPrompt: number; // 固定,不压缩
|
|
95
|
-
toolDefinitions: number; // 按需懒加载
|
|
96
|
-
knowledge: number; // 500-800
|
|
97
|
-
notes: number; // 200-500
|
|
98
|
-
history: number; // 剩余预算
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface PipelineInput {
|
|
102
|
-
sources: ContextSource[];
|
|
103
|
-
budget: TokenBudgetAllocation;
|
|
104
|
-
knowledge?: QueryResult;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export interface PipelineOutput {
|
|
108
|
-
prompt: string;
|
|
109
|
-
snapshot: ContextUsageSnapshot;
|
|
110
|
-
dropped: Array<{ type: string; id: string; reason: string }>;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
52
|
// ========================================
|
|
114
53
|
// 上下文使用快照
|
|
115
54
|
// ========================================
|
|
@@ -64,7 +64,6 @@ describe('ConstraintInterceptor', () => {
|
|
|
64
64
|
mockChecker.getConstraints.mockReturnValue({
|
|
65
65
|
ironLaws: { test_iron_law: mockIronLaw },
|
|
66
66
|
guidelines: { test_guideline: mockGuideline },
|
|
67
|
-
tips: {},
|
|
68
67
|
prompts: {},
|
|
69
68
|
});
|
|
70
69
|
});
|
|
@@ -202,7 +201,6 @@ describe('ConstraintInterceptor', () => {
|
|
|
202
201
|
mockChecker.getConstraints.mockReturnValue({
|
|
203
202
|
ironLaws: {},
|
|
204
203
|
guidelines: {},
|
|
205
|
-
tips: {},
|
|
206
204
|
prompts: {},
|
|
207
205
|
});
|
|
208
206
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* custom 追加 → scenes 过滤),与 init 注入、harness check 同一来源。
|
|
9
9
|
*
|
|
10
10
|
* 输出按层级分组:铁律 → 指导原则 → 行为提示;无 promptInjection 的约束
|
|
11
|
-
* (如 docs_freshness)不渲染。
|
|
11
|
+
* (如 docs_freshness)不渲染。
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type { Constraint, ConstraintLevel, ConstraintTrigger } from '../../types/constraint';
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CAPABILITIES.md
|
|
2
|
+
* CAPABILITIES.md 解析与能力清单计数(工单 19-B / H2 O10-R3)
|
|
3
3
|
*
|
|
4
4
|
* 此前 checker.parseCapabilitiesFiles 与 sync-docs.parseCapabilitiesFiles
|
|
5
|
-
* 各持一份正则,收敛到此处。
|
|
5
|
+
* 各持一份正则,收敛到此处。H2 起能力清单计数(checkCapabilityCounts /
|
|
6
|
+
* updateCapabilityCounts)也从 sync-docs/capabilities-syncer 收敛到此,
|
|
7
|
+
* 使本模块成为 CAPABILITIES.md 解析 + 计数唯一入口。
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import * as fs from 'fs';
|
|
11
|
+
import { IRON_LAWS, GUIDELINES } from './definitions';
|
|
12
|
+
import { FreshnessRunner } from './doc-freshness/runner';
|
|
13
|
+
import type { DocFreshnessCheck } from '../../types/project-config';
|
|
9
14
|
|
|
10
15
|
/** 匹配表格单元格中的源码文件条目(如 `src/foo.ts`、`foo.tsx`) */
|
|
11
16
|
const FILE_CELL_REGEX = /\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/g;
|
|
@@ -96,3 +101,91 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
|
|
|
96
101
|
if (idx === -1) return prefix;
|
|
97
102
|
return prefix + rest.slice(0, idx) + '/';
|
|
98
103
|
}
|
|
104
|
+
|
|
105
|
+
// ── 能力清单计数 ────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 构建 CAPABILITIES.md 能力清单格式的检查配置
|
|
109
|
+
*/
|
|
110
|
+
function buildCapabilityChecks(): DocFreshnessCheck[] {
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
type: 'doc_regex_count',
|
|
114
|
+
doc: 'CAPABILITIES.md',
|
|
115
|
+
label: 'CLI Commands',
|
|
116
|
+
pattern: 'CLI Commands\\s*\\((\\d+)\\)',
|
|
117
|
+
// index.ts(已删 barrel)与 definitions.ts(命令注册表纯数据)不是命令实现,不计入
|
|
118
|
+
actual: { kind: 'dir_count', path: 'src/cli/commands', extension: '.ts', exclude: ['index.ts', 'definitions.ts'] },
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'doc_regex_count',
|
|
122
|
+
doc: 'CAPABILITIES.md',
|
|
123
|
+
label: 'Quality Gates',
|
|
124
|
+
pattern: 'Quality Gates?\\s*\\((\\d+)\\)',
|
|
125
|
+
actual: { kind: 'dir_count', path: 'src/gates', extension: '.ts', exclude: ['index.ts', 'types.ts'] },
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: 'doc_regex_count',
|
|
129
|
+
doc: 'CAPABILITIES.md',
|
|
130
|
+
label: 'Iron Laws',
|
|
131
|
+
pattern: 'Iron Laws?\\s*\\((\\d+)\\)',
|
|
132
|
+
actual: { kind: 'const_count', value: Object.keys(IRON_LAWS).length },
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'doc_regex_count',
|
|
136
|
+
doc: 'CAPABILITIES.md',
|
|
137
|
+
label: 'Guidelines',
|
|
138
|
+
pattern: 'Guidelines?\\s*\\((\\d+)\\)',
|
|
139
|
+
actual: { kind: 'const_count', value: Object.keys(GUIDELINES).length },
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 使用 FreshnessRunner 检查能力清单计数是否与代码一致(--check 模式)
|
|
146
|
+
*/
|
|
147
|
+
export function checkCapabilityCounts(
|
|
148
|
+
projectPath: string
|
|
149
|
+
): { match: boolean; mismatches: string[] } {
|
|
150
|
+
const runner = new FreshnessRunner();
|
|
151
|
+
const checks = buildCapabilityChecks();
|
|
152
|
+
const results = runner.runAll({ checks }, projectPath);
|
|
153
|
+
|
|
154
|
+
const mismatches: string[] = [];
|
|
155
|
+
for (const r of results) {
|
|
156
|
+
if (!r.pass && r.message) {
|
|
157
|
+
mismatches.push(r.message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return { match: mismatches.length === 0, mismatches };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
|
|
166
|
+
*
|
|
167
|
+
* 使用 FreshnessRunner 获取实际计数,然后 regex 替换文档计数行。
|
|
168
|
+
*/
|
|
169
|
+
export function updateCapabilityCounts(content: string, projectPath: string): string {
|
|
170
|
+
const runner = new FreshnessRunner();
|
|
171
|
+
|
|
172
|
+
const cliCount = runner.countFromDir('src/cli/commands', '.ts', ['index.ts', 'definitions.ts'], projectPath);
|
|
173
|
+
const gateCount = runner.countFromDir('src/gates', '.ts', ['index.ts', 'types.ts'], projectPath);
|
|
174
|
+
const ironCount = Object.keys(IRON_LAWS).length;
|
|
175
|
+
const guideCount = Object.keys(GUIDELINES).length;
|
|
176
|
+
|
|
177
|
+
const replacements: [RegExp, string][] = [
|
|
178
|
+
[/CLI Commands\s*\(\d+\)/, `CLI Commands (${cliCount})`],
|
|
179
|
+
[/Quality Gates?\s*\(\d+\)/, `Quality Gates (${gateCount})`],
|
|
180
|
+
[/Iron Laws?\s*\(\d+\)/, `Iron Laws (${ironCount})`],
|
|
181
|
+
[/Guidelines?\s*\(\d+\)/, `Guidelines (${guideCount})`],
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
for (const [regex, replacement] of replacements) {
|
|
185
|
+
if (regex.test(content)) {
|
|
186
|
+
content = content.replace(regex, replacement);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return content;
|
|
191
|
+
}
|