autosnippet 3.0.11 → 3.0.13
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/bin/cli.js +64 -1
- package/config/default.json +9 -0
- package/dashboard/dist/assets/{index-I2ySoCmF.js → index-Bnm26ulL.js} +47 -47
- package/dashboard/dist/index.html +1 -1
- package/lib/cli/SetupService.js +92 -5
- package/lib/cli/UpgradeService.js +14 -5
- package/lib/core/discovery/GenericDiscoverer.js +4 -28
- package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +246 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +80 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +275 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +600 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +125 -342
- package/lib/external/mcp/handlers/bootstrap/refine.js +362 -0
- package/lib/external/mcp/handlers/bootstrap.js +6 -590
- package/lib/external/mcp/handlers/browse.js +119 -9
- package/lib/external/mcp/handlers/guard.js +25 -6
- package/lib/external/mcp/handlers/search.js +56 -24
- package/lib/http/routes/guardRules.js +9 -17
- package/lib/injection/ServiceContainer.js +12 -3
- package/lib/platform/ios/xcode/XcodeImportResolver.js +434 -0
- package/lib/platform/ios/xcode/XcodeIntegration.js +40 -659
- package/lib/platform/ios/xcode/XcodeWriteUtils.js +220 -0
- package/lib/service/chat/ChatAgent.js +39 -418
- package/lib/service/chat/ChatAgentPrompts.js +149 -0
- package/lib/service/chat/ChatAgentTasks.js +297 -0
- package/lib/service/chat/tools/_shared.js +61 -0
- package/lib/service/chat/tools/ai-analysis.js +284 -0
- package/lib/service/chat/tools/ast-graph.js +681 -0
- package/lib/service/chat/tools/composite.js +496 -0
- package/lib/service/chat/tools/guard.js +265 -0
- package/lib/service/chat/tools/index.js +250 -0
- package/lib/service/chat/tools/infrastructure.js +222 -0
- package/lib/service/chat/tools/knowledge-graph.js +234 -0
- package/lib/service/chat/tools/lifecycle.js +469 -0
- package/lib/service/chat/tools/project-access.js +923 -0
- package/lib/service/chat/tools/query.js +264 -0
- package/lib/service/chat/tools.js +14 -3994
- package/lib/service/cursor/AgentInstructionsGenerator.js +395 -0
- package/lib/service/cursor/CursorDeliveryPipeline.js +70 -11
- package/lib/service/cursor/FileProtection.js +116 -0
- package/lib/service/cursor/KnowledgeCompressor.js +61 -11
- package/lib/service/cursor/SkillsSyncer.js +5 -3
- package/lib/service/cursor/TopicClassifier.js +19 -3
- package/lib/service/guard/ExclusionManager.js +26 -2
- package/lib/service/guard/GuardCheckEngine.js +38 -370
- package/lib/service/guard/GuardCodeChecks.js +362 -0
- package/lib/service/guard/GuardCrossFileChecks.js +307 -0
- package/lib/service/guard/GuardPatternUtils.js +180 -0
- package/lib/service/guard/GuardService.js +80 -38
- package/lib/service/module/ModuleService.js +1 -0
- package/lib/service/search/SearchEngine.js +10 -2
- package/lib/service/wiki/WikiGenerator.js +226 -1532
- package/lib/service/wiki/WikiRenderers.js +1878 -0
- package/lib/service/wiki/WikiUtils.js +907 -0
- package/lib/shared/LanguageService.js +299 -0
- package/package.json +1 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardPatternUtils - Guard 模式匹配与掩码工具函数
|
|
3
|
+
*
|
|
4
|
+
* 从 GuardCheckEngine 拆分,包含:
|
|
5
|
+
* - compilePattern: 正则编译(带缓存)
|
|
6
|
+
* - clearPatternCache: 清除正则缓存
|
|
7
|
+
* - buildTestBlockMask: 测试块掩码(Rust #[cfg(test)])
|
|
8
|
+
* - buildCommentMask: 注释行掩码
|
|
9
|
+
* - detectLanguage: 文件扩展名推断语言
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { LanguageService } from '../../shared/LanguageService.js';
|
|
13
|
+
|
|
14
|
+
/** @type {Map<string, RegExp>} 已编译的正则缓存 (pattern string → RegExp) */
|
|
15
|
+
const _regexCache = new Map();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 编译正则模式(支持 RegExp 对象和 string,带缓存)
|
|
19
|
+
* @param {RegExp|string} pattern
|
|
20
|
+
* @returns {RegExp}
|
|
21
|
+
*/
|
|
22
|
+
export function compilePattern(pattern) {
|
|
23
|
+
if (pattern instanceof RegExp) {
|
|
24
|
+
return pattern;
|
|
25
|
+
}
|
|
26
|
+
const key = String(pattern);
|
|
27
|
+
let cached = _regexCache.get(key);
|
|
28
|
+
if (!cached) {
|
|
29
|
+
cached = new RegExp(key);
|
|
30
|
+
_regexCache.set(key, cached);
|
|
31
|
+
}
|
|
32
|
+
return cached;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 清除正则缓存
|
|
37
|
+
*/
|
|
38
|
+
export function clearPatternCache() {
|
|
39
|
+
_regexCache.clear();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 构建内联测试块掩码
|
|
44
|
+
* 目前支持 Rust #[cfg(test)] mod xxx { ... } 块
|
|
45
|
+
* @param {string[]} lines
|
|
46
|
+
* @param {string} language
|
|
47
|
+
* @returns {boolean[]} 每行是否在测试块内
|
|
48
|
+
*/
|
|
49
|
+
export function buildTestBlockMask(lines, language) {
|
|
50
|
+
const mask = new Array(lines.length).fill(false);
|
|
51
|
+
|
|
52
|
+
// 目前仅 Rust 需要 — #[cfg(test)] 内联测试模块
|
|
53
|
+
if (language !== 'rust') return mask;
|
|
54
|
+
|
|
55
|
+
let inTestBlock = false;
|
|
56
|
+
let braceDepth = 0;
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < lines.length; i++) {
|
|
59
|
+
const trimmed = lines[i].trimStart();
|
|
60
|
+
|
|
61
|
+
if (!inTestBlock) {
|
|
62
|
+
// 检测 #[cfg(test)] 属性行
|
|
63
|
+
if (/^#\[cfg\(test\)\]/.test(trimmed)) {
|
|
64
|
+
// 向后找 mod xxx { — 标记为测试块起始
|
|
65
|
+
// 可能在同一行: #[cfg(test)] mod tests {
|
|
66
|
+
// 也可能在下一行: mod tests {
|
|
67
|
+
const restOfLine = trimmed.slice('#[cfg(test)]'.length).trim();
|
|
68
|
+
if (/^mod\s+\w+/.test(restOfLine)) {
|
|
69
|
+
// 同一行有 mod 声明
|
|
70
|
+
inTestBlock = true;
|
|
71
|
+
braceDepth = 0;
|
|
72
|
+
// 计算本行的花括号
|
|
73
|
+
for (const ch of lines[i]) {
|
|
74
|
+
if (ch === '{') braceDepth++;
|
|
75
|
+
else if (ch === '}') braceDepth--;
|
|
76
|
+
}
|
|
77
|
+
mask[i] = true;
|
|
78
|
+
if (braceDepth <= 0) inTestBlock = false; // 单行 mod 声明 (mod tests;)
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// 检查下一行是否是 mod xxx {
|
|
82
|
+
if (i + 1 < lines.length && /^\s*mod\s+\w+/.test(lines[i + 1])) {
|
|
83
|
+
mask[i] = true; // #[cfg(test)] 行本身也标记
|
|
84
|
+
inTestBlock = true;
|
|
85
|
+
braceDepth = 0;
|
|
86
|
+
// 下一行会在循环中处理
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// 单行 #[cfg(test)] 但后面不是 mod — 不处理
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
// 正在测试块内 — 追踪花括号深度
|
|
93
|
+
mask[i] = true;
|
|
94
|
+
for (const ch of lines[i]) {
|
|
95
|
+
if (ch === '{') braceDepth++;
|
|
96
|
+
else if (ch === '}') braceDepth--;
|
|
97
|
+
}
|
|
98
|
+
if (braceDepth <= 0) {
|
|
99
|
+
inTestBlock = false; // 测试块结束
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return mask;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 构建注释行掩码 — 识别行注释和块注释内部行
|
|
109
|
+
*
|
|
110
|
+
* 支持的注释形式:
|
|
111
|
+
* // 行注释, /// 文档注释, //! 内部文档注释 (C/Java/JS/TS/Go/Rust/Swift/Kotlin/Dart)
|
|
112
|
+
* # 行注释 (Python)
|
|
113
|
+
* /* ... * / 块注释 (C/Java/JS/TS/Go/Rust/Swift/Kotlin)
|
|
114
|
+
* \"\"\" ... \"\"\" (Python doc-string — 简化: 整行以 \"\"\" 开头的行)
|
|
115
|
+
*
|
|
116
|
+
* @param {string[]} lines
|
|
117
|
+
* @param {string} language
|
|
118
|
+
* @returns {boolean[]} 每行是否为注释行
|
|
119
|
+
*/
|
|
120
|
+
export function buildCommentMask(lines, language) {
|
|
121
|
+
const mask = new Array(lines.length).fill(false);
|
|
122
|
+
let inBlock = false; // 是否在 /* ... */ 块内
|
|
123
|
+
|
|
124
|
+
const usesHash = language === 'python'; // Python 用 # 注释
|
|
125
|
+
const usesSlash = !usesHash; // 其他语言用 //
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < lines.length; i++) {
|
|
128
|
+
const trimmed = lines[i].trimStart();
|
|
129
|
+
|
|
130
|
+
// 块注释延续
|
|
131
|
+
if (inBlock) {
|
|
132
|
+
mask[i] = true;
|
|
133
|
+
if (trimmed.includes('*/')) {
|
|
134
|
+
inBlock = false;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 块注释开始(同行不闭合)
|
|
140
|
+
if (usesSlash && /^\s*\/\*/.test(lines[i])) {
|
|
141
|
+
mask[i] = true;
|
|
142
|
+
if (!trimmed.includes('*/')) {
|
|
143
|
+
inBlock = true;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 行注释: // 或 /// 或 //!
|
|
149
|
+
if (usesSlash && /^\s*\/\//.test(lines[i])) {
|
|
150
|
+
mask[i] = true;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Python 行注释: #
|
|
155
|
+
if (usesHash && /^\s*#/.test(lines[i])) {
|
|
156
|
+
mask[i] = true;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Python docstring 行 (简化: 整行以 """ 或 ''' 开头)
|
|
161
|
+
if (usesHash && /^\s*("""|''')/.test(lines[i])) {
|
|
162
|
+
mask[i] = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return mask;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 从文件扩展名推断语言
|
|
172
|
+
*/
|
|
173
|
+
export function detectLanguage(filePath) {
|
|
174
|
+
if (!filePath) {
|
|
175
|
+
return 'unknown';
|
|
176
|
+
}
|
|
177
|
+
const lang = LanguageService.inferLang(filePath);
|
|
178
|
+
// 向后兼容: Guard 内置规则使用 'objc' 而非 'objectivec'
|
|
179
|
+
return LanguageService.toGuardLangId(lang);
|
|
180
|
+
}
|
|
@@ -12,12 +12,18 @@ import { unixNow } from '../../shared/utils/common.js';
|
|
|
12
12
|
export class GuardService {
|
|
13
13
|
/**
|
|
14
14
|
* @param {import('../../domain/knowledge/KnowledgeRepository.js').KnowledgeRepository} knowledgeRepository
|
|
15
|
+
* @param {object} auditLogger
|
|
16
|
+
* @param {object} gateway
|
|
17
|
+
* @param {object} [deps] - 可选依赖注入
|
|
18
|
+
* @param {import('./GuardCheckEngine.js').GuardCheckEngine} [deps.guardCheckEngine] - 核心引擎实例
|
|
15
19
|
*/
|
|
16
|
-
constructor(knowledgeRepository, auditLogger, gateway) {
|
|
20
|
+
constructor(knowledgeRepository, auditLogger, gateway, deps = {}) {
|
|
17
21
|
this.knowledgeRepository = knowledgeRepository;
|
|
18
22
|
this.auditLogger = auditLogger;
|
|
19
23
|
this.gateway = gateway;
|
|
20
24
|
this.logger = Logger.getInstance();
|
|
25
|
+
/** @type {import('./GuardCheckEngine.js').GuardCheckEngine|null} */
|
|
26
|
+
this._engine = deps.guardCheckEngine || null;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -152,7 +158,8 @@ export class GuardService {
|
|
|
152
158
|
|
|
153
159
|
/**
|
|
154
160
|
* 检查代码是否匹配 Guard 规则
|
|
155
|
-
*
|
|
161
|
+
* 优先代理到 GuardCheckEngine(完整管线: 内置 + DB + EP + Code-Level + AST),
|
|
162
|
+
* 若引擎不可用则降级为仅 DB 规则的简化检查
|
|
156
163
|
*/
|
|
157
164
|
async checkCode(code, options = {}) {
|
|
158
165
|
try {
|
|
@@ -162,51 +169,86 @@ export class GuardService {
|
|
|
162
169
|
|
|
163
170
|
const { language = null } = options;
|
|
164
171
|
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
matches: codeMatches.map((m) => ({
|
|
187
|
-
match: m[0],
|
|
188
|
-
index: m.index,
|
|
189
|
-
line: code.substring(0, m.index).split('\\n').length,
|
|
190
|
-
})),
|
|
191
|
-
matchCount: codeMatches.length,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
} catch (e) {
|
|
195
|
-
this.logger.warn('Error matching guard pattern', {
|
|
196
|
-
entryId: entry.id,
|
|
197
|
-
error: e.message,
|
|
198
|
-
});
|
|
199
|
-
}
|
|
172
|
+
// ── 优先路径: 代理到 GuardCheckEngine(完整管线)──
|
|
173
|
+
if (this._engine) {
|
|
174
|
+
try {
|
|
175
|
+
const violations = this._engine.checkCode(code, language || 'unknown', {
|
|
176
|
+
scope: 'file',
|
|
177
|
+
});
|
|
178
|
+
return violations.map((v) => ({
|
|
179
|
+
ruleId: v.ruleId,
|
|
180
|
+
ruleName: v.ruleId,
|
|
181
|
+
severity: v.severity || 'warning',
|
|
182
|
+
message: v.message || '',
|
|
183
|
+
line: v.line,
|
|
184
|
+
snippet: v.snippet,
|
|
185
|
+
matchCount: 1,
|
|
186
|
+
...(v.fixSuggestion ? { fixSuggestion: v.fixSuggestion } : {}),
|
|
187
|
+
...(v.reasoning ? { reasoning: v.reasoning } : {}),
|
|
188
|
+
}));
|
|
189
|
+
} catch (engineErr) {
|
|
190
|
+
this.logger.debug('GuardCheckEngine.checkCode failed, falling back to DB-only check', {
|
|
191
|
+
error: engineErr.message,
|
|
192
|
+
});
|
|
200
193
|
}
|
|
201
194
|
}
|
|
202
195
|
|
|
203
|
-
|
|
196
|
+
// ── 降级路径: 仅 DB 规则简化检查 ──
|
|
197
|
+
return this._checkCodeDbOnly(code, { language });
|
|
204
198
|
} catch (error) {
|
|
205
199
|
this.logger.error('Error checking code against rules', { error: error.message });
|
|
206
200
|
throw error;
|
|
207
201
|
}
|
|
208
202
|
}
|
|
209
203
|
|
|
204
|
+
/**
|
|
205
|
+
* 仅 DB 规则的简化检查(降级路径)
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
async _checkCodeDbOnly(code, options = {}) {
|
|
209
|
+
const { language = null } = options;
|
|
210
|
+
|
|
211
|
+
// V3: 使用 findActiveRules() 查询 kind='rule' + lifecycle='active'
|
|
212
|
+
let guardEntries = await this.knowledgeRepository.findActiveRules();
|
|
213
|
+
|
|
214
|
+
// 按语言过滤
|
|
215
|
+
if (language) {
|
|
216
|
+
guardEntries = guardEntries.filter((e) => !e.language || e.language === language);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const matches = [];
|
|
220
|
+
for (const entry of guardEntries) {
|
|
221
|
+
const guards = entry.constraints?.guards || [];
|
|
222
|
+
for (const guard of guards) {
|
|
223
|
+
try {
|
|
224
|
+
const regex = new RegExp(guard.pattern, 'gm');
|
|
225
|
+
const codeMatches = [...code.matchAll(regex)];
|
|
226
|
+
if (codeMatches.length > 0) {
|
|
227
|
+
matches.push({
|
|
228
|
+
ruleId: entry.id,
|
|
229
|
+
ruleName: entry.title,
|
|
230
|
+
severity: guard.severity || 'warning',
|
|
231
|
+
message: guard.message || '',
|
|
232
|
+
matches: codeMatches.map((m) => ({
|
|
233
|
+
match: m[0],
|
|
234
|
+
index: m.index,
|
|
235
|
+
line: code.substring(0, m.index).split('\\n').length,
|
|
236
|
+
})),
|
|
237
|
+
matchCount: codeMatches.length,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
this.logger.warn('Error matching guard pattern', {
|
|
242
|
+
entryId: entry.id,
|
|
243
|
+
error: e.message,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return matches;
|
|
250
|
+
}
|
|
251
|
+
|
|
210
252
|
/**
|
|
211
253
|
* 查询规则列表 (kind='rule' + knowledgeType='boundary-constraint')
|
|
212
254
|
*/
|
|
@@ -659,7 +659,7 @@ export class SearchEngine {
|
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
/**
|
|
662
|
-
* 补充详细字段(content / description / trigger
|
|
662
|
+
* 补充详细字段(content / description / trigger / delivery 字段)— 批量 IN 查询
|
|
663
663
|
* 用于向量搜索结果与 BM25 结果的一致性
|
|
664
664
|
*/
|
|
665
665
|
_supplementDetails(items) {
|
|
@@ -674,7 +674,8 @@ export class SearchEngine {
|
|
|
674
674
|
rows = this.db
|
|
675
675
|
.prepare(
|
|
676
676
|
`SELECT id, content, description, trigger, headers, moduleName,
|
|
677
|
-
tags, language, category, updatedAt, createdAt, quality, stats, difficulty
|
|
677
|
+
tags, language, category, updatedAt, createdAt, quality, stats, difficulty,
|
|
678
|
+
whenClause, doClause
|
|
678
679
|
FROM knowledge_entries WHERE id IN (${placeholders})`
|
|
679
680
|
)
|
|
680
681
|
.all(...ids);
|
|
@@ -694,6 +695,13 @@ export class SearchEngine {
|
|
|
694
695
|
if (row.moduleName) {
|
|
695
696
|
item.moduleName = row.moduleName;
|
|
696
697
|
}
|
|
698
|
+
// Cursor 交付字段 — 供 Agent 投影生成 actionHint
|
|
699
|
+
if (!item.whenClause && row.whenClause) {
|
|
700
|
+
item.whenClause = row.whenClause;
|
|
701
|
+
}
|
|
702
|
+
if (!item.doClause && row.doClause) {
|
|
703
|
+
item.doClause = row.doClause;
|
|
704
|
+
}
|
|
697
705
|
// 排序信号补充 — 确保 Funnel/Ranker 有真实数据
|
|
698
706
|
if (!item.language && row.language) {
|
|
699
707
|
item.language = row.language;
|