@dommaker/harness 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -1
- package/bin/harness.js +81 -3
- package/dist/cli/commands/diagnose.d.ts +16 -0
- package/dist/cli/commands/diagnose.d.ts.map +1 -0
- package/dist/cli/commands/diagnose.js +195 -0
- package/dist/cli/commands/diagnose.js.map +1 -0
- package/dist/cli/commands/index.d.ts +3 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +7 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/propose.d.ts +18 -0
- package/dist/cli/commands/propose.d.ts.map +1 -0
- package/dist/cli/commands/propose.js +331 -0
- package/dist/cli/commands/propose.js.map +1 -0
- package/dist/cli/commands/traces.d.ts +15 -0
- package/dist/cli/commands/traces.d.ts.map +1 -0
- package/dist/cli/commands/traces.js +167 -0
- package/dist/cli/commands/traces.js.map +1 -0
- package/dist/core/constraints/checker.d.ts +4 -0
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +54 -0
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/monitoring/constraint-doctor.d.ts +130 -0
- package/dist/monitoring/constraint-doctor.d.ts.map +1 -0
- package/dist/monitoring/constraint-doctor.js +305 -0
- package/dist/monitoring/constraint-doctor.js.map +1 -0
- package/dist/monitoring/constraint-evolver.d.ts +174 -0
- package/dist/monitoring/constraint-evolver.d.ts.map +1 -0
- package/dist/monitoring/constraint-evolver.js +412 -0
- package/dist/monitoring/constraint-evolver.js.map +1 -0
- package/dist/monitoring/index.d.ts +14 -0
- package/dist/monitoring/index.d.ts.map +1 -0
- package/dist/monitoring/index.js +30 -0
- package/dist/monitoring/index.js.map +1 -0
- package/dist/monitoring/trace-analyzer.d.ts +100 -0
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -0
- package/dist/monitoring/trace-analyzer.js +432 -0
- package/dist/monitoring/trace-analyzer.js.map +1 -0
- package/dist/monitoring/traces.d.ts +111 -0
- package/dist/monitoring/traces.d.ts.map +1 -0
- package/dist/monitoring/traces.js +312 -0
- package/dist/monitoring/traces.js.map +1 -0
- package/dist/types/constraint.d.ts +2 -0
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/trace.d.ts +151 -0
- package/dist/types/trace.d.ts.map +1 -0
- package/dist/types/trace.js +8 -0
- package/dist/types/trace.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,6 +58,13 @@ harness passes-gate
|
|
|
58
58
|
|
|
59
59
|
# 生成报告
|
|
60
60
|
harness report
|
|
61
|
+
|
|
62
|
+
# Trace 分析(Execution Traces)
|
|
63
|
+
harness traces stats # 查看 trace 文件统计
|
|
64
|
+
harness traces summary # 查看约束汇总
|
|
65
|
+
harness traces anomalies # 检测异常模式
|
|
66
|
+
harness traces report # 生成完整报告
|
|
67
|
+
harness traces clean # 清理旧 trace 文件
|
|
61
68
|
```
|
|
62
69
|
|
|
63
70
|
### 3. 在 CI 中使用
|
|
@@ -215,4 +222,130 @@ npm test
|
|
|
215
222
|
|
|
216
223
|
## 许可证
|
|
217
224
|
|
|
218
|
-
MIT © dommaker
|
|
225
|
+
MIT © dommaker
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Execution Trace 系统(v0.3+)
|
|
230
|
+
|
|
231
|
+
### 概念
|
|
232
|
+
|
|
233
|
+
Execution Trace 是约束检查的轻量记录,用于:
|
|
234
|
+
- 统计约束触发频率
|
|
235
|
+
- 检测异常模式(高频绕过、失败率上升)
|
|
236
|
+
- 为 Agent 诊断提供数据基础
|
|
237
|
+
|
|
238
|
+
### 设计原则
|
|
239
|
+
|
|
240
|
+
| 原则 | 说明 |
|
|
241
|
+
|------|------|
|
|
242
|
+
| **零 Token 成本** | 记录和统计都不调用 LLM |
|
|
243
|
+
| **轻量记录** | 只记录核心字段,不记录代码片段 |
|
|
244
|
+
| **异步分析** | 统计每小时执行,异常检测每日执行 |
|
|
245
|
+
| **按需诊断** | Agent 仅在检测到异常时才介入 |
|
|
246
|
+
|
|
247
|
+
### Trace 数据结构
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
interface ExecutionTrace {
|
|
251
|
+
constraintId: string; // 约束 ID
|
|
252
|
+
level: 'iron_law' | 'guideline' | 'tip';
|
|
253
|
+
timestamp: number; // Unix timestamp
|
|
254
|
+
result: 'pass' | 'fail' | 'bypassed';
|
|
255
|
+
operation?: string; // 触发条件
|
|
256
|
+
exceptionApplied?: string; // 例外类型
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### 自动记录
|
|
261
|
+
|
|
262
|
+
约束检查时自动记录:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { checkConstraints } from '@dommaker/harness';
|
|
266
|
+
|
|
267
|
+
// 每次检查都会自动记录 trace
|
|
268
|
+
const result = await checkConstraints(context);
|
|
269
|
+
// Trace 已写入 .harness/traces/execution.log
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Trace 文件位置
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
.harness/traces/
|
|
276
|
+
├── execution.log # 当前 trace 文件
|
|
277
|
+
├── execution-2026-04-05.log # 滚动备份(超出 10MB 时)
|
|
278
|
+
├── summary.json # 统计汇总
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 统计汇总
|
|
282
|
+
|
|
283
|
+
每小时自动执行:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { TraceAnalyzer } from '@dommaker/harness';
|
|
287
|
+
|
|
288
|
+
const analyzer = new TraceAnalyzer();
|
|
289
|
+
const summaries = analyzer.runHourlySummary();
|
|
290
|
+
|
|
291
|
+
// 输出:
|
|
292
|
+
// [
|
|
293
|
+
// { constraintId: 'no_fix_without_root_cause', passRate: 0.7, bypassRate: 0.1 },
|
|
294
|
+
// { constraintId: 'no_code_without_test', passRate: 0.9, bypassRate: 0 },
|
|
295
|
+
// ]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 异常检测
|
|
299
|
+
|
|
300
|
+
每日自动执行:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const anomalies = analyzer.runDailyAnomalyCheck();
|
|
304
|
+
|
|
305
|
+
// 检测类型:
|
|
306
|
+
// - high_bypass_rate:绕过率 > 30%
|
|
307
|
+
// - rising_fail_rate:失败率上升趋势
|
|
308
|
+
// - exception_overuse:例外使用率 > 40%
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### CLI 使用
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# 查看 trace 文件统计
|
|
315
|
+
harness traces stats
|
|
316
|
+
|
|
317
|
+
# 查看最近 24 小时的约束汇总
|
|
318
|
+
harness traces summary --hours 24
|
|
319
|
+
|
|
320
|
+
# 检测异常
|
|
321
|
+
harness traces anomalies
|
|
322
|
+
|
|
323
|
+
# JSON 格式输出
|
|
324
|
+
harness traces summary --format json
|
|
325
|
+
|
|
326
|
+
# 运行诊断
|
|
327
|
+
harness diagnose run --hours 24 --save
|
|
328
|
+
|
|
329
|
+
# 查看诊断列表
|
|
330
|
+
harness diagnose list
|
|
331
|
+
|
|
332
|
+
# 生成提案
|
|
333
|
+
harness propose generate --save
|
|
334
|
+
|
|
335
|
+
# 审核提案
|
|
336
|
+
harness propose review --diagnosis <id> --accept
|
|
337
|
+
|
|
338
|
+
# 查看实施指导
|
|
339
|
+
harness propose implement --diagnosis <id>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 成本控制
|
|
343
|
+
|
|
344
|
+
| 活动 | 频率 | Token 成本 |
|
|
345
|
+
|------|------|:----------:|
|
|
346
|
+
| Trace 记录 | 每次检查 | 0 |
|
|
347
|
+
| 统计汇总 | 每小时 | 0 |
|
|
348
|
+
| 异常检测 | 每日 | 0(未触发)~500(触发) |
|
|
349
|
+
| Agent 诊断 | 按需 | ~2000 |
|
|
350
|
+
|
|
351
|
+
**对比 Meta-Harness**:百万级 vs 5500/周,成本降低 **180 倍**。
|
package/bin/harness.js
CHANGED
|
@@ -7,14 +7,24 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { Command } = require('commander');
|
|
10
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
check,
|
|
12
|
+
listLaws,
|
|
13
|
+
validate,
|
|
14
|
+
runPassesGate,
|
|
15
|
+
init,
|
|
16
|
+
report,
|
|
17
|
+
tracesCommand,
|
|
18
|
+
diagnoseCommand,
|
|
19
|
+
proposeCommand
|
|
20
|
+
} = require('../dist/cli/commands/index');
|
|
11
21
|
|
|
12
22
|
const program = new Command();
|
|
13
23
|
|
|
14
24
|
program
|
|
15
25
|
.name('harness')
|
|
16
|
-
.description('通用工程约束框架 -
|
|
17
|
-
.version('0.
|
|
26
|
+
.description('通用工程约束框架 - 铁律系统、检查点验证、测试门控、执行追踪')
|
|
27
|
+
.version('0.3.0');
|
|
18
28
|
|
|
19
29
|
// ========================================
|
|
20
30
|
// harness check
|
|
@@ -100,5 +110,73 @@ program
|
|
|
100
110
|
await report(options);
|
|
101
111
|
});
|
|
102
112
|
|
|
113
|
+
// ========================================
|
|
114
|
+
// harness traces
|
|
115
|
+
// ========================================
|
|
116
|
+
program
|
|
117
|
+
.command('traces [subcommand]')
|
|
118
|
+
.description('Execution Trace 分析')
|
|
119
|
+
.option('--hours <n>', '分析最近 N 小时', '1')
|
|
120
|
+
.option('--constraint <id>', '过滤约束 ID')
|
|
121
|
+
.option('--format <format>', '输出格式 (json/text)', 'text')
|
|
122
|
+
.option('--max-age-days <n>', '清理超过 N 天的文件', '30')
|
|
123
|
+
.action(async (subcommand, options, command) => {
|
|
124
|
+
const sub = subcommand || 'stats';
|
|
125
|
+
await tracesCommand(sub, {
|
|
126
|
+
hours: parseInt(options.hours, 10),
|
|
127
|
+
constraintId: options.constraint,
|
|
128
|
+
format: options.format,
|
|
129
|
+
maxAgeDays: parseInt(options.maxAgeDays, 10),
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ========================================
|
|
134
|
+
// harness diagnose
|
|
135
|
+
// ========================================
|
|
136
|
+
program
|
|
137
|
+
.command('diagnose [subcommand]')
|
|
138
|
+
.description('约束诊断')
|
|
139
|
+
.option('--hours <n>', '分析最近 N 小时', '24')
|
|
140
|
+
.option('--constraint <id>', '过滤约束 ID')
|
|
141
|
+
.option('--anomaly <id>', '特定异常 ID')
|
|
142
|
+
.option('--format <format>', '输出格式 (json/text)', 'text')
|
|
143
|
+
.option('--save', '保存诊断结果', false)
|
|
144
|
+
.action(async (subcommand, options, command) => {
|
|
145
|
+
const sub = subcommand || 'list';
|
|
146
|
+
await diagnoseCommand(sub, {
|
|
147
|
+
hours: parseInt(options.hours, 10),
|
|
148
|
+
constraintId: options.constraint,
|
|
149
|
+
anomalyId: options.anomaly,
|
|
150
|
+
format: options.format,
|
|
151
|
+
save: options.save,
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ========================================
|
|
156
|
+
// harness propose
|
|
157
|
+
// ========================================
|
|
158
|
+
program
|
|
159
|
+
.command('propose [subcommand]')
|
|
160
|
+
.description('约束提案')
|
|
161
|
+
.option('--diagnosis <id>', '诊断 ID')
|
|
162
|
+
.option('--status <status>', '过滤状态')
|
|
163
|
+
.option('--format <format>', '输出格式 (json/text)', 'text')
|
|
164
|
+
.option('--save', '保存提案', false)
|
|
165
|
+
.option('--accept', '接受提案', false)
|
|
166
|
+
.option('--reject', '拒绝提案', false)
|
|
167
|
+
.option('--comment <text>', '审核意见')
|
|
168
|
+
.action(async (subcommand, options, command) => {
|
|
169
|
+
const sub = subcommand || 'list';
|
|
170
|
+
await proposeCommand(sub, {
|
|
171
|
+
diagnosisId: options.diagnosis,
|
|
172
|
+
status: options.status,
|
|
173
|
+
format: options.format,
|
|
174
|
+
save: options.save,
|
|
175
|
+
accept: options.accept,
|
|
176
|
+
reject: options.reject,
|
|
177
|
+
comment: options.comment,
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
103
181
|
// 解析命令行参数
|
|
104
182
|
program.parse();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnose CLI 命令
|
|
3
|
+
*
|
|
4
|
+
* 运行诊断分析异常
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* diagnose 命令
|
|
8
|
+
*/
|
|
9
|
+
export declare function diagnoseCommand(subcommand: string, options: {
|
|
10
|
+
hours?: number;
|
|
11
|
+
constraintId?: string;
|
|
12
|
+
anomalyId?: string;
|
|
13
|
+
format?: 'json' | 'text';
|
|
14
|
+
save?: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/diagnose.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH;;GAEG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GACA,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Diagnose CLI 命令
|
|
4
|
+
*
|
|
5
|
+
* 运行诊断分析异常
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.diagnoseCommand = diagnoseCommand;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const traces_1 = require("../../monitoring/traces");
|
|
45
|
+
const trace_analyzer_1 = require("../../monitoring/trace-analyzer");
|
|
46
|
+
const constraint_doctor_1 = require("../../monitoring/constraint-doctor");
|
|
47
|
+
/**
|
|
48
|
+
* diagnose 命令
|
|
49
|
+
*/
|
|
50
|
+
async function diagnoseCommand(subcommand, options) {
|
|
51
|
+
switch (subcommand) {
|
|
52
|
+
case 'run':
|
|
53
|
+
await runDiagnose(options);
|
|
54
|
+
break;
|
|
55
|
+
case 'show':
|
|
56
|
+
await showDiagnose(options);
|
|
57
|
+
break;
|
|
58
|
+
case 'list':
|
|
59
|
+
await listDiagnoses(options);
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
console.log('Usage: harness diagnose <subcommand>');
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log('Subcommands:');
|
|
65
|
+
console.log(' run Run diagnosis on detected anomalies');
|
|
66
|
+
console.log(' show Show a specific diagnosis result');
|
|
67
|
+
console.log(' list List all diagnosis results');
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('Options:');
|
|
70
|
+
console.log(' --hours <n> Analyze last N hours (default: 24)');
|
|
71
|
+
console.log(' --constraint <id> Filter by constraint ID');
|
|
72
|
+
console.log(' --anomaly <id> Show specific anomaly diagnosis');
|
|
73
|
+
console.log(' --format <format> Output format: json or text (default: text)');
|
|
74
|
+
console.log(' --save Save diagnosis to file');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 运行诊断
|
|
79
|
+
*/
|
|
80
|
+
async function runDiagnose(options) {
|
|
81
|
+
const hours = options.hours || 24;
|
|
82
|
+
const analyzer = (0, trace_analyzer_1.createAnalyzer)();
|
|
83
|
+
const doctor = (0, constraint_doctor_1.createDoctor)();
|
|
84
|
+
// 1. 检测异常
|
|
85
|
+
const anomalies = analyzer.runDailyAnomalyCheck();
|
|
86
|
+
// 过滤特定约束
|
|
87
|
+
let filteredAnomalies = anomalies;
|
|
88
|
+
if (options.constraintId) {
|
|
89
|
+
filteredAnomalies = anomalies.filter(a => a.constraintId === options.constraintId);
|
|
90
|
+
}
|
|
91
|
+
if (filteredAnomalies.length === 0) {
|
|
92
|
+
console.log('✅ No anomalies detected. No diagnosis needed.');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
console.log(`🔍 Detected ${filteredAnomalies.length} anomalies, running diagnosis...`);
|
|
96
|
+
console.log('');
|
|
97
|
+
// 2. 获取 traces
|
|
98
|
+
const collector = (0, traces_1.getTraceCollector)();
|
|
99
|
+
const traces = collector.readRecent(hours);
|
|
100
|
+
// 3. 运行诊断
|
|
101
|
+
const diagnoses = [];
|
|
102
|
+
for (const anomaly of filteredAnomalies) {
|
|
103
|
+
doctor.setData(traces.filter(t => t.constraintId === anomaly.constraintId));
|
|
104
|
+
const diagnosis = await doctor.diagnose(anomaly);
|
|
105
|
+
diagnoses.push(diagnosis);
|
|
106
|
+
// 保存诊断
|
|
107
|
+
if (options.save) {
|
|
108
|
+
const outputPath = `.harness/diagnoses/${diagnosis.anomalyId}.json`;
|
|
109
|
+
doctor.saveDiagnosis(diagnosis, outputPath);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// 4. 输出结果
|
|
113
|
+
if (options.format === 'json') {
|
|
114
|
+
console.log(JSON.stringify(diagnoses, null, 2));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
for (const diagnosis of diagnoses) {
|
|
118
|
+
console.log(doctor.generateReport(diagnosis));
|
|
119
|
+
console.log('---');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 5. 统计
|
|
123
|
+
const needsChange = diagnoses.filter(d => d.needsChange).length;
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(`📊 Summary: ${needsChange} diagnoses need constraint changes`);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 显示特定诊断
|
|
129
|
+
*/
|
|
130
|
+
async function showDiagnose(options) {
|
|
131
|
+
if (!options.anomalyId) {
|
|
132
|
+
console.log('❌ Please specify --anomaly <id>');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const doctor = (0, constraint_doctor_1.createDoctor)();
|
|
136
|
+
const diagnosisPath = `.harness/diagnoses/${options.anomalyId}.json`;
|
|
137
|
+
if (!fs.existsSync(diagnosisPath)) {
|
|
138
|
+
console.log(`❌ Diagnosis not found: ${options.anomalyId}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const diagnosis = doctor.loadDiagnosis(diagnosisPath);
|
|
142
|
+
if (options.format === 'json') {
|
|
143
|
+
console.log(JSON.stringify(diagnosis, null, 2));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log(doctor.generateReport(diagnosis));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 列出所有诊断
|
|
151
|
+
*/
|
|
152
|
+
async function listDiagnoses(options) {
|
|
153
|
+
const diagnosesDir = '.harness/diagnoses';
|
|
154
|
+
if (!fs.existsSync(diagnosesDir)) {
|
|
155
|
+
console.log('❌ No diagnoses found. Run `harness diagnose run` first.');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const files = fs.readdirSync(diagnosesDir)
|
|
159
|
+
.filter(f => f.endsWith('.json'));
|
|
160
|
+
if (files.length === 0) {
|
|
161
|
+
console.log('❌ No diagnoses found.');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const doctor = (0, constraint_doctor_1.createDoctor)();
|
|
165
|
+
const diagnoses = files.map(f => {
|
|
166
|
+
const content = fs.readFileSync(path.join(diagnosesDir, f), 'utf-8');
|
|
167
|
+
return JSON.parse(content);
|
|
168
|
+
});
|
|
169
|
+
if (options.format === 'json') {
|
|
170
|
+
console.log(JSON.stringify(diagnoses.map(d => ({
|
|
171
|
+
anomalyId: d.anomalyId,
|
|
172
|
+
constraintId: d.constraintId,
|
|
173
|
+
needsChange: d.needsChange,
|
|
174
|
+
urgency: d.urgency,
|
|
175
|
+
})), null, 2));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.log('📋 Diagnosis List');
|
|
179
|
+
console.log('');
|
|
180
|
+
for (const diagnosis of diagnoses) {
|
|
181
|
+
const urgencyEmoji = {
|
|
182
|
+
low: '🟢',
|
|
183
|
+
medium: '🟡',
|
|
184
|
+
high: '🔴',
|
|
185
|
+
}[diagnosis.urgency] || '⚪';
|
|
186
|
+
console.log(`${urgencyEmoji} ${diagnosis.anomalyId}`);
|
|
187
|
+
console.log(` Constraint: ${diagnosis.constraintId}`);
|
|
188
|
+
console.log(` Needs Change: ${diagnosis.needsChange ? 'Yes' : 'No'}`);
|
|
189
|
+
console.log(` Urgency: ${diagnosis.urgency}`);
|
|
190
|
+
console.log('');
|
|
191
|
+
}
|
|
192
|
+
console.log(`Total: ${diagnoses.length} diagnoses`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../../src/cli/commands/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,4 +6,7 @@ export { validate, createExampleCheckpoint, type ValidateOptions } from './valid
|
|
|
6
6
|
export { runPassesGate, checkCoverage, type PassesGateOptions } from './passes-gate';
|
|
7
7
|
export { init, type InitOptions } from './init';
|
|
8
8
|
export { report, type ReportOptions } from './report';
|
|
9
|
+
export { tracesCommand } from './traces';
|
|
10
|
+
export { diagnoseCommand } from './diagnose';
|
|
11
|
+
export { proposeCommand } from './propose';
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* CLI 命令导出
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.report = exports.init = exports.checkCoverage = exports.runPassesGate = exports.createExampleCheckpoint = exports.validate = exports.listLaws = exports.check = void 0;
|
|
6
|
+
exports.proposeCommand = exports.diagnoseCommand = exports.tracesCommand = exports.report = exports.init = exports.checkCoverage = exports.runPassesGate = exports.createExampleCheckpoint = exports.validate = exports.listLaws = exports.check = void 0;
|
|
7
7
|
var check_1 = require("./check");
|
|
8
8
|
Object.defineProperty(exports, "check", { enumerable: true, get: function () { return check_1.check; } });
|
|
9
9
|
Object.defineProperty(exports, "listLaws", { enumerable: true, get: function () { return check_1.listLaws; } });
|
|
@@ -17,4 +17,10 @@ var init_1 = require("./init");
|
|
|
17
17
|
Object.defineProperty(exports, "init", { enumerable: true, get: function () { return init_1.init; } });
|
|
18
18
|
var report_1 = require("./report");
|
|
19
19
|
Object.defineProperty(exports, "report", { enumerable: true, get: function () { return report_1.report; } });
|
|
20
|
+
var traces_1 = require("./traces");
|
|
21
|
+
Object.defineProperty(exports, "tracesCommand", { enumerable: true, get: function () { return traces_1.tracesCommand; } });
|
|
22
|
+
var diagnose_1 = require("./diagnose");
|
|
23
|
+
Object.defineProperty(exports, "diagnoseCommand", { enumerable: true, get: function () { return diagnose_1.diagnoseCommand; } });
|
|
24
|
+
var propose_1 = require("./propose");
|
|
25
|
+
Object.defineProperty(exports, "proposeCommand", { enumerable: true, get: function () { return propose_1.proposeCommand; } });
|
|
20
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,iCAA6D;AAApD,8FAAA,KAAK,OAAA;AAAE,iGAAA,QAAQ,OAAA;AACxB,uCAAqF;AAA5E,oGAAA,QAAQ,OAAA;AAAE,mHAAA,uBAAuB,OAAA;AAC1C,6CAAqF;AAA5E,4GAAA,aAAa,OAAA;AAAE,4GAAA,aAAa,OAAA;AACrC,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,mCAAsD;AAA7C,gGAAA,MAAM,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,iCAA6D;AAApD,8FAAA,KAAK,OAAA;AAAE,iGAAA,QAAQ,OAAA;AACxB,uCAAqF;AAA5E,oGAAA,QAAQ,OAAA;AAAE,mHAAA,uBAAuB,OAAA;AAC1C,6CAAqF;AAA5E,4GAAA,aAAa,OAAA;AAAE,4GAAA,aAAa,OAAA;AACrC,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,mCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,uCAA6C;AAApC,2GAAA,eAAe,OAAA;AACxB,qCAA2C;AAAlC,yGAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Propose CLI 命令
|
|
3
|
+
*
|
|
4
|
+
* 根据诊断生成约束提案
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* propose 命令
|
|
8
|
+
*/
|
|
9
|
+
export declare function proposeCommand(subcommand: string, options: {
|
|
10
|
+
diagnosisId?: string;
|
|
11
|
+
format?: 'json' | 'text';
|
|
12
|
+
save?: boolean;
|
|
13
|
+
status?: 'proposed' | 'accepted' | 'rejected';
|
|
14
|
+
accept?: boolean;
|
|
15
|
+
reject?: boolean;
|
|
16
|
+
comment?: string;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=propose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/propose.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH;;GAEG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,IAAI,CAAC,CAyCf"}
|