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
@@ -13,13 +13,13 @@
13
13
  * GET /api/v1/wiki/file/:path — 读取某个 Wiki 文件内容
14
14
  */
15
15
 
16
- import express from 'express';
17
16
  import fs from 'node:fs';
18
17
  import path from 'node:path';
19
- import { asyncHandler } from '../middleware/errorHandler.js';
20
- import { getServiceContainer } from '../../injection/ServiceContainer.js';
21
- import { WikiGenerator, WikiPhase } from '../../service/wiki/WikiGenerator.js';
18
+ import express from 'express';
22
19
  import Logger from '../../infrastructure/logging/Logger.js';
20
+ import { getServiceContainer } from '../../injection/ServiceContainer.js';
21
+ import { WikiGenerator } from '../../service/wiki/WikiGenerator.js';
22
+ import { asyncHandler } from '../middleware/errorHandler.js';
23
23
 
24
24
  const router = express.Router();
25
25
  const logger = Logger.getInstance();
@@ -27,7 +27,7 @@ const logger = Logger.getInstance();
27
27
  /* ═══ 进程内 Wiki 任务状态 ═══════════════════════════════ */
28
28
 
29
29
  let wikiTask = {
30
- status: 'idle', // idle | running | done | error
30
+ status: 'idle', // idle | running | done | error
31
31
  phase: null,
32
32
  progress: 0,
33
33
  message: null,
@@ -58,29 +58,44 @@ function resetWikiTask() {
58
58
  * 创建 WikiGenerator 实例
59
59
  */
60
60
  function createGenerator(container) {
61
- const projectRoot = container.singletons?._projectRoot
62
- || process.env.ASD_PROJECT_DIR
63
- || process.cwd();
61
+ const projectRoot =
62
+ container.singletons?._projectRoot || process.env.ASD_PROJECT_DIR || process.cwd();
64
63
 
65
64
  // 尝试获取可用的服务(非必须的优雅降级)
66
- let spmService = null;
65
+ let moduleService = null;
67
66
  let knowledgeService = null;
68
67
  let codeEntityGraph = null;
69
68
 
70
- try { spmService = container.get('spmService'); } catch { /* ok */ }
71
- try { knowledgeService = container.get('knowledgeService'); } catch { /* ok */ }
72
- try { codeEntityGraph = container.get('codeEntityGraph'); } catch { /* ok */ }
69
+ try {
70
+ moduleService = container.get('moduleService');
71
+ } catch {
72
+ /* ok */
73
+ }
74
+ try {
75
+ knowledgeService = container.get('knowledgeService');
76
+ } catch {
77
+ /* ok */
78
+ }
79
+ try {
80
+ codeEntityGraph = container.get('codeEntityGraph');
81
+ } catch {
82
+ /* ok */
83
+ }
73
84
 
74
85
  // 尝试获取已缓存的 ProjectGraph(可能在 bootstrap 中构建过)
75
- let projectGraph = container.singletons?.projectGraph || null;
86
+ const projectGraph = container.singletons?.projectGraph || null;
76
87
 
77
88
  // 获取 RealtimeService 用于推送进度
78
89
  let realtimeService = null;
79
- try { realtimeService = container.singletons?.realtimeService || null; } catch { /* ok */ }
90
+ try {
91
+ realtimeService = container.singletons?.realtimeService || null;
92
+ } catch {
93
+ /* ok */
94
+ }
80
95
 
81
96
  const generator = new WikiGenerator({
82
97
  projectRoot,
83
- spmService,
98
+ moduleService,
84
99
  knowledgeService,
85
100
  projectGraph,
86
101
  codeEntityGraph,
@@ -99,7 +114,9 @@ function createGenerator(container) {
99
114
  message,
100
115
  timestamp: Date.now(),
101
116
  });
102
- } catch { /* non-critical */ }
117
+ } catch {
118
+ /* non-critical */
119
+ }
103
120
  }
104
121
  },
