@dommaker/harness 1.1.0 → 1.2.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 +19 -2
- package/README.md +2 -4
- package/bin/harness.js +12 -37
- package/dist/cli/commands/check.d.ts +2 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +7 -32
- package/dist/cli/commands/check.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.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +6 -37
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +1 -12
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +0 -2
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +2 -11
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/context/index.d.ts +9 -6
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +18 -20
- package/dist/context/index.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +3 -2
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +25 -47
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +32 -33
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +38 -128
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +2 -1
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +3 -0
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +25 -0
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +24 -0
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
- package/dist/core/constraints/definitions/guidelines.js +0 -2
- package/dist/core/constraints/definitions/guidelines.js.map +1 -1
- package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
- package/dist/core/constraints/definitions/prompts.js +0 -5
- package/dist/core/constraints/definitions/prompts.js.map +1 -1
- package/dist/core/constraints/index.d.ts +1 -2
- package/dist/core/constraints/index.d.ts.map +1 -1
- package/dist/core/constraints/index.js +1 -7
- package/dist/core/constraints/index.js.map +1 -1
- package/dist/core/constraints/usage-report.d.ts +1 -2
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +2 -5
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/effective-constraints.d.ts +24 -4
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +28 -7
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/effective-set.d.ts +30 -0
- package/dist/core/effective-set.d.ts.map +1 -0
- package/dist/core/effective-set.js +35 -0
- package/dist/core/effective-set.js.map +1 -0
- package/dist/core/index.d.ts +13 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +44 -21
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +3 -6
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +47 -61
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/failure/constraint-handler.d.ts +1 -1
- package/dist/failure/constraint-handler.js +1 -1
- package/dist/gates/checker-gate.d.ts +1 -4
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +3 -11
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/definitions.d.ts +9 -38
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +24 -13
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/effective-gates.d.ts.map +1 -1
- package/dist/gates/effective-gates.js +14 -18
- package/dist/gates/effective-gates.js.map +1 -1
- package/dist/gates/index.d.ts +1 -1
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +0 -3
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +43 -53
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +180 -138
- package/dist/index.js.map +1 -1
- package/dist/knowledge/query.d.ts +15 -0
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +23 -0
- package/dist/knowledge/query.js.map +1 -1
- package/dist/monitoring/analyzer-base.d.ts +0 -4
- package/dist/monitoring/analyzer-base.d.ts.map +1 -1
- package/dist/monitoring/analyzer-base.js +0 -21
- package/dist/monitoring/analyzer-base.js.map +1 -1
- package/dist/monitoring/index.d.ts +6 -12
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +13 -29
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +2 -68
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +2 -6
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +0 -14
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/presets/index.d.ts +2 -2
- package/dist/presets/index.d.ts.map +1 -1
- package/dist/presets/index.js +3 -4
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/standard.d.ts +10 -22
- package/dist/presets/standard.d.ts.map +1 -1
- package/dist/presets/standard.js +15 -75
- package/dist/presets/standard.js.map +1 -1
- package/dist/types/constraint.d.ts +1 -29
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +1 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -4
- package/dist/types/index.js.map +1 -1
- package/dist/types/project-config.d.ts +4 -8
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/trace.d.ts +9 -22
- package/dist/types/trace.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/CONTEXT.md +5 -7
- package/src/__tests__/checker-extra.test.ts +80 -139
- package/src/__tests__/checker.test.ts +0 -376
- package/src/__tests__/project-config-loader-extra.test.ts +42 -29
- package/src/__tests__/public-exports.test.ts +138 -0
- package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
- package/src/__tests__/trace-analyzer.test.ts +4 -5
- package/src/__tests__/trace-collector.test.ts +0 -11
- package/src/__tests__/traces.test.ts +3 -22
- package/src/cli/commands/CONTEXT.md +2 -2
- package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
- package/src/cli/commands/__tests__/check.test.ts +29 -69
- package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
- package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
- package/src/cli/commands/__tests__/registry.test.ts +8 -6
- package/src/cli/commands/__tests__/status-extra.test.ts +6 -28
- package/src/cli/commands/__tests__/status.test.ts +6 -21
- package/src/cli/commands/check.ts +8 -34
- package/src/cli/commands/definitions.ts +2 -0
- package/src/cli/commands/init.ts +6 -37
- package/src/cli/commands/knowledge.ts +1 -16
- package/src/cli/commands/report.ts +0 -2
- package/src/cli/commands/status.ts +2 -12
- package/src/context/index.ts +29 -6
- package/src/core/CONTEXT.md +4 -3
- package/src/core/__tests__/effective-set.test.ts +80 -0
- package/src/core/constraints/capabilities-parser.ts +43 -49
- package/src/core/constraints/checker.ts +56 -147
- package/src/core/constraints/checkers/index.ts +2 -1
- package/src/core/constraints/checkers/types.ts +42 -0
- package/src/core/constraints/definitions/guidelines.ts +0 -2
- package/src/core/constraints/definitions/prompts.ts +0 -5
- package/src/core/constraints/index.ts +2 -17
- package/src/core/constraints/usage-report.ts +5 -8
- package/src/core/effective-constraints.ts +35 -7
- package/src/core/effective-set.ts +56 -0
- package/src/core/index.ts +80 -6
- package/src/core/project-config-loader.ts +53 -68
- package/src/failure/CONTEXT.md +1 -1
- package/src/failure/constraint-handler.ts +1 -1
- package/src/gates/CONTEXT.md +3 -3
- package/src/gates/checker-gate.ts +4 -12
- package/src/gates/definitions.ts +27 -50
- package/src/gates/effective-gates.ts +14 -21
- package/src/gates/index.ts +1 -1
- package/src/hooks/bootstrap.ts +0 -3
- package/src/index.ts +384 -137
- package/src/knowledge/CONTEXT.md +2 -2
- package/src/knowledge/__tests__/query.test.ts +64 -0
- package/src/knowledge/query.ts +28 -0
- package/src/monitoring/CONTEXT.md +7 -13
- package/src/monitoring/__tests__/traces.test.ts +0 -10
- package/src/monitoring/analyzer-base.ts +0 -22
- package/src/monitoring/index.ts +6 -12
- package/src/monitoring/trace-analyzer.ts +2 -73
- package/src/monitoring/traces.ts +2 -22
- package/src/presets/__tests__/standard.test.ts +48 -69
- package/src/presets/index.ts +3 -5
- package/src/presets/standard.ts +14 -79
- package/src/spec/CONTEXT.md +5 -13
- package/src/types/constraint.ts +1 -51
- package/src/types/index.ts +0 -12
- package/src/types/project-config.ts +4 -10
- package/src/types/trace.ts +9 -34
- package/dist/core/constraints/interceptor.d.ts +0 -38
- package/dist/core/constraints/interceptor.d.ts.map +0 -1
- package/dist/core/constraints/interceptor.js +0 -166
- package/dist/core/constraints/interceptor.js.map +0 -1
- package/dist/dashboard/data.d.ts +0 -31
- package/dist/dashboard/data.d.ts.map +0 -1
- package/dist/dashboard/data.js +0 -81
- package/dist/dashboard/data.js.map +0 -1
- package/dist/dashboard/index.d.ts +0 -4
- package/dist/dashboard/index.d.ts.map +0 -1
- package/dist/dashboard/index.js +0 -20
- package/dist/dashboard/index.js.map +0 -1
- package/dist/dashboard/stats.d.ts +0 -20
- package/dist/dashboard/stats.d.ts.map +0 -1
- package/dist/dashboard/stats.js +0 -115
- package/dist/dashboard/stats.js.map +0 -1
- package/dist/dashboard/types.d.ts +0 -110
- package/dist/dashboard/types.d.ts.map +0 -1
- package/dist/dashboard/types.js +0 -8
- package/dist/dashboard/types.js.map +0 -1
- package/dist/monitoring/constraint-doctor.d.ts +0 -82
- package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
- package/dist/monitoring/constraint-doctor.js +0 -191
- package/dist/monitoring/constraint-doctor.js.map +0 -1
- package/dist/monitoring/diagnosis-rules.d.ts +0 -18
- package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
- package/dist/monitoring/diagnosis-rules.js +0 -119
- package/dist/monitoring/diagnosis-rules.js.map +0 -1
- package/dist/monitoring/knowledge-doctor.d.ts +0 -78
- package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
- package/dist/monitoring/knowledge-doctor.js +0 -266
- package/dist/monitoring/knowledge-doctor.js.map +0 -1
- package/dist/monitoring/knowledge-evolver.d.ts +0 -72
- package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
- package/dist/monitoring/knowledge-evolver.js +0 -205
- package/dist/monitoring/knowledge-evolver.js.map +0 -1
- package/dist/monitoring/performance-analyzer.d.ts +0 -92
- package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
- package/dist/monitoring/performance-analyzer.js +0 -343
- package/dist/monitoring/performance-analyzer.js.map +0 -1
- package/dist/monitoring/performance-collector.d.ts +0 -103
- package/dist/monitoring/performance-collector.d.ts.map +0 -1
- package/dist/monitoring/performance-collector.js +0 -298
- package/dist/monitoring/performance-collector.js.map +0 -1
- package/dist/safety/index.d.ts +0 -6
- package/dist/safety/index.d.ts.map +0 -1
- package/dist/safety/index.js +0 -22
- package/dist/safety/index.js.map +0 -1
- package/dist/safety/input-guardrail.d.ts +0 -36
- package/dist/safety/input-guardrail.d.ts.map +0 -1
- package/dist/safety/input-guardrail.js +0 -118
- package/dist/safety/input-guardrail.js.map +0 -1
- package/dist/safety/output-guardrail.d.ts +0 -39
- package/dist/safety/output-guardrail.d.ts.map +0 -1
- package/dist/safety/output-guardrail.js +0 -147
- package/dist/safety/output-guardrail.js.map +0 -1
- package/dist/safety/sandbox.d.ts +0 -45
- package/dist/safety/sandbox.d.ts.map +0 -1
- package/dist/safety/sandbox.js +0 -134
- package/dist/safety/sandbox.js.map +0 -1
- package/dist/safety/tool-guardrail.d.ts +0 -51
- package/dist/safety/tool-guardrail.d.ts.map +0 -1
- package/dist/safety/tool-guardrail.js +0 -147
- package/dist/safety/tool-guardrail.js.map +0 -1
- package/dist/safety/types.d.ts +0 -104
- package/dist/safety/types.d.ts.map +0 -1
- package/dist/safety/types.js +0 -6
- package/dist/safety/types.js.map +0 -1
- package/dist/spec/annotation-checker.d.ts +0 -47
- package/dist/spec/annotation-checker.d.ts.map +0 -1
- package/dist/spec/annotation-checker.js +0 -279
- package/dist/spec/annotation-checker.js.map +0 -1
- package/dist/types/enforcement.d.ts +0 -42
- package/dist/types/enforcement.d.ts.map +0 -1
- package/dist/types/enforcement.js +0 -6
- package/dist/types/enforcement.js.map +0 -1
- package/dist/types/monitoring-types.d.ts +0 -53
- package/dist/types/monitoring-types.d.ts.map +0 -1
- package/dist/types/monitoring-types.js +0 -10
- package/dist/types/monitoring-types.js.map +0 -1
- package/dist/types/performance.d.ts +0 -204
- package/dist/types/performance.d.ts.map +0 -1
- package/dist/types/performance.js +0 -12
- package/dist/types/performance.js.map +0 -1
- package/dist/verification/index.d.ts +0 -4
- package/dist/verification/index.d.ts.map +0 -1
- package/dist/verification/index.js +0 -20
- package/dist/verification/index.js.map +0 -1
- package/dist/verification/loop.d.ts +0 -30
- package/dist/verification/loop.d.ts.map +0 -1
- package/dist/verification/loop.js +0 -114
- package/dist/verification/loop.js.map +0 -1
- package/dist/verification/rules-based.d.ts +0 -40
- package/dist/verification/rules-based.d.ts.map +0 -1
- package/dist/verification/rules-based.js +0 -130
- package/dist/verification/rules-based.js.map +0 -1
- package/dist/verification/types.d.ts +0 -69
- package/dist/verification/types.d.ts.map +0 -1
- package/dist/verification/types.js +0 -6
- package/dist/verification/types.js.map +0 -1
- package/src/__tests__/annotation-checker.test.ts +0 -183
- package/src/__tests__/constraint-doctor.test.ts +0 -271
- package/src/__tests__/doctor-extra.test.ts +0 -155
- package/src/__tests__/extend-exceptions.test.ts +0 -149
- package/src/__tests__/interceptor.test.ts +0 -89
- package/src/__tests__/performance-analyzer.test.ts +0 -499
- package/src/__tests__/performance-collector.test.ts +0 -276
- package/src/__tests__/presets.test.ts +0 -65
- package/src/core/constraints/__tests__/interceptor.test.ts +0 -253
- package/src/core/constraints/interceptor.ts +0 -214
- package/src/dashboard/CONTEXT.md +0 -21
- package/src/dashboard/__tests__/data.test.ts +0 -111
- package/src/dashboard/__tests__/stats.test.ts +0 -159
- package/src/dashboard/data.ts +0 -103
- package/src/dashboard/index.ts +0 -3
- package/src/dashboard/stats.ts +0 -127
- package/src/dashboard/types.ts +0 -130
- package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
- package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
- package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
- package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
- package/src/monitoring/constraint-doctor.ts +0 -239
- package/src/monitoring/diagnosis-rules.ts +0 -132
- package/src/monitoring/knowledge-doctor.ts +0 -322
- package/src/monitoring/knowledge-evolver.ts +0 -289
- package/src/monitoring/performance-analyzer.ts +0 -400
- package/src/monitoring/performance-collector.ts +0 -326
- package/src/safety/CONTEXT.md +0 -23
- package/src/safety/__tests__/input-guardrail.test.ts +0 -105
- package/src/safety/__tests__/output-guardrail.test.ts +0 -108
- package/src/safety/__tests__/sandbox.test.ts +0 -158
- package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
- package/src/safety/index.ts +0 -5
- package/src/safety/input-guardrail.ts +0 -133
- package/src/safety/output-guardrail.ts +0 -170
- package/src/safety/sandbox.ts +0 -148
- package/src/safety/tool-guardrail.ts +0 -176
- package/src/safety/types.ts +0 -124
- package/src/spec/__tests__/annotation-checker.test.ts +0 -294
- package/src/spec/annotation-checker.ts +0 -320
- package/src/types/enforcement.ts +0 -48
- package/src/types/monitoring-types.ts +0 -68
- package/src/types/performance.ts +0 -295
- package/src/verification/CONTEXT.md +0 -23
- package/src/verification/__tests__/loop.test.ts +0 -303
- package/src/verification/__tests__/rules-based.test.ts +0 -240
- package/src/verification/index.ts +0 -3
- package/src/verification/loop.ts +0 -137
- package/src/verification/rules-based.ts +0 -152
- package/src/verification/types.ts +0 -81
|
@@ -87,7 +87,7 @@ describe('status command', () => {
|
|
|
87
87
|
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
88
88
|
|
|
89
89
|
const mockSummarize = jest.fn().mockReturnValue([
|
|
90
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 1,
|
|
90
|
+
{ constraintId: 'test1', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 1 },
|
|
91
91
|
]);
|
|
92
92
|
const mockAnalyze = {
|
|
93
93
|
summarize: mockSummarize,
|
|
@@ -106,7 +106,7 @@ describe('status command', () => {
|
|
|
106
106
|
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
107
107
|
|
|
108
108
|
const mockSummarize = jest.fn().mockReturnValue([
|
|
109
|
-
{ constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1,
|
|
109
|
+
{ constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 5 },
|
|
110
110
|
]);
|
|
111
111
|
const mockAnalyze = {
|
|
112
112
|
summarize: mockSummarize,
|
|
@@ -131,7 +131,7 @@ describe('status command', () => {
|
|
|
131
131
|
];
|
|
132
132
|
const mockAnalyze = {
|
|
133
133
|
summarize: jest.fn().mockReturnValue([
|
|
134
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 0.2,
|
|
134
|
+
{ constraintId: 'test1', level: 'iron_law', passRate: 0.2, failRate: 0.8, totalChecks: 5 },
|
|
135
135
|
]),
|
|
136
136
|
detectAnomalies: jest.fn().mockReturnValue(mockAnomalies),
|
|
137
137
|
};
|
|
@@ -150,7 +150,7 @@ describe('status command', () => {
|
|
|
150
150
|
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
151
151
|
|
|
152
152
|
const mockSummarize = jest.fn().mockReturnValue([
|
|
153
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 0.8,
|
|
153
|
+
{ constraintId: 'test1', level: 'iron_law', passRate: 0.8, failRate: 0.2, totalChecks: 10 },
|
|
154
154
|
]);
|
|
155
155
|
const mockAnalyze = {
|
|
156
156
|
summarize: mockSummarize,
|
|
@@ -184,7 +184,7 @@ describe('status command', () => {
|
|
|
184
184
|
|
|
185
185
|
const mockAnalyze = {
|
|
186
186
|
summarize: jest.fn().mockReturnValue([
|
|
187
|
-
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.9,
|
|
187
|
+
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.9, failRate: 0.1, totalChecks: 10 },
|
|
188
188
|
]),
|
|
189
189
|
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
190
190
|
};
|
|
@@ -193,21 +193,6 @@ describe('status command', () => {
|
|
|
193
193
|
await status({});
|
|
194
194
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Guidelines'));
|
|
195
195
|
});
|
|
196
|
-
|
|
197
|
-
it('应该显示 Tips 统计', async () => {
|
|
198
|
-
mockFs.readFileSync.mockReturnValue('{"constraintId":"test"}');
|
|
199
|
-
|
|
200
|
-
const mockAnalyze = {
|
|
201
|
-
summarize: jest.fn().mockReturnValue([
|
|
202
|
-
{ constraintId: 'test_tip', level: 'tip', passRate: 1, totalChecks: 5, bypassRate: 0 },
|
|
203
|
-
]),
|
|
204
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
205
|
-
};
|
|
206
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
207
|
-
|
|
208
|
-
await status({});
|
|
209
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Tips'));
|
|
210
|
-
});
|
|
211
196
|
});
|
|
212
197
|
|
|
213
198
|
describe('异常模式', () => {
|
|
@@ -291,7 +276,7 @@ describe('status command', () => {
|
|
|
291
276
|
|
|
292
277
|
const mockAnalyze = {
|
|
293
278
|
summarize: jest.fn().mockReturnValue([
|
|
294
|
-
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.6,
|
|
279
|
+
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.6, failRate: 0.4, totalChecks: 10 },
|
|
295
280
|
]),
|
|
296
281
|
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
297
282
|
};
|
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
* harness check 命令
|
|
3
3
|
*
|
|
4
4
|
* 检查约束是否满足(check 层:Iron Laws / Guidelines;prompt 层仅注入不检查)
|
|
5
|
-
* 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
|
|
6
|
-
* ADR-0001:约束集统一走
|
|
5
|
+
* 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
|
|
6
|
+
* ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import { constraintChecker } from '../../core/constraints/checker';
|
|
13
|
-
import { getTraceCollector } from '../../monitoring/traces';
|
|
14
13
|
import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
|
|
15
|
-
import {
|
|
14
|
+
import { getMergedConstraintsConfig } from '../../core/effective-constraints';
|
|
16
15
|
import { buildConstraintContext } from '../../core/constraints/context-builder';
|
|
17
16
|
import { detectInjectionDrift } from '../../core/constraints/injection-drift';
|
|
18
17
|
import { DEFAULT_TRACE_FILE } from '../../types/trace';
|
|
@@ -37,18 +36,12 @@ export async function check(options: CheckOptions): Promise<void> {
|
|
|
37
36
|
console.log(chalk.gray(`预设: ${options.preset}`));
|
|
38
37
|
|
|
39
38
|
try {
|
|
40
|
-
// 加载项目级自定义约束
|
|
41
39
|
const projectPath = options.projectPath || process.cwd();
|
|
42
|
-
const configLoader = new ProjectConfigLoader(projectPath);
|
|
43
|
-
configLoader.load();
|
|
44
|
-
constraintChecker.setTraceRecorder(getTraceCollector());
|
|
45
40
|
|
|
46
41
|
// 生效约束集(ADR-0001):内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
|
|
47
|
-
// --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset
|
|
48
|
-
// 项目自定义配置优先于 CLI
|
|
49
|
-
const merged =
|
|
50
|
-
? configLoader.mergeConstraints()
|
|
51
|
-
: configLoader.mergeConstraints({ preset: options.preset || 'standard' });
|
|
42
|
+
// --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(工单 23 语义:
|
|
43
|
+
// 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
|
|
44
|
+
const merged = getMergedConstraintsConfig(projectPath, { preset: options.preset });
|
|
52
45
|
if (merged.custom.length > 0) {
|
|
53
46
|
console.log(chalk.gray(`自定义约束: ${merged.custom.length} 条`));
|
|
54
47
|
}
|
|
@@ -199,23 +192,7 @@ async function getSmartHint(projectPath: string): Promise<string | null> {
|
|
|
199
192
|
hints.push('📊 记录已足够,运行 harness status 查看统计');
|
|
200
193
|
state.shownHints.push('trace_50');
|
|
201
194
|
}
|
|
202
|
-
|
|
203
|
-
// 条件 2: 检查异常趋势(简单检查绕过率)
|
|
204
|
-
const bypassCount = lines.filter(line => {
|
|
205
|
-
try {
|
|
206
|
-
const trace = JSON.parse(line);
|
|
207
|
-
return trace.result === 'bypassed';
|
|
208
|
-
} catch {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
}).length;
|
|
212
|
-
|
|
213
|
-
const bypassRate = traceCount > 10 ? bypassCount / traceCount : 0;
|
|
214
|
-
if (bypassRate > 0.3 && !state.shownHints.includes('high_bypass')) {
|
|
215
|
-
hints.push('⚠️ 发现异常趋势,建议运行 harness status 查看详情');
|
|
216
|
-
state.shownHints.push('high_bypass');
|
|
217
|
-
}
|
|
218
|
-
|
|
195
|
+
|
|
219
196
|
// 保存状态
|
|
220
197
|
if (hints.length > 0) {
|
|
221
198
|
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
@@ -242,14 +219,11 @@ export function listLaws(): void {
|
|
|
242
219
|
});
|
|
243
220
|
|
|
244
221
|
// Guidelines
|
|
245
|
-
console.log(chalk.yellow('🟡 指导原则 (Guidelines) -
|
|
222
|
+
console.log(chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,违背发警告但不阻止:\n'));
|
|
246
223
|
Object.values(GUIDELINES).forEach(constraint => {
|
|
247
224
|
console.log(chalk.yellow(` ${constraint.id}`));
|
|
248
225
|
console.log(chalk.gray(` ${constraint.rule}`));
|
|
249
226
|
console.log(chalk.gray(` ${constraint.message}`));
|
|
250
|
-
if (constraint.exceptions && constraint.exceptions.length > 0) {
|
|
251
|
-
console.log(chalk.gray(` 例外: ${constraint.exceptions.join(', ')}`));
|
|
252
|
-
}
|
|
253
227
|
console.log();
|
|
254
228
|
});
|
|
255
229
|
|
|
@@ -81,6 +81,8 @@ export interface CommandDefinition {
|
|
|
81
81
|
subcommands?: Record<string, CommandSubcommand>;
|
|
82
82
|
/** false = 未知位置参数不报错、落回默认 action(spec 的文件参数用法) */
|
|
83
83
|
subcommandStrict?: boolean;
|
|
84
|
+
/** true = 有 subcommands 但无位置参数时运行默认 action 而非显示帮助(门禁命令语义) */
|
|
85
|
+
bareRunsAction?: boolean;
|
|
84
86
|
/** 选项条件路由(匹配时替代默认 action 执行) */
|
|
85
87
|
optionRoutes?: CommandOptionRoute[];
|
|
86
88
|
/** 默认 action 实参构造(缺省为 [options]) */
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -37,19 +37,15 @@ export interface InitOptions {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* 默认配置
|
|
40
|
+
*
|
|
41
|
+
* 只写有运行时消费者的字段:preset(ADR-0001 生效集链路由 mergeConstraints 消费)。
|
|
42
|
+
* 历史模板里的 enabled / ironLaws.enforceErrors / ironLaws.warnWarnings /
|
|
43
|
+
* validators.{checkpoint,passesGate,cso} 均为零消费者的死字段,不再写入;
|
|
44
|
+
* strict/standard/relaxed 三档差异曾只存在于这些死字段上(实为两档),
|
|
45
|
+
* 现在三档差异完全由 preset 键经生效集链路体现。
|
|
40
46
|
*/
|
|
41
47
|
const DEFAULT_CONFIG = {
|
|
42
48
|
preset: 'standard',
|
|
43
|
-
enabled: true,
|
|
44
|
-
ironLaws: {
|
|
45
|
-
enforceErrors: true,
|
|
46
|
-
warnWarnings: true,
|
|
47
|
-
},
|
|
48
|
-
validators: {
|
|
49
|
-
checkpoint: true,
|
|
50
|
-
passesGate: true,
|
|
51
|
-
cso: false,
|
|
52
|
-
},
|
|
53
49
|
};
|
|
54
50
|
|
|
55
51
|
/**
|
|
@@ -59,15 +55,6 @@ const PRESETS = {
|
|
|
59
55
|
strict: {
|
|
60
56
|
...DEFAULT_CONFIG,
|
|
61
57
|
preset: 'strict',
|
|
62
|
-
ironLaws: {
|
|
63
|
-
enforceErrors: true,
|
|
64
|
-
warnWarnings: true,
|
|
65
|
-
},
|
|
66
|
-
validators: {
|
|
67
|
-
checkpoint: true,
|
|
68
|
-
passesGate: true,
|
|
69
|
-
cso: true,
|
|
70
|
-
},
|
|
71
58
|
},
|
|
72
59
|
standard: {
|
|
73
60
|
...DEFAULT_CONFIG,
|
|
@@ -76,10 +63,6 @@ const PRESETS = {
|
|
|
76
63
|
relaxed: {
|
|
77
64
|
...DEFAULT_CONFIG,
|
|
78
65
|
preset: 'relaxed',
|
|
79
|
-
ironLaws: {
|
|
80
|
-
enforceErrors: true,
|
|
81
|
-
warnWarnings: false,
|
|
82
|
-
},
|
|
83
66
|
},
|
|
84
67
|
};
|
|
85
68
|
|
|
@@ -483,7 +466,6 @@ custom_constraints:
|
|
|
483
466
|
# rule: "NO MOMENT.JS IMPORTS"
|
|
484
467
|
# message: "禁止使用 moment.js,请使用 date-fns 或 dayjs"
|
|
485
468
|
# trigger: ["code_implementation"]
|
|
486
|
-
# exceptions: ["legacy_migration"]
|
|
487
469
|
|
|
488
470
|
# 示例 3:要求特定的文件命名
|
|
489
471
|
# my_project_component_naming:
|
|
@@ -492,19 +474,6 @@ custom_constraints:
|
|
|
492
474
|
# rule: "REACT COMPONENTS SHOULD BE PASCAL CASE"
|
|
493
475
|
# message: "React 组件文件名应使用 PascalCase"
|
|
494
476
|
# trigger: ["file_creation"]
|
|
495
|
-
|
|
496
|
-
# ========================================
|
|
497
|
-
# 扩展内置约束的例外
|
|
498
|
-
# ========================================
|
|
499
|
-
|
|
500
|
-
# 如果需要为内置约束添加项目特定的例外,
|
|
501
|
-
# 可以在 .harness/config.yml 中配置:
|
|
502
|
-
|
|
503
|
-
# constraints:
|
|
504
|
-
# no_fix_without_root_cause:
|
|
505
|
-
# # 添加项目特定的例外
|
|
506
|
-
# exceptions:
|
|
507
|
-
# - my_custom_exception
|
|
508
477
|
`;
|
|
509
478
|
|
|
510
479
|
await fs.writeFile(customConstraintsPath, content, 'utf-8');
|
|
@@ -81,22 +81,7 @@ export async function knowledgeSearch(
|
|
|
81
81
|
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
82
82
|
const queryEngine = new KnowledgeQuery(store);
|
|
83
83
|
|
|
84
|
-
const
|
|
85
|
-
phase: 'cli',
|
|
86
|
-
maxTokens: 10000,
|
|
87
|
-
maxEntries: options.limit || 20,
|
|
88
|
-
focusTypes: [] as KnowledgeSubsystem[],
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const result = queryEngine.query(budget);
|
|
92
|
-
|
|
93
|
-
// 简单文本匹配过滤
|
|
94
|
-
const q = query.toLowerCase();
|
|
95
|
-
const matched = result.entries.filter(e =>
|
|
96
|
-
e.title.toLowerCase().includes(q) ||
|
|
97
|
-
e.content.toLowerCase().includes(q) ||
|
|
98
|
-
e.tags.some(t => t.toLowerCase().includes(q))
|
|
99
|
-
);
|
|
84
|
+
const matched = queryEngine.search(query, { limit: options.limit || 20 });
|
|
100
85
|
|
|
101
86
|
if (options.json) {
|
|
102
87
|
console.log(JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import * as fs from 'fs/promises';
|
|
9
9
|
import { ConstraintChecker } from '../../core/constraints/checker';
|
|
10
|
-
import { getTraceCollector } from '../../monitoring/traces';
|
|
11
10
|
import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
|
|
12
11
|
import { executeWithCollect } from '../../failure/constraint-handler';
|
|
13
12
|
import type { ConstraintContext } from '../../types/constraint';
|
|
@@ -48,7 +47,6 @@ export async function report(options: ReportOptions): Promise<void> {
|
|
|
48
47
|
|
|
49
48
|
const projectPath = options.projectPath || process.cwd();
|
|
50
49
|
const checker = ConstraintChecker.getInstance();
|
|
51
|
-
checker.setTraceRecorder(getTraceCollector());
|
|
52
50
|
|
|
53
51
|
const allConstraints = { ...IRON_LAWS, ...GUIDELINES, ...PROMPTS };
|
|
54
52
|
const totalConstraints = Object.keys(allConstraints).length;
|
|
@@ -109,7 +109,7 @@ export async function status(options: StatusOptions): Promise<void> {
|
|
|
109
109
|
const status = s.passRate >= 1 ? '✅' : '❌';
|
|
110
110
|
console.log(` ${status} ${s.constraintId}`);
|
|
111
111
|
if (options.detail) {
|
|
112
|
-
console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% |
|
|
112
|
+
console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 失败: ${(s.failRate * 100).toFixed(0)}%`));
|
|
113
113
|
}
|
|
114
114
|
});
|
|
115
115
|
console.log();
|
|
@@ -123,22 +123,12 @@ export async function status(options: StatusOptions): Promise<void> {
|
|
|
123
123
|
const status = s.passRate >= 0.8 ? '✅' : s.passRate >= 0.5 ? '⚠️' : '❌';
|
|
124
124
|
console.log(` ${status} ${s.constraintId}`);
|
|
125
125
|
if (options.detail) {
|
|
126
|
-
console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% |
|
|
126
|
+
console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 失败: ${(s.failRate * 100).toFixed(0)}%`));
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
console.log();
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// Tips
|
|
133
|
-
const tipSummaries = summaries.filter((s: TraceSummary) => s.level === 'tip');
|
|
134
|
-
if (tipSummaries.length > 0) {
|
|
135
|
-
console.log(chalk.blue('🔵 Tips:'));
|
|
136
|
-
tipSummaries.forEach((s: TraceSummary) => {
|
|
137
|
-
console.log(` 💡 ${s.constraintId}`);
|
|
138
|
-
});
|
|
139
|
-
console.log();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
132
|
// 异常检测
|
|
143
133
|
if (anomalies.length > 0) {
|
|
144
134
|
console.log(chalk.yellow(`⚠️ 发现 ${anomalies.length} 个异常`));
|
package/src/context/index.ts
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 上下文管理模块(ADR-0003:显式清单,禁 export *)
|
|
3
3
|
*
|
|
4
4
|
* Token 预算 + 会话压缩 + 知识注入
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// 类型
|
|
8
|
+
export type {
|
|
9
|
+
CompactionConfig,
|
|
10
|
+
CompactionLevel,
|
|
11
|
+
ContextSource,
|
|
12
|
+
ContextSourceType,
|
|
13
|
+
ContextUsageSnapshot,
|
|
14
|
+
SessionCheckpoint,
|
|
15
|
+
SessionEvent,
|
|
16
|
+
SessionEventType,
|
|
17
|
+
SessionHandle,
|
|
18
|
+
SessionMessage,
|
|
19
|
+
} from './types';
|
|
20
|
+
export { DEFAULT_COMPACTION_CONFIG } from './types';
|
|
21
|
+
|
|
22
|
+
// Token 预算
|
|
23
|
+
export { AdaptiveTokenBudget, TokenBudget, TokenEstimator } from './token-budget';
|
|
24
|
+
|
|
25
|
+
// 会话压缩
|
|
26
|
+
export { SessionCompaction } from './compaction';
|
|
27
|
+
export type { CompactionResult } from './compaction';
|
|
28
|
+
|
|
29
|
+
// 会话管理
|
|
30
|
+
export { SessionManager } from './session-manager';
|
|
31
|
+
|
|
32
|
+
// 知识注入
|
|
33
|
+
export { KnowledgeInjector } from './knowledge-injector';
|
|
34
|
+
export type { InjectionConfig, InjectionResult } from './knowledge-injector';
|
package/src/core/CONTEXT.md
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
约束引擎核心:check/prompt 二元约束系统(ADR-0001)、生效集合并(effective-constraints)、检查点验证器(CSO/passes-gate)、会话管理、Spec 验证器、项目配置加载。
|
|
5
5
|
|
|
6
6
|
## 核心导出
|
|
7
|
-
- `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS
|
|
8
|
-
- `effective-constraints.ts` — `getEffectiveConstraints(projectRoot)`:全仓唯一生效集来源(内置 → preset → config.yml 禁用(内置与 custom 同效)→ custom 追加(禁用/已退役的不追加)→ scenes 过滤);`lintEffectiveConfig` 配置诊断
|
|
7
|
+
- `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS) + 检查引擎(ConstraintChecker,拦截统一由 checkBeforeExecution 承担,ADR-0004) + 缓存(CheckCache:TTL 缓存 + 计数采样,H6/G5 起公开导出) + 注入渲染(injection-renderer) + Agent prompt 渲染(agent-prompt-renderer:trigger 参数化分组渲染,role 路由留 studio,H6/G6)/漂移校验(injection-drift)/使用统计(usage-report);CheckEnv 生产侧唯一构造点 `buildCheckEnv(context, providers|'none')`(checkers/types.ts:providers = 证据接线,'none' = 显式不接 → evidence flag checker 按契约 skip)
|
|
8
|
+
- `effective-constraints.ts` — `getEffectiveConstraints(projectRoot, {preset?})`:全仓唯一生效集来源(内置 → preset → config.yml 禁用(内置与 custom 同效)→ custom 追加(禁用/已退役的不追加)→ scenes 过滤);`getMergedConstraintsConfig(projectRoot, {preset?})`:同链路的完整 MergedConstraintsConfig 形状(含 disabled/custom/unknownIds),内置工单 23 优先级规则(--preset 仅在无项目自定义配置时生效),check 命令经此入口;`lintEffectiveConfig` 配置诊断
|
|
9
|
+
- `effective-set.ts` — `filterEnabledEntries(knownIds, entries, {onUnknownId})`:约束侧(collect)与门禁侧(throw)共用的 config 条目筛选器
|
|
9
10
|
- `validators/` — checkpoints、passes-gate、CSO 验证器
|
|
10
11
|
- `session/` — 会话管理
|
|
11
12
|
- `spec/validator` — SpecValidator
|
|
12
|
-
- `project-config-loader` — 项目配置加载 +
|
|
13
|
+
- `project-config-loader` — 项目配置加载 + 约束合并(mergeConstraints 内含 preset 裁剪:presets/ 纯数据 + 未知名回落 standard,禁用到未知 id 经 effective-set 共享筛选器 collect 模式)
|
|
13
14
|
|
|
14
15
|
## 依赖关系
|
|
15
16
|
- 被所有模块依赖(基础层,无上层依赖)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* effective-set 共享筛选器测试
|
|
3
|
+
*
|
|
4
|
+
* 覆盖约束侧(collect)与门禁侧(throw)两种 onUnknownId 模式。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { filterEnabledEntries } from '../effective-set';
|
|
8
|
+
|
|
9
|
+
const KNOWN = new Set(['a', 'b', 'c']);
|
|
10
|
+
|
|
11
|
+
describe('filterEnabledEntries', () => {
|
|
12
|
+
describe('onUnknownId: collect(约束侧)', () => {
|
|
13
|
+
it('已知 id 全部通过,enabled:false 收进 disabledIds', () => {
|
|
14
|
+
const result = filterEnabledEntries(
|
|
15
|
+
KNOWN,
|
|
16
|
+
{ a: { enabled: false }, b: { enabled: true }, c: {} },
|
|
17
|
+
{ onUnknownId: 'collect' }
|
|
18
|
+
);
|
|
19
|
+
expect(result.disabledIds).toEqual(['a']);
|
|
20
|
+
expect(result.unknownIds).toEqual([]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('未知 id 静默忽略并收集进 unknownIds', () => {
|
|
24
|
+
const result = filterEnabledEntries(
|
|
25
|
+
KNOWN,
|
|
26
|
+
{ a: {}, ghost: { enabled: false } },
|
|
27
|
+
{ onUnknownId: 'collect' }
|
|
28
|
+
);
|
|
29
|
+
expect(result.unknownIds).toEqual(['ghost']);
|
|
30
|
+
// 未知 id 带 enabled:false 同样计入 disabledIds(历史行为:delete 空桶为 no-op)
|
|
31
|
+
expect(result.disabledIds).toEqual(['ghost']);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('未知 id 无 enabled 标记时只收集不进 disabledIds', () => {
|
|
35
|
+
const result = filterEnabledEntries(
|
|
36
|
+
KNOWN,
|
|
37
|
+
{ ghost: {} },
|
|
38
|
+
{ onUnknownId: 'collect' }
|
|
39
|
+
);
|
|
40
|
+
expect(result.unknownIds).toEqual(['ghost']);
|
|
41
|
+
expect(result.disabledIds).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('空 entries → 空结果', () => {
|
|
45
|
+
const result = filterEnabledEntries(KNOWN, {}, { onUnknownId: 'collect' });
|
|
46
|
+
expect(result).toEqual({ disabledIds: [], unknownIds: [] });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('onUnknownId: throw(门禁侧)', () => {
|
|
51
|
+
it('未知 id 抛错(默认消息)', () => {
|
|
52
|
+
expect(() =>
|
|
53
|
+
filterEnabledEntries(KNOWN, { nope: { enabled: false } }, { onUnknownId: 'throw' })
|
|
54
|
+
).toThrow(/未注册的 id "nope"/);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('未知 id 抛错(unknownIdError 定制消息)', () => {
|
|
58
|
+
expect(() =>
|
|
59
|
+
filterEnabledEntries(
|
|
60
|
+
KNOWN,
|
|
61
|
+
{ nope: {} },
|
|
62
|
+
{
|
|
63
|
+
onUnknownId: 'throw',
|
|
64
|
+
unknownIdError: id => `gates.${id} 引用了未注册的门禁。可用门禁: a, b, c。`,
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
).toThrow(/gates\.nope 引用了未注册的门禁/);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('已知 id 的 enabled:false 正常收集,不抛错', () => {
|
|
71
|
+
const result = filterEnabledEntries(
|
|
72
|
+
KNOWN,
|
|
73
|
+
{ a: { enabled: false }, b: { enabled: true } },
|
|
74
|
+
{ onUnknownId: 'throw' }
|
|
75
|
+
);
|
|
76
|
+
expect(result.disabledIds).toEqual(['a']);
|
|
77
|
+
expect(result.unknownIds).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -9,9 +9,16 @@
|
|
|
9
9
|
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import { IRON_LAWS, GUIDELINES } from './definitions';
|
|
12
|
+
import { COMMAND_DEFINITIONS } from '../../cli/commands/definitions';
|
|
13
|
+
import { GATE_DEFINITIONS } from '../../gates/definitions';
|
|
12
14
|
import { FreshnessRunner } from './doc-freshness/runner';
|
|
13
15
|
import type { DocFreshnessCheck } from '../../types/project-config';
|
|
14
16
|
|
|
17
|
+
/** CLI 命令数 = 非门禁命令定义 + 门禁命令定义(ADR-0002:定义表是命令形状单一来源) */
|
|
18
|
+
function cliCommandCount(): number {
|
|
19
|
+
return COMMAND_DEFINITIONS.length + GATE_DEFINITIONS.filter(g => g.cli).length;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
/** 匹配表格单元格中的源码文件条目(如 `src/foo.ts`、`foo.tsx`) */
|
|
16
23
|
const FILE_CELL_REGEX = /\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/g;
|
|
17
24
|
|
|
@@ -104,41 +111,40 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
|
|
|
104
111
|
|
|
105
112
|
// ── 能力清单计数 ────────────────────────────────────────────
|
|
106
113
|
|
|
114
|
+
/**
|
|
115
|
+
* 能力清单统计规则单份定义(ADR-0008:check/write 两方向共用,
|
|
116
|
+
* 此前 label+pattern 在 buildCapabilityChecks 与 updateCapabilityCounts 各写一遍)
|
|
117
|
+
*
|
|
118
|
+
* - label:CAPABILITIES.md 计数行 label(check 的 DocFreshnessCheck.label +
|
|
119
|
+
* write 的替换文本前缀,如 `Quality Gates (6)`)
|
|
120
|
+
* - pattern:同时供 check(doc_regex_count 字符串 pattern,捕获组为文档计数)
|
|
121
|
+
* 与 write(编译为替换 regex)
|
|
122
|
+
* - actual:定义表实际计数(ADR-0002 单一来源)
|
|
123
|
+
*/
|
|
124
|
+
interface CapabilityCountRule {
|
|
125
|
+
label: string;
|
|
126
|
+
pattern: string;
|
|
127
|
+
actual: () => number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const CAPABILITY_COUNT_RULES: CapabilityCountRule[] = [
|
|
131
|
+
{ label: 'CLI Commands', pattern: 'CLI Commands\\s*\\((\\d+)\\)', actual: cliCommandCount },
|
|
132
|
+
{ label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: () => GATE_DEFINITIONS.length },
|
|
133
|
+
{ label: 'Iron Laws', pattern: 'Iron Laws?\\s*\\((\\d+)\\)', actual: () => Object.keys(IRON_LAWS).length },
|
|
134
|
+
{ label: 'Guidelines', pattern: 'Guidelines?\\s*\\((\\d+)\\)', actual: () => Object.keys(GUIDELINES).length },
|
|
135
|
+
];
|
|
136
|
+
|
|
107
137
|
/**
|
|
108
138
|
* 构建 CAPABILITIES.md 能力清单格式的检查配置
|
|
109
139
|
*/
|
|
110
140
|
function buildCapabilityChecks(): DocFreshnessCheck[] {
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
];
|
|
141
|
+
return CAPABILITY_COUNT_RULES.map(rule => ({
|
|
142
|
+
type: 'doc_regex_count' as const,
|
|
143
|
+
doc: 'CAPABILITIES.md',
|
|
144
|
+
label: rule.label,
|
|
145
|
+
pattern: rule.pattern,
|
|
146
|
+
actual: { kind: 'const_count' as const, value: rule.actual() },
|
|
147
|
+
}));
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
/**
|
|
@@ -164,26 +170,14 @@ export function checkCapabilityCounts(
|
|
|
164
170
|
/**
|
|
165
171
|
* 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
|
|
166
172
|
*
|
|
167
|
-
*
|
|
173
|
+
* 命令/门禁计数取自定义表(ADR-0002 单一来源),regex 替换文档计数行;
|
|
174
|
+
* 规则与 check 方向共用 CAPABILITY_COUNT_RULES(ADR-0008)。
|
|
168
175
|
*/
|
|
169
|
-
export function updateCapabilityCounts(content: string,
|
|
170
|
-
const
|
|
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) {
|
|
176
|
+
export function updateCapabilityCounts(content: string, _projectPath: string): string {
|
|
177
|
+
for (const rule of CAPABILITY_COUNT_RULES) {
|
|
178
|
+
const regex = new RegExp(rule.pattern);
|
|
185
179
|
if (regex.test(content)) {
|
|
186
|
-
content = content.replace(regex,
|
|
180
|
+
content = content.replace(regex, `${rule.label} (${rule.actual()})`);
|
|
187
181
|
}
|
|
188
182
|
}
|
|
189
183
|
|