autosnippet 2.0.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -113
- package/bin/api-server.js +1 -4
- package/bin/cli.js +1 -50
- package/config/constitution.yaml +33 -107
- package/dashboard/dist/assets/{icons-B4FfLfBA.js → icons-B5rs8uNb.js} +85 -80
- package/dashboard/dist/assets/index-0YzLw2ga.css +1 -0
- package/dashboard/dist/assets/index-B9py3ybr.js +154 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/bootstrap.js +5 -31
- package/lib/cli/SetupService.js +16 -14
- package/lib/core/capability/CapabilityProbe.js +8 -6
- package/lib/core/constitution/Constitution.js +13 -4
- package/lib/core/constitution/ConstitutionValidator.js +106 -211
- package/lib/core/gateway/Gateway.js +34 -98
- package/lib/core/gateway/GatewayActionRegistry.js +12 -1
- package/lib/core/permission/PermissionManager.js +2 -2
- package/lib/external/mcp/McpServer.js +4 -7
- package/lib/external/mcp/handlers/bootstrap.js +13 -1
- package/lib/external/mcp/handlers/browse.js +0 -7
- package/lib/external/mcp/handlers/candidate.js +1 -1
- package/lib/external/mcp/handlers/guard.js +11 -0
- package/lib/external/mcp/handlers/skill.js +186 -18
- package/lib/external/mcp/tools.js +40 -1
- package/lib/http/middleware/roleResolver.js +1 -1
- package/lib/http/routes/auth.js +2 -2
- package/lib/http/routes/commands.js +58 -3
- package/lib/http/routes/monitoring.js +4 -4
- package/lib/http/routes/recipes.js +96 -4
- package/lib/http/routes/search.js +34 -35
- package/lib/injection/ServiceContainer.js +21 -40
- package/lib/service/candidate/CandidateService.js +12 -1
- package/lib/service/chat/ChatAgent.js +171 -30
- package/lib/service/chat/Memory.js +104 -0
- package/lib/service/chat/tools.js +244 -10
- package/lib/service/guard/GuardCheckEngine.js +9 -1
- package/lib/service/knowledge/KnowledgeGraphService.js +20 -9
- package/lib/service/recipe/RecipeService.js +8 -0
- package/lib/service/skills/SkillHooks.js +126 -0
- package/package.json +1 -1
- package/scripts/init-db.js +1 -2
- package/templates/constitution.yaml +29 -85
- package/dashboard/dist/assets/index-ChxJxX4B.js +0 -154
- package/dashboard/dist/assets/index-DwAp1mx5.css +0 -1
- package/lib/core/session/SessionManager.js +0 -232
- package/lib/infrastructure/logging/ReasoningLogger.js +0 -269
- package/lib/infrastructure/monitoring/RoleDriftMonitor.js +0 -259
- package/lib/infrastructure/quality/ComplianceEvaluator.js +0 -326
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ComplianceEvaluator - 宪法合规评估工具
|
|
3
|
-
*
|
|
4
|
-
* 自动评估系统在四大优先级上的合规程度,生成结构化报告。
|
|
5
|
-
* 可通过 CLI 命令 `asd compliance` 或 API 调用。
|
|
6
|
-
*
|
|
7
|
-
* 四大优先级:
|
|
8
|
-
* 1. Data Integrity - 数据完整性
|
|
9
|
-
* 2. Human Oversight - 人工监督
|
|
10
|
-
* 3. AI Transparency - AI 透明性
|
|
11
|
-
* 4. Helpfulness - 帮助性
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import Logger from '../logging/Logger.js';
|
|
15
|
-
|
|
16
|
-
export class ComplianceEvaluator {
|
|
17
|
-
constructor(db) {
|
|
18
|
-
this.db = typeof db?.getDb === 'function' ? db.getDb() : db;
|
|
19
|
-
this.logger = Logger.getInstance();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 执行完整合规评估
|
|
24
|
-
* @param {object} options - { period: 'all'|'weekly'|'monthly', priority: null|string }
|
|
25
|
-
* @returns {object} 合规报告
|
|
26
|
-
*/
|
|
27
|
-
evaluate(options = {}) {
|
|
28
|
-
const since = this._getSinceTimestamp(options.period);
|
|
29
|
-
const report = {
|
|
30
|
-
evaluatedAt: new Date().toISOString(),
|
|
31
|
-
period: options.period || 'all',
|
|
32
|
-
priorities: {},
|
|
33
|
-
overallScore: 0,
|
|
34
|
-
recommendations: [],
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// 评估每个优先级
|
|
38
|
-
report.priorities.dataIntegrity = this._evaluateDataIntegrity(since);
|
|
39
|
-
report.priorities.humanOversight = this._evaluateHumanOversight(since);
|
|
40
|
-
report.priorities.aiTransparency = this._evaluateAITransparency(since);
|
|
41
|
-
report.priorities.helpfulness = this._evaluateHelpfulness(since);
|
|
42
|
-
|
|
43
|
-
// 加权总分 (P1=35%, P2=30%, P3=20%, P4=15%)
|
|
44
|
-
report.overallScore = Math.round((
|
|
45
|
-
report.priorities.dataIntegrity.score * 0.35 +
|
|
46
|
-
report.priorities.humanOversight.score * 0.30 +
|
|
47
|
-
report.priorities.aiTransparency.score * 0.20 +
|
|
48
|
-
report.priorities.helpfulness.score * 0.15
|
|
49
|
-
) * 100) / 100;
|
|
50
|
-
|
|
51
|
-
// 生成改进建议
|
|
52
|
-
report.recommendations = this._generateRecommendations(report.priorities);
|
|
53
|
-
|
|
54
|
-
return report;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ========== Priority 1: Data Integrity ==========
|
|
58
|
-
|
|
59
|
-
_evaluateDataIntegrity(since) {
|
|
60
|
-
const result = { score: 0, metrics: {}, issues: [] };
|
|
61
|
-
const whereTime = since ? 'AND created_at >= ?' : '';
|
|
62
|
-
const whereParams = since ? [since] : [];
|
|
63
|
-
|
|
64
|
-
// 1. Candidate → Recipe 转化率 (目标 > 60%)
|
|
65
|
-
const candidateStats = this._safeQuery(`
|
|
66
|
-
SELECT
|
|
67
|
-
COUNT(*) as total,
|
|
68
|
-
SUM(CASE WHEN status = 'applied' THEN 1 ELSE 0 END) as applied,
|
|
69
|
-
SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved
|
|
70
|
-
FROM candidates WHERE 1=1 ${whereTime}
|
|
71
|
-
`, whereParams);
|
|
72
|
-
const conversionRate = candidateStats.total > 0
|
|
73
|
-
? (candidateStats.applied + candidateStats.approved) / candidateStats.total
|
|
74
|
-
: 0;
|
|
75
|
-
result.metrics.candidateConversionRate = Math.round(conversionRate * 100) / 100;
|
|
76
|
-
|
|
77
|
-
if (conversionRate < 0.6) {
|
|
78
|
-
result.issues.push({ severity: 'warning', message: `Candidate conversion rate ${(conversionRate * 100).toFixed(0)}% is below 60% target` });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 2. Recipe 版本追踪 (audit_logs 覆盖率)
|
|
82
|
-
const recipeCount = this._safeQuery(`SELECT COUNT(*) as total FROM recipes WHERE 1=1 ${whereTime}`, whereParams);
|
|
83
|
-
const auditedRecipes = this._safeQuery(`
|
|
84
|
-
SELECT COUNT(DISTINCT resource_id) as total FROM audit_logs
|
|
85
|
-
WHERE resource_type = 'recipe' ${whereTime}
|
|
86
|
-
`, whereParams);
|
|
87
|
-
const auditCoverage = recipeCount.total > 0 ? auditedRecipes.total / recipeCount.total : 1;
|
|
88
|
-
result.metrics.recipeAuditCoverage = Math.round(auditCoverage * 100) / 100;
|
|
89
|
-
|
|
90
|
-
if (auditCoverage < 1) {
|
|
91
|
-
result.issues.push({ severity: 'info', message: `${((1 - auditCoverage) * 100).toFixed(0)}% of recipes lack audit trail` });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 3. Candidate 有推理过程的比率
|
|
95
|
-
const withReasoning = this._safeQuery(`
|
|
96
|
-
SELECT
|
|
97
|
-
COUNT(*) as total,
|
|
98
|
-
SUM(CASE WHEN reasoning_json IS NOT NULL AND reasoning_json != '{}' AND reasoning_json != 'null' THEN 1 ELSE 0 END) as with_reasoning
|
|
99
|
-
FROM candidates WHERE 1=1 ${whereTime}
|
|
100
|
-
`, whereParams);
|
|
101
|
-
const reasoningRate = withReasoning.total > 0 ? withReasoning.with_reasoning / withReasoning.total : 0;
|
|
102
|
-
result.metrics.reasoningRate = Math.round(reasoningRate * 100) / 100;
|
|
103
|
-
|
|
104
|
-
// 综合评分
|
|
105
|
-
result.score = Math.round((conversionRate * 0.4 + auditCoverage * 0.3 + reasoningRate * 0.3) * 100) / 100;
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ========== Priority 2: Human Oversight ==========
|
|
110
|
-
|
|
111
|
-
_evaluateHumanOversight(since) {
|
|
112
|
-
const result = { score: 0, metrics: {}, issues: [] };
|
|
113
|
-
const whereTime = since ? 'AND created_at >= ?' : '';
|
|
114
|
-
const whereParams = since ? [since] : [];
|
|
115
|
-
|
|
116
|
-
// 1. 零自动修改事件 (AI 不应直接修改 Recipe)
|
|
117
|
-
const autoModifications = this._safeQuery(`
|
|
118
|
-
SELECT COUNT(*) as total FROM audit_logs
|
|
119
|
-
WHERE action IN ('create_recipe', 'publish_recipe', 'update_recipe')
|
|
120
|
-
AND actor IN ('cursor_agent', 'asd_ais', 'guard_engine') ${whereTime}
|
|
121
|
-
`, whereParams);
|
|
122
|
-
result.metrics.autoModifications = autoModifications.total;
|
|
123
|
-
const noAutoModScore = autoModifications.total === 0 ? 1 : Math.max(0, 1 - autoModifications.total * 0.1);
|
|
124
|
-
|
|
125
|
-
if (autoModifications.total > 0) {
|
|
126
|
-
result.issues.push({ severity: 'error', message: `${autoModifications.total} auto-modifications by AI actors detected` });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 2. 审核覆盖率 (所有 Candidate 都有人工操作)
|
|
130
|
-
const reviewed = this._safeQuery(`
|
|
131
|
-
SELECT
|
|
132
|
-
COUNT(*) as total,
|
|
133
|
-
SUM(CASE WHEN status IN ('approved', 'rejected', 'applied') THEN 1 ELSE 0 END) as reviewed
|
|
134
|
-
FROM candidates WHERE 1=1 ${whereTime}
|
|
135
|
-
`, whereParams);
|
|
136
|
-
const reviewRate = reviewed.total > 0 ? reviewed.reviewed / reviewed.total : 1;
|
|
137
|
-
result.metrics.reviewRate = Math.round(reviewRate * 100) / 100;
|
|
138
|
-
|
|
139
|
-
// 3. 审计日志完整性
|
|
140
|
-
const totalActions = this._safeQuery(`SELECT COUNT(*) as total FROM audit_logs WHERE 1=1 ${whereTime}`, whereParams);
|
|
141
|
-
const failedAudits = this._safeQuery(`
|
|
142
|
-
SELECT COUNT(*) as total FROM audit_logs WHERE result = 'failure' ${whereTime}
|
|
143
|
-
`, whereParams);
|
|
144
|
-
const auditSuccess = totalActions.total > 0 ? 1 - (failedAudits.total / totalActions.total) : 1;
|
|
145
|
-
result.metrics.auditSuccessRate = Math.round(auditSuccess * 100) / 100;
|
|
146
|
-
|
|
147
|
-
result.score = Math.round((noAutoModScore * 0.5 + reviewRate * 0.3 + auditSuccess * 0.2) * 100) / 100;
|
|
148
|
-
return result;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ========== Priority 3: AI Transparency ==========
|
|
152
|
-
|
|
153
|
-
_evaluateAITransparency(since) {
|
|
154
|
-
const result = { score: 0, metrics: {}, issues: [] };
|
|
155
|
-
const whereTime = since ? 'AND created_at >= ?' : '';
|
|
156
|
-
const whereParams = since ? [since] : [];
|
|
157
|
-
|
|
158
|
-
// 1. AI 创建的 Candidate 推理完整性
|
|
159
|
-
const aiCandidates = this._safeQuery(`
|
|
160
|
-
SELECT
|
|
161
|
-
COUNT(*) as total,
|
|
162
|
-
SUM(CASE WHEN reasoning_json IS NOT NULL AND reasoning_json != '{}' AND reasoning_json != 'null' AND LENGTH(reasoning_json) > 20 THEN 1 ELSE 0 END) as with_full_reasoning
|
|
163
|
-
FROM candidates
|
|
164
|
-
WHERE source IN ('cursor_agent', 'asd_ais', 'ai') ${whereTime}
|
|
165
|
-
`, whereParams);
|
|
166
|
-
const aiReasoningRate = aiCandidates.total > 0 ? aiCandidates.with_full_reasoning / aiCandidates.total : 1;
|
|
167
|
-
result.metrics.aiReasoningCompleteness = Math.round(aiReasoningRate * 100) / 100;
|
|
168
|
-
|
|
169
|
-
if (aiReasoningRate < 0.7) {
|
|
170
|
-
result.issues.push({ severity: 'warning', message: `Only ${(aiReasoningRate * 100).toFixed(0)}% of AI candidates have complete reasoning (target: 70%)` });
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// 2. Guard 规则(boundary-constraint 类型 Recipe)有来源的比率
|
|
174
|
-
const guardRecipes = this._safeQuery(`
|
|
175
|
-
SELECT
|
|
176
|
-
COUNT(*) as total,
|
|
177
|
-
SUM(CASE WHEN source_candidate_id IS NOT NULL AND source_candidate_id != '' THEN 1 ELSE 0 END) as with_source
|
|
178
|
-
FROM recipes WHERE knowledge_type = 'boundary-constraint' ${whereTime}
|
|
179
|
-
`, whereParams);
|
|
180
|
-
const guardSourceRate = guardRecipes.total > 0 ? guardRecipes.with_source / guardRecipes.total : 1;
|
|
181
|
-
result.metrics.guardRuleSourceRate = Math.round(guardSourceRate * 100) / 100;
|
|
182
|
-
|
|
183
|
-
// 3. 推理日志记录率
|
|
184
|
-
let reasoningLogRate = 1;
|
|
185
|
-
try {
|
|
186
|
-
const hasTable = this.db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='reasoning_logs'`).get();
|
|
187
|
-
if (hasTable) {
|
|
188
|
-
const logs = this._safeQuery(`SELECT COUNT(*) as total FROM reasoning_logs WHERE 1=1 ${whereTime}`, whereParams);
|
|
189
|
-
const expected = aiCandidates.total + (guardRecipes.total > 0 ? 1 : 0);
|
|
190
|
-
reasoningLogRate = expected > 0 ? Math.min(1, logs.total / expected) : 1;
|
|
191
|
-
}
|
|
192
|
-
} catch {}
|
|
193
|
-
result.metrics.reasoningLogRate = Math.round(reasoningLogRate * 100) / 100;
|
|
194
|
-
|
|
195
|
-
result.score = Math.round((aiReasoningRate * 0.4 + guardSourceRate * 0.3 + reasoningLogRate * 0.3) * 100) / 100;
|
|
196
|
-
return result;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ========== Priority 4: Helpfulness ==========
|
|
200
|
-
|
|
201
|
-
_evaluateHelpfulness(since) {
|
|
202
|
-
const result = { score: 0, metrics: {}, issues: [] };
|
|
203
|
-
const whereTime = since ? 'AND created_at >= ?' : '';
|
|
204
|
-
const whereParams = since ? [since] : [];
|
|
205
|
-
|
|
206
|
-
// 1. Recipe 采纳率
|
|
207
|
-
const recipes = this._safeQuery(`
|
|
208
|
-
SELECT
|
|
209
|
-
COUNT(*) as total,
|
|
210
|
-
SUM(adoption_count) as total_adoptions,
|
|
211
|
-
SUM(application_count) as total_applications,
|
|
212
|
-
AVG(quality_overall) as avg_quality
|
|
213
|
-
FROM recipes WHERE status = 'active' ${whereTime}
|
|
214
|
-
`, whereParams);
|
|
215
|
-
result.metrics.activeRecipes = recipes.total;
|
|
216
|
-
result.metrics.totalAdoptions = recipes.total_adoptions || 0;
|
|
217
|
-
result.metrics.totalApplications = recipes.total_applications || 0;
|
|
218
|
-
result.metrics.avgQuality = Math.round((recipes.avg_quality || 0) * 100) / 100;
|
|
219
|
-
|
|
220
|
-
// 活跃 Recipe 有使用记录的比率
|
|
221
|
-
const usedRecipes = this._safeQuery(`
|
|
222
|
-
SELECT COUNT(*) as total FROM recipes
|
|
223
|
-
WHERE status = 'active' AND (adoption_count > 0 OR application_count > 0) ${whereTime}
|
|
224
|
-
`, whereParams);
|
|
225
|
-
const usageRate = recipes.total > 0 ? usedRecipes.total / recipes.total : 0;
|
|
226
|
-
result.metrics.recipeUsageRate = Math.round(usageRate * 100) / 100;
|
|
227
|
-
|
|
228
|
-
// 2. Guard 规则启用率(boundary-constraint 类型 Recipe 中 active 的比率)
|
|
229
|
-
const guardStats = this._safeQuery(`
|
|
230
|
-
SELECT
|
|
231
|
-
COUNT(*) as total,
|
|
232
|
-
SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as enabled_count
|
|
233
|
-
FROM recipes WHERE knowledge_type = 'boundary-constraint'
|
|
234
|
-
`);
|
|
235
|
-
const enabledRate = guardStats.total > 0 ? guardStats.enabled_count / guardStats.total : 0;
|
|
236
|
-
result.metrics.guardRuleEnabledRate = Math.round(enabledRate * 100) / 100;
|
|
237
|
-
|
|
238
|
-
// 3. Candidate 采纳率 (approved+applied vs total)
|
|
239
|
-
const candidates = this._safeQuery(`
|
|
240
|
-
SELECT
|
|
241
|
-
COUNT(*) as total,
|
|
242
|
-
SUM(CASE WHEN status IN ('approved', 'applied') THEN 1 ELSE 0 END) as accepted
|
|
243
|
-
FROM candidates WHERE 1=1 ${whereTime}
|
|
244
|
-
`, whereParams);
|
|
245
|
-
const acceptRate = candidates.total > 0 ? candidates.accepted / candidates.total : 0;
|
|
246
|
-
result.metrics.candidateAcceptRate = Math.round(acceptRate * 100) / 100;
|
|
247
|
-
|
|
248
|
-
if (acceptRate < 0.6) {
|
|
249
|
-
result.issues.push({ severity: 'info', message: `Candidate acceptance rate ${(acceptRate * 100).toFixed(0)}% is below 60% target` });
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
result.score = Math.round((usageRate * 0.3 + enabledRate * 0.2 + acceptRate * 0.3 + (recipes.avg_quality || 0) * 0.2) * 100) / 100;
|
|
253
|
-
return result;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// ========== Recommendations ==========
|
|
257
|
-
|
|
258
|
-
_generateRecommendations(priorities) {
|
|
259
|
-
const recs = [];
|
|
260
|
-
|
|
261
|
-
if (priorities.dataIntegrity.score < 0.7) {
|
|
262
|
-
recs.push({
|
|
263
|
-
priority: 'P1:DataIntegrity',
|
|
264
|
-
action: 'Improve candidate reasoning completeness and conversion rate',
|
|
265
|
-
severity: 'high',
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
if (priorities.humanOversight.metrics.autoModifications > 0) {
|
|
269
|
-
recs.push({
|
|
270
|
-
priority: 'P2:HumanOversight',
|
|
271
|
-
action: 'Investigate and block AI auto-modifications to recipes',
|
|
272
|
-
severity: 'critical',
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
if (priorities.aiTransparency.metrics.aiReasoningCompleteness < 0.7) {
|
|
276
|
-
recs.push({
|
|
277
|
-
priority: 'P3:AITransparency',
|
|
278
|
-
action: 'Enforce reasoning field for AI-generated candidates',
|
|
279
|
-
severity: 'medium',
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
if (priorities.helpfulness.metrics.candidateAcceptRate < 0.6) {
|
|
283
|
-
recs.push({
|
|
284
|
-
priority: 'P4:Helpfulness',
|
|
285
|
-
action: 'Improve AI candidate quality to increase acceptance rate',
|
|
286
|
-
severity: 'medium',
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return recs;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// ========== Helpers ==========
|
|
294
|
-
|
|
295
|
-
_getSinceTimestamp(period) {
|
|
296
|
-
if (!period || period === 'all') return null;
|
|
297
|
-
const now = Math.floor(Date.now() / 1000);
|
|
298
|
-
switch (period) {
|
|
299
|
-
case 'weekly': return now - 7 * 86400;
|
|
300
|
-
case 'monthly': return now - 30 * 86400;
|
|
301
|
-
case 'daily': return now - 86400;
|
|
302
|
-
default: return null;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
_safeQuery(sql, params = []) {
|
|
307
|
-
try {
|
|
308
|
-
return this.db.prepare(sql).get(...params) || {};
|
|
309
|
-
} catch {
|
|
310
|
-
return {};
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
let instance = null;
|
|
316
|
-
|
|
317
|
-
export function initComplianceEvaluator(db) {
|
|
318
|
-
instance = new ComplianceEvaluator(db);
|
|
319
|
-
return instance;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export function getComplianceEvaluator() {
|
|
323
|
-
return instance;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
export default ComplianceEvaluator;
|