105
122
  options: {
@@ -112,203 +129,227 @@ function createGenerator(container) {
112
129
 
113
130
  /* ═══ POST /api/v1/wiki/generate ═══════════════════════ */
114
131
 
115
- router.post('/generate', asyncHandler(async (req, res) => {
116
- if (wikiTask.status === 'running') {
117
- return res.status(409).json({
118
- success: false,
119
- error: { code: 'ALREADY_RUNNING', message: 'Wiki 生成正在进行中' },
120
- data: { progress: wikiTask.progress, phase: wikiTask.phase },
121
- });
122
- }
132
+ router.post(
133
+ '/generate',
134
+ asyncHandler(async (req, res) => {
135
+ if (wikiTask.status === 'running') {
136
+ return res.status(409).json({
137
+ success: false,
138
+ error: { code: 'ALREADY_RUNNING', message: 'Wiki 生成正在进行中' },
139
+ data: { progress: wikiTask.progress, phase: wikiTask.phase },
140
+ });
141
+ }
123
142
 
124
- const container = getServiceContainer();
125
- resetWikiTask();
143
+ const container = getServiceContainer();
144
+ resetWikiTask();
126
145
 
127
- wikiTask.status = 'running';
128
- wikiTask.startedAt = Date.now();
146
+ wikiTask.status = 'running';
147
+ wikiTask.startedAt = Date.now();
129
148
 
130
- const generator = createGenerator(container);
131
- currentGenerator = generator;
149
+ const generator = createGenerator(container);
150
+ currentGenerator = generator;
132
151
 
133
- // 异步执行,立即返回 202
134
- res.status(202).json({
135
- success: true,
136
- message: 'Wiki 生成已启动,通过 /api/v1/wiki/status 或 Socket.io wiki:progress 事件追踪进度',
137
- });
152
+ // 异步执行,立即返回 202
153
+ res.status(202).json({
154
+ success: true,
155
+ message: 'Wiki 生成已启动,通过 /api/v1/wiki/status 或 Socket.io wiki:progress 事件追踪进度',
156
+ });
138
157
 
139
- // 后台执行生成
140
- try {
141
- const result = await generator.generate();
142
- wikiTask.status = result.success ? 'done' : 'error';
143
- wikiTask.finishedAt = Date.now();
144
- wikiTask.result = result;
145
- if (!result.success) wikiTask.error = result.error;
146
-
147
- // 推送完成事件
148
- const realtimeService = container.singletons?.realtimeService || null;
149
- if (realtimeService) {
150
- realtimeService.broadcastEvent('wiki:completed', {
151
- success: result.success,
152
- filesGenerated: result.filesGenerated,
153
- duration: result.duration,
154
- });
158
+ // 后台执行生成
159
+ try {
160
+ const result = await generator.generate();
161
+ wikiTask.status = result.success ? 'done' : 'error';
162
+ wikiTask.finishedAt = Date.now();
163
+ wikiTask.result = result;
164
+ if (!result.success) {
165
+ wikiTask.error = result.error;
166
+ }
167
+
168
+ // 推送完成事件
169
+ const realtimeService = container.singletons?.realtimeService || null;
170
+ if (realtimeService) {
171
+ realtimeService.broadcastEvent('wiki:completed', {
172
+ success: result.success,
173
+ filesGenerated: result.filesGenerated,
174
+ duration: result.duration,
175
+ });
176
+ }
177
+ } catch (err) {
178
+ wikiTask.status = 'error';
179
+ wikiTask.finishedAt = Date.now();
180
+ wikiTask.error = err.message;
181
+ logger.error('[Wiki Route] Generation failed', { error: err.message });
155
182
  }
156
- } catch (err) {
157
- wikiTask.status = 'error';
158
- wikiTask.finishedAt = Date.now();
159
- wikiTask.error = err.message;
160
- logger.error('[Wiki Route] Generation failed', { error: err.message });
161
- }
162
183
 
163
- currentGenerator = null;
164
- }));
184
+ currentGenerator = null;
185
+ })
186
+ );
165
187
 
166
188
  /* ═══ POST /api/v1/wiki/update ═══════════════════════ */
167
189
 
168
- router.post('/update', asyncHandler(async (req, res) => {
169
- if (wikiTask.status === 'running') {
170
- return res.status(409).json({
171
- success: false,
172
- error: { code: 'ALREADY_RUNNING', message: 'Wiki 生成正在进行中' },
173
- });
174
- }
190
+ router.post(
191
+ '/update',
192
+ asyncHandler(async (req, res) => {
193
+ if (wikiTask.status === 'running') {
194
+ return res.status(409).json({
195
+ success: false,
196
+ error: { code: 'ALREADY_RUNNING', message: 'Wiki 生成正在进行中' },
197
+ });
198
+ }
175
199
 
176
- const container = getServiceContainer();
177
- resetWikiTask();
200
+ const container = getServiceContainer();
201
+ resetWikiTask();
178
202
 
179
- wikiTask.status = 'running';
180
- wikiTask.startedAt = Date.now();
203
+ wikiTask.status = 'running';
204
+ wikiTask.startedAt = Date.now();
181
205
 
182
- const generator = createGenerator(container);
183
- currentGenerator = generator;
206
+ const generator = createGenerator(container);
207
+ currentGenerator = generator;
184
208
 
185
- res.status(202).json({
186
- success: true,
187
- message: 'Wiki 增量更新已启动',
188
- });
209
+ res.status(202).json({
210
+ success: true,
211
+ message: 'Wiki 增量更新已启动',
212
+ });
189
213
 
190
- try {
191
- const result = await generator.update();
192
- wikiTask.status = result.success ? 'done' : 'error';
193
- wikiTask.finishedAt = Date.now();
194
- wikiTask.result = result;
195
- if (!result.success) wikiTask.error = result.error;
196
- } catch (err) {
197
- wikiTask.status = 'error';
198
- wikiTask.finishedAt = Date.now();
199
- wikiTask.error = err.message;
200
- }
214
+ try {
215
+ const result = await generator.update();
216
+ wikiTask.status = result.success ? 'done' : 'error';
217
+ wikiTask.finishedAt = Date.now();
218
+ wikiTask.result = result;
219
+ if (!result.success) {
220
+ wikiTask.error = result.error;
221
+ }
222
+ } catch (err) {
223
+ wikiTask.status = 'error';
224
+ wikiTask.finishedAt = Date.now();
225
+ wikiTask.error = err.message;
226
+ }
201
227
 
202
- currentGenerator = null;
203
- }));
228
+ currentGenerator = null;
229
+ })
230
+ );
204
231
 
205
232
  /* ═══ POST /api/v1/wiki/abort ═══════════════════════ */
206
233
 
207
- router.post('/abort', asyncHandler(async (req, res) => {
208
- if (wikiTask.status !== 'running' || !currentGenerator) {
209
- return res.json({ success: true, message: '没有正在运行的 Wiki 任务' });
210
- }
234
+ router.post(
235
+ '/abort',
236
+ asyncHandler(async (req, res) => {
237
+ if (wikiTask.status !== 'running' || !currentGenerator) {
238
+ return res.json({ success: true, message: '没有正在运行的 Wiki 任务' });
239
+ }
211
240
 
212
- currentGenerator.abort();
213
- wikiTask.status = 'error';
214
- wikiTask.error = 'Aborted by user';
215
- wikiTask.finishedAt = Date.now();
241
+ currentGenerator.abort();
242
+ wikiTask.status = 'error';
243
+ wikiTask.error = 'Aborted by user';
244
+ wikiTask.finishedAt = Date.now();
216
245
 
217
- res.json({ success: true, message: 'Wiki 生成已中止' });
218
- }));
246
+ res.json({ success: true, message: 'Wiki 生成已中止' });
247
+ })
248
+ );
219
249
 
220
250
  /* ═══ GET /api/v1/wiki/status ═══════════════════════ */
221
251
 
222
- router.get('/status', asyncHandler(async (req, res) => {
223
- const container = getServiceContainer();
252
+ router.get(
253
+ '/status',
254
+ asyncHandler(async (req, res) => {
255
+ const container = getServiceContainer();
256
+
257
+ // 如果没有活跃任务,从磁盘读取元数据
258
+ if (wikiTask.status === 'idle') {
259
+ const generator = createGenerator(container);
260
+ const diskStatus = generator.getStatus();
261
+ return res.json({
262
+ success: true,
263
+ data: {
264
+ task: wikiTask,
265
+ wiki: diskStatus,
266
+ },
267
+ });
268
+ }
224
269
 
225
- // 如果没有活跃任务,从磁盘读取元数据
226
- if (wikiTask.status === 'idle') {
227
- const generator = createGenerator(container);
228
- const diskStatus = generator.getStatus();
229
- return res.json({
270
+ res.json({
230
271
  success: true,
231
272
  data: {
232
- task: wikiTask,
233
- wiki: diskStatus,
273
+ task: { ...wikiTask },
234
274
  },
235
275
  });
236
- }
237
-
238
- res.json({
239
- success: true,
240
- data: {
241
- task: { ...wikiTask },
242
- },
243
- });
244
- }));
276
+ })
277
+ );
245
278
 
246
279
  /* ═══ GET /api/v1/wiki/files ═══════════════════════ */
247
280
 
248
- router.get('/files', asyncHandler(async (req, res) => {
249
- const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
250
- const wikiDir = path.join(projectRoot, 'AutoSnippet', 'wiki');
281
+ router.get(
282
+ '/files',
283
+ asyncHandler(async (req, res) => {
284
+ const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
285
+ const wikiDir = path.join(projectRoot, 'AutoSnippet', 'wiki');
251
286
 
252
- if (!fs.existsSync(wikiDir)) {
253
- return res.json({ success: true, data: { files: [], exists: false } });
254
- }
287
+ if (!fs.existsSync(wikiDir)) {
288
+ return res.json({ success: true, data: { files: [], exists: false } });
289
+ }
255
290
 
256
- const files = [];
257
- const readDir = (dir, prefix = '') => {
258
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
259
- const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
260
- if (entry.isDirectory()) {
261
- readDir(path.join(dir, entry.name), rel);
262
- } else if (entry.name.endsWith('.md')) {
263
- const stat = fs.statSync(path.join(dir, entry.name));
264
- files.push({
265
- path: rel,
266
- name: entry.name,
267
- size: stat.size,
268
- modifiedAt: stat.mtime.toISOString(),
269
- });
291
+ const files = [];
292
+ const readDir = (dir, prefix = '') => {
293
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
294
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
295
+ if (entry.isDirectory()) {
296
+ readDir(path.join(dir, entry.name), rel);
297
+ } else if (entry.name.endsWith('.md')) {
298
+ const stat = fs.statSync(path.join(dir, entry.name));
299
+ files.push({
300
+ path: rel,
301
+ name: entry.name,
302
+ size: stat.size,
303
+ modifiedAt: stat.mtime.toISOString(),
304
+ });
305
+ }
270
306
  }
271
- }
272
- };
307
+ };
273
308
 
274
- readDir(wikiDir);
309
+ readDir(wikiDir);
275
310
 
276
- res.json({
277
- success: true,
278
- data: { files, exists: true, wikiDir },
279
- });
280
- }));
311
+ res.json({
312
+ success: true,
313
+ data: { files, exists: true, wikiDir },
314
+ });
315
+ })
316
+ );
281
317
 
282
318
  /* ═══ GET /api/v1/wiki/file/:path(*) ═══════════════ */
283
319
 
284
- router.get('/file/*', asyncHandler(async (req, res) => {
285
- const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
286
- const wikiDir = path.join(projectRoot, 'AutoSnippet', 'wiki');
287
- const requestedPath = req.params[0];
320
+ router.get(
321
+ '/file/*',
322
+ asyncHandler(async (req, res) => {
323
+ const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
324
+ const wikiDir = path.join(projectRoot, 'AutoSnippet', 'wiki');
325
+ const requestedPath = req.params[0];
288
326
 
289
- if (!requestedPath) {
290
- return res.status(400).json({ success: false, error: { message: 'path required' } });
291
- }
327
+ if (!requestedPath) {
328
+ return res.status(400).json({ success: false, error: { message: 'path required' } });
329
+ }
292
330
 
293
- // 安全检查:防止路径穿越
294
- const fullPath = path.resolve(wikiDir, requestedPath);
295
- if (!fullPath.startsWith(wikiDir)) {
296
- return res.status(403).json({ success: false, error: { message: 'Path traversal not allowed' } });
297
- }
331
+ // 安全检查:防止路径穿越
332
+ const fullPath = path.resolve(wikiDir, requestedPath);
333
+ if (!fullPath.startsWith(wikiDir)) {
334
+ return res
335
+ .status(403)
336
+ .json({ success: false, error: { message: 'Path traversal not allowed' } });
337
+ }
298
338
 
299
- if (!fs.existsSync(fullPath)) {
300
- return res.status(404).json({ success: false, error: { message: 'File not found' } });
301
- }
339
+ if (!fs.existsSync(fullPath)) {
340
+ return res.status(404).json({ success: false, error: { message: 'File not found' } });
341
+ }
302
342
 
303
- const content = fs.readFileSync(fullPath, 'utf-8');
304
- res.json({
305
- success: true,
306
- data: {
307
- path: requestedPath,
308
- content,
309
- size: Buffer.byteLength(content),
310
- },
311
- });
312
- }));
343
+ const content = fs.readFileSync(fullPath, 'utf-8');
344
+ res.json({
345
+ success: true,
346
+ data: {
347
+ path: requestedPath,
348
+ content,
349
+ size: Buffer.byteLength(content),
350
+ },
351
+ });
352
+ })
353
+ );
313
354
 
314
355
  export default router;
@@ -26,6 +26,8 @@ export function getContext(req) {
26
26
  */
27
27
  export function safeInt(value, defaultValue, min = 1, max = 1000) {
28
28
  const parsed = parseInt(value, 10);
29
- if (Number.isNaN(parsed)) return defaultValue;
29
+ if (Number.isNaN(parsed)) {
30
+ return defaultValue;
31
+ }
30
32
  return Math.max(min, Math.min(max, parsed));
31
33
  }
@@ -13,7 +13,7 @@
13
13
  * @module lib/http/utils/sse-sessions
14
14
  */
15
15
 
16
- import { EventEmitter } from 'events';
16
+ import { EventEmitter } from 'node:events';
17
17
 
18
18
  /** @type {Map<string, StreamSession>} */
19
19
  const _sessions = new Map();
@@ -59,14 +59,18 @@ export function createStreamSession(scene) {
59
59
  * @param {object} [donePayload={}]
60
60
  */
61
61
  end(donePayload = {}) {
62
- if (session.completed) return;
62
+ if (session.completed) {
63
+ return;
64
+ }
63
65
  const payload = { type: 'stream:done', ts: Date.now(), ...donePayload };
64
66
  session.buffer.push(payload);
65
67
  emitter.emit('event', payload);
66
68
  session.completed = true;
67
69
  // 完成后保留一段时间供客户端重连
68
70
  const keepTimer = setTimeout(() => _sessions.delete(sessionId), COMPLETED_KEEP);
69
- if (keepTimer.unref) keepTimer.unref();
71
+ if (keepTimer.unref) {
72
+ keepTimer.unref();
73
+ }
70
74
  },
71
75
 
72
76
  /**
@@ -75,13 +79,17 @@ export function createStreamSession(scene) {
75
79
  * @param {string} [code]
76
80
  */
77
81
  error(message, code) {
78
- if (session.completed) return;
82
+ if (session.completed) {
83
+ return;
84
+ }
79
85
  const payload = { type: 'stream:error', ts: Date.now(), message, code };
80
86
  session.buffer.push(payload);
81
87
  emitter.emit('event', payload);
82
88
  session.completed = true;
83
89
  const keepTimer = setTimeout(() => _sessions.delete(sessionId), COMPLETED_KEEP);
84
- if (keepTimer.unref) keepTimer.unref();
90
+ if (keepTimer.unref) {
91
+ keepTimer.unref();
92
+ }
85
93
  },
86
94
 
87
95
  /**
@@ -99,7 +107,9 @@ export function createStreamSession(scene) {
99
107
 
100
108
  // 硬性 TTL: 无论是否完成,5 分钟后强制清理
101
109
  const ttlTimer = setTimeout(() => _sessions.delete(sessionId), SESSION_TTL);
102
- if (ttlTimer.unref) ttlTimer.unref();
110
+ if (ttlTimer.unref) {
111
+ ttlTimer.unref();
112
+ }
103
113
 
104
114
  return session;
105
115
  }
@@ -42,7 +42,9 @@ export function createSSESession(req, res, scene) {
42
42
 
43
43
  /** 安全写入一段 SSE 数据 */
44
44
  function _write(data) {
45
- if (disconnected || res.writableEnded) return false;
45
+ if (disconnected || res.writableEnded) {
46
+ return false;
47
+ }
46
48
  try {
47
49
  return res.write(data);
48
50
  } catch {
@@ -74,7 +76,9 @@ export function createSSESession(req, res, scene) {
74
76
  * @param {object} event — 必须包含 type 字段
75
77
  */
76
78
  send(event) {
77
- if (disconnected || res.writableEnded) return;
79
+ if (disconnected || res.writableEnded) {
80
+ return;
81
+ }
78
82
  const payload = JSON.stringify({ ...event, ts: event.ts || Date.now() });
79
83
  _write(`data: ${payload}\n\n`);
80
84
  metrics.eventCount++;
@@ -90,7 +94,9 @@ export function createSSESession(req, res, scene) {
90
94
  */
91
95
  end(donePayload = {}) {
92
96
  clearInterval(heartbeat);
93
- if (disconnected || res.writableEnded) return;
97
+ if (disconnected || res.writableEnded) {
98
+ return;
99
+ }
94
100
  const payload = JSON.stringify({ type: 'stream:done', ts: Date.now(), ...donePayload });
95
101
  _write(`data: ${payload}\n\n`);
96
102
  res.end();
@@ -103,14 +109,18 @@ export function createSSESession(req, res, scene) {
103
109
  */
104
110
  error(message, code) {
105
111
  clearInterval(heartbeat);
106
- if (disconnected || res.writableEnded) return;
112
+ if (disconnected || res.writableEnded) {
113
+ return;
114
+ }
107
115
  const payload = JSON.stringify({ type: 'stream:error', ts: Date.now(), message, code });
108
116
  _write(`data: ${payload}\n\n`);
109
117
  res.end();
110
118
  },
111
119
 
112
120
  /** 是否已断开 */
113
- get isDisconnected() { return disconnected; },
121
+ get isDisconnected() {
122
+ return disconnected;
123
+ },
114
124
 
115
125
  /** 会话 ID */
116
126
  sessionId,
@@ -17,8 +17,11 @@ export class AuditLogger {
17
17
  */
18
18
  async log(entry) {
19
19
  // 兼容 Service 层传入 resourceType + resourceId(而非 resource)
20
- const resource = entry.resource
21
- || (entry.resourceType && entry.resourceId ? `${entry.resourceType}:${entry.resourceId}` : undefined);
20
+ const resource =
21
+ entry.resource ||
22
+ (entry.resourceType && entry.resourceId
23
+ ? `${entry.resourceType}:${entry.resourceId}`
24
+ : undefined);
22
25
 
23
26
  // 兼容 Service 层传入 details(而非 data)
24
27
  const data = entry.data || (entry.details ? { details: entry.details } : {});
@@ -144,11 +144,15 @@ export class AuditStore {
144
144
 
145
145
  // 成功/失败统计
146
146
  const successCount = this.db
147
- .prepare("SELECT COUNT(*) as count FROM audit_logs WHERE timestamp >= ? AND result = 'success'")
147
+ .prepare(
148
+ "SELECT COUNT(*) as count FROM audit_logs WHERE timestamp >= ? AND result = 'success'"
149
+ )
148
150
  .get(startTime);
149
151
 
150
152
  const failureCount = this.db
151
- .prepare("SELECT COUNT(*) as count FROM audit_logs WHERE timestamp >= ? AND result = 'failure'")
153
+ .prepare(
154
+ "SELECT COUNT(*) as count FROM audit_logs WHERE timestamp >= ? AND result = 'failure'"
155
+ )
152
156
  .get(startTime);
153
157
 
154
158
  // 按角色统计
@@ -187,8 +191,9 @@ export class AuditStore {
187
191
  total: total.count,
188
192
  success: successCount.count,
189
193
  failure: failureCount.count,
190
- successRate: total.count > 0 ? (successCount.count / total.count * 100).toFixed(2) + '%' : '0%',
191
- avgDuration: avgDuration.avg_duration ? Math.round(avgDuration.avg_duration) + 'ms' : 'N/A',
194
+ successRate:
195
+ total.count > 0 ? `${((successCount.count / total.count) * 100).toFixed(2)}%` : '0%',
196
+ avgDuration: avgDuration.avg_duration ? `${Math.round(avgDuration.avg_duration)}ms` : 'N/A',
192
197
  byActor,
193
198
  byAction,
194
199
  };
@@ -203,9 +208,7 @@ export class AuditStore {
203
208
  cleanup({ maxAgeDays = 90 } = {}) {
204
209
  try {
205
210
  const cutoff = Date.now() - maxAgeDays * 86400000;
206
- const result = this.db.prepare(
207
- 'DELETE FROM audit_logs WHERE timestamp < ?'
208
- ).run(cutoff);
211
+ const result = this.db.prepare('DELETE FROM audit_logs WHERE timestamp < ?').run(cutoff);
209
212
  return { deleted: result.changes || 0 };
210
213
  } catch {
211
214
  return { deleted: 0 };
@@ -19,7 +19,9 @@ export class CacheService {
19
19
  this.cleanupInterval = setInterval(() => {
20
20
  this.cleanupExpired();
21
21
  }, 60000);
22
- if (this.cleanupInterval.unref) this.cleanupInterval.unref();
22
+ if (this.cleanupInterval.unref) {
23
+ this.cleanupInterval.unref();
24
+ }
23
25
  }
24
26
 
25
27
  /**