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
@@ -10,6 +10,7 @@
10
10
 
11
11
  import fs from 'node:fs';
12
12
  import path from 'node:path';
13
+
13
14
  const REQUIRED_FIELDS = [
14
15
  'title',
15
16
  'trigger',
@@ -17,7 +18,7 @@ const REQUIRED_FIELDS = [
17
18
  'language',
18
19
  'summary_cn',
19
20
  'summary_en',
20
- 'headers'
21
+ 'headers',
21
22
  ];
22
23
 
23
24
  const CATEGORIES = new Set([
@@ -28,7 +29,7 @@ const CATEGORIES = new Set([
28
29
  'Network',
29
30
  'Storage',
30
31
  'UI',
31
- 'Utility'
32
+ 'Utility',
32
33
  ]);
33
34
 
34
35
  const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/;
@@ -39,9 +40,11 @@ const FENCED_CODE_RE = /```(\w*)\r?\n([\s\S]*?)```/;
39
40
  function findProjectRoot(startDir) {
40
41
  let current = startDir;
41
42
  while (current && current !== path.dirname(current)) {
42
- const candidate = path.join(current, 'AutoSnippet', 'AutoSnippet.boxspec.json');
43
- if (fs.existsSync(candidate)) return current;
44
- current = path.dirname(current);
43
+ const candidate = path.join(current, 'AutoSnippet', 'AutoSnippet.boxspec.json');
44
+ if (fs.existsSync(candidate)) {
45
+ return current;
46
+ }
47
+ current = path.dirname(current);
45
48
  }
46
49
  return null;
47
50
  }
@@ -50,12 +53,12 @@ function readAllMarkdownFiles(dir) {
50
53
  const results = [];
51
54
  const entries = fs.readdirSync(dir, { withFileTypes: true });
52
55
  for (const entry of entries) {
53
- const full = path.join(dir, entry.name);
54
- if (entry.isDirectory()) {
55
- results.push(...readAllMarkdownFiles(full));
56
- } else if (entry.isFile() && entry.name.endsWith('.md')) {
57
- results.push(full);
58
- }
56
+ const full = path.join(dir, entry.name);
57
+ if (entry.isDirectory()) {
58
+ results.push(...readAllMarkdownFiles(full));
59
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
60
+ results.push(full);
61
+ }
59
62
  }
60
63
  return results;
61
64
  }
@@ -63,63 +66,78 @@ function readAllMarkdownFiles(dir) {
63
66
  function parseFrontmatter(text) {
64
67
  const out = {};
65
68
  const match = text.match(FRONTMATTER_RE);
66
- if (!match || !match[1]) return out;
69
+ if (!match || !match[1]) {
70
+ return out;
71
+ }
67
72
  const lines = match[1].split(/\r?\n/);
68
73
  let key = null;
69
74
  let valueLines = [];
70
75
  for (const line of lines) {
71
- const m = line.match(/^(\w+):\s*(.*)$/);
72
- if (m) {
73
- if (key) {
74
- out[key] = normalizeValue(valueLines.join('\n'));
75
- }
76
- key = m[1];
77
- const rest = m[2].trim();
78
- if (rest.startsWith('[')) {
79
- out[key] = parseInlineArray(rest);
80
- key = null;
81
- valueLines = [];
76
+ const m = line.match(/^(\w+):\s*(.*)$/);
77
+ if (m) {
78
+ if (key) {
79
+ out[key] = normalizeValue(valueLines.join('\n'));
80
+ }
81
+ key = m[1];
82
+ const rest = m[2].trim();
83
+ if (rest.startsWith('[')) {
84
+ out[key] = parseInlineArray(rest);
85
+ key = null;
86
+ valueLines = [];
87
+ } else {
88
+ valueLines = [rest];
89
+ }
90
+ } else if (key && line.match(/^\s*-\s+/)) {
91
+ valueLines.push(line.trim().replace(/^[-\s]+/, ''));
92
+ } else if (key && line.match(/^\s/)) {
93
+ valueLines.push(line.trim());
82
94
  } else {
83
- valueLines = [rest];
95
+ if (key) {
96
+ out[key] = normalizeValue(valueLines.join('\n'));
97
+ }
98
+ key = null;
99
+ valueLines = [];
84
100
  }
85
- } else if (key && line.match(/^\s*-\s+/)) {
86
- valueLines.push(line.trim().replace(/^[-\s]+/, ''));
87
- } else if (key && line.match(/^\s/)) {
88
- valueLines.push(line.trim());
89
- } else {
90
- if (key) {
91
- out[key] = normalizeValue(valueLines.join('\n'));
92
- }
93
- key = null;
94
- valueLines = [];
95
101
  }
102
+ if (key) {
103
+ out[key] = normalizeValue(valueLines.join('\n'));
96
104
  }
97
- if (key) out[key] = normalizeValue(valueLines.join('\n'));
98
105
  return out;
99
106
  }
100
107
 
101
108
  function parseInlineArray(str) {
102
109
  try {
103
- const parsed = JSON.parse(str.replace(/'/g, '"'));
104
- return Array.isArray(parsed) ? parsed : [String(parsed)];
110
+ const parsed = JSON.parse(str.replace(/'/g, '"'));
111
+ return Array.isArray(parsed) ? parsed : [String(parsed)];
105
112
  } catch (_) {
106
- return [str];
113
+ return [str];
107
114
  }
108
115
  }
109
116
 
110
117
  function normalizeValue(value) {
111
- if (value == null) return '';
112
- const trimmed = String(value).trim().replace(/^['"]|['"]$/g, '');
118
+ if (value == null) {
119
+ return '';
120
+ }
121
+ const trimmed = String(value)
122
+ .trim()
123
+ .replace(/^['"]|['"]$/g, '');
113
124
  if (trimmed.includes('\n')) {
114
- const list = trimmed.split(/\r?\n/).map(v => v.trim()).filter(Boolean);
115
- return list.length > 0 ? list : trimmed;
125
+ const list = trimmed
126
+ .split(/\r?\n/)
127
+ .map((v) => v.trim())
128
+ .filter(Boolean);
129
+ return list.length > 0 ? list : trimmed;
116
130
  }
117
131
  return trimmed;
118
132
  }
119
133
 
120
134
  function toArray(value) {
121
- if (Array.isArray(value)) return value;
122
- if (!value) return [];
135
+ if (Array.isArray(value)) {
136
+ return value;
137
+ }
138
+ if (!value) {
139
+ return [];
140
+ }
123
141
  return [String(value)];
124
142
  }
125
143
 
@@ -132,69 +150,76 @@ function auditRecipe(filePath, content) {
132
150
  const hasCodeBlock = FENCED_CODE_RE.test(body);
133
151
 
134
152
  for (const field of REQUIRED_FIELDS) {
135
- const value = fm[field];
136
- if (!value || (Array.isArray(value) && value.length === 0)) {
137
- issues.push(`缺少必填字段: ${field}`);
138
- }
153
+ const value = fm[field];
154
+ if (!value || (Array.isArray(value) && value.length === 0)) {
155
+ issues.push(`缺少必填字段: ${field}`);
156
+ }
139
157
  }
140
158
 
141
159
  if (fm.trigger && !String(fm.trigger).startsWith('@')) {
142
- issues.push('trigger 必须以 @ 开头');
160
+ issues.push('trigger 必须以 @ 开头');
143
161
  }
144
162
 
145
163
  if (fm.category && !CATEGORIES.has(String(fm.category))) {
146
- issues.push(`category 非法: ${fm.category}`);
164
+ issues.push(`category 非法: ${fm.category}`);
147
165
  }
148
166
 
149
- if (fm.language && !['swift', 'objectivec', 'markdown'].includes(String(fm.language).toLowerCase())) {
150
- issues.push(`language 非法: ${fm.language}`);
167
+ if (
168
+ fm.language &&
169
+ !['swift', 'objectivec', 'markdown'].includes(String(fm.language).toLowerCase())
170
+ ) {
171
+ issues.push(`language 非法: ${fm.language}`);
151
172
  }
152
173
 
153
174
  const headers = toArray(fm.headers);
154
175
  if (headers.length > 0) {
155
- const bad = headers.filter(h => !/^#import\s+<.+>$/.test(h) && !/^import\s+\w+/.test(h));
156
- if (bad.length > 0) issues.push('headers 包含非完整 import 语句');
176
+ const bad = headers.filter((h) => !/^#import\s+<.+>$/.test(h) && !/^import\s+\w+/.test(h));
177
+ if (bad.length > 0) {
178
+ issues.push('headers 包含非完整 import 语句');
179
+ }
157
180
  }
158
181
 
159
- if (!hasUsageHeading) issues.push('缺少 Usage Guide 标题');
182
+ if (!hasUsageHeading) {
183
+ issues.push('缺少 Usage Guide 标题');
184
+ }
160
185
  if (!hasSnippetHeading && hasCodeBlock) {
161
- issues.push('存在代码块但缺少 Snippet 标题');
186
+ issues.push('存在代码块但缺少 Snippet 标题');
162
187
  }
163
188
 
164
189
  const introOnly = !hasCodeBlock;
165
190
 
166
191
  return {
167
- filePath,
168
- introOnly,
169
- issues
192
+ filePath,
193
+ introOnly,
194
+ issues,
170
195
  };
171
196
  }
172
197
 
173
198
  function main() {
174
199
  const projectRoot = findProjectRoot(process.cwd());
175
200
  if (!projectRoot) {
176
- console.error('未找到项目根(AutoSnippet/AutoSnippet.boxspec.json)。');
177
- process.exit(1);
201
+ console.error('未找到项目根(AutoSnippet/AutoSnippet.boxspec.json)。');
202
+ process.exit(1);
178
203
  }
179
204
 
180
205
  const recipesDir = path.join(projectRoot, 'AutoSnippet', 'recipes');
181
206
  if (!fs.existsSync(recipesDir)) {
182
- console.error(`未找到 recipes 目录: ${recipesDir}`);
183
- process.exit(1);
207
+ console.error(`未找到 recipes 目录: ${recipesDir}`);
208
+ process.exit(1);
184
209
  }
185
210
 
186
211
  const files = readAllMarkdownFiles(recipesDir);
187
212
  const results = [];
188
213
  for (const file of files) {
189
- const content = fs.readFileSync(file, 'utf-8');
190
- results.push(auditRecipe(path.relative(projectRoot, file), content));
214
+ const content = fs.readFileSync(file, 'utf-8');
215
+ results.push(auditRecipe(path.relative(projectRoot, file), content));
191
216
  }
192
217
 
193
- const withIssues = results.filter(r => r.issues.length > 0);
218
+ const withIssues = results.filter((r) => r.issues.length > 0);
194
219
  const summary = {
195
- checked: results.length,
196
- withIssues: withIssues.length,
197
- introOnly: results.filter(r => r.introOnly).length
220
+ checked: results.length,
221
+ withIssues: withIssues.length,
222
+ introOnly: results.filter((r) => r.introOnly).length,
198
223
  };
199
224
 
200
225
  const report = { summary, results: withIssues };
@@ -203,25 +228,24 @@ function main() {
203
228
  fs.writeFileSync(path.join(reportDir, 'recipe-audit.json'), JSON.stringify(report, null, 2));
204
229
 
205
230
  const mdLines = [
206
- '# Recipe 审计报告',
207
- '',
208
- `- 总数: ${summary.checked}`,
209
- `- 有问题: ${summary.withIssues}`,
210
- `- Intro-only: ${summary.introOnly}`,
211
- '',
212
- '## 需要处理的条目',
213
- ''
231
+ '# Recipe 审计报告',
232
+ '',
233
+ `- 总数: ${summary.checked}`,
234
+ `- 有问题: ${summary.withIssues}`,
235
+ `- Intro-only: ${summary.introOnly}`,
236
+ '',
237
+ '## 需要处理的条目',
238
+ '',
214
239
  ];
215
240
 
216
241
  for (const item of withIssues) {
217
- mdLines.push(`- ${item.filePath}`);
218
- for (const issue of item.issues) {
219
- mdLines.push(` - ${issue}`);
220
- }
242
+ mdLines.push(`- ${item.filePath}`);
243
+ for (const issue of item.issues) {
244
+ mdLines.push(` - ${issue}`);
245
+ }
221
246
  }
222
247
 
223
248
  fs.writeFileSync(path.join(reportDir, 'recipe-audit.md'), mdLines.join('\n'));
224
- console.log(`审计完成:${summary.checked} 条,问题 ${summary.withIssues} 条。报告已输出到 reports/recipe-audit.*`);
225
249
  }
226
250
 
227
251
  if (require.main === module) {