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
@@ -11,19 +11,19 @@
11
11
  * @module pipeline/orchestrator
12
12
  */
13
13
 
14
- import path from 'node:path';
15
14
  import fs from 'node:fs/promises';
15
+ import path from 'node:path';
16
+ import Logger from '../../../../../infrastructure/logging/Logger.js';
16
17
  import { AnalystAgent } from '../../../../../service/chat/AnalystAgent.js';
18
+ import { EpisodicConsolidator } from '../../../../../service/chat/EpisodicConsolidator.js';
17
19
  import { ProducerAgent } from '../../../../../service/chat/ProducerAgent.js';
18
- import { TierScheduler } from './tier-scheduler.js';
20
+ import { ProjectSemanticMemory } from '../../../../../service/chat/ProjectSemanticMemory.js';
21
+ import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
19
22
  import { DimensionContext, parseDimensionDigest } from './dimension-context.js';
20
23
  import { EpisodicMemory } from './EpisodicMemory.js';
21
- import { ToolResultCache } from './ToolResultCache.js';
22
- import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
23
- import { ProjectSemanticMemory } from '../../../../../service/chat/ProjectSemanticMemory.js';
24
- import { EpisodicConsolidator } from '../../../../../service/chat/EpisodicConsolidator.js';
25
24
  import { IncrementalBootstrap } from './IncrementalBootstrap.js';
26
- import Logger from '../../../../../infrastructure/logging/Logger.js';
25
+ import { ToolResultCache } from './ToolResultCache.js';
26
+ import { TierScheduler } from './tier-scheduler.js';
27
27
 
28
28
  const logger = Logger.getInstance();
29
29
 
@@ -47,7 +47,7 @@ async function saveDimensionCheckpoint(projectRoot, sessionId, dimId, result, di
47
47
  await fs.mkdir(checkpointDir, { recursive: true });
48
48
  await fs.writeFile(
49
49
  path.join(checkpointDir, `${dimId}.json`),
50
- JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() }),
50
+ JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() })
51
51
  );
52
52
  } catch (err) {
53
53
  logger.warn(`[Bootstrap-v3] checkpoint save failed for "${dimId}": ${err.message}`);
@@ -66,16 +66,22 @@ async function loadCheckpoints(projectRoot) {
66
66
  const files = await fs.readdir(checkpointDir).catch(() => []);
67
67
  const now = Date.now();
68
68
  for (const file of files) {
69
- if (!file.endsWith('.json')) continue;
69
+ if (!file.endsWith('.json')) {
70
+ continue;
71
+ }
70
72
  try {
71
73
  const content = await fs.readFile(path.join(checkpointDir, file), 'utf-8');
72
74
  const data = JSON.parse(content);
73
- if (data.completedAt && (now - data.completedAt) < CHECKPOINT_TTL_MS) {
75
+ if (data.completedAt && now - data.completedAt < CHECKPOINT_TTL_MS) {
74
76
  checkpoints.set(data.dimId, data);
75
77
  }
76
- } catch { /* skip corrupt checkpoint */ }
78
+ } catch {
79
+ /* skip corrupt checkpoint */
80
+ }
77
81
  }
78
- } catch { /* checkpoint dir doesn't exist */ }
82
+ } catch {
83
+ /* checkpoint dir doesn't exist */
84
+ }
79
85
  return checkpoints;
80
86
  }
81
87
 
@@ -87,7 +93,9 @@ async function clearCheckpoints(projectRoot) {
87
93
  try {
88
94
  const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
89
95
  await fs.rm(checkpointDir, { recursive: true, force: true });
90
- } catch { /* ignore */ }
96
+ } catch {
97
+ /* ignore */
98
+ }
91
99
  }
92
100
 
93
101
  // ──────────────────────────────────────────────────────────────────
