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
@@ -37,15 +37,28 @@
37
37
 
38
38
  import fs from 'node:fs';
39
39
  import path from 'node:path';
40
- import { envelope } from '../envelope.js';
41
- import { inferLang, detectPrimaryLanguage, buildLanguageExtension } from './LanguageExtensions.js';
42
- import { inferTargetRole, inferFilePriority } from './TargetClassifier.js';
43
- import { analyzeProject, generateContextForAgent, isAvailable as astIsAvailable } from '../../../core/AstAnalyzer.js';
40
+ import {
41
+ analyzeProject,
42
+ isAvailable as astIsAvailable,
43
+ generateContextForAgent,
44
+ } from '../../../core/AstAnalyzer.js';
45
+ import { DimensionCopy } from '../../../shared/DimensionCopyRegistry.js';
46
+ import { LanguageService } from '../../../shared/LanguageService.js';
44
47
  import pathGuard from '../../../shared/PathGuard.js';
45
-
48
+ import { envelope } from '../envelope.js';
49
+ import {
50
+ clearCheckpoints,
51
+ clearSnapshots,
52
+ fillDimensionsV3,
53
+ } from './bootstrap/pipeline/orchestrator.js';
46
54
  // ── Sub-modules ──
47
- import { loadBootstrapSkills, extractSkillDimensionGuides, enhanceDimensions } from './bootstrap/skills.js';
48
- import { fillDimensionsV3, clearCheckpoints, clearSnapshots } from './bootstrap/pipeline/orchestrator.js';
55
+ import {
56
+ enhanceDimensions,
57
+ extractSkillDimensionGuides,
58
+ loadBootstrapSkills,
59
+ } from './bootstrap/skills.js';
60
+ import { buildLanguageExtension, detectPrimaryLanguage, inferLang } from './LanguageExtensions.js';
61
+ import { inferFilePriority, inferTargetRole } from './TargetClassifier.js';
49
62
 
50
63
  // Re-export for external consumers
51
64
  export { loadBootstrapSkills };
@@ -95,21 +108,26 @@ export async function bootstrapKnowledge(ctx, args) {
95
108
  };
96
109
 
97
110
  // ═══════════════════════════════════════════════════════════
98
- // Phase 1: 文件收集
111
+ // Phase 1: 文件收集(通过 DiscovererRegistry 自动选择项目类型)
99
112
  // ═══════════════════════════════════════════════════════════
100
- const { SpmService } = await import('../../../service/spm/SpmService.js');
101
- const spm = new SpmService(projectRoot);
102
- await spm.load();
103
- const allTargets = await spm.listTargets();
113
+ const { getDiscovererRegistry } = await import('../../../core/discovery/index.js');
114
+ const registry = getDiscovererRegistry();
115
+ const discoverer = await registry.detect(projectRoot);
116
+ ctx.logger.info(`[Bootstrap] Project type: ${discoverer.displayName} (${discoverer.id})`);
117
+
118
+ await discoverer.load(projectRoot);
119
+ const allTargets = await discoverer.listTargets();
104
120
 
105
121
  const seenPaths = new Set();
106
122
  const allFiles = []; // { name, path, relativePath, content, targetName }
107
123
  for (const t of allTargets) {
108
124
  try {
109
- const fileList = await spm.getTargetFiles(t);
125
+ const fileList = await discoverer.getTargetFiles(t);
110
126
  for (const f of fileList) {
111
127
  const fp = typeof f === 'string' ? f : f.path;
112
- if (seenPaths.has(fp)) continue;
128
+ if (seenPaths.has(fp)) {
129
+ continue;
130
+ }
113
131
  seenPaths.add(fp);
114
132
  try {
115
133
  const content = fs.readFileSync(fp, 'utf8');
@@ -120,14 +138,24 @@ export async function bootstrapKnowledge(ctx, args) {
120
138
  content,
121
139
  targetName: typeof t === 'string' ? t : t.name,
122
140
  });
123
- } catch { /* skip unreadable */ }
124
- if (allFiles.length >= maxFiles) break;
141
+ } catch {
142
+ /* skip unreadable */
143
+ }
144
+ if (allFiles.length >= maxFiles) {
145
+ break;
146
+ }
125
147
  }
126
- } catch { /* skip target */ }
127
- if (allFiles.length >= maxFiles) break;
148
+ } catch {
149
+ /* skip target */
150
+ }
151
+ if (allFiles.length >= maxFiles) {
152
+ break;
153
+ }
128
154
  }
129
155
 
