@dommaker/harness 1.5.0 → 1.7.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 +26 -0
- package/README.md +0 -2
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +1 -32
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +0 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +0 -1
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +0 -4
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +10 -20
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/report.d.ts +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +2 -55
- 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 +4 -8
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/context/index.d.ts +2 -5
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +2 -8
- package/dist/context/index.js.map +1 -1
- package/dist/context/token-budget.d.ts +0 -29
- package/dist/context/token-budget.d.ts.map +1 -1
- package/dist/context/token-budget.js +1 -65
- package/dist/context/token-budget.js.map +1 -1
- package/dist/context/types.d.ts +0 -1
- package/dist/context/types.d.ts.map +1 -1
- package/dist/context/types.js +0 -9
- package/dist/context/types.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +14 -0
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +22 -2
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +6 -3
- package/dist/core/constraints/git-evidence.d.ts.map +1 -1
- package/dist/core/constraints/git-evidence.js +6 -3
- package/dist/core/constraints/git-evidence.js.map +1 -1
- package/dist/core/index.d.ts +1 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -9
- package/dist/core/index.js.map +1 -1
- package/dist/core/spec/validator.d.ts +2 -0
- package/dist/core/spec/validator.d.ts.map +1 -1
- package/dist/core/spec/validator.js +9 -11
- package/dist/core/spec/validator.js.map +1 -1
- package/dist/core/validators/index.d.ts +1 -1
- package/dist/core/validators/index.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +1 -15
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +2 -127
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/failure/index.d.ts +0 -1
- package/dist/failure/index.d.ts.map +1 -1
- package/dist/failure/index.js +1 -7
- package/dist/failure/index.js.map +1 -1
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +0 -4
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/performance.d.ts +7 -22
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +7 -89
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/types.d.ts +2 -8
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/index.d.ts +6 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -22
- package/dist/index.js.map +1 -1
- package/dist/knowledge/index.d.ts +0 -1
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/index.js +1 -3
- package/dist/knowledge/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +25 -10
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +147 -116
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/types/passes-gate.d.ts +0 -32
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/passes-gate-check.test.ts +20 -4
- package/src/__tests__/passes-gate.test.ts +5 -99
- package/src/__tests__/performance-gate.test.ts +3 -11
- package/src/__tests__/public-exports.test.ts +68 -16
- package/src/__tests__/public-type-surface.test.ts +359 -0
- package/src/__tests__/trace-analyzer.test.ts +52 -2
- package/src/cli/commands/CONTEXT.md +3 -2
- package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +158 -0
- package/src/cli/commands/__tests__/passes-gate.test.ts +7 -3
- package/src/cli/commands/__tests__/performance.test.ts +5 -16
- package/src/cli/commands/__tests__/registry.test.ts +46 -3
- package/src/cli/commands/__tests__/report-extra.test.ts +0 -19
- package/src/cli/commands/__tests__/report-false-green.test.ts +46 -0
- package/src/cli/commands/__tests__/report.test.ts +0 -20
- package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +68 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +63 -116
- package/src/cli/commands/__tests__/status.test.ts +66 -148
- package/src/cli/commands/definitions.ts +1 -32
- package/src/cli/commands/passes-gate.ts +0 -3
- package/src/cli/commands/performance.ts +13 -27
- package/src/cli/commands/report.ts +3 -61
- package/src/cli/commands/status.ts +5 -10
- package/src/context/CONTEXT.md +2 -3
- package/src/context/__tests__/token-budget.test.ts +1 -81
- package/src/context/index.ts +2 -7
- package/src/context/token-budget.ts +0 -73
- package/src/context/types.ts +0 -9
- package/src/core/CONTEXT.md +5 -6
- package/src/core/constraints/__tests__/collect-constraints.test.ts +66 -0
- package/src/core/constraints/checker.ts +33 -2
- package/src/core/constraints/git-evidence.ts +6 -3
- package/src/core/index.ts +0 -12
- package/src/core/spec/__tests__/validator.test.ts +24 -0
- package/src/core/spec/validator.ts +9 -10
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -9
- package/src/core/validators/index.ts +0 -2
- package/src/core/validators/passes-gate.ts +3 -152
- package/src/failure/CONTEXT.md +8 -6
- package/src/failure/index.ts +0 -10
- package/src/gates/CONTEXT.md +3 -2
- package/src/gates/__tests__/performance.test.ts +6 -74
- package/src/gates/definitions.ts +0 -4
- package/src/gates/performance.ts +9 -111
- package/src/gates/types.ts +2 -8
- package/src/index.ts +1 -37
- package/src/knowledge/CONTEXT.md +1 -2
- package/src/knowledge/index.ts +0 -1
- package/src/monitoring/CONTEXT.md +2 -2
- package/src/monitoring/trace-analyzer.ts +160 -126
- package/src/types/passes-gate.ts +0 -43
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +0 -1
- package/dist/cli/commands/analyze-sessions.d.ts +0 -20
- package/dist/cli/commands/analyze-sessions.d.ts.map +0 -1
- package/dist/cli/commands/analyze-sessions.js +0 -290
- package/dist/cli/commands/analyze-sessions.js.map +0 -1
- package/dist/cli/commands/update-user-model.d.ts +0 -30
- package/dist/cli/commands/update-user-model.d.ts.map +0 -1
- package/dist/cli/commands/update-user-model.js +0 -406
- package/dist/cli/commands/update-user-model.js.map +0 -1
- package/dist/cli/session-mining/corrections.d.ts +0 -17
- package/dist/cli/session-mining/corrections.d.ts.map +0 -1
- package/dist/cli/session-mining/corrections.js +0 -58
- package/dist/cli/session-mining/corrections.js.map +0 -1
- package/dist/cli/session-mining/index.d.ts +0 -13
- package/dist/cli/session-mining/index.d.ts.map +0 -1
- package/dist/cli/session-mining/index.js +0 -29
- package/dist/cli/session-mining/index.js.map +0 -1
- package/dist/cli/session-mining/text.d.ts +0 -31
- package/dist/cli/session-mining/text.d.ts.map +0 -1
- package/dist/cli/session-mining/text.js +0 -126
- package/dist/cli/session-mining/text.js.map +0 -1
- package/dist/cli/session-mining/transcript.d.ts +0 -34
- package/dist/cli/session-mining/transcript.d.ts.map +0 -1
- package/dist/cli/session-mining/transcript.js +0 -130
- package/dist/cli/session-mining/transcript.js.map +0 -1
- package/dist/context/compaction.d.ts +0 -57
- package/dist/context/compaction.d.ts.map +0 -1
- package/dist/context/compaction.js +0 -165
- package/dist/context/compaction.js.map +0 -1
- package/dist/core/session/clean-state.d.ts +0 -17
- package/dist/core/session/clean-state.d.ts.map +0 -1
- package/dist/core/session/clean-state.js +0 -192
- package/dist/core/session/clean-state.js.map +0 -1
- package/dist/core/session/index.d.ts +0 -6
- package/dist/core/session/index.d.ts.map +0 -1
- package/dist/core/session/index.js +0 -15
- package/dist/core/session/index.js.map +0 -1
- package/dist/core/session/startup.d.ts +0 -47
- package/dist/core/session/startup.d.ts.map +0 -1
- package/dist/core/session/startup.js +0 -263
- package/dist/core/session/startup.js.map +0 -1
- package/dist/failure/constraint-handler.d.ts +0 -83
- package/dist/failure/constraint-handler.d.ts.map +0 -1
- package/dist/failure/constraint-handler.js +0 -138
- package/dist/failure/constraint-handler.js.map +0 -1
- package/dist/knowledge/lifecycle-hooks.d.ts +0 -62
- package/dist/knowledge/lifecycle-hooks.d.ts.map +0 -1
- package/dist/knowledge/lifecycle-hooks.js +0 -143
- package/dist/knowledge/lifecycle-hooks.js.map +0 -1
- package/dist/types/session.d.ts +0 -113
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/session.js +0 -6
- package/dist/types/session.js.map +0 -1
- package/src/__tests__/clean-state-extra.test.ts +0 -301
- package/src/__tests__/clean-state.test.ts +0 -169
- package/src/__tests__/constraint-handler.test.ts +0 -132
- package/src/__tests__/passes-gate-extra.test.ts +0 -93
- package/src/__tests__/session-startup.test.ts +0 -334
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +0 -184
- package/src/cli/commands/__tests__/update-user-model.test.ts +0 -268
- package/src/cli/commands/analyze-sessions.ts +0 -335
- package/src/cli/commands/update-user-model.ts +0 -476
- package/src/cli/session-mining/__tests__/transcript.test.ts +0 -118
- package/src/cli/session-mining/corrections.ts +0 -56
- package/src/cli/session-mining/index.ts +0 -13
- package/src/cli/session-mining/text.ts +0 -117
- package/src/cli/session-mining/transcript.ts +0 -125
- package/src/context/__tests__/compaction.test.ts +0 -169
- package/src/context/compaction.ts +0 -201
- package/src/core/session/__tests__/startup.test.ts +0 -281
- package/src/core/session/clean-state.ts +0 -178
- package/src/core/session/index.ts +0 -15
- package/src/core/session/startup.ts +0 -253
- package/src/failure/constraint-handler.ts +0 -171
- package/src/knowledge/__tests__/lifecycle-hooks.test.ts +0 -140
- package/src/knowledge/lifecycle-hooks.ts +0 -202
- package/src/types/session.ts +0 -132
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* status 命令测试
|
|
3
|
+
*
|
|
4
|
+
* ADR-0020 起不再 mock TraceAnalyzer/TraceCollector:统计与异常由 trace-analyzer
|
|
5
|
+
* 的模块级纯函数真算,用例喂合法 trace 行、断言真实输出。
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { status } from '../status';
|
|
6
9
|
import { captureIO, type CapturingIO } from '../../command-contract';
|
|
7
10
|
import * as fs from 'fs';
|
|
8
|
-
import {
|
|
11
|
+
import type { ExecutionTrace } from '../../../types/trace';
|
|
9
12
|
|
|
10
13
|
// Mock fs
|
|
11
14
|
jest.mock('fs', () => ({
|
|
@@ -15,22 +18,6 @@ jest.mock('fs', () => ({
|
|
|
15
18
|
writeFileSync: jest.fn(),
|
|
16
19
|
}));
|
|
17
20
|
|
|
18
|
-
// Mock TraceCollector
|
|
19
|
-
jest.mock('../../../monitoring/traces', () => ({
|
|
20
|
-
TraceCollector: jest.fn().mockImplementation(() => ({
|
|
21
|
-
record: jest.fn(),
|
|
22
|
-
read: jest.fn().mockReturnValue([]),
|
|
23
|
-
})),
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
// Mock TraceAnalyzer
|
|
27
|
-
jest.mock('../../../monitoring/trace-analyzer', () => ({
|
|
28
|
-
TraceAnalyzer: jest.fn().mockImplementation(() => ({
|
|
29
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
30
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
31
|
-
})),
|
|
32
|
-
}));
|
|
33
|
-
|
|
34
21
|
// Mock chalk
|
|
35
22
|
jest.mock('chalk', () => ({
|
|
36
23
|
blue: jest.fn((str: string) => str),
|
|
@@ -41,7 +28,18 @@ jest.mock('chalk', () => ({
|
|
|
41
28
|
}));
|
|
42
29
|
|
|
43
30
|
const mockFs = fs as jest.Mocked<typeof fs>;
|
|
44
|
-
|
|
31
|
+
|
|
32
|
+
/** trace 文件内容:一 trace 一行,缺省字段补齐成合法 ExecutionTrace(timestamp 递增) */
|
|
33
|
+
function traceFile(traces: Array<Partial<ExecutionTrace>>): string {
|
|
34
|
+
return traces
|
|
35
|
+
.map((t, i) => JSON.stringify({ level: 'iron_law', timestamp: i + 1, result: 'pass', ...t }))
|
|
36
|
+
.join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** n 条同一约束的 pass/fail 记录 */
|
|
40
|
+
function repeats(constraintId: string, n: number, result: ExecutionTrace['result']): Array<Partial<ExecutionTrace>> {
|
|
41
|
+
return Array.from({ length: n }, () => ({ constraintId, result }));
|
|
42
|
+
}
|
|
45
43
|
|
|
46
44
|
let io: CapturingIO;
|
|
47
45
|
beforeEach(() => {
|
|
@@ -80,98 +78,56 @@ describe('status command', () => {
|
|
|
80
78
|
|
|
81
79
|
describe('正常状态显示', () => {
|
|
82
80
|
it('应该显示记录数', async () => {
|
|
83
|
-
|
|
84
|
-
{ constraintId: 'test1'
|
|
85
|
-
{ constraintId: 'test2', level: 'guideline'
|
|
86
|
-
];
|
|
87
|
-
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
88
|
-
|
|
89
|
-
const mockSummarize = jest.fn().mockReturnValue([
|
|
90
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 1 },
|
|
91
|
-
]);
|
|
92
|
-
const mockAnalyze = {
|
|
93
|
-
summarize: mockSummarize,
|
|
94
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
95
|
-
};
|
|
96
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
81
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
82
|
+
{ constraintId: 'test1' },
|
|
83
|
+
{ constraintId: 'test2', level: 'guideline' },
|
|
84
|
+
]));
|
|
97
85
|
|
|
98
86
|
await status({}, io);
|
|
99
|
-
expect(io.outText()).
|
|
87
|
+
expect(io.outText()).toContain('记录数: 2 条');
|
|
88
|
+
expect(io.outText()).toContain('📈 约束统计:');
|
|
100
89
|
});
|
|
101
90
|
|
|
102
91
|
it('应该显示 Iron Laws 统计', async () => {
|
|
103
|
-
|
|
104
|
-
{ constraintId: 'no_bypass_checkpoint'
|
|
105
|
-
];
|
|
106
|
-
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
107
|
-
|
|
108
|
-
const mockSummarize = jest.fn().mockReturnValue([
|
|
109
|
-
{ constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 5 },
|
|
110
|
-
]);
|
|
111
|
-
const mockAnalyze = {
|
|
112
|
-
summarize: mockSummarize,
|
|
113
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
114
|
-
};
|
|
115
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
92
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
93
|
+
{ constraintId: 'no_bypass_checkpoint' },
|
|
94
|
+
]));
|
|
116
95
|
|
|
117
96
|
await status({ detail: true }, io);
|
|
118
|
-
expect(io.outText()).
|
|
97
|
+
expect(io.outText()).toContain('🔴 Iron Laws:');
|
|
98
|
+
expect(io.outText()).toContain('✅ no_bypass_checkpoint');
|
|
99
|
+
expect(io.outText()).toContain('检查: 1 | 通过: 100% | 失败: 0%');
|
|
119
100
|
});
|
|
120
101
|
});
|
|
121
102
|
|
|
122
103
|
describe('异常检测', () => {
|
|
123
104
|
it('应该显示异常列表', async () => {
|
|
124
|
-
|
|
125
|
-
{ constraintId: 'test1',
|
|
126
|
-
];
|
|
127
|
-
mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
|
|
128
|
-
|
|
129
|
-
const mockAnomalies = [
|
|
130
|
-
{ constraintId: 'test1', type: 'high_failure_rate', current: 0.8, threshold: 0.5 },
|
|
131
|
-
];
|
|
132
|
-
const mockAnalyze = {
|
|
133
|
-
summarize: jest.fn().mockReturnValue([
|
|
134
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 0.2, failRate: 0.8, totalChecks: 5 },
|
|
135
|
-
]),
|
|
136
|
-
detectAnomalies: jest.fn().mockReturnValue(mockAnomalies),
|
|
137
|
-
};
|
|
138
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
105
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
106
|
+
{ constraintId: 'test1', result: 'fail' },
|
|
107
|
+
]));
|
|
139
108
|
|
|
140
109
|
await status({ anomalies: true }, io);
|
|
141
|
-
expect(io.outText()).toContain('
|
|
110
|
+
expect(io.outText()).toContain('发现 1 个异常');
|
|
111
|
+
expect(io.outText()).toContain(' test1');
|
|
112
|
+
expect(io.outText()).toContain('类型: low_pass_rate');
|
|
142
113
|
});
|
|
143
114
|
});
|
|
144
115
|
|
|
145
116
|
describe('详细模式', () => {
|
|
146
117
|
it('应该显示详细统计', async () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const mockSummarize = jest.fn().mockReturnValue([
|
|
153
|
-
{ constraintId: 'test1', level: 'iron_law', passRate: 0.8, failRate: 0.2, totalChecks: 10 },
|
|
154
|
-
]);
|
|
155
|
-
const mockAnalyze = {
|
|
156
|
-
summarize: mockSummarize,
|
|
157
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
158
|
-
};
|
|
159
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
118
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
119
|
+
...repeats('test1', 4, 'pass'),
|
|
120
|
+
{ constraintId: 'test1', result: 'fail' },
|
|
121
|
+
]));
|
|
160
122
|
|
|
161
123
|
await status({ detail: true }, io);
|
|
162
|
-
expect(io.outText()).
|
|
124
|
+
expect(io.outText()).toContain('检查: 5 | 通过: 80% | 失败: 20%');
|
|
163
125
|
});
|
|
164
126
|
});
|
|
165
127
|
|
|
166
128
|
describe('状态文件更新', () => {
|
|
167
129
|
it('应该更新 .state.json', async () => {
|
|
168
|
-
mockFs.readFileSync.mockReturnValue(
|
|
169
|
-
|
|
170
|
-
const mockAnalyze = {
|
|
171
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
172
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
173
|
-
};
|
|
174
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
130
|
+
mockFs.readFileSync.mockReturnValue(traceFile([{ constraintId: 'test' }]));
|
|
175
131
|
|
|
176
132
|
await status({}, io);
|
|
177
133
|
expect(mockFs.writeFileSync).toHaveBeenCalled();
|
|
@@ -180,110 +136,72 @@ describe('status command', () => {
|
|
|
180
136
|
|
|
181
137
|
describe('Guidelines 统计', () => {
|
|
182
138
|
it('应该显示 Guidelines 统计', async () => {
|
|
183
|
-
mockFs.readFileSync.mockReturnValue(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
summarize: jest.fn().mockReturnValue([
|
|
187
|
-
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.9, failRate: 0.1, totalChecks: 10 },
|
|
188
|
-
]),
|
|
189
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
190
|
-
};
|
|
191
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
139
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
140
|
+
{ constraintId: 'test_guide', level: 'guideline' },
|
|
141
|
+
]));
|
|
192
142
|
|
|
193
143
|
await status({}, io);
|
|
194
|
-
expect(io.outText()).toContain('Guidelines');
|
|
144
|
+
expect(io.outText()).toContain('🟡 Guidelines:');
|
|
145
|
+
expect(io.outText()).toContain('✅ test_guide');
|
|
195
146
|
});
|
|
196
147
|
});
|
|
197
148
|
|
|
198
149
|
describe('异常模式', () => {
|
|
199
150
|
it('应该显示未发现异常当无异常', async () => {
|
|
200
|
-
mockFs.readFileSync.mockReturnValue(
|
|
201
|
-
|
|
202
|
-
const mockAnalyze = {
|
|
203
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
204
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
205
|
-
};
|
|
206
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
151
|
+
mockFs.readFileSync.mockReturnValue(traceFile([{ constraintId: 'test' }]));
|
|
207
152
|
|
|
208
153
|
await status({ anomalies: true }, io);
|
|
209
|
-
expect(io.outText()).toContain('未发现异常');
|
|
154
|
+
expect(io.outText()).toContain('✅ 未发现异常');
|
|
210
155
|
});
|
|
211
156
|
|
|
212
157
|
it('应该显示异常详情', async () => {
|
|
213
|
-
mockFs.readFileSync.mockReturnValue(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
217
|
-
detectAnomalies: jest.fn().mockReturnValue([
|
|
218
|
-
{ constraintId: 'test', type: 'high_failure_rate', data: { currentRate: 0.8, threshold: 0.5 } },
|
|
219
|
-
]),
|
|
220
|
-
};
|
|
221
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
158
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
159
|
+
{ constraintId: 'test', result: 'fail' },
|
|
160
|
+
]));
|
|
222
161
|
|
|
223
162
|
await status({ anomalies: true }, io);
|
|
224
|
-
expect(io.outText()).toContain('
|
|
163
|
+
expect(io.outText()).toContain('当前值: 0');
|
|
164
|
+
expect(io.outText()).toContain('阈值: 0.3');
|
|
225
165
|
expect(io.outText()).toContain('下一步建议');
|
|
226
166
|
});
|
|
227
167
|
});
|
|
228
168
|
|
|
229
169
|
describe('建议', () => {
|
|
230
170
|
it('应该显示良好建议当 trace >= 100', async () => {
|
|
231
|
-
|
|
232
|
-
mockFs.readFileSync.mockReturnValue(traces);
|
|
233
|
-
|
|
234
|
-
const mockAnalyze = {
|
|
235
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
236
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
237
|
-
};
|
|
238
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
171
|
+
mockFs.readFileSync.mockReturnValue(traceFile(repeats('test', 100, 'pass')));
|
|
239
172
|
|
|
240
173
|
await status({}, io);
|
|
174
|
+
expect(io.outText()).toContain('记录数: 100 条');
|
|
241
175
|
expect(io.outText()).toContain('状态良好');
|
|
242
176
|
});
|
|
243
177
|
|
|
244
178
|
it('应该显示积累数据建议当 trace < 100', async () => {
|
|
245
|
-
mockFs.readFileSync.mockReturnValue(
|
|
246
|
-
|
|
247
|
-
const mockAnalyze = {
|
|
248
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
249
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
250
|
-
};
|
|
251
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
179
|
+
mockFs.readFileSync.mockReturnValue(traceFile([{ constraintId: 'test' }]));
|
|
252
180
|
|
|
253
181
|
await status({}, io);
|
|
254
182
|
expect(io.outText()).toContain('继续积累数据');
|
|
255
183
|
});
|
|
256
184
|
|
|
257
185
|
it('应该显示诊断建议当有异常', async () => {
|
|
258
|
-
mockFs.readFileSync.mockReturnValue(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
summarize: jest.fn().mockReturnValue([]),
|
|
262
|
-
detectAnomalies: jest.fn().mockReturnValue([
|
|
263
|
-
{ constraintId: 'test', type: 'high_failure_rate' },
|
|
264
|
-
]),
|
|
265
|
-
};
|
|
266
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
186
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
187
|
+
{ constraintId: 'test', result: 'fail' },
|
|
188
|
+
]));
|
|
267
189
|
|
|
268
|
-
await status({}, io);
|
|
190
|
+
await status({ anomalies: true }, io);
|
|
269
191
|
expect(io.outText()).toContain('harness status --detail');
|
|
270
192
|
});
|
|
271
193
|
});
|
|
272
194
|
|
|
273
|
-
describe('
|
|
195
|
+
describe('详细模式扩展', () => {
|
|
274
196
|
it('应该显示 Guidelines 详细统计', async () => {
|
|
275
|
-
mockFs.readFileSync.mockReturnValue(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
{ constraintId: 'test_guide', level: 'guideline', passRate: 0.6, failRate: 0.4, totalChecks: 10 },
|
|
280
|
-
]),
|
|
281
|
-
detectAnomalies: jest.fn().mockReturnValue([]),
|
|
282
|
-
};
|
|
283
|
-
(MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
|
|
197
|
+
mockFs.readFileSync.mockReturnValue(traceFile([
|
|
198
|
+
...repeats('test_guide', 3, 'pass'),
|
|
199
|
+
...repeats('test_guide', 2, 'fail'),
|
|
200
|
+
].map(t => ({ ...t, level: 'guideline' as const }))));
|
|
284
201
|
|
|
285
202
|
await status({ detail: true }, io);
|
|
286
|
-
expect(io.outText()).toContain('
|
|
203
|
+
expect(io.outText()).toContain('⚠️ test_guide');
|
|
204
|
+
expect(io.outText()).toContain('检查: 5 | 通过: 60% | 失败: 40%');
|
|
287
205
|
});
|
|
288
206
|
});
|
|
289
207
|
});
|
|
@@ -128,7 +128,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
|
128
128
|
{ flags: '-t, --test-command <command>', description: '测试命令' },
|
|
129
129
|
{ flags: '-p, --project-path <path>', description: '项目路径' },
|
|
130
130
|
{ flags: '--allow-partial', description: '允许部分测试通过', defaultValue: false },
|
|
131
|
-
{ flags: '--max-retries <n>', description: '最大重试次数', defaultValue: '2' },
|
|
132
131
|
{ flags: '--coverage', description: '检查测试覆盖率' },
|
|
133
132
|
{ flags: '--coverage-threshold <n>', description: '覆盖率阈值', defaultValue: '80' },
|
|
134
133
|
],
|
|
@@ -157,7 +156,7 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
|
157
156
|
description: '生成检查报告',
|
|
158
157
|
options: [
|
|
159
158
|
{ flags: '-o, --output <path>', description: '输出文件路径' },
|
|
160
|
-
{ flags: '-f, --format <format>', description: '输出格式 (json/markdown
|
|
159
|
+
{ flags: '-f, --format <format>', description: '输出格式 (json/markdown)', defaultValue: 'markdown' },
|
|
161
160
|
{ flags: '-p, --project-path <path>', description: '项目路径' },
|
|
162
161
|
],
|
|
163
162
|
action: { module: 'report', export: 'report' },
|
|
@@ -298,22 +297,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
|
298
297
|
action: { module: 'posteval-plan', export: 'postevalPlan' },
|
|
299
298
|
mapActionArgs: (positionals) => [{ planPath: positionals[0] }],
|
|
300
299
|
},
|
|
301
|
-
{
|
|
302
|
-
command: 'update-user-model',
|
|
303
|
-
alias: 'uum',
|
|
304
|
-
description: '从新对话中提取信号,更新用户思维模型(增量演化)',
|
|
305
|
-
options: [
|
|
306
|
-
{ flags: '--json', description: 'JSON 格式输出', defaultValue: false },
|
|
307
|
-
{ flags: '--dry-run', description: '只显示变化,不更新状态', defaultValue: false },
|
|
308
|
-
{ flags: '--days <n>', description: '只处理最近 N 天的会话(自然日,含今天)' },
|
|
309
|
-
],
|
|
310
|
-
action: { module: 'update-user-model', export: 'updateUserModel' },
|
|
311
|
-
mapActionArgs: (_pos, options) => [{
|
|
312
|
-
days: options.days !== undefined ? parseInt(String(options.days), 10) : undefined,
|
|
313
|
-
json: options.json,
|
|
314
|
-
dryRun: options.dryRun,
|
|
315
|
-
}],
|
|
316
|
-
},
|
|
317
300
|
{
|
|
318
301
|
command: 'release',
|
|
319
302
|
description: 'npm 发布流水线:tsc → dist 验证 → npm version → git push → npm publish → gh release。不依赖 Studio API。',
|
|
@@ -324,20 +307,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
|
324
307
|
action: { module: 'release', export: 'release' },
|
|
325
308
|
mapActionArgs: (_pos, options) => [{ bumpType: options.bump, dryRun: options.dryRun }],
|
|
326
309
|
},
|
|
327
|
-
{
|
|
328
|
-
command: 'analyze-sessions',
|
|
329
|
-
alias: 'analyze',
|
|
330
|
-
description: '分析 Claude Code 对话,挖掘纠正模式和高频概念,生成规则候选',
|
|
331
|
-
options: [
|
|
332
|
-
{ flags: '-d, --days <n>', description: '分析最近 N 天的会话', defaultValue: '7' },
|
|
333
|
-
{ flags: '--json', description: 'JSON 格式输出', defaultValue: false },
|
|
334
|
-
],
|
|
335
|
-
action: { module: 'analyze-sessions', export: 'analyzeSessions' },
|
|
336
|
-
mapActionArgs: (_pos, options) => [{
|
|
337
|
-
days: parseInt(String(options.days), 10),
|
|
338
|
-
json: options.json,
|
|
339
|
-
}],
|
|
340
|
-
},
|
|
341
310
|
{
|
|
342
311
|
command: 'constraints',
|
|
343
312
|
description: '输出约束集合元数据(版本、hash、计数、文本大小)',
|
|
@@ -19,8 +19,6 @@ export interface PassesGateOptions {
|
|
|
19
19
|
projectPath?: string;
|
|
20
20
|
/** 是否允许部分通过 */
|
|
21
21
|
allowPartial?: boolean;
|
|
22
|
-
/** 最大重试次数 */
|
|
23
|
-
maxRetries?: number;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
/**
|
|
@@ -54,7 +52,6 @@ export async function runPassesGate(
|
|
|
54
52
|
testCommand,
|
|
55
53
|
requireEvidence: false,
|
|
56
54
|
allowPartialPass: options.allowPartial || false,
|
|
57
|
-
maxRetries: options.maxRetries || 2,
|
|
58
55
|
};
|
|
59
56
|
|
|
60
57
|
// 执行测试
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
|
-
import { PerformanceGate } from '../../gates/performance';
|
|
8
|
+
import { PerformanceGate, type ExtendedPerformanceGateConfig } from '../../gates/performance';
|
|
9
|
+
import type { GateContext, PerformanceThresholds } from '../../gates/types';
|
|
9
10
|
import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
10
11
|
|
|
11
12
|
export interface PerformanceOptions {
|
|
@@ -19,10 +20,6 @@ export interface PerformanceOptions {
|
|
|
19
20
|
bundle?: boolean;
|
|
20
21
|
/** 打包大小阈值(KB) */
|
|
21
22
|
bundleThreshold?: number;
|
|
22
|
-
/** 是否检查基准测试 */
|
|
23
|
-
benchmark?: boolean;
|
|
24
|
-
/** 基准测试超时(秒) */
|
|
25
|
-
benchmarkTimeout?: number;
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
/**
|
|
@@ -36,34 +33,28 @@ export async function performance(
|
|
|
36
33
|
|
|
37
34
|
const projectPath = options.projectPath || process.cwd();
|
|
38
35
|
|
|
39
|
-
//
|
|
40
|
-
|
|
36
|
+
// 构建配置(架构评审候选2:键名对齐 PerformanceThresholds 真字段——
|
|
37
|
+
// 原 thresholds.coverage / bundleSize 字节换算是错位键,旗帜恒不生效)
|
|
38
|
+
const config: Partial<ExtendedPerformanceGateConfig> = {};
|
|
39
|
+
const thresholds: PerformanceThresholds = {};
|
|
41
40
|
|
|
42
41
|
if (options.coverage && options.coverageThreshold) {
|
|
43
|
-
|
|
44
|
-
coverage: options.coverageThreshold,
|
|
45
|
-
};
|
|
42
|
+
thresholds.minCoverage = options.coverageThreshold;
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
if (options.bundleThreshold) {
|
|
49
|
-
|
|
50
|
-
config.thresholds.bundleSize = options.bundleThreshold * 1024; // KB to bytes
|
|
46
|
+
thresholds.maxBundleSize = options.bundleThreshold; // KB 直传,gate 按 KB 比较
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
if (
|
|
54
|
-
config.
|
|
49
|
+
if (Object.keys(thresholds).length > 0) {
|
|
50
|
+
config.thresholds = thresholds;
|
|
55
51
|
}
|
|
56
52
|
|
|
57
53
|
// 创建性能门控实例
|
|
58
54
|
const gate = new PerformanceGate(config);
|
|
59
55
|
|
|
60
56
|
try {
|
|
61
|
-
const result = await gate.check({
|
|
62
|
-
projectPath,
|
|
63
|
-
checkCoverage: options.coverage,
|
|
64
|
-
checkBundle: options.bundle,
|
|
65
|
-
checkBenchmark: options.benchmark,
|
|
66
|
-
} as any);
|
|
57
|
+
const result = await gate.check({ projectPath } as GateContext);
|
|
67
58
|
|
|
68
59
|
if (result.passed) {
|
|
69
60
|
log(io);
|
|
@@ -83,13 +74,8 @@ export async function performance(
|
|
|
83
74
|
|
|
84
75
|
if (metrics.bundleSize !== undefined) {
|
|
85
76
|
const thresholdKB = options.bundleThreshold || 500;
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
log(io, chalk.gray(` 打包大小: ${actualKB.toFixed(2)} KB ${status}`));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (metrics.benchmarkTime !== undefined) {
|
|
92
|
-
log(io, chalk.gray(` 基准测试: ${metrics.benchmarkTime}ms`));
|
|
77
|
+
const status = metrics.bundleSize <= thresholdKB ? '✅' : '❌';
|
|
78
|
+
log(io, chalk.gray(` 打包大小: ${metrics.bundleSize} KB ${status}`));
|
|
93
79
|
}
|
|
94
80
|
}
|
|
95
81
|
} else {
|
|
@@ -8,7 +8,6 @@ import chalk from 'chalk';
|
|
|
8
8
|
import * as fs from 'fs/promises';
|
|
9
9
|
import { ConstraintChecker } from '../../core/constraints/checker';
|
|
10
10
|
import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
|
|
11
|
-
import { executeWithCollect } from '../../failure/constraint-handler';
|
|
12
11
|
import { getTraceCollector } from '../../monitoring/traces';
|
|
13
12
|
import type { ConstraintContext } from '../../types/constraint';
|
|
14
13
|
import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
@@ -17,7 +16,7 @@ export interface ReportOptions {
|
|
|
17
16
|
/** 输出文件路径 */
|
|
18
17
|
output?: string;
|
|
19
18
|
/** 输出格式 */
|
|
20
|
-
format: 'json' | 'markdown'
|
|
19
|
+
format: 'json' | 'markdown';
|
|
21
20
|
/** 项目路径 */
|
|
22
21
|
projectPath?: string;
|
|
23
22
|
}
|
|
@@ -59,12 +58,8 @@ export async function report(options: ReportOptions, io: CommandIO = processIO):
|
|
|
59
58
|
projectPath,
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
//
|
|
63
|
-
const
|
|
64
|
-
checker.checkConstraints(context)
|
|
65
|
-
);
|
|
66
|
-
// COLLECT 策略始终返回 checkResult
|
|
67
|
-
const result = checkResult!;
|
|
61
|
+
// 收集模式(架构评审候选1):不抛、全量收集,铁律违规如实进报告
|
|
62
|
+
const result = await checker.collectConstraints(context);
|
|
68
63
|
|
|
69
64
|
const failedIronLaws = result.ironLaws.filter(r => !r.satisfied);
|
|
70
65
|
const failedGuidelines = result.guidelines.filter(r => !r.satisfied);
|
|
@@ -99,9 +94,6 @@ export async function report(options: ReportOptions, io: CommandIO = processIO):
|
|
|
99
94
|
case 'markdown':
|
|
100
95
|
content = generateMarkdownReport(reportData);
|
|
101
96
|
break;
|
|
102
|
-
case 'html':
|
|
103
|
-
content = generateHtmlReport(reportData);
|
|
104
|
-
break;
|
|
105
97
|
default:
|
|
106
98
|
content = JSON.stringify(reportData, null, 2);
|
|
107
99
|
}
|
|
@@ -150,53 +142,3 @@ function generateMarkdownReport(data: ReportData): string {
|
|
|
150
142
|
return lines.join('\n');
|
|
151
143
|
}
|
|
152
144
|
|
|
153
|
-
function generateHtmlReport(data: ReportData): string {
|
|
154
|
-
const violationsHtml = data.constraints.violations.length > 0
|
|
155
|
-
? `<h3>违规项</h3><ul>${data.constraints.violations.map(v =>
|
|
156
|
-
`<li><strong>${v.id}</strong> (${v.level}): ${v.message}</li>`
|
|
157
|
-
).join('')}</ul>`
|
|
158
|
-
: '';
|
|
159
|
-
|
|
160
|
-
return `<!DOCTYPE html>
|
|
161
|
-
<html lang="zh-CN">
|
|
162
|
-
<head>
|
|
163
|
-
<meta charset="UTF-8">
|
|
164
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
165
|
-
<title>Harness 检查报告</title>
|
|
166
|
-
<style>
|
|
167
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
|
168
|
-
h1 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 10px; }
|
|
169
|
-
h2 { color: #555; margin-top: 30px; }
|
|
170
|
-
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
|
|
171
|
-
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
172
|
-
th { background-color: #4CAF50; color: white; }
|
|
173
|
-
tr:nth-child(even) { background-color: #f2f2f2; }
|
|
174
|
-
.passed { color: #4CAF50; }
|
|
175
|
-
.failed { color: #f44336; }
|
|
176
|
-
.meta { color: #666; font-size: 0.9em; margin-bottom: 20px; }
|
|
177
|
-
</style>
|
|
178
|
-
</head>
|
|
179
|
-
<body>
|
|
180
|
-
<h1>Harness 检查报告</h1>
|
|
181
|
-
<p class="meta">生成时间: ${data.timestamp}<br>项目路径: ${data.projectPath}</p>
|
|
182
|
-
|
|
183
|
-
<h2>约束检查</h2>
|
|
184
|
-
<table>
|
|
185
|
-
<tr><th>指标</th><th>数值</th></tr>
|
|
186
|
-
<tr><td>总约束</td><td>${data.constraints.total}</td></tr>
|
|
187
|
-
<tr><td>Iron Laws</td><td>${data.constraints.ironLaws}</td></tr>
|
|
188
|
-
<tr><td>Guidelines</td><td>${data.constraints.guidelines}</td></tr>
|
|
189
|
-
<tr><td>Prompts</td><td>${data.constraints.prompts}</td></tr>
|
|
190
|
-
<tr><td>通过</td><td class="passed">${data.constraints.passed}</td></tr>
|
|
191
|
-
<tr><td>失败</td><td class="failed">${data.constraints.failed}</td></tr>
|
|
192
|
-
<tr><td>警告</td><td>${data.constraints.warnings}</td></tr>
|
|
193
|
-
</table>
|
|
194
|
-
|
|
195
|
-
${violationsHtml}
|
|
196
|
-
|
|
197
|
-
<footer style="margin-top: 40px; color: #999; text-align: center;">
|
|
198
|
-
报告由 @dommaker/harness 生成
|
|
199
|
-
</footer>
|
|
200
|
-
</body>
|
|
201
|
-
</html>`;
|
|
202
|
-
}
|
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
|
-
import {
|
|
11
|
-
import { TraceAnalyzer } from '../../monitoring/trace-analyzer';
|
|
10
|
+
import { summarizeTraces, detectTraceAnomalies } from '../../monitoring/trace-analyzer';
|
|
12
11
|
import { readJsonl } from '../../utils/jsonl';
|
|
13
12
|
import { DEFAULT_TRACE_FILE } from '../../types/trace';
|
|
14
13
|
import type { ExecutionTrace } from '../../types/trace';
|
|
@@ -57,18 +56,14 @@ export async function status(options: StatusOptions, io: CommandIO = processIO):
|
|
|
57
56
|
// filter(Boolean) 沿用原语义:parse 成功但值为 falsy 的行(如 "null")不进分析
|
|
58
57
|
// 计数去向:harness#100——skippedLines 另起一行走 stderr 告知(口径不改,只补告知)。
|
|
59
58
|
// 不经 TraceCollector.readReport():本命令按 -p 的 projectPath 直读读链正本,且要的是
|
|
60
|
-
// records + skippedLines
|
|
59
|
+
// records + skippedLines 的原始行数口径;下游只做纯判定(ADR-0020 直调模块级函数)
|
|
61
60
|
const { records, skippedLines } = readJsonl<ExecutionTrace>(tracesPath, 'skip');
|
|
62
61
|
const traces = records.filter(Boolean);
|
|
63
62
|
const traceCount = records.length + skippedLines;
|
|
64
63
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
// 生成统计
|
|
70
|
-
const summaries = analyzer.summarize(traces);
|
|
71
|
-
const anomalies = analyzer.detectAnomalies(summaries);
|
|
64
|
+
// 生成统计(数据进数据出,无需 collector/分析器实例)
|
|
65
|
+
const summaries = summarizeTraces(traces);
|
|
66
|
+
const anomalies = detectTraceAnomalies(summaries);
|
|
72
67
|
|
|
73
68
|
// 基本统计
|
|
74
69
|
log(io, chalk.gray(`记录数: ${traceCount} 条`));
|
package/src/context/CONTEXT.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# context/
|
|
2
2
|
|
|
3
3
|
## 职责
|
|
4
|
-
上下文管理:Token 预算(多级分配)
|
|
4
|
+
上下文管理:Token 预算(多级分配)、会话管理、知识注入。
|
|
5
5
|
|
|
6
6
|
## 核心导出
|
|
7
7
|
- `TokenBudget` — 多级 token 预算(system/user/tool/reserve)
|
|
8
|
-
- `Compaction` — 会话压缩(摘要/截断/滑动窗口)
|
|
9
8
|
- `SessionManager` — 会话管理
|
|
10
9
|
- `KnowledgeInjector` — 知识注入引擎
|
|
11
10
|
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
|
|
17
16
|
## 约定
|
|
18
17
|
- Token 预算策略由配置文件控制
|
|
19
|
-
-
|
|
18
|
+
- 压缩只剩词汇不留引擎:`types.ts` 保留 `CompactionLevel`(被 `ContextUsageSnapshot.compactionLevel` 引用)与 `CompactionConfig`,但 `SessionCompaction` 引擎、`CompactionResult`、`DEFAULT_COMPACTION_CONFIG` 与 `AdaptiveTokenBudget` 已随 ADR-0022(零生产消费者)删除,本目录不再提供压缩策略组合点
|
|
20
19
|
|
|
21
20
|
## 注意事项
|
|
22
21
|
- 零 Token 成本:纯计算,不调用 LLM
|