autosnippet 3.0.0 → 3.0.2

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 (290) hide show
  1. package/README.md +230 -324
  2. package/bin/api-server.js +1 -1
  3. package/bin/cli.js +204 -244
  4. package/bin/mcp-server.js +5 -3
  5. package/config/knowledge-base.config.js +132 -132
  6. package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
  7. package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
  8. package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
  9. package/dashboard/dist/index.html +3 -3
  10. package/lib/bootstrap.js +8 -8
  11. package/lib/cli/AiScanService.js +86 -40
  12. package/lib/cli/KnowledgeSyncService.js +113 -74
  13. package/lib/cli/SetupService.js +439 -277
  14. package/lib/cli/UpgradeService.js +63 -100
  15. package/lib/core/AstAnalyzer.js +276 -597
  16. package/lib/core/ast/ProjectGraph.js +101 -40
  17. package/lib/core/ast/ensure-grammars.js +232 -0
  18. package/lib/core/ast/index.js +115 -0
  19. package/lib/core/ast/lang-dart.js +661 -0
  20. package/lib/core/ast/lang-go.js +530 -0
  21. package/lib/core/ast/lang-java.js +435 -0
  22. package/lib/core/ast/lang-javascript.js +272 -0
  23. package/lib/core/ast/lang-kotlin.js +423 -0
  24. package/lib/core/ast/lang-objc.js +388 -0
  25. package/lib/core/ast/lang-python.js +371 -0
  26. package/lib/core/ast/lang-swift.js +337 -0
  27. package/lib/core/ast/lang-typescript.js +503 -0
  28. package/lib/core/capability/CapabilityProbe.js +18 -9
  29. package/lib/core/constitution/Constitution.js +2 -3
  30. package/lib/core/constitution/ConstitutionValidator.js +65 -24
  31. package/lib/core/discovery/DartDiscoverer.js +534 -0
  32. package/lib/core/discovery/DiscovererRegistry.js +83 -0
  33. package/lib/core/discovery/GenericDiscoverer.js +225 -0
  34. package/lib/core/discovery/GoDiscoverer.js +541 -0
  35. package/lib/core/discovery/JvmDiscoverer.js +506 -0
  36. package/lib/core/discovery/NodeDiscoverer.js +466 -0
  37. package/lib/core/discovery/ProjectDiscoverer.js +93 -0
  38. package/lib/core/discovery/PythonDiscoverer.js +338 -0
  39. package/lib/core/discovery/SpmDiscoverer.js +5 -0
  40. package/lib/core/discovery/index.js +53 -0
  41. package/lib/core/enhancement/EnhancementPack.js +71 -0
  42. package/lib/core/enhancement/EnhancementRegistry.js +47 -0
  43. package/lib/core/enhancement/android-enhancement.js +102 -0
  44. package/lib/core/enhancement/django-enhancement.js +70 -0
  45. package/lib/core/enhancement/fastapi-enhancement.js +63 -0
  46. package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
  47. package/lib/core/enhancement/go-web-enhancement.js +201 -0
  48. package/lib/core/enhancement/index.js +65 -0
  49. package/lib/core/enhancement/node-server-enhancement.js +88 -0
  50. package/lib/core/enhancement/react-enhancement.js +86 -0
  51. package/lib/core/enhancement/spring-enhancement.js +112 -0
  52. package/lib/core/enhancement/vue-enhancement.js +96 -0
  53. package/lib/core/gateway/Gateway.js +8 -9
  54. package/lib/core/gateway/GatewayActionRegistry.js +1 -1
  55. package/lib/core/permission/PermissionManager.js +12 -8
  56. package/lib/domain/index.js +13 -9
  57. package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
  58. package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
  59. package/lib/domain/knowledge/Lifecycle.js +22 -22
  60. package/lib/domain/knowledge/index.js +9 -12
  61. package/lib/domain/knowledge/values/Constraints.js +31 -21
  62. package/lib/domain/knowledge/values/Content.js +21 -13
  63. package/lib/domain/knowledge/values/Quality.js +31 -18
  64. package/lib/domain/knowledge/values/Reasoning.js +20 -12
  65. package/lib/domain/knowledge/values/Relations.js +37 -25
  66. package/lib/domain/knowledge/values/Stats.js +18 -12
  67. package/lib/domain/knowledge/values/index.js +4 -3
  68. package/lib/domain/snippet/Snippet.js +35 -10
  69. package/lib/external/ai/AiFactory.js +48 -16
  70. package/lib/external/ai/AiProvider.js +184 -90
  71. package/lib/external/ai/providers/ClaudeProvider.js +25 -12
  72. package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
  73. package/lib/external/ai/providers/MockProvider.js +9 -3
  74. package/lib/external/ai/providers/OpenAiProvider.js +51 -29
  75. package/lib/external/mcp/McpServer.js +66 -36
  76. package/lib/external/mcp/errorHandler.js +23 -11
  77. package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
  78. package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
  79. package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
  80. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
  81. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
  82. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
  83. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
  84. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
  85. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
  86. package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
  87. package/lib/external/mcp/handlers/bootstrap.js +691 -168
  88. package/lib/external/mcp/handlers/browse.js +66 -22
  89. package/lib/external/mcp/handlers/candidate.js +118 -35
  90. package/lib/external/mcp/handlers/consolidated.js +49 -17
  91. package/lib/external/mcp/handlers/guard.js +104 -39
  92. package/lib/external/mcp/handlers/knowledge.js +60 -36
  93. package/lib/external/mcp/handlers/search.js +43 -14
  94. package/lib/external/mcp/handlers/skill.js +120 -45
  95. package/lib/external/mcp/handlers/structure.js +240 -86
  96. package/lib/external/mcp/handlers/system.js +42 -12
  97. package/lib/external/mcp/handlers/wiki.js +58 -33
  98. package/lib/external/mcp/tools.js +306 -123
  99. package/lib/http/HttpServer.js +72 -47
  100. package/lib/http/middleware/RateLimiter.js +5 -3
  101. package/lib/http/middleware/errorHandler.js +6 -1
  102. package/lib/http/middleware/requestLogger.js +14 -3
  103. package/lib/http/middleware/roleResolver.js +30 -23
  104. package/lib/http/routes/ai.js +387 -265
  105. package/lib/http/routes/auth.js +81 -61
  106. package/lib/http/routes/candidates.js +430 -320
  107. package/lib/http/routes/commands.js +289 -189
  108. package/lib/http/routes/extract.js +158 -125
  109. package/lib/http/routes/guardRules.js +309 -217
  110. package/lib/http/routes/knowledge.js +213 -154
  111. package/lib/http/routes/modules.js +578 -0
  112. package/lib/http/routes/monitoring.js +6 -6
  113. package/lib/http/routes/recipes.js +104 -93
  114. package/lib/http/routes/search.js +361 -305
  115. package/lib/http/routes/skills.js +145 -98
  116. package/lib/http/routes/snippets.js +42 -30
  117. package/lib/http/routes/spm.js +3 -405
  118. package/lib/http/routes/violations.js +113 -93
  119. package/lib/http/routes/wiki.js +211 -170
  120. package/lib/http/utils/routeHelpers.js +3 -1
  121. package/lib/http/utils/sse-sessions.js +16 -6
  122. package/lib/http/utils/sse.js +15 -5
  123. package/lib/infrastructure/audit/AuditLogger.js +5 -2
  124. package/lib/infrastructure/audit/AuditStore.js +10 -7
  125. package/lib/infrastructure/cache/CacheService.js +3 -1
  126. package/lib/infrastructure/cache/GraphCache.js +8 -4
  127. package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
  128. package/lib/infrastructure/config/ConfigLoader.js +9 -5
  129. package/lib/infrastructure/config/Defaults.js +30 -10
  130. package/lib/infrastructure/config/Paths.js +28 -8
  131. package/lib/infrastructure/config/TriggerSymbol.js +22 -10
  132. package/lib/infrastructure/database/DatabaseConnection.js +15 -10
  133. package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
  134. package/lib/infrastructure/external/ClipboardManager.js +6 -2
  135. package/lib/infrastructure/external/NativeUi.js +50 -43
  136. package/lib/infrastructure/external/OpenBrowser.js +14 -17
  137. package/lib/infrastructure/external/XcodeAutomation.js +14 -258
  138. package/lib/infrastructure/logging/Logger.js +46 -30
  139. package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
  140. package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
  141. package/lib/infrastructure/paths/HeaderResolver.js +25 -9
  142. package/lib/infrastructure/paths/PathFinder.js +34 -12
  143. package/lib/infrastructure/plugin/PluginManager.js +26 -8
  144. package/lib/infrastructure/realtime/RealtimeService.js +2 -2
  145. package/lib/infrastructure/vector/Chunker.js +22 -7
  146. package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
  147. package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
  148. package/lib/infrastructure/vector/VectorStore.js +28 -10
  149. package/lib/injection/ServiceContainer.js +247 -93
  150. package/lib/platform/ios/index.js +63 -0
  151. package/lib/platform/ios/routes/spm.js +437 -0
  152. package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
  153. package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
  154. package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
  155. package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
  156. package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
  157. package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
  158. package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
  159. package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
  160. package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
  161. package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
  162. package/lib/repository/base/BaseRepository.js +7 -9
  163. package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
  164. package/lib/repository/token/TokenUsageStore.js +4 -2
  165. package/lib/service/automation/ActionPipeline.js +1 -1
  166. package/lib/service/automation/AutomationOrchestrator.js +8 -4
  167. package/lib/service/automation/ContextCollector.js +7 -5
  168. package/lib/service/automation/DirectiveDetector.js +23 -16
  169. package/lib/service/automation/FileWatcher.js +112 -56
  170. package/lib/service/automation/TriggerResolver.js +6 -4
  171. package/lib/service/automation/handlers/AlinkHandler.js +24 -12
  172. package/lib/service/automation/handlers/CreateHandler.js +19 -20
  173. package/lib/service/automation/handlers/DraftHandler.js +14 -8
  174. package/lib/service/automation/handlers/GuardHandler.js +93 -63
  175. package/lib/service/automation/handlers/HeaderHandler.js +1 -6
  176. package/lib/service/automation/handlers/SearchHandler.js +155 -88
  177. package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
  178. package/lib/service/candidate/SimilarityService.js +25 -9
  179. package/lib/service/chat/AnalystAgent.js +50 -24
  180. package/lib/service/chat/CandidateGuardrail.js +143 -17
  181. package/lib/service/chat/ChatAgent.js +759 -243
  182. package/lib/service/chat/ContextWindow.js +116 -71
  183. package/lib/service/chat/ConversationStore.js +77 -36
  184. package/lib/service/chat/EpisodicConsolidator.js +47 -23
  185. package/lib/service/chat/HandoffProtocol.js +98 -22
  186. package/lib/service/chat/Memory.js +34 -14
  187. package/lib/service/chat/ProducerAgent.js +40 -20
  188. package/lib/service/chat/ProjectSemanticMemory.js +109 -78
  189. package/lib/service/chat/ReasoningLayer.js +148 -70
  190. package/lib/service/chat/ReasoningTrace.js +44 -32
  191. package/lib/service/chat/TaskPipeline.js +39 -19
  192. package/lib/service/chat/ToolRegistry.js +48 -29
  193. package/lib/service/chat/WorkingMemory.js +44 -18
  194. package/lib/service/chat/tools.js +1096 -494
  195. package/lib/service/context/RecipeExtractor.js +132 -51
  196. package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
  197. package/lib/service/cursor/KnowledgeCompressor.js +25 -22
  198. package/lib/service/cursor/RulesGenerator.js +13 -7
  199. package/lib/service/cursor/SkillsSyncer.js +77 -27
  200. package/lib/service/cursor/TokenBudget.js +2 -2
  201. package/lib/service/cursor/TopicClassifier.js +54 -20
  202. package/lib/service/guard/ComplianceReporter.js +55 -43
  203. package/lib/service/guard/ExclusionManager.js +67 -29
  204. package/lib/service/guard/GuardCheckEngine.js +381 -86
  205. package/lib/service/guard/GuardFeedbackLoop.js +22 -10
  206. package/lib/service/guard/GuardService.js +29 -19
  207. package/lib/service/guard/RuleLearner.js +55 -23
  208. package/lib/service/guard/SourceFileCollector.js +27 -20
  209. package/lib/service/guard/ViolationsStore.js +43 -38
  210. package/lib/service/knowledge/CodeEntityGraph.js +147 -82
  211. package/lib/service/knowledge/ConfidenceRouter.js +12 -10
  212. package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
  213. package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
  214. package/lib/service/knowledge/KnowledgeService.js +222 -112
  215. package/lib/service/module/ModuleService.js +969 -0
  216. package/lib/service/quality/FeedbackCollector.js +27 -15
  217. package/lib/service/quality/QualityScorer.js +78 -24
  218. package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
  219. package/lib/service/recipe/RecipeParser.js +78 -45
  220. package/lib/service/search/CoarseRanker.js +43 -28
  221. package/lib/service/search/CrossEncoderReranker.js +32 -21
  222. package/lib/service/search/InvertedIndex.js +21 -7
  223. package/lib/service/search/MultiSignalRanker.js +90 -28
  224. package/lib/service/search/RetrievalFunnel.js +45 -24
  225. package/lib/service/search/SearchEngine.js +255 -103
  226. package/lib/service/skills/EventAggregator.js +32 -15
  227. package/lib/service/skills/SignalCollector.js +140 -64
  228. package/lib/service/skills/SkillAdvisor.js +79 -42
  229. package/lib/service/skills/SkillHooks.js +16 -14
  230. package/lib/service/snippet/PlaceholderConverter.js +5 -0
  231. package/lib/service/snippet/SnippetFactory.js +116 -99
  232. package/lib/service/snippet/SnippetInstaller.js +234 -62
  233. package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
  234. package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
  235. package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
  236. package/lib/service/wiki/WikiGenerator.js +637 -263
  237. package/lib/shared/DimensionCopyRegistry.js +472 -0
  238. package/lib/shared/LanguageService.js +399 -0
  239. package/lib/shared/PathGuard.js +45 -28
  240. package/lib/shared/RecipeReadinessChecker.js +72 -12
  241. package/lib/shared/constants.js +41 -41
  242. package/lib/shared/errors/BaseError.js +2 -2
  243. package/lib/shared/errors/index.js +4 -4
  244. package/lib/shared/similarity.js +25 -8
  245. package/lib/shared/token-utils.js +6 -2
  246. package/lib/shared/utils/common.js +12 -4
  247. package/package.json +49 -13
  248. package/scripts/bench-real-projects.mjs +256 -0
  249. package/scripts/build-native-ui.js +30 -30
  250. package/scripts/clear-old-vector-index.js +5 -35
  251. package/scripts/clear-vector-cache.js +7 -37
  252. package/scripts/collect-test-project-stats.mjs +160 -0
  253. package/scripts/diagnose-mcp.js +41 -32
  254. package/scripts/ensure-parse-package.js +6 -9
  255. package/scripts/generate-recipe-drafts.js +116 -77
  256. package/scripts/init-db.js +3 -20
  257. package/scripts/init-snippets.js +305 -0
  258. package/scripts/init-vector-db.js +173 -170
  259. package/scripts/install-cursor-skill.js +148 -104
  260. package/scripts/install-full.js +8 -21
  261. package/scripts/install-vscode-copilot.js +146 -145
  262. package/scripts/migrate-md-to-knowledge.mjs +139 -151
  263. package/scripts/postinstall-safe.js +5 -17
  264. package/scripts/recipe-audit.js +106 -82
  265. package/scripts/release.js +283 -323
  266. package/scripts/setup-mcp-config.js +60 -52
  267. package/scripts/verify-context-api.js +20 -20
  268. package/skills/autosnippet-analysis/SKILL.md +10 -6
  269. package/skills/autosnippet-candidates/SKILL.md +27 -26
  270. package/skills/autosnippet-coldstart/SKILL.md +555 -38
  271. package/skills/autosnippet-concepts/SKILL.md +349 -337
  272. package/skills/autosnippet-create/SKILL.md +5 -5
  273. package/skills/autosnippet-reference-dart/SKILL.md +543 -0
  274. package/skills/autosnippet-reference-go/SKILL.md +539 -0
  275. package/skills/autosnippet-reference-java/SKILL.md +534 -0
  276. package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
  277. package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
  278. package/skills/autosnippet-reference-objc/SKILL.md +29 -6
  279. package/skills/autosnippet-reference-python/SKILL.md +800 -0
  280. package/skills/autosnippet-reference-swift/SKILL.md +70 -14
  281. package/skills/autosnippet-structure/SKILL.md +4 -4
  282. package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
  283. package/templates/recipes-setup/README.md +2 -2
  284. package/templates/recipes-setup/_template.md +1 -1
  285. package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
  286. package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
  287. package/resources/asd-entry/main.swift +0 -159
  288. package/scripts/build-asd-entry.js +0 -51
  289. package/scripts/init-xcode-snippets.js +0 -311
  290. package/template.json +0 -39
