@hongmaple0820/scale-engine 0.6.0 → 0.7.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 +29 -6
- package/dist/adapters/ClaudeCodeAdapter.d.ts +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
- package/dist/adapters/QCoderAdapter.d.ts +13 -0
- package/dist/adapters/QCoderAdapter.js +153 -0
- package/dist/adapters/QCoderAdapter.js.map +1 -0
- package/dist/adapters/TraeAdapter.d.ts +13 -0
- package/dist/adapters/TraeAdapter.js +153 -0
- package/dist/adapters/TraeAdapter.js.map +1 -0
- package/dist/adapters/VSCAdapter.d.ts +13 -0
- package/dist/adapters/VSCAdapter.js +153 -0
- package/dist/adapters/VSCAdapter.js.map +1 -0
- package/dist/adapters/WorkBuddyAdapter.d.ts +13 -0
- package/dist/adapters/WorkBuddyAdapter.js +153 -0
- package/dist/adapters/WorkBuddyAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +13 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/api/cli.js +59 -3
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.js +29 -10
- package/dist/api/doctor.js.map +1 -1
- package/dist/artifact/types.d.ts +3 -3
- package/dist/artifact/types.js.map +1 -1
- package/dist/context/ContextBuilder.d.ts +4 -0
- package/dist/context/ContextBuilder.js +43 -9
- package/dist/context/ContextBuilder.js.map +1 -1
- package/dist/dashboard/DashboardServer.d.ts +63 -0
- package/dist/dashboard/DashboardServer.js +167 -0
- package/dist/dashboard/DashboardServer.js.map +1 -0
- package/dist/evolution/AutoDefectCreator.d.ts +34 -0
- package/dist/evolution/AutoDefectCreator.js +115 -0
- package/dist/evolution/AutoDefectCreator.js.map +1 -0
- package/dist/evolution/BehaviorTracker.d.ts +8 -0
- package/dist/evolution/BehaviorTracker.js +18 -1
- package/dist/evolution/BehaviorTracker.js.map +1 -1
- package/dist/evolution/EvolutionEvaluator.d.ts +59 -0
- package/dist/evolution/EvolutionEvaluator.js +115 -0
- package/dist/evolution/EvolutionEvaluator.js.map +1 -0
- package/dist/evolution/LessonValidator.d.ts +36 -0
- package/dist/evolution/LessonValidator.js +136 -0
- package/dist/evolution/LessonValidator.js.map +1 -0
- package/dist/fsm/FSMAgentBridge.d.ts +59 -0
- package/dist/fsm/FSMAgentBridge.js +195 -0
- package/dist/fsm/FSMAgentBridge.js.map +1 -0
- package/dist/fsm/index.d.ts +2 -0
- package/dist/fsm/index.js +3 -0
- package/dist/fsm/index.js.map +1 -0
- package/dist/guardrails/DetectorEnhanced.d.ts +111 -0
- package/dist/guardrails/DetectorEnhanced.js +200 -0
- package/dist/guardrails/DetectorEnhanced.js.map +1 -0
- package/dist/hooks/HookDeployer.d.ts +44 -0
- package/dist/hooks/HookDeployer.js +145 -0
- package/dist/hooks/HookDeployer.js.map +1 -0
- package/dist/hooks/HookGeneratorEnhanced.d.ts +67 -0
- package/dist/hooks/HookGeneratorEnhanced.js +238 -0
- package/dist/hooks/HookGeneratorEnhanced.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +26 -2
- package/dist/index.js +21 -5
- package/dist/index.js.map +1 -1
- package/dist/knowledge/SQLiteKnowledgeBase.js +28 -28
- package/dist/skills/SkillDiscovery.js +8 -0
- package/dist/skills/SkillDiscovery.js.map +1 -1
- package/dist/skills/SkillExecutor.d.ts +28 -0
- package/dist/skills/SkillExecutor.js +84 -0
- package/dist/skills/SkillExecutor.js.map +1 -0
- package/dist/skills/SkillRegistry.d.ts +93 -0
- package/dist/skills/SkillRegistry.js +130 -0
- package/dist/skills/SkillRegistry.js.map +1 -0
- package/dist/skills/TriggerEngine.d.ts +43 -0
- package/dist/skills/TriggerEngine.js +144 -0
- package/dist/skills/TriggerEngine.js.map +1 -0
- package/dist/skills/coreSkills.d.ts +6 -0
- package/dist/skills/coreSkills.js +41 -0
- package/dist/skills/coreSkills.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.js +6 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/workflows/GateParser.d.ts +55 -0
- package/dist/workflows/GateParser.js +73 -0
- package/dist/workflows/GateParser.js.map +1 -0
- package/dist/workflows/WorkflowExecutor.d.ts +56 -0
- package/dist/workflows/WorkflowExecutor.js +145 -0
- package/dist/workflows/WorkflowExecutor.js.map +1 -0
- package/dist/workflows/index.d.ts +4 -0
- package/dist/workflows/index.js +5 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { IDetector, DetectorContext } from './Gateway.js';
|
|
2
|
+
import type { ToolUseInput, ToolResultInput, DetectorResult } from '../artifact/types.js';
|
|
3
|
+
import type { IEventBus } from '../core/eventBus.js';
|
|
4
|
+
export interface DetectorTriggerRecord {
|
|
5
|
+
detectorName: string;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
tool: string;
|
|
8
|
+
severity: string;
|
|
9
|
+
triggeredAt: number;
|
|
10
|
+
reason: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DetectorStatistics {
|
|
13
|
+
detectorName: string;
|
|
14
|
+
totalTriggers: number;
|
|
15
|
+
bySeverity: Record<string, number>;
|
|
16
|
+
byTool: Record<string, number>;
|
|
17
|
+
recentTriggers: DetectorTriggerRecord[];
|
|
18
|
+
}
|
|
19
|
+
export interface IDetectorStatisticsTracker {
|
|
20
|
+
record(trigger: DetectorTriggerRecord): void;
|
|
21
|
+
getStats(detectorName: string): DetectorStatistics | null;
|
|
22
|
+
getAllStats(): DetectorStatistics[];
|
|
23
|
+
getRecentTriggers(limit?: number): DetectorTriggerRecord[];
|
|
24
|
+
clear(): void;
|
|
25
|
+
}
|
|
26
|
+
export declare class DetectorStatisticsTracker implements IDetectorStatisticsTracker {
|
|
27
|
+
private triggers;
|
|
28
|
+
private maxRecords;
|
|
29
|
+
constructor(maxRecords?: number);
|
|
30
|
+
record(trigger: DetectorTriggerRecord): void;
|
|
31
|
+
getStats(detectorName: string): DetectorStatistics | null;
|
|
32
|
+
getAllStats(): DetectorStatistics[];
|
|
33
|
+
getRecentTriggers(limit?: number): DetectorTriggerRecord[];
|
|
34
|
+
clear(): void;
|
|
35
|
+
private groupBy;
|
|
36
|
+
}
|
|
37
|
+
export interface DetectorConfig {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
threshold?: number;
|
|
40
|
+
windowMs?: number;
|
|
41
|
+
customPatterns?: Array<{
|
|
42
|
+
pattern: RegExp;
|
|
43
|
+
description: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
export interface IDetectorRegistry {
|
|
47
|
+
register(detector: IDetector, hook: 'preTool' | 'postTool' | 'beforeStop', config?: DetectorConfig): void;
|
|
48
|
+
unregister(detectorName: string): boolean;
|
|
49
|
+
getDetector(detectorName: string): IDetector | null;
|
|
50
|
+
getConfig(detectorName: string): DetectorConfig | null;
|
|
51
|
+
setConfig(detectorName: string, config: Partial<DetectorConfig>): void;
|
|
52
|
+
listDetectors(): Array<{
|
|
53
|
+
name: string;
|
|
54
|
+
hook: string;
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
enable(detectorName: string): void;
|
|
58
|
+
disable(detectorName: string): void;
|
|
59
|
+
}
|
|
60
|
+
export declare class DetectorRegistry implements IDetectorRegistry {
|
|
61
|
+
private detectors;
|
|
62
|
+
register(detector: IDetector, hook: 'preTool' | 'postTool' | 'beforeStop', config?: DetectorConfig): void;
|
|
63
|
+
unregister(detectorName: string): boolean;
|
|
64
|
+
getDetector(detectorName: string): IDetector | null;
|
|
65
|
+
getConfig(detectorName: string): DetectorConfig | null;
|
|
66
|
+
setConfig(detectorName: string, config: Partial<DetectorConfig>): void;
|
|
67
|
+
listDetectors(): Array<{
|
|
68
|
+
name: string;
|
|
69
|
+
hook: string;
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
enable(detectorName: string): void;
|
|
73
|
+
disable(detectorName: string): void;
|
|
74
|
+
}
|
|
75
|
+
export declare class AISlopDetector implements IDetector {
|
|
76
|
+
name: string;
|
|
77
|
+
private patterns;
|
|
78
|
+
private threshold;
|
|
79
|
+
private windowMs;
|
|
80
|
+
constructor(opts?: {
|
|
81
|
+
threshold?: number;
|
|
82
|
+
windowMs?: number;
|
|
83
|
+
});
|
|
84
|
+
check(input: ToolUseInput, ctx: DetectorContext): Promise<DetectorResult>;
|
|
85
|
+
}
|
|
86
|
+
export declare class HallucinationDetector implements IDetector {
|
|
87
|
+
name: string;
|
|
88
|
+
private patterns;
|
|
89
|
+
check(input: ToolResultInput, ctx: DetectorContext): Promise<DetectorResult>;
|
|
90
|
+
}
|
|
91
|
+
export declare class DuplicateEditDetector implements IDetector {
|
|
92
|
+
name: string;
|
|
93
|
+
private maxDuplicates;
|
|
94
|
+
constructor(opts?: {
|
|
95
|
+
maxDuplicates?: number;
|
|
96
|
+
});
|
|
97
|
+
check(input: ToolUseInput, ctx: DetectorContext): Promise<DetectorResult>;
|
|
98
|
+
}
|
|
99
|
+
export interface IEnhancedGateway {
|
|
100
|
+
registry: IDetectorRegistry;
|
|
101
|
+
stats: IDetectorStatisticsTracker;
|
|
102
|
+
}
|
|
103
|
+
export declare class EnhancedGatewayContext implements IEnhancedGateway {
|
|
104
|
+
registry: IDetectorRegistry;
|
|
105
|
+
stats: IDetectorStatisticsTracker;
|
|
106
|
+
constructor(eventBus: IEventBus);
|
|
107
|
+
}
|
|
108
|
+
export declare const ALL_ENHANCED_DETECTORS: Array<{
|
|
109
|
+
detector: IDetector;
|
|
110
|
+
hook: 'preTool' | 'postTool' | 'beforeStop';
|
|
111
|
+
}>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// SCALE Engine — Detector Enhanced (v0.7.0)
|
|
2
|
+
// 增强 Detector 管理:统计、配置、AI-Slop检测、Hallucination检测
|
|
3
|
+
import { logger } from '../core/logger.js';
|
|
4
|
+
export class DetectorStatisticsTracker {
|
|
5
|
+
triggers = [];
|
|
6
|
+
maxRecords;
|
|
7
|
+
constructor(maxRecords = 1000) { this.maxRecords = maxRecords; }
|
|
8
|
+
record(trigger) {
|
|
9
|
+
this.triggers.push(trigger);
|
|
10
|
+
if (this.triggers.length > this.maxRecords)
|
|
11
|
+
this.triggers.shift();
|
|
12
|
+
}
|
|
13
|
+
getStats(detectorName) {
|
|
14
|
+
const matches = this.triggers.filter(t => t.detectorName === detectorName);
|
|
15
|
+
if (matches.length === 0)
|
|
16
|
+
return null;
|
|
17
|
+
return {
|
|
18
|
+
detectorName,
|
|
19
|
+
totalTriggers: matches.length,
|
|
20
|
+
bySeverity: this.groupBy(matches, 'severity'),
|
|
21
|
+
byTool: this.groupBy(matches, 'tool'),
|
|
22
|
+
recentTriggers: matches.slice(-10),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
getAllStats() {
|
|
26
|
+
const names = new Set(this.triggers.map(t => t.detectorName));
|
|
27
|
+
return Array.from(names).map(n => this.getStats(n)).filter(Boolean);
|
|
28
|
+
}
|
|
29
|
+
getRecentTriggers(limit = 50) { return this.triggers.slice(-limit); }
|
|
30
|
+
clear() { this.triggers = []; }
|
|
31
|
+
groupBy(arr, key) {
|
|
32
|
+
const result = {};
|
|
33
|
+
for (const item of arr) {
|
|
34
|
+
const val = String(item[key]);
|
|
35
|
+
result[val] = (result[val] ?? 0) + 1;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class DetectorRegistry {
|
|
41
|
+
detectors = new Map();
|
|
42
|
+
register(detector, hook, config) {
|
|
43
|
+
this.detectors.set(detector.name, { detector, hook, config: config ?? { enabled: true } });
|
|
44
|
+
logger.info({ name: detector.name, hook }, 'Detector registered in registry');
|
|
45
|
+
}
|
|
46
|
+
unregister(detectorName) { return this.detectors.delete(detectorName); }
|
|
47
|
+
getDetector(detectorName) { return this.detectors.get(detectorName)?.detector ?? null; }
|
|
48
|
+
getConfig(detectorName) { return this.detectors.get(detectorName)?.config ?? null; }
|
|
49
|
+
setConfig(detectorName, config) {
|
|
50
|
+
const existing = this.detectors.get(detectorName);
|
|
51
|
+
if (existing)
|
|
52
|
+
existing.config = { ...existing.config, ...config };
|
|
53
|
+
}
|
|
54
|
+
listDetectors() {
|
|
55
|
+
return Array.from(this.detectors.entries()).map(([name, { hook, config }]) => ({ name, hook, enabled: config.enabled }));
|
|
56
|
+
}
|
|
57
|
+
enable(detectorName) { this.setConfig(detectorName, { enabled: true }); }
|
|
58
|
+
disable(detectorName) { this.setConfig(detectorName, { enabled: false }); }
|
|
59
|
+
}
|
|
60
|
+
export class AISlopDetector {
|
|
61
|
+
name = 'ai-slop';
|
|
62
|
+
patterns = [
|
|
63
|
+
{ pattern: /gradient.*purple.*blue/i, description: 'purple-blue gradient overuse' },
|
|
64
|
+
{ pattern: /gradient.*linear.*135deg/i, description: 'generic 135deg gradient' },
|
|
65
|
+
{ pattern: /borderRadius:s*(8|12|16)(px|rem)/i, description: 'uniform rounded corners' },
|
|
66
|
+
{ pattern: /rounded-[(8|12|16)px]/i, description: 'uniform rounded corners (Tailwind)' },
|
|
67
|
+
{ pattern: /hero.*section.*center.*gradient/i, description: 'generic hero section' },
|
|
68
|
+
{ pattern: /grid-cols-3.*gap-4/i, description: 'generic 3-column grid' },
|
|
69
|
+
{ pattern: /flex.*justify-between.*items-center/i, description: 'generic flex center layout' },
|
|
70
|
+
{ pattern: /[🚀💡🎯✨🎉📊🏆⚡💡🔧]/u, description: 'emoji overuse' },
|
|
71
|
+
{ pattern: /background.*blur.*opacity.*0.[1-5]/i, description: 'decorative blur overlay' },
|
|
72
|
+
];
|
|
73
|
+
threshold;
|
|
74
|
+
windowMs;
|
|
75
|
+
constructor(opts = {}) {
|
|
76
|
+
this.threshold = opts.threshold ?? 3;
|
|
77
|
+
this.windowMs = opts.windowMs ?? 5 * 60 * 1000;
|
|
78
|
+
}
|
|
79
|
+
async check(input, ctx) {
|
|
80
|
+
if (!['Edit', 'Write', 'MultiEdit'].includes(input.tool))
|
|
81
|
+
return { triggered: false };
|
|
82
|
+
const content = JSON.stringify(input.args);
|
|
83
|
+
const matches = [];
|
|
84
|
+
for (const { pattern, description } of this.patterns) {
|
|
85
|
+
if (pattern.test(content))
|
|
86
|
+
matches.push(description);
|
|
87
|
+
}
|
|
88
|
+
if (matches.length < 2)
|
|
89
|
+
return { triggered: false };
|
|
90
|
+
const key = 'ai-slop:' + input.sessionId;
|
|
91
|
+
const history = ctx.cache.get(key) ?? [];
|
|
92
|
+
const recent = history.filter(t => Date.now() - t < this.windowMs);
|
|
93
|
+
recent.push(Date.now());
|
|
94
|
+
ctx.cache.set(key, recent);
|
|
95
|
+
if (recent.length >= this.threshold) {
|
|
96
|
+
ctx.eventBus.emit('behavior.ai_slop', { sessionId: input.sessionId, patterns: matches, count: recent.length }, { sessionId: input.sessionId });
|
|
97
|
+
return {
|
|
98
|
+
triggered: true,
|
|
99
|
+
severity: 'warn',
|
|
100
|
+
reason: 'Detected AI-Slop patterns: ' + matches.slice(0, 3).join(', ') + '. Make code look human-written.',
|
|
101
|
+
suggestion: 'Avoid: gradient abuse, uniform rounded corners, emoji, template hero, 3-column grid.',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return { triggered: false };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export class HallucinationDetector {
|
|
108
|
+
name = 'hallucination';
|
|
109
|
+
patterns = [
|
|
110
|
+
{ pattern: /测试.*通过|passed.*test/i, description: 'unverified test pass claim' },
|
|
111
|
+
{ pattern: /已.*验证|verified.*success/i, description: 'unverified verification claim' },
|
|
112
|
+
{ pattern: /构建.*成功|build.*succeeded/i, description: 'unverified build success claim' },
|
|
113
|
+
{ pattern: /lint.*通过|lint.*passed/i, description: 'unverified lint pass claim' },
|
|
114
|
+
];
|
|
115
|
+
async check(input, ctx) {
|
|
116
|
+
const text = input.output ?? '';
|
|
117
|
+
const matches = [];
|
|
118
|
+
for (const { pattern, description } of this.patterns) {
|
|
119
|
+
if (pattern.test(text))
|
|
120
|
+
matches.push(description);
|
|
121
|
+
}
|
|
122
|
+
if (matches.length === 0)
|
|
123
|
+
return { triggered: false };
|
|
124
|
+
const recentCommands = await ctx.eventBus.query({
|
|
125
|
+
sessionId: input.sessionId,
|
|
126
|
+
types: ['tool.completed'],
|
|
127
|
+
filter: (e) => {
|
|
128
|
+
const p = e.payload;
|
|
129
|
+
return p.tool === 'Bash' && /test|lint|build|verify/i.test(p.args?.command ?? '');
|
|
130
|
+
},
|
|
131
|
+
limit: 10,
|
|
132
|
+
});
|
|
133
|
+
const hasSuccessClaim = matches.some(m => m.includes('unverified'));
|
|
134
|
+
if (hasSuccessClaim && recentCommands.length === 0) {
|
|
135
|
+
ctx.eventBus.emit('behavior.hallucination', { sessionId: input.sessionId, patterns: matches, type: 'unverified_claim' }, { sessionId: input.sessionId });
|
|
136
|
+
return {
|
|
137
|
+
triggered: true,
|
|
138
|
+
severity: 'warn',
|
|
139
|
+
reason: 'Detected hallucination: claiming "' + matches[0] + '" without running verification.',
|
|
140
|
+
suggestion: 'Run actual verification commands: bun test, pnpm lint, pnpm build',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { triggered: false };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export class DuplicateEditDetector {
|
|
147
|
+
name = 'duplicate-edit';
|
|
148
|
+
maxDuplicates;
|
|
149
|
+
constructor(opts = {}) { this.maxDuplicates = opts.maxDuplicates ?? 2; }
|
|
150
|
+
async check(input, ctx) {
|
|
151
|
+
if (input.tool !== 'Edit')
|
|
152
|
+
return { triggered: false };
|
|
153
|
+
const args = input.args;
|
|
154
|
+
if (!args.old_string || !args.file_path)
|
|
155
|
+
return { triggered: false };
|
|
156
|
+
const key = 'duplicate-edit:' + input.sessionId + ':' + args.file_path;
|
|
157
|
+
const edits = ctx.cache.get(key) ?? [];
|
|
158
|
+
const duplicateCount = edits.filter(s => s === args.old_string).length;
|
|
159
|
+
edits.push(args.old_string);
|
|
160
|
+
ctx.cache.set(key, edits);
|
|
161
|
+
if (duplicateCount >= this.maxDuplicates) {
|
|
162
|
+
ctx.eventBus.emit('behavior.duplicate_edit', { sessionId: input.sessionId, file: args.file_path, count: duplicateCount + 1 }, { sessionId: input.sessionId });
|
|
163
|
+
return {
|
|
164
|
+
triggered: true,
|
|
165
|
+
severity: 'warn',
|
|
166
|
+
reason: 'Detected duplicate edit: same content edited ' + (duplicateCount + 1) + ' times in ' + args.file_path,
|
|
167
|
+
suggestion: 'Check if previous edits applied correctly, try different strategy.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { triggered: false };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
export class EnhancedGatewayContext {
|
|
174
|
+
registry;
|
|
175
|
+
stats;
|
|
176
|
+
constructor(eventBus) {
|
|
177
|
+
this.registry = new DetectorRegistry();
|
|
178
|
+
this.stats = new DetectorStatisticsTracker();
|
|
179
|
+
// Listen to all events and filter behavior events
|
|
180
|
+
eventBus.on('*', (e) => {
|
|
181
|
+
if (!e.type.startsWith('behavior.'))
|
|
182
|
+
return;
|
|
183
|
+
const payload = e.payload;
|
|
184
|
+
this.stats.record({
|
|
185
|
+
detectorName: String(e.type.replace('behavior.', '')),
|
|
186
|
+
sessionId: String(payload.sessionId ?? 'unknown'),
|
|
187
|
+
tool: String(payload.tool ?? 'unknown'),
|
|
188
|
+
severity: 'warn',
|
|
189
|
+
triggeredAt: Date.now(),
|
|
190
|
+
reason: String(payload.reason ?? ''),
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export const ALL_ENHANCED_DETECTORS = [
|
|
196
|
+
{ detector: new AISlopDetector(), hook: 'preTool' },
|
|
197
|
+
{ detector: new HallucinationDetector(), hook: 'postTool' },
|
|
198
|
+
{ detector: new DuplicateEditDetector(), hook: 'preTool' },
|
|
199
|
+
];
|
|
200
|
+
//# sourceMappingURL=DetectorEnhanced.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DetectorEnhanced.js","sourceRoot":"","sources":["../../src/guardrails/DetectorEnhanced.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IEventBus } from '../core/eventBus.js';
|
|
2
|
+
import type { EnhancedHook } from './HookGeneratorEnhanced.js';
|
|
3
|
+
export interface DeploymentResult {
|
|
4
|
+
success: boolean;
|
|
5
|
+
hookId: string;
|
|
6
|
+
settingsPath: string;
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface DeploymentStatus {
|
|
10
|
+
hookId: string;
|
|
11
|
+
deployedAt: number;
|
|
12
|
+
settingsPath: string;
|
|
13
|
+
active: boolean;
|
|
14
|
+
rollbackAvailable: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface IHookDeployer {
|
|
17
|
+
deploy(hook: EnhancedHook, settingsPath: string): DeploymentResult;
|
|
18
|
+
deployMultiple(hooks: EnhancedHook[], settingsPath: string): DeploymentResult[];
|
|
19
|
+
rollback(hookId: string, settingsPath: string): boolean;
|
|
20
|
+
getStatus(hookId: string): DeploymentStatus | null;
|
|
21
|
+
listDeployed(): DeploymentStatus[];
|
|
22
|
+
validateForDeployment(hook: EnhancedHook): {
|
|
23
|
+
valid: boolean;
|
|
24
|
+
errors: string[];
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare class HookDeployer implements IHookDeployer {
|
|
28
|
+
private eventBus;
|
|
29
|
+
private deployments;
|
|
30
|
+
private hooksBackup;
|
|
31
|
+
constructor(eventBus: IEventBus);
|
|
32
|
+
deploy(hook: EnhancedHook, settingsPath: string): DeploymentResult;
|
|
33
|
+
deployMultiple(hooks: EnhancedHook[], settingsPath: string): DeploymentResult[];
|
|
34
|
+
rollback(hookId: string, settingsPath: string): boolean;
|
|
35
|
+
getStatus(hookId: string): DeploymentStatus | null;
|
|
36
|
+
listDeployed(): DeploymentStatus[];
|
|
37
|
+
validateForDeployment(hook: EnhancedHook): {
|
|
38
|
+
valid: boolean;
|
|
39
|
+
errors: string[];
|
|
40
|
+
};
|
|
41
|
+
private readSettings;
|
|
42
|
+
private writeSettings;
|
|
43
|
+
private buildHookConfig;
|
|
44
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// SCALE Engine — Hook Deployer (v0.7.0)
|
|
2
|
+
// Hook 部署管理:验证、安装、跟踪、回滚
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { logger } from '../core/logger.js';
|
|
6
|
+
export class HookDeployer {
|
|
7
|
+
eventBus;
|
|
8
|
+
deployments = new Map();
|
|
9
|
+
hooksBackup = new Map();
|
|
10
|
+
constructor(eventBus) {
|
|
11
|
+
this.eventBus = eventBus;
|
|
12
|
+
}
|
|
13
|
+
deploy(hook, settingsPath) {
|
|
14
|
+
const validation = this.validateForDeployment(hook);
|
|
15
|
+
if (!validation.valid) {
|
|
16
|
+
return { success: false, hookId: hook.id, settingsPath, errors: validation.errors };
|
|
17
|
+
}
|
|
18
|
+
// 读取现有 settings
|
|
19
|
+
const settings = this.readSettings(settingsPath);
|
|
20
|
+
if (!settings) {
|
|
21
|
+
return { success: false, hookId: hook.id, settingsPath, errors: ['Cannot read settings.json'] };
|
|
22
|
+
}
|
|
23
|
+
// 备份原配置
|
|
24
|
+
this.hooksBackup.set(hook.id, JSON.stringify(settings));
|
|
25
|
+
// 添加 hook 配置
|
|
26
|
+
const hookConfig = this.buildHookConfig(hook);
|
|
27
|
+
const hooks = settings.hooks ?? {};
|
|
28
|
+
if (!hooks[hook.hookType])
|
|
29
|
+
hooks[hook.hookType] = [];
|
|
30
|
+
hooks[hook.hookType].push(hookConfig);
|
|
31
|
+
settings.hooks = hooks;
|
|
32
|
+
// 写入文件
|
|
33
|
+
try {
|
|
34
|
+
this.writeSettings(settingsPath, settings);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return { success: false, hookId: hook.id, settingsPath, errors: ['Failed to write settings: ' + e.message] };
|
|
38
|
+
}
|
|
39
|
+
// 记录部署状态
|
|
40
|
+
const status = {
|
|
41
|
+
hookId: hook.id,
|
|
42
|
+
deployedAt: Date.now(),
|
|
43
|
+
settingsPath,
|
|
44
|
+
active: true,
|
|
45
|
+
rollbackAvailable: true,
|
|
46
|
+
};
|
|
47
|
+
this.deployments.set(hook.id, status);
|
|
48
|
+
this.eventBus.emit('hook.deployed', { hookId: hook.id, hookType: hook.hookType, scriptPath: hook.scriptPath, settingsPath });
|
|
49
|
+
logger.info({ hookId: hook.id, settingsPath }, 'Hook deployed');
|
|
50
|
+
return { success: true, hookId: hook.id, settingsPath, errors: [] };
|
|
51
|
+
}
|
|
52
|
+
deployMultiple(hooks, settingsPath) {
|
|
53
|
+
return hooks.map(h => this.deploy(h, settingsPath));
|
|
54
|
+
}
|
|
55
|
+
rollback(hookId, settingsPath) {
|
|
56
|
+
const status = this.deployments.get(hookId);
|
|
57
|
+
if (!status || !status.rollbackAvailable) {
|
|
58
|
+
logger.warn({ hookId }, 'No rollback available for hook');
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const backup = this.hooksBackup.get(hookId);
|
|
62
|
+
if (!backup) {
|
|
63
|
+
logger.warn({ hookId }, 'No backup found for hook');
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
writeFileSync(settingsPath, backup, 'utf-8');
|
|
68
|
+
status.active = false;
|
|
69
|
+
status.rollbackAvailable = false;
|
|
70
|
+
this.eventBus.emit('hook.rollback', { hookId, settingsPath });
|
|
71
|
+
logger.info({ hookId }, 'Hook rolled back');
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
logger.error({ hookId, error: e.message }, 'Rollback failed');
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
getStatus(hookId) {
|
|
80
|
+
return this.deployments.get(hookId) ?? null;
|
|
81
|
+
}
|
|
82
|
+
listDeployed() {
|
|
83
|
+
return Array.from(this.deployments.values());
|
|
84
|
+
}
|
|
85
|
+
validateForDeployment(hook) {
|
|
86
|
+
const errors = [];
|
|
87
|
+
// 检查脚本文件存在
|
|
88
|
+
if (!existsSync(hook.scriptPath)) {
|
|
89
|
+
errors.push('Hook script does not exist: ' + hook.scriptPath);
|
|
90
|
+
}
|
|
91
|
+
// 检查 hook 类型
|
|
92
|
+
const validTypes = ['PreToolUse', 'PostToolUse', 'Stop', 'SessionStart'];
|
|
93
|
+
if (!validTypes.includes(hook.hookType)) {
|
|
94
|
+
errors.push('Invalid hook type: ' + hook.hookType);
|
|
95
|
+
}
|
|
96
|
+
// 检查 matcher
|
|
97
|
+
if (hook.hookType !== 'Stop' && hook.hookType !== 'SessionStart' && !hook.matcher) {
|
|
98
|
+
errors.push('Matcher is required for PreToolUse/PostToolUse hooks');
|
|
99
|
+
}
|
|
100
|
+
// 检查超时合理
|
|
101
|
+
if (hook.timeout < 1000 || hook.timeout > 60000) {
|
|
102
|
+
errors.push('Timeout should be between 1000ms and 60000ms');
|
|
103
|
+
}
|
|
104
|
+
return { valid: errors.length === 0, errors };
|
|
105
|
+
}
|
|
106
|
+
readSettings(path) {
|
|
107
|
+
if (!existsSync(path)) {
|
|
108
|
+
// 创建默认配置
|
|
109
|
+
return { hooks: {} };
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const content = readFileSync(path, 'utf-8');
|
|
113
|
+
return JSON.parse(content);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
logger.error({ path, error: e.message }, 'Failed to read settings');
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
writeSettings(path, settings) {
|
|
121
|
+
const dir = join(path, '..');
|
|
122
|
+
if (!existsSync(dir))
|
|
123
|
+
mkdirSync(dir, { recursive: true });
|
|
124
|
+
writeFileSync(path, JSON.stringify(settings, null, 2), 'utf-8');
|
|
125
|
+
}
|
|
126
|
+
buildHookConfig(hook) {
|
|
127
|
+
const config = {
|
|
128
|
+
matcher: hook.matcher || '',
|
|
129
|
+
command: 'node ' + hook.scriptPath,
|
|
130
|
+
timeout: hook.timeout,
|
|
131
|
+
};
|
|
132
|
+
// 添加描述
|
|
133
|
+
if (hook.templateId) {
|
|
134
|
+
config.description = 'Generated from template: ' + hook.templateId;
|
|
135
|
+
}
|
|
136
|
+
else if (hook.detectorType) {
|
|
137
|
+
config.description = 'Generated from detector: ' + hook.detectorType;
|
|
138
|
+
}
|
|
139
|
+
else if (hook.ruleId) {
|
|
140
|
+
config.description = 'Generated from rule: ' + hook.ruleId;
|
|
141
|
+
}
|
|
142
|
+
return config;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=HookDeployer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HookDeployer.js","sourceRoot":"","sources":["../../src/hooks/HookDeployer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { IEventBus } from '../core/eventBus.js';
|
|
2
|
+
import type { ProposedRule } from '../evolution/EvolutionEngine.js';
|
|
3
|
+
export interface HookTemplate {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
hookType: 'PreToolUse' | 'PostToolUse' | 'Stop' | 'SessionStart';
|
|
7
|
+
matcherPattern: string;
|
|
8
|
+
description: string;
|
|
9
|
+
templateBody: string;
|
|
10
|
+
variables: HookVariable[];
|
|
11
|
+
}
|
|
12
|
+
export interface HookVariable {
|
|
13
|
+
name: string;
|
|
14
|
+
type: 'string' | 'number' | 'boolean' | 'regex' | 'array';
|
|
15
|
+
required: boolean;
|
|
16
|
+
defaultValue?: unknown;
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
export interface EnhancedHook {
|
|
20
|
+
id: string;
|
|
21
|
+
ruleId?: string;
|
|
22
|
+
hookType: 'PreToolUse' | 'PostToolUse' | 'Stop' | 'SessionStart';
|
|
23
|
+
matcher: string;
|
|
24
|
+
scriptPath: string;
|
|
25
|
+
createdAt: number;
|
|
26
|
+
templateId?: string;
|
|
27
|
+
detectorType?: string;
|
|
28
|
+
language: 'shell' | 'typescript' | 'javascript';
|
|
29
|
+
checkBody: string;
|
|
30
|
+
timeout: number;
|
|
31
|
+
retryable: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface IHookGeneratorEnhanced {
|
|
34
|
+
generateFromRule(rule: ProposedRule, hooksDir: string): EnhancedHook | null;
|
|
35
|
+
generateFromTemplate(template: HookTemplate, variables: Record<string, unknown>, hooksDir: string): EnhancedHook;
|
|
36
|
+
generateFromDetector(detectorType: string, pattern: string, hooksDir: string): EnhancedHook;
|
|
37
|
+
getTemplates(): HookTemplate[];
|
|
38
|
+
registerTemplate(template: HookTemplate): void;
|
|
39
|
+
validateHook(hookPath: string): Promise<{
|
|
40
|
+
valid: boolean;
|
|
41
|
+
errors: string[];
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
export declare class HookGeneratorEnhanced implements IHookGeneratorEnhanced {
|
|
45
|
+
private eventBus;
|
|
46
|
+
private templates;
|
|
47
|
+
private generatedHooks;
|
|
48
|
+
constructor(eventBus: IEventBus);
|
|
49
|
+
generateFromRule(rule: ProposedRule, hooksDir: string): EnhancedHook | null;
|
|
50
|
+
generateFromTemplate(template: HookTemplate, variables: Record<string, unknown>, hooksDir: string): EnhancedHook;
|
|
51
|
+
generateFromDetector(detectorType: string, pattern: string, hooksDir: string): EnhancedHook;
|
|
52
|
+
getTemplates(): HookTemplate[];
|
|
53
|
+
registerTemplate(template: HookTemplate): void;
|
|
54
|
+
validateHook(hookPath: string): Promise<{
|
|
55
|
+
valid: boolean;
|
|
56
|
+
errors: string[];
|
|
57
|
+
}>;
|
|
58
|
+
private findSuitableTemplate;
|
|
59
|
+
private renderTemplate;
|
|
60
|
+
private extractVariablesFromRule;
|
|
61
|
+
private generateRuleBasedHook;
|
|
62
|
+
private generateDetectorHook;
|
|
63
|
+
private inferHookType;
|
|
64
|
+
private inferMatcher;
|
|
65
|
+
private inferHookTypeFromDetector;
|
|
66
|
+
private inferMatcherFromDetector;
|
|
67
|
+
}
|