autosnippet 3.3.5 → 3.3.7

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 (279) hide show
  1. package/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
  2. package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
  3. package/dashboard/dist/assets/index-DzoB7kxK.css +1 -0
  4. package/dashboard/dist/index.html +3 -3
  5. package/dist/bin/api-server.js +1 -0
  6. package/dist/bin/cli.d.ts +1 -0
  7. package/dist/bin/cli.js +137 -9
  8. package/dist/lib/agent/AgentFactory.d.ts +0 -17
  9. package/dist/lib/agent/AgentFactory.js +1 -25
  10. package/dist/lib/agent/AgentRuntime.d.ts +2 -2
  11. package/dist/lib/agent/AgentRuntime.js +26 -18
  12. package/dist/lib/agent/capabilities.d.ts +11 -0
  13. package/dist/lib/agent/capabilities.js +29 -5
  14. package/dist/lib/agent/context/ExplorationTracker.js +10 -1
  15. package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
  16. package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
  17. package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
  18. package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
  19. package/dist/lib/agent/domain/insight-analyst.js +111 -11
  20. package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
  21. package/dist/lib/agent/domain/insight-evolver.js +230 -0
  22. package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
  23. package/dist/lib/agent/domain/insight-gate.js +41 -0
  24. package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
  25. package/dist/lib/agent/domain/insight-producer.js +60 -5
  26. package/dist/lib/agent/domain/scan-prompts.js +10 -7
  27. package/dist/lib/agent/forced-summary.js +7 -2
  28. package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
  29. package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
  30. package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
  31. package/dist/lib/agent/memory/SessionStore.js +9 -15
  32. package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
  33. package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
  34. package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
  35. package/dist/lib/agent/memory/session-store-schema.js +41 -0
  36. package/dist/lib/agent/presets.d.ts +89 -1
  37. package/dist/lib/agent/presets.js +53 -5
  38. package/dist/lib/agent/tools/_shared.d.ts +7 -15
  39. package/dist/lib/agent/tools/_shared.js +20 -21
  40. package/dist/lib/agent/tools/composite.d.ts +25 -22
  41. package/dist/lib/agent/tools/composite.js +108 -109
  42. package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
  43. package/dist/lib/agent/tools/evolution-tools.js +161 -0
  44. package/dist/lib/agent/tools/index.d.ts +163 -92
  45. package/dist/lib/agent/tools/index.js +9 -1
  46. package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
  47. package/dist/lib/agent/tools/lifecycle.js +59 -75
  48. package/dist/lib/cli/AiScanService.js +5 -5
  49. package/dist/lib/cli/KnowledgeSyncService.js +1 -1
  50. package/dist/lib/core/AstAnalyzer.d.ts +1 -0
  51. package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
  52. package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
  53. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
  54. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
  55. package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
  56. package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
  57. package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
  58. package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
  59. package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
  60. package/dist/lib/core/discovery/index.d.ts +2 -0
  61. package/dist/lib/core/discovery/index.js +4 -0
  62. package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
  63. package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
  64. package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
  65. package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
  66. package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
  67. package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
  68. package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
  69. package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
  70. package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
  71. package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
  72. package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
  73. package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
  74. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
  75. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
  76. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
  77. package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
  78. package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
  79. package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
  80. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
  81. package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
  82. package/dist/lib/domain/dimension/index.d.ts +10 -0
  83. package/dist/lib/domain/dimension/index.js +9 -0
  84. package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
  85. package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
  86. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +40 -112
  87. package/dist/lib/domain/knowledge/KnowledgeEntry.js +44 -9
  88. package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
  89. package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
  90. package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
  91. package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
  92. package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
  93. package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
  94. package/dist/lib/external/ai/AiProvider.d.ts +12 -0
  95. package/dist/lib/external/ai/AiProvider.js +24 -0
  96. package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
  97. package/dist/lib/external/ai/AiProviderManager.js +193 -0
  98. package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
  99. package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
  100. package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
  101. package/dist/lib/external/ai/providers/MockProvider.js +290 -14
  102. package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
  103. package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
  104. package/dist/lib/external/lark/LarkTransport.js +10 -2
  105. package/dist/lib/external/mcp/McpServer.js +4 -0
  106. package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
  107. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
  108. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
  109. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
  110. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
  111. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
  112. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
  113. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
  114. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
  115. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
  116. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
  117. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
  118. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
  119. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
  120. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
  121. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +188 -169
  122. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
  123. package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
  124. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
  125. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
  126. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
  127. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
  128. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
  129. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
  130. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
  131. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
  132. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
  133. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
  134. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
  135. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
  136. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
  137. package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
  138. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
  139. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
  140. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +23 -10
  141. package/dist/lib/external/mcp/handlers/bootstrap-external.js +41 -51
  142. package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
  143. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +117 -82
  144. package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
  145. package/dist/lib/external/mcp/handlers/consolidated.js +108 -332
  146. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +71 -2
  147. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
  148. package/dist/lib/external/mcp/handlers/evolve-external.js +229 -0
  149. package/dist/lib/external/mcp/handlers/knowledge.js +30 -5
  150. package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
  151. package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
  152. package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
  153. package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
  154. package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
  155. package/dist/lib/external/mcp/handlers/search.js +6 -5
  156. package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
  157. package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
  158. package/dist/lib/external/mcp/tools.d.ts +8 -18
  159. package/dist/lib/external/mcp/tools.js +58 -2
  160. package/dist/lib/http/routes/ai.js +111 -30
  161. package/dist/lib/http/routes/candidates.js +11 -4
  162. package/dist/lib/http/routes/commands.js +10 -1
  163. package/dist/lib/http/routes/health.js +11 -0
  164. package/dist/lib/http/routes/knowledge.js +122 -1
  165. package/dist/lib/http/routes/modules.js +52 -3
  166. package/dist/lib/http/routes/panorama.js +16 -4
  167. package/dist/lib/http/routes/recipes.js +7 -0
  168. package/dist/lib/http/utils/routeHelpers.js +2 -1
  169. package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
  170. package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
  171. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
  172. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
  173. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
  174. package/dist/lib/injection/ServiceContainer.d.ts +6 -5
  175. package/dist/lib/injection/ServiceContainer.js +64 -25
  176. package/dist/lib/injection/ServiceMap.d.ts +10 -1
  177. package/dist/lib/injection/modules/AiModule.d.ts +6 -9
  178. package/dist/lib/injection/modules/AiModule.js +82 -39
  179. package/dist/lib/injection/modules/KnowledgeModule.js +15 -1
  180. package/dist/lib/injection/modules/PanoramaModule.js +1 -1
  181. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
  182. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
  183. package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
  184. package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
  185. package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
  186. package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
  187. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +5 -0
  188. package/dist/lib/service/bootstrap/UiStartupTasks.js +20 -0
  189. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
  190. package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
  191. package/dist/lib/service/cleanup/CleanupService.d.ts +132 -0
  192. package/dist/lib/service/cleanup/CleanupService.js +571 -0
  193. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
  194. package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
  195. package/dist/lib/service/delivery/FileProtection.js +54 -0
  196. package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
  197. package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
  198. package/dist/lib/service/evolution/ContentPatcher.js +310 -0
  199. package/dist/lib/service/evolution/ProposalExecutor.d.ts +4 -0
  200. package/dist/lib/service/evolution/ProposalExecutor.js +77 -13
  201. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
  202. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
  203. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
  204. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
  205. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
  206. package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
  207. package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
  208. package/dist/lib/service/guard/ComplianceReporter.js +51 -0
  209. package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
  210. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +6 -0
  211. package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
  212. package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
  213. package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
  214. package/dist/lib/service/knowledge/KnowledgeService.js +67 -14
  215. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
  216. package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
  217. package/dist/lib/service/module/ModuleService.js +10 -19
  218. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
  219. package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
  220. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +4 -3
  221. package/dist/lib/service/panorama/DimensionAnalyzer.js +40 -151
  222. package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
  223. package/dist/lib/service/panorama/LayerInferrer.js +118 -1
  224. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
  225. package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
  226. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
  227. package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
  228. package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
  229. package/dist/lib/service/panorama/PanoramaService.js +10 -5
  230. package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
  231. package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
  232. package/dist/lib/service/panorama/RoleRefiner.js +41 -0
  233. package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
  234. package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
  235. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  236. package/dist/lib/service/search/SearchEngine.d.ts +11 -10
  237. package/dist/lib/service/search/SearchEngine.js +38 -36
  238. package/dist/lib/service/search/SearchTypes.d.ts +14 -8
  239. package/dist/lib/service/search/SearchTypes.js +1 -1
  240. package/dist/lib/service/search/tokenizer.d.ts +1 -1
  241. package/dist/lib/service/search/tokenizer.js +2 -2
  242. package/dist/lib/service/skills/SignalCollector.d.ts +1 -0
  243. package/dist/lib/service/skills/SignalCollector.js +6 -5
  244. package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
  245. package/dist/lib/service/vector/ContextualEnricher.js +4 -0
  246. package/dist/lib/shared/LanguageService.js +3 -0
  247. package/dist/lib/shared/developer-identity.d.ts +18 -0
  248. package/dist/lib/shared/developer-identity.js +62 -0
  249. package/dist/lib/shared/schemas/common.d.ts +4 -4
  250. package/dist/lib/shared/schemas/http-requests.d.ts +20 -18
  251. package/dist/lib/shared/schemas/http-requests.js +17 -6
  252. package/dist/lib/shared/schemas/mcp-tools.d.ts +32 -2
  253. package/dist/lib/shared/schemas/mcp-tools.js +38 -0
  254. package/dist/lib/types/evolution.d.ts +135 -0
  255. package/dist/lib/types/evolution.js +6 -0
  256. package/dist/lib/types/graph-shared.d.ts +25 -0
  257. package/dist/lib/types/graph-shared.js +7 -0
  258. package/dist/lib/types/knowledge-wire.d.ts +132 -0
  259. package/dist/lib/types/knowledge-wire.js +7 -0
  260. package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
  261. package/dist/lib/types/project-snapshot-builder.js +189 -0
  262. package/dist/lib/types/project-snapshot.d.ts +399 -0
  263. package/dist/lib/types/project-snapshot.js +17 -0
  264. package/dist/lib/types/search-wire.d.ts +46 -0
  265. package/dist/lib/types/search-wire.js +7 -0
  266. package/dist/lib/types/snapshot-views.d.ts +58 -0
  267. package/dist/lib/types/snapshot-views.js +103 -0
  268. package/package.json +1 -1
  269. package/skills/autosnippet-recipes/SKILL.md +1 -1
  270. package/templates/instructions/agent-static.md +2 -0
  271. package/templates/instructions/conventions.md +3 -1
  272. package/templates/recipes-setup/README.md +2 -2
  273. package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
  274. package/dashboard/dist/assets/index-B659K9t5.js +0 -128
  275. package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
  276. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
  277. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
  278. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
  279. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +0 -821