@@ -98,11 +106,7 @@ const DIMENSION_CONFIGS_V3 = {
98
106
  'project-profile': {
99
107
  label: '项目概貌',
100
108
  guide: '分析项目的整体结构、技术栈、模块划分和入口点。',
101
- focusAreas: [
102
- '项目结构和模块划分',
103
- '技术栈和框架依赖',
104
- '核心入口点和启动流程',
105
- ],
109
+ focusAreas: ['项目结构和模块划分', '技术栈和框架依赖', '核心入口点和启动流程'],
106
110
  outputType: 'dual',
107
111
  allowedKnowledgeTypes: ['architecture'],
108
112
  },
@@ -140,7 +144,7 @@ const DIMENSION_CONFIGS_V3 = {
140
144
  outputType: 'dual',
141
145
  allowedKnowledgeTypes: ['code-standard', 'code-style'],
142
146
  },
143
- 'architecture': {
147
+ architecture: {
144
148
  label: '架构模式',
145
149
  guide: '分析项目的分层架构、模块职责和依赖关系。',
146
150
  focusAreas: [
@@ -200,6 +204,57 @@ const DIMENSION_CONFIGS_V3 = {
200
204
  outputType: 'skill',
201
205
  allowedKnowledgeTypes: ['boundary-constraint', 'code-standard'],
202
206
  },
207
+
208
+ // ── 语言条件维度(v3.1: 多语言支持)──────────────────────
209
+
210
+ 'module-export-scan': {
211
+ label: '模块导出分析',
212
+ guide: '分析 TS/JS 模块的导出结构和 public API surface。',
213
+ focusAreas: [
214
+ 'barrel export 结构和 re-export 链路',
215
+ 'public API surface 合规性',
216
+ 'tree-shaking 兼容性',
217
+ '循环依赖检测',
218
+ ],
219
+ outputType: 'dual',
220
+ allowedKnowledgeTypes: ['code-standard', 'architecture'],
221
+ },
222
+ 'framework-convention-scan': {
223
+ label: '框架约定扫描',
224
+ guide: '分析前端框架约定(组件结构、状态管理、路由)。',
225
+ focusAreas: [
226
+ '组件目录结构和命名约定',
227
+ '状态管理模式 (Redux/Vuex/Pinia/Zustand)',
228
+ '路由约定和数据获取模式',
229
+ '样式约定 (CSS Module/Tailwind/CSS-in-JS)',
230
+ ],
231
+ outputType: 'dual',
232
+ allowedKnowledgeTypes: ['code-standard', 'architecture'],
233
+ },
234
+ 'python-package-scan': {
235
+ label: 'Python 包结构分析',
236
+ guide: '分析 Python 包的导入风格、类型标注和 __init__.py 策略。',
237
+ focusAreas: [
238
+ '__init__.py 导出策略和 __all__ 定义',
239
+ '相对/绝对导入风格',
240
+ 'type hints 覆盖率和 Protocol 使用',
241
+ 'decorator 使用模式',
242
+ ],
243
+ outputType: 'dual',
244
+ allowedKnowledgeTypes: ['code-standard', 'architecture'],
245
+ },
246
+ 'jvm-annotation-scan': {
247
+ label: '注解/Annotation 扫描',
248
+ guide: '扫描 Java/Kotlin 项目中的 DI、ORM、API 注解使用模式。',
249
+ focusAreas: [
250
+ 'DI 注解 (@Inject/@Autowired/@Component)',
251
+ 'ORM 注解 (@Entity/@Table/@Column)',
252
+ 'API 注解 (@RestController/@RequestMapping)',
253
+ '自定义注解和元编程模式',
254
+ ],
255
+ outputType: 'dual',
256
+ allowedKnowledgeTypes: ['code-pattern', 'architecture'],
257
+ },
203
258
  };
204
259
 
205
260
  // ──────────────────────────────────────────────────────────────────
@@ -251,7 +306,7 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
251
306
  }
252
307
  }
253
308
  // 统计关键词
254
- const words = (f.finding || '').split(/[\s,,。.]+/).filter(w => w.length > 3);
309
+ const words = (f.finding || '').split(/[\s,,。.]+/).filter((w) => w.length > 3);
255
310
  for (const w of words) {
256
311
  keywordMentions[w] = (keywordMentions[w] || 0) + 1;
257
312
  }
@@ -262,18 +317,14 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
262
317
  // 多维度引用的文件 = 跨维度热点
263
318
  for (const [file, count] of Object.entries(fileMentions)) {
264
319
  if (count >= 2) {
265
- crossDimensionPatterns.push(
266
- `文件 "${file}" 被 ${count} 个维度引用 — 可能是系统核心组件`
267
- );
320
+ crossDimensionPatterns.push(`文件 "${file}" 被 ${count} 个维度引用 — 可能是系统核心组件`);
268
321
  }
269
322
  }
270
323
 
271
324
  // 多维度提及的关键词
272
325
  for (const [word, count] of Object.entries(keywordMentions)) {
273
326
  if (count >= 3) {
274
- crossDimensionPatterns.push(
275
- `关键词 "${word}" 出现 ${count} 次 — 跨维度关联主题`
276
- );
327
+ crossDimensionPatterns.push(`关键词 "${word}" 出现 ${count} 次 — 跨维度关联主题`);
277
328
  }
278
329
  }
279
330
 
@@ -324,14 +375,22 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
324
375
  */
325
376
  export async function fillDimensionsV3(fillContext) {
326
377
  const {
327
- ctx, dimensions, taskManager, sessionId, projectRoot,
328
- depGraphData, guardAudit, langStats, primaryLang, astProjectSummary,
329
- skillContext, skillsEnhanced,
330
- incrementalPlan, // v5.0: 增量 Bootstrap 计划 (from bootstrap.js)
378
+ ctx,
379
+ dimensions,
380
+ taskManager,
381
+ sessionId,
382
+ projectRoot,
383
+ depGraphData,
384
+ guardAudit,
385
+ primaryLang,
386
+ astProjectSummary,
387
+ incrementalPlan, // v5.0: 增量 Bootstrap 计划 (from bootstrap.js)
331
388
  } = fillContext;
332
389
 
333
390
  const isIncremental = incrementalPlan?.canIncremental && incrementalPlan?.mode === 'incremental';
334
- logger.info(`[Bootstrap-v3] ═══ fillDimensionsV3 entered — ${isIncremental ? 'INCREMENTAL' : 'FULL'} pipeline`);
391
+ logger.info(
392
+ `[Bootstrap-v3] ═══ fillDimensionsV3 entered — ${isIncremental ? 'INCREMENTAL' : 'FULL'} pipeline`
393
+ );
335
394
 
336
395
  let allFiles = fillContext.allFiles;
337
396
  fillContext.allFiles = null;
@@ -342,9 +401,15 @@ export async function fillDimensionsV3(fillContext) {
342
401
  let chatAgent = null;
343
402
  try {
344
403
  chatAgent = ctx.container.get('chatAgent');
345
- if (chatAgent && !chatAgent.hasRealAI) chatAgent = null;
346
- if (chatAgent) chatAgent.resetGlobalSubmittedTitles();
347
- } catch { /* not available */ }
404
+ if (chatAgent && !chatAgent.hasRealAI) {
405
+ chatAgent = null;
406
+ }
407
+ if (chatAgent) {
408
+ chatAgent.resetGlobalSubmittedTitles();
409
+ }
410
+ } catch {
411
+ /* not available */
412
+ }
348
413
 
349
414
  if (!chatAgent) {
350
415
  logger.info('[Bootstrap-v3] AI not available — aborting v3 pipeline');
@@ -368,7 +433,9 @@ export async function fillDimensionsV3(fillContext) {
368
433
  });
369
434
  if (projectGraph) {
370
435
  const overview = projectGraph.getOverview();
371
- logger.info(`[Bootstrap-v3] ProjectGraph: ${overview.totalClasses} classes, ${overview.totalProtocols} protocols (${overview.buildTimeMs}ms)`);
436
+ logger.info(
437
+ `[Bootstrap-v3] ProjectGraph: ${overview.totalClasses} classes, ${overview.totalProtocols} protocols (${overview.buildTimeMs}ms)`
438
+ );
372
439
  }
373
440
  } catch (e) {
374
441
  logger.warn(`[Bootstrap-v3] ProjectGraph build failed: ${e.message}`);
@@ -386,7 +453,7 @@ export async function fillDimensionsV3(fillContext) {
386
453
  // 项目信息
387
454
  const projectInfo = {
388
455
  name: path.basename(projectRoot),
389
- lang: primaryLang || 'objectivec',
456
+ lang: primaryLang || 'unknown',
390
457
  fileCount: allFiles?.length || 0,
391
458
  };
392
459
 
@@ -408,7 +475,9 @@ export async function fillDimensionsV3(fillContext) {
408
475
  if (isIncremental && incrementalPlan.restoredEpisodic) {
409
476
  episodicMemory = incrementalPlan.restoredEpisodic;
410
477
  const restoredDims = episodicMemory.getCompletedDimensions();
411
- logger.info(`[Bootstrap-v3] Restored EpisodicMemory: ${restoredDims.length} dims [${restoredDims.join(', ')}]`);
478
+ logger.info(
479
+ `[Bootstrap-v3] Restored EpisodicMemory: ${restoredDims.length} dims [${restoredDims.join(', ')}]`
480
+ );
412
481
 
413
482
  // 同步恢复 DimensionContext 的 digests (兼容)
414
483
  for (const dimId of restoredDims) {
@@ -440,7 +509,7 @@ export async function fillDimensionsV3(fillContext) {
440
509
  if (smStats.total > 0) {
441
510
  logger.info(
442
511
  `[Bootstrap-v3] Loaded ${smStats.total} semantic memories from previous bootstrap ` +
443
- `(fact: ${smStats.byType.fact || 0}, insight: ${smStats.byType.insight || 0}, preference: ${smStats.byType.preference || 0})`
512
+ `(fact: ${smStats.byType.fact || 0}, insight: ${smStats.byType.insight || 0}, preference: ${smStats.byType.preference || 0})`
444
513
  );
445
514
  }
446
515
  }
@@ -473,10 +542,8 @@ export async function fillDimensionsV3(fillContext) {
473
542
  const enableParallel = process.env.ASD_PARALLEL_BOOTSTRAP !== 'false';
474
543
  const scheduler = new TierScheduler();
475
544
 
476
- // 过滤出有定义的维度
477
- let activeDimIds = dimensions
478
- .map(d => d.id)
479
- .filter(id => DIMENSION_CONFIGS_V3[id]);
545
+ // 包含所有维度(含 Enhancement Pack 动态追加的维度)
546
+ const activeDimIds = dimensions.map((d) => d.id);
480
547
 
481
548
  // v5.0: 增量模式 — 仅执行受影响维度, 跳过未变更维度
482
549
  const incrementalSkippedDims = [];
@@ -495,12 +562,14 @@ export async function fillDimensionsV3(fillContext) {
495
562
  if (incrementalSkippedDims.length > 0) {
496
563
  logger.info(
497
564
  `[Bootstrap-v3] ⏩ Incremental skip: [${incrementalSkippedDims.join(', ')}] ` +
498
- `(using historical results)`
565
+ `(using historical results)`
499
566
  );
500
567
  }
501
568
  }
502
569
 
503
- logger.info(`[Bootstrap-v3] Active dimensions: [${activeDimIds.join(', ')}], concurrency=${enableParallel ? concurrency : 1}${isIncremental ? `, incremental skip: [${incrementalSkippedDims.join(', ')}]` : ''}`);
570
+ logger.info(
571
+ `[Bootstrap-v3] Active dimensions: [${activeDimIds.join(', ')}], concurrency=${enableParallel ? concurrency : 1}${isIncremental ? `, incremental skip: [${incrementalSkippedDims.join(', ')}]` : ''}`
572
+ );
504
573
 
505
574
  // ── P3: 断点续传 — 加载有效 checkpoints ──
506
575
  const completedCheckpoints = await loadCheckpoints(projectRoot);
@@ -585,27 +654,43 @@ export async function fillDimensionsV3(fillContext) {
585
654
  referencedFiles: restoredFiles,
586
655
  candidatesSummary: [],
587
656
  });
588
- logger.info(`[Bootstrap-v3] ✅ Checkpoint "${dimId}": analysisText restored (${cp.analysisText.length} chars) — Skill generation enabled`);
657
+ logger.info(
658
+ `[Bootstrap-v3] ✅ Checkpoint "${dimId}": analysisText restored (${cp.analysisText.length} chars) — Skill generation enabled`
659
+ );
589
660
  }
590
661
 
591
662
  return cpResult;
592
663
  }
593
664
 
594
- const dim = dimensions.find(d => d.id === dimId);
595
- const v3Config = DIMENSION_CONFIGS_V3[dimId];
596
- if (!dim || !v3Config) {
665
+ const dim = dimensions.find((d) => d.id === dimId);
666
+ if (!dim) {
597
667
  return { candidateCount: 0, error: 'dimension not found' };
598
668
  }
599
669
 
600
- // 合并 v3 配置和原始维度配置 (保留 skillWorthy, skillMeta 等)
601
- const dimConfig = {
602
- ...v3Config,
603
- id: dimId,
604
- skillWorthy: dim.skillWorthy,
605
- dualOutput: dim.dualOutput,
606
- skillMeta: dim.skillMeta,
607
- knowledgeTypes: dim.knowledgeTypes || v3Config.allowedKnowledgeTypes,
608
- };
670
+ // 合并 v3 配置和原始维度配置
671
+ // Enhancement Pack 动态维度可能不在 DIMENSION_CONFIGS_V3 中 — 从 dim 本身构建配置
672
+ const v3Config = DIMENSION_CONFIGS_V3[dimId];
673
+ const dimConfig = v3Config
674
+ ? {
675
+ ...v3Config,
676
+ id: dimId,
677
+ skillWorthy: dim.skillWorthy,
678
+ dualOutput: dim.dualOutput,
679
+ skillMeta: dim.skillMeta,
680
+ knowledgeTypes: dim.knowledgeTypes || v3Config.allowedKnowledgeTypes,
681
+ }
682
+ : {
683
+ id: dimId,
684
+ label: dim.label,
685
+ guide: dim.guide || '',
686
+ focusAreas: dim.focusAreas || [dim.guide || ''].filter(Boolean),
687
+ outputType: dim.dualOutput ? 'dual' : dim.skillWorthy ? 'skill' : 'candidate',
688
+ allowedKnowledgeTypes: dim.knowledgeTypes || [],
689
+ skillWorthy: dim.skillWorthy,
690
+ dualOutput: dim.dualOutput,
691
+ skillMeta: dim.skillMeta,
692
+ knowledgeTypes: dim.knowledgeTypes || [],
693
+ };
609
694
 
610
695
  // Session 有效性检查
611
696
  if (taskManager && !taskManager.isSessionValid(sessionId)) {
@@ -637,7 +722,8 @@ export async function fillDimensionsV3(fillContext) {
637
722
  codeEntityGraph: codeEntityGraphInst,
638
723
  }),
639
724
  new Promise((_, reject) =>
640
- setTimeout(() => reject(new Error(`Analyst timeout for "${dimId}"`)), 180_000)),
725
+ setTimeout(() => reject(new Error(`Analyst timeout for "${dimId}"`)), 300_000)
726
+ ),
641
727
  ]);
642
728
 
643
729
  // v4.0: 蒸馏 Working → Episodic
@@ -652,9 +738,9 @@ export async function fillDimensionsV3(fillContext) {
652
738
 
653
739
  logger.info(
654
740
  `[Bootstrap-v3] Analyst "${dimId}": ${analysisReport.analysisText.length} chars, ` +
655
- `${analysisReport.referencedFiles.length} files, ` +
656
- `${distilled.keyFindings.length} key findings, ` +
657
- `${distilled.totalObservations} observations (${Date.now() - dimStartTime}ms)`
741
+ `${analysisReport.referencedFiles.length} files, ` +
742
+ `${distilled.keyFindings.length} key findings, ` +
743
+ `${distilled.totalObservations} observations (${Date.now() - dimStartTime}ms)`
658
744
  );
659
745
 
660
746
  // ── Phase 2: Producer (如果需要候选输出) ──
@@ -662,18 +748,34 @@ export async function fillDimensionsV3(fillContext) {
662
748
  // v3 优先使用 DIMENSION_CONFIGS_V3 的 outputType,回退到 baseDimension 的 skillWorthy/dualOutput
663
749
  const v3OutputType = DIMENSION_CONFIGS_V3[dimId]?.outputType;
664
750
  const needsCandidates = v3OutputType
665
- ? v3OutputType !== 'skill' // 'dual' 或 'candidate' 都产出候选
666
- : (!dimConfig.skillWorthy || dimConfig.dualOutput);
751
+ ? v3OutputType !== 'skill' // 'dual' 或 'candidate' 都产出候选
752
+ : !dimConfig.skillWorthy || dimConfig.dualOutput;
753
+
754
+ // 先保存 Analyst 结果,确保即使 Producer 失败也能生成 Skill
755
+ dimensionCandidates[dimId] = {
756
+ analysisReport,
757
+ producerResult,
758
+ };
667
759
 
668
760
  if (needsCandidates && analysisReport.analysisText.length >= 100) {
669
- producerResult = await Promise.race([
670
- producerAgent.produce(analysisReport, dimConfig, projectInfo, { sessionId }),
671
- new Promise((_, reject) =>
672
- setTimeout(() => reject(new Error(`Producer timeout for "${dimId}"`)), 120_000)),
673
- ]);
674
-
675
- candidateResults.created += producerResult.candidateCount;
676
- logger.info(`[Bootstrap-v3] Producer "${dimId}": ${producerResult.candidateCount} candidates (${Date.now() - dimStartTime}ms total)`);
761
+ try {
762
+ producerResult = await Promise.race([
763
+ producerAgent.produce(analysisReport, dimConfig, projectInfo, { sessionId }),
764
+ new Promise((_, reject) =>
765
+ setTimeout(() => reject(new Error(`Producer timeout for "${dimId}"`)), 180_000)
766
+ ),
767
+ ]);
768
+
769
+ candidateResults.created += producerResult.candidateCount;
770
+ // 更新 dimensionCandidates 以包含 Producer 结果
771
+ dimensionCandidates[dimId].producerResult = producerResult;
772
+ logger.info(
773
+ `[Bootstrap-v3] Producer "${dimId}": ${producerResult.candidateCount} candidates (${Date.now() - dimStartTime}ms total)`
774
+ );
775
+ } catch (producerErr) {
776
+ logger.error(`[Bootstrap-v3] Producer "${dimId}" failed: ${producerErr.message} — Analyst result preserved for Skill generation`);
777
+ candidateResults.errors.push({ dimId, error: `Producer: ${producerErr.message}` });
778
+ }
677
779
  }
678
780
 
679
781
  // ── Phase 3: 记录 DimensionDigest ──
@@ -690,7 +792,7 @@ export async function fillDimensionsV3(fillContext) {
690
792
  episodicMemory.addDimensionDigest(dimId, digest);
691
793
 
692
794
  // 记录到 DimensionContext + EpisodicMemory
693
- for (const tc of (producerResult.toolCalls || [])) {
795
+ for (const tc of producerResult.toolCalls || []) {
694
796
  const tool = tc.tool || tc.name;
695
797
  if (tool === 'submit_knowledge' || tool === 'submit_with_check') {
696
798
  const candidateSummary = {
@@ -704,19 +806,14 @@ export async function fillDimensionsV3(fillContext) {
704
806
  }
705
807
  }
706
808
 
707
- // 保存分析结果供 Skill 生成
708
- dimensionCandidates[dimId] = {
709
- analysisReport,
710
- producerResult,
711
- };
712
-
713
809
  taskManager?.markTaskCompleted(dimId, {
714
810
  type: needsCandidates ? 'candidate' : 'skill',
715
811
  extracted: producerResult.candidateCount,
716
812
  created: producerResult.candidateCount,
717
813
  status: 'v3-complete',
718
814
  durationMs: Date.now() - dimStartTime,
719
- toolCallCount: (analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
815
+ toolCallCount:
816
+ (analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
720
817
  });
721
818
 
722
819
  // P4.1: 聚合 token 用量
@@ -733,7 +830,8 @@ export async function fillDimensionsV3(fillContext) {
733
830
  analysisChars: analysisReport.analysisText.length,
734
831
  referencedFiles: analysisReport.referencedFiles.length,
735
832
  durationMs: Date.now() - dimStartTime,
736
- toolCallCount: (analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
833
+ toolCallCount:
834
+ (analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
737
835
  tokenUsage: dimTokenUsage,
738
836
  // P3+: 保存 analysisText 供 checkpoint 恢复后 Skill 生成使用
739
837
  analysisText: analysisReport.analysisText,
@@ -747,7 +845,6 @@ export async function fillDimensionsV3(fillContext) {
747
845
  await saveDimensionCheckpoint(projectRoot, sessionId, dimId, dimResult, digest);
748
846
 
749
847
  return dimResult;
750
-
751
848
  } catch (err) {
752
849
  logger.error(`[Bootstrap-v3] Dimension "${dimId}" failed: ${err.message}`);
753
850
  candidateResults.errors.push({ dimId, error: err.message });
@@ -764,11 +861,14 @@ export async function fillDimensionsV3(fillContext) {
764
861
  if (enableParallel) {
765
862
  const results = await scheduler.execute(executeDimension, {
766
863
  concurrency,
864
+ activeDimIds,
767
865
  shouldAbort: () => taskManager && !taskManager.isSessionValid(sessionId),
768
866
  onTierComplete: (tierIndex, tierResults) => {
769
867
  const tierStats = [...tierResults.values()];
770
868
  const totalCandidates = tierStats.reduce((s, r) => s + (r.candidateCount || 0), 0);
771
- logger.info(`[Bootstrap-v3] Tier ${tierIndex + 1} complete: ${tierResults.size} dimensions, ${totalCandidates} candidates`);
869
+ logger.info(
870
+ `[Bootstrap-v3] Tier ${tierIndex + 1} complete: ${tierResults.size} dimensions, ${totalCandidates} candidates`
871
+ );
772
872
 
773
873
  // v4.0: Tier 级 Reflection — 综合本 Tier 所有维度的发现
774
874
  try {
@@ -776,8 +876,8 @@ export async function fillDimensionsV3(fillContext) {
776
876
  episodicMemory.addTierReflection(tierIndex, reflection);
777
877
  logger.info(
778
878
  `[Bootstrap-v3] Tier ${tierIndex + 1} reflection: ` +
779
- `${reflection.topFindings.length} top findings, ` +
780
- `${reflection.crossDimensionPatterns.length} patterns`
879
+ `${reflection.topFindings.length} top findings, ` +
880
+ `${reflection.crossDimensionPatterns.length} patterns`
781
881
  );
782
882
  } catch (refErr) {
783
883
  logger.warn(`[Bootstrap-v3] Tier ${tierIndex + 1} reflection failed: ${refErr.message}`);
@@ -785,25 +885,31 @@ export async function fillDimensionsV3(fillContext) {
785
885
  },
786
886
  });
787
887
 
788
- logger.info(`[Bootstrap-v3] All tiers complete: ${results.size} dimensions in ${Date.now() - t0}ms`);
888
+ logger.info(
889
+ `[Bootstrap-v3] All tiers complete: ${results.size} dimensions in ${Date.now() - t0}ms`
890
+ );
789
891
  // v4.0: 记录 EpisodicMemory 统计 + ToolResultCache 效率
790
892
  const emStats = episodicMemory.getStats();
791
893
  const cacheStats = toolResultCache.getStats();
792
894
  logger.info(
793
895
  `[Bootstrap-v3] Memory stats: ${emStats.completedDimensions} dims, ` +
794
- `${emStats.totalFindings} findings, ${emStats.referencedFiles} files, ` +
795
- `${emStats.crossReferences} cross-refs, ${emStats.tierReflections} reflections`
896
+ `${emStats.totalFindings} findings, ${emStats.referencedFiles} files, ` +
897
+ `${emStats.crossReferences} cross-refs, ${emStats.tierReflections} reflections`
796
898
  );
797
899
  logger.info(
798
900
  `[Bootstrap-v3] Cache stats: ${cacheStats.hitRate} hit rate, ` +
799
- `${cacheStats.searchCacheSize} searches, ${cacheStats.fileCacheSize} files`
901
+ `${cacheStats.searchCacheSize} searches, ${cacheStats.fileCacheSize} files`
800
902
  );
801
903
  } else {
802
904
  // 串行: 按 TierScheduler 内部顺序逐个执行
803
905
  for (const tier of scheduler.getTiers()) {
804
906
  for (const dimId of tier) {
805
- if (!activeDimIds.includes(dimId)) continue;
806
- if (taskManager && !taskManager.isSessionValid(sessionId)) break;
907
+ if (!activeDimIds.includes(dimId)) {
908
+ continue;
909
+ }
910
+ if (taskManager && !taskManager.isSessionValid(sessionId)) {
911
+ break;
912
+ }
807
913
  await executeDimension(dimId);
808
914
  }
809
915
  }
@@ -822,19 +928,63 @@ export async function fillDimensionsV3(fillContext) {
822
928
  const { createSkill } = await import('../../skill.js');
823
929
 
824
930
  for (const dim of dimensions) {
825
- if (!dim.skillWorthy) continue;
931
+ if (!dim.skillWorthy) {
932
+ continue;
933
+ }
826
934
  const dimData = dimensionCandidates[dim.id];
827
- if (!dimData?.analysisReport?.analysisText) continue;
828
- if (taskManager && !taskManager.isSessionValid(sessionId)) break;
935
+ if (!dimData?.analysisReport?.analysisText) {
936
+ continue;
937
+ }
938
+ if (taskManager && !taskManager.isSessionValid(sessionId)) {
939
+ break;
940
+ }
829
941
 
830
942
  try {
831
943
  const skillName = dim.skillMeta?.name || `project-${dim.id}`;
832
- const skillDescription = dim.skillMeta?.description || `Auto-generated skill for ${dim.label}`;
944
+ const skillDescription =
945
+ dim.skillMeta?.description || `Auto-generated skill for ${dim.label}`;
833
946
 
834
947
  // v3: Analyst 分析文本就是高质量的 Skill 内容
835
948
  const analysisText = dimData.analysisReport.analysisText;
836
949
  const referencedFiles = dimData.analysisReport.referencedFiles || [];
837
950
 
951
+ // ── Skill 质量门控 ──
952
+ // 1. 文本过短(Analyst 产出空洞或仅 "请继续")
953
+ if (!analysisText || analysisText.trim().length < 100) {
954
+ logger.warn(
955
+ `[Bootstrap-v3] Skill "${dim.id}" skipped — analysisText too short (${analysisText?.trim().length || 0} chars)`
956
+ );
957
+ skillResults.failed++;
958
+ skillResults.errors.push({ dimId: dim.id, error: 'analysisText too short' });
959
+ continue;
960
+ }
961
+ // 2. 重复行检测(AI 陷入循环输出工具提示等)
962
+ const textLines = analysisText.split('\n').filter(l => l.trim().length > 0);
963
+ const uniqueLines = new Set(textLines.map(l => l.trim()));
964
+ const uniqueRatio = textLines.length > 0 ? uniqueLines.size / textLines.length : 1;
965
+ if (textLines.length > 20 && uniqueRatio < 0.3) {
966
+ logger.warn(
967
+ `[Bootstrap-v3] Skill "${dim.id}" skipped — heavy repetition (${uniqueLines.size}/${textLines.length} unique, ratio ${uniqueRatio.toFixed(2)})`
968
+ );
969
+ skillResults.failed++;
970
+ skillResults.errors.push({ dimId: dim.id, error: 'repetitive content detected' });
971
+ continue;
972
+ }
973
+ // 3. 内容中不包含项目特定标记(无 Markdown 标题、列表、代码块等结构化内容)
974
+ const hasStructure =
975
+ /^#{1,3}\s.+/m.test(analysisText) ||
976
+ /^\d+\.\s/m.test(analysisText) ||
977
+ /^[-*•]\s/m.test(analysisText) ||
978
+ /```[\s\S]*?```/.test(analysisText);
979
+ if (!hasStructure && analysisText.length < 500) {
980
+ logger.warn(
981
+ `[Bootstrap-v3] Skill "${dim.id}" skipped — no structured content detected`
982
+ );
983
+ skillResults.failed++;
984
+ skillResults.errors.push({ dimId: dim.id, error: 'no structured content' });
985
+ continue;
986
+ }
987
+
838
988
  // 构建 Markdown Skill 内容
839
989
  const skillContent = [
840
990
  `# ${dim.label || dim.id}`,
@@ -844,9 +994,11 @@ export async function fillDimensionsV3(fillContext) {
844
994
  analysisText,
845
995
  '',
846
996
  referencedFiles.length > 0
847
- ? `## Referenced Files\n\n${referencedFiles.map(f => `- \`${f}\``).join('\n')}`
997
+ ? `## Referenced Files\n\n${referencedFiles.map((f) => `- \`${f}\``).join('\n')}`
848
998
  : '',
849
- ].filter(Boolean).join('\n');
999
+ ]
1000
+ .filter(Boolean)
1001
+ .join('\n');
850
1002
 
851
1003
  const result = createSkill(ctx, {
852
1004
  name: skillName,
@@ -917,7 +1069,9 @@ export async function fillDimensionsV3(fillContext) {
917
1069
  }
918
1070
  }
919
1071
  } catch (cegErr) {
920
- logger.warn(`[Bootstrap-v3] Code Entity Graph relations failed (non-blocking): ${cegErr.message}`);
1072
+ logger.warn(
1073
+ `[Bootstrap-v3] Code Entity Graph relations failed (non-blocking): ${cegErr.message}`
1074
+ );
921
1075
  }
922
1076
 
923
1077
  // ═══════════════════════════════════════════════════════════
@@ -941,16 +1095,18 @@ export async function fillDimensionsV3(fillContext) {
941
1095
  const smStats = semanticMemory.getStats();
942
1096
  logger.info(
943
1097
  `[Bootstrap-v3] Semantic Memory consolidation: ` +
944
- `+${consolidationResult.total.added} ADD, ` +
945
- `~${consolidationResult.total.updated} UPDATE, ` +
946
- `⊕${consolidationResult.total.merged} MERGE | ` +
947
- `Total: ${smStats.total} memories (avg importance: ${smStats.avgImportance})`
1098
+ `+${consolidationResult.total.added} ADD, ` +
1099
+ `~${consolidationResult.total.updated} UPDATE, ` +
1100
+ `⊕${consolidationResult.total.merged} MERGE | ` +
1101
+ `Total: ${smStats.total} memories (avg importance: ${smStats.avgImportance})`
948
1102
  );
949
1103
  } else {
950
1104
  logger.warn('[Bootstrap-v3] Database not available — skipping Semantic Memory consolidation');
951
1105
  }
952
1106
  } catch (consolidateErr) {
953
- logger.warn(`[Bootstrap-v3] Semantic Memory consolidation failed (non-blocking): ${consolidateErr.message}`);
1107
+ logger.warn(
1108
+ `[Bootstrap-v3] Semantic Memory consolidation failed (non-blocking): ${consolidateErr.message}`
1109
+ );
954
1110
  }
955
1111
 
956
1112
  // ═══════════════════════════════════════════════════════════
@@ -960,7 +1116,10 @@ export async function fillDimensionsV3(fillContext) {
960
1116
 
961
1117
  // P4.1: 汇总所有维度 token 用量
962
1118
  const totalTokenUsage = { input: 0, output: 0 };
963
- const totalToolCalls = Object.values(dimensionStats).reduce((sum, s) => sum + (s.toolCallCount || 0), 0);
1119
+ const totalToolCalls = Object.values(dimensionStats).reduce(
1120
+ (sum, s) => sum + (s.toolCallCount || 0),
1121
+ 0
1122
+ );
964
1123
  for (const stat of Object.values(dimensionStats)) {
965
1124
  if (stat.tokenUsage) {
966
1125
  totalTokenUsage.input += stat.tokenUsage.input || 0;
@@ -968,19 +1127,29 @@ export async function fillDimensionsV3(fillContext) {
968
1127
  }
969
1128
  }
970
1129
 
971
- logger.info([
972
- `[Bootstrap-v3] ═══ Pipeline complete ═══`,
973
- isIncremental ? ` Mode: INCREMENTAL (${incrementalPlan.affectedDimensions.length} affected, ${incrementalSkippedDims.length} skipped)` : '',
974
- ` Candidates: ${candidateResults.created} created, ${candidateResults.errors.length} errors`,
975
- ` Skills: ${skillResults.created} created, ${skillResults.failed} failed`,
976
- consolidationResult ? ` Semantic Memory: +${consolidationResult.total.added} ADD, ~${consolidationResult.total.updated} UPDATE, ⊕${consolidationResult.total.merged} MERGE` : '',
977
- ` Time: ${totalTimeMs}ms (${(totalTimeMs / 1000).toFixed(1)}s)`,
978
- ` Mode: ${enableParallel ? `parallel (concurrency=${concurrency})` : 'serial'}`,
979
- ` Tokens: input=${totalTokenUsage.input}, output=${totalTokenUsage.output}`,
980
- ` Tool calls: ${totalToolCalls}`,
981
- skippedDims.length > 0 ? ` Checkpoints restored: [${skippedDims.join(', ')}]` : '',
982
- incrementalSkippedDims.length > 0 ? ` Incremental skip: [${incrementalSkippedDims.join(', ')}]` : '',
983
- ].filter(Boolean).join('\n'));
1130
+ logger.info(
1131
+ [
1132
+ `[Bootstrap-v3] ═══ Pipeline complete ═══`,
1133
+ isIncremental
1134
+ ? ` Mode: INCREMENTAL (${incrementalPlan.affectedDimensions.length} affected, ${incrementalSkippedDims.length} skipped)`
1135
+ : '',
1136
+ ` Candidates: ${candidateResults.created} created, ${candidateResults.errors.length} errors`,
1137
+ ` Skills: ${skillResults.created} created, ${skillResults.failed} failed`,
1138
+ consolidationResult
1139
+ ? ` Semantic Memory: +${consolidationResult.total.added} ADD, ~${consolidationResult.total.updated} UPDATE, ⊕${consolidationResult.total.merged} MERGE`
1140
+ : '',
1141
+ ` Time: ${totalTimeMs}ms (${(totalTimeMs / 1000).toFixed(1)}s)`,
1142
+ ` Mode: ${enableParallel ? `parallel (concurrency=${concurrency})` : 'serial'}`,
1143
+ ` Tokens: input=${totalTokenUsage.input}, output=${totalTokenUsage.output}`,
1144
+ ` Tool calls: ${totalToolCalls}`,
1145
+ skippedDims.length > 0 ? ` Checkpoints restored: [${skippedDims.join(', ')}]` : '',
1146
+ incrementalSkippedDims.length > 0
1147
+ ? ` Incremental skip: [${incrementalSkippedDims.join(', ')}]`
1148
+ : '',
1149
+ ]
1150
+ .filter(Boolean)
1151
+ .join('\n')
1152
+ );
984
1153
 
985
1154
  // P4.2: 生成冷启动报告
986
1155
  try {
@@ -1007,25 +1176,31 @@ export async function fillDimensionsV3(fillContext) {
1007
1176
  checkpoints: {
1008
1177
  restored: skippedDims,
1009
1178
  },
1010
- incremental: isIncremental ? {
1011
- mode: 'incremental',
1012
- affectedDimensions: incrementalPlan.affectedDimensions,
1013
- skippedDimensions: incrementalSkippedDims,
1014
- diff: incrementalPlan.diff ? {
1015
- added: incrementalPlan.diff.added.length,
1016
- modified: incrementalPlan.diff.modified.length,
1017
- deleted: incrementalPlan.diff.deleted.length,
1018
- unchanged: incrementalPlan.diff.unchanged.length,
1019
- } : null,
1020
- reason: incrementalPlan.reason,
1021
- } : null,
1022
- semanticMemory: consolidationResult ? {
1023
- added: consolidationResult.total.added,
1024
- updated: consolidationResult.total.updated,
1025
- merged: consolidationResult.total.merged,
1026
- skipped: consolidationResult.total.skipped,
1027
- durationMs: consolidationResult.durationMs,
1028
- } : null,
1179
+ incremental: isIncremental
1180
+ ? {
1181
+ mode: 'incremental',
1182
+ affectedDimensions: incrementalPlan.affectedDimensions,
1183
+ skippedDimensions: incrementalSkippedDims,
1184
+ diff: incrementalPlan.diff
1185
+ ? {
1186
+ added: incrementalPlan.diff.added.length,
1187
+ modified: incrementalPlan.diff.modified.length,
1188
+ deleted: incrementalPlan.diff.deleted.length,
1189
+ unchanged: incrementalPlan.diff.unchanged.length,
1190
+ }
1191
+ : null,
1192
+ reason: incrementalPlan.reason,
1193
+ }
1194
+ : null,
1195
+ semanticMemory: consolidationResult
1196
+ ? {
1197
+ added: consolidationResult.total.added,
1198
+ updated: consolidationResult.total.updated,
1199
+ merged: consolidationResult.total.merged,
1200
+ skipped: consolidationResult.total.skipped,
1201
+ durationMs: consolidationResult.durationMs,
1202
+ }
1203
+ : null,
1029
1204
  };
1030
1205
 
1031
1206
  for (const [dimId, stat] of Object.entries(dimensionStats)) {
@@ -1042,7 +1217,9 @@ export async function fillDimensionsV3(fillContext) {
1042
1217
 
1043
1218
  // Phase E: 附加 Code Entity Graph 拓扑到报告
1044
1219
  try {
1045
- const { CodeEntityGraph } = await import('../../../../../service/knowledge/CodeEntityGraph.js');
1220
+ const { CodeEntityGraph } = await import(
1221
+ '../../../../../service/knowledge/CodeEntityGraph.js'
1222
+ );
1046
1223
  const db = ctx.container.get('database');
1047
1224
  if (db) {
1048
1225
  const ceg = new CodeEntityGraph(db, { projectRoot, logger });
@@ -1055,13 +1232,15 @@ export async function fillDimensionsV3(fillContext) {
1055
1232
  hotNodes: topo.hotNodes?.slice(0, 5),
1056
1233
  };
1057
1234
  }
1058
- } catch { /* non-blocking */ }
1235
+ } catch {
1236
+ /* non-blocking */
1237
+ }
1059
1238
 
1060
1239
  const reportDir = path.join(projectRoot, '.autosnippet');
1061
1240
  await fs.mkdir(reportDir, { recursive: true });
1062
1241
  await fs.writeFile(
1063
1242
  path.join(reportDir, 'bootstrap-report.json'),
1064
- JSON.stringify(report, null, 2),
1243
+ JSON.stringify(report, null, 2)
1065
1244
  );
1066
1245
  logger.info(`[Bootstrap-v3] 📊 Bootstrap report saved to .autosnippet/bootstrap-report.json`);
1067
1246
  } catch (reportErr) {
@@ -1105,11 +1284,13 @@ export async function fillDimensionsV3(fillContext) {
1105
1284
  if (container.services.cursorDeliveryPipeline) {
1106
1285
  const pipeline = container.get('cursorDeliveryPipeline');
1107
1286
  const deliveryResult = await pipeline.deliver();
1108
- logger.info(`[Bootstrap-v3] 🚀 Cursor Delivery complete — ` +
1109
- `A: ${deliveryResult.channelA.rulesCount} rules, ` +
1110
- `B: ${deliveryResult.channelB.topicCount} topics, ` +
1111
- `C: ${deliveryResult.channelC.synced} skills, ` +
1112
- `D: ${deliveryResult.channelD?.documentsCount || 0} documents`);
1287
+ logger.info(
1288
+ `[Bootstrap-v3] 🚀 Cursor Delivery complete — ` +
1289
+ `A: ${deliveryResult.channelA.rulesCount} rules, ` +
1290
+ `B: ${deliveryResult.channelB.topicCount} topics, ` +
1291
+ `C: ${deliveryResult.channelC.synced} skills, ` +
1292
+ `D: ${deliveryResult.channelD?.documentsCount || 0} documents`
1293
+ );
1113
1294
  }
1114
1295
  } catch (deliveryErr) {
1115
1296
  logger.warn(`[Bootstrap-v3] Cursor Delivery failed (non-blocking): ${deliveryErr.message}`);
@@ -1117,29 +1298,47 @@ export async function fillDimensionsV3(fillContext) {
1117
1298
 
1118
1299
  // ── Repo Wiki: 自动生成项目文档 Wiki ──
1119
1300
  try {
1120
- const { getServiceContainer: getWikiContainer } = await import('../../../../../injection/ServiceContainer.js');
1301
+ const { getServiceContainer: getWikiContainer } = await import(
1302
+ '../../../../../injection/ServiceContainer.js'
1303
+ );
1121
1304
  const wikiContainer = getWikiContainer();
1122
1305
  const { WikiGenerator } = await import('../../../../../service/wiki/WikiGenerator.js');
1123
1306
 
1124
- let spmService = null, knowledgeService = null, codeEntityGraph = null;
1125
- try { spmService = wikiContainer.get('spmService'); } catch { /* optional */ }
1126
- try { knowledgeService = wikiContainer.get('knowledgeService'); } catch { /* optional */ }
1127
- try { codeEntityGraph = wikiContainer.get('codeEntityGraph'); } catch { /* optional */ }
1307
+ let moduleService = null,
1308
+ knowledgeService = null,
1309
+ codeEntityGraph = null;
1310
+ try {
1311
+ moduleService = wikiContainer.get('moduleService');
1312
+ } catch {
1313
+ /* optional */
1314
+ }
1315
+ try {
1316
+ knowledgeService = wikiContainer.get('knowledgeService');
1317
+ } catch {
1318
+ /* optional */
1319
+ }
1320
+ try {
1321
+ codeEntityGraph = wikiContainer.get('codeEntityGraph');
1322
+ } catch {
1323
+ /* optional */
1324
+ }
1128
1325
 
1129
1326
  const wiki = new WikiGenerator({
1130
1327
  projectRoot,
1131
- spmService,
1328
+ moduleService,
1132
1329
  knowledgeService,
1133
- projectGraph, // 来自 Step 0.5 构建的 ProjectGraph
1330
+ projectGraph, // 来自 Step 0.5 构建的 ProjectGraph
1134
1331
  codeEntityGraph,
1135
1332
  aiProvider: wikiContainer.singletons?.aiProvider || null,
1136
1333
  options: { language: process.env.ASD_WIKI_LANG || 'zh' },
1137
1334
  });
1138
1335
  const wikiResult = await wiki.generate();
1139
1336
  if (wikiResult.success) {
1140
- logger.info(`[Bootstrap-v3] 📖 Wiki generated — ${wikiResult.filesGenerated} files, ` +
1141
- `AI: ${wikiResult.aiComposed || 0}, Synced: ${wikiResult.syncedDocs || 0}, ` +
1142
- `Dedup removed: ${wikiResult.dedup?.removed?.length || 0}`);
1337
+ logger.info(
1338
+ `[Bootstrap-v3] 📖 Wiki generated ${wikiResult.filesGenerated} files, ` +
1339
+ `AI: ${wikiResult.aiComposed || 0}, Synced: ${wikiResult.syncedDocs || 0}, ` +
1340
+ `Dedup removed: ${wikiResult.dedup?.removed?.length || 0}`
1341
+ );
1143
1342
  }
1144
1343
  } catch (wikiErr) {
1145
1344
  logger.warn(`[Bootstrap-v3] Wiki generation failed (non-blocking): ${wikiErr.message}`);