@@ -8,13 +8,19 @@ import path from 'node:path';
8
8
  import { envelope } from '../envelope.js';
9
9
 
10
10
  export async function guardCheck(ctx, args) {
11
- const { GuardCheckEngine, detectLanguage } = await import('../../../service/guard/GuardCheckEngine.js');
11
+ const { GuardCheckEngine, detectLanguage } = await import(
12
+ '../../../service/guard/GuardCheckEngine.js'
13
+ );
12
14
 
13
15
  // 输入校验:空代码直接返回
14
16
  if (!args.code || !args.code.trim()) {
15
17
  return envelope({
16
18
  success: true,
17
- data: { language: args.language || 'unknown', violations: [], summary: { total: 0, errors: 0, warnings: 0 } },
19
+ data: {
20
+ language: args.language || 'unknown',
21
+ violations: [],
22
+ summary: { total: 0, errors: 0, warnings: 0 },
23
+ },
18
24
  meta: { tool: 'autosnippet_guard', note: 'Empty code — skipped' },
19
25
  });
20
26
  }
@@ -30,10 +36,14 @@ export async function guardCheck(ctx, args) {
30
36
  if (skillHooks.has('onGuardCheck')) {
31
37
  for (let i = 0; i < violations.length; i++) {
32
38
  const modified = await skillHooks.run('onGuardCheck', violations[i], { language });
33
- if (modified && typeof modified === 'object') violations[i] = modified;
39
+ if (modified && typeof modified === 'object') {
40
+ violations[i] = modified;
41
+ }
34
42
  }
35
43
  }
36
- } catch { /* skillHooks not available */ }
44
+ } catch {
45
+ /* skillHooks not available */
46
+ }
37
47
 
