autosnippet 3.0.1 → 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 +655 -260
  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
@@ -7,46 +7,54 @@
7
7
 
8
8
  import fs from 'node:fs';
9
9
  import path from 'node:path';
10
+
10
11
  function parseArgs(argv) {
11
12
  const args = {};
12
13
  for (let i = 2; i < argv.length; i++) {
13
- const a = argv[i];
14
- if (!a.startsWith('--')) continue;
15
- const [k, v] = a.split('=');
16
- const key = k.replace(/^--/, '');
17
- if (v !== undefined) args[key] = v;
18
- else if (argv[i + 1] && !argv[i + 1].startsWith('--')) {
19
- args[key] = argv[i + 1];
20
- i++;
21
- } else {
22
- args[key] = true;
23
- }
14
+ const a = argv[i];
15
+ if (!a.startsWith('--')) {
16
+ continue;
17
+ }
18
+ const [k, v] = a.split('=');
19
+ const key = k.replace(/^--/, '');
20
+ if (v !== undefined) {
21
+ args[key] = v;
22
+ } else if (argv[i + 1] && !argv[i + 1].startsWith('--')) {
23
+ args[key] = argv[i + 1];
24
+ i++;
25
+ } else {
26
+ args[key] = true;
27
+ }
24
28
  }
25
29
  return args;
26
30
  }
27
31
 
28
32
  function ensureDir(dir) {
29
33
  if (!fs.existsSync(dir)) {
30
- fs.mkdirSync(dir, { recursive: true });
34
+ fs.mkdirSync(dir, { recursive: true });
31
35
  }
32
36
  }
33
37
 
34
38
  function walk(dir, exts, out) {
35
39
  const entries = fs.readdirSync(dir, { withFileTypes: true });
36
40
  for (const e of entries) {
37
- const full = path.join(dir, e.name);
38
- if (e.isDirectory()) {
39
- if (e.name.startsWith('.')) continue;
40
- walk(full, exts, out);
41
- continue;
42
- }
43
- if (!exts.includes(path.extname(e.name))) continue;
44
- out.push(full);
41
+ const full = path.join(dir, e.name);
42
+ if (e.isDirectory()) {
43
+ if (e.name.startsWith('.')) {
44
+ continue;
45
+ }
46
+ walk(full, exts, out);
47
+ continue;
48
+ }
49
+ if (!exts.includes(path.extname(e.name))) {
50
+ continue;
51
+ }
52
+ out.push(full);
45
53
  }
46
54
  }
47
55
 
48
56
  function toTitle(base) {
49
- return base.replace(/[-_]+/g, ' ').replace(/\b\w/g, s => s.toUpperCase());
57
+ return base.replace(/[-_]+/g, ' ').replace(/\b\w/g, (s) => s.toUpperCase());
50
58
  }
51
59
 
