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
@@ -16,9 +16,9 @@
16
16
  * @module EpisodicMemory
17
17
  */
18
18
 
19
- import Logger from '../../../../../infrastructure/logging/Logger.js';
20
19
  import fs from 'node:fs';
21
20
  import path from 'node:path';
21
+ import Logger from '../../../../../infrastructure/logging/Logger.js';
22
22
 
23
23
  // ──────────────────────────────────────────────────────────────
24
24
  // 数据结构定义
@@ -136,7 +136,7 @@ export class EpisodicMemory {
136
136
  });
137
137
 
138
138
  // 自动提取文件级 Evidence
139
- for (const f of (report.findings || [])) {
139
+ for (const f of report.findings || []) {
140
140
  if (f.evidence) {
141
141
  const filePath = f.evidence.split(':')[0]; // "file.m:123" → "file.m"
142
142
  this.addEvidence(filePath, {
@@ -163,8 +163,8 @@ export class EpisodicMemory {
163
163
 
164
164
  this.#logger.info(
165
165
  `[EpisodicMemory] Stored report for "${dimId}": ` +
166
- `${report.findings?.length || 0} findings, ` +
167
- `${report.referencedFiles?.length || 0} files`
166
+ `${report.findings?.length || 0} findings, ` +
167
+ `${report.referencedFiles?.length || 0} files`
168
168
  );
169
169
  }
170
170
 
@@ -218,7 +218,9 @@ export class EpisodicMemory {
218
218
 
219
219
  for (const [filePath, evidences] of this.#evidenceStore) {
220
220
  for (const ev of evidences) {
221
- if (dimId && ev.dimId !== dimId) continue;
221
+ if (dimId && ev.dimId !== dimId) {
222
+ continue;
223
+ }
222
224
 
223
225
  const matchesFile = filePath.toLowerCase().includes(lowerQuery);
224
226
  const matchesFinding = (ev.finding || '').toLowerCase().includes(lowerQuery);
@@ -269,7 +271,7 @@ export class EpisodicMemory {
269
271
  dimId,
270
272
  completedAt: Date.now(),
271
273
  analysisText: digest.summary || '',
272
- findings: (digest.keyFindings || []).map(f => ({
274
+ findings: (digest.keyFindings || []).map((f) => ({
273
275
  finding: typeof f === 'string' ? f : f.finding || '',
274
276
  evidence: '',
275
277
  importance: 5,
@@ -287,7 +289,7 @@ export class EpisodicMemory {
287
289
  if (detail) {
288
290
  // 避免重复
289
291
  const exists = this.#crossReferences.some(
290
- cr => cr.from === dimId && cr.to === targetDim
292
+ (cr) => cr.from === dimId && cr.to === targetDim
291
293
  );
292
294
  if (!exists) {
293
295
  this.#crossReferences.push({
@@ -313,8 +315,8 @@ export class EpisodicMemory {
313
315
  this.#tierReflections.push(reflection);
314
316
  this.#logger.info(
315
317
  `[EpisodicMemory] Tier ${tierIndex + 1} reflection: ` +
316
- `${reflection.topFindings?.length || 0} top findings, ` +
317
- `${reflection.crossDimensionPatterns?.length || 0} patterns`
318
+ `${reflection.topFindings?.length || 0} top findings, ` +
319
+ `${reflection.crossDimensionPatterns?.length || 0} patterns`
318
320
  );
319
321
  }
320
322
 
@@ -324,7 +326,9 @@ export class EpisodicMemory {
324
326
  * @returns {string|null} - 格式化的 Markdown 文本
325
327
  */
326
328
  getRelevantReflections(currentDimId) {
327
- if (this.#tierReflections.length === 0) return null;
329
+ if (this.#tierReflections.length === 0) {
330
+ return null;
331
+ }
328
332
 
329
333
  const parts = [];
330
334
  for (const ref of this.#tierReflections) {
@@ -372,8 +376,9 @@ export class EpisodicMemory {
372
376
  */
373
377
  buildContextForDimension(currentDimId, focusAreas = []) {
374
378
  const parts = [];
375
- const completedDims = [...this.#dimensionReports.entries()]
376
- .filter(([id]) => id !== currentDimId);
379
+ const completedDims = [...this.#dimensionReports.entries()].filter(
380
+ ([id]) => id !== currentDimId
381
+ );
377
382
 
378
383
  if (completedDims.length === 0 && this.#tierReflections.length === 0) {
379
384
  return '';
@@ -389,18 +394,18 @@ export class EpisodicMemory {
389
394
  if (report.digest?.summary) {
390
395
  parts.push(report.digest.summary);
391
396
  } else if (report.analysisText) {
392
- parts.push(report.analysisText.substring(0, 300) + '…');
397
+ parts.push(`${report.analysisText.substring(0, 300)}…`);
393
398
  }
394
399
 
395
400
  // 选择与当前维度相关的 findings
396
- const relevantFindings = this.#selectRelevantFindings(
397
- report.findings, focusAreas, 5
398
- );
401
+ const relevantFindings = this.#selectRelevantFindings(report.findings, focusAreas, 5);
399
402
  if (relevantFindings.length > 0) {
400
403
  parts.push('**具体发现**:');
401
404
  for (const f of relevantFindings) {
402
405
  let line = `- [${f.importance}/10] ${f.finding}`;
403
- if (f.evidence) line += ` _(${f.evidence})_`;
406
+ if (f.evidence) {
407
+ line += ` _(${f.evidence})_`;
408
+ }
404
409
  parts.push(line);
405
410
  }
406
411
  }
@@ -408,7 +413,9 @@ export class EpisodicMemory {
408
413
  // 候选数量
409
414
  const candidates = this.#submittedCandidates.get(dimId) || [];
410
415
  if (candidates.length > 0) {
411
- parts.push(`已提交 ${candidates.length} 个候选: ${candidates.map(c => c.title).join(', ')}`);
416
+ parts.push(
417
+ `已提交 ${candidates.length} 个候选: ${candidates.map((c) => c.title).join(', ')}`
418
+ );
412
419
  }
413
420
  }
414
421
 
@@ -429,9 +436,7 @@ export class EpisodicMemory {
429
436
  }
430
437
 
431
438
  // §3: 跨维度引用建议
432
- const relevantCrossRefs = this.#crossReferences.filter(
433
- cr => cr.to === currentDimId
434
- );
439
+ const relevantCrossRefs = this.#crossReferences.filter((cr) => cr.to === currentDimId);
435
440
  if (relevantCrossRefs.length > 0) {
436
441
  parts.push(`### 其他维度对 ${currentDimId} 的建议`);
437
442
  for (const cr of relevantCrossRefs) {
@@ -458,11 +463,13 @@ export class EpisodicMemory {
458
463
  buildContextSnapshot(currentDimId) {
459
464
  const previousDimensions = {};
460
465
  for (const [dimId, report] of this.#dimensionReports) {
461
- if (dimId === currentDimId) continue;
466
+ if (dimId === currentDimId) {
467
+ continue;
468
+ }
462
469
  previousDimensions[dimId] = report.digest || {
463
470
  summary: report.analysisText?.substring(0, 300) || '',
464
471
  candidateCount: report.candidatesSummary?.length || 0,
465
- keyFindings: report.findings?.map(f => f.finding) || [],
472
+ keyFindings: report.findings?.map((f) => f.finding) || [],
466
473
  crossRefs: {},
467
474
  gaps: [],
468
475
  };
@@ -491,11 +498,14 @@ export class EpisodicMemory {
491
498
  version: 1,
492
499
  savedAt: Date.now(),
493
500
  dimensionReports: Object.fromEntries(
494
- [...this.#dimensionReports].map(([k, v]) => [k, {
495
- ...v,
496
- // 不保存 analysisText 全文 (太大), 只保存 digest + findings
497
- analysisText: v.analysisText?.substring(0, 500) || '',
498
- }])
501
+ [...this.#dimensionReports].map(([k, v]) => [
502
+ k,
503
+ {
504
+ ...v,
505
+ // 不保存 analysisText 全文 (太大), 只保存 digest + findings
506
+ analysisText: v.analysisText?.substring(0, 500) || '',
507
+ },
508
+ ])
499
509
  ),
500
510
  crossReferences: this.#crossReferences,
501
511
  tierReflections: this.#tierReflections,
@@ -509,7 +519,9 @@ export class EpisodicMemory {
509
519
  'utf-8'
510
520
  );
511
521
 
512
- this.#logger.info(`[EpisodicMemory] Checkpoint saved: ${this.#dimensionReports.size} reports`);
522
+ this.#logger.info(
523
+ `[EpisodicMemory] Checkpoint saved: ${this.#dimensionReports.size} reports`
524
+ );
513
525
  } catch (err) {
514
526
  this.#logger.warn(`[EpisodicMemory] Failed to save checkpoint: ${err.message}`);
515
527
  }
@@ -522,11 +534,16 @@ export class EpisodicMemory {
522
534
  */
523
535
  async loadCheckpoint(projectRoot) {
524
536
  const checkpointPath = path.join(
525
- projectRoot, '.autosnippet', 'bootstrap-checkpoint', 'episodic-memory.json'
537
+ projectRoot,
538
+ '.autosnippet',
539
+ 'bootstrap-checkpoint',
540
+ 'episodic-memory.json'
526
541
  );
527
542
 
528
543
  try {
529
- if (!fs.existsSync(checkpointPath)) return false;
544
+ if (!fs.existsSync(checkpointPath)) {
545
+ return false;
546
+ }
530
547
 
531
548
  const raw = fs.readFileSync(checkpointPath, 'utf-8');
532
549
  const data = JSON.parse(raw);
@@ -561,7 +578,9 @@ export class EpisodicMemory {
561
578
  }
562
579
  }
563
580
 
564
- this.#logger.info(`[EpisodicMemory] Checkpoint loaded: ${this.#dimensionReports.size} reports`);
581
+ this.#logger.info(
582
+ `[EpisodicMemory] Checkpoint loaded: ${this.#dimensionReports.size} reports`
583
+ );
565
584
  return true;
566
585
  } catch (err) {
567
586
  this.#logger.warn(`[EpisodicMemory] Failed to load checkpoint: ${err.message}`);
@@ -640,12 +659,18 @@ export class EpisodicMemory {
640
659
  * @returns {object}
641
660
  */
642
661
  getStats() {
643
- const totalFindings = [...this.#dimensionReports.values()]
644
- .reduce((sum, r) => sum + r.findings.length, 0);
645
- const totalEvidence = [...this.#evidenceStore.values()]
646
- .reduce((sum, arr) => sum + arr.length, 0);
647
- const totalCandidates = [...this.#submittedCandidates.values()]
648
- .reduce((sum, arr) => sum + arr.length, 0);
662
+ const totalFindings = [...this.#dimensionReports.values()].reduce(
663
+ (sum, r) => sum + r.findings.length,
664
+ 0
665
+ );
666
+ const totalEvidence = [...this.#evidenceStore.values()].reduce(
667
+ (sum, arr) => sum + arr.length,
668
+ 0
669
+ );
670
+ const totalCandidates = [...this.#submittedCandidates.values()].reduce(
671
+ (sum, arr) => sum + arr.length,
672
+ 0
673
+ );
649
674
 
650
675
  return {
651
676
  completedDimensions: this.#dimensionReports.size,
@@ -668,7 +693,9 @@ export class EpisodicMemory {
668
693
  * @returns {Finding[]}
669
694
  */
670
695
  #selectRelevantFindings(findings, focusAreas, limit) {
671
- if (!findings || findings.length === 0) return [];
696
+ if (!findings || findings.length === 0) {
697
+ return [];
698
+ }
672
699
 
673
700
  if (!focusAreas || focusAreas.length === 0) {
674
701
  // 无焦点领域: 按重要性排序
@@ -679,10 +706,12 @@ export class EpisodicMemory {
679
706
 
680
707
  // 有焦点领域: 综合重要性 + 关键词匹配
681
708
  return [...findings]
682
- .map(f => {
683
- const relevance = focusAreas.some(area =>
709
+ .map((f) => {
710
+ const relevance = focusAreas.some((area) =>
684
711
  (f.finding || '').toLowerCase().includes(area.toLowerCase())
685
- ) ? 1 : 0;
712
+ )
713
+ ? 1
714
+ : 0;
686
715
  return { ...f, _score: relevance * 10 + (f.importance || 5) };
687
716
  })
688
717
  .sort((a, b) => b._score - a._score)
@@ -15,8 +15,8 @@
15
15
  * @module pipeline/IncrementalBootstrap
16
16
  */
17
17
 
18
- import { EpisodicMemory } from './EpisodicMemory.js';
19
18
  import { BootstrapSnapshot } from './BootstrapSnapshot.js';
19
+ import { EpisodicMemory } from './EpisodicMemory.js';
20
20
 
21
21
  // ──────────────────────────────────────────────────────────────
22
22
  // IncrementalBootstrap 类
@@ -85,14 +85,12 @@ export class IncrementalBootstrap {
85
85
 
86
86
  this.#log(
87
87
  `Diff: +${diff.added.length} added, ~${diff.modified.length} modified, ` +
88
- `-${diff.deleted.length} deleted, =${diff.unchanged.length} unchanged ` +
89
- `(ratio: ${(diff.changeRatio * 100).toFixed(1)}%)`
88
+ `-${diff.deleted.length} deleted, =${diff.unchanged.length} unchanged ` +
89
+ `(ratio: ${(diff.changeRatio * 100).toFixed(1)}%)`
90
90
  );
91
91
 
92
92
  // 3. 推断受影响维度
93
- const inference = this.#snapshot.inferAffectedDimensions(
94
- previousSnapshot, diff, allDimIds
95
- );
93
+ const inference = this.#snapshot.inferAffectedDimensions(previousSnapshot, diff, allDimIds);
96
94
 
97
95
  if (inference.mode === 'full') {
98
96
  this.#log(`Full rebuild recommended: ${inference.reason}`);
@@ -113,7 +111,9 @@ export class IncrementalBootstrap {
113
111
  if (previousSnapshot.episodicData) {
114
112
  try {
115
113
  restoredEpisodic = EpisodicMemory.fromJSON(previousSnapshot.episodicData);
116
- this.#log(`Restored EpisodicMemory: ${restoredEpisodic.getCompletedDimensions().length} dimensions`);
114
+ this.#log(
115
+ `Restored EpisodicMemory: ${restoredEpisodic.getCompletedDimensions().length} dimensions`
116
+ );
117
117
  } catch (err) {
118
118
  this.#log(`Failed to restore EpisodicMemory: ${err.message}`, 'warn');
119
119
  }
@@ -121,7 +121,7 @@ export class IncrementalBootstrap {
121
121
 
122
122
  this.#log(
123
123
  `Incremental plan: ${inference.dimensions.length} affected, ` +
124
- `${inference.skippedDimensions.length} skipped — ${inference.reason}`
124
+ `${inference.skippedDimensions.length} skipped — ${inference.reason}`
125
125
  );
126
126
 
127
127
  return {
@@ -134,7 +134,6 @@ export class IncrementalBootstrap {
134
134
  reason: inference.reason,
135
135
  restoredEpisodic,
136
136
  };
137
-
138
137
  } catch (err) {
139
138
  this.#log(`Incremental evaluation failed: ${err.message} — fallback to full`, 'warn');
140
139
  return {
@@ -163,14 +162,7 @@ export class IncrementalBootstrap {
163
162
  * @returns {string} 快照 ID
164
163
  */
165
164
  saveSnapshot(params) {
166
- const {
167
- sessionId,
168
- allFiles,
169
- dimensionStats,
170
- episodicMemory,
171
- meta = {},
172
- plan = null,
173
- } = params;
165
+ const { sessionId, allFiles, dimensionStats, episodicMemory, meta = {}, plan = null } = params;
174
166
 
175
167
  // 构建带 referencedFilesList 的 dimensionStats
176
168
  const enrichedStats = { ...dimensionStats };
@@ -58,7 +58,9 @@ export class ToolResultCache {
58
58
  if (this.#ttlMs > 0 && cleanupInterval > 0) {
59
59
  this.#cleanupTimer = setInterval(() => this.#evictExpired(), cleanupInterval);
60
60
  // 允许进程退出时不被 timer 阻塞
61
- if (this.#cleanupTimer.unref) this.#cleanupTimer.unref();
61
+ if (this.#cleanupTimer.unref) {
62
+ this.#cleanupTimer.unref();
63
+ }
62
64
  }
63
65
  }
64
66
 
@@ -91,7 +93,7 @@ export class ToolResultCache {
91
93
  const entry = this.#searchCache.get(pattern);
92
94
  if (entry) {
93
95
  // TTL 检查
94
- if (this.#ttlMs > 0 && (Date.now() - entry.cachedAt) > this.#ttlMs) {
96
+ if (this.#ttlMs > 0 && Date.now() - entry.cachedAt > this.#ttlMs) {
95
97
  this.#searchCache.delete(pattern);
96
98
  this.#stats.evictions++;
97
99
  this.#stats.misses++;
@@ -133,7 +135,7 @@ export class ToolResultCache {
133
135
  const entry = this.#fileCache.get(filePath);
134
136
  if (entry) {
135
137
  // TTL 检查
136
- if (this.#ttlMs > 0 && (Date.now() - entry.cachedAt) > this.#ttlMs) {
138
+ if (this.#ttlMs > 0 && Date.now() - entry.cachedAt > this.#ttlMs) {
137
139
  this.#fileCache.delete(filePath);
138
140
  this.#stats.evictions++;
139
141
  this.#stats.misses++;
@@ -205,9 +207,10 @@ export class ToolResultCache {
205
207
  getStats() {
206
208
  return {
207
209
  ...this.#stats,
208
- hitRate: this.#stats.hits + this.#stats.misses > 0
209
- ? (this.#stats.hits / (this.#stats.hits + this.#stats.misses) * 100).toFixed(1) + '%'
210
- : '0%',
210
+ hitRate:
211
+ this.#stats.hits + this.#stats.misses > 0
212
+ ? `${((this.#stats.hits / (this.#stats.hits + this.#stats.misses)) * 100).toFixed(1)}%`
213
+ : '0%',
211
214
  searchCacheSize: this.#searchCache.size,
212
215
  fileCacheSize: this.#fileCache.size,
213
216
  };
@@ -241,18 +244,20 @@ export class ToolResultCache {
241
244
  * @private
242
245
  */
243
246
  #evictExpired() {
244
- if (this.#ttlMs <= 0) return;
247
+ if (this.#ttlMs <= 0) {
248
+ return;
249
+ }
245
250
  const now = Date.now();
246
251
  let evicted = 0;
247
252
 
248
253
  for (const [key, entry] of this.#searchCache) {
249
- if ((now - entry.cachedAt) > this.#ttlMs) {
254
+ if (now - entry.cachedAt > this.#ttlMs) {
250
255
  this.#searchCache.delete(key);
251
256
  evicted++;
252
257
  }
253
258
  }
254
259
  for (const [key, entry] of this.#fileCache) {
255
- if ((now - entry.cachedAt) > this.#ttlMs) {
260
+ if (now - entry.cachedAt > this.#ttlMs) {
256
261
  this.#fileCache.delete(key);
257
262
  evicted++;
258
263
  }
@@ -91,7 +91,7 @@ export class DimensionContext {
91
91
  return {
92
92
  project: this.projectContext,
93
93
  previousDimensions,
94
- existingCandidates: this.submittedCandidates.map(c => ({
94
+ existingCandidates: this.submittedCandidates.map((c) => ({
95
95
  dimId: c.dimId,
96
96
  title: c.title,
97
97
  subTopic: c.subTopic,
@@ -107,7 +107,7 @@ export class DimensionContext {
107
107
  * @returns {Array<CandidateSummary>}
108
108
  */
109
109
  getExistingCandidatesForDimension(dimId) {
110
- return this.submittedCandidates.filter(c => c.dimId === dimId);
110
+ return this.submittedCandidates.filter((c) => c.dimId === dimId);
111
111
  }
112
112
 
113
113
  /**
@@ -117,7 +117,9 @@ export class DimensionContext {
117
117
  * @returns {string}
118
118
  */
119
119
  getDigestsSummaryText() {
120
- if (this.completedDimensions.size === 0) return '(尚无已完成维度)';
120
+ if (this.completedDimensions.size === 0) {
121
+ return '(尚无已完成维度)';
122
+ }
121
123
 
122
124
  const lines = [];
123
125
  for (const [id, digest] of this.completedDimensions) {
@@ -136,7 +138,7 @@ export class DimensionContext {
136
138
  lines.push(`- 缺口: ${digest.gaps.join('; ')}`);
137
139
  }
138
140
  if (digest.remainingTasks?.length) {
139
- lines.push(`- 遗留任务: ${digest.remainingTasks.map(t => t.signal || t).join('; ')}`);
141
+ lines.push(`- 遗留任务: ${digest.remainingTasks.map((t) => t.signal || t).join('; ')}`);
140
142
  }
141
143
  lines.push('');
142
144
  }
@@ -180,7 +182,9 @@ export class DimensionContext {
180
182
  * @returns {DimensionDigest|null}
181
183
  */
182
184
  export function parseDimensionDigest(reply) {
183
- if (!reply || typeof reply !== 'string') return null;
185
+ if (!reply || typeof reply !== 'string') {
186
+ return null;
187
+ }
184
188
 
185
189
  // 尝试匹配 {"dimensionDigest": {...}} 格式
186
190
  const jsonBlockRe = /```(?:json)?\s*\n?\s*(\{[\s\S]*?"dimensionDigest"[\s\S]*?\})\s*\n?\s*```/;
@@ -192,14 +196,18 @@ export function parseDimensionDigest(reply) {
192
196
  match = reply.match(bareRe);
193
197
  }
194
198
 
195
- if (!match) return null;
199
+ if (!match) {
200
+ return null;
201
+ }
196
202
 
197
203
  try {
198
204
  const parsed = JSON.parse(match[1]);
199
205
  const digest = parsed.dimensionDigest || parsed;
200
206
 
201
207
  // 验证必要字段
202
- if (!digest.summary && !digest.candidateCount) return null;
208
+ if (!digest.summary && !digest.candidateCount) {
209
+ return null;
210
+ }
203
211
 
204
212
  return {
205
213
  summary: digest.summary || '',