38
48
  const warnings = [];
39
49
  if (language === 'unknown') {
@@ -42,7 +52,16 @@ export async function guardCheck(ctx, args) {
42
52
 
43
53
  return envelope({
44
54
  success: true,
45
- data: { language, violations, summary: { total: violations.length, errors: violations.filter(v => v.severity === 'error').length, warnings: violations.filter(v => v.severity === 'warning').length }, ...(warnings.length ? { warnings } : {}) },
55
+ data: {
56
+ language,
57
+ violations,
58
+ summary: {
59
+ total: violations.length,
60
+ errors: violations.filter((v) => v.severity === 'error').length,
61
+ warnings: violations.filter((v) => v.severity === 'warning').length,
62
+ },
63
+ ...(warnings.length ? { warnings } : {}),
64
+ },
46
65
  meta: { tool: 'autosnippet_guard' },
47
66
  });
48
67
  }
@@ -58,7 +77,7 @@ export async function guardAuditFiles(ctx, args) {
58
77
  const engine = new GuardCheckEngine(db);
59
78
 
60
79
  // 补充缺失的 content(从磁盘读取)
61
- const filesToAudit = args.files.map(f => ({
80
+ const filesToAudit = args.files.map((f) => ({
62
81
  path: f.path,
63
82
  content: f.content || (fs.existsSync(f.path) ? fs.readFileSync(f.path, 'utf8') : ''),
64
83
  }));
@@ -68,7 +87,7 @@ export async function guardAuditFiles(ctx, args) {
68
87
  // 写入 ViolationsStore + GuardFeedbackLoop
69
88
  try {
70
89
  const violationsStore = ctx.container.get('violationsStore');
71
- for (const fileResult of (result.files || [])) {
90
+ for (const fileResult of result.files || []) {
72
91
  if (fileResult.violations.length > 0) {
73
92
  violationsStore.appendRun({
74
93
  filePath: fileResult.filePath,
@@ -81,21 +100,27 @@ export async function guardAuditFiles(ctx, args) {
81
100
  try {
82
101
  const feedbackLoop = ctx.container.get('guardFeedbackLoop');
83
102
  feedbackLoop.processFixDetection(fileResult, fileResult.filePath);
84
- } catch { /* guardFeedbackLoop not available */ }
103
+ } catch {
104
+ /* guardFeedbackLoop not available */
105
+ }
85
106
  }
86
- } catch { /* ViolationsStore not available */ }
107
+ } catch {
108
+ /* ViolationsStore not available */
109
+ }
87
110
 
88
111
  return envelope({
89
112
  success: true,
90
113
  data: {
91
114
  summary: result.summary,
92
- files: result.files.map(f => ({
115
+ files: result.files.map((f) => ({
93
116
  filePath: f.filePath,
94
117
  language: f.language,
95
118
  violations: f.violations,
96
119
  summary: f.summary,
97
120
  })),
98
- ...(result.crossFileViolations?.length ? { crossFileViolations: result.crossFileViolations } : {}),
121
+ ...(result.crossFileViolations?.length
122
+ ? { crossFileViolations: result.crossFileViolations }
123
+ : {}),
99
124
  },
100
125
  meta: { tool: 'autosnippet_guard' },
101
126
  });
@@ -107,13 +132,25 @@ export async function scanProject(ctx, args) {
107
132
  const contentMaxLines = args.contentMaxLines || 100;
108
133
 
109
134
  const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
110
- const { SpmService } = await import('../../../service/spm/SpmService.js');
111
- const spm = new SpmService(projectRoot);
112
- await spm.load();
113
- const allTargets = await spm.listTargets();
135
+
136
+ // 优先使用 ModuleService(多语言统一入口),回退到 SpmService
137
+ let service;
138
+ try {
139
+ const { ModuleService } = await import('../../../service/module/ModuleService.js');
140
+ service = new ModuleService(projectRoot);
141
+ } catch {
142
+ const { SpmService } = await import('../../../platform/ios/spm/SpmService.js');
143
+ service = new SpmService(projectRoot);
144
+ }
145
+ await service.load();
146
+ const allTargets = await service.listTargets();
114
147
 
115
148
  if (!allTargets || allTargets.length === 0) {
116
- return envelope({ success: true, data: { targets: [], files: [], guardAudit: null, message: 'No SPM targets found' }, meta: { tool: 'autosnippet_bootstrap' } });
149
+ return envelope({
150
+ success: true,
151
+ data: { targets: [], files: [], guardAudit: null, message: 'No module targets found' },
152
+ meta: { tool: 'autosnippet_bootstrap' },
153
+ });
117
154
  }
118
155
 
119
156
  // 收集所有文件(去重)
@@ -121,12 +158,19 @@ export async function scanProject(ctx, args) {
121
158
  const allFiles = [];
122
159
  for (const t of allTargets) {
123
160
  try {
124
- const fileList = await spm.getTargetFiles(t);
161
+ const fileList = await service.getTargetFiles(t);
125
162
  for (const f of fileList) {
126
163
  const fp = typeof f === 'string' ? f : f.path;
127
- if (seenPaths.has(fp)) continue;
164
+ if (seenPaths.has(fp)) {
165
+ continue;
166
+ }
128
167
  seenPaths.add(fp);
129
- const entry = { name: f.name || path.basename(fp), path: fp, relativePath: f.relativePath || path.basename(fp), targetName: t.name };
168
+ const entry = {
169
+ name: f.name || path.basename(fp),
170
+ path: fp,
171
+ relativePath: f.relativePath || path.basename(fp),
172
+ targetName: t.name,
173
+ };
130
174
  if (includeContent) {
131
175
  try {
132
176
  const raw = fs.readFileSync(fp, 'utf8');
@@ -134,13 +178,22 @@ export async function scanProject(ctx, args) {
134
178
  entry.content = lines.slice(0, contentMaxLines).join('\n');
135
179
  entry.totalLines = lines.length;
136
180
  entry.truncated = lines.length > contentMaxLines;
137
- } catch { entry.content = ''; entry.totalLines = 0; }
181
+ } catch {
182
+ entry.content = '';
183
+ entry.totalLines = 0;
184
+ }
138
185
  }
139
186
  allFiles.push(entry);
140
- if (allFiles.length >= maxFiles) break;
187
+ if (allFiles.length >= maxFiles) {
188
+ break;
189
+ }
141
190
  }
142
- } catch { /* skip target */ }
143
- if (allFiles.length >= maxFiles) break;
191
+ } catch {
192
+ /* skip target */
193
+ }
194
+ if (allFiles.length >= maxFiles) {
195
+ break;
196
+ }
144
197
  }
145
198
 
146
199
  // Guard 审计
@@ -150,7 +203,7 @@ export async function scanProject(ctx, args) {
150
203
  const db = ctx.container.get('database');
151
204
  const engine = new GuardCheckEngine(db);
152
205
 
153
- const filesToAudit = allFiles.map(f => {
206
+ const filesToAudit = allFiles.map((f) => {
154
207
  const content = f.content || (fs.existsSync(f.path) ? fs.readFileSync(f.path, 'utf8') : '');
155
208
  return { path: f.path, content };
156
209
  });
@@ -159,7 +212,7 @@ export async function scanProject(ctx, args) {
159
212
  // 写入 ViolationsStore
160
213
  try {
161
214
  const violationsStore = ctx.container.get('violationsStore');
162
- for (const fileResult of (guardAudit.files || [])) {
215
+ for (const fileResult of guardAudit.files || []) {
163
216
  if (fileResult.violations.length > 0) {
164
217
  violationsStore.appendRun({
165
218
  filePath: fileResult.filePath,
@@ -168,34 +221,46 @@ export async function scanProject(ctx, args) {
168
221
  });
169
222
  }
170
223
  }
171
- } catch { /* store not available */ }
224
+ } catch {
225
+ /* store not available */
226
+ }
172
227
  } catch (e) {
173
228
  ctx.logger.warn(`[MCP] Guard audit in scanProject failed: ${e.message}`);
174
229
  }
175
230
 
176
231
  // 构建文件列表摘要
177
- const fileSummary = allFiles.map(f => {
232
+ const fileSummary = allFiles.map((f) => {
178
233
  const base = { name: f.name, path: f.relativePath, targetName: f.targetName };
179
- if (includeContent) { base.content = f.content; base.totalLines = f.totalLines; base.truncated = f.truncated; }
234
+ if (includeContent) {
235
+ base.content = f.content;
236
+ base.totalLines = f.totalLines;
237
+ base.truncated = f.truncated;
238
+ }
180
239
  return base;
181
240
  });
182
241
 
183
242
  return envelope({
184
243
  success: true,
185
244
  data: {
186
- targets: allTargets.map(t => ({ name: t.name, type: t.type, packageName: t.packageName })),
245
+ targets: allTargets.map((t) => ({ name: t.name, type: t.type, packageName: t.packageName })),
187
246
  files: fileSummary,
188
247
  fileCount: allFiles.length,
189
- guardAudit: guardAudit ? {
190
- summary: guardAudit.summary,
191
- filesWithViolations: (guardAudit.files || []).filter(f => f.violations.length > 0).map(f => ({
192
- filePath: f.filePath,
193
- language: f.language,
194
- violations: f.violations,
195
- summary: f.summary,
196
- })),
197
- ...(guardAudit.crossFileViolations?.length ? { crossFileViolations: guardAudit.crossFileViolations } : {}),
198
- } : null,
248
+ guardAudit: guardAudit
249
+ ? {
250
+ summary: guardAudit.summary,
251
+ filesWithViolations: (guardAudit.files || [])
252
+ .filter((f) => f.violations.length > 0)
253
+ .map((f) => ({
254
+ filePath: f.filePath,
255
+ language: f.language,
256
+ violations: f.violations,
257
+ summary: f.summary,
258
+ })),
259
+ ...(guardAudit.crossFileViolations?.length
260
+ ? { crossFileViolations: guardAudit.crossFileViolations }
261
+ : {}),
262
+ }
263
+ : null,
199
264
  },
200
265
  meta: { tool: 'autosnippet_bootstrap' },
201
266
  });
@@ -3,8 +3,8 @@
3
3
  * submitKnowledge, submitKnowledgeBatch, knowledgeLifecycle
4
4
  */
5
5
 
6
- import { envelope } from '../envelope.js';
7
6
  import { checkRecipeReadiness } from '../../../shared/RecipeReadinessChecker.js';
7
+ import { envelope } from '../envelope.js';
8
8
 
9
9
  // ─── 限流 ──────────────────────────────────────────────────
10
10
 
@@ -36,7 +36,9 @@ function _enrichToV3(args, container) {
36
36
  const data = { ...args };
37
37
 
38
38
  // 来源标记(非 Cursor 职责)
39
- if (!data.source) data.source = 'mcp';
39
+ if (!data.source) {
40
+ data.source = 'mcp';
41
+ }
40
42
 
41
43
  // QualityScorer 评分(程序化)
42
44
  try {
@@ -55,7 +57,9 @@ function _enrichToV3(args, container) {
55
57
  grade: scoreResult.grade || '',
56
58
  };
57
59
  }
58
- } catch { /* best effort */ }
60
+ } catch {
61
+ /* best effort */
62
+ }
59
63
 
60
64
  // RecipeExtractor 语义标签(程序化)
61
65
  try {
@@ -64,17 +68,25 @@ function _enrichToV3(args, container) {
64
68
  const codeForTags = data.content?.pattern || '';
65
69
  if (codeForTags) {
66
70
  const extracted = recipeExtractor.extractFromContent(
67
- codeForTags, `${data.title || 'unknown'}.${data.language || 'swift'}`, ''
71
+ codeForTags,
72
+ `${data.title || 'unknown'}.${data.language || 'unknown'}`,
73
+ ''
68
74
  );
69
75
  if (extracted.semanticTags?.length > 0) {
70
76
  data.tags = [...new Set([...(data.tags || []), ...extracted.semanticTags])];
71
77
  }
72
- if ((!data.category || data.category === 'Utility') && extracted.category && extracted.category !== 'general') {
78
+ if (
79
+ (!data.category || data.category === 'Utility') &&
80
+ extracted.category &&
81
+ extracted.category !== 'general'
82
+ ) {
73
83
  data.category = extracted.category;
74
84
  }
75
85
  }
76
86
  }
77
- } catch { /* best effort */ }
87
+ } catch {
88
+ /* best effort */
89
+ }
78
90
 
79
91
  return data;
80
92
  }
@@ -90,7 +102,9 @@ function _enrichToV3(args, container) {
90
102
  export async function submitKnowledge(ctx, args) {
91
103
  // 限流
92
104
  const blocked = await _checkRateLimit('autosnippet_submit_knowledge', args.client_id);
93
- if (blocked) return blocked;
105
+ if (blocked) {
106
+ return blocked;
107
+ }
94
108
 
95
109
  const service = ctx.container.get('knowledgeService');
96
110
 
@@ -135,23 +149,27 @@ export async function submitKnowledgeBatch(ctx, args) {
135
149
 
136
150
  // 限流
137
151
  const blocked = await _checkRateLimit('autosnippet_submit_knowledge_batch', args.client_id);
138
- if (blocked) return blocked;
152
+ if (blocked) {
153
+ return blocked;
154
+ }
139
155
 
140
156
  // 去重(可选)
141
157
  let items = args.items;
142
158
  if (args.deduplicate !== false) {
143
159
  try {
144
- const { aggregateCandidates } = await import('../../../service/candidate/CandidateAggregator.js');
160
+ const { aggregateCandidates } = await import(
161
+ '../../../service/candidate/CandidateAggregator.js'
162
+ );
145
163
  // 对 title 字段做去重
146
- const readinessItems = items.map(it => ({
164
+ const readinessItems = items.map((it) => ({
147
165
  ...it,
148
166
  code: it.content?.pattern || it.code || '',
149
167
  }));
150
168
  const result = aggregateCandidates(readinessItems);
151
169
  // 保留原始 items 顺序中去重后的
152
170
  if (result.items && result.items.length < items.length) {
153
- const titles = new Set(result.items.map(it => it.title));
154
- items = items.filter(it => titles.has(it.title));
171
+ const titles = new Set(result.items.map((it) => it.title));
172
+ items = items.filter((it) => titles.has(it.title));
155
173
  }
156
174
  } catch {
157
175
  // CandidateAggregator 加载失败时降级:不去重
@@ -188,11 +206,13 @@ export async function submitKnowledgeBatch(ctx, args) {
188
206
  }
189
207
 
190
208
  const data = { count, total: items.length, targetName: args.target_name };
191
- if (itemErrors.length > 0) data.errors = itemErrors;
209
+ if (itemErrors.length > 0) {
210
+ data.errors = itemErrors;
211
+ }
192
212
 
193
213
  // 被拒绝的条目:告知 Agent 需补齐哪些字段
194
214
  if (rejectedItems.length > 0) {
195
- const allMissing = [...new Set(rejectedItems.flatMap(it => it.missingFields))];
215
+ const allMissing = [...new Set(rejectedItems.flatMap((it) => it.missingFields))];
196
216
  data.rejectedItems = rejectedItems;
197
217
  data.rejectedSummary = {
198
218
  rejectedCount: rejectedItems.length,
@@ -268,34 +288,36 @@ export async function saveDocument(ctx, args) {
268
288
 
269
289
  // 限流
270
290
  const blocked = await _checkRateLimit('autosnippet_save_document', args.client_id);
271
- if (blocked) return blocked;
291
+ if (blocked) {
292
+ return blocked;
293
+ }
272
294
 
273
295
  const service = ctx.container.get('knowledgeService');
274
296
 
275
297
  const data = {
276
- title: args.title.trim(),
277
- description: args.description || '',
298
+ title: args.title.trim(),
299
+ description: args.description || '',
278
300
  knowledgeType: 'dev-document',
279
- kind: 'fact',
280
- source: args.source || 'agent',
281
- scope: args.scope || 'project-specific',
282
- tags: args.tags || [],
301
+ kind: 'fact',
302
+ source: args.source || 'agent',
303
+ scope: args.scope || 'project-specific',
304
+ tags: args.tags || [],
283
305
  content: {
284
306
  markdown: args.markdown,
285
- pattern: '',
307
+ pattern: '',
286
308
  },
287
309
  // 文档不需要 Cursor Delivery 字段
288
- trigger: '',
289
- doClause: '',
310
+ trigger: '',
311
+ doClause: '',
290
312
  dontClause: '',
291
313
  whenClause: '',
292
- topicHint: '',
293
- coreCode: '',
314
+ topicHint: '',
315
+ coreCode: '',
294
316
  // 基础推理
295
317
  reasoning: {
296
318
  whyStandard: 'Agent development document — preserved for team knowledge',
297
- sources: ['agent'],
298
- confidence: 0.8,
319
+ sources: ['agent'],
320
+ confidence: 0.8,
299
321
  },
300
322
  };
301
323
 
@@ -311,10 +333,10 @@ export async function saveDocument(ctx, args) {
311
333
  return envelope({
312
334
  success: true,
313
335
  data: {
314
- id: entry.id,
336
+ id: entry.id,
315
337
  lifecycle: 'active',
316
- title: entry.title,
317
- kind: 'fact',
338
+ title: entry.title,
339
+ kind: 'fact',
318
340
  knowledgeType: 'dev-document',
319
341
  },
320
342
  message: `文档「${entry.title}」已保存到知识库。`,
@@ -336,11 +358,13 @@ function _toReadinessInput(args) {
336
358
  trigger: args.trigger,
337
359
  description: args.description,
338
360
  headers: args.headers,
339
- reasoning: args.reasoning ? {
340
- whyStandard: args.reasoning.whyStandard,
341
- sources: args.reasoning.sources,
342
- confidence: args.reasoning.confidence,
343
- } : undefined,
361
+ reasoning: args.reasoning
362
+ ? {
363
+ whyStandard: args.reasoning.whyStandard,
364
+ sources: args.reasoning.sources,
365
+ confidence: args.reasoning.confidence,
366
+ }
367
+ : undefined,
344
368
  knowledgeType: args.knowledgeType,
345
369
  complexity: args.complexity,
346
370
  usageGuide: args.usageGuide,
@@ -50,8 +50,10 @@ function groupByKind(items) {
50
50
  * 根据 kind 参数过滤 items
51
51
  */
52
52
  function filterByKind(items, kind) {
53
- if (!kind || kind === 'all') return items;
54
- return items.filter(it => (it.kind || it.metadata?.kind || 'pattern') === kind);
53
+ if (!kind || kind === 'all') {
54
+ return items;
55
+ }
56
+ return items.filter((it) => (it.kind || it.metadata?.kind || 'pattern') === kind);
55
57
  }
56
58
 
57
59
  // ─── 1. autosnippet_search — 统合搜索入口 ─────────────────────
@@ -64,7 +66,7 @@ function filterByKind(items, kind) {
64
66
  */
65
67
  export async function search(ctx, args) {
66
68
  const t0 = Date.now();
67
- const engine = getSearchEngine(ctx) || await getFallbackEngine(ctx);
69
+ const engine = getSearchEngine(ctx) || (await getFallbackEngine(ctx));
68
70
  const query = args.query;
69
71
  const limit = args.limit || 10;
70
72
  const kind = args.kind || args.type || 'all';
@@ -72,7 +74,10 @@ export async function search(ctx, args) {
72
74
 
73
75
  // 统一调用 SearchEngine(auto 模式内置 BM25+semantic 融合去重 + Ranking Pipeline)
74
76
  const result = await engine.search(query, {
75
- mode, limit: kind !== 'all' ? limit * 2 : limit, rank: true, groupByKind: true,
77
+ mode,
78
+ limit: kind !== 'all' ? limit * 2 : limit,
79
+ rank: true,
80
+ groupByKind: true,
76
81
  });
77
82
  let items = result?.items || [];
78
83
  const actualMode = result?.mode || mode;
@@ -93,7 +98,11 @@ export async function search(ctx, args) {
93
98
  totalResults: items.length,
94
99
  items,
95
100
  byKind,
96
- kindCounts: { rule: byKind.rule.length, pattern: byKind.pattern.length, fact: byKind.fact.length },
101
+ kindCounts: {
102
+ rule: byKind.rule.length,
103
+ pattern: byKind.pattern.length,
104
+ fact: byKind.fact.length,
105
+ },
97
106
  },
98
107
  meta: { tool: 'autosnippet_search', responseTimeMs: elapsed },
99
108
  });
@@ -111,11 +120,14 @@ export async function search(ctx, args) {
111
120
  */
112
121
  export async function contextSearch(ctx, args) {
113
122
  const t0 = Date.now();
114
- const engine = getSearchEngine(ctx) || await getFallbackEngine(ctx);
123
+ const engine = getSearchEngine(ctx) || (await getFallbackEngine(ctx));
115
124
  const limit = args.limit ?? 5;
116
125
 
117
126
  const result = await engine.search(args.query, {
118
- mode: 'bm25', limit, rank: true, groupByKind: true,
127
+ mode: 'bm25',
128
+ limit,
129
+ rank: true,
130
+ groupByKind: true,
119
131
  context: {
120
132
  intent: 'search',
121
133
  language: args.language,
@@ -136,7 +148,11 @@ export async function contextSearch(ctx, args) {
136
148
  metadata: {
137
149
  responseTimeMs: elapsed,
138
150
  totalResults: items.length,
139
- kindCounts: { rule: byKind.rule.length, pattern: byKind.pattern.length, fact: byKind.fact.length },
151
+ kindCounts: {
152
+ rule: byKind.rule.length,
153
+ pattern: byKind.pattern.length,
154
+ fact: byKind.fact.length,
155
+ },
140
156
  },
141
157
  },
142
158
  meta: { tool: 'autosnippet_context_search', source, responseTimeMs: elapsed },
@@ -154,13 +170,15 @@ export async function contextSearch(ctx, args) {
154
170
  */
155
171
  export async function keywordSearch(ctx, args) {
156
172
  const t0 = Date.now();
157
- const engine = getSearchEngine(ctx) || await getFallbackEngine(ctx);
173
+ const engine = getSearchEngine(ctx) || (await getFallbackEngine(ctx));
158
174
  const query = args.query;
159
175
  const limit = args.limit || 10;
160
176
  const kind = args.kind || 'all';
161
177
 
162
178
  const result = await engine.search(query, {
163
- mode: 'keyword', limit, groupByKind: true,
179
+ mode: 'keyword',
180
+ limit,
181
+ groupByKind: true,
164
182
  });
165
183
 
166
184
  let items = result?.items || [];
@@ -177,7 +195,11 @@ export async function keywordSearch(ctx, args) {
177
195
  totalResults: items.length,
178
196
  items,
179
197
  byKind,
180
- kindCounts: { rule: byKind.rule.length, pattern: byKind.pattern.length, fact: byKind.fact.length },
198
+ kindCounts: {
199
+ rule: byKind.rule.length,
200
+ pattern: byKind.pattern.length,
201
+ fact: byKind.fact.length,
202
+ },
181
203
  },
182
204
  meta: { tool: 'autosnippet_keyword_search', responseTimeMs: elapsed },
183
205
  });
@@ -194,13 +216,16 @@ export async function keywordSearch(ctx, args) {
194
216
  */
195
217
  export async function semanticSearch(ctx, args) {
196
218
  const t0 = Date.now();
197
- const engine = getSearchEngine(ctx) || await getFallbackEngine(ctx);
219
+ const engine = getSearchEngine(ctx) || (await getFallbackEngine(ctx));
198
220
  const query = args.query;
199
221
  const limit = args.limit || 10;
200
222
  const kind = args.kind || 'all';
201
223
 
202
224
  const result = await engine.search(query, {
203
- mode: 'semantic', limit: limit * 2, rank: true, groupByKind: true,
225
+ mode: 'semantic',
226
+ limit: limit * 2,
227
+ rank: true,
228
+ groupByKind: true,
204
229
  });
205
230
 
206
231
  let items = result?.items || [];
@@ -223,7 +248,11 @@ export async function semanticSearch(ctx, args) {
223
248
  totalResults: items.length,
224
249
  items,
225
250
  byKind,
226
- kindCounts: { rule: byKind.rule.length, pattern: byKind.pattern.length, fact: byKind.fact.length },
251
+ kindCounts: {
252
+ rule: byKind.rule.length,
253
+ pattern: byKind.pattern.length,
254
+ fact: byKind.fact.length,
255
+ },
227
256
  },
228
257
  meta: { tool: 'autosnippet_semantic_search', responseTimeMs: elapsed },
229
258
  });