52
60
  function toTrigger(base) {
@@ -55,64 +63,95 @@ function toTrigger(base) {
55
63
 
56
64
  function readSnippet(filePath, maxChars) {
57
65
  const raw = fs.readFileSync(filePath, 'utf8');
58
- if (raw.length <= maxChars) return raw;
59
- return raw.slice(0, maxChars) + '\n// ... (truncated)';
66
+ if (raw.length <= maxChars) {
67
+ return raw;
68
+ }
69
+ return `${raw.slice(0, maxChars)}\n// ... (truncated)`;
60
70
  }
61
71
 
62
72
  function detectLanguageByExt(ext) {
63
- if (ext === '.swift') return 'swift';
64
- if (ext === '.m' || ext === '.h') return 'objectivec';
65
- return 'text';
73
+ const map = {
74
+ '.swift': 'swift',
75
+ '.m': 'objectivec', '.h': 'objectivec', '.mm': 'objectivec',
76
+ '.js': 'javascript', '.mjs': 'javascript', '.jsx': 'javascript',
77
+ '.ts': 'typescript', '.tsx': 'typescript',
78
+ '.py': 'python',
79
+ '.java': 'java', '.kt': 'kotlin',
80
+ '.go': 'go',
81
+ '.rs': 'rust', '.rb': 'ruby',
82
+ };
83
+ return map[ext] || 'text';
66
84
  }
67
85
 
68
86
  function buildRecipe({ title, trigger, language, sourceFile, snippet }) {
69
87
  const fence = '```';
70
88
  return [
71
- '---',
72
- `title: ${title}`,
73
- `trigger: ${trigger}`,
74
- `language: ${language}`,
75
- 'category: draft',
76
- `source: ${sourceFile}`,
77
- '---',
78
- '',
79
- '## Snippet / Code Reference',
80
- '',
81
- `${fence}${language}`,
82
- snippet,
83
- fence,
84
- '',
85
- '## AI Context / Usage Guide',
86
- '',
87
- '(待补充)',
88
- ''
89
+ '---',
90
+ `title: ${title}`,
91
+ `trigger: ${trigger}`,
92
+ `language: ${language}`,
93
+ 'category: draft',
94
+ `source: ${sourceFile}`,
95
+ '---',
96
+ '',
97
+ '## Snippet / Code Reference',
98
+ '',
99
+ `${fence}${language}`,
100
+ snippet,
101
+ fence,
102
+ '',
103
+ '## AI Context / Usage Guide',
104
+ '',
105
+ '(待补充)',
106
+ '',
89
107
  ].join('\n');
90
108
  }
91
109
 
110
+ const DEFAULT_EXTS = '.swift,.m,.h,.mm,.js,.mjs,.jsx,.ts,.tsx,.py,.java,.kt,.go';
111
+
112
+ function printUsage() {
113
+ console.log(`Usage: generate-recipe-drafts [options]
114
+
115
+ Options:
116
+ --projectRoot <path> 项目根目录 (默认: 当前目录)
117
+ --targetDir <path> 要扫描的源码目录 (默认: projectRoot)
118
+ --outDir <path> 输出目录 (默认: <projectRoot>/autosnippet-drafts/recipes)
119
+ --exts <list> 扫描的扩展名,逗号分隔 (默认: ${DEFAULT_EXTS})
120
+ --maxChars <n> 单文件最大截取字符数 (默认: 4000)
121
+ --help 显示帮助
122
+ `);
123
+ }
124
+
92
125
  function main() {
93
126
  const args = parseArgs(process.argv);
127
+
128
+ if (args.help) {
129
+ printUsage();
130
+ process.exit(0);
131
+ }
132
+
94
133
  const projectRoot = args.projectRoot
95
- ? path.resolve(args.projectRoot)
96
- : '/Users/gaoxuefeng/Documents/github/BiliDemo';
134
+ ? path.resolve(args.projectRoot)
135
+ : process.cwd();
97
136
 
98
137
  const targetDir = args.targetDir
99
- ? path.resolve(args.targetDir)
100
- : path.join(projectRoot, 'BiliDili');
138
+ ? path.resolve(args.targetDir)
139
+ : projectRoot;
101
140
 
102
141
  const outDir = args.outDir
103
- ? path.resolve(args.outDir)
104
- : path.join(projectRoot, 'autosnippet-drafts', 'recipes');
142
+ ? path.resolve(args.outDir)
143
+ : path.join(projectRoot, 'autosnippet-drafts', 'recipes');
105
144
 
106
- const exts = String(args.exts || '.m,.h,.swift')
107
- .split(',')
108
- .map(s => s.trim())
109
- .filter(Boolean);
145
+ const exts = String(args.exts || DEFAULT_EXTS)
146
+ .split(',')
147
+ .map((s) => s.trim())
148
+ .filter(Boolean);
110
149
 
111
150
  const maxChars = Number(args.maxChars || 4000);
112
151
 
113
152
  if (!fs.existsSync(targetDir)) {
114
- console.error(`targetDir 不存在: ${targetDir}`);
115
- process.exit(1);
153
+ console.error(`targetDir 不存在: ${targetDir}`);
154
+ process.exit(1);
116
155
  }
117
156
 
118
157
  ensureDir(outDir);
@@ -122,29 +161,29 @@ function main() {
122
161
 
123
162
  let count = 0;
124
163
  for (const filePath of files) {
125
- const ext = path.extname(filePath);
126
- const base = path.basename(filePath, ext);
127
- const title = toTitle(base);
128
- const trigger = toTrigger(base);
129
- const language = detectLanguageByExt(ext);
130
- const snippet = readSnippet(filePath, maxChars);
131
-
132
- const rel = path.relative(projectRoot, filePath).replace(/\\/g, '/');
133
- const recipe = buildRecipe({
134
- title,
135
- trigger,
136
- language,
137
- sourceFile: rel,
138
- snippet
139
- });
140
-
141
- const outFile = path.join(outDir, `${base}.md`);
142
- fs.writeFileSync(outFile, recipe, 'utf8');
143
- count++;
164
+ const ext = path.extname(filePath);
165
+ const base = path.basename(filePath, ext);
166
+ const title = toTitle(base);
167
+ const trigger = toTrigger(base);
168
+ const language = detectLanguageByExt(ext);
169
+ const snippet = readSnippet(filePath, maxChars);
170
+
171
+ const rel = path.relative(projectRoot, filePath).replace(/\\/g, '/');
172
+ const recipe = buildRecipe({
173
+ title,
174
+ trigger,
175
+ language,
176
+ sourceFile: rel,
177
+ snippet,
178
+ });
179
+
180
+ const safeName = `${base}${ext}`.replace(/\./g, '_');
181
+ const outFile = path.join(outDir, `${safeName}.md`);
182
+ fs.writeFileSync(outFile, recipe, 'utf8');
183
+ count++;
144
184
  }
145
185
 
146
- console.log(`已生成 ${count} 个 Recipe 草稿`);
147
- console.log(`输出目录: ${outDir}`);
186
+ console.log(`✅ 生成 ${count} 个 recipe 草稿 → ${outDir}`);
148
187
  }
149
188
 
150
189
  main();
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
5
  import Bootstrap from '../lib/bootstrap.js';
6
6
 
7
7
  const __filename = fileURLToPath(import.meta.url);
@@ -11,31 +11,14 @@ const __dirname = path.dirname(__filename);
11
11
  * 初始化 AutoSnippet 数据库
12
12
  */
13
13
  async function main() {
14
- console.log('🚀 AutoSnippet 2.0 - Database Initialization\n');
15
-
16
14
  try {
17
15
  const bootstrap = new Bootstrap({ env: process.env.NODE_ENV || 'development' });
18
16
  const components = await bootstrap.initialize();
19
17
 
20
- console.log('✅ Database initialized successfully');
21
- console.log('\nComponents ready:');
22
- console.log(' - Database:', components.db ? '✓' : '✗');
23
- console.log(' - Logger:', components.logger ? '✓' : '✗');
24
- console.log(' - Constitution:', components.constitution ? '✓' : '✗');
25
- console.log(' - Gateway:', components.gateway ? '✓' : '✗');
26
- console.log(' - Permission Manager:', components.permissionManager ? '✓' : '✗');
27
- console.log(' - Audit Logger:', components.auditLogger ? '✓' : '✗');
28
-
29
18
  // 显示宪法信息
30
- const constitutionInfo = components.constitution.toJSON();
31
- console.log('\n📜 Constitution:');
32
- console.log(' - Version:', constitutionInfo.version);
33
- console.log(' - Effective Date:', constitutionInfo.effectiveDate);
34
- console.log(' - Rules:', (constitutionInfo.rules || []).length);
35
- console.log(' - Roles:', constitutionInfo.roles.length);
19
+ const _constitutionInfo = components.constitution.toJSON();
36
20
 
37
21
  await bootstrap.shutdown();
38
- console.log('\n✅ Initialization complete');
39
22
  process.exit(0);
40
23
  } catch (error) {
41
24
  console.error('\n❌ Initialization failed:', error.message);
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Snippet 统一初始化脚本
5
+ *
6
+ * 为 AutoSnippet 生成快速触发 Snippet(ass/asc/asa)到目标 IDE:
7
+ * - Xcode: ~/Library/Developer/Xcode/UserData/CodeSnippets/*.codesnippet
8
+ * - VSCode: .vscode/autosnippet-triggers.code-snippets (项目级)
9
+ *
10
+ * 用法:
11
+ * node scripts/init-snippets.js [init|list|remove] [--target xcode|vscode|all]
12
+ * npm run init:snippets
13
+ */
14
+
15
+ import { execSync } from 'node:child_process';
16
+ import fs from 'node:fs';
17
+ import os from 'node:os';
18
+ import path from 'node:path';
19
+
20
+ // ─── Trigger Snippet 定义 (IDE 无关) ─────────────────────
21
+
22
+ const TRIGGER_SNIPPETS = [
23
+ {
24
+ id: 'com.autosnippet.search.long',
25
+ shortcut: 'ass',
26
+ title: 'AutoSnippet: Search (Long)',
27
+ summary: 'Search and insert Recipe/Snippet from knowledge base',
28
+ xcodeContent: '// as:search <#keyword#>',
29
+ vscodeBody: ['// as:search ${1:keyword}'],
30
+ },
31
+ {
32
+ id: 'com.autosnippet.create',
33
+ shortcut: 'asc',
34
+ title: 'AutoSnippet: Create Recipe',
35
+ summary: 'Create new Recipe (Dashboard or clipboard/file)',
36
+ xcodeContent: '// as:create <#-c or -f#>',
37
+ vscodeBody: ['// as:create ${1:-c or -f}'],
38
+ },
39
+ {
40
+ id: 'com.autosnippet.audit',
41
+ shortcut: 'asa',
42
+ title: 'AutoSnippet: Audit Code',
43
+ summary: 'AI code review against knowledge base',
44
+ xcodeContent: '// as:audit <#keyword or scope (file/target/project)#>',
45
+ vscodeBody: ['// as:audit ${1:keyword or scope (file/target/project)}'],
46
+ },
47
+ ];
48
+
49
+ // ─── Xcode 初始化器 ─────────────────────
50
+
51
+ class XcodeInitializer {
52
+ constructor() {
53
+ this.snippetsDir = path.join(os.homedir(), 'Library/Developer/Xcode/UserData/CodeSnippets');
54
+ }
55
+
56
+ isAvailable() {
57
+ if (process.platform !== 'darwin') return false;
58
+ try {
59
+ execSync('xcode-select -p', { stdio: 'ignore' });
60
+ return true;
61
+ } catch {
62
+ return false;
63
+ }
64
+ }
65
+
66
+ ensureDir() {
67
+ if (!fs.existsSync(this.snippetsDir)) {
68
+ try {
69
+ fs.mkdirSync(this.snippetsDir, { recursive: true });
70
+ return true;
71
+ } catch {
72
+ return false;
73
+ }
74
+ }
75
+ return true;
76
+ }
77
+
78
+ generatePlist(snippet) {
79
+ const escape = (s) =>
80
+ String(s || '')
81
+ .replace(/&/g, '&amp;')
82
+ .replace(/</g, '&lt;')
83
+ .replace(/>/g, '&gt;')
84
+ .replace(/"/g, '&quot;')
85
+ .replace(/'/g, '&apos;');
86
+
87
+ return `<?xml version="1.0" encoding="UTF-8"?>
88
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
89
+ <plist version="1.0">
90
+ <dict>
91
+ <key>IDECodeSnippetCompletionPrefix</key>
92
+ <string>${escape(snippet.shortcut)}</string>
93
+ <key>IDECodeSnippetCompletionScopes</key>
94
+ <array>
95
+ <string>All</string>
96
+ </array>
97
+ <key>IDECodeSnippetContents</key>
98
+ <string>${escape(snippet.xcodeContent)}</string>
99
+ <key>IDECodeSnippetIdentifier</key>
100
+ <string>${escape(snippet.id)}</string>
101
+ <key>IDECodeSnippetLanguage</key>
102
+ <string>Xcode.SourceCodeLanguage.Generic</string>
103
+ <key>IDECodeSnippetSummary</key>
104
+ <string>${escape(snippet.summary)}</string>
105
+ <key>IDECodeSnippetTitle</key>
106
+ <string>${escape(snippet.title)}</string>
107
+ <key>IDECodeSnippetUserSnippet</key>
108
+ <true/>
109
+ <key>IDECodeSnippetVersion</key>
110
+ <integer>2</integer>
111
+ </dict>
112
+ </plist>`;
113
+ }
114
+
115
+ init() {
116
+ if (!this.isAvailable()) return { skipped: true, reason: 'Xcode not available' };
117
+ if (!this.ensureDir()) return { skipped: true, reason: 'Cannot create snippets dir' };
118
+
119
+ let count = 0;
120
+ for (const snippet of TRIGGER_SNIPPETS) {
121
+ const filePath = path.join(this.snippetsDir, `${snippet.id}.codesnippet`);
122
+ fs.writeFileSync(filePath, this.generatePlist(snippet), 'utf-8');
123
+ count++;
124
+ }
125
+ return { success: true, count };
126
+ }
127
+
128
+ list() {
129
+ if (!fs.existsSync(this.snippetsDir)) return [];
130
+ return fs
131
+ .readdirSync(this.snippetsDir)
132
+ .filter((f) => f.startsWith('com.autosnippet') && f.endsWith('.codesnippet'));
133
+ }
134
+
135
+ remove() {
136
+ const files = this.list();
137
+ let removed = 0;
138
+ for (const f of files) {
139
+ try {
140
+ fs.unlinkSync(path.join(this.snippetsDir, f));
141
+ removed++;
142
+ } catch {
143
+ /* ignore */
144
+ }
145
+ }
146
+ return { removed };
147
+ }
148
+ }
149
+
150
+ // ─── VSCode 初始化器 ─────────────────────
151
+
152
+ class VSCodeInitializer {
153
+ constructor(projectRoot) {
154
+ this.projectRoot = projectRoot || process.cwd();
155
+ this.vscodeDir = path.join(this.projectRoot, '.vscode');
156
+ this.filename = 'autosnippet-triggers.code-snippets';
157
+ }
158
+
159
+ isAvailable() {
160
+ // VSCode snippets 跨平台可用
161
+ return true;
162
+ }
163
+
164
+ ensureDir() {
165
+ if (!fs.existsSync(this.vscodeDir)) {
166
+ try {
167
+ fs.mkdirSync(this.vscodeDir, { recursive: true });
168
+ return true;
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+
176
+ init() {
177
+ if (!this.ensureDir()) return { skipped: true, reason: 'Cannot create .vscode dir' };
178
+
179
+ const bundle = {};
180
+ for (const snippet of TRIGGER_SNIPPETS) {
181
+ bundle[snippet.title] = {
182
+ prefix: snippet.shortcut,
183
+ body: snippet.vscodeBody,
184
+ description: snippet.summary,
185
+ };
186
+ }
187
+
188
+ const filePath = path.join(this.vscodeDir, this.filename);
189
+ fs.writeFileSync(filePath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
190
+ return { success: true, count: TRIGGER_SNIPPETS.length, path: filePath };
191
+ }
192
+
193
+ list() {
194
+ const filePath = path.join(this.vscodeDir, this.filename);
195
+ if (!fs.existsSync(filePath)) return [];
196
+ try {
197
+ const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
198
+ return Object.keys(content);
199
+ } catch {
200
+ return [];
201
+ }
202
+ }
203
+
204
+ remove() {
205
+ const filePath = path.join(this.vscodeDir, this.filename);
206
+ if (fs.existsSync(filePath)) {
207
+ fs.unlinkSync(filePath);
208
+ return { removed: 1 };
209
+ }
210
+ return { removed: 0 };
211
+ }
212
+ }
213
+
214
+ // ─── 统一入口 ─────────────────────
215
+
216
+ export class SnippetInitializer {
217
+ constructor(projectRoot) {
218
+ this.xcode = new XcodeInitializer();
219
+ this.vscode = new VSCodeInitializer(projectRoot);
220
+ }
221
+
222
+ /**
223
+ * 初始化 snippet 到指定目标
224
+ * @param {string} target — 'xcode' | 'vscode' | 'all'
225
+ * @returns {{ xcode?: object, vscode?: object }}
226
+ */
227
+ async initialize(target = 'all') {
228
+ const result = {};
229
+
230
+ if (target === 'all' || target === 'xcode') {
231
+ result.xcode = this.xcode.init();
232
+ }
233
+ if (target === 'all' || target === 'vscode') {
234
+ result.vscode = this.vscode.init();
235
+ }
236
+
237
+ return result;
238
+ }
239
+
240
+ list(target = 'all') {
241
+ const result = {};
242
+ if (target === 'all' || target === 'xcode') result.xcode = this.xcode.list();
243
+ if (target === 'all' || target === 'vscode') result.vscode = this.vscode.list();
244
+ return result;
245
+ }
246
+
247
+ remove(target = 'all') {
248
+ const result = {};
249
+ if (target === 'all' || target === 'xcode') result.xcode = this.xcode.remove();
250
+ if (target === 'all' || target === 'vscode') result.vscode = this.vscode.remove();
251
+ return result;
252
+ }
253
+ }
254
+
255
+ // 导出供其他脚本使用
256
+ export default {
257
+ SnippetInitializer,
258
+ initialize: async (projectRoot, target) => {
259
+ const init = new SnippetInitializer(projectRoot);
260
+ return init.initialize(target);
261
+ },
262
+ };
263
+
264
+ // ─── CLI 入口 ─────────────────────
265
+
266
+ async function main() {
267
+ const args = process.argv.slice(2);
268
+ const command = args.find((a) => !a.startsWith('-')) || 'init';
269
+ const targetFlag = args.find((a) => a.startsWith('--target='));
270
+ const target = targetFlag ? targetFlag.split('=')[1] : 'all';
271
+
272
+ const init = new SnippetInitializer(process.cwd());
273
+
274
+ switch (command) {
275
+ case 'init': {
276
+ const result = await init.initialize(target);
277
+ console.log('✅ Snippets initialized:', JSON.stringify(result, null, 2));
278
+ break;
279
+ }
280
+ case 'list': {
281
+ const result = init.list(target);
282
+ console.log('📋 Installed snippets:', JSON.stringify(result, null, 2));
283
+ break;
284
+ }
285
+ case 'remove': {
286
+ const result = init.remove(target);
287
+ console.log('🗑️ Snippets removed:', JSON.stringify(result, null, 2));
288
+ break;
289
+ }
290
+ case 'help':
291
+ console.log(`Usage: init-snippets.js [init|list|remove] [--target=xcode|vscode|all]`);
292
+ break;
293
+ default:
294
+ console.error(`Unknown command: ${command}`);
295
+ process.exit(1);
296
+ }
297
+ }
298
+
299
+ const isMain = process.argv[1] && import.meta.url === `file://${process.argv[1]}`;
300
+ if (isMain) {
301
+ main().catch((err) => {
302
+ console.error('❌ 初始化失败:', err.message);
303
+ process.exit(1);
304
+ });
305
+ }