@@ -0,0 +1,571 @@
1
+ /**
2
+ * CleanupService — 统一数据清理策略(垃圾桶模式)
3
+ *
4
+ * 提供两种清理模式:
5
+ * - fullReset(): 全量清理 — 将旧数据打包到时间戳垃圾桶文件夹,DB 表清空
6
+ * - rescanClean(): Rescan 清理 — 保留 Recipe,清除衍生缓存
7
+ * - snapshotRecipes(): 快照当前活跃 Recipe 信息
8
+ * - purgeExpiredTrash(): 清除超时限的垃圾桶文件夹
9
+ *
10
+ * 垃圾桶设计:
11
+ * - 位于 .autosnippet/.trash/<ISO-timestamp>/ 下
12
+ * - fullReset 时先将 candidates/ recipes/ skills/ wiki/ 移入垃圾桶,再清 DB
13
+ * - DB 数据导出为 db-snapshot.jsonl 保存在垃圾桶内
14
+ * - 超过保留天数(默认 7 天)的垃圾桶在下次 fullReset 或服务启动时自动清除
15
+ * - 暂不提供恢复功能(需要 merge 处理过于复杂)
16
+ *
17
+ * 保留原则:
18
+ * - 配置数据 (config.json, constitution.yaml, boxspec.json) 永不清理
19
+ * - IDE 集成配置 (.vscode/, .cursor/, .github/) 永不清理
20
+ * - 交付物 (.cursor/rules/autosnippet-*) 由 R4 重建,不在此清理
21
+ *
22
+ * @module service/cleanup/CleanupService
23
+ */
24
+ import fs from 'node:fs';
25
+ import path from 'node:path';
26
+ import { CANDIDATES_DIR } from '#infra/config/Defaults.js';
27
+ import { getContextIndexPath, getProjectKnowledgePath, getProjectRecipesPath, getProjectSkillsPath, } from '#infra/config/Paths.js';
28
+ // ── 常量 ────────────────────────────────────────────────────
29
+ /** 垃圾桶根目录(相对于 .autosnippet/) */
30
+ const TRASH_DIR = '.trash';
31
+ /** 垃圾桶保留天数,超过后自动 purge */
32
+ const TRASH_RETENTION_DAYS = 7;
33
+ /** DB 快照文件名 */
34
+ const DB_SNAPSHOT_FILE = 'db-snapshot.jsonl';
35
+ /**
36
+ * fullReset 时清除的所有 DB 表(不含 schema_migrations)
37
+ *
38
+ * ⚠️ 顺序重要:子表必须排在父表之前,否则 FK 约束会阻止 DELETE。
39
+ * lifecycle_transition_events → knowledge_entries, evolution_proposals
40
+ * evolution_proposals → knowledge_entries
41
+ * recipe_source_refs → knowledge_entries (CASCADE)
42
+ * bootstrap_dim_files → bootstrap_snapshots (CASCADE)
43
+ */
44
+ const ALL_DATA_TABLES = [
45
+ // ── FK 子表先删 ──
46
+ 'lifecycle_transition_events',
47
+ 'recipe_source_refs',
48
+ 'evolution_proposals',
49
+ 'knowledge_edges',
50
+ 'bootstrap_dim_files',
51
+ // ── 父表后删 ──
52
+ 'knowledge_entries',
53
+ 'bootstrap_snapshots',
54
+ // ── 无 FK 依赖 ──
55
+ 'guard_violations',
56
+ 'audit_logs',
57
+ 'sessions',
58
+ 'semantic_memories',
59
+ 'code_entities',
60
+ 'remote_commands',
61
+ 'remote_state',
62
+ ];
63
+ /** rescanClean 时清除的 DB 表(保留知识/进化相关表) */
64
+ const RESCAN_CLEAN_TABLES = [
65
+ 'bootstrap_dim_files', // FK → bootstrap_snapshots, 先删
66
+ 'recipe_source_refs', // FK → knowledge_entries, 先删
67
+ 'bootstrap_snapshots',
68
+ 'code_entities',
69
+ 'guard_violations',
70
+ 'semantic_memories',
71
+ 'sessions',
72
+ 'audit_logs',
73
+ 'remote_commands',
74
+ 'remote_state',
75
+ ];
76
+ // ── CleanupService ──────────────────────────────────────────
77
+ export class CleanupService {
78
+ #projectRoot;
79
+ #logger;
80
+ #db;
81
+ constructor(opts) {
82
+ this.#projectRoot = opts.projectRoot;
83
+ this.#logger = opts.logger || { info() { }, warn() { } };
84
+ this.#db = opts.db
85
+ ? typeof opts.db?.getDb === 'function'
86
+ ? opts.db.getDb()
87
+ : opts.db
88
+ : null;
89
+ }
90
+ /** 更新 DB 引用(fullReset 后重连时调用) */
91
+ setDb(db) {
92
+ this.#db = db
93
+ ? typeof db?.getDb === 'function'
94
+ ? db.getDb()
95
+ : db
96
+ : null;
97
+ }
98
+ // ─── 需求 A:全量清理(垃圾桶模式) ────────────────────
99
+ /**
100
+ * 全量清理 — 用于 bootstrap 冷启动(垃圾桶模式)
101
+ *
102
+ * 流程:
103
+ * 1. 先清除过期垃圾桶(超过 TRASH_RETENTION_DAYS)
104
+ * 2. 创建时间戳垃圾桶文件夹
105
+ * 3. 将 candidates/ recipes/ skills/ wiki/ 移入垃圾桶
106
+ * 4. 导出 DB 关键表数据到 db-snapshot.jsonl
107
+ * 5. 清空 DB 所有数据表
108
+ * 6. 清除向量索引、bootstrap-report、logs 等缓存
109
+ *
110
+ * 保留: config.json、constitution.yaml、boxspec.json、IDE 配置
111
+ */
112
+ async fullReset() {
113
+ const result = {
114
+ deletedFiles: 0,
115
+ clearedTables: [],
116
+ preservedRecipes: 0,
117
+ errors: [],
118
+ };
119
+ this.#logger.info('[CleanupService] Starting fullReset (trash-bin mode)...');
120
+ // 0. 清除过期垃圾桶
121
+ const purged = this.#purgeExpiredTrash();
122
+ if (purged.count > 0) {
123
+ result.purgedTrash = purged;
124
+ this.#logger.info(`[CleanupService] Purged ${purged.count} expired trash folders`);
125
+ }
126
+ // 1. 创建时间戳垃圾桶文件夹
127
+ const trashFolder = this.#createTrashFolder();
128
+ let movedItems = 0;
129
+ let dbSnapshotRows = 0;
130
+ // 2. 将知识目录移入垃圾桶(move 而非 copy,速度快)
131
+ const kbPath = getProjectKnowledgePath(this.#projectRoot);
132
+ const dirsToTrash = [
133
+ { src: path.join(this.#projectRoot, CANDIDATES_DIR), name: 'candidates' },
134
+ { src: getProjectRecipesPath(this.#projectRoot), name: 'recipes' },
135
+ { src: getProjectSkillsPath(this.#projectRoot), name: 'skills' },
136
+ { src: path.join(kbPath, 'wiki'), name: 'wiki' },
137
+ ];
138
+ for (const { src, name } of dirsToTrash) {
139
+ const moved = this.#moveToTrash(src, path.join(trashFolder, name));
140
+ movedItems += moved;
141
+ }
142
+ // 3. 导出 DB 数据到垃圾桶(JSONL 格式,每行一个 {table, row})
143
+ if (this.#db) {
144
+ dbSnapshotRows = this.#exportDbToTrash(trashFolder);
145
+ }
146
+ // 4. 清空 DB 所有数据表
147
+ if (this.#db) {
148
+ for (const table of ALL_DATA_TABLES) {
149
+ try {
150
+ this.#db.exec(`DELETE FROM ${table}`);
151
+ result.clearedTables.push(table);
152
+ }
153
+ catch (err) {
154
+ const msg = err instanceof Error ? err.message : String(err);
155
+ if (!msg.includes('no such table')) {
156
+ result.errors.push(`Failed to clear ${table}: ${msg}`);
157
+ this.#logger.warn(`[CleanupService] DELETE FROM ${table} failed: ${msg}`);
158
+ }
159
+ }
160
+ }
161
+ // tasks 相关表(来自 migration 002,需先删子表)
162
+ for (const table of ['task_events', 'task_dependencies', 'tasks']) {
163
+ try {
164
+ this.#db.exec(`DELETE FROM ${table}`);
165
+ result.clearedTables.push(table);
166
+ }
167
+ catch {
168
+ /* table may not exist */
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ this.#logger.warn('[CleanupService] No database reference — DB tables NOT cleared!');
174
+ result.errors.push('DB reference is null, database tables were not cleared');
175
+ }
176
+ // 5. 重建被移走的空目录(bootstrap 后续步骤需要)
177
+ for (const { src } of dirsToTrash) {
178
+ if (!fs.existsSync(src)) {
179
+ fs.mkdirSync(src, { recursive: true });
180
+ }
181
+ }
182
+ // 6. 清除向量索引
183
+ result.deletedFiles += this.#clearDirectory(getContextIndexPath(this.#projectRoot));
184
+ // 7. 删除 bootstrap-report.json
185
+ result.deletedFiles += this.#deleteFile(path.join(kbPath, '.autosnippet', 'bootstrap-report.json'));
186
+ // 8. 清除 logs/signals/
187
+ result.deletedFiles += this.#clearDirectory(path.join(kbPath, '.autosnippet', 'logs', 'signals'));
188
+ result.deletedFiles += movedItems;
189
+ result.trash = { folder: trashFolder, movedItems, dbSnapshotRows };
190
+ this.#logger.info('[CleanupService] fullReset complete (trash-bin mode)', {
191
+ trashFolder: path.basename(trashFolder),
192
+ movedItems,
193
+ dbSnapshotRows,
194
+ tables: result.clearedTables.length,
195
+ purgedExpired: purged.count,
196
+ errors: result.errors.length,
197
+ });
198
+ return result;
199
+ }
200
+ // ─── 需求 B:Rescan 清理(保留 Recipe) ───────────────
201
+ /**
202
+ * Rescan 清理 — 保留 Recipe,清除衍生缓存
203
+ *
204
+ * 清除: 衍生 DB 表、pending/rejected/deprecated 知识条目、
205
+ * candidates/、skills/、wiki/、向量索引、bootstrap-report
206
+ * 保留: recipes/、active/published/staging/evolving 知识条目、
207
+ * knowledge_edges、evolution_proposals
208
+ */
209
+ async rescanClean() {
210
+ const result = {
211
+ deletedFiles: 0,
212
+ clearedTables: [],
213
+ preservedRecipes: 0,
214
+ errors: [],
215
+ };
216
+ this.#logger.info('[CleanupService] Starting rescanClean...');
217
+ // 1. 清除衍生 DB 表
218
+ if (this.#db) {
219
+ for (const table of RESCAN_CLEAN_TABLES) {
220
+ try {
221
+ this.#db.exec(`DELETE FROM ${table}`);
222
+ result.clearedTables.push(table);
223
+ }
224
+ catch (err) {
225
+ const msg = err instanceof Error ? err.message : String(err);
226
+ if (!msg.includes('no such table')) {
227
+ result.errors.push(`Failed to clear ${table}: ${msg}`);
228
+ }
229
+ }
230
+ }
231
+ // 清除旧候选/废弃条目,保留活跃知识
232
+ try {
233
+ this.#db.exec(`DELETE FROM knowledge_entries WHERE lifecycle IN ('pending', 'rejected', 'deprecated')`);
234
+ result.clearedTables.push('knowledge_entries (pending/rejected/deprecated)');
235
+ }
236
+ catch (err) {
237
+ const msg = err instanceof Error ? err.message : String(err);
238
+ result.errors.push(`Failed to clean old entries: ${msg}`);
239
+ }
240
+ // 也清除 tasks 相关表
241
+ for (const table of ['tasks', 'task_dependencies', 'task_events']) {
242
+ try {
243
+ this.#db.exec(`DELETE FROM ${table}`);
244
+ result.clearedTables.push(table);
245
+ }
246
+ catch {
247
+ /* table may not exist */
248
+ }
249
+ }
250
+ }
251
+ // 2. 清空 candidates/ 目录
252
+ result.deletedFiles += this.#clearDirectory(path.join(this.#projectRoot, CANDIDATES_DIR));
253
+ // 3. 清空 skills/ 目录
254
+ result.deletedFiles += this.#clearDirectory(getProjectSkillsPath(this.#projectRoot));
255
+ // 4. 清空 wiki/ 目录
256
+ result.deletedFiles += this.#clearDirectory(path.join(getProjectKnowledgePath(this.#projectRoot), 'wiki'));
257
+ // 5. 删除向量索引
258
+ result.deletedFiles += this.#clearDirectory(getContextIndexPath(this.#projectRoot));
259
+ // 6. 删除 bootstrap-report.json
260
+ result.deletedFiles += this.#deleteFile(path.join(getProjectKnowledgePath(this.#projectRoot), '.autosnippet', 'bootstrap-report.json'));
261
+ this.#logger.info('[CleanupService] rescanClean complete', {
262
+ tables: result.clearedTables.length,
263
+ files: result.deletedFiles,
264
+ errors: result.errors.length,
265
+ });
266
+ return result;
267
+ }
268
+ // ─── 快照当前 Recipe ──────────────────────────────────
269
+ /**
270
+ * 快照当前活跃 Recipe 信息
271
+ * 用于 rescan 前记录保留的知识条目
272
+ */
273
+ async snapshotRecipes() {
274
+ if (!this.#db) {
275
+ return { count: 0, entries: [], coverageByDimension: {} };
276
+ }
277
+ try {
278
+ const rows = this.#db
279
+ .prepare(`SELECT id, title, trigger, category, knowledgeType, doClause,
280
+ sourceFile, lifecycle, content, json_extract(reasoning, '$.sources') AS sourceRefsJson
281
+ FROM knowledge_entries
282
+ WHERE lifecycle IN ('active', 'staging', 'evolving')`)
283
+ .all();
284
+ const entries = rows.map((r) => {
285
+ let parsedContent;
286
+ try {
287
+ parsedContent = r.content
288
+ ? JSON.parse(r.content)
289
+ : undefined;
290
+ }
291
+ catch {
292
+ parsedContent = undefined;
293
+ }
294
+ let parsedSourceRefs;
295
+ try {
296
+ parsedSourceRefs = r.sourceRefsJson
297
+ ? JSON.parse(r.sourceRefsJson)
298
+ : undefined;
299
+ }
300
+ catch {
301
+ parsedSourceRefs = undefined;
302
+ }
303
+ return {
304
+ id: r.id,
305
+ title: r.title || '',
306
+ trigger: r.trigger || '',
307
+ category: r.category || '',
308
+ knowledgeType: r.knowledgeType || 'code-pattern',
309
+ doClause: r.doClause || '',
310
+ sourceFile: r.sourceFile || undefined,
311
+ lifecycle: r.lifecycle,
312
+ content: parsedContent,
313
+ sourceRefs: parsedSourceRefs,
314
+ };
315
+ });
316
+ // 按维度统计覆盖度 (使用 knowledgeType = 维度 id)
317
+ const coverageByDimension = {};
318
+ for (const entry of entries) {
319
+ const dim = entry.knowledgeType || 'unknown';
320
+ coverageByDimension[dim] = (coverageByDimension[dim] || 0) + 1;
321
+ }
322
+ return {
323
+ count: entries.length,
324
+ entries,
325
+ coverageByDimension,
326
+ };
327
+ }
328
+ catch (err) {
329
+ const msg = err instanceof Error ? err.message : String(err);
330
+ this.#logger.warn(`[CleanupService] snapshotRecipes failed: ${msg}`);
331
+ return { count: 0, entries: [], coverageByDimension: {} };
332
+ }
333
+ }
334
+ // ─── 垃圾桶管理 ───────────────────────────────────────
335
+ /**
336
+ * 清除超过保留期限的垃圾桶文件夹
337
+ * 可在服务启动时或 fullReset 前调用
338
+ */
339
+ purgeExpiredTrash() {
340
+ return this.#purgeExpiredTrash();
341
+ }
342
+ /**
343
+ * 列出当前所有垃圾桶(供 Dashboard 展示)
344
+ */
345
+ listTrashFolders() {
346
+ const trashRoot = this.#getTrashRoot();
347
+ if (!fs.existsSync(trashRoot)) {
348
+ return [];
349
+ }
350
+ const entries = fs.readdirSync(trashRoot).sort().reverse();
351
+ return entries
352
+ .filter((name) => /^\d{4}-\d{2}-\d{2}T/.test(name))
353
+ .map((name) => {
354
+ const fullPath = path.join(trashRoot, name);
355
+ const stat = fs.statSync(fullPath);
356
+ return {
357
+ name,
358
+ createdAt: stat.birthtime,
359
+ sizeMB: Math.round((this.#getDirSize(fullPath) / 1024 / 1024) * 100) / 100,
360
+ };
361
+ });
362
+ }
363
+ // ─── 内部工具方法 ─────────────────────────────────────
364
+ /** 获取垃圾桶根目录 (.autosnippet/.trash/) */
365
+ #getTrashRoot() {
366
+ return path.join(this.#projectRoot, '.autosnippet', TRASH_DIR);
367
+ }
368
+ /** 创建时间戳垃圾桶文件夹,返回绝对路径 */
369
+ #createTrashFolder() {
370
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
371
+ const trashFolder = path.join(this.#getTrashRoot(), ts);
372
+ fs.mkdirSync(trashFolder, { recursive: true });
373
+ return trashFolder;
374
+ }
375
+ /**
376
+ * 将源目录内容移入垃圾桶对应子目录
377
+ * 使用 rename 实现(同文件系统内是原子操作,速度极快)
378
+ * @returns 移动的顶层条目数
379
+ */
380
+ #moveToTrash(srcDir, trashSubDir) {
381
+ if (!fs.existsSync(srcDir)) {
382
+ return 0;
383
+ }
384
+ const entries = fs.readdirSync(srcDir);
385
+ if (entries.length === 0) {
386
+ return 0;
387
+ }
388
+ fs.mkdirSync(trashSubDir, { recursive: true });
389
+ let count = 0;
390
+ for (const entry of entries) {
391
+ const src = path.join(srcDir, entry);
392
+ const dest = path.join(trashSubDir, entry);
393
+ try {
394
+ fs.renameSync(src, dest);
395
+ count++;
396
+ }
397
+ catch {
398
+ // rename 可能跨设备失败,fallback 到 copy+delete
399
+ try {
400
+ fs.cpSync(src, dest, { recursive: true });
401
+ fs.rmSync(src, { recursive: true, force: true });
402
+ count++;
403
+ }
404
+ catch (err) {
405
+ const msg = err instanceof Error ? err.message : String(err);
406
+ this.#logger.warn(`[CleanupService] Failed to move ${entry} to trash: ${msg}`);
407
+ }
408
+ }
409
+ }
410
+ return count;
411
+ }
412
+ /**
413
+ * 导出 DB 关键表数据到垃圾桶(JSONL 格式)
414
+ * 只导出有实际业务数据的表,跳过纯缓存表
415
+ */
416
+ #exportDbToTrash(trashFolder) {
417
+ if (!this.#db) {
418
+ return 0;
419
+ }
420
+ const tablesToExport = [
421
+ 'knowledge_entries',
422
+ 'knowledge_edges',
423
+ 'lifecycle_transition_events',
424
+ 'evolution_proposals',
425
+ 'recipe_source_refs',
426
+ 'guard_violations',
427
+ ];
428
+ const snapshotPath = path.join(trashFolder, DB_SNAPSHOT_FILE);
429
+ let totalRows = 0;
430
+ const lines = [];
431
+ for (const table of tablesToExport) {
432
+ try {
433
+ const rows = this.#db.prepare(`SELECT * FROM ${table}`).all();
434
+ for (const row of rows) {
435
+ lines.push(JSON.stringify({ _table: table, ...row }));
436
+ totalRows++;
437
+ }
438
+ }
439
+ catch {
440
+ // 表可能不存在,跳过
441
+ }
442
+ }
443
+ if (lines.length > 0) {
444
+ fs.writeFileSync(snapshotPath, `${lines.join('\n')}\n`, 'utf-8');
445
+ this.#logger.info(`[CleanupService] DB snapshot: ${totalRows} rows → ${DB_SNAPSHOT_FILE}`);
446
+ }
447
+ return totalRows;
448
+ }
449
+ /** 清除过期垃圾桶文件夹 */
450
+ #purgeExpiredTrash() {
451
+ const trashRoot = this.#getTrashRoot();
452
+ if (!fs.existsSync(trashRoot)) {
453
+ return { count: 0, freedBytes: 0, folders: [] };
454
+ }
455
+ const now = Date.now();
456
+ const maxAge = TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
457
+ const entries = fs.readdirSync(trashRoot);
458
+ let count = 0;
459
+ let freedBytes = 0;
460
+ const folders = [];
461
+ for (const entry of entries) {
462
+ const fullPath = path.join(trashRoot, entry);
463
+ try {
464
+ const stat = fs.statSync(fullPath);
465
+ if (!stat.isDirectory()) {
466
+ continue;
467
+ }
468
+ // 从文件夹名解析时间戳(格式: 2026-04-09T14-30-00-000Z)
469
+ const ts = entry.replace(/-(\d{2})-(\d{2})-(\d{3}Z)$/, ':$1:$2.$3');
470
+ const created = new Date(ts).getTime();
471
+ const age = now - (Number.isNaN(created) ? stat.birthtimeMs : created);
472
+ if (age > maxAge) {
473
+ const size = this.#getDirSize(fullPath);
474
+ fs.rmSync(fullPath, { recursive: true, force: true });
475
+ freedBytes += size;
476
+ count++;
477
+ folders.push(entry);
478
+ this.#logger.info(`[CleanupService] Purged expired trash: ${entry} (${Math.round(size / 1024)}KB)`);
479
+ }
480
+ }
481
+ catch (err) {
482
+ const msg = err instanceof Error ? err.message : String(err);
483
+ this.#logger.warn(`[CleanupService] Failed to purge trash ${entry}: ${msg}`);
484
+ }
485
+ }
486
+ // 如果垃圾桶根目录为空,也删掉
487
+ try {
488
+ const remaining = fs.readdirSync(trashRoot);
489
+ if (remaining.length === 0) {
490
+ fs.rmdirSync(trashRoot);
491
+ }
492
+ }
493
+ catch {
494
+ /* ignore */
495
+ }
496
+ return { count, freedBytes, folders };
497
+ }
498
+ /** 递归计算目录大小 (bytes) */
499
+ #getDirSize(dirPath) {
500
+ let size = 0;
501
+ try {
502
+ const entries = fs.readdirSync(dirPath);
503
+ for (const entry of entries) {
504
+ const fullPath = path.join(dirPath, entry);
505
+ const stat = fs.statSync(fullPath);
506
+ if (stat.isDirectory()) {
507
+ size += this.#getDirSize(fullPath);
508
+ }
509
+ else {
510
+ size += stat.size;
511
+ }
512
+ }
513
+ }
514
+ catch {
515
+ /* ignore */
516
+ }
517
+ return size;
518
+ }
519
+ /**
520
+ * 清空目录内容(保留目录本身)
521
+ * @returns 删除的文件数
522
+ */
523
+ #clearDirectory(dirPath) {
524
+ let count = 0;
525
+ try {
526
+ if (!fs.existsSync(dirPath)) {
527
+ return 0;
528
+ }
529
+ const entries = fs.readdirSync(dirPath);
530
+ for (const entry of entries) {
531
+ const fullPath = path.join(dirPath, entry);
532
+ try {
533
+ const stat = fs.statSync(fullPath);
534
+ if (stat.isDirectory()) {
535
+ fs.rmSync(fullPath, { recursive: true });
536
+ }
537
+ else {
538
+ fs.unlinkSync(fullPath);
539
+ }
540
+ count++;
541
+ }
542
+ catch (err) {
543
+ const msg = err instanceof Error ? err.message : String(err);
544
+ this.#logger.warn(`[CleanupService] Failed to delete ${entry}: ${msg}`);
545
+ }
546
+ }
547
+ }
548
+ catch (err) {
549
+ const msg = err instanceof Error ? err.message : String(err);
550
+ this.#logger.warn(`[CleanupService] clearDirectory failed for ${dirPath}: ${msg}`);
551
+ }
552
+ return count;
553
+ }
554
+ /**
555
+ * 删除单个文件
556
+ * @returns 1 if deleted, 0 otherwise
557
+ */
558
+ #deleteFile(filePath) {
559
+ try {
560
+ if (fs.existsSync(filePath)) {
561
+ fs.unlinkSync(filePath);
562
+ return 1;
563
+ }
564
+ }
565
+ catch (err) {
566
+ const msg = err instanceof Error ? err.message : String(err);
567
+ this.#logger.warn(`[CleanupService] Failed to delete file ${filePath}: ${msg}`);
568
+ }
569
+ return 0;
570
+ }
571
+ }