@hddz/plugin-harness 0.1.19 → 0.2.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.

Potentially problematic release.


This version of @hddz/plugin-harness might be problematic. Click here for more details.

Files changed (41) hide show
  1. package/README.md +97 -114
  2. package/dist/core/auditors/index.d.ts +2 -0
  3. package/dist/core/auditors/index.js +7 -0
  4. package/dist/core/auditors/skill-auditor.d.ts +72 -0
  5. package/dist/core/auditors/skill-auditor.js +488 -0
  6. package/dist/core/index.d.ts +22 -0
  7. package/dist/core/index.js +47 -0
  8. package/dist/core/loggers/config-logger.d.ts +25 -0
  9. package/dist/core/loggers/config-logger.js +139 -0
  10. package/dist/core/loggers/index.d.ts +4 -0
  11. package/dist/core/loggers/index.js +9 -0
  12. package/dist/core/loggers/operation-logger.d.ts +23 -0
  13. package/dist/core/loggers/operation-logger.js +125 -0
  14. package/dist/core/middleware/context-injector.d.ts +25 -0
  15. package/dist/core/middleware/context-injector.js +174 -0
  16. package/dist/core/middleware/index.d.ts +5 -0
  17. package/dist/core/middleware/index.js +11 -0
  18. package/dist/core/middleware/loop-detector.d.ts +18 -0
  19. package/dist/core/middleware/loop-detector.js +125 -0
  20. package/dist/core/middleware/trace-logger.d.ts +34 -0
  21. package/dist/core/middleware/trace-logger.js +141 -0
  22. package/dist/core/utils/file.d.ts +28 -0
  23. package/dist/core/utils/file.js +104 -0
  24. package/dist/core/utils/format.d.ts +16 -0
  25. package/dist/core/utils/format.js +60 -0
  26. package/dist/core/utils/index.d.ts +2 -0
  27. package/dist/core/utils/index.js +14 -0
  28. package/dist/core/validators/config-validator.d.ts +25 -0
  29. package/dist/core/validators/config-validator.js +235 -0
  30. package/dist/core/validators/index.d.ts +2 -0
  31. package/dist/core/validators/index.js +7 -0
  32. package/dist/file-watcher.d.ts +37 -0
  33. package/dist/file-watcher.js +151 -0
  34. package/dist/index.d.ts +63 -0
  35. package/dist/index.js +166 -106
  36. package/dist/src/file-watcher.d.ts +37 -0
  37. package/dist/src/file-watcher.js +151 -0
  38. package/dist/src/index.d.ts +70 -0
  39. package/dist/src/index.js +192 -0
  40. package/package.json +4 -12
  41. package/openclaw.plugin.json +0 -39
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ // src/middleware/loop-detector.ts - 循环检测中间件
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.LoopDetector = void 0;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ class LoopDetector {
41
+ workspacePath;
42
+ fileEditCounts = new Map();
43
+ stateFilePath;
44
+ config;
45
+ constructor(workspacePath, config = {}) {
46
+ this.workspacePath = workspacePath;
47
+ this.config = {
48
+ limit: 5,
49
+ windowMs: 300000, // 5 分钟
50
+ warningMessage: `⚠️ 警告:{file} 已被修改 {count} 次({window}分钟内)\n` +
51
+ '请考虑:\n' +
52
+ '1. 重新阅读任务规格\n' +
53
+ '2. 检查是否有根本性设计问题\n' +
54
+ '3. 考虑寻求人类帮助',
55
+ ...config,
56
+ };
57
+ // 状态持久化文件
58
+ const logsDir = path.join(workspacePath, 'logs');
59
+ if (!fs.existsSync(logsDir)) {
60
+ fs.mkdirSync(logsDir, { recursive: true });
61
+ }
62
+ this.stateFilePath = path.join(logsDir, 'loop-detector-state.json');
63
+ // 加载之前的状态
64
+ this.loadState();
65
+ }
66
+ loadState() {
67
+ try {
68
+ if (fs.existsSync(this.stateFilePath)) {
69
+ const data = fs.readFileSync(this.stateFilePath, 'utf8');
70
+ const state = JSON.parse(data);
71
+ this.fileEditCounts = new Map(Object.entries(state));
72
+ }
73
+ }
74
+ catch (error) {
75
+ // 忽略加载错误,从空状态开始
76
+ }
77
+ }
78
+ saveState() {
79
+ try {
80
+ const state = Object.fromEntries(this.fileEditCounts);
81
+ fs.writeFileSync(this.stateFilePath, JSON.stringify(state, null, 2));
82
+ }
83
+ catch (error) {
84
+ // 忽略保存错误
85
+ }
86
+ }
87
+ onFileEdit(filePath) {
88
+ const now = Date.now();
89
+ const edits = this.fileEditCounts.get(filePath) || [];
90
+ // 移除超出时间窗口的记录
91
+ const windowStart = now - this.config.windowMs;
92
+ const recentEdits = edits.filter(time => time > windowStart);
93
+ recentEdits.push(now);
94
+ this.fileEditCounts.set(filePath, recentEdits);
95
+ this.saveState();
96
+ if (recentEdits.length >= this.config.limit) {
97
+ return this.config.warningMessage
98
+ .replace('{file}', filePath)
99
+ .replace('{count}', recentEdits.length.toString())
100
+ .replace('{window}', (this.config.windowMs / 60000).toString());
101
+ }
102
+ return null;
103
+ }
104
+ reset(filePath) {
105
+ if (filePath) {
106
+ this.fileEditCounts.delete(filePath);
107
+ }
108
+ else {
109
+ this.fileEditCounts.clear();
110
+ }
111
+ this.saveState();
112
+ }
113
+ getStats() {
114
+ const stats = {};
115
+ this.fileEditCounts.forEach((edits, file) => {
116
+ stats[file] = edits.length;
117
+ });
118
+ return stats;
119
+ }
120
+ getConfig() {
121
+ return { ...this.config };
122
+ }
123
+ }
124
+ exports.LoopDetector = LoopDetector;
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9vcC1kZXRlY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL21pZGRsZXdhcmUvbG9vcC1kZXRlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsNENBQTRDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFNUMsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQVE3QixNQUFhLFlBQVk7SUFNYjtJQUxGLGNBQWMsR0FBMEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUNsRCxhQUFhLENBQVM7SUFDdEIsTUFBTSxDQUErQjtJQUU3QyxZQUNVLGFBQXFCLEVBQzdCLFNBQTZCLEVBQUU7UUFEdkIsa0JBQWEsR0FBYixhQUFhLENBQVE7UUFHN0IsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLEtBQUssRUFBRSxDQUFDO1lBQ1IsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPO1lBQ3pCLGNBQWMsRUFBRSw0Q0FBNEM7Z0JBQzVDLFFBQVE7Z0JBQ1IsZUFBZTtnQkFDZixtQkFBbUI7Z0JBQ25CLGFBQWE7WUFDN0IsR0FBRyxNQUFNO1NBQ1YsQ0FBQztRQUVGLFVBQVU7UUFDVixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzVCLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDN0MsQ0FBQztRQUNELElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsMEJBQTBCLENBQUMsQ0FBQztRQUVwRSxVQUFVO1FBQ1YsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQ25CLENBQUM7SUFFTyxTQUFTO1FBQ2YsSUFBSSxDQUFDO1lB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LENBQUM7SUFFRCxTQUFTO1FBQ1AsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzVCLENBQUM7Q0FDRjtBQTlGRCxvQ0E4RkMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBzcmMvbWlkZGxld2FyZS9sb29wLWRldGVjdG9yLnRzIC0g5b6q546v5qOA5rWL5Lit6Ze05Lu2XG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9vcERldGVjdG9yQ29uZmlnIHtcbiAgbGltaXQ/OiBudW1iZXI7ICAgICAgICAgICAvLyDnvJbovpHmrKHmlbDpmIjlgLxcbiAgd2luZG93TXM/OiBudW1iZXI7ICAgICAgICAvLyDml7bpl7Tnqpflj6PvvIjmr6vnp5LvvIlcbiAgd2FybmluZ01lc3NhZ2U/OiBzdHJpbmc7ICAvLyDorablkYrmtojmga/mqKHmnb9cbn1cblxuZXhwb3J0IGNsYXNzIExvb3BEZXRlY3RvciB7XG4gIHByaXZhdGUgZmlsZUVkaXRDb3VudHM6IE1hcDxzdHJpbmcsIG51bWJlcltdPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBzdGF0ZUZpbGVQYXRoOiBzdHJpbmc7XG4gIHByaXZhdGUgY29uZmlnOiBSZXF1aXJlZDxMb29wRGV0ZWN0b3JDb25maWc+O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgd29ya3NwYWNlUGF0aDogc3RyaW5nLFxuICAgIGNvbmZpZzogTG9vcERldGVjdG9yQ29uZmlnID0ge31cbiAgKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICBsaW1pdDogNSxcbiAgICAgIHdpbmRvd01zOiAzMDAwMDAsIC8vIDUg5YiG6ZKfXG4gICAgICB3YXJuaW5nTWVzc2FnZTogYOKaoO+4jyDorablkYrvvJp7ZmlsZX0g5bey6KKr5L+u5pS5IHtjb3VudH0g5qyh77yIe3dpbmRvd33liIbpkp/lhoXvvIlcXG5gICtcbiAgICAgICAgICAgICAgICAgICAgICAn6K+36ICD6JmR77yaXFxuJyArXG4gICAgICAgICAgICAgICAgICAgICAgJzEuIOmHjeaWsOmYheivu+S7u+WKoeinhOagvFxcbicgK1xuICAgICAgICAgICAgICAgICAgICAgICcyLiDmo4Dmn6XmmK/lkKbmnInmoLnmnKzmgKforr7orqHpl67pophcXG4nICtcbiAgICAgICAgICAgICAgICAgICAgICAnMy4g6ICD6JmR5a+75rGC5Lq657G75biu5YqpJyxcbiAgICAgIC4uLmNvbmZpZyxcbiAgICB9O1xuXG4gICAgLy8g54q25oCB5oyB5LmF5YyW5paH5Lu2XG4gICAgY29uc3QgbG9nc0RpciA9IHBhdGguam9pbih3b3Jrc3BhY2VQYXRoLCAnbG9ncycpO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhsb2dzRGlyKSkge1xuICAgICAgZnMubWtkaXJTeW5jKGxvZ3NEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cbiAgICB0aGlzLnN0YXRlRmlsZVBhdGggPSBwYXRoLmpvaW4obG9nc0RpciwgJ2xvb3AtZGV0ZWN0b3Itc3RhdGUuanNvbicpO1xuICAgIFxuICAgIC8vIOWKoOi9veS5i+WJjeeahOeKtuaAgVxuICAgIHRoaXMubG9hZFN0YXRlKCk7XG4gIH1cblxuICBwcml2YXRlIGxvYWRTdGF0ZSgpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgaWYgKGZzLmV4aXN0c1N5bmModGhpcy5zdGF0ZUZpbGVQYXRoKSkge1xuICAgICAgICBjb25zdCBkYXRhID0gZnMucmVhZEZpbGVTeW5jKHRoaXMuc3RhdGVGaWxlUGF0aCwgJ3V0ZjgnKTtcbiAgICAgICAgY29uc3Qgc3RhdGUgPSBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICB0aGlzLmZpbGVFZGl0Q291bnRzID0gbmV3IE1hcChPYmplY3QuZW50cmllcyhzdGF0ZSkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyDlv73nlaXliqDovb3plJnor6/vvIzku47nqbrnirbmgIHlvIDlp4tcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNhdmVTdGF0ZSgpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBPYmplY3QuZnJvbUVudHJpZXModGhpcy5maWxlRWRpdENvdW50cyk7XG4gICAgICBmcy53cml0ZUZpbGVTeW5jKHRoaXMuc3RhdGVGaWxlUGF0aCwgSlNPTi5zdHJpbmdpZnkoc3RhdGUsIG51bGwsIDIpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8g5b+955Wl5L+d5a2Y6ZSZ6K+vXG4gICAgfVxuICB9XG5cbiAgb25GaWxlRWRpdChmaWxlUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCBlZGl0cyA9IHRoaXMuZmlsZUVkaXRDb3VudHMuZ2V0KGZpbGVQYXRoKSB8fCBbXTtcbiAgICBcbiAgICAvLyDnp7vpmaTotoXlh7rml7bpl7Tnqpflj6PnmoTorrDlvZVcbiAgICBjb25zdCB3aW5kb3dTdGFydCA9IG5vdyAtIHRoaXMuY29uZmlnLndpbmRvd01zO1xuICAgIGNvbnN0IHJlY2VudEVkaXRzID0gZWRpdHMuZmlsdGVyKHRpbWUgPT4gdGltZSA+IHdpbmRvd1N0YXJ0KTtcbiAgICBcbiAgICByZWNlbnRFZGl0cy5wdXNoKG5vdyk7XG4gICAgdGhpcy5maWxlRWRpdENvdW50cy5zZXQoZmlsZVBhdGgsIHJlY2VudEVkaXRzKTtcbiAgICB0aGlzLnNhdmVTdGF0ZSgpO1xuXG4gICAgaWYgKHJlY2VudEVkaXRzLmxlbmd0aCA+PSB0aGlzLmNvbmZpZy5saW1pdCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29uZmlnLndhcm5pbmdNZXNzYWdlXG4gICAgICAgIC5yZXBsYWNlKCd7ZmlsZX0nLCBmaWxlUGF0aClcbiAgICAgICAgLnJlcGxhY2UoJ3tjb3VudH0nLCByZWNlbnRFZGl0cy5sZW5ndGgudG9TdHJpbmcoKSlcbiAgICAgICAgLnJlcGxhY2UoJ3t3aW5kb3d9JywgKHRoaXMuY29uZmlnLndpbmRvd01zIC8gNjAwMDApLnRvU3RyaW5nKCkpO1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmVzZXQoZmlsZVBhdGg/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoZmlsZVBhdGgpIHtcbiAgICAgIHRoaXMuZmlsZUVkaXRDb3VudHMuZGVsZXRlKGZpbGVQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5maWxlRWRpdENvdW50cy5jbGVhcigpO1xuICAgIH1cbiAgICB0aGlzLnNhdmVTdGF0ZSgpO1xuICB9XG5cbiAgZ2V0U3RhdHMoKTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB7XG4gICAgY29uc3Qgc3RhdHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgICB0aGlzLmZpbGVFZGl0Q291bnRzLmZvckVhY2goKGVkaXRzLCBmaWxlKSA9PiB7XG4gICAgICBzdGF0c1tmaWxlXSA9IGVkaXRzLmxlbmd0aDtcbiAgICB9KTtcbiAgICByZXR1cm4gc3RhdHM7XG4gIH1cblxuICBnZXRDb25maWcoKTogUmVxdWlyZWQ8TG9vcERldGVjdG9yQ29uZmlnPiB7XG4gICAgcmV0dXJuIHsgLi4udGhpcy5jb25maWcgfTtcbiAgfVxufVxuIl19
@@ -0,0 +1,34 @@
1
+ export interface TraceEntry {
2
+ timestamp: string;
3
+ sessionId: string;
4
+ type: 'tool_call' | 'user_request' | 'agent_response' | 'error' | 'config_change';
5
+ data: Record<string, any>;
6
+ metadata?: {
7
+ tokenUsage?: {
8
+ in: number;
9
+ out: number;
10
+ };
11
+ durationMs?: number;
12
+ model?: string;
13
+ modifier?: string;
14
+ };
15
+ }
16
+ export declare class TraceLogger {
17
+ private workspacePath;
18
+ private logFilePath;
19
+ constructor(workspacePath: string);
20
+ log(entry: Omit<TraceEntry, 'timestamp'>): void;
21
+ logToolCall(sessionId: string, tool: string, params: any, result: any, metadata?: TraceEntry['metadata']): void;
22
+ logUserRequest(sessionId: string, request: string): void;
23
+ logAgentResponse(sessionId: string, response: string, metadata?: TraceEntry['metadata']): void;
24
+ logError(sessionId: string, error: Error, context?: any): void;
25
+ logConfigChange(sessionId: string, file: string, changes: Array<{
26
+ field: string;
27
+ oldValue: any;
28
+ newValue: any;
29
+ }>, reason: string, modifier?: string): void;
30
+ getSessionTraces(sessionId: string): TraceEntry[];
31
+ getRecentTraces(limit?: number): TraceEntry[];
32
+ getTracesByType(type: TraceEntry['type'], limit?: number): TraceEntry[];
33
+ exportToJson(outputPath: string): void;
34
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ // src/middleware/trace-logger.ts - Trace 记录器
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.TraceLogger = void 0;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ class TraceLogger {
41
+ workspacePath;
42
+ logFilePath;
43
+ constructor(workspacePath) {
44
+ this.workspacePath = workspacePath;
45
+ const logsDir = path.join(workspacePath, 'logs');
46
+ if (!fs.existsSync(logsDir)) {
47
+ fs.mkdirSync(logsDir, { recursive: true });
48
+ }
49
+ this.logFilePath = path.join(logsDir, 'traces.jsonl');
50
+ }
51
+ log(entry) {
52
+ const fullEntry = {
53
+ ...entry,
54
+ timestamp: new Date().toISOString(),
55
+ };
56
+ fs.appendFileSync(this.logFilePath, JSON.stringify(fullEntry) + '\n');
57
+ }
58
+ logToolCall(sessionId, tool, params, result, metadata) {
59
+ this.log({
60
+ sessionId,
61
+ type: 'tool_call',
62
+ data: { tool, params, result },
63
+ metadata,
64
+ });
65
+ }
66
+ logUserRequest(sessionId, request) {
67
+ this.log({
68
+ sessionId,
69
+ type: 'user_request',
70
+ data: { request },
71
+ });
72
+ }
73
+ logAgentResponse(sessionId, response, metadata) {
74
+ this.log({
75
+ sessionId,
76
+ type: 'agent_response',
77
+ data: { response },
78
+ metadata,
79
+ });
80
+ }
81
+ logError(sessionId, error, context) {
82
+ this.log({
83
+ sessionId,
84
+ type: 'error',
85
+ data: { error: error.message, stack: error.stack, context },
86
+ });
87
+ }
88
+ logConfigChange(sessionId, file, changes, reason, modifier) {
89
+ this.log({
90
+ sessionId,
91
+ type: 'config_change',
92
+ data: { file, changes, reason },
93
+ metadata: { modifier },
94
+ });
95
+ }
96
+ getSessionTraces(sessionId) {
97
+ if (!fs.existsSync(this.logFilePath))
98
+ return [];
99
+ const content = fs.readFileSync(this.logFilePath, 'utf8');
100
+ return content
101
+ .split('\n')
102
+ .filter(line => line.trim())
103
+ .map(line => JSON.parse(line))
104
+ .filter(entry => entry.sessionId === sessionId);
105
+ }
106
+ getRecentTraces(limit = 100) {
107
+ if (!fs.existsSync(this.logFilePath))
108
+ return [];
109
+ const content = fs.readFileSync(this.logFilePath, 'utf8');
110
+ return content
111
+ .split('\n')
112
+ .filter(line => line.trim())
113
+ .map(line => JSON.parse(line))
114
+ .slice(-limit);
115
+ }
116
+ getTracesByType(type, limit = 50) {
117
+ if (!fs.existsSync(this.logFilePath))
118
+ return [];
119
+ const content = fs.readFileSync(this.logFilePath, 'utf8');
120
+ return content
121
+ .split('\n')
122
+ .filter(line => line.trim())
123
+ .map(line => JSON.parse(line))
124
+ .filter(entry => entry.type === type)
125
+ .slice(-limit);
126
+ }
127
+ exportToJson(outputPath) {
128
+ if (!fs.existsSync(this.logFilePath)) {
129
+ fs.writeFileSync(outputPath, '[]');
130
+ return;
131
+ }
132
+ const content = fs.readFileSync(this.logFilePath, 'utf8');
133
+ const traces = content
134
+ .split('\n')
135
+ .filter(line => line.trim())
136
+ .map(line => JSON.parse(line));
137
+ fs.writeFileSync(outputPath, JSON.stringify(traces, null, 2));
138
+ }
139
+ }
140
+ exports.TraceLogger = TraceLogger;
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UtbG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvcmUvbWlkZGxld2FyZS90cmFjZS1sb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDZDQUE2Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRTdDLHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFlN0IsTUFBYSxXQUFXO0lBR0Y7SUFGWixXQUFXLENBQVM7SUFFNUIsWUFBb0IsYUFBcUI7UUFBckIsa0JBQWEsR0FBYixhQUFhLENBQVE7UUFDdkMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM1QixFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRCxHQUFHLENBQUMsS0FBb0M7UUFDdEMsTUFBTSxTQUFTLEdBQWU7WUFDNUIsR0FBRyxLQUFLO1lBQ1IsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO1NBQ3BDLENBQUM7UUFDRixFQUFFLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQsV0FBVyxDQUNULFNBQWlCLEVBQ2pCLElBQVksRUFDWixNQUFXLEVBQ1gsTUFBVyxFQUNYLFFBQWlDO1FBRWpDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDUCxTQUFTO1lBQ1Qs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a0NBOEhDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gc3JjL21pZGRsZXdhcmUvdHJhY2UtbG9nZ2VyLnRzIC0gVHJhY2Ug6K6w5b2V5ZmoXG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhY2VFbnRyeSB7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuICBzZXNzaW9uSWQ6IHN0cmluZztcbiAgdHlwZTogJ3Rvb2xfY2FsbCcgfCAndXNlcl9yZXF1ZXN0JyB8ICdhZ2VudF9yZXNwb25zZScgfCAnZXJyb3InIHwgJ2NvbmZpZ19jaGFuZ2UnO1xuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICBtZXRhZGF0YT86IHtcbiAgICB0b2tlblVzYWdlPzogeyBpbjogbnVtYmVyOyBvdXQ6IG51bWJlciB9O1xuICAgIGR1cmF0aW9uTXM/OiBudW1iZXI7XG4gICAgbW9kZWw/OiBzdHJpbmc7XG4gICAgbW9kaWZpZXI/OiBzdHJpbmc7XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBUcmFjZUxvZ2dlciB7XG4gIHByaXZhdGUgbG9nRmlsZVBhdGg6IHN0cmluZztcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdvcmtzcGFjZVBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IGxvZ3NEaXIgPSBwYXRoLmpvaW4od29ya3NwYWNlUGF0aCwgJ2xvZ3MnKTtcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMobG9nc0RpcikpIHtcbiAgICAgIGZzLm1rZGlyU3luYyhsb2dzRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG4gICAgdGhpcy5sb2dGaWxlUGF0aCA9IHBhdGguam9pbihsb2dzRGlyLCAndHJhY2VzLmpzb25sJyk7XG4gIH1cblxuICBsb2coZW50cnk6IE9taXQ8VHJhY2VFbnRyeSwgJ3RpbWVzdGFtcCc+KTogdm9pZCB7XG4gICAgY29uc3QgZnVsbEVudHJ5OiBUcmFjZUVudHJ5ID0ge1xuICAgICAgLi4uZW50cnksXG4gICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICB9O1xuICAgIGZzLmFwcGVuZEZpbGVTeW5jKHRoaXMubG9nRmlsZVBhdGgsIEpTT04uc3RyaW5naWZ5KGZ1bGxFbnRyeSkgKyAnXFxuJyk7XG4gIH1cblxuICBsb2dUb29sQ2FsbChcbiAgICBzZXNzaW9uSWQ6IHN0cmluZyxcbiAgICB0b29sOiBzdHJpbmcsXG4gICAgcGFyYW1zOiBhbnksXG4gICAgcmVzdWx0OiBhbnksXG4gICAgbWV0YWRhdGE/OiBUcmFjZUVudHJ5WydtZXRhZGF0YSddXG4gICk6IHZvaWQge1xuICAgIHRoaXMubG9nKHtcbiAgICAgIHNlc3Npb25JZCxcbiAgICAgIHR5cGU6ICd0b29sX2NhbGwnLFxuICAgICAgZGF0YTogeyB0b29sLCBwYXJhbXMsIHJlc3VsdCB9LFxuICAgICAgbWV0YWRhdGEsXG4gICAgfSk7XG4gIH1cblxuICBsb2dVc2VyUmVxdWVzdChzZXNzaW9uSWQ6IHN0cmluZywgcmVxdWVzdDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5sb2coe1xuICAgICAgc2Vzc2lvbklkLFxuICAgICAgdHlwZTogJ3VzZXJfcmVxdWVzdCcsXG4gICAgICBkYXRhOiB7IHJlcXVlc3QgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGxvZ0FnZW50UmVzcG9uc2UoXG4gICAgc2Vzc2lvbklkOiBzdHJpbmcsXG4gICAgcmVzcG9uc2U6IHN0cmluZyxcbiAgICBtZXRhZGF0YT86IFRyYWNlRW50cnlbJ21ldGFkYXRhJ11cbiAgKTogdm9pZCB7XG4gICAgdGhpcy5sb2coe1xuICAgICAgc2Vzc2lvbklkLFxuICAgICAgdHlwZTogJ2FnZW50X3Jlc3BvbnNlJyxcbiAgICAgIGRhdGE6IHsgcmVzcG9uc2UgfSxcbiAgICAgIG1ldGFkYXRhLFxuICAgIH0pO1xuICB9XG5cbiAgbG9nRXJyb3Ioc2Vzc2lvbklkOiBzdHJpbmcsIGVycm9yOiBFcnJvciwgY29udGV4dD86IGFueSk6IHZvaWQge1xuICAgIHRoaXMubG9nKHtcbiAgICAgIHNlc3Npb25JZCxcbiAgICAgIHR5cGU6ICdlcnJvcicsXG4gICAgICBkYXRhOiB7IGVycm9yOiBlcnJvci5tZXNzYWdlLCBzdGFjazogZXJyb3Iuc3RhY2ssIGNvbnRleHQgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGxvZ0NvbmZpZ0NoYW5nZShcbiAgICBzZXNzaW9uSWQ6IHN0cmluZyxcbiAgICBmaWxlOiBzdHJpbmcsXG4gICAgY2hhbmdlczogQXJyYXk8eyBmaWVsZDogc3RyaW5nOyBvbGRWYWx1ZTogYW55OyBuZXdWYWx1ZTogYW55IH0+LFxuICAgIHJlYXNvbjogc3RyaW5nLFxuICAgIG1vZGlmaWVyPzogc3RyaW5nXG4gICk6IHZvaWQge1xuICAgIHRoaXMubG9nKHtcbiAgICAgIHNlc3Npb25JZCxcbiAgICAgIHR5cGU6ICdjb25maWdfY2hhbmdlJyxcbiAgICAgIGRhdGE6IHsgZmlsZSwgY2hhbmdlcywgcmVhc29uIH0sXG4gICAgICBtZXRhZGF0YTogeyBtb2RpZmllciB9LFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0U2Vzc2lvblRyYWNlcyhzZXNzaW9uSWQ6IHN0cmluZyk6IFRyYWNlRW50cnlbXSB7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRoaXMubG9nRmlsZVBhdGgpKSByZXR1cm4gW107XG4gICAgXG4gICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmxvZ0ZpbGVQYXRoLCAndXRmOCcpO1xuICAgIHJldHVybiBjb250ZW50XG4gICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAuZmlsdGVyKGxpbmUgPT4gbGluZS50cmltKCkpXG4gICAgICAubWFwKGxpbmUgPT4gSlNPTi5wYXJzZShsaW5lKSlcbiAgICAgIC5maWx0ZXIoZW50cnkgPT4gZW50cnkuc2Vzc2lvbklkID09PSBzZXNzaW9uSWQpO1xuICB9XG5cbiAgZ2V0UmVjZW50VHJhY2VzKGxpbWl0OiBudW1iZXIgPSAxMDApOiBUcmFjZUVudHJ5W10ge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmxvZ0ZpbGVQYXRoKSkgcmV0dXJuIFtdO1xuICAgIFxuICAgIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmModGhpcy5sb2dGaWxlUGF0aCwgJ3V0ZjgnKTtcbiAgICByZXR1cm4gY29udGVudFxuICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgLmZpbHRlcihsaW5lID0+IGxpbmUudHJpbSgpKVxuICAgICAgLm1hcChsaW5lID0+IEpTT04ucGFyc2UobGluZSkpXG4gICAgICAuc2xpY2UoLWxpbWl0KTtcbiAgfVxuXG4gIGdldFRyYWNlc0J5VHlwZSh0eXBlOiBUcmFjZUVudHJ5Wyd0eXBlJ10sIGxpbWl0OiBudW1iZXIgPSA1MCk6IFRyYWNlRW50cnlbXSB7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRoaXMubG9nRmlsZVBhdGgpKSByZXR1cm4gW107XG4gICAgXG4gICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmxvZ0ZpbGVQYXRoLCAndXRmOCcpO1xuICAgIHJldHVybiBjb250ZW50XG4gICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAuZmlsdGVyKGxpbmUgPT4gbGluZS50cmltKCkpXG4gICAgICAubWFwKGxpbmUgPT4gSlNPTi5wYXJzZShsaW5lKSlcbiAgICAgIC5maWx0ZXIoZW50cnkgPT4gZW50cnkudHlwZSA9PT0gdHlwZSlcbiAgICAgIC5zbGljZSgtbGltaXQpO1xuICB9XG5cbiAgZXhwb3J0VG9Kc29uKG91dHB1dFBhdGg6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmxvZ0ZpbGVQYXRoKSkge1xuICAgICAgZnMud3JpdGVGaWxlU3luYyhvdXRwdXRQYXRoLCAnW10nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmxvZ0ZpbGVQYXRoLCAndXRmOCcpO1xuICAgIGNvbnN0IHRyYWNlcyA9IGNvbnRlbnRcbiAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgIC5maWx0ZXIobGluZSA9PiBsaW5lLnRyaW0oKSlcbiAgICAgIC5tYXAobGluZSA9PiBKU09OLnBhcnNlKGxpbmUpKTtcbiAgICBcbiAgICBmcy53cml0ZUZpbGVTeW5jKG91dHB1dFBhdGgsIEpTT04uc3RyaW5naWZ5KHRyYWNlcywgbnVsbCwgMikpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 确保目录存在
3
+ */
4
+ export declare function ensureDir(dirPath: string): void;
5
+ /**
6
+ * 读取文件
7
+ */
8
+ export declare function readFile(filePath: string, encoding?: BufferEncoding): string;
9
+ /**
10
+ * 写入文件
11
+ */
12
+ export declare function writeFile(filePath: string, content: string, encoding?: BufferEncoding): void;
13
+ /**
14
+ * 检查文件是否存在
15
+ */
16
+ export declare function fileExists(filePath: string): boolean;
17
+ /**
18
+ * 追加内容到文件
19
+ */
20
+ export declare function appendToFile(filePath: string, content: string, encoding?: BufferEncoding): void;
21
+ /**
22
+ * 安全删除文件(移动到回收站)
23
+ */
24
+ export declare function safeDelete(filePath: string): boolean;
25
+ /**
26
+ * 备份文件
27
+ */
28
+ export declare function backupFile(filePath: string, backupPath?: string): string;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ // src/utils/file.ts - 文件工具
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.ensureDir = ensureDir;
38
+ exports.readFile = readFile;
39
+ exports.writeFile = writeFile;
40
+ exports.fileExists = fileExists;
41
+ exports.appendToFile = appendToFile;
42
+ exports.safeDelete = safeDelete;
43
+ exports.backupFile = backupFile;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ /**
47
+ * 确保目录存在
48
+ */
49
+ function ensureDir(dirPath) {
50
+ if (!fs.existsSync(dirPath)) {
51
+ fs.mkdirSync(dirPath, { recursive: true });
52
+ }
53
+ }
54
+ /**
55
+ * 读取文件
56
+ */
57
+ function readFile(filePath, encoding = 'utf8') {
58
+ return fs.readFileSync(filePath, encoding);
59
+ }
60
+ /**
61
+ * 写入文件
62
+ */
63
+ function writeFile(filePath, content, encoding = 'utf8') {
64
+ const dir = path.dirname(filePath);
65
+ ensureDir(dir);
66
+ fs.writeFileSync(filePath, content, encoding);
67
+ }
68
+ /**
69
+ * 检查文件是否存在
70
+ */
71
+ function fileExists(filePath) {
72
+ return fs.existsSync(filePath);
73
+ }
74
+ /**
75
+ * 追加内容到文件
76
+ */
77
+ function appendToFile(filePath, content, encoding = 'utf8') {
78
+ const dir = path.dirname(filePath);
79
+ ensureDir(dir);
80
+ fs.appendFileSync(filePath, content, encoding);
81
+ }
82
+ /**
83
+ * 安全删除文件(移动到回收站)
84
+ */
85
+ function safeDelete(filePath) {
86
+ try {
87
+ // 简单实现:重命名为 .deleted 后缀
88
+ const deletedPath = filePath + '.deleted';
89
+ fs.renameSync(filePath, deletedPath);
90
+ return true;
91
+ }
92
+ catch (error) {
93
+ return false;
94
+ }
95
+ }
96
+ /**
97
+ * 备份文件
98
+ */
99
+ function backupFile(filePath, backupPath) {
100
+ const dest = backupPath || `${filePath}.bak.${Date.now()}`;
101
+ fs.copyFileSync(filePath, dest);
102
+ return dest;
103
+ }
104
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3V0aWxzL2ZpbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDJCQUEyQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFRM0IsOEJBSUM7QUFLRCw0QkFFQztBQUtELDhCQUlDO0FBS0QsZ0NBRUM7QUFLRCxvQ0FJQztBQUtELGdDQVNDO0FBS0QsZ0NBSUM7QUFqRUQsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUU3Qjs7R0FFRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxPQUFlO0lBQ3ZDLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDNUIsRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM3QyxDQUFDO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsUUFBUSxDQUFDLFFBQWdCLEVBQUUsV0FBMkIsTUFBTTtJQUMxRSxPQUFPLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxRQUFnQixFQUFFLE9BQWUsRUFBRSxXQUEyQixNQUFNO0lBQzVGLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbkMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsRUFBRSxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBQ2hELENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLFVBQVUsQ0FBQyxRQUFnQjtJQUN6QyxPQUFPLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsWUFBWSxDQUFDLFFBQWdCLEVBQUUsT0FBZSxFQUFFLFdBQTJCLE1BQU07SUFDL0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNuQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDZixFQUFFLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFDakQsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLFFBQWdCO0lBQ3pDLElBQUksQ0FBQztRQUNILHdCQUF3QjtRQUN4QixNQUFNLFdBQVcsR0FBRyxRQUFRLEdBQUcsVUFBVSxDQUFDO1FBQzFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3JDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixVQUFVLENBQUMsUUFBZ0IsRUFBRSxVQUFtQjtJQUM5RCxNQUFNLElBQUksR0FBRyxVQUFVLElBQUksR0FBRyxRQUFRLFFBQVEsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7SUFDM0QsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDaEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gc3JjL3V0aWxzL2ZpbGUudHMgLSDmlofku7blt6XlhbdcblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuLyoqXG4gKiDnoa7kv53nm67lvZXlrZjlnKhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuc3VyZURpcihkaXJQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKCFmcy5leGlzdHNTeW5jKGRpclBhdGgpKSB7XG4gICAgZnMubWtkaXJTeW5jKGRpclBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICB9XG59XG5cbi8qKlxuICog6K+75Y+W5paH5Lu2XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkRmlsZShmaWxlUGF0aDogc3RyaW5nLCBlbmNvZGluZzogQnVmZmVyRW5jb2RpbmcgPSAndXRmOCcpOiBzdHJpbmcge1xuICByZXR1cm4gZnMucmVhZEZpbGVTeW5jKGZpbGVQYXRoLCBlbmNvZGluZyk7XG59XG5cbi8qKlxuICog5YaZ5YWl5paH5Lu2XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3cml0ZUZpbGUoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nLCBlbmNvZGluZzogQnVmZmVyRW5jb2RpbmcgPSAndXRmOCcpOiB2b2lkIHtcbiAgY29uc3QgZGlyID0gcGF0aC5kaXJuYW1lKGZpbGVQYXRoKTtcbiAgZW5zdXJlRGlyKGRpcik7XG4gIGZzLndyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIGNvbnRlbnQsIGVuY29kaW5nKTtcbn1cblxuLyoqXG4gKiDmo4Dmn6Xmlofku7bmmK/lkKblrZjlnKhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbGVFeGlzdHMoZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gZnMuZXhpc3RzU3luYyhmaWxlUGF0aCk7XG59XG5cbi8qKlxuICog6L+95Yqg5YaF5a655Yiw5paH5Lu2XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBlbmRUb0ZpbGUoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nLCBlbmNvZGluZzogQnVmZmVyRW5jb2RpbmcgPSAndXRmOCcpOiB2b2lkIHtcbiAgY29uc3QgZGlyID0gcGF0aC5kaXJuYW1lKGZpbGVQYXRoKTtcbiAgZW5zdXJlRGlyKGRpcik7XG4gIGZzLmFwcGVuZEZpbGVTeW5jKGZpbGVQYXRoLCBjb250ZW50LCBlbmNvZGluZyk7XG59XG5cbi8qKlxuICog5a6J5YWo5Yig6Zmk5paH5Lu277yI56e75Yqo5Yiw5Zue5pS256uZ77yJXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYWZlRGVsZXRlKGZpbGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgdHJ5IHtcbiAgICAvLyDnroDljZXlrp7njrDvvJrph43lkb3lkI3kuLogLmRlbGV0ZWQg5ZCO57yAXG4gICAgY29uc3QgZGVsZXRlZFBhdGggPSBmaWxlUGF0aCArICcuZGVsZXRlZCc7XG4gICAgZnMucmVuYW1lU3luYyhmaWxlUGF0aCwgZGVsZXRlZFBhdGgpO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIOWkh+S7veaWh+S7tlxuICovXG5leHBvcnQgZnVuY3Rpb24gYmFja3VwRmlsZShmaWxlUGF0aDogc3RyaW5nLCBiYWNrdXBQYXRoPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgZGVzdCA9IGJhY2t1cFBhdGggfHwgYCR7ZmlsZVBhdGh9LmJhay4ke0RhdGUubm93KCl9YDtcbiAgZnMuY29weUZpbGVTeW5jKGZpbGVQYXRoLCBkZXN0KTtcbiAgcmV0dXJuIGRlc3Q7XG59XG4iXX0=
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 格式化文件大小
3
+ */
4
+ export declare function formatFileSize(bytes: number): string;
5
+ /**
6
+ * 格式化日期
7
+ */
8
+ export declare function formatDate(date: Date | string, format?: string): string;
9
+ /**
10
+ * 截断字符串
11
+ */
12
+ export declare function truncate(str: string, maxLength: number, suffix?: string): string;
13
+ /**
14
+ * 格式化持续时间
15
+ */
16
+ export declare function formatDuration(ms: number): string;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ // src/utils/format.ts - 格式化工具
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.formatFileSize = formatFileSize;
5
+ exports.formatDate = formatDate;
6
+ exports.truncate = truncate;
7
+ exports.formatDuration = formatDuration;
8
+ /**
9
+ * 格式化文件大小
10
+ */
11
+ function formatFileSize(bytes) {
12
+ const units = ['B', 'KB', 'MB', 'GB'];
13
+ let unitIndex = 0;
14
+ let size = bytes;
15
+ while (size >= 1024 && unitIndex < units.length - 1) {
16
+ size /= 1024;
17
+ unitIndex++;
18
+ }
19
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
20
+ }
21
+ /**
22
+ * 格式化日期
23
+ */
24
+ function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
25
+ const d = typeof date === 'string' ? new Date(date) : date;
26
+ const year = d.getFullYear();
27
+ const month = String(d.getMonth() + 1).padStart(2, '0');
28
+ const day = String(d.getDate()).padStart(2, '0');
29
+ const hours = String(d.getHours()).padStart(2, '0');
30
+ const minutes = String(d.getMinutes()).padStart(2, '0');
31
+ const seconds = String(d.getSeconds()).padStart(2, '0');
32
+ return format
33
+ .replace('YYYY', String(year))
34
+ .replace('MM', month)
35
+ .replace('DD', day)
36
+ .replace('HH', hours)
37
+ .replace('mm', minutes)
38
+ .replace('ss', seconds);
39
+ }
40
+ /**
41
+ * 截断字符串
42
+ */
43
+ function truncate(str, maxLength, suffix = '...') {
44
+ if (str.length <= maxLength)
45
+ return str;
46
+ return str.substring(0, maxLength - suffix.length) + suffix;
47
+ }
48
+ /**
49
+ * 格式化持续时间
50
+ */
51
+ function formatDuration(ms) {
52
+ if (ms < 1000)
53
+ return `${ms}ms`;
54
+ if (ms < 60000)
55
+ return `${(ms / 1000).toFixed(1)}s`;
56
+ const minutes = Math.floor(ms / 60000);
57
+ const seconds = Math.floor((ms % 60000) / 1000);
58
+ return `${minutes}m ${seconds}s`;
59
+ }
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvcmUvdXRpbHMvZm9ybWF0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSw4QkFBOEI7O0FBSzlCLHdDQVdDO0FBS0QsZ0NBaUJDO0FBS0QsNEJBR0M7QUFLRCx3Q0FPQztBQXhERDs7R0FFRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxLQUFhO0lBQzFDLE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdEMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLElBQUksSUFBSSxHQUFHLEtBQUssQ0FBQztJQUVqQixPQUFPLElBQUksSUFBSSxJQUFJLElBQUksU0FBUyxHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDcEQsSUFBSSxJQUFJLElBQUksQ0FBQztRQUNiLFNBQVMsRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO0FBQ2xELENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLFVBQVUsQ0FBQyxJQUFtQixFQUFFLFNBQWlCLHFCQUFxQjtJQUNwRixNQUFNLENBQUMsR0FBRyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFFM0QsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzdCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN4RCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNqRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNwRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN4RCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUV4RCxPQUFPLE1BQU07U0FDVixPQUFPLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUM3QixPQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQztTQUNwQixPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQztTQUNsQixPQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQztTQUNwQixPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQztTQUN0QixPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQzVCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLFFBQVEsQ0FBQyxHQUFXLEVBQUUsU0FBaUIsRUFBRSxTQUFpQixLQUFLO0lBQzdFLElBQUksR0FBRyxDQUFDLE1BQU0sSUFBSSxTQUFTO1FBQUUsT0FBTyxHQUFHLENBQUM7SUFDeEMsT0FBTyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQztBQUM5RCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixjQUFjLENBQUMsRUFBVTtJQUN2QyxJQUFJLEVBQUUsR0FBRyxJQUFJO1FBQUUsT0FBTyxHQUFHLEVBQUUsSUFBSSxDQUFDO0lBQ2hDLElBQUksRUFBRSxHQUFHLEtBQUs7UUFBRSxPQUFPLEdBQUcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFFcEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDdkMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUNoRCxPQUFPLEdBQUcsT0FBTyxLQUFLLE9BQU8sR0FBRyxDQUFDO0FBQ25DLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBzcmMvdXRpbHMvZm9ybWF0LnRzIC0g5qC85byP5YyW5bel5YW3XG5cbi8qKlxuICog5qC85byP5YyW5paH5Lu25aSn5bCPXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRGaWxlU2l6ZShieXRlczogbnVtYmVyKTogc3RyaW5nIHtcbiAgY29uc3QgdW5pdHMgPSBbJ0InLCAnS0InLCAnTUInLCAnR0InXTtcbiAgbGV0IHVuaXRJbmRleCA9IDA7XG4gIGxldCBzaXplID0gYnl0ZXM7XG5cbiAgd2hpbGUgKHNpemUgPj0gMTAyNCAmJiB1bml0SW5kZXggPCB1bml0cy5sZW5ndGggLSAxKSB7XG4gICAgc2l6ZSAvPSAxMDI0O1xuICAgIHVuaXRJbmRleCsrO1xuICB9XG5cbiAgcmV0dXJuIGAke3NpemUudG9GaXhlZCgyKX0gJHt1bml0c1t1bml0SW5kZXhdfWA7XG59XG5cbi8qKlxuICog5qC85byP5YyW5pel5pyfXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXREYXRlKGRhdGU6IERhdGUgfCBzdHJpbmcsIGZvcm1hdDogc3RyaW5nID0gJ1lZWVktTU0tREQgSEg6bW06c3MnKTogc3RyaW5nIHtcbiAgY29uc3QgZCA9IHR5cGVvZiBkYXRlID09PSAnc3RyaW5nJyA/IG5ldyBEYXRlKGRhdGUpIDogZGF0ZTtcbiAgXG4gIGNvbnN0IHllYXIgPSBkLmdldEZ1bGxZZWFyKCk7XG4gIGNvbnN0IG1vbnRoID0gU3RyaW5nKGQuZ2V0TW9udGgoKSArIDEpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIGNvbnN0IGRheSA9IFN0cmluZyhkLmdldERhdGUoKSkucGFkU3RhcnQoMiwgJzAnKTtcbiAgY29uc3QgaG91cnMgPSBTdHJpbmcoZC5nZXRIb3VycygpKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBtaW51dGVzID0gU3RyaW5nKGQuZ2V0TWludXRlcygpKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBzZWNvbmRzID0gU3RyaW5nKGQuZ2V0U2Vjb25kcygpKS5wYWRTdGFydCgyLCAnMCcpO1xuXG4gIHJldHVybiBmb3JtYXRcbiAgICAucmVwbGFjZSgnWVlZWScsIFN0cmluZyh5ZWFyKSlcbiAgICAucmVwbGFjZSgnTU0nLCBtb250aClcbiAgICAucmVwbGFjZSgnREQnLCBkYXkpXG4gICAgLnJlcGxhY2UoJ0hIJywgaG91cnMpXG4gICAgLnJlcGxhY2UoJ21tJywgbWludXRlcylcbiAgICAucmVwbGFjZSgnc3MnLCBzZWNvbmRzKTtcbn1cblxuLyoqXG4gKiDmiKrmlq3lrZfnrKbkuLJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRydW5jYXRlKHN0cjogc3RyaW5nLCBtYXhMZW5ndGg6IG51bWJlciwgc3VmZml4OiBzdHJpbmcgPSAnLi4uJyk6IHN0cmluZyB7XG4gIGlmIChzdHIubGVuZ3RoIDw9IG1heExlbmd0aCkgcmV0dXJuIHN0cjtcbiAgcmV0dXJuIHN0ci5zdWJzdHJpbmcoMCwgbWF4TGVuZ3RoIC0gc3VmZml4Lmxlbmd0aCkgKyBzdWZmaXg7XG59XG5cbi8qKlxuICog5qC85byP5YyW5oyB57ut5pe26Ze0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXREdXJhdGlvbihtczogbnVtYmVyKTogc3RyaW5nIHtcbiAgaWYgKG1zIDwgMTAwMCkgcmV0dXJuIGAke21zfW1zYDtcbiAgaWYgKG1zIDwgNjAwMDApIHJldHVybiBgJHsobXMgLyAxMDAwKS50b0ZpeGVkKDEpfXNgO1xuICBcbiAgY29uc3QgbWludXRlcyA9IE1hdGguZmxvb3IobXMgLyA2MDAwMCk7XG4gIGNvbnN0IHNlY29uZHMgPSBNYXRoLmZsb29yKChtcyAlIDYwMDAwKSAvIDEwMDApO1xuICByZXR1cm4gYCR7bWludXRlc31tICR7c2Vjb25kc31zYDtcbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export { formatFileSize, formatDate, truncate } from './format';
2
+ export { ensureDir, readFile, writeFile, fileExists } from './file';
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fileExists = exports.writeFile = exports.readFile = exports.ensureDir = exports.truncate = exports.formatDate = exports.formatFileSize = void 0;
4
+ // src/utils/index.ts
5
+ var format_1 = require("./format");
6
+ Object.defineProperty(exports, "formatFileSize", { enumerable: true, get: function () { return format_1.formatFileSize; } });
7
+ Object.defineProperty(exports, "formatDate", { enumerable: true, get: function () { return format_1.formatDate; } });
8
+ Object.defineProperty(exports, "truncate", { enumerable: true, get: function () { return format_1.truncate; } });
9
+ var file_1 = require("./file");
10
+ Object.defineProperty(exports, "ensureDir", { enumerable: true, get: function () { return file_1.ensureDir; } });
11
+ Object.defineProperty(exports, "readFile", { enumerable: true, get: function () { return file_1.readFile; } });
12
+ Object.defineProperty(exports, "writeFile", { enumerable: true, get: function () { return file_1.writeFile; } });
13
+ Object.defineProperty(exports, "fileExists", { enumerable: true, get: function () { return file_1.fileExists; } });
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29yZS91dGlscy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxQkFBcUI7QUFDckIsbUNBQWdFO0FBQXZELHdHQUFBLGNBQWMsT0FBQTtBQUFFLG9HQUFBLFVBQVUsT0FBQTtBQUFFLGtHQUFBLFFBQVEsT0FBQTtBQUM3QywrQkFBb0U7QUFBM0QsaUdBQUEsU0FBUyxPQUFBO0FBQUUsZ0dBQUEsUUFBUSxPQUFBO0FBQUUsaUdBQUEsU0FBUyxPQUFBO0FBQUUsa0dBQUEsVUFBVSxPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gc3JjL3V0aWxzL2luZGV4LnRzXG5leHBvcnQgeyBmb3JtYXRGaWxlU2l6ZSwgZm9ybWF0RGF0ZSwgdHJ1bmNhdGUgfSBmcm9tICcuL2Zvcm1hdCc7XG5leHBvcnQgeyBlbnN1cmVEaXIsIHJlYWRGaWxlLCB3cml0ZUZpbGUsIGZpbGVFeGlzdHMgfSBmcm9tICcuL2ZpbGUnO1xuIl19
@@ -0,0 +1,25 @@
1
+ export interface ValidationResult {
2
+ valid: boolean;
3
+ errors: string[];
4
+ warnings: string[];
5
+ info: string[];
6
+ }
7
+ export declare class ConfigValidator {
8
+ private workspacePath;
9
+ private configPath;
10
+ constructor(workspacePath: string);
11
+ /**
12
+ * 验证配置内容(用于包装层拦截)
13
+ */
14
+ validateContent(config: any): ValidationResult;
15
+ validate(configPath?: string): ValidationResult;
16
+ validateAndThrow(configPath?: string): void;
17
+ /**
18
+ * 比较两个配置的差异
19
+ */
20
+ diffConfigs(oldConfigPath: string, newConfigPath: string): Array<{
21
+ field: string;
22
+ oldValue: any;
23
+ newValue: any;
24
+ }>;
25
+ }