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
@@ -12,11 +12,14 @@
12
12
  * 运行方式:在项目根目录执行 npm run install:cursor-skill,或 asd install:cursor-skill,或 node scripts/install-cursor-skill.js
13
13
  */
14
14
 
15
- import { fileURLToPath } from 'node:url';
16
15
  import { dirname } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+
17
18
  const __filename = fileURLToPath(import.meta.url);
18
19
  const __dirname = dirname(__filename);
20
+
19
21
  import { createRequire } from 'node:module';
22
+
20
23
  const require = createRequire(import.meta.url);
21
24
 
22
25
  import fs from 'node:fs';
@@ -34,25 +37,27 @@ function findProjectRootFromCwd() {
34
37
  let current = path.resolve(process.cwd());
35
38
  const maxLevels = 20;
36
39
  let levels = 0;
37
-
40
+
38
41
  while (levels < maxLevels) {
39
- const boxspecPath = path.join(current, 'AutoSnippet', 'AutoSnippet.boxspec.json');
40
- if (fs.existsSync(boxspecPath)) {
41
- return current; // 当前目录就是项目根
42
- }
43
-
44
- // 还要检查当前目录本身就是知识库目录的情况(用户直接在 AutoSnippet/ 中运行)
45
- const directBoxspec = path.join(current, 'AutoSnippet.boxspec.json');
46
- if (fs.existsSync(directBoxspec)) {
47
- return path.dirname(current); // 当前是知识库,其父级才是项目根
48
- }
49
-
50
- const parentPath = path.dirname(current);
51
- if (parentPath === current) break;
52
- current = parentPath;
53
- levels++;
42
+ const boxspecPath = path.join(current, 'AutoSnippet', 'AutoSnippet.boxspec.json');
43
+ if (fs.existsSync(boxspecPath)) {
44
+ return current; // 当前目录就是项目根
45
+ }
46
+
47
+ // 还要检查当前目录本身就是知识库目录的情况(用户直接在 AutoSnippet/ 中运行)
48
+ const directBoxspec = path.join(current, 'AutoSnippet.boxspec.json');
49
+ if (fs.existsSync(directBoxspec)) {
50
+ return path.dirname(current); // 当前是知识库,其父级才是项目根
51
+ }
52
+
53
+ const parentPath = path.dirname(current);
54
+ if (parentPath === current) {
55
+ break;
56
+ }
57
+ current = parentPath;
58
+ levels++;
54
59
  }
55
-
60
+
56
61
  return null;
57
62
  }
58
63
 
@@ -62,10 +67,14 @@ if (found) {
62
67
  } else {
63
68
  // 备选方案:使用PathFinder的查找逻辑
64
69
  try {
65
- const findPath = require(path.join(autoSnippetRoot, 'lib', 'infrastructure/paths/PathFinder.js'));
66
- const fallback = findPath.findProjectRootSync(process.cwd());
67
- if (fallback) projectRoot = fallback;
68
- } catch (err) {}
70
+ const findPath = require(
71
+ path.join(autoSnippetRoot, 'lib', 'infrastructure/paths/PathFinder.js')
72
+ );
73
+ const fallback = findPath.findProjectRootSync(process.cwd());
74
+ if (fallback) {
75
+ projectRoot = fallback;
76
+ }
77
+ } catch (_err) {}
69
78
  }
70
79
 
71
80
  const skillsTarget = path.join(projectRoot, '.cursor', 'skills');
@@ -75,16 +84,14 @@ if (!fs.existsSync(skillsSource)) {
75
84
  process.exit(1);
76
85
  }
77
86
 
78
- const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true })
79
- .filter(d => d.isDirectory())
80
- .map(d => d.name);
87
+ const skillDirs = fs
88
+ .readdirSync(skillsSource, { withFileTypes: true })
89
+ .filter((d) => d.isDirectory())
90
+ .map((d) => d.name);
81
91
 
82
92
  if (skillDirs.length === 0) {
83
- console.log('ℹ️ skills 下暂无 skill 目录,跳过安装。');
84
93
  process.exit(0);
85
94
  }