130
156
  report.phases.fileCollection = {
157
+ discoverer: discoverer.id,
158
+ discovererName: discoverer.displayName,
131
159
  targets: allTargets.length,
132
160
  files: allFiles.length,
133
161
  truncated: allFiles.length >= maxFiles,
@@ -142,13 +170,27 @@ export async function bootstrapKnowledge(ctx, args) {
142
170
  try {
143
171
  const db = ctx.container.get('database');
144
172
  if (db) {
145
- const { IncrementalBootstrap } = await import('./bootstrap/pipeline/IncrementalBootstrap.js');
173
+ const { IncrementalBootstrap } = await import(
174
+ './bootstrap/pipeline/IncrementalBootstrap.js'
175
+ );
146
176
  const ib = new IncrementalBootstrap(db, projectRoot, { logger: ctx.logger });
147
- // 所有 9 个维度 ID
177
+ // 所有可能的维度 ID(动态维度在后面按语言过滤 + Enhancement Pack 追加)
148
178
  const allDimIds = [
149
- 'project-profile', 'objc-deep-scan', 'category-scan',
150
- 'code-standard', 'architecture', 'code-pattern',
151
- 'event-and-data-flow', 'best-practice', 'agent-guidelines',
179
+ 'project-profile',
180
+ 'code-standard',
181
+ 'code-pattern',
182
+ 'architecture',
183
+ 'best-practice',
184
+ 'event-and-data-flow',
185
+ 'agent-guidelines',
186
+ // 语言条件维度
187
+ 'objc-deep-scan',
188
+ 'category-scan',
189
+ 'module-export-scan',
190
+ 'framework-convention-scan',
191
+ 'python-package-scan',
192
+ 'jvm-annotation-scan',
193
+ 'go-module-scan',
152
194
  ];
153
195
  incrementalPlan = ib.evaluate(allFiles, allDimIds);
154
196
  report.phases.incrementalEvaluation = {
@@ -157,25 +199,29 @@ export async function bootstrapKnowledge(ctx, args) {
157
199
  affectedDimensions: incrementalPlan.affectedDimensions,
158
200
  skippedDimensions: incrementalPlan.skippedDimensions,
159
201
  reason: incrementalPlan.reason,
160
- diff: incrementalPlan.diff ? {
161
- added: incrementalPlan.diff.added.length,
162
- modified: incrementalPlan.diff.modified.length,
163
- deleted: incrementalPlan.diff.deleted.length,
164
- unchanged: incrementalPlan.diff.unchanged.length,
165
- changeRatio: incrementalPlan.diff.changeRatio,
166
- } : null,
202
+ diff: incrementalPlan.diff
203
+ ? {
204
+ added: incrementalPlan.diff.added.length,
205
+ modified: incrementalPlan.diff.modified.length,
206
+ deleted: incrementalPlan.diff.deleted.length,
207
+ unchanged: incrementalPlan.diff.unchanged.length,
208
+ changeRatio: incrementalPlan.diff.changeRatio,
209
+ }
210
+ : null,
167
211
  };
168
212
  if (incrementalPlan.canIncremental) {
169
213
  ctx.logger.info(
170
214
  `[Bootstrap] 🔄 Incremental mode: ${incrementalPlan.affectedDimensions.length} affected, ` +
171
- `${incrementalPlan.skippedDimensions.length} skipped — ${incrementalPlan.reason}`
215
+ `${incrementalPlan.skippedDimensions.length} skipped — ${incrementalPlan.reason}`
172
216
  );
173
217
  } else {
174
218
  ctx.logger.info(`[Bootstrap] Full mode: ${incrementalPlan.reason}`);
175
219
  }
176
220
  }
177
221
  } catch (incErr) {
178
- ctx.logger.warn(`[Bootstrap] Incremental evaluation failed (fallback to full): ${incErr.message}`);
222
+ ctx.logger.warn(
223
+ `[Bootstrap] Incremental evaluation failed (fallback to full): ${incErr.message}`
224
+ );
179
225
  }
180
226
  }
181
227
 
@@ -197,24 +243,73 @@ export async function bootstrapKnowledge(ctx, args) {
197
243
  // ═══════════════════════════════════════════════════════════
198
244
  // Phase 1.5: AST 代码结构分析(Tree-sitter)
199
245
  // ═══════════════════════════════════════════════════════════
246
+
247
+ // ── Phase 1.5a: 按需安装缺失的 tree-sitter 语法包 ──────────
248
+ let grammarInstallResult = null;
249
+ try {
250
+ const { ensureGrammars, inferLanguagesFromStats, reloadPlugins } = await import(
251
+ '../../../core/ast/ensure-grammars.js'
252
+ );
253
+ const neededLangs = inferLanguagesFromStats(langStats);
254
+ if (neededLangs.length > 0) {
255
+ grammarInstallResult = await ensureGrammars(neededLangs, { logger: ctx.logger });
256
+ if (grammarInstallResult.installed.length > 0) {
257
+ ctx.logger.info(
258
+ `[Bootstrap] Installed grammar packages: ${grammarInstallResult.installed.join(', ')} — reloading AST plugins`
259
+ );
260
+ await reloadPlugins();
261
+ }
262
+ }
263
+ // 确保 AST 插件已加载(即使没有新安装语法包 — 首次启动时需要触发 loadPlugins)
264
+ await import('../../../core/ast/index.js');
265
+ } catch (e) {
266
+ ctx.logger.warn(`[Bootstrap] Grammar auto-install skipped: ${e.message}`);
267
+ }
268
+ report.phases.grammarEnsure = grammarInstallResult || { installed: [], skipped: [], failed: [] };
269
+
270
+ // ── Phase 1.5b: AST 分析 ──────────────────────────────────
200
271
  let astProjectSummary = null;
201
272
  let astContext = '';
202
273
  const primaryLangEarly = detectPrimaryLanguage(langStats);
203
274
  if (astIsAvailable() && primaryLangEarly) {
204
275
  try {
205
- const astFiles = allFiles.map(f => ({
276
+ const astFiles = allFiles.map((f) => ({
206
277
  name: f.name,
207
278
  relativePath: f.relativePath,
208
279
  content: f.content,
209
280
  }));
210
- astProjectSummary = analyzeProject(astFiles, primaryLangEarly);
281
+
282
+ // SFC 预处理: 支持 .vue / .svelte 等框架特有文件的 <script> 提取
283
+ let sfcPreprocessor = null;
284
+ try {
285
+ const { initEnhancementRegistry } = await import('../../../core/enhancement/index.js');
286
+ const enhReg = await initEnhancementRegistry();
287
+ const allPacks = enhReg.all();
288
+ // 找到第一个提供 preprocessFile 的增强包
289
+ const preprocessPack = allPacks.find(
290
+ (p) => typeof p.preprocessFile === 'function'
291
+ );
292
+ if (preprocessPack) {
293
+ sfcPreprocessor = preprocessPack.preprocessFile.bind(preprocessPack);
294
+ }
295
+ } catch {
296
+ /* Enhancement 未加载时跳过预处理 */
297
+ }
298
+
299
+ astProjectSummary = analyzeProject(astFiles, primaryLangEarly, {
300
+ preprocessFile: sfcPreprocessor,
301
+ });
211
302
  astContext = generateContextForAgent(astProjectSummary);
212
- ctx.logger.info(`[Bootstrap] AST analysis: ${astProjectSummary.classes.length} classes, ${astProjectSummary.protocols.length} protocols, ${astProjectSummary.categories.length} categories, ${Object.keys(astProjectSummary.patternStats).length} patterns`);
303
+ ctx.logger.info(
304
+ `[Bootstrap] AST analysis: ${astProjectSummary.classes.length} classes, ${astProjectSummary.protocols.length} protocols, ${astProjectSummary.categories.length} categories, ${Object.keys(astProjectSummary.patternStats).length} patterns`
305
+ );
213
306
  } catch (e) {
214
307
  ctx.logger.warn(`[Bootstrap] AST analysis failed (graceful degradation): ${e.message}`);
215
308
  }
216
309
  } else {
217
- ctx.logger.info(`[Bootstrap] AST analysis skipped: tree-sitter ${astIsAvailable() ? 'available' : 'not available'}, lang=${primaryLangEarly}`);
310
+ ctx.logger.info(
311
+ `[Bootstrap] AST analysis skipped: tree-sitter ${astIsAvailable() ? 'available' : 'not available'}, lang=${primaryLangEarly}`
312
+ );
218
313
  }
219
314
  report.phases.astAnalysis = {
220
315
  available: astIsAvailable(),
@@ -238,7 +333,7 @@ export async function bootstrapKnowledge(ctx, args) {
238
333
  codeEntityResult = ceg.populateFromAst(astProjectSummary);
239
334
  ctx.logger.info(
240
335
  `[Bootstrap] Code Entity Graph: ${codeEntityResult.entitiesUpserted} entities, ` +
241
- `${codeEntityResult.edgesCreated} edges (${codeEntityResult.durationMs}ms)`
336
+ `${codeEntityResult.edgesCreated} edges (${codeEntityResult.durationMs}ms)`
242
337
  );
243
338
  }
244
339
  } catch (e) {
@@ -252,39 +347,48 @@ export async function bootstrapKnowledge(ctx, args) {
252
347
  };
253
348
 
254
349
  // ═══════════════════════════════════════════════════════════
255
- // Phase 2: SPM 依赖关系 → knowledge_edges
350
+ // Phase 2: 依赖关系 → knowledge_edges
256
351
  // ═══════════════════════════════════════════════════════════
257
352
  let depEdgesWritten = 0;
258
353
  let depGraphData = null;
259
354
  try {
260
355
  const knowledgeGraphService = ctx.container.get('knowledgeGraphService');
261
- depGraphData = await spm.getDependencyGraph();
356
+ depGraphData = await discoverer.getDependencyGraph();
262
357
  if (knowledgeGraphService) {
263
- for (const edge of (depGraphData.edges || [])) {
358
+ for (const edge of depGraphData.edges || []) {
264
359
  const result = knowledgeGraphService.addEdge(
265
- edge.from, 'module', edge.to, 'module', 'depends_on',
266
- { weight: 1.0, source: 'spm-bootstrap' },
360
+ edge.from,
361
+ 'module',
362
+ edge.to,
363
+ 'module',
364
+ 'depends_on',
365
+ { weight: 1.0, source: `${discoverer.id}-bootstrap` }
267
366
  );
268
- if (result.success) depEdgesWritten++;
367
+ if (result.success) {
368
+ depEdgesWritten++;
369
+ }
269
370
  }
270
371
  }
271
372
  } catch (e) {
272
- ctx.logger.warn(`[Bootstrap] SPM→Graph failed: ${e.message}`);
373
+ ctx.logger.warn(`[Bootstrap] DepGraph failed: ${e.message}`);
273
374
  }
274
- report.phases.spmDependencyGraph = { edgesWritten: depEdgesWritten };
375
+ report.phases.dependencyGraph = { edgesWritten: depEdgesWritten };
275
376
 
276
- // Phase 2.1: SPM module 实体节点写入 Code Entity Graph
377
+ // Phase 2.1: Module 实体节点写入 Code Entity Graph
277
378
  if (depGraphData?.nodes?.length > 0) {
278
379
  try {
279
380
  const { CodeEntityGraph } = await import('../../../service/knowledge/CodeEntityGraph.js');
280
381
  const db = ctx.container.get('database');
281
382
  if (db) {
282
383
  const ceg = new CodeEntityGraph(db, { projectRoot });
283
- const spmResult = ceg.populateFromSpm(depGraphData);
284
- ctx.logger.info(`[Bootstrap] Code Entity Graph SPM: ${spmResult.entitiesUpserted} module entities`);
384
+ // populateFromSpm 接受通用的 { nodes, edges } 结构,不仅限于 SPM
385
+ const depResult = ceg.populateFromSpm(depGraphData);
386
+ ctx.logger.info(
387
+ `[Bootstrap] Code Entity Graph modules: ${depResult.entitiesUpserted} entities`
388
+ );
285
389
  }
286
390
  } catch (e) {
287
- ctx.logger.warn(`[Bootstrap] Code Entity Graph SPM failed: ${e.message}`);
391
+ ctx.logger.warn(`[Bootstrap] Code Entity Graph modules failed: ${e.message}`);
288
392
  }
289
393
  }
290
394
 
@@ -297,13 +401,13 @@ export async function bootstrapKnowledge(ctx, args) {
297
401
  const { GuardCheckEngine } = await import('../../../service/guard/GuardCheckEngine.js');
298
402
  const db = ctx.container.get('database');
299
403
  const engine = new GuardCheckEngine(db);
300
- const guardFiles = allFiles.map(f => ({ path: f.path, content: f.content }));
404
+ const guardFiles = allFiles.map((f) => ({ path: f.path, content: f.content }));
301
405
  guardAudit = engine.auditFiles(guardFiles, { scope: 'project' });
302
406
 
303
407
  // 写入 ViolationsStore
304
408
  try {
305
409
  const violationsStore = ctx.container.get('violationsStore');
306
- for (const fileResult of (guardAudit.files || [])) {
410
+ for (const fileResult of guardAudit.files || []) {
307
411
  if (fileResult.violations.length > 0) {
308
412
  violationsStore.appendRun({
309
413
  filePath: fileResult.filePath,
@@ -312,27 +416,31 @@ export async function bootstrapKnowledge(ctx, args) {
312
416
  });
313
417
  }
314
418
  }
315
- } catch { /* ViolationsStore not available */ }
419
+ } catch {
420
+ /* ViolationsStore not available */
421
+ }
316
422
  } catch (e) {
317
423
  ctx.logger.warn(`[Bootstrap] Guard audit failed: ${e.message}`);
318
424
  }
319
425
  }
320
426
  report.phases.guardAudit = {
321
427
  totalViolations: guardAudit?.summary?.totalViolations || 0,
322
- filesWithViolations: (guardAudit?.files || []).filter(f => f.violations.length > 0).length,
428
+ filesWithViolations: (guardAudit?.files || []).filter((f) => f.violations.length > 0).length,
323
429
  skipped: skipGuard,
324
430
  };
325
431
  report.totals.guardViolations = guardAudit?.summary?.totalViolations || 0;
326
432
  report.totals.graphEdges = depEdgesWritten;
327
433
 
328
- const elapsed = Date.now() - t0;
434
+ const _elapsed = Date.now() - t0;
329
435
 
330
436
  // ═══════════════════════════════════════════════════════════
331
437
  // Phase 4: 构建响应 — filesByTarget + analysisFramework
332
438
  // ═══════════════════════════════════════════════════════════
333
439
  const targetFileMap = {};
334
440
  for (const f of allFiles) {
335
- if (!targetFileMap[f.targetName]) targetFileMap[f.targetName] = [];
441
+ if (!targetFileMap[f.targetName]) {
442
+ targetFileMap[f.targetName] = [];
443
+ }
336
444
  const lines = f.content.split('\n');
337
445
  targetFileMap[f.targetName].push({
338
446
  name: f.name,
@@ -370,17 +478,23 @@ export async function bootstrapKnowledge(ctx, args) {
370
478
  const skillsEnhanced = Object.keys(skillGuides).length > 0;
371
479
 
372
480
  if (skillsEnhanced) {
373
- ctx.logger.info(`[Bootstrap] Skill dimension guides extracted for: ${Object.keys(skillGuides).join(', ')}`);
481
+ ctx.logger.info(
482
+ `[Bootstrap] Skill dimension guides extracted for: ${Object.keys(skillGuides).join(', ')}`
483
+ );
374
484
  // 输出每个 guide 的前 80 字符用于诊断
375
485
  for (const [dimId, guide] of Object.entries(skillGuides)) {
376
486
  ctx.logger.debug(`[Bootstrap] Skill guide [${dimId}]: ${guide.substring(0, 80)}...`);
377
487
  }
378
488
  // 输出 sectionMap 诊断
379
489
  for (const [dimId, sections] of Object.entries(skillSections)) {
380
- ctx.logger.debug(`[Bootstrap] Skill sections [${dimId}]: ${sections.length} section(s) — ${sections.map(s => s.title).join(', ')}`);
490
+ ctx.logger.debug(
491
+ `[Bootstrap] Skill sections [${dimId}]: ${sections.length} section(s) — ${sections.map((s) => s.title).join(', ')}`
492
+ );
381
493
  }
382
494
  } else {
383
- ctx.logger.warn('[Bootstrap] No skill dimension guides extracted — Skills may not match expected format');
495
+ ctx.logger.warn(
496
+ '[Bootstrap] No skill dimension guides extracted — Skills may not match expected format'
497
+ );
384
498
  }
385
499
 
386
500
  report.phases.skillLoading = {
@@ -398,41 +512,278 @@ export async function bootstrapKnowledge(ctx, args) {
398
512
  // ⑧ ⑨ 提前到 ⑥ 前面执行 → deep-scan / category-scan 的中间结果
399
513
  // 通过 PipelineContext 缓存,供 project-profile 复用,避免重复扫描
400
514
  const baseDimensions = [
401
- // 代码规范(Dual: Skill + Candidate)— 新增 api-naming、comment-style 子主题
402
- { id: 'code-standard', label: '代码规范', guide: '命名约定(类名前缀/方法签名风格/API 命名)、注释风格(语言/格式/MARK 分段)、文件组织规范', knowledgeTypes: ['code-standard', 'code-style'],
403
- skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-code-standard', description: 'Project coding standards and naming conventions (auto-generated by bootstrap)' } },
404
- // ② 代码模式(Candidate)— 新增 builder、observer、coordinator
405
- { id: 'code-pattern', label: '设计模式与代码惯例', guide: '单例/委托/Category·Extension/工厂/Builder/观察者/Coordinator 模式、继承关系', knowledgeTypes: ['code-pattern', 'code-relation', 'inheritance'] },
406
- // ③ 架构模式(Dual: Skill + Candidate)— 新增 boundary-rules 子主题
407
- { id: 'architecture', label: '架构模式', guide: '分层架构、模块职责与边界、依赖图、导入约束规则', knowledgeTypes: ['architecture', 'module-dependency', 'boundary-constraint'],
408
- skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-architecture', description: 'Project architecture layers, module boundaries and dependency graph (auto-generated by bootstrap)' } },
409
- // 最佳实践(Candidate)— 新增 logging、testing 子主题
410
- { id: 'best-practice', label: '最佳实践', guide: '错误处理、并发安全、内存管理、日志规范、测试模式', knowledgeTypes: ['best-practice'] },
411
- // ⑤ 事件与数据流(Candidate)— 合并原 call-chain + data-flow,消除重叠
412
- { id: 'event-and-data-flow', label: '事件与数据流', guide: '事件传播(Delegate/Notification/Block·Closure/Target-Action)、数据状态管理(KVO/属性观察/响应式/持久化)', knowledgeTypes: ['call-chain', 'data-flow'] },
413
- // ⑧ ObjC/Swift 深度扫描(dualOutput: Skill + Candidate → Recipe → Snippet)— 常量 + Hook
414
- // ★ 提前到 ⑥ 前面执行,中间结果缓存到 PipelineContext 供 project-profile 复用
415
- { id: 'objc-deep-scan', label: '深度扫描(常量/Hook)', guide: '全量扫描 #define 值宏/函数宏、extern/static 常量、Method Swizzling hook 对(Agent 必须使用项目常量,修改被 hook 方法前必须查阅 hook 清单)', knowledgeTypes: ['code-standard', 'code-pattern'],
416
- skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-objc-deep-scan', description: 'Project #define macros, static constants, and Method Swizzling hooks (auto-generated by bootstrap)' } },
417
- // ⑨ Foundation/UIKit Category/Extension 专项扫描(dualOutput: Skill + Candidate → Recipe → Snippet)
418
- // 提前到 ⑥ 前面执行,分类方法清单缓存到 PipelineContext 供 project-profile/base-extensions 复用
419
- { id: 'category-scan', label: '基础类分类方法扫描', guide: 'Foundation/UIKit Category/Extension 逐方法清单(含完整实现代码与项目使用频次),仅扫描基础类分类、不含业务代码(Agent 遇到同等功能必须使用项目已有分类方法,禁止重复实现)', knowledgeTypes: ['code-standard', 'code-pattern'],
420
- skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-category-scan', description: 'Foundation/UIKit Category and Extension methods with implementations and usage patterns — base classes only, no business code (auto-generated by bootstrap)' } },
421
- // ⑥ 项目特征(Dual: Skill + Candidate)— v4.2: 8 个子主题
422
- // 排在 ⑧⑨ 之后,可从 PipelineContext 读取 deep-scan/category-scan 的缓存结果
423
- { id: 'project-profile', label: '项目特征', guide: '技术栈、目录结构、三方依赖枚举与用途、Extension/Category 分类聚合、自定义基类层级与全局定义(宏/typealias/PCH)、系统事件 hook 与生命周期入口、基础设施服务注册表、Runtime 与语言互操作', knowledgeTypes: ['architecture'],
424
- skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-profile', description: 'Project tech stack, module structure, third-party dependencies, base extensions/classes, event hooks, infrastructure services, and runtime/interop features (auto-generated by bootstrap)' } },
425
- // Agent 开发注意事项(Skill)— 新增 deprecated-api、arch-constraints、coding-principles 子主题
426
- { id: 'agent-guidelines', label: 'Agent开发注意事项', guide: '三大核心原则(严谨性/深度特征挖掘/完整性)、命名强制、线程安全、内存约束、已废弃 API 标记、架构约束注释、TODO/FIXME', knowledgeTypes: ['boundary-constraint', 'code-standard'],
427
- skillWorthy: true, skillMeta: { name: 'project-agent-guidelines', description: 'Mandatory coding rules, deprecated APIs and agent constraints for this project (auto-generated by bootstrap)' } },
515
+ // ── 通用维度(所有语言共享)──────────────────────────────────
516
+
517
+ // 代码规范(Dual: Skill + Candidate)
518
+ {
519
+ id: 'code-standard',
520
+ label: '代码规范',
521
+ guide:
522
+ '命名约定(类名前缀/方法签名风格/API 命名)、注释风格(语言/格式/MARK 分段)、文件组织规范',
523
+ knowledgeTypes: ['code-standard', 'code-style'],
524
+ skillWorthy: true,
525
+ dualOutput: true,
526
+ skillMeta: {
527
+ name: 'project-code-standard',
528
+ description:
529
+ 'Project coding standards and naming conventions (auto-generated by bootstrap)',
530
+ },
531
+ },
532
+ // 代码模式(Candidate)
533
+ {
534
+ id: 'code-pattern',
535
+ label: '设计模式与代码惯例',
536
+ guide: '单例/委托/Category·Extension/工厂/Builder/观察者/Coordinator 模式、继承关系',
537
+ knowledgeTypes: ['code-pattern', 'code-relation', 'inheritance'],
538
+ },
539
+ // 架构模式(Dual: Skill + Candidate)
540
+ {
541
+ id: 'architecture',
542
+ label: '架构模式',
543
+ guide: '分层架构、模块职责与边界、依赖图、导入约束规则',
544
+ knowledgeTypes: ['architecture', 'module-dependency', 'boundary-constraint'],
545
+ skillWorthy: true,
546
+ dualOutput: true,
547
+ skillMeta: {
548
+ name: 'project-architecture',
549
+ description:
550
+ 'Project architecture layers, module boundaries and dependency graph (auto-generated by bootstrap)',
551
+ },
552
+ },
553
+ // ④ 最佳实践(Candidate)
554
+ {
555
+ id: 'best-practice',
556
+ label: '最佳实践',
557
+ guide: '错误处理、并发安全、内存管理、日志规范、测试模式',
558
+ knowledgeTypes: ['best-practice'],
559
+ },
560
+ // ⑤ 事件与数据流(Candidate)
561
+ {
562
+ id: 'event-and-data-flow',
563
+ label: '事件与数据流',
564
+ guide:
565
+ '事件传播(Delegate/Notification/Block·Closure/Target-Action)、数据状态管理(KVO/属性观察/响应式/持久化)',
566
+ knowledgeTypes: ['call-chain', 'data-flow'],
567
+ },
568
+ // ⑥ 项目特征(Dual: Skill + Candidate)
569
+ {
570
+ id: 'project-profile',
571
+ label: '项目特征',
572
+ guide:
573
+ '技术栈、目录结构、三方依赖枚举与用途、Extension/Category 分类聚合、自定义基类层级与全局定义(宏/typealias/PCH)、系统事件 hook 与生命周期入口、基础设施服务注册表、Runtime 与语言互操作',
574
+ knowledgeTypes: ['architecture'],
575
+ skillWorthy: true,
576
+ dualOutput: true,
577
+ skillMeta: {
578
+ name: 'project-profile',
579
+ description:
580
+ 'Project tech stack, module structure, third-party dependencies, base extensions/classes, event hooks, infrastructure services, and runtime/interop features (auto-generated by bootstrap)',
581
+ },
582
+ },
583
+ // ⑦ Agent 开发注意事项(Skill)
584
+ {
585
+ id: 'agent-guidelines',
586
+ label: 'Agent开发注意事项',
587
+ guide:
588
+ '三大核心原则(严谨性/深度特征挖掘/完整性)、命名强制、线程安全、内存约束、已废弃 API 标记、架构约束注释、TODO/FIXME',
589
+ knowledgeTypes: ['boundary-constraint', 'code-standard'],
590
+ skillWorthy: true,
591
+ skillMeta: {
592
+ name: 'project-agent-guidelines',
593
+ description:
594
+ 'Mandatory coding rules, deprecated APIs and agent constraints for this project (auto-generated by bootstrap)',
595
+ },
596
+ },
597
+
598
+ // ── 语言条件维度(按 conditions 过滤)──────────────────────
599
+
600
+ // ⑧ ObjC/Swift 深度扫描
601
+ {
602
+ id: 'objc-deep-scan',
603
+ label: '深度扫描(常量/Hook)',
604
+ guide:
605
+ '全量扫描 #define 值宏/函数宏、extern/static 常量、Method Swizzling hook 对(Agent 必须使用项目常量,修改被 hook 方法前必须查阅 hook 清单)',
606
+ knowledgeTypes: ['code-standard', 'code-pattern'],
607
+ conditions: { languages: ['objectivec', 'swift'] },
608
+ skillWorthy: true,
609
+ dualOutput: true,
610
+ skillMeta: {
611
+ name: 'project-objc-deep-scan',
612
+ description:
613
+ 'Project #define macros, static constants, and Method Swizzling hooks (auto-generated by bootstrap)',
614
+ },
615
+ },
616
+ // ⑨ Foundation/UIKit Category/Extension 专项扫描
617
+ {
618
+ id: 'category-scan',
619
+ label: '基础类分类方法扫描',
620
+ guide:
621
+ 'Foundation/UIKit Category/Extension 逐方法清单(含完整实现代码与项目使用频次),仅扫描基础类分类、不含业务代码(Agent 遇到同等功能必须使用项目已有分类方法,禁止重复实现)',
622
+ knowledgeTypes: ['code-standard', 'code-pattern'],
623
+ conditions: { languages: ['objectivec', 'swift'] },
624
+ skillWorthy: true,
625
+ dualOutput: true,
626
+ skillMeta: {
627
+ name: 'project-category-scan',
628
+ description:
629
+ 'Foundation/UIKit Category and Extension methods with implementations and usage patterns — base classes only, no business code (auto-generated by bootstrap)',
630
+ },
631
+ },
632
+
633
+ // ⑩ TS/JS 模块导出分析
634
+ {
635
+ id: 'module-export-scan',
636
+ label: '模块导出分析',
637
+ guide: 'barrel export 结构、re-export 链路、public API surface、tree-shaking 合规性',
638
+ knowledgeTypes: ['code-standard', 'architecture'],
639
+ conditions: { languages: ['typescript', 'javascript'] },
640
+ skillWorthy: true,
641
+ dualOutput: true,
642
+ skillMeta: {
643
+ name: 'project-module-exports',
644
+ description: 'Module export structure and public API surface (auto-generated by bootstrap)',
645
+ },
646
+ },
647
+ // ⑪ TS/JS 框架约定扫描
648
+ {
649
+ id: 'framework-convention-scan',
650
+ label: '框架约定扫描',
651
+ guide: '组件目录结构、状态管理约定、路由约定、样式约定、数据获取模式',
652
+ knowledgeTypes: ['code-standard', 'architecture'],
653
+ conditions: {
654
+ languages: ['typescript', 'javascript'],
655
+ frameworks: ['react', 'vue', 'angular', 'nextjs', 'nuxt'],
656
+ },
657
+ skillWorthy: true,
658
+ dualOutput: true,
659
+ skillMeta: {
660
+ name: 'project-framework-conventions',
661
+ description: 'Framework-specific conventions and patterns (auto-generated by bootstrap)',
662
+ },
663
+ },
664
+
665
+ // ⑫ Python 包结构分析
666
+ {
667
+ id: 'python-package-scan',
668
+ label: 'Python 包结构分析',
669
+ guide:
670
+ '__init__.py 导出策略、相对/绝对导入风格、type hints 覆盖率、decorator 使用模式、__all__ 定义',
671
+ knowledgeTypes: ['code-standard', 'architecture'],
672
+ conditions: { languages: ['python'] },
673
+ skillWorthy: true,
674
+ dualOutput: true,
675
+ skillMeta: {
676
+ name: 'project-python-structure',
677
+ description:
678
+ 'Python package structure, import patterns and type hint coverage (auto-generated by bootstrap)',
679
+ },
680
+ },
681
+
682
+ // ⑬ Java/Kotlin 注解扫描
683
+ {
684
+ id: 'jvm-annotation-scan',
685
+ label: '注解/Annotation 扫描',
686
+ guide:
687
+ 'DI 注解(@Inject/@Autowired/@Component)、ORM 注解(@Entity/@Table)、API 注解(@RestController/@RequestMapping)、自定义注解、元编程模式',
688
+ knowledgeTypes: ['code-pattern', 'architecture'],
689
+ conditions: { languages: ['java', 'kotlin'] },
690
+ skillWorthy: true,
691
+ dualOutput: true,
692
+ skillMeta: {
693
+ name: 'project-jvm-annotations',
694
+ description:
695
+ 'Annotation/DI usage patterns and meta-programming (auto-generated by bootstrap)',
696
+ },
697
+ },
698
+
699
+ // ⑭ Go 模块结构分析
700
+ {
701
+ id: 'go-module-scan',
702
+ label: 'Go 模块结构分析',
703
+ guide:
704
+ 'go.mod 依赖图、internal 包隔离边界、cmd/ 入口点枚举、build tags/constraints、interface 分布与实现关系、init() 函数清单',
705
+ knowledgeTypes: ['architecture', 'code-pattern'],
706
+ conditions: { languages: ['go'] },
707
+ skillWorthy: true,
708
+ dualOutput: true,
709
+ skillMeta: {
710
+ name: 'project-go-module-structure',
711
+ description:
712
+ 'Go module structure, internal packages, build tags and interface distribution (auto-generated by bootstrap)',
713
+ },
714
+ },
428
715
  ];
429
716
 
717
+ // ── 根据项目主语言和框架过滤条件维度 ──────────────────────
718
+ const detectedFrameworks = allTargets
719
+ .map((t) => (typeof t === 'object' ? t.framework : null))
720
+ .filter(Boolean);
721
+ const activeDimensions = _resolveActiveDimensions(
722
+ baseDimensions,
723
+ primaryLang,
724
+ detectedFrameworks
725
+ );
726
+
727
+ // ── Enhancement Pack 动态追加维度 + Guard 规则 ─────────────
728
+ const enhancementPackInfo = [];
729
+ const enhancementGuardRules = [];
730
+ const enhancementPatterns = [];
731
+ try {
732
+ const { initEnhancementRegistry } = await import('../../../core/enhancement/index.js');
733
+ const enhReg = await initEnhancementRegistry();
734
+ const matchedPacks = enhReg.resolve(primaryLang, detectedFrameworks);
735
+ for (const pack of matchedPacks) {
736
+ enhancementPackInfo.push({ id: pack.id, displayName: pack.displayName });
737
+ // 追加额外维度
738
+ const extraDims = pack.getExtraDimensions();
739
+ for (const dim of extraDims) {
740
+ // 避免与 baseDimensions 中已有的 id 重复
741
+ if (!activeDimensions.some((d) => d.id === dim.id)) {
742
+ activeDimensions.push(dim);
743
+ }
744
+ }
745
+ // 收集 Guard 规则
746
+ const guardRules = pack.getGuardRules();
747
+ if (guardRules.length > 0) {
748
+ enhancementGuardRules.push(...guardRules);
749
+ }
750
+ // 收集 AST 模式检测
751
+ if (astProjectSummary) {
752
+ try {
753
+ const patterns = pack.detectPatterns(astProjectSummary);
754
+ if (patterns.length > 0) {
755
+ enhancementPatterns.push(...patterns.map((p) => ({ ...p, source: pack.id })));
756
+ }
757
+ } catch {
758
+ /* graceful degradation */
759
+ }
760
+ }
761
+ }
762
+ if (matchedPacks.length > 0) {
763
+ ctx.logger.info(
764
+ `[Bootstrap] Enhancement packs matched: ${matchedPacks.map((p) => p.id).join(', ')} → +${activeDimensions.length - baseDimensions.length} extra dims, ${enhancementGuardRules.length} guard rules, ${enhancementPatterns.length} patterns`
765
+ );
766
+ }
767
+ } catch (enhErr) {
768
+ ctx.logger.warn(`[Bootstrap] Enhancement pack loading skipped: ${enhErr.message}`);
769
+ }
770
+ report.phases.enhancementPacks = {
771
+ matched: enhancementPackInfo,
772
+ extraDimensions: enhancementPackInfo.length,
773
+ guardRules: enhancementGuardRules.length,
774
+ patterns: enhancementPatterns.length,
775
+ };
776
+
777
+ // 按项目语言画像注入差异化文案(支持多语言项目)
778
+ const langProfile = LanguageService.detectProfile(langStats);
779
+ DimensionCopy.applyMulti(activeDimensions, langProfile.primary, langProfile.secondary);
780
+
430
781
  // 用 Skill 内容增强维度 guide(共享层增强点)
431
- const dimensions = enhanceDimensions(baseDimensions, skillGuides, skillSections);
782
+ const dimensions = enhanceDimensions(activeDimensions, skillGuides, skillSections);
432
783
 
433
784
  const responseData = {
434
785
  report,
435
- targets: allTargets.map(t => {
786
+ targets: allTargets.map((t) => {
436
787
  const name = typeof t === 'string' ? t : t.name;
437
788
  return {
438
789
  name,
@@ -448,65 +799,102 @@ export async function bootstrapKnowledge(ctx, args) {
448
799
  Object.entries(targetFileMap).map(([target, files]) => {
449
800
  const sorted = [...files].sort((a, b) => (b.priority || 0) - (a.priority || 0));
450
801
  const top = sorted.slice(0, 10);
451
- return [target, {
452
- totalFiles: files.length,
453
- topFiles: top.map(({ content, ...meta }) => meta),
454
- ...(files.length > 10 ? { truncated: true } : {}),
455
- }];
802
+ return [
803
+ target,
804
+ {
805
+ totalFiles: files.length,
806
+ topFiles: top.map(({ content, ...meta }) => meta),
807
+ ...(files.length > 10 ? { truncated: true } : {}),
808
+ },
809
+ ];
456
810
  })
457
811
  ),
458
- dependencyGraph: depGraphData ? {
459
- nodes: (depGraphData.nodes || []).map(n => ({
460
- id: typeof n === 'string' ? n : n.id,
461
- label: typeof n === 'string' ? n : n.label,
462
- })),
463
- edges: depGraphData.edges || [],
464
- } : null,
812
+ dependencyGraph: depGraphData
813
+ ? {
814
+ nodes: (depGraphData.nodes || []).map((n) => ({
815
+ id: typeof n === 'string' ? n : n.id,
816
+ label: typeof n === 'string' ? n : n.label,
817
+ })),
818
+ edges: depGraphData.edges || [],
819
+ }
820
+ : null,
465
821
  languageStats: langStats,
466
822
  primaryLanguage: primaryLang,
823
+ secondaryLanguages: langProfile.secondary,
824
+ isMultiLang: langProfile.isMultiLang,
467
825
  languageExtension: buildLanguageExtension(primaryLang),
468
- guardSummary: guardAudit ? {
469
- totalViolations: guardAudit.summary?.totalViolations || 0,
470
- errors: guardAudit.summary?.errors || 0,
471
- warnings: guardAudit.summary?.warnings || 0,
472
- } : null,
826
+ guardSummary: guardAudit
827
+ ? {
828
+ totalViolations: guardAudit.summary?.totalViolations || 0,
829
+ errors: guardAudit.summary?.errors || 0,
830
+ warnings: guardAudit.summary?.warnings || 0,
831
+ }
832
+ : null,
473
833
  guardViolationFiles: guardAudit
474
- ? (guardAudit.files || []).filter(f => f.violations.length > 0).map(f => ({
475
- filePath: f.filePath,
476
- violations: f.violations.map(v => ({ ruleId: v.ruleId, severity: v.severity, message: v.message, line: v.line })),
477
- }))
834
+ ? (guardAudit.files || [])
835
+ .filter((f) => f.violations.length > 0)
836
+ .map((f) => ({
837
+ filePath: f.filePath,
838
+ violations: f.violations.map((v) => ({
839
+ ruleId: v.ruleId,
840
+ severity: v.severity,
841
+ message: v.message,
842
+ line: v.line,
843
+ })),
844
+ }))
478
845
  : [],
479
846
 
480
847
  // 9 维度分析框架(4 Skill-only + 2 dualOutput + 3 Candidate-only)
481
848
  // 注意:anti-pattern 已移除,代码问题由 Guard 独立处理
482
849
  analysisFramework: {
483
850
  dimensions,
484
- skillWorthyDimensions: dimensions.filter(d => d.skillWorthy).map(d => d.id),
485
- candidateOnlyDimensions: dimensions.filter(d => !d.skillWorthy).map(d => d.id),
486
- candidateRequiredFields: ['title', 'code', 'language', 'category', 'knowledgeType', 'reasoning'],
851
+ skillWorthyDimensions: dimensions.filter((d) => d.skillWorthy).map((d) => d.id),
852
+ candidateOnlyDimensions: dimensions.filter((d) => !d.skillWorthy).map((d) => d.id),
853
+ candidateRequiredFields: [
854
+ 'title',
855
+ 'code',
856
+ 'language',
857
+ 'category',
858
+ 'knowledgeType',
859
+ 'reasoning',
860
+ ],
487
861
  submissionTool: 'autosnippet_submit_knowledge_batch',
488
- expectedOutput: '候选知识(微观代码维度:code-pattern/best-practice/event-and-data-flow + 深度扫描:objc-deep-scan/category-scan)+ 6 个 Project Skills(宏观叙事维度:code-standard/architecture/project-profile/agent-guidelines + 深度扫描:objc-deep-scan/category-scan)',
862
+ expectedOutput: `候选知识(微观代码维度:code-pattern/best-practice/event-and-data-flow + 语言条件扫描)+ Project Skills(宏观叙事维度:code-standard/architecture/project-profile/agent-guidelines + 语言条件扫描)— 共 ${dimensions.length} 个维度`,
489
863
  },
490
864
 
491
865
  // AST 代码结构分析上下文(供 ChatAgent 使用)
492
866
  astContext: astContext || null,
493
- astSummary: astProjectSummary ? {
494
- classes: astProjectSummary.classes.length,
495
- protocols: astProjectSummary.protocols.length,
496
- categories: astProjectSummary.categories.length,
497
- patterns: Object.keys(astProjectSummary.patternStats || {}),
498
- metrics: astProjectSummary.projectMetrics ? {
499
- totalMethods: astProjectSummary.projectMetrics.totalMethods,
500
- avgMethodsPerClass: astProjectSummary.projectMetrics.avgMethodsPerClass,
501
- maxNestingDepth: astProjectSummary.projectMetrics.maxNestingDepth,
502
- complexMethods: astProjectSummary.projectMetrics.complexMethods?.length || 0,
503
- longMethods: astProjectSummary.projectMetrics.longMethods?.length || 0,
504
- } : null,
505
- } : null,
867
+ astSummary: astProjectSummary
868
+ ? {
869
+ classes: astProjectSummary.classes.length,
870
+ protocols: astProjectSummary.protocols.length,
871
+ categories: astProjectSummary.categories.length,
872
+ patterns: Object.keys(astProjectSummary.patternStats || {}),
873
+ metrics: astProjectSummary.projectMetrics
874
+ ? {
875
+ totalMethods: astProjectSummary.projectMetrics.totalMethods,
876
+ avgMethodsPerClass: astProjectSummary.projectMetrics.avgMethodsPerClass,
877
+ maxNestingDepth: astProjectSummary.projectMetrics.maxNestingDepth,
878
+ complexMethods: astProjectSummary.projectMetrics.complexMethods?.length || 0,
879
+ longMethods: astProjectSummary.projectMetrics.longMethods?.length || 0,
880
+ }
881
+ : null,
882
+ }
883
+ : null,
884
+
885
+ // Enhancement Pack 检测到的额外模式
886
+ enhancementPacks:
887
+ enhancementPackInfo.length > 0
888
+ ? {
889
+ matched: enhancementPackInfo,
890
+ patterns: enhancementPatterns,
891
+ guardRules: enhancementGuardRules.length,
892
+ }
893
+ : null,
506
894
 
507
895
  // 引导 Agent 下一步操作
508
896
  nextSteps: [
509
- '✅ Bootstrap 骨架已创建,9 个维度的 AI 分析任务已在后台启动。',
897
+ `✅ Bootstrap 骨架已创建,${dimensions.length} 个维度的 AI 分析任务已在后台启动。`,
510
898
  '',
511
899
  '== 后台自动执行中 ==',
512
900
  '后台 AI pipeline 正在逐维度分析代码并创建候选(Analyst → Producer 双 Agent 模式)。',
@@ -519,7 +907,10 @@ export async function bootstrapKnowledge(ctx, args) {
519
907
  '4. 使用 autosnippet_skill({ operation: "load", name }) 加载自动生成的 Project Skills',
520
908
  '',
521
909
  '== 宏观维度 → Project Skills ==',
522
- '宏观维度(architecture/code-standard/project-profile/agent-guidelines/objc-deep-scan/category-scan)',
910
+ `宏观维度(${dimensions
911
+ .filter((d) => d.skillWorthy)
912
+ .map((d) => d.id)
913
+ .join('/')})`,
523
914
  '自动生成 Project Skill 到 AutoSnippet/skills/,可通过 autosnippet_skill({ operation: "load" }) 加载。',
524
915
  ],
525
916
  };
@@ -534,7 +925,7 @@ export async function bootstrapKnowledge(ctx, args) {
534
925
  // ═══════════════════════════════════════════════════════════
535
926
 
536
927
  // 构建任务定义列表
537
- const taskDefs = dimensions.map(dim => ({
928
+ const taskDefs = dimensions.map((dim) => ({
538
929
  id: dim.id,
539
930
  meta: {
540
931
  type: dim.skillWorthy ? 'skill' : 'candidate',
@@ -551,7 +942,9 @@ export async function bootstrapKnowledge(ctx, args) {
551
942
  const taskManager = ctx.container.get('bootstrapTaskManager');
552
943
  bootstrapSession = taskManager.startSession(taskDefs);
553
944
  } catch (e) {
554
- ctx.logger.warn(`[Bootstrap] BootstrapTaskManager init failed (graceful degradation): ${e.message}`);
945
+ ctx.logger.warn(
946
+ `[Bootstrap] BootstrapTaskManager init failed (graceful degradation): ${e.message}`
947
+ );
555
948
  }
556
949
 
557
950
  // 立即构建骨架响应
@@ -575,7 +968,13 @@ export async function bootstrapKnowledge(ctx, args) {
575
968
  astProjectSummary,
576
969
  skillContext,
577
970
  skillsEnhanced,
578
- taskManager: (() => { try { return ctx.container.get('bootstrapTaskManager'); } catch { return null; } })(),
971
+ taskManager: (() => {
972
+ try {
973
+ return ctx.container.get('bootstrapTaskManager');
974
+ } catch {
975
+ return null;
976
+ }
977
+ })(),
579
978
  sessionId: bootstrapSession?.id || null,
580
979
  projectRoot,
581
980
  // v5.0: 增量 Bootstrap 计划
@@ -585,7 +984,7 @@ export async function bootstrapKnowledge(ctx, args) {
585
984
  // 使用 setImmediate 避免阻塞 HTTP 响应
586
985
  setImmediate(() => {
587
986
  ctx.logger.info(`[Bootstrap] Dispatching v3 AI-First pipeline`);
588
- fillDimensionsV3(fillContext).catch(e => {
987
+ fillDimensionsV3(fillContext).catch((e) => {
589
988
  ctx.logger.error(`[Bootstrap] Async fill (v3) failed: ${e.message}`);
590
989
  });
591
990
  });
@@ -593,16 +992,23 @@ export async function bootstrapKnowledge(ctx, args) {
593
992
  // ── SkillHooks: onBootstrapStarted (fire-and-forget) ──
594
993
  try {
595
994
  const skillHooks = ctx.container.get('skillHooks');
596
- skillHooks.run('onBootstrapComplete', {
597
- filesScanned: allFiles.length,
598
- targetsFound: allTargets.length,
599
- candidatesCreated: 0, // 异步填充中,初始为 0
600
- candidatesFailed: 0,
601
- autoSkillsCreated: 0,
602
- autoSkills: [],
603
- }, { projectRoot: ctx.container.get('database')?.filename || '' })
995
+ skillHooks
996
+ .run(
997
+ 'onBootstrapComplete',
998
+ {
999
+ filesScanned: allFiles.length,
1000
+ targetsFound: allTargets.length,
1001
+ candidatesCreated: 0, // 异步填充中,初始为 0
1002
+ candidatesFailed: 0,
1003
+ autoSkillsCreated: 0,
1004
+ autoSkills: [],
1005
+ },
1006
+ { projectRoot: ctx.container.get('database')?.filename || '' }
1007
+ )
604
1008
  .catch(() => {}); // fire-and-forget
605
- } catch { /* skillHooks not available */ }
1009
+ } catch {
1010
+ /* skillHooks not available */
1011
+ }
606
1012
 
607
1013
  return envelope({
608
1014
  success: true,
@@ -629,7 +1035,11 @@ export async function bootstrapRefine(ctx, args) {
629
1035
  const aiProvider = ctx.container.get('aiProvider');
630
1036
 
631
1037
  if (!aiProvider) {
632
- return envelope({ success: false, message: 'AI provider not configured', errorCode: 'MISSING_AI_PROVIDER' });
1038
+ return envelope({
1039
+ success: false,
1040
+ message: 'AI provider not configured',
1041
+ errorCode: 'MISSING_AI_PROVIDER',
1042
+ });
633
1043
  }
634
1044
 
635
1045
  // 接入 BootstrapTaskManager 双通道推送 refine:* 事件
@@ -637,7 +1047,9 @@ export async function bootstrapRefine(ctx, args) {
637
1047
  try {
638
1048
  const taskManager = ctx.container.get('bootstrapTaskManager');
639
1049
  onProgress = (eventName, data) => taskManager.emitProgress(eventName, data);
640
- } catch { /* optional */ }
1050
+ } catch {
1051
+ /* optional */
1052
+ }
641
1053
 
642
1054
  // 1. 收集待润色条目
643
1055
  let entries;
@@ -645,21 +1057,39 @@ export async function bootstrapRefine(ctx, args) {
645
1057
  entries = [];
646
1058
  for (const id of args.candidateIds) {
647
1059
  const e = await knowledgeService.get(id);
648
- if (e) entries.push(typeof e.toJSON === 'function' ? e.toJSON() : e);
1060
+ if (e) {
1061
+ entries.push(typeof e.toJSON === 'function' ? e.toJSON() : e);
1062
+ }
649
1063
  }
650
1064
  } else {
651
- const result = await knowledgeService.list({ lifecycle: 'pending', source: 'bootstrap' }, { page: 1, pageSize: 200 });
652
- entries = (result.items || []).map(e => typeof e.toJSON === 'function' ? e.toJSON() : e);
1065
+ const result = await knowledgeService.list(
1066
+ { lifecycle: 'pending', source: 'bootstrap' },
1067
+ { page: 1, pageSize: 200 }
1068
+ );
1069
+ entries = (result.items || []).map((e) => (typeof e.toJSON === 'function' ? e.toJSON() : e));
653
1070
  }
654
1071
 
655
1072
  if (entries.length === 0) {
656
- return envelope({ success: true, data: { refined: 0, total: 0, errors: [], results: [] }, meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 } });
1073
+ return envelope({
1074
+ success: true,
1075
+ data: { refined: 0, total: 0, errors: [], results: [] },
1076
+ meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
1077
+ });
657
1078
  }
658
1079
 
659
- onProgress?.('refine:started', { total: entries.length, candidateIds: entries.map(e => e.id) });
1080
+ onProgress?.('refine:started', { total: entries.length, candidateIds: entries.map((e) => e.id) });
660
1081
 
661
- // 2. 逐条 AI 润色
662
- const allTitles = entries.map(e => e.title).filter(Boolean);
1082
+ // 2. 收集已发布 Recipe 标题(关联关系只能指向已发布 Recipe,不能在候选之间互关联)
1083
+ let publishedTitles = [];
1084
+ try {
1085
+ const published = await knowledgeService.list(
1086
+ { lifecycle: 'active' },
1087
+ { page: 1, pageSize: 200 }
1088
+ );
1089
+ publishedTitles = (published.items || []).map((e) => e.title).filter(Boolean);
1090
+ } catch { /* ignore */ }
1091
+
1092
+ // 3. 逐条 AI 润色
663
1093
  const results = [];
664
1094
  const errors = [];
665
1095
  let refined = 0;
@@ -667,7 +1097,13 @@ export async function bootstrapRefine(ctx, args) {
667
1097
 
668
1098
  for (const entry of entries) {
669
1099
  processed++;
670
- onProgress?.('refine:item-started', { candidateId: entry.id, title: entry.title, current: processed, total: entries.length, progress: Math.round(((processed - 1) / entries.length) * 100) });
1100
+ onProgress?.('refine:item-started', {
1101
+ candidateId: entry.id,
1102
+ title: entry.title,
1103
+ current: processed,
1104
+ total: entries.length,
1105
+ progress: Math.round(((processed - 1) / entries.length) * 100),
1106
+ });
671
1107
 
672
1108
  try {
673
1109
  const before = {
@@ -685,7 +1121,7 @@ export async function bootstrapRefine(ctx, args) {
685
1121
 
686
1122
  const refineInstruction = args.userPrompt
687
1123
  ? args.userPrompt
688
- : '请改善描述使其更专业简洁,补充高阶架构洞察,如缺少关联关系请推断补充';
1124
+ : '请改善描述使其更专业简洁,补充高阶架构洞察';
689
1125
 
690
1126
  const prompt = `你是一位高级代码知识管理专家。请改进以下知识条目。
691
1127
 
@@ -736,7 +1172,7 @@ ${before.aiInsight || '(空)'}
736
1172
  【agentNotes】Agent 笔记
737
1173
  ${JSON.stringify(before.agentNotes || [])}
738
1174
 
739
- 同批次知识: ${allTitles.slice(0, 20).join(', ')}
1175
+ ${publishedTitles.length > 0 ? `已发布的 Recipe: ${publishedTitles.slice(0, 20).join(', ')}` : '(尚无已发布的 Recipe)'}
740
1176
 
741
1177
  ## 润色指令
742
1178
 
@@ -747,7 +1183,8 @@ ${refineInstruction}
747
1183
  1. 只修改需要改进的字段,未涉及的必须原样返回。
748
1184
  2. tags 采用合并策略(保留原有 + 补充新建议),不要删除已有标签。
749
1185
  3. relations 为 object 格式,key 为关系类型(如 inherits/implements/calls/depends_on/extends/related),value 为 string[]。
750
- 4. 每个 key 都必须存在,key 名称必须与上述完全一致。
1186
+ 4. relations 只能指向已发布的 Recipe,不能在候选之间建立关联。如果没有已发布的 Recipe,relations 应保持为空 {}。
1187
+ 5. 每个 key 都必须存在,key 名称必须与上述完全一致。
751
1188
 
752
1189
  仅返回 JSON,不要添加任何其他文字或代码块标记。`;
753
1190
 
@@ -755,39 +1192,77 @@ ${refineInstruction}
755
1192
 
756
1193
  if (!parsed) {
757
1194
  errors.push({ id: entry.id, title: entry.title, error: 'AI returned no valid JSON' });
758
- onProgress?.('refine:item-failed', { candidateId: entry.id, title: entry.title, error: 'No valid JSON', current: processed, total: entries.length, progress: Math.round((processed / entries.length) * 100) });
1195
+ onProgress?.('refine:item-failed', {
1196
+ candidateId: entry.id,
1197
+ title: entry.title,
1198
+ error: 'No valid JSON',
1199
+ current: processed,
1200
+ total: entries.length,
1201
+ progress: Math.round((processed / entries.length) * 100),
1202
+ });
759
1203
  continue;
760
1204
  }
761
1205
 
762
1206
  if (args.dryRun) {
763
1207
  results.push({ id: entry.id, title: entry.title, preview: parsed });
764
- onProgress?.('refine:item-completed', { candidateId: entry.id, title: entry.title, refined: false, current: processed, total: entries.length, progress: Math.round((processed / entries.length) * 100) });
1208
+ onProgress?.('refine:item-completed', {
1209
+ candidateId: entry.id,
1210
+ title: entry.title,
1211
+ refined: false,
1212
+ current: processed,
1213
+ total: entries.length,
1214
+ progress: Math.round((processed / entries.length) * 100),
1215
+ });
765
1216
  continue;
766
1217
  }
767
1218
 
768
1219
  // ─── key 别名归一化(与 candidates.js 保持一致) ───
769
1220
  const KEY_ALIASES = {
770
- summary: 'description', desc: 'description',
771
- content: 'pattern', design: 'rationale', designRationale: 'rationale',
772
- markdownDoc: 'markdown', doc: 'markdown',
773
- tag: 'tags', label: 'tags', labels: 'tags',
1221
+ summary: 'description',
1222
+ desc: 'description',
1223
+ content: 'pattern',
1224
+ design: 'rationale',
1225
+ designRationale: 'rationale',
1226
+ markdownDoc: 'markdown',
1227
+ doc: 'markdown',
1228
+ tag: 'tags',
1229
+ label: 'tags',
1230
+ labels: 'tags',
774
1231
  score: 'confidence',
775
- ai_insight: 'aiInsight', insight: 'aiInsight', aiinsight: 'aiInsight',
776
- agent_notes: 'agentNotes', notes: 'agentNotes', agentnotes: 'agentNotes',
1232
+ ai_insight: 'aiInsight',
1233
+ insight: 'aiInsight',
1234
+ aiinsight: 'aiInsight',
1235
+ agent_notes: 'agentNotes',
1236
+ notes: 'agentNotes',
1237
+ agentnotes: 'agentNotes',
777
1238
  relation: 'relations',
778
1239
  };
779
- const VALID_KEYS = new Set(['description', 'pattern', 'markdown', 'rationale', 'tags', 'confidence', 'aiInsight', 'agentNotes', 'relations']);
1240
+ const VALID_KEYS = new Set([
1241
+ 'description',
1242
+ 'pattern',
1243
+ 'markdown',
1244
+ 'rationale',
1245
+ 'tags',
1246
+ 'confidence',
1247
+ 'aiInsight',
1248
+ 'agentNotes',
1249
+ 'relations',
1250
+ ]);
780
1251
  const normalized = {};
781
1252
  for (const [key, value] of Object.entries(parsed)) {
782
1253
  if (VALID_KEYS.has(key)) {
783
1254
  normalized[key] = value;
784
1255
  } else {
785
1256
  const mapped = KEY_ALIASES[key] || KEY_ALIASES[key.toLowerCase?.()];
786
- if (mapped && !(mapped in normalized)) normalized[mapped] = value;
1257
+ if (mapped && !(mapped in normalized)) {
1258
+ normalized[mapped] = value;
1259
+ }
787
1260
  }
788
1261
  }
789
1262
  for (const k of VALID_KEYS) {
790
- if (!(k in normalized)) normalized[k] = before[k];
1263
+ if (!(k in normalized)) {
1264
+ normalized[k] = before[k];
1265
+ }
791
1266
  }
792
1267
 
793
1268
  // 构建更新数据
@@ -806,7 +1281,10 @@ ${refineInstruction}
806
1281
  changed = true;
807
1282
  }
808
1283
  }
809
- if (typeof normalized.confidence === 'number' && normalized.confidence !== before.confidence) {
1284
+ if (
1285
+ typeof normalized.confidence === 'number' &&
1286
+ normalized.confidence !== before.confidence
1287
+ ) {
810
1288
  updateData.reasoning = { ...(entry.reasoning || {}), confidence: normalized.confidence };
811
1289
  changed = true;
812
1290
  }
@@ -853,11 +1331,31 @@ ${refineInstruction}
853
1331
  refined++;
854
1332
  }
855
1333
 
856
- results.push({ id: entry.id, title: entry.title, refined: changed, fields: Object.keys(parsed) });
857
- onProgress?.('refine:item-completed', { candidateId: entry.id, title: entry.title, refined: changed, current: processed, total: entries.length, progress: Math.round((processed / entries.length) * 100), refinedSoFar: refined });
1334
+ results.push({
1335
+ id: entry.id,
1336
+ title: entry.title,
1337
+ refined: changed,
1338
+ fields: Object.keys(parsed),
1339
+ });
1340
+ onProgress?.('refine:item-completed', {
1341
+ candidateId: entry.id,
1342
+ title: entry.title,
1343
+ refined: changed,
1344
+ current: processed,
1345
+ total: entries.length,
1346
+ progress: Math.round((processed / entries.length) * 100),
1347
+ refinedSoFar: refined,
1348
+ });
858
1349
  } catch (err) {
859
1350
  errors.push({ id: entry.id, title: entry.title, error: err.message });
860
- onProgress?.('refine:item-failed', { candidateId: entry.id, title: entry.title, error: err.message, current: processed, total: entries.length, progress: Math.round((processed / entries.length) * 100) });
1351
+ onProgress?.('refine:item-failed', {
1352
+ candidateId: entry.id,
1353
+ title: entry.title,
1354
+ error: err.message,
1355
+ current: processed,
1356
+ total: entries.length,
1357
+ progress: Math.round((processed / entries.length) * 100),
1358
+ });
861
1359
  }
862
1360
  }
863
1361
 
@@ -875,3 +1373,28 @@ ${refineInstruction}
875
1373
  meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
876
1374
  });
877
1375
  }
1376
+
1377
+ // ══════════════════════════════════════════════════════════════════
1378
+ // 内部辅助 — 维度条件化
1379
+ // ══════════════════════════════════════════════════════════════════
1380
+
1381
+ /**
1382
+ * 根据项目主语言和检测到的框架过滤条件维度
1383
+ * @param {Array} allDimensions 所有维度定义(含 conditions 字段)
1384
+ * @param {string} primaryLang 主语言
1385
+ * @param {string[]} detectedFrameworks 检测到的框架
1386
+ * @returns {Array} 适用的维度列表
1387
+ */
1388
+ function _resolveActiveDimensions(allDimensions, primaryLang, detectedFrameworks = []) {
1389
+ return allDimensions.filter((dim) => {
1390
+ if (!dim.conditions) {
1391
+ return true; // 无条件 → 通用维度
1392
+ }
1393
+ const langMatch = !dim.conditions.languages || dim.conditions.languages.includes(primaryLang);
1394
+ const fwMatch =
1395
+ !dim.conditions.frameworks ||
1396
+ dim.conditions.frameworks.some((f) => detectedFrameworks.includes(f));
1397
+ // languages 必须匹配;frameworks 为可选增强(有 frameworks 条件时必须至少命中一个)
1398
+ return langMatch && (dim.conditions.frameworks ? fwMatch : true);
1399
+ });
1400
+ }