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.
Files changed (47) hide show
  1. package/README.md +189 -113
  2. package/bin/api-server.js +1 -4
  3. package/bin/cli.js +1 -50
  4. package/config/constitution.yaml +33 -107
  5. package/dashboard/dist/assets/{icons-B4FfLfBA.js → icons-B5rs8uNb.js} +85 -80
  6. package/dashboard/dist/assets/index-0YzLw2ga.css +1 -0
  7. package/dashboard/dist/assets/index-B9py3ybr.js +154 -0
  8. package/dashboard/dist/index.html +3 -3
  9. package/lib/bootstrap.js +5 -31
  10. package/lib/cli/SetupService.js +16 -14
  11. package/lib/core/capability/CapabilityProbe.js +8 -6
  12. package/lib/core/constitution/Constitution.js +13 -4
  13. package/lib/core/constitution/ConstitutionValidator.js +106 -211
  14. package/lib/core/gateway/Gateway.js +34 -98
  15. package/lib/core/gateway/GatewayActionRegistry.js +12 -1
  16. package/lib/core/permission/PermissionManager.js +2 -2
  17. package/lib/external/mcp/McpServer.js +4 -7
  18. package/lib/external/mcp/handlers/bootstrap.js +13 -1
  19. package/lib/external/mcp/handlers/browse.js +0 -7
  20. package/lib/external/mcp/handlers/candidate.js +1 -1
  21. package/lib/external/mcp/handlers/guard.js +11 -0
  22. package/lib/external/mcp/handlers/skill.js +186 -18
  23. package/lib/external/mcp/tools.js +40 -1
  24. package/lib/http/middleware/roleResolver.js +1 -1
  25. package/lib/http/routes/auth.js +2 -2
  26. package/lib/http/routes/commands.js +58 -3
  27. package/lib/http/routes/monitoring.js +4 -4
  28. package/lib/http/routes/recipes.js +96 -4
  29. package/lib/http/routes/search.js +34 -35
  30. package/lib/injection/ServiceContainer.js +21 -40
  31. package/lib/service/candidate/CandidateService.js +12 -1
  32. package/lib/service/chat/ChatAgent.js +171 -30
  33. package/lib/service/chat/Memory.js +104 -0
  34. package/lib/service/chat/tools.js +244 -10
  35. package/lib/service/guard/GuardCheckEngine.js +9 -1
  36. package/lib/service/knowledge/KnowledgeGraphService.js +20 -9
  37. package/lib/service/recipe/RecipeService.js +8 -0
  38. package/lib/service/skills/SkillHooks.js +126 -0
  39. package/package.json +1 -1
  40. package/scripts/init-db.js +1 -2
  41. package/templates/constitution.yaml +29 -85
  42. package/dashboard/dist/assets/index-ChxJxX4B.js +0 -154
  43. package/dashboard/dist/assets/index-DwAp1mx5.css +0 -1
  44. package/lib/core/session/SessionManager.js +0 -232
  45. package/lib/infrastructure/logging/ReasoningLogger.js +0 -269
  46. package/lib/infrastructure/monitoring/RoleDriftMonitor.js +0 -259
  47. 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;