86
-
87
- console.log('🚀 Cursor Skills 安装\n');
88
95
 
89
96
  function getRecipesDir(root) {
90
97
  try {
@@ -97,25 +104,31 @@ function getRecipesDir(root) {
97
104
  if (fs.existsSync(specPath)) {
98
105
  const spec = JSON.parse(fs.readFileSync(specPath, 'utf8'));
99
106
  const dir = spec?.recipes?.dir;
100
- if (dir) return path.join(root, dir);
107
+ if (dir) {
108
+ return path.join(root, dir);
109
+ }
101
110
  }
102
111
  }
103
- } catch { /* fallback */ }
112
+ } catch {
113
+ /* fallback */
114
+ }
104
115
  return path.join(root, defaults.RECIPES_DIR);
105
116
  }
106
117
 
107
118
  function collectMdFiles(dir, baseDir, list = []) {
108
- if (!fs.existsSync(dir)) return list;
119
+ if (!fs.existsSync(dir)) {
120
+ return list;
121
+ }
109
122
  const entries = fs.readdirSync(dir, { withFileTypes: true });
110
123
  for (const e of entries) {
111
- const full = path.join(dir, e.name);
112
- if (e.isDirectory() && !e.name.startsWith('.')) {
113
- collectMdFiles(full, baseDir, list);
114
- continue;
115
- }
116
- if (e.isFile() && e.name.toLowerCase().endsWith('.md')) {
117
- list.push(path.relative(baseDir, full).replace(/\\/g, '/'));
118
- }
124
+ const full = path.join(dir, e.name);
125
+ if (e.isDirectory() && !e.name.startsWith('.')) {
126
+ collectMdFiles(full, baseDir, list);
127
+ continue;
128
+ }
129
+ if (e.isFile() && e.name.toLowerCase().endsWith('.md')) {
130
+ list.push(path.relative(baseDir, full).replace(/\\/g, '/'));
131
+ }
119
132
  }
120
133
  return list;
121
134
  }
@@ -125,7 +138,9 @@ function collectMdFiles(dir, baseDir, list = []) {
125
138
  */
126
139
  function extractFrontmatterFields(content) {
127
140
  const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
128
- if (!m) return {};
141
+ if (!m) {
142
+ return {};
143
+ }
129
144
  const block = m[1];
130
145
  const extract = (key) => {
131
146
  const re = new RegExp(`^${key}:\s*["']?(.+?)["']?\s*$`, 'm');
@@ -152,9 +167,13 @@ function extractFrontmatterFields(content) {
152
167
  */
153
168
  function buildProjectRecipesContext(projectRoot) {
154
169
  const recipesDir = getRecipesDir(projectRoot);
155
- if (!fs.existsSync(recipesDir)) return null;
170
+ if (!fs.existsSync(recipesDir)) {
171
+ return null;
172
+ }
156
173
  const mdFiles = collectMdFiles(recipesDir, recipesDir).sort();
157
- if (mdFiles.length === 0) return null;
174
+ if (mdFiles.length === 0) {
175
+ return null;
176
+ }
158
177
 
159
178
  const lines = [
160
179
  '# Project Recipes Index\n\n',
@@ -178,7 +197,9 @@ function buildProjectRecipesContext(projectRoot) {
178
197
  const lang = fm.language || '';
179
198
  const kind = fm.kind || '';
180
199
  const summary = (fm.summary_cn || fm.summary_en || '').replace(/\|/g, '/');
181
- lines.push(`| ${idx} | ${rel} | ${title} | ${trigger} | ${cat} | ${lang} | ${kind} | ${summary} |\n`);
200
+ lines.push(
201
+ `| ${idx} | ${rel} | ${title} | ${trigger} | ${cat} | ${lang} | ${kind} | ${summary} |\n`
202
+ );
182
203
  } catch (_) {
183
204
  lines.push(`| ${idx} | ${rel} | *(read error)* | | | | | |\n`);
184
205
  }
@@ -200,9 +221,15 @@ function buildProjectRecipesContext(projectRoot) {
200
221
  }
201
222
 
202
223
  lines.push('\n## Usage Tips\n\n');
203
- lines.push('- 查找 Recipe: `autosnippet_search({ query })` 或 `autosnippet_search({ query, mode: "context" })`\n');
204
- lines.push('- 获取详情: `autosnippet_knowledge({ operation: "get", id })` 返回完整 Recipe 内容、关系、约束\n');
205
- lines.push('- 按类型浏览: `autosnippet_knowledge({ operation: "list", kind: "rule" })` / `kind: "pattern"` / `kind: "fact"`\n');
224
+ lines.push(
225
+ '- 查找 Recipe: `autosnippet_search({ query })` `autosnippet_search({ query, mode: "context" })`\n'
226
+ );
227
+ lines.push(
228
+ '- 获取详情: `autosnippet_knowledge({ operation: "get", id })` — 返回完整 Recipe 内容、关系、约束\n'
229
+ );
230
+ lines.push(
231
+ '- 按类型浏览: `autosnippet_knowledge({ operation: "list", kind: "rule" })` / `kind: "pattern"` / `kind: "fact"`\n'
232
+ );
206
233
  lines.push('- Guard 检查: `autosnippet_guard({ code })` / `autosnippet_guard({ files })`\n');
207
234
 
208
235
  return lines.join('');
@@ -210,26 +237,32 @@ function buildProjectRecipesContext(projectRoot) {
210
237
 
211
238
  function buildSpmmapSummary(projectRoot) {
212
239
  const spmmapPath = path.join(projectRoot, defaults.SPMMAP_PATH);
213
- if (!fs.existsSync(spmmapPath)) return null;
214
- try {
215
- const data = JSON.parse(fs.readFileSync(spmmapPath, 'utf8'));
216
- const graph = data.graph || {};
217
- const packages = graph.packages || {};
218
- const edges = graph.edges || {};
219
- const lines = ['# SPM 依赖结构摘要\n', `Generated by \`asd install:cursor-skill\`. Source: ${defaults.SPMMAP_PATH}\n`, '\n## Packages\n'];
220
- for (const [pkg, info] of Object.entries(packages)) {
221
- const targets = (info.targets || []).join(', ');
222
- lines.push(`- **${pkg}**: ${targets || '(no targets)'}\n`);
240
+ if (!fs.existsSync(spmmapPath)) {
241
+ return null;
223
242
  }
224
- lines.push('\n## 依赖关系 (from → to)\n');
225
- for (const [from, toList] of Object.entries(edges)) {
226
- if (Array.isArray(toList)) {
227
- lines.push(`- ${from} ${toList.join(', ')}\n`);
243
+ try {
244
+ const data = JSON.parse(fs.readFileSync(spmmapPath, 'utf8'));
245
+ const graph = data.graph || {};
246
+ const packages = graph.packages || {};
247
+ const edges = graph.edges || {};
248
+ const lines = [
249
+ '# SPM 依赖结构摘要\n',
250
+ `Generated by \`asd install:cursor-skill\`. Source: ${defaults.SPMMAP_PATH}\n`,
251
+ '\n## Packages\n',
252
+ ];
253
+ for (const [pkg, info] of Object.entries(packages)) {
254
+ const targets = (info.targets || []).join(', ');
255
+ lines.push(`- **${pkg}**: ${targets || '(no targets)'}\n`);
228
256
  }
229
- }
230
- return lines.join('');
257
+ lines.push('\n## 依赖关系 (from → to)\n');
258
+ for (const [from, toList] of Object.entries(edges)) {
259
+ if (Array.isArray(toList)) {
260
+ lines.push(`- ${from} → ${toList.join(', ')}\n`);
261
+ }
262
+ }
263
+ return lines.join('');
231
264
  } catch (_) {
232
- return null;
265
+ return null;
233
266
  }
234
267
  }
235
268
 
@@ -238,53 +271,62 @@ for (const name of skillDirs) {
238
271
  const dest = path.join(skillsTarget, name);
239
272
  // 合并模式:只覆盖源文件中存在的文件,保留用户在 skill 目录下自己添加的文件
240
273
  fs.cpSync(src, dest, { recursive: true, force: true });
241
- console.log(` ✅ ${name}`);
242
274
 
243
275
  if (name === 'autosnippet-recipes') {
244
276
  // V2: 生成轻量 Recipe 索引(替代 V1 全文拼接 + by-category 切片)
245
277
  const context = buildProjectRecipesContext(projectRoot);
246
278
  const refDir = path.join(dest, 'references');
247
- if (!fs.existsSync(refDir)) fs.mkdirSync(refDir, { recursive: true });
279
+ if (!fs.existsSync(refDir)) {
280
+ fs.mkdirSync(refDir, { recursive: true });
281
+ }
248
282
  const contextPath = path.join(refDir, 'project-recipes-context.md');
249
283
  if (context) {
250
284
  fs.writeFileSync(contextPath, context, 'utf8');
251
- console.log(` 📋 Recipe 索引已生成 (轻量索引 + MCP 按需检索)`);
252
285
  } else {
253
- if (fs.existsSync(contextPath)) fs.unlinkSync(contextPath);
286
+ if (fs.existsSync(contextPath)) {
287
+ fs.unlinkSync(contextPath);
288
+ }
254
289
  }
255
290
  // 清理 V1 遗留的 by-category 切片(如存在)
256
291
  const oldCatDir = path.join(refDir, 'by-category');
257
292
  if (fs.existsSync(oldCatDir)) {
258
293
  fs.rmSync(oldCatDir, { recursive: true });
259
- console.log(` 🧹 已清理 V1 遗留 by-category 切片`);
260
294
  }
261
295
  const oldIndexJson = path.join(refDir, 'index.json');
262
- if (fs.existsSync(oldIndexJson)) fs.unlinkSync(oldIndexJson);
296
+ if (fs.existsSync(oldIndexJson)) {
297
+ fs.unlinkSync(oldIndexJson);
298
+ }
263
299
  }
264
300
  if (name === 'autosnippet-structure') {
265
301
  // spmmap 摘要注入到 structure skill(替代已删除的 dep-graph skill)
266
302
  const summary = buildSpmmapSummary(projectRoot);
267
303
  const refDir = path.join(dest, 'references');
268
- if (!fs.existsSync(refDir)) fs.mkdirSync(refDir, { recursive: true });
304
+ if (!fs.existsSync(refDir)) {
305
+ fs.mkdirSync(refDir, { recursive: true });
306
+ }
269
307
  const summaryPath = path.join(refDir, 'spmmap-summary.md');
270
308
  if (summary) {
271
309
  fs.writeFileSync(summaryPath, summary, 'utf8');
272
- console.log(` 🗺️ SPM 依赖摘要已生成`);
273
310
  } else {
274
- if (fs.existsSync(summaryPath)) fs.unlinkSync(summaryPath);
311
+ if (fs.existsSync(summaryPath)) {
312
+ fs.unlinkSync(summaryPath);
313
+ }
275
314
  }
276
315
  }
277
316
  if (name === 'autosnippet-guard') {
278
317
  // V2: Guard 索引(同 recipes 索引),Agent 主路径走 MCP guard_check
279
318
  const context = buildProjectRecipesContext(projectRoot);
280
319
  const refDir = path.join(dest, 'references');
281
- if (!fs.existsSync(refDir)) fs.mkdirSync(refDir, { recursive: true });
320
+ if (!fs.existsSync(refDir)) {
321
+ fs.mkdirSync(refDir, { recursive: true });
322
+ }
282
323
  const guardPath = path.join(refDir, 'guard-context.md');
283
324
  if (context) {
284
325
  fs.writeFileSync(guardPath, context, 'utf8');
285
- console.log(` 🛡️ Guard 索引已生成 (轻量 fallback)`);
286
326
  } else {
287
- if (fs.existsSync(guardPath)) fs.unlinkSync(guardPath);
327
+ if (fs.existsSync(guardPath)) {
328
+ fs.unlinkSync(guardPath);
329
+ }
288
330
  }
289
331
  }
290
332
  }
@@ -293,17 +335,19 @@ for (const name of skillDirs) {
293
335
  const cursorRulesSource = path.join(autoSnippetRoot, 'templates', 'cursor-rules');
294
336
  const cursorRulesTarget = path.join(projectRoot, '.cursor', 'rules');
295
337
  if (fs.existsSync(cursorRulesSource)) {
296
- const ruleFiles = fs.readdirSync(cursorRulesSource, { withFileTypes: true })
297
- .filter(d => d.isFile() && d.name.toLowerCase().endsWith('.mdc'))
298
- .map(d => d.name);
338
+ const ruleFiles = fs
339
+ .readdirSync(cursorRulesSource, { withFileTypes: true })
340
+ .filter((d) => d.isFile() && d.name.toLowerCase().endsWith('.mdc'))
341
+ .map((d) => d.name);
299
342
  if (ruleFiles.length > 0) {
300
- if (!fs.existsSync(cursorRulesTarget)) fs.mkdirSync(cursorRulesTarget, { recursive: true });
301
- for (const name of ruleFiles) {
302
- const src = path.join(cursorRulesSource, name);
303
- const dest = path.join(cursorRulesTarget, name);
304
- fs.copyFileSync(src, dest);
305
- console.log(` ✅ ${name}`);
306
- }
343
+ if (!fs.existsSync(cursorRulesTarget)) {
344
+ fs.mkdirSync(cursorRulesTarget, { recursive: true });
345
+ }
346
+ for (const name of ruleFiles) {
347
+ const src = path.join(cursorRulesSource, name);
348
+ const dest = path.join(cursorRulesTarget, name);
349
+ fs.copyFileSync(src, dest);
350
+ }
307
351
  }
308
352
  }
309
353
 
@@ -314,36 +358,36 @@ const addMcp = process.argv.includes('--mcp');
314
358
  if (addMcp && fs.existsSync(mcpServerScript)) {
315
359
  let mcp = { mcpServers: {} };
316
360
  if (fs.existsSync(mcpPath)) {
317
- try {
318
- mcp = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
319
- if (!mcp.mcpServers) mcp.mcpServers = {};
320
- } catch (_) {}
361
+ try {
362
+ mcp = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
363
+ if (!mcp.mcpServers) {
364
+ mcp.mcpServers = {};
365
+ }
366
+ } catch (_) {}
321
367
  }
322
368
  mcp.mcpServers.autosnippet = {
323
- type: 'stdio',
324
- command: 'node',
325
- args: [mcpServerScript],
326
- env: { ASD_UI_URL: process.env.ASD_UI_URL || defaults.DEFAULT_ASD_UI_URL }
369
+ type: 'stdio',
370
+ command: 'node',
371
+ args: [mcpServerScript],
372
+ env: { ASD_UI_URL: process.env.ASD_UI_URL || defaults.DEFAULT_ASD_UI_URL },
327
373
  };
328
374
  fs.mkdirSync(path.dirname(mcpPath), { recursive: true });
329
375
  fs.writeFileSync(mcpPath, JSON.stringify(mcp, null, 2), 'utf8');
330
- console.log(' ✅ MCP 配置');
331
376
  } else if (addMcp) {
332
377
  // mcp-server.js 不存在,已跳过
333
378
  }
334
379
 
335
- console.log('🎯 Cursor skills 已就绪,安装到项目:', projectRoot);
336
- console.log(`\n📌 下一步:重启 Cursor 后生效`);
337
-
338
380
  const runEmbed = process.argv.includes('--embed');
339
381
  if (runEmbed) {
340
382
  (async () => {
341
- try {
342
- const IndexingPipeline = require(path.join(autoSnippetRoot, 'lib', 'context', 'IndexingPipeline'));
343
- const result = await IndexingPipeline.run(projectRoot, { clear: false });
344
- // 语义索引已更新
345
- } catch (e) {
346
- console.warn('⚠️ 语义索引更新失败:', e.message);
347
- }
383
+ try {
384
+ const IndexingPipeline = require(
385
+ path.join(autoSnippetRoot, 'lib', 'context', 'IndexingPipeline')
386
+ );
387
+ const _result = await IndexingPipeline.run(projectRoot, { clear: false });
388
+ // 语义索引已更新
389
+ } catch (e) {
390
+ console.warn('⚠️ 语义索引更新失败:', e.message);
391
+ }
348
392
  })().catch(() => process.exit(1));
349
393
  }
@@ -6,53 +6,40 @@
6
6
  * asd install:full --parser - 上述 + Swift 解析器
7
7
  */
8
8
 
9
- import { fileURLToPath } from 'node:url';
10
9
  import { dirname } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+
11
12
  const __filename = fileURLToPath(import.meta.url);
12
13
  const __dirname = dirname(__filename);
13
14
 
14
15
  import { execSync } from 'node:child_process';
15
- import path from 'node:path';
16
16
  import fs from 'node:fs';
17
+ import path from 'node:path';
17
18
 
18
19
  const rootDir = path.resolve(__dirname, '..');
19
- const withParser = process.env.ASD_INSTALL_PARSER === '1' || process.env.ASD_INSTALL_PARSER === 'true';
20
- const withNativeUi = process.env.ASD_INSTALL_NATIVE_UI === '1' || process.env.ASD_INSTALL_NATIVE_UI === 'true';
20
+ const withParser =
21
+ process.env.ASD_INSTALL_PARSER === '1' || process.env.ASD_INSTALL_PARSER === 'true';
22
+ const withNativeUi =
23
+ process.env.ASD_INSTALL_NATIVE_UI === '1' || process.env.ASD_INSTALL_NATIVE_UI === 'true';
21
24
  const dashboardDist = path.join(rootDir, 'dashboard', 'dist');
22
-
23
- console.log('=== AutoSnippet 全量安装 ===\n');
24
-
25
- // 1. 核心 + 可选依赖
26
- console.log('1/4 安装核心与可选依赖...');
27
25
  execSync('npm install', { cwd: rootDir, stdio: 'inherit' });
28
- console.log('');
29
26
 
30
27
  // 2. Dashboard(仅当前端不存在时安装并构建)
31
28
  if (!fs.existsSync(dashboardDist)) {
32
- console.log('2/4 前端不存在,安装并构建 Dashboard...');
33
29
  const dashboardDir = path.join(rootDir, 'dashboard');
34
30
  execSync('npm install', { cwd: dashboardDir, stdio: 'inherit' });
35
31
  execSync('npm run build:dashboard', { cwd: rootDir, stdio: 'inherit' });
36
- console.log('');
37
32
  } else {
38
- console.log('2/4 跳过 Dashboard(已存在预构建前端)');
39
- console.log('');
40
33
  }
41
34
 
42
35
  // 3. ParsePackage / Native UI(可选)
43
36
  if (withParser) {
44
- console.log('3/4 构建 Swift 解析器(ParsePackage)...');
45
37
  execSync('npm run build:parser', { cwd: rootDir, stdio: 'inherit' });
46
38
  } else {
47
- console.log('3/4 跳过 ParsePackage(需时执行 asd install:full --parser)');
48
39
  }
49
40
  if (withNativeUi || process.platform === 'darwin') {
50
- console.log('4/4 构建 Native UI 辅助程序(macOS)...');
51
41
  try {
52
- await import('./build-native-ui.js');
42
+ await import('./build-native-ui.js');
53
43
  } catch (_) {}
54
44
  } else {
55
- console.log('4/4 跳过 Native UI(非 macOS)');
56
45
  }
57
-
58
- console.log('\n✅ 全量安装完成');