autosnippet 3.0.10 → 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.
Files changed (56) hide show
  1. package/bin/cli.js +64 -1
  2. package/config/default.json +9 -0
  3. package/dashboard/dist/assets/{index-I2ySoCmF.js → index-Bnm26ulL.js} +47 -47
  4. package/dashboard/dist/index.html +1 -1
  5. package/lib/cli/SetupService.js +92 -5
  6. package/lib/cli/UpgradeService.js +14 -5
  7. package/lib/core/discovery/GenericDiscoverer.js +4 -28
  8. package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +246 -0
  9. package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +80 -0
  10. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +275 -0
  11. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +600 -0
  12. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +125 -342
  13. package/lib/external/mcp/handlers/bootstrap/refine.js +362 -0
  14. package/lib/external/mcp/handlers/bootstrap.js +6 -590
  15. package/lib/external/mcp/handlers/browse.js +119 -9
  16. package/lib/external/mcp/handlers/guard.js +25 -6
  17. package/lib/external/mcp/handlers/search.js +56 -24
  18. package/lib/http/routes/guardRules.js +9 -17
  19. package/lib/injection/ServiceContainer.js +12 -3
  20. package/lib/platform/ios/xcode/XcodeImportResolver.js +434 -0
  21. package/lib/platform/ios/xcode/XcodeIntegration.js +40 -659
  22. package/lib/platform/ios/xcode/XcodeWriteUtils.js +220 -0
  23. package/lib/service/chat/ChatAgent.js +39 -418
  24. package/lib/service/chat/ChatAgentPrompts.js +149 -0
  25. package/lib/service/chat/ChatAgentTasks.js +297 -0
  26. package/lib/service/chat/tools/_shared.js +61 -0
  27. package/lib/service/chat/tools/ai-analysis.js +284 -0
  28. package/lib/service/chat/tools/ast-graph.js +681 -0
  29. package/lib/service/chat/tools/composite.js +496 -0
  30. package/lib/service/chat/tools/guard.js +265 -0
  31. package/lib/service/chat/tools/index.js +250 -0
  32. package/lib/service/chat/tools/infrastructure.js +222 -0
  33. package/lib/service/chat/tools/knowledge-graph.js +234 -0
  34. package/lib/service/chat/tools/lifecycle.js +469 -0
  35. package/lib/service/chat/tools/project-access.js +923 -0
  36. package/lib/service/chat/tools/query.js +264 -0
  37. package/lib/service/chat/tools.js +14 -3994
  38. package/lib/service/cursor/AgentInstructionsGenerator.js +395 -0
  39. package/lib/service/cursor/CursorDeliveryPipeline.js +70 -11
  40. package/lib/service/cursor/FileProtection.js +116 -0
  41. package/lib/service/cursor/KnowledgeCompressor.js +61 -11
  42. package/lib/service/cursor/SkillsSyncer.js +5 -3
  43. package/lib/service/cursor/TopicClassifier.js +19 -3
  44. package/lib/service/guard/ExclusionManager.js +26 -2
  45. package/lib/service/guard/GuardCheckEngine.js +38 -370
  46. package/lib/service/guard/GuardCodeChecks.js +362 -0
  47. package/lib/service/guard/GuardCrossFileChecks.js +307 -0
  48. package/lib/service/guard/GuardPatternUtils.js +180 -0
  49. package/lib/service/guard/GuardService.js +80 -38
  50. package/lib/service/module/ModuleService.js +1 -0
  51. package/lib/service/search/SearchEngine.js +10 -2
  52. package/lib/service/wiki/WikiGenerator.js +226 -1532
  53. package/lib/service/wiki/WikiRenderers.js +1878 -0
  54. package/lib/service/wiki/WikiUtils.js +907 -0
  55. package/lib/shared/LanguageService.js +299 -0
  56. 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
- * 查询所有 active rule 实体的 constraints.guards[]
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
- // V3: 使用 findActiveRules() 查询 kind='rule' + lifecycle='active'
166
- let guardEntries = await this.knowledgeRepository.findActiveRules();
167
-
168
- // 按语言过滤
169
- if (language) {
170
- guardEntries = guardEntries.filter((e) => !e.language || e.language === language);
171
- }
172
-
173
- const matches = [];
174
- for (const entry of guardEntries) {
175
- const guards = entry.constraints?.guards || [];
176
- for (const guard of guards) {
177
- try {
178
- const regex = new RegExp(guard.pattern, 'gm');
179
- const codeMatches = [...code.matchAll(regex)];
180
- if (codeMatches.length > 0) {
181
- matches.push({
182
- ruleId: entry.id,
183
- ruleName: entry.title,
184
- severity: guard.severity || 'warning',
185
- message: guard.message || '',
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
- return matches;
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
  */
@@ -313,6 +313,7 @@ export class ModuleService {
313
313
 
314
314
  return {
315
315
  projectRoot: this.#projectRoot,
316
+ projectName: _pathBasename(this.#projectRoot) || '',
316
317
  primaryLanguage: primaryDiscoverer
317
318
  ? this.#discovererToLanguage(primaryDiscoverer.id)
318
319
  : 'unknown',
@@ -659,7 +659,7 @@ export class SearchEngine {
659
659
  }
660
660
 
661
661
  /**
662
- * 补充详细字段(content / description / trigger)— 批量 IN 查询
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;