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
@@ -108,8 +108,8 @@ export class EpisodicConsolidator {
108
108
 
109
109
  this.#logger.info(
110
110
  `[Consolidator] Extracted ${allCandidates.length} candidate memories: ` +
111
- `${findingMemories.length} findings, ${insightMemories.length} insights, ` +
112
- `${textFactMemories.length} text facts`
111
+ `${findingMemories.length} findings, ${insightMemories.length} insights, ` +
112
+ `${textFactMemories.length} text facts`
113
113
  );
114
114
 
115
115
  const result = this.#semanticMemory.consolidate(allCandidates, { bootstrapSession });
@@ -117,8 +117,8 @@ export class EpisodicConsolidator {
117
117
  const durationMs = Date.now() - t0;
118
118
  this.#logger.info(
119
119
  `[Consolidator] Consolidation complete in ${durationMs}ms: ` +
120
- `+${result.added} ADD, ~${result.updated} UPDATE, ⊕${result.merged} MERGE, ` +
121
- `=${result.skipped} SKIP`
120
+ `+${result.added} ADD, ~${result.updated} UPDATE, ⊕${result.merged} MERGE, ` +
121
+ `=${result.skipped} SKIP`
122
122
  );
123
123
 
124
124
  return {
@@ -143,15 +143,21 @@ export class EpisodicConsolidator {
143
143
 
144
144
  for (const dimId of completedDims) {
145
145
  const report = episodicMemory.getDimensionReport(dimId);
146
- if (!report?.findings) continue;
146
+ if (!report?.findings) {
147
+ continue;
148
+ }
147
149
 
148
150
  for (const f of report.findings) {
149
151
  // 跳过低重要性的发现
150
- if ((f.importance || 5) < 4) continue;
152
+ if ((f.importance || 5) < 4) {
153
+ continue;
154
+ }
151
155
 
152
156
  // 跳过过短的发现
153
- const content = typeof f === 'string' ? f : (f.finding || '');
154
- if (content.length < 10) continue;
157
+ const content = typeof f === 'string' ? f : f.finding || '';
158
+ if (content.length < 10) {
159
+ continue;
160
+ }
155
161
 
156
162
  // 提取关联实体 (从 evidence 中提取文件名/类名)
157
163
  const entities = this.#extractEntities(content, f.evidence);
@@ -160,9 +166,9 @@ export class EpisodicConsolidator {
160
166
  type: 'fact',
161
167
  content: content.substring(0, 500),
162
168
  source: 'bootstrap',
163
- importance: typeof f === 'string' ? 5 : (f.importance || 5),
169
+ importance: typeof f === 'string' ? 5 : f.importance || 5,
164
170
  sourceDimension: dimId,
165
- sourceEvidence: typeof f === 'string' ? '' : (f.evidence || ''),
171
+ sourceEvidence: typeof f === 'string' ? '' : f.evidence || '',
166
172
  relatedEntities: entities,
167
173
  tags: [dimId],
168
174
  });
@@ -186,8 +192,10 @@ export class EpisodicConsolidator {
186
192
 
187
193
  for (const ref of reflections) {
188
194
  // 跨维度模式 → insight
189
- for (const pattern of (ref.crossDimensionPatterns || [])) {
190
- if (pattern.length < 10) continue;
195
+ for (const pattern of ref.crossDimensionPatterns || []) {
196
+ if (pattern.length < 10) {
197
+ continue;
198
+ }
191
199
  memories.push({
192
200
  type: 'insight',
193
201
  content: pattern.substring(0, 500),
@@ -200,8 +208,10 @@ export class EpisodicConsolidator {
200
208
  }
201
209
 
202
210
  // 建议 → insight (较低优先级)
203
- for (const suggestion of (ref.suggestionsForNextTier || [])) {
204
- if (suggestion.length < 10) continue;
211
+ for (const suggestion of ref.suggestionsForNextTier || []) {
212
+ if (suggestion.length < 10) {
213
+ continue;
214
+ }
205
215
  memories.push({
206
216
  type: 'insight',
207
217
  content: suggestion.substring(0, 500),
@@ -213,10 +223,14 @@ export class EpisodicConsolidator {
213
223
  }
214
224
 
215
225
  // 高重要性 topFindings → fact (≥ 7 分的重要发现)
216
- for (const f of (ref.topFindings || [])) {
217
- if ((f.importance || 5) < 7) continue;
218
- const content = typeof f === 'string' ? f : (f.finding || '');
219
- if (content.length < 10) continue;
226
+ for (const f of ref.topFindings || []) {
227
+ if ((f.importance || 5) < 7) {
228
+ continue;
229
+ }
230
+ const content = typeof f === 'string' ? f : f.finding || '';
231
+ if (content.length < 10) {
232
+ continue;
233
+ }
220
234
 
221
235
  memories.push({
222
236
  type: 'fact',
@@ -246,7 +260,9 @@ export class EpisodicConsolidator {
246
260
 
247
261
  for (const dimId of completedDims) {
248
262
  const report = episodicMemory.getDimensionReport(dimId);
249
- if (!report?.analysisText) continue;
263
+ if (!report?.analysisText) {
264
+ continue;
265
+ }
250
266
 
251
267
  const text = report.analysisText;
252
268
 
@@ -258,8 +274,12 @@ export class EpisodicConsolidator {
258
274
  let matchCount = 0;
259
275
  while ((match = pattern.exec(text)) !== null && matchCount < 5) {
260
276
  const fullMatch = match[0].trim();
261
- if (fullMatch.length < 10 || fullMatch.length > 120) continue;
262
- if (seen.has(fullMatch)) continue;
277
+ if (fullMatch.length < 10 || fullMatch.length > 120) {
278
+ continue;
279
+ }
280
+ if (seen.has(fullMatch)) {
281
+ continue;
282
+ }
263
283
  seen.add(fullMatch);
264
284
  matchCount++;
265
285
 
@@ -282,8 +302,12 @@ export class EpisodicConsolidator {
282
302
  let matchCount = 0;
283
303
  while ((match = pattern.exec(text)) !== null && matchCount < 3) {
284
304
  const fullMatch = match[0].trim();
285
- if (fullMatch.length < 10 || fullMatch.length > 120) continue;
286
- if (seen.has(fullMatch)) continue;
305
+ if (fullMatch.length < 10 || fullMatch.length > 120) {
306
+ continue;
307
+ }
308
+ if (seen.has(fullMatch)) {
309
+ continue;
310
+ }
287
311
  seen.add(fullMatch);
288
312
  matchCount++;
289
313
 
@@ -18,7 +18,9 @@
18
18
  * 这些内容如果传给 Producer,会干扰其正常工作流。
19
19
  */
20
20
  function sanitizeAnalysisText(text) {
21
- if (!text) return '';
21
+ if (!text) {
22
+ return '';
23
+ }
22
24
  // 移除 graceful exit nudge 及 digest 模板指令
23
25
  const patterns = [
24
26
  /\*{0,2}⚠️?\s*(?:你已使用|轮次即将耗尽|仅剩|请立即停止|必须立即结束)[^\n]*\n?/gi,
@@ -28,6 +30,63 @@ function sanitizeAnalysisText(text) {
28
30
  /> ?⚠️ 严禁输出任何非 JSON 内容[^\n]*\n?/gi,
29
31
  // 移除 AI 回显的 dimensionDigest JSON 块(对 Producer 无价值且会干扰)
30
32
  /```json\s*\n\s*\{\s*"dimensionDigest"\s*:[\s\S]*?\n```/g,
33
+
34
+ // ── AI 思考伪影清理 ──
35
+
36
+ // 轮次/阶段计数器(如 "第 18/24 轮 | 验证阶段 | 剩余 6 轮")
37
+ /^-{2,3}\s*\n\s*第\s*\d+\/\d+\s*轮[^\n]*\n(-{2,3}\s*\n)?/gm,
38
+ // 独立分隔线 + 空内容
39
+ /^-{3}\s*$/gm,
40
+
41
+ // AI 规划/反思段落("计划偏差分析"、"最终总结阶段" 等)
42
+ /^#{1,3}\s*(?:计划偏差分析|最终总结阶段|执行计划|下一步计划|分析计划)\s*\n[\s\S]*?(?=\n#{1,3}\s|\n\n(?=[^#\s-]))/gm,
43
+
44
+ // 系统提示回显("(提示: ...)")
45
+ /^\(提示[::][^)]*\)\s*\n?/gm,
46
+
47
+ // AI 英文思考泄漏("Wait, I have enough information..."、"Let me..."、"I'll stop here...")
48
+ /^(?:Wait,|Let me|I'll stop here|I will stop|I need to|I should|I have enough)[^\n]*\n?/gm,
49
+
50
+ // 工具提示循环("尝试使用 `tool_name`..."、"- 尝试使用...")
51
+ /^[-•]\s*尝试使用\s*`[^`]+`[^\n]*\n?/gm,
52
+ /^💡\s*提示[::]?\s*\n?/gm,
53
+
54
+ // 请继续 / 请接续 单行(AI 被截断后的续写请求)
55
+ /^请(?:继续|接续)[。.]?\s*$/gm,
56
+
57
+ // 📊 中期反思块("📊 中期反思 (第 N/M 轮, X% 预算):" 及后续所有内容直到下一个 ## 或 📊)
58
+ /📊\s*中期反思\s*\([^)]*\):?\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
59
+
60
+ // AI 思考方向列表("你最近的思考方向:" + 编号列表 + 嵌套的探索计划)
61
+ /^你最近的思考方向:\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
62
+
63
+ // AI 探索计划标题("### 探索计划")— 这是 AI 内部规划,不应出现在最终输出中
64
+ /^#{1,3}\s*探索计划\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划)|\n\n(?=[^#\s\d-])|\n(?=📊)|$))/gm,
65
+ // 编号前缀的探索计划(" 1. ### 探索计划" + 紧随的编号列表项)
66
+ /^\s*\d+\.\s+#{1,3}\s*探索计划[^\n]*\n(?:\d+\.\s+\*{0,2}[^\n]*\n?)*/gm,
67
+
68
+ // AI 轮次标题("### 第 N 轮:..." 开头的规划/反思段落)
69
+ /^#{1,3}\s*第\s*\d+\s*轮[::][^\n]*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n\n(?=#{1,3}\s)|\n(?=📊)|$))/gm,
70
+
71
+ // 行动效率统计行("行动效率: 最近 N 轮中 X% 获取到新信息")
72
+ /^行动效率[::][^\n]*\n?/gm,
73
+ /^累计[::]\s*\d+\s*文件[^\n]*\n?/gm,
74
+
75
+ // 计划进度("📋 计划进度: 0/1 步骤已完成")
76
+ /^📋\s*计划进度[::][^\n]*\n?/gm,
77
+
78
+ // 请评估提示块("请评估: 1. ...")
79
+ /^请评估[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
80
+
81
+ // AI 对话提示回显("(请在继续调用工具前...)", "(由于当前已是第 N 轮...)", "(注意: 每一轮都必须...)")
82
+ /^\([请由注](?:在继续|于当前|意[::])[^)]*\)\s*\n?/gm,
83
+
84
+ // AI 步骤进度与计划更新("已经读取,未完成步骤..."、"计划更新:..."、"更新后的计划:...")
85
+ /^(?:\d+\.\s+)?(?:`[^`]*`\s+)?(?:已经读取|未完成步骤仅剩|计划更新|更新后的计划)[^\n]*\n?/gm,
86
+ /^更新后的计划[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
87
+
88
+ // 纯数字编号残留行(清理被上面 pattern 删除后留下的孤立编号)
89
+ /^\s*\d+\.\s*$/gm,
31
90
  ];
32
91
  let cleaned = text;
33
92
  for (const pat of patterns) {
@@ -53,24 +112,30 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
53
112
  const searchQueries = [];
54
113
  const classesExplored = [];
55
114
 
56
- for (const call of (analystResult.toolCalls || [])) {
115
+ for (const call of analystResult.toolCalls || []) {
57
116
  const tool = call.tool || call.name;
58
117
  const args = call.params || call.args || {};
59
118
  const result = call.result;
60
119
 
61
120
  switch (tool) {
62
121
  case 'read_project_file':
63
- if (args.filePath) referencedFiles.add(args.filePath);
122
+ if (args.filePath) {
123
+ referencedFiles.add(args.filePath);
124
+ }
64
125
  break;
65
126
  case 'search_project_code':
66
- if (args.pattern || args.query) searchQueries.push(args.pattern || args.query);
127
+ if (args.pattern || args.query) {
128
+ searchQueries.push(args.pattern || args.query);
129
+ }
67
130
  // 从搜索结果中提取文件路径
68
131
  if (typeof result === 'string') {
69
- const fileMatches = result.match(/(?:^|\n)([\w/.-]+\.[mhswift]+)(?::\d+)?/g);
132
+ const fileMatches = result.match(/(?:^|\n)([\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst))(?::\d+)?/gi);
70
133
  if (fileMatches) {
71
134
  for (const m of fileMatches) {
72
135
  const clean = m.trim().replace(/:\d+$/, '').replace(/^\n/, '');
73
- if (clean.length > 2 && clean.length < 120) referencedFiles.add(clean);
136
+ if (clean.length > 2 && clean.length < 120) {
137
+ referencedFiles.add(clean);
138
+ }
74
139
  }
75
140
  }
76
141
  }
@@ -81,28 +146,35 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
81
146
  // 从 ProjectGraph 反查文件路径
82
147
  if (projectGraph) {
83
148
  const info = projectGraph.getClassInfo(args.className);
84
- if (info?.filePath) referencedFiles.add(info.filePath);
149
+ if (info?.filePath) {
150
+ referencedFiles.add(info.filePath);
151
+ }
85
152
  }
86
153
  }
87
154
  break;
88
155
  case 'get_protocol_info':
89
156
  if (args.protocolName && projectGraph) {
90
157
  const info = projectGraph.getProtocolInfo(args.protocolName);
91
- if (info?.filePath) referencedFiles.add(info.filePath);
158
+ if (info?.filePath) {
159
+ referencedFiles.add(info.filePath);
160
+ }
92
161
  }
93
162
  break;
94
163
  case 'get_file_summary':
95
- if (args.filePath) referencedFiles.add(args.filePath);
164
+ if (args.filePath) {
165
+ referencedFiles.add(args.filePath);
166
+ }
96
167
  break;
97
168
  }
98
169
  }
99
170
 
100
- // 从分析文本中提取文件路径
171
+ // 从分析文本中提取文件路径(支持多语言项目)
101
172
  const text = sanitizeAnalysisText(analystResult.reply || '');
102
- const textFileRefs = text.match(/[\w/.-]+\.[mhswift]+/g);
173
+ const FILE_EXT_RE = /[\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst)\b/gi;
174
+ const textFileRefs = text.match(FILE_EXT_RE);
103
175
  if (textFileRefs) {
104
176
  for (const f of textFileRefs) {
105
- if (f.length > 2 && f.length < 120 && /\.[mhswift]+$/.test(f)) {
177
+ if (f.length > 2 && f.length < 120) {
106
178
  referencedFiles.add(f);
107
179
  }
108
180
  }
@@ -156,19 +228,20 @@ export function analysisQualityGate(report, options = {}) {
156
228
  /I cannot|I'm unable|I don't have access/i,
157
229
  /无法分析|无法访问|没有足够/,
158
230
  ];
159
- if (refusalPatterns.some(p => p.test(report.analysisText))) {
231
+ if (refusalPatterns.some((p) => p.test(report.analysisText))) {
160
232
  return { pass: false, reason: 'Agent refused to analyze', action: 'degrade' };
161
233
  }
162
234
 
163
235
  // 规则 4: 内容实质性检查 — 有结构化内容或足够多的探索
164
236
  // v3.1: 放宽条件 — tool calling 模式下 AI 往往不输出 markdown 格式
165
237
  // 只要分析足够长且引用了足够多的文件,就认为有实质性内容
166
- const hasStructure = /#{1,3}\s/.test(report.analysisText) ||
167
- /\d+\.\s/.test(report.analysisText) ||
168
- /[-•]\s/.test(report.analysisText) ||
169
- /[::].+\n/.test(report.analysisText) ||
170
- report.analysisText.length >= 500 ||
171
- (report.referencedFiles.length >= 3 && report.analysisText.length >= 200);
238
+ const hasStructure =
239
+ /#{1,3}\s/.test(report.analysisText) ||
240
+ /\d+\.\s/.test(report.analysisText) ||
241
+ /[-•]\s/.test(report.analysisText) ||
242
+ /[::].+\n/.test(report.analysisText) ||
243
+ report.analysisText.length >= 500 ||
244
+ (report.referencedFiles.length >= 3 && report.analysisText.length >= 200);
172
245
  if (!hasStructure) {
173
246
  return { pass: false, reason: 'Analysis lacks structure', action: 'retry' };
174
247
  }
@@ -184,9 +257,12 @@ export function analysisQualityGate(report, options = {}) {
184
257
  */
185
258
  export function buildRetryPrompt(reason) {
186
259
  const hints = {
187
- 'Analysis too short': '你的分析不够深入。请使用更多工具(get_class_info、read_project_file、search_project_code)查看实际代码,输出至少 500 字的分析。',
188
- 'Too few file references': '你的分析缺少代码引用。请使用 get_class_inforead_project_file 查看至少 3 个相关文件,并在分析中引用具体文件和行号。',
189
- 'Analysis lacks structure': '请将分析组织成结构化的段落,使用编号列表或标题来区分不同的发现。每个发现应包含具体的文件路径和代码位置。',
260
+ 'Analysis too short':
261
+ '你的分析不够深入。请使用更多工具(get_class_inforead_project_file、search_project_code)查看实际代码,输出至少 500 字的分析。',
262
+ 'Too few file references':
263
+ '你的分析缺少代码引用。请使用 get_class_info 和 read_project_file 查看至少 3 个相关文件,并在分析中引用具体文件和行号。',
264
+ 'Analysis lacks structure':
265
+ '请将分析组织成结构化的段落,使用编号列表或标题来区分不同的发现。每个发现应包含具体的文件路径和代码位置。',
190
266
  };
191
267
 
192
268
  return hints[reason] || '请更深入地分析代码,引用至少 3 个具体文件,每个发现都要有代码证据。';
@@ -51,16 +51,26 @@ export class Memory {
51
51
  */
52
52
  load(limit = 20, { source } = {}) {
53
53
  try {
54
- if (!fs.existsSync(this.#filePath)) return [];
54
+ if (!fs.existsSync(this.#filePath)) {
55
+ return [];
56
+ }
55
57
  const raw = fs.readFileSync(this.#filePath, 'utf-8').trim();
56
- if (!raw) return [];
58
+ if (!raw) {
59
+ return [];
60
+ }
57
61
  const lines = raw.split('\n').filter(Boolean);
58
62
  const now = Date.now();
59
63
  return lines
60
- .map(l => { try { return JSON.parse(l); } catch { return null; } })
64
+ .map((l) => {
65
+ try {
66
+ return JSON.parse(l);
67
+ } catch {
68
+ return null;
69
+ }
70
+ })
61
71
  .filter(Boolean)
62
- .filter(m => !m.ttl || (now - new Date(m.ts).getTime()) < m.ttl * 86400000)
63
- .filter(m => !source || (m.source || 'user') === source)
72
+ .filter((m) => !m.ttl || now - new Date(m.ts).getTime() < m.ttl * 86400000)
73
+ .filter((m) => !source || (m.source || 'user') === source)
64
74
  .slice(-limit);
65
75
  } catch {
66
76
  return [];
@@ -77,9 +87,11 @@ export class Memory {
77
87
  const existing = this.load(this.#maxEntries);
78
88
  const normalizedContent = (entry.content || '').trim().substring(0, 200);
79
89
  const isDuplicate = existing.some(
80
- m => m.type === entry.type && m.content === normalizedContent,
90
+ (m) => m.type === entry.type && m.content === normalizedContent
81
91
  );
82
- if (isDuplicate) return;
92
+ if (isDuplicate) {
93
+ return;
94
+ }
83
95
 
84
96
  const dir = path.dirname(this.#filePath);
85
97
  fs.mkdirSync(dir, { recursive: true });
@@ -89,9 +101,11 @@ export class Memory {
89
101
  ...entry,
90
102
  content: normalizedContent,
91
103
  });
92
- fs.appendFileSync(this.#filePath, line + '\n', 'utf-8');
104
+ fs.appendFileSync(this.#filePath, `${line}\n`, 'utf-8');
93
105
  this.#compact();
94
- } catch { /* write failure non-critical */ }
106
+ } catch {
107
+ /* write failure non-critical */
108
+ }
95
109
  }
96
110
 
97
111
  /**
@@ -105,8 +119,10 @@ export class Memory {
105
119
  */
106
120
  toPromptSection({ source } = {}) {
107
121
  const memories = this.load(20, { source });
108
- if (memories.length === 0) return '';
109
- const lines = memories.map(m => `- [${m.type}] ${m.content}`).join('\n');
122
+ if (memories.length === 0) {
123
+ return '';
124
+ }
125
+ const lines = memories.map((m) => `- [${m.type}] ${m.content}`).join('\n');
110
126
  return `\n## 历史记忆\n以下是之前对话中积累的项目偏好和决策,请参考:\n${lines}\n`;
111
127
  }
112
128
 
@@ -125,12 +141,16 @@ export class Memory {
125
141
  #compact() {
126
142
  try {
127
143
  const raw = fs.readFileSync(this.#filePath, 'utf-8').trim();
128
- if (!raw) return;
144
+ if (!raw) {
145
+ return;
146
+ }
129
147
  const lines = raw.split('\n').filter(Boolean);
130
148
  if (lines.length > this.#maxEntries) {
131
- fs.writeFileSync(this.#filePath, lines.slice(-this.#maxEntries).join('\n') + '\n', 'utf-8');
149
+ fs.writeFileSync(this.#filePath, `${lines.slice(-this.#maxEntries).join('\n')}\n`, 'utf-8');
132
150
  }
133
- } catch { /* ignore */ }
151
+ } catch {
152
+ /* ignore */
153
+ }
134
154
  }
135
155
  }
136
156
 
@@ -55,18 +55,14 @@ const PRODUCER_SYSTEM_PROMPT = `你是知识管理专家。你会收到一段代
55
55
  // Producer 可用工具白名单 — 只做格式化和提交
56
56
  // ──────────────────────────────────────────────────────────────────
57
57
 
58
- const PRODUCER_TOOLS = [
59
- 'submit_knowledge',
60
- 'submit_with_check',
61
- 'read_project_file',
62
- ];
58
+ const PRODUCER_TOOLS = ['submit_knowledge', 'submit_with_check', 'read_project_file'];
63
59
 
64
60
  // ──────────────────────────────────────────────────────────────────
65
61
  // Producer 预算 — 格式化任务,迭代更少
66
62
  // ──────────────────────────────────────────────────────────────────
67
63
 
68
64
  const PRODUCER_BUDGET = {
69
- maxIterations: 24, // was 18 — 与 Analyst 统一
65
+ maxIterations: 24, // was 18 — 与 Analyst 统一
70
66
  searchBudget: 4,
71
67
  searchBudgetGrace: 3,
72
68
  maxSubmits: 10,
@@ -111,7 +107,7 @@ submit_knowledge 的 content.markdown 字段必须是「项目特写」。
111
107
  - dontClause: 反向约束英文描述(不以 "Don't" 开头,调用方会加前缀)。如 "use @synchronized for singleton"
112
108
  - whenClause: 触发场景英文。如 "When implementing singleton pattern or global shared instance"
113
109
  - topicHint: 主题分类,取值 networking / ui / data / architecture / conventions
114
- - coreCode: 最典型纯代码片段 3-8 行(不含 Markdown 格式、无 # 标题、无围栏、无 > 引用)
110
+ - coreCode: 最典型纯代码片段 3-8 行(不含 Markdown 格式、无 # 标题、无围栏、无 > 引用;必须语法完整——括号配对、不以 } 或 ) 开头、不以 { 或 ( 结尾)
115
111
 
116
112
  ### 规范
117
113
  1. trigger 以 @ 开头,kebab-case,不得在同一批次重复
@@ -208,7 +204,9 @@ export class ProducerAgent {
208
204
  }
209
205
 
210
206
  const prompt = buildProducerPrompt(analysisReport, dimConfig, projectInfo);
211
- this.#logger.info(`[ProducerAgent] ▶ producing candidates for "${dimId}" — prompt ${prompt.length} chars`);
207
+ this.#logger.info(
208
+ `[ProducerAgent] ▶ producing candidates for "${dimId}" — prompt ${prompt.length} chars`
209
+ );
212
210
 
213
211
  const budget = options.budget
214
212
  ? { ...PRODUCER_BUDGET, ...options.budget }
@@ -233,24 +231,38 @@ export class ProducerAgent {
233
231
 
234
232
  // 统计提交 (区分成功/失败)
235
233
  const submitCalls = (result.toolCalls || []).filter(
236
- tc => (tc.tool || tc.name) === 'submit_knowledge' || (tc.tool || tc.name) === 'submit_with_check'
234
+ (tc) =>
235
+ (tc.tool || tc.name) === 'submit_knowledge' ||
236
+ (tc.tool || tc.name) === 'submit_with_check'
237
237
  );
238
- const successCount = submitCalls.filter(tc => {
238
+ const successCount = submitCalls.filter((tc) => {
239
239
  const res = tc.result;
240
- if (!res) return true; // 无结果信息默认成功
241
- if (typeof res === 'string') return !res.includes('rejected') && !res.includes('error');
240
+ if (!res) {
241
+ return true; // 无结果信息默认成功
242
+ }
243
+ if (typeof res === 'string') {
244
+ return !res.includes('rejected') && !res.includes('error');
245
+ }
242
246
  return res.status !== 'rejected' && res.status !== 'error';
243
247
  }).length;
244
248
  const rejectedCount = submitCalls.length - successCount;
245
249
 
246
250
  // ── 拒绝率过高时追加一轮修正尝试 ──
247
- if (rejectedCount > successCount && rejectedCount >= 2 && options.retryOnRejection !== false) {
248
- this.#logger.info(`[ProducerAgent] 高拒绝率 (${rejectedCount}/${submitCalls.length}) — 尝试修正`);
251
+ if (
252
+ rejectedCount > successCount &&
253
+ rejectedCount >= 2 &&
254
+ options.retryOnRejection !== false
255
+ ) {
256
+ this.#logger.info(
257
+ `[ProducerAgent] 高拒绝率 (${rejectedCount}/${submitCalls.length}) — 尝试修正`
258
+ );
249
259
  try {
250
260
  const retryPrompt = `你的 ${rejectedCount} 个提交被拒绝了。请根据拒绝原因改进后重新提交,确保:\n1. content.markdown 字段 ≥ 200 字符\n2. 包含代码块 (\`\`\`)\n3. 包含来源标注 (来源: FileName.m:行号)\n4. 标题使用项目真实类名\n5. 必填: trigger (@kebab-case)、kind (rule/pattern/fact)、doClause (英文祈使句)`;
251
261
  const retryResult = await this.#chatAgent.execute(retryPrompt, {
252
262
  source: 'system',
253
- conversationId: options.sessionId ? `producer-retry-${options.sessionId}-${dimId}` : undefined,
263
+ conversationId: options.sessionId
264
+ ? `producer-retry-${options.sessionId}-${dimId}`
265
+ : undefined,
254
266
  budget: { ...budget, maxIterations: 5, maxSubmits: rejectedCount },
255
267
  systemPromptOverride: PRODUCER_SYSTEM_PROMPT,
256
268
  allowedTools: PRODUCER_TOOLS,
@@ -265,12 +277,18 @@ export class ProducerAgent {
265
277
  });
266
278
 
267
279
  const retrySubmits = (retryResult.toolCalls || []).filter(
268
- tc => (tc.tool || tc.name) === 'submit_knowledge' || (tc.tool || tc.name) === 'submit_with_check'
280
+ (tc) =>
281
+ (tc.tool || tc.name) === 'submit_knowledge' ||
282
+ (tc.tool || tc.name) === 'submit_with_check'
269
283
  );
270
- const retrySuccess = retrySubmits.filter(tc => {
284
+ const retrySuccess = retrySubmits.filter((tc) => {
271
285
  const res = tc.result;
272
- if (!res) return true;
273
- if (typeof res === 'string') return !res.includes('rejected') && !res.includes('error');
286
+ if (!res) {
287
+ return true;
288
+ }
289
+ if (typeof res === 'string') {
290
+ return !res.includes('rejected') && !res.includes('error');
291
+ }
274
292
  return res.status !== 'rejected' && res.status !== 'error';
275
293
  }).length;
276
294
 
@@ -297,7 +315,9 @@ export class ProducerAgent {
297
315
  }
298
316
  }
299
317
 
300
- this.#logger.info(`[ProducerAgent] ✅ dimension "${dimId}" — ${successCount} candidates created (${rejectedCount} rejected), ${result.toolCalls?.length || 0} total tool calls`);
318
+ this.#logger.info(
319
+ `[ProducerAgent] ✅ dimension "${dimId}" — ${successCount} candidates created (${rejectedCount} rejected), ${result.toolCalls?.length || 0} total tool calls`
320
+ );
301
321
 
302
322
  return {
303
323
  candidateCount: successCount,