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
@@ -26,8 +26,8 @@
26
26
  * @module ReasoningLayer
27
27
  */
28
28
 
29
- import { ReasoningTrace } from './ReasoningTrace.js';
30
29
  import Logger from '../../infrastructure/logging/Logger.js';
30
+ import { ReasoningTrace } from './ReasoningTrace.js';
31
31
 
32
32
  /** 反思间隔(每 N 轮触发一次) */
33
33
  const DEFAULT_REFLECTION_INTERVAL = 5;
@@ -109,7 +109,9 @@ export class ReasoningLayer {
109
109
  * @returns {string|null} — 反思/规划提示(null = 不触发)
110
110
  */
111
111
  beforeAICall(iteration, { explorationMetrics, budget, phase } = {}) {
112
- if (!this.#config.enabled) return null;
112
+ if (!this.#config.enabled) {
113
+ return null;
114
+ }
113
115
 
114
116
  this.#trace.startRound(iteration);
115
117
 
@@ -133,7 +135,7 @@ export class ReasoningLayer {
133
135
  // ── 合并 replan + reflection ──
134
136
  if (replanNudge && reflectionNudge) {
135
137
  // 两者同时触发 → 合并,避免两条独立 nudge
136
- return replanNudge + '\n\n' + reflectionNudge;
138
+ return `${replanNudge}\n\n${reflectionNudge}`;
137
139
  }
138
140
  return replanNudge || reflectionNudge || null;
139
141
  }
@@ -146,7 +148,9 @@ export class ReasoningLayer {
146
148
  * @param {object} aiResult — AI 返回结果 (native tool calling)
147
149
  */
148
150
  afterAICall(aiResult) {
149
- if (!this.#config.enabled) return;
151
+ if (!this.#config.enabled) {
152
+ return;
153
+ }
150
154
 
151
155
  let extractedText = null;
152
156
 
@@ -154,7 +158,9 @@ export class ReasoningLayer {
154
158
  if (aiResult?.text && aiResult?.functionCalls?.length > 0) {
155
159
  this.#trace.setThought(aiResult.text);
156
160
  extractedText = aiResult.text;
157
- this.#logger.info(`[ReasoningLayer] 💭 thought: ${aiResult.text.substring(0, 150).replace(/\n/g, '↵')}…`);
161
+ this.#logger.info(
162
+ `[ReasoningLayer] 💭 thought: ${aiResult.text.substring(0, 150).replace(/\n/g, '↵')}…`
163
+ );
158
164
  } else if (aiResult?.text) {
159
165
  extractedText = aiResult.text;
160
166
  }
@@ -179,7 +185,7 @@ export class ReasoningLayer {
179
185
  this.#trace.updatePlan(replanText, iteration);
180
186
  const plan = this.#trace.getPlan();
181
187
  // 重置进度追踪
182
- this.#planProgress.coveredSteps = plan.steps.filter(s => s.status === 'done').length;
188
+ this.#planProgress.coveredSteps = plan.steps.filter((s) => s.status === 'done').length;
183
189
  this.#planProgress.totalSteps = plan.steps.length;
184
190
  this.#planProgress.unplannedActions = 0;
185
191
  this.#planProgress.consecutiveOffPlan = 0;
@@ -201,7 +207,9 @@ export class ReasoningLayer {
201
207
  * @param {object} [explorationMetrics] — 探索指标(用于判断是否新信息)
202
208
  */
203
209
  afterToolExec(toolName, args, result, explorationMetrics) {
204
- if (!this.#config.enabled) return;
210
+ if (!this.#config.enabled) {
211
+ return;
212
+ }
205
213
 
206
214
  this.#trace.addAction(toolName, args);
207
215
 
@@ -222,7 +230,9 @@ export class ReasoningLayer {
222
230
  * @param {object} [roundResults.explorationMetrics] — 探索指标
223
231
  */
224
232
  afterRound({ newInfoCount, totalCalls, submitCount, explorationMetrics } = {}) {
225
- if (!this.#config.enabled) return;
233
+ if (!this.#config.enabled) {
234
+ return;
235
+ }
226
236
 
227
237
  this.#trace.setRoundSummary({
228
238
  newInfoCount: newInfoCount || 0,
@@ -269,26 +279,29 @@ export class ReasoningLayer {
269
279
  const hasPlan = plan && plan.steps.length > 0;
270
280
  let planScore = 0;
271
281
  if (hasPlan) {
272
- const completionRate = this.#planProgress.totalSteps > 0
273
- ? this.#planProgress.coveredSteps / this.#planProgress.totalSteps
274
- : 0;
282
+ const completionRate =
283
+ this.#planProgress.totalSteps > 0
284
+ ? this.#planProgress.coveredSteps / this.#planProgress.totalSteps
285
+ : 0;
275
286
  const adherenceRate = 1 - (this.#planProgress.deviationScore || 0);
276
287
  planScore = completionRate * 0.6 + adherenceRate * 0.4;
277
288
  }
278
289
 
279
290
  const score = hasPlan
280
291
  ? Math.round(
281
- (thoughtRatio * 0.30 +
282
- reflectionRatio * 0.15 +
283
- actionEfficiency * 0.15 +
284
- observationCoverage * 0.15 +
285
- planScore * 0.25) * 100
292
+ (thoughtRatio * 0.3 +
293
+ reflectionRatio * 0.15 +
294
+ actionEfficiency * 0.15 +
295
+ observationCoverage * 0.15 +
296
+ planScore * 0.25) *
297
+ 100
286
298
  )
287
299
  : Math.round(
288
300
  (thoughtRatio * 0.4 +
289
- reflectionRatio * 0.2 +
290
- actionEfficiency * 0.2 +
291
- observationCoverage * 0.2) * 100
301
+ reflectionRatio * 0.2 +
302
+ actionEfficiency * 0.2 +
303
+ observationCoverage * 0.2) *
304
+ 100
292
305
  );
293
306
 
294
307
  const breakdown = {
@@ -339,13 +352,18 @@ export class ReasoningLayer {
339
352
 
340
353
  // 触发条件
341
354
  const periodicTrigger = iteration > 1 && interval > 0 && iteration % interval === 0;
342
- const staleTrigger = explorationMetrics?.staleRounds >= staleThreshold
343
- && iteration >= MIN_ITERS_FOR_STALE_REFLECTION;
355
+ const staleTrigger =
356
+ explorationMetrics?.staleRounds >= staleThreshold &&
357
+ iteration >= MIN_ITERS_FOR_STALE_REFLECTION;
344
358
 
345
- if (!periodicTrigger && !staleTrigger) return null;
359
+ if (!periodicTrigger && !staleTrigger) {
360
+ return null;
361
+ }
346
362
 
347
363
  const summary = this.#trace.getRecentSummary(interval || 3);
348
- if (!summary) return null;
364
+ if (!summary) {
365
+ return null;
366
+ }
349
367
 
350
368
  const stats = this.#trace.getStats();
351
369
  const maxIter = budget?.maxIterations || 30;
@@ -356,34 +374,44 @@ export class ReasoningLayer {
356
374
  const parts = [];
357
375
 
358
376
  if (staleTrigger) {
359
- parts.push(`📊 停滞反思 (第 ${iteration}/${maxIter} 轮, 连续 ${explorationMetrics.staleRounds} 轮无新信息):`);
377
+ parts.push(
378
+ `📊 停滞反思 (第 ${iteration}/${maxIter} 轮, 连续 ${explorationMetrics.staleRounds} 轮无新信息):`
379
+ );
360
380
  } else {
361
381
  parts.push(`📊 中期反思 (第 ${iteration}/${maxIter} 轮, ${progressPct}% 预算):`);
362
382
  }
363
383
 
364
384
  // 过去推理回顾
365
385
  if (summary.thoughts.length > 0) {
366
- parts.push(`\n你最近的思考方向:\n${summary.thoughts.map((t, i) => ` ${i + 1}. ${t}`).join('\n')}`);
386
+ parts.push(
387
+ `\n你最近的思考方向:\n${summary.thoughts.map((t, i) => ` ${i + 1}. ${t}`).join('\n')}`
388
+ );
367
389
  }
368
390
 
369
391
  // 行动效率统计
370
- parts.push(`\n行动效率: 最近 ${summary.roundCount} 轮中 ${Math.round(summary.newInfoRatio * 100)}% 获取到新信息`);
392
+ parts.push(
393
+ `\n行动效率: 最近 ${summary.roundCount} 轮中 ${Math.round(summary.newInfoRatio * 100)}% 获取到新信息`
394
+ );
371
395
 
372
396
  // 累计进度
373
- parts.push(`累计: ${explorationMetrics?.uniqueFiles?.size || 0} 文件, ${explorationMetrics?.uniquePatterns?.size || 0} 搜索模式, ${stats.totalActions} 次工具调用`);
397
+ parts.push(
398
+ `累计: ${explorationMetrics?.uniqueFiles?.size || 0} 文件, ${explorationMetrics?.uniquePatterns?.size || 0} 搜索模式, ${stats.totalActions} 次工具调用`
399
+ );
374
400
 
375
401
  // ── Planning 进度附加 ──
376
402
  if (this.#config.planningEnabled) {
377
403
  const plan = this.#trace.getPlan();
378
404
  if (plan && plan.steps.length > 0) {
379
- const doneCount = plan.steps.filter(s => s.status === 'done').length;
405
+ const doneCount = plan.steps.filter((s) => s.status === 'done').length;
380
406
  parts.push(`\n📋 计划进度: ${doneCount}/${plan.steps.length} 步骤已完成`);
381
407
  }
382
408
  }
383
409
 
384
410
  // 阶段化评估问题
385
411
  if (phase === 'EXPLORE' || !phase) {
386
- parts.push(`\n请评估:\n1. 到目前为止最重要的发现是什么?\n2. 还有哪些关键方面未覆盖?\n3. 剩余 ${remaining} 轮,最有价值的下一步是什么?`);
412
+ parts.push(
413
+ `\n请评估:\n1. 到目前为止最重要的发现是什么?\n2. 还有哪些关键方面未覆盖?\n3. 剩余 ${remaining} 轮,最有价值的下一步是什么?`
414
+ );
387
415
  } else if (phase === 'PRODUCE') {
388
416
  parts.push(`\n请评估:\n1. 已提交的候选是否覆盖了核心发现?\n2. 是否有高价值知识点被遗漏?`);
389
417
  }
@@ -393,7 +421,9 @@ export class ReasoningLayer {
393
421
  // 记录到 trace
394
422
  this.#trace.setReflection(reflectionText);
395
423
 
396
- this.#logger.info(`[ReasoningLayer] 💭 reflection triggered at iteration ${iteration} (${staleTrigger ? 'stale' : 'periodic'})`);
424
+ this.#logger.info(
425
+ `[ReasoningLayer] 💭 reflection triggered at iteration ${iteration} (${staleTrigger ? 'stale' : 'periodic'})`
426
+ );
397
427
 
398
428
  return reflectionText;
399
429
  }
@@ -434,18 +464,24 @@ export class ReasoningLayer {
434
464
  if (metrics?.uniqueFiles) {
435
465
  const allFiles = [];
436
466
  for (const m of matches) {
437
- if (m.file) allFiles.push(m.file);
467
+ if (m.file) {
468
+ allFiles.push(m.file);
469
+ }
438
470
  }
439
471
  if (batchResults) {
440
472
  for (const sub of Object.values(batchResults)) {
441
- for (const m of (sub.matches || [])) {
442
- if (m.file) allFiles.push(m.file);
473
+ for (const m of sub.matches || []) {
474
+ if (m.file) {
475
+ allFiles.push(m.file);
476
+ }
443
477
  }
444
478
  }
445
479
  }
446
- const newFiles = allFiles.filter(f => !metrics.uniqueFiles.has(f));
480
+ const newFiles = allFiles.filter((f) => !metrics.uniqueFiles.has(f));
447
481
  meta.gotNewInfo = newFiles.length > 0;
448
- if (newFiles.length > 0) meta.keyFacts.push(`${newFiles.length} new files`);
482
+ if (newFiles.length > 0) {
483
+ meta.keyFacts.push(`${newFiles.length} new files`);
484
+ }
449
485
  } else {
450
486
  meta.gotNewInfo = totalMatches > 0;
451
487
  }
@@ -458,7 +494,7 @@ export class ReasoningLayer {
458
494
  const fps = args?.filePaths || [];
459
495
  const allPaths = fp ? [fp, ...fps] : fps;
460
496
  if (metrics?.uniqueFiles) {
461
- const newPaths = allPaths.filter(p => !metrics.uniqueFiles.has(p));
497
+ const newPaths = allPaths.filter((p) => !metrics.uniqueFiles.has(p));
462
498
  meta.gotNewInfo = newPaths.length > 0;
463
499
  } else {
464
500
  meta.gotNewInfo = allPaths.length > 0;
@@ -471,7 +507,7 @@ export class ReasoningLayer {
471
507
  case 'submit_with_check': {
472
508
  meta.resultType = 'submit';
473
509
  meta.gotNewInfo = true; // submit 本身就是进展
474
- const status = typeof result === 'object' ? (result?.status || 'ok') : 'ok';
510
+ const status = typeof result === 'object' ? result?.status || 'ok' : 'ok';
475
511
  const title = args?.title || '(untitled)';
476
512
  meta.keyFacts.push(`submit "${title}": ${status}`);
477
513
  break;
@@ -582,7 +618,9 @@ export class ReasoningLayer {
582
618
  */
583
619
  #checkReplan(iteration, explorationMetrics, budget, phase) {
584
620
  const plan = this.#trace.getPlan();
585
- if (!plan) return null;
621
+ if (!plan) {
622
+ return null;
623
+ }
586
624
 
587
625
  const progress = this.#planProgress;
588
626
  const interval = this.#config.replanInterval;
@@ -590,12 +628,14 @@ export class ReasoningLayer {
590
628
 
591
629
  // 触发条件
592
630
  const baseIteration = progress.lastReplanIteration || plan.createdAtIteration;
593
- const periodicTrigger = interval > 0 && iteration > 1
594
- && (iteration - baseIteration) >= interval;
595
- const deviationTrigger = progress.consecutiveOffPlan >= 3
596
- || (progress.totalSteps > 0 && progress.deviationScore > deviationThreshold);
631
+ const periodicTrigger = interval > 0 && iteration > 1 && iteration - baseIteration >= interval;
632
+ const deviationTrigger =
633
+ progress.consecutiveOffPlan >= 3 ||
634
+ (progress.totalSteps > 0 && progress.deviationScore > deviationThreshold);
597
635
 
598
- if (!periodicTrigger && !deviationTrigger) return null;
636
+ if (!periodicTrigger && !deviationTrigger) {
637
+ return null;
638
+ }
599
639
 
600
640
  // 构建 replan nudge
601
641
  const maxIter = budget?.maxIterations || 30;
@@ -613,8 +653,8 @@ export class ReasoningLayer {
613
653
  }
614
654
 
615
655
  // 步骤完成情况
616
- const doneSteps = plan.steps.filter(s => s.status === 'done');
617
- const pendingSteps = plan.steps.filter(s => s.status === 'pending');
656
+ const doneSteps = plan.steps.filter((s) => s.status === 'done');
657
+ const pendingSteps = plan.steps.filter((s) => s.status === 'pending');
618
658
 
619
659
  if (doneSteps.length > 0) {
620
660
  parts.push(`\n✅ 已完成 (${doneSteps.length}/${plan.steps.length}):`);
@@ -640,7 +680,9 @@ export class ReasoningLayer {
640
680
  progress.lastReplanIteration = iteration;
641
681
  this.#pendingReplan = true;
642
682
 
643
- this.#logger.info(`[ReasoningLayer] 📋 replan triggered at iteration ${iteration} (${deviationTrigger ? 'deviation' : 'periodic'})`);
683
+ this.#logger.info(
684
+ `[ReasoningLayer] 📋 replan triggered at iteration ${iteration} (${deviationTrigger ? 'deviation' : 'periodic'})`
685
+ );
644
686
 
645
687
  return parts.join('\n');
646
688
  }
@@ -653,10 +695,14 @@ export class ReasoningLayer {
653
695
  */
654
696
  #updatePlanProgress() {
655
697
  const steps = this.#trace.getPlanStepsMutable();
656
- if (steps.length === 0) return;
698
+ if (steps.length === 0) {
699
+ return;
700
+ }
657
701
 
658
702
  const actions = this.#trace.getCurrentRoundActions();
659
- if (actions.length === 0) return;
703
+ if (actions.length === 0) {
704
+ return;
705
+ }
660
706
 
661
707
  let matchedThisRound = false;
662
708
 
@@ -678,11 +724,10 @@ export class ReasoningLayer {
678
724
  }
679
725
 
680
726
  // 重新计算进度
681
- this.#planProgress.coveredSteps = steps.filter(s => s.status === 'done').length;
727
+ this.#planProgress.coveredSteps = steps.filter((s) => s.status === 'done').length;
682
728
  this.#planProgress.totalSteps = steps.length;
683
- this.#planProgress.deviationScore = steps.length > 0
684
- ? 1 - (this.#planProgress.coveredSteps / steps.length)
685
- : 0;
729
+ this.#planProgress.deviationScore =
730
+ steps.length > 0 ? 1 - this.#planProgress.coveredSteps / steps.length : 0;
686
731
  }
687
732
 
688
733
  /**
@@ -702,35 +747,62 @@ export class ReasoningLayer {
702
747
  const argsStr = JSON.stringify(action.params || {}).toLowerCase();
703
748
 
704
749
  for (const step of steps) {
705
- if (step.status === 'done') continue;
750
+ if (step.status === 'done') {
751
+ continue;
752
+ }
706
753
 
707
754
  // 策略 1: 关键词匹配
708
755
  if (step.keywords?.length > 0) {
709
- const matched = step.keywords.some(kw => argsStr.includes(kw.toLowerCase()));
710
- if (matched) return step;
756
+ const matched = step.keywords.some((kw) => argsStr.includes(kw.toLowerCase()));
757
+ if (matched) {
758
+ return step;
759
+ }
711
760
  }
712
761
 
713
762
  // 策略 2: 工具类型 → 步骤描述的语义匹配
714
763
  const desc = step.description.toLowerCase();
715
- if (toolName === 'get_project_overview'
716
- && (desc.includes('概览') || desc.includes('overview') || desc.includes('结构') || desc.includes('项目'))) {
764
+ if (
765
+ toolName === 'get_project_overview' &&
766
+ (desc.includes('概览') ||
767
+ desc.includes('overview') ||
768
+ desc.includes('结构') ||
769
+ desc.includes('项目'))
770
+ ) {
717
771
  return step;
718
772
  }
719
- if (toolName === 'list_project_structure'
720
- && (desc.includes('目录') || desc.includes('结构') || desc.includes('structure'))) {
773
+ if (
774
+ toolName === 'list_project_structure' &&
775
+ (desc.includes('目录') || desc.includes('结构') || desc.includes('structure'))
776
+ ) {
721
777
  return step;
722
778
  }
723
- if ((toolName === 'get_class_info' || toolName === 'get_class_hierarchy')
724
- && (desc.includes('继承') || desc.includes('') || desc.includes('hierarchy') || desc.includes('class'))) {
779
+ if (
780
+ (toolName === 'get_class_info' || toolName === 'get_class_hierarchy') &&
781
+ (desc.includes('继承') ||
782
+ desc.includes('类') ||
783
+ desc.includes('hierarchy') ||
784
+ desc.includes('class'))
785
+ ) {
725
786
  return step;
726
787
  }
727
- if (toolName === 'read_project_file'
728
- && (desc.includes('阅读') || desc.includes('read') || desc.includes('深入') || desc.includes('查看') || desc.includes('文件'))) {
788
+ if (
789
+ toolName === 'read_project_file' &&
790
+ (desc.includes('阅读') ||
791
+ desc.includes('read') ||
792
+ desc.includes('深入') ||
793
+ desc.includes('查看') ||
794
+ desc.includes('文件'))
795
+ ) {
729
796
  return step;
730
797
  }
731
798
  // search_project_code 匹配更宽松:任何含"搜索/查找/search"的待处理步骤
732
- if (toolName === 'search_project_code'
733
- && (desc.includes('搜索') || desc.includes('search') || desc.includes('查找') || desc.includes('分析'))) {
799
+ if (
800
+ toolName === 'search_project_code' &&
801
+ (desc.includes('搜索') ||
802
+ desc.includes('search') ||
803
+ desc.includes('查找') ||
804
+ desc.includes('分析'))
805
+ ) {
734
806
  return step;
735
807
  }
736
808
  }
@@ -750,7 +822,9 @@ export class ReasoningLayer {
750
822
  * @private
751
823
  */
752
824
  #extractPlanFromText(text) {
753
- if (!text || text.length < 30) return null;
825
+ if (!text || text.length < 30) {
826
+ return null;
827
+ }
754
828
 
755
829
  // 在文本的前 2000 字符中搜索计划
756
830
  const searchArea = text.substring(0, 2000);
@@ -774,13 +848,15 @@ export class ReasoningLayer {
774
848
 
775
849
  // 策略 2: 如果没有标记,查找第一个编号列表的起始位置
776
850
  if (planStart === -1) {
777
- const listMatch = searchArea.match(/\n\s*1[\.\)]\s+/);
851
+ const listMatch = searchArea.match(/\n\s*1[.)]\s+/);
778
852
  if (listMatch) {
779
853
  planStart = listMatch.index;
780
854
  }
781
855
  }
782
856
 
783
- if (planStart === -1) return null;
857
+ if (planStart === -1) {
858
+ return null;
859
+ }
784
860
 
785
861
  // 从 planStart 开始提取到列表结束
786
862
  const remaining = searchArea.substring(planStart);
@@ -789,7 +865,7 @@ export class ReasoningLayer {
789
865
  let inList = false;
790
866
 
791
867
  for (const line of lines) {
792
- if (/^\s*(?:\d+[\.\)]\s+|[-*]\s+)/.test(line)) {
868
+ if (/^\s*(?:\d+[.)]\s+|[-*]\s+)/.test(line)) {
793
869
  inList = true;
794
870
  planLines.push(line);
795
871
  } else if (inList && line.trim() === '') {
@@ -801,7 +877,9 @@ export class ReasoningLayer {
801
877
  }
802
878
  }
803
879
 
804
- if (planLines.length < 2) return null;
880
+ if (planLines.length < 2) {
881
+ return null;
882
+ }
805
883
 
806
884
  return planLines.join('\n').trim();
807
885
  }
@@ -57,7 +57,9 @@ export class ReasoningTrace {
57
57
  * @param {number} iteration — 轮次编号
58
58
  */
59
59
  startRound(iteration) {
60
- if (this.#currentRound) this.endRound(); // 安全关闭上一轮
60
+ if (this.#currentRound) {
61
+ this.endRound(); // 安全关闭上一轮
62
+ }
61
63
  this.#currentRound = {
62
64
  iteration,
63
65
  thought: null,
@@ -137,8 +139,8 @@ export class ReasoningTrace {
137
139
  */
138
140
  getThoughts() {
139
141
  return this.#rounds
140
- .filter(r => r.thought)
141
- .map(r => ({ iteration: r.iteration, thought: r.thought }));
142
+ .filter((r) => r.thought)
143
+ .map((r) => ({ iteration: r.iteration, thought: r.thought }));
142
144
  }
143
145
 
144
146
  /**
@@ -148,16 +150,19 @@ export class ReasoningTrace {
148
150
  */
149
151
  getRecentSummary(n = 3) {
150
152
  const recent = this.#rounds.slice(-n);
151
- if (recent.length === 0) return null;
153
+ if (recent.length === 0) {
154
+ return null;
155
+ }
152
156
 
153
157
  const thoughts = recent
154
- .filter(r => r.thought)
155
- .map(r => r.thought.length > 100 ? r.thought.substring(0, 100) + '…' : r.thought);
158
+ .filter((r) => r.thought)
159
+ .map((r) => (r.thought.length > 100 ? `${r.thought.substring(0, 100)}…` : r.thought));
156
160
 
157
- const tools = recent.flatMap(r => r.actions.map(a => a.tool));
161
+ const tools = recent.flatMap((r) => r.actions.map((a) => a.tool));
158
162
 
159
- const newInfoCount = recent.reduce((c, r) =>
160
- c + r.observations.filter(o => o.gotNewInfo).length, 0
163
+ const newInfoCount = recent.reduce(
164
+ (c, r) => c + r.observations.filter((o) => o.gotNewInfo).length,
165
+ 0
161
166
  );
162
167
  const totalObs = recent.reduce((c, r) => c + r.observations.length, 0);
163
168
 
@@ -177,12 +182,13 @@ export class ReasoningTrace {
177
182
  getStats() {
178
183
  return {
179
184
  totalRounds: this.#rounds.length,
180
- thoughtCount: this.#rounds.filter(r => r.thought).length,
185
+ thoughtCount: this.#rounds.filter((r) => r.thought).length,
181
186
  totalActions: this.#rounds.reduce((c, r) => c + r.actions.length, 0),
182
187
  totalObservations: this.#rounds.reduce((c, r) => c + r.observations.length, 0),
183
- reflectionCount: this.#rounds.filter(r => r.reflection).length,
184
- totalDurationMs: this.#rounds.reduce((d, r) =>
185
- d + ((r.endTime || Date.now()) - r.startTime), 0
188
+ reflectionCount: this.#rounds.filter((r) => r.reflection).length,
189
+ totalDurationMs: this.#rounds.reduce(
190
+ (d, r) => d + ((r.endTime || Date.now()) - r.startTime),
191
+ 0
186
192
  ),
187
193
  };
188
194
  }
@@ -213,7 +219,7 @@ export class ReasoningTrace {
213
219
  this.setPlan(replanText, iteration);
214
220
  return;
215
221
  }
216
- this.#planHistory.push({ ...this.#plan, steps: this.#plan.steps.map(s => ({ ...s })) });
222
+ this.#planHistory.push({ ...this.#plan, steps: this.#plan.steps.map((s) => ({ ...s })) });
217
223
  this.#plan.text = replanText;
218
224
  this.#plan.steps = this.#parsePlanSteps(replanText);
219
225
  this.#plan.lastUpdatedAtIteration = iteration;
@@ -224,10 +230,12 @@ export class ReasoningTrace {
224
230
  * @returns {Plan|null}
225
231
  */
226
232
  getPlan() {
227
- if (!this.#plan) return null;
233
+ if (!this.#plan) {
234
+ return null;
235
+ }
228
236
  return {
229
237
  ...this.#plan,
230
- steps: this.#plan.steps.map(s => ({ ...s })),
238
+ steps: this.#plan.steps.map((s) => ({ ...s })),
231
239
  };
232
240
  }
233
241
 
@@ -244,7 +252,7 @@ export class ReasoningTrace {
244
252
  * @returns {Array<Plan>}
245
253
  */
246
254
  getPlanHistory() {
247
- return this.#planHistory.map(p => ({ ...p, steps: p.steps.map(s => ({ ...s })) }));
255
+ return this.#planHistory.map((p) => ({ ...p, steps: p.steps.map((s) => ({ ...s })) }));
248
256
  }
249
257
 
250
258
  /**
@@ -272,12 +280,14 @@ export class ReasoningTrace {
272
280
  * @private
273
281
  */
274
282
  #parsePlanSteps(text) {
275
- if (!text) return [];
283
+ if (!text) {
284
+ return [];
285
+ }
276
286
  const lines = text.split('\n');
277
287
  const steps = [];
278
288
  for (const line of lines) {
279
289
  // 匹配: 1. xxx / - xxx / * xxx / 1) xxx
280
- const m = line.match(/^\s*(?:\d+[\.\)]\s*|[-*]\s+)(.+)/);
290
+ const m = line.match(/^\s*(?:\d+[.)]\s*|[-*]\s+)(.+)/);
281
291
  if (m && m[1].trim().length > 5) {
282
292
  steps.push({
283
293
  description: m[1].trim(),
@@ -297,11 +307,11 @@ export class ReasoningTrace {
297
307
  */
298
308
  #extractKeywords(text) {
299
309
  // 提取反引号/引号内的标识符
300
- const quoted = [...text.matchAll(/[`"']([A-Za-z_]\w{2,})[`"']/g)].map(m => m[1]);
310
+ const quoted = [...text.matchAll(/[`"']([A-Za-z_]\w{2,})[`"']/g)].map((m) => m[1]);
301
311
  // 提取 CamelCase 词
302
- const camelCase = [...text.matchAll(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g)].map(m => m[0]);
312
+ const camelCase = [...text.matchAll(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g)].map((m) => m[0]);
303
313
  // 提取全大写缩写 (如 API, HTTP, URL)
304
- const acronyms = [...text.matchAll(/\b([A-Z]{2,}[a-z]\w+)\b/g)].map(m => m[0]);
314
+ const acronyms = [...text.matchAll(/\b([A-Z]{2,}[a-z]\w+)\b/g)].map((m) => m[0]);
305
315
  return [...new Set([...quoted, ...camelCase, ...acronyms])];
306
316
  }
307
317
 
@@ -311,17 +321,19 @@ export class ReasoningTrace {
311
321
  */
312
322
  toJSON() {
313
323
  return {
314
- rounds: this.#rounds.map(r => ({ ...r })),
324
+ rounds: this.#rounds.map((r) => ({ ...r })),
315
325
  stats: this.getStats(),
316
- ...(this.#plan ? {
317
- plan: {
318
- text: this.#plan.text,
319
- steps: this.#plan.steps.map(s => ({ ...s })),
320
- createdAtIteration: this.#plan.createdAtIteration,
321
- lastUpdatedAtIteration: this.#plan.lastUpdatedAtIteration,
322
- },
323
- planHistory: this.#planHistory.length,
324
- } : {}),
326
+ ...(this.#plan
327
+ ? {
328
+ plan: {
329
+ text: this.#plan.text,
330
+ steps: this.#plan.steps.map((s) => ({ ...s })),
331
+ createdAtIteration: this.#plan.createdAtIteration,
332
+ lastUpdatedAtIteration: this.#plan.lastUpdatedAtIteration,
333
+ },
334
+ planHistory: this.#planHistory.length,
335
+ }
336
+ : {}),
325
337
  };
326
338
  }
327
339
  }