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
@@ -5,57 +5,82 @@
5
5
 
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
- import { envelope } from '../envelope.js';
9
8
  import * as Paths from '../../../infrastructure/config/Paths.js';
9
+ import { LanguageService } from '../../../shared/LanguageService.js';
10
+ import { envelope } from '../envelope.js';
10
11
 
11
- // ─── SpmService 缓存 ─────────────────────────────────────
12
+ // ─── Discoverer 缓存 ─────────────────────────────────────
12
13
  // 同一 projectRoot 在模块生命期内只初始化一次
13
- let _spmCache = null; // { projectRoot, spm, targets }
14
+ let _discovererCache = null; // { projectRoot, discoverer, targets }
14
15
 
15
- async function _getLoadedSpm() {
16
+ async function _getLoadedDiscoverer() {
16
17
  const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
17
- if (_spmCache && _spmCache.projectRoot === projectRoot) return _spmCache;
18
- const { SpmService } = await import('../../../service/spm/SpmService.js');
19
- const spm = new SpmService(projectRoot);
20
- await spm.load();
21
- const targets = await spm.listTargets() || [];
22
- _spmCache = { projectRoot, spm, targets };
23
- return _spmCache;
18
+ if (_discovererCache && _discovererCache.projectRoot === projectRoot) {
19
+ return _discovererCache;
20
+ }
21
+
22
+ // 优先使用 DiscovererRegistry(多语言统一接口)
23
+ const { getDiscovererRegistry } = await import('../../../core/discovery/index.js');
24
+ const registry = getDiscovererRegistry();
25
+ const discoverer = await registry.detect(projectRoot);
26
+ await discoverer.load(projectRoot);
27
+ const targets = (await discoverer.listTargets()) || [];
28
+ _discovererCache = { projectRoot, discoverer, targets };
29
+ return _discovererCache;
24
30
  }
25
31
 
26
32
  function _findTarget(targets, targetName) {
27
- const t = targets.find(t => t.name === targetName);
28
- if (!t) throw new Error(`Target not found: ${targetName}`);
33
+ const t = targets.find((t) => t.name === targetName);
34
+ if (!t) {
35
+ throw new Error(`Target not found: ${targetName}`);
36
+ }
29
37
  return t;
30
38
  }
31
39
 
32
- /** 推断语言 */
40
+ /** 推断语言 — 委托给 LanguageService */
33
41
  function _inferLang(filename) {
34
- const ext = path.extname(filename).toLowerCase();
35
- const map = {
36
- '.swift': 'swift', '.m': 'objectivec', '.h': 'objectivec', '.mm': 'objectivec',
37
- '.c': 'c', '.cpp': 'cpp', '.js': 'javascript', '.ts': 'typescript',
38
- '.py': 'python', '.rb': 'ruby', '.java': 'java', '.kt': 'kotlin',
39
- '.go': 'go', '.rs': 'rust',
40
- };
41
- return map[ext] || 'unknown';
42
+ return LanguageService.inferLang(filename);
42
43
  }
43
44
 
44
45
  /** 推断 Target 职责 */
45
46
  function _inferTargetRole(targetName) {
46
47
  const n = targetName.toLowerCase();
47
- if (/core|kit|shared|common|foundation|base/i.test(n)) return 'core';
48
- if (/service|manager|provider|repository|store/i.test(n)) return 'service';
49
- if (/ui|view|screen|component|widget/i.test(n)) return 'ui';
50
- if (/network|api|http|grpc|socket/i.test(n)) return 'networking';
51
- if (/storage|database|cache|persist|realm|coredata/i.test(n)) return 'storage';
52
- if (/test|spec|mock|stub|fake/i.test(n)) return 'test';
53
- if (/app|main|launch|entry/i.test(n)) return 'app';
54
- if (/router|coordinator|navigation/i.test(n)) return 'routing';
55
- if (/util|helper|extension|tool/i.test(n)) return 'utility';
56
- if (/model|entity|dto|schema/i.test(n)) return 'model';
57
- if (/auth|login|session|token/i.test(n)) return 'auth';
58
- if (/config|setting|environment|constant/i.test(n)) return 'config';
48
+ if (/core|kit|shared|common|foundation|base/i.test(n)) {
49
+ return 'core';
50
+ }
51
+ if (/service|manager|provider|repository|store/i.test(n)) {
52
+ return 'service';
53
+ }
54
+ if (/ui|view|screen|component|widget/i.test(n)) {
55
+ return 'ui';
56
+ }
57
+ if (/network|api|http|grpc|socket/i.test(n)) {
58
+ return 'networking';
59
+ }
60
+ if (/storage|database|cache|persist|realm|coredata/i.test(n)) {
61
+ return 'storage';
62
+ }
63
+ if (/test|spec|mock|stub|fake/i.test(n)) {
64
+ return 'test';
65
+ }
66
+ if (/app|main|launch|entry/i.test(n)) {
67
+ return 'app';
68
+ }
69
+ if (/router|coordinator|navigation/i.test(n)) {
70
+ return 'routing';
71
+ }
72
+ if (/util|helper|extension|tool/i.test(n)) {
73
+ return 'utility';
74
+ }
75
+ if (/model|entity|dto|schema/i.test(n)) {
76
+ return 'model';
77
+ }
78
+ if (/auth|login|session|token/i.test(n)) {
79
+ return 'auth';
80
+ }
81
+ if (/config|setting|environment|constant/i.test(n)) {
82
+ return 'config';
83
+ }
59
84
  return 'feature';
60
85
  }
61
86
 
@@ -64,7 +89,7 @@ function _inferTargetRole(targetName) {
64
89
  // ═══════════════════════════════════════════════════════════
65
90
 
66
91
  export async function getTargets(ctx, args = {}) {
67
- const { spm, targets } = await _getLoadedSpm();
92
+ const { discoverer, targets } = await _getLoadedDiscoverer();
68
93
  const includeSummary = args.includeSummary !== false; // 默认 true
69
94
 
70
95
  if (!includeSummary) {
@@ -80,14 +105,16 @@ export async function getTargets(ctx, args = {}) {
80
105
  let fileCount = 0;
81
106
  const langStats = {};
82
107
  try {
83
- const fileList = await spm.getTargetFiles(t);
108
+ const fileList = await discoverer.getTargetFiles(t);
84
109
  fileCount = fileList.length;
85
110
  for (const f of fileList) {
86
111
  const lang = _inferLang(f.name);
87
112
  langStats[lang] = (langStats[lang] || 0) + 1;
88
113
  globalLangStats[lang] = (globalLangStats[lang] || 0) + 1;
89
114
  }
90
- } catch { /* skip */ }
115
+ } catch {
116
+ /* skip */
117
+ }
91
118
  totalFiles += fileCount;
92
119
  enriched.push({
93
120
  name: t.name,
@@ -114,12 +141,14 @@ export async function getTargets(ctx, args = {}) {
114
141
  // ═══════════════════════════════════════════════════════════
115
142
 
116
143
  export async function getTargetFiles(ctx, args) {
117
- if (!args.targetName) throw new Error('targetName is required');
118
- const { spm, targets } = await _getLoadedSpm();
144
+ if (!args.targetName) {
145
+ throw new Error('targetName is required');
146
+ }
147
+ const { discoverer, targets } = await _getLoadedDiscoverer();
119
148
  const target = _findTarget(targets, args.targetName);
120
149
 
121
- // 使用 SpmService.getTargetFiles — 正确定位 Sources/<target>/ 目录
122
- const rawFiles = await spm.getTargetFiles(target);
150
+ // 使用 Discoverer.getTargetFiles — 统一接口定位源文件
151
+ const rawFiles = await discoverer.getTargetFiles(target);
123
152
 
124
153
  const includeContent = args.includeContent || false;
125
154
  const contentMaxLines = args.contentMaxLines || 100;
@@ -127,7 +156,9 @@ export async function getTargetFiles(ctx, args) {
127
156
 
128
157
  const files = [];
129
158
  for (const f of rawFiles) {
130
- if (files.length >= maxFiles) break;
159
+ if (files.length >= maxFiles) {
160
+ break;
161
+ }
131
162
  const entry = {
132
163
  name: f.name,
133
164
  path: f.path,
@@ -142,14 +173,20 @@ export async function getTargetFiles(ctx, args) {
142
173
  entry.content = lines.slice(0, contentMaxLines).join('\n');
143
174
  entry.totalLines = lines.length;
144
175
  entry.truncated = lines.length > contentMaxLines;
145
- } catch { entry.content = null; entry.totalLines = 0; entry.truncated = false; }
176
+ } catch {
177
+ entry.content = null;
178
+ entry.totalLines = 0;
179
+ entry.truncated = false;
180
+ }
146
181
  }
147
182
  files.push(entry);
148
183
  }
149
184
 
150
185
  // 文件语言统计
151
186
  const langStats = {};
152
- for (const f of files) { langStats[f.language] = (langStats[f.language] || 0) + 1; }
187
+ for (const f of files) {
188
+ langStats[f.language] = (langStats[f.language] || 0) + 1;
189
+ }
153
190
 
154
191
  return envelope({
155
192
  success: true,
@@ -169,21 +206,27 @@ export async function getTargetFiles(ctx, args) {
169
206
  // ═══════════════════════════════════════════════════════════
170
207
 
171
208
  export async function getTargetMetadata(ctx, args) {
172
- if (!args.targetName) throw new Error('targetName is required');
173
- const { spm, targets, projectRoot } = await _getLoadedSpm();
209
+ if (!args.targetName) {
210
+ throw new Error('targetName is required');
211
+ }
212
+ const { targets } = await _getLoadedDiscoverer();
174
213
  const target = _findTarget(targets, args.targetName);
214
+ const projectRoot = _discovererCache.projectRoot;
175
215
 
176
216
  // ── 基础元数据 ──
177
217
  const meta = {
178
218
  name: target.name,
219
+ path: target.path || null,
179
220
  packageName: target.packageName || null,
180
221
  packagePath: target.packagePath || null,
181
222
  type: target.type || 'target',
223
+ language: target.language || null,
224
+ framework: target.framework || null,
182
225
  inferredRole: _inferTargetRole(target.name),
183
226
  targetDir: target.targetDir || null,
184
227
  sourcesPath: target.info?.path || null,
185
228
  sources: target.info?.sources || null,
186
- dependencies: target.info?.dependencies || [],
229
+ dependencies: target.info?.dependencies || target.metadata?.dependencies || [],
187
230
  };
188
231
 
189
232
  // ── SPM 图谱 (spmmap.json) ──
@@ -199,7 +242,9 @@ export async function getTargetMetadata(ctx, args) {
199
242
  meta.packageTargets = pkg.targets || [];
200
243
  }
201
244
  }
202
- } catch { /* ignore */ }
245
+ } catch {
246
+ /* ignore */
247
+ }
203
248
 
204
249
  // ── 知识图谱关系 (knowledge_edges) ──
205
250
  try {
@@ -207,11 +252,21 @@ export async function getTargetMetadata(ctx, args) {
207
252
  if (graphService) {
208
253
  const edges = graphService.getEdges(target.name, 'module', 'both');
209
254
  meta.graphEdges = {
210
- outgoing: (edges.outgoing || []).map(e => ({ toId: e.toId, toType: e.toType, relation: e.relation })),
211
- incoming: (edges.incoming || []).map(e => ({ fromId: e.fromId, fromType: e.fromType, relation: e.relation })),
255
+ outgoing: (edges.outgoing || []).map((e) => ({
256
+ toId: e.toId,
257
+ toType: e.toType,
258
+ relation: e.relation,
259
+ })),
260
+ incoming: (edges.incoming || []).map((e) => ({
261
+ fromId: e.fromId,
262
+ fromType: e.fromType,
263
+ relation: e.relation,
264
+ })),
212
265
  };
213
266
  }
214
- } catch { /* knowledge_edges may not exist */ }
267
+ } catch {
268
+ /* knowledge_edges may not exist */
269
+ }
215
270
 
216
271
  return envelope({ success: true, data: meta, meta: { tool: 'autosnippet_structure' } });
217
272
  }
@@ -219,7 +274,11 @@ export async function getTargetMetadata(ctx, args) {
219
274
  export async function graphQuery(ctx, args) {
220
275
  const graphService = ctx.container.get('knowledgeGraphService');
221
276
  if (!graphService) {
222
- return envelope({ success: false, message: 'KnowledgeGraphService not available — knowledge_edges 表可能未初始化', meta: { tool: 'autosnippet_graph' } });
277
+ return envelope({
278
+ success: false,
279
+ message: 'KnowledgeGraphService not available — knowledge_edges 表可能未初始化',
280
+ meta: { tool: 'autosnippet_graph' },
281
+ });
223
282
  }
224
283
  const nodeType = args.nodeType || 'recipe';
225
284
  const direction = args.direction || 'both';
@@ -234,7 +293,11 @@ export async function graphQuery(ctx, args) {
234
293
  // knowledge_edges 表不存在时 graceful 降级到 relations 字段
235
294
  if (err.message?.includes('no such table')) {
236
295
  data = await _fallbackRelationsFromRecipe(ctx, args.nodeId, args.relation, direction);
237
- return envelope({ success: true, data, meta: { tool: 'autosnippet_graph', source: 'relations-fallback' } });
296
+ return envelope({
297
+ success: true,
298
+ data,
299
+ meta: { tool: 'autosnippet_graph', source: 'relations-fallback' },
300
+ });
238
301
  }
239
302
  throw err;
240
303
  }
@@ -244,7 +307,11 @@ export async function graphQuery(ctx, args) {
244
307
  export async function graphImpact(ctx, args) {
245
308
  const graphService = ctx.container.get('knowledgeGraphService');
246
309
  if (!graphService) {
247
- return envelope({ success: false, message: 'KnowledgeGraphService not available — knowledge_edges 表可能未初始化', meta: { tool: 'autosnippet_graph' } });
310
+ return envelope({
311
+ success: false,
312
+ message: 'KnowledgeGraphService not available — knowledge_edges 表可能未初始化',
313
+ meta: { tool: 'autosnippet_graph' },
314
+ });
248
315
  }
249
316
  const nodeType = args.nodeType || 'recipe';
250
317
  let impacted;
@@ -254,11 +321,25 @@ export async function graphImpact(ctx, args) {
254
321
  // knowledge_edges 表不存在时 graceful 降级
255
322
  if (err.message?.includes('no such table')) {
256
323
  impacted = await _fallbackImpactFromRecipe(ctx, args.nodeId);
257
- return envelope({ success: true, data: { nodeId: args.nodeId, impactedCount: impacted.length, impacted, degraded: true, degradedReason: 'knowledge_edges 表不存在,仅从 relations 字段反查' }, meta: { tool: 'autosnippet_graph', source: 'relations-fallback' } });
324
+ return envelope({
325
+ success: true,
326
+ data: {
327
+ nodeId: args.nodeId,
328
+ impactedCount: impacted.length,
329
+ impacted,
330
+ degraded: true,
331
+ degradedReason: 'knowledge_edges 表不存在,仅从 relations 字段反查',
332
+ },
333
+ meta: { tool: 'autosnippet_graph', source: 'relations-fallback' },
334
+ });
258
335
  }
259
336
  throw err;
260
337
  }
261
- return envelope({ success: true, data: { nodeId: args.nodeId, impactedCount: impacted.length, impacted }, meta: { tool: 'autosnippet_graph' } });
338
+ return envelope({
339
+ success: true,
340
+ data: { nodeId: args.nodeId, impactedCount: impacted.length, impacted },
341
+ meta: { tool: 'autosnippet_graph' },
342
+ });
262
343
  }
263
344
 
264
345
  /**
@@ -268,15 +349,28 @@ async function _fallbackRelationsFromRecipe(ctx, nodeId, relation, direction) {
268
349
  try {
269
350
  const knowledgeService = ctx.container.get('knowledgeService');
270
351
  const entry = await knowledgeService.get(nodeId);
271
- if (!entry) return { outgoing: [], incoming: [] };
352
+ if (!entry) {
353
+ return { outgoing: [], incoming: [] };
354
+ }
272
355
 
273
- const relJson = typeof entry.relations?.toJSON === 'function' ? entry.relations.toJSON() : (entry.relations || {});
356
+ const relJson =
357
+ typeof entry.relations?.toJSON === 'function'
358
+ ? entry.relations.toJSON()
359
+ : entry.relations || {};
274
360
  const outgoing = [];
275
361
  if (direction === 'both' || direction === 'out') {
276
362
  for (const [relType, targets] of Object.entries(relJson)) {
277
- if (relation && relType !== relation) continue;
278
- for (const t of (Array.isArray(targets) ? targets : [])) {
279
- outgoing.push({ fromId: nodeId, fromType: 'knowledge', toId: t.target || t.id || t, toType: 'knowledge', relation: relType });
363
+ if (relation && relType !== relation) {
364
+ continue;
365
+ }
366
+ for (const t of Array.isArray(targets) ? targets : []) {
367
+ outgoing.push({
368
+ fromId: nodeId,
369
+ fromType: 'knowledge',
370
+ toId: t.target || t.id || t,
371
+ toType: 'knowledge',
372
+ relation: relType,
373
+ });
280
374
  }
281
375
  }
282
376
  }
@@ -285,27 +379,39 @@ async function _fallbackRelationsFromRecipe(ctx, nodeId, relation, direction) {
285
379
  const incoming = [];
286
380
  if (direction === 'both' || direction === 'in') {
287
381
  const knowledgeRepo = ctx.container.get('knowledgeRepository');
288
- const reverseRows = knowledgeRepo.db.prepare(
289
- `SELECT id, relations FROM knowledge_entries WHERE relations LIKE ? AND id != ?`
290
- ).all(`%${nodeId}%`, nodeId);
382
+ const reverseRows = knowledgeRepo.db
383
+ .prepare(`SELECT id, relations FROM knowledge_entries WHERE relations LIKE ? AND id != ?`)
384
+ .all(`%${nodeId}%`, nodeId);
291
385
  for (const row of reverseRows) {
292
386
  try {
293
387
  const rels = JSON.parse(row.relations || '{}');
294
388
  for (const [relType, targets] of Object.entries(rels)) {
295
- if (relation && relType !== relation) continue;
296
- for (const t of (Array.isArray(targets) ? targets : [])) {
389
+ if (relation && relType !== relation) {
390
+ continue;
391
+ }
392
+ for (const t of Array.isArray(targets) ? targets : []) {
297
393
  const targetId = t.target || t.id || t;
298
394
  if (targetId === nodeId) {
299
- incoming.push({ fromId: row.id, fromType: 'knowledge', toId: nodeId, toType: 'knowledge', relation: relType });
395
+ incoming.push({
396
+ fromId: row.id,
397
+ fromType: 'knowledge',
398
+ toId: nodeId,
399
+ toType: 'knowledge',
400
+ relation: relType,
401
+ });
300
402
  }
301
403
  }
302
404
  }
303
- } catch { /* ignore parse error */ }
405
+ } catch {
406
+ /* ignore parse error */
407
+ }
304
408
  }
305
409
  }
306
410
 
307
411
  return { outgoing, incoming };
308
- } catch { return { outgoing: [], incoming: [] }; }
412
+ } catch {
413
+ return { outgoing: [], incoming: [] };
414
+ }
309
415
  }
310
416
 
311
417
  /**
@@ -314,34 +420,52 @@ async function _fallbackRelationsFromRecipe(ctx, nodeId, relation, direction) {
314
420
  async function _fallbackImpactFromRecipe(ctx, nodeId) {
315
421
  try {
316
422
  const knowledgeRepo = ctx.container.get('knowledgeRepository');
317
- const rows = knowledgeRepo.db.prepare(
318
- `SELECT id, title, relations FROM knowledge_entries WHERE relations LIKE ? AND id != ?`
319
- ).all(`%${nodeId}%`, nodeId);
423
+ const rows = knowledgeRepo.db
424
+ .prepare(
425
+ `SELECT id, title, relations FROM knowledge_entries WHERE relations LIKE ? AND id != ?`
426
+ )
427
+ .all(`%${nodeId}%`, nodeId);
320
428
 
321
429
  const impacted = [];
322
430
  for (const row of rows) {
323
431
  try {
324
432
  const rels = JSON.parse(row.relations || '{}');
325
433
  for (const [relType, targets] of Object.entries(rels)) {
326
- for (const t of (Array.isArray(targets) ? targets : [])) {
434
+ for (const t of Array.isArray(targets) ? targets : []) {
327
435
  if ((t.target || t.id || t) === nodeId) {
328
- impacted.push({ id: row.id, title: row.title, type: 'knowledge', relation: relType, depth: 1 });
436
+ impacted.push({
437
+ id: row.id,
438
+ title: row.title,
439
+ type: 'knowledge',
440
+ relation: relType,
441
+ depth: 1,
442
+ });
329
443
  }
330
444
  }
331
445
  }
332
- } catch { /* ignore */ }
446
+ } catch {
447
+ /* ignore */
448
+ }
333
449
  }
334
450
  return impacted;
335
- } catch { return []; }
451
+ } catch {
452
+ return [];
453
+ }
336
454
  }
337
455
 
338
456
  // ─── graph_path — 路径查找 ─────────────────────────────────
339
457
 
340
458
  export async function graphPath(ctx, args) {
341
- if (!args.fromId || !args.toId) throw new Error('fromId and toId are required');
459
+ if (!args.fromId || !args.toId) {
460
+ throw new Error('fromId and toId are required');
461
+ }
342
462
  const graphService = ctx.container.get('knowledgeGraphService');
343
463
  if (!graphService) {
344
- return envelope({ success: false, message: 'KnowledgeGraphService not available', meta: { tool: 'autosnippet_graph' } });
464
+ return envelope({
465
+ success: false,
466
+ message: 'KnowledgeGraphService not available',
467
+ meta: { tool: 'autosnippet_graph' },
468
+ });
345
469
  }
346
470
  const fromType = args.fromType || 'recipe';
347
471
  const toType = args.toType || 'recipe';
@@ -353,7 +477,11 @@ export async function graphPath(ctx, args) {
353
477
  if (err.message?.includes('no such table')) {
354
478
  // 降级:用 relations 字段做单跳查找
355
479
  result = await _fallbackPathFromRecipe(ctx, args.fromId, args.toId);
356
- return envelope({ success: true, data: result, meta: { tool: 'autosnippet_graph', source: 'relations-fallback' } });
480
+ return envelope({
481
+ success: true,
482
+ data: result,
483
+ meta: { tool: 'autosnippet_graph', source: 'relations-fallback' },
484
+ });
357
485
  }
358
486
  throw err;
359
487
  }
@@ -367,23 +495,36 @@ async function _fallbackPathFromRecipe(ctx, fromId, toId) {
367
495
  try {
368
496
  const knowledgeService = ctx.container.get('knowledgeService');
369
497
  const entry = await knowledgeService.get(fromId);
370
- if (!entry) return { found: false, path: [], depth: -1 };
498
+ if (!entry) {
499
+ return { found: false, path: [], depth: -1 };
500
+ }
371
501
 
372
- const relJson = typeof entry.relations?.toJSON === 'function' ? entry.relations.toJSON() : (entry.relations || {});
502
+ const relJson =
503
+ typeof entry.relations?.toJSON === 'function'
504
+ ? entry.relations.toJSON()
505
+ : entry.relations || {};
373
506
  for (const [relType, targets] of Object.entries(relJson)) {
374
- for (const t of (Array.isArray(targets) ? targets : [])) {
507
+ for (const t of Array.isArray(targets) ? targets : []) {
375
508
  const targetId = t.target || t.id || t;
376
509
  if (targetId === toId) {
377
510
  return {
378
511
  found: true,
379
- path: [{ from: { id: fromId, type: 'knowledge' }, to: { id: toId, type: 'knowledge' }, relation: relType }],
512
+ path: [
513
+ {
514
+ from: { id: fromId, type: 'knowledge' },
515
+ to: { id: toId, type: 'knowledge' },
516
+ relation: relType,
517
+ },
518
+ ],
380
519
  depth: 1,
381
520
  };
382
521
  }
383
522
  }
384
523
  }
385
524
  return { found: false, path: [], depth: -1 };
386
- } catch { return { found: false, path: [], depth: -1 }; }
525
+ } catch {
526
+ return { found: false, path: [], depth: -1 };
527
+ }
387
528
  }
388
529
 
389
530
  // ─── graph_stats — 图谱统计 ────────────────────────────────
@@ -391,14 +532,27 @@ async function _fallbackPathFromRecipe(ctx, fromId, toId) {
391
532
  export async function graphStats(ctx) {
392
533
  const graphService = ctx.container.get('knowledgeGraphService');
393
534
  if (!graphService) {
394
- return envelope({ success: false, message: 'KnowledgeGraphService not available', meta: { tool: 'autosnippet_graph' } });
535
+ return envelope({
536
+ success: false,
537
+ message: 'KnowledgeGraphService not available',
538
+ meta: { tool: 'autosnippet_graph' },
539
+ });
395
540
  }
396
541
  let stats;
397
542
  try {
398
543
  stats = graphService.getStats();
399
544
  } catch (err) {
400
545
  if (err.message?.includes('no such table')) {
401
- return envelope({ success: true, data: { totalEdges: 0, byRelation: {}, nodeTypes: [], note: 'knowledge_edges 表不存在,请运行数据库迁移' }, meta: { tool: 'autosnippet_graph' } });
546
+ return envelope({
547
+ success: true,
548
+ data: {
549
+ totalEdges: 0,
550
+ byRelation: {},
551
+ nodeTypes: [],
552
+ note: 'knowledge_edges 表不存在,请运行数据库迁移',
553
+ },
554
+ meta: { tool: 'autosnippet_graph' },
555
+ });
402
556
  }
403
557
  throw err;
404
558
  }
@@ -6,7 +6,7 @@
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
8
  import { envelope } from '../envelope.js';
9
- import { TOOLS, TOOL_GATEWAY_MAP, TIER_ORDER } from '../tools.js';
9
+ import { TIER_ORDER, TOOL_GATEWAY_MAP, TOOLS } from '../tools.js';
10
10
 
11
11
  export async function health(ctx) {
12
12
  const checks = { database: false, gateway: false, vectorStore: false };
@@ -31,24 +31,36 @@ export async function health(ctx) {
31
31
  // 知识库统计(轻量聚合查询)
32
32
  try {
33
33
  // V3: knowledge_entries 统一表(lifecycle 替代 status)
34
- const rStats = db.prepare(`
34
+ const rStats = db
35
+ .prepare(`
35
36
  SELECT COUNT(*) as total,
36
37
  SUM(CASE WHEN lifecycle='active' THEN 1 ELSE 0 END) as active,
37
38
  SUM(CASE WHEN kind='rule' THEN 1 ELSE 0 END) as rules,
38
39
  SUM(CASE WHEN kind='pattern' THEN 1 ELSE 0 END) as patterns,
39
40
  SUM(CASE WHEN kind='fact' THEN 1 ELSE 0 END) as facts
40
41
  FROM knowledge_entries
41
- `).get();
42
- const cPending = db.prepare(`
42
+ `)
43
+ .get();
44
+ const cPending = db
45
+ .prepare(`
43
46
  SELECT COUNT(*) as total,
44
47
  SUM(CASE WHEN lifecycle='pending' THEN 1 ELSE 0 END) as pending
45
48
  FROM knowledge_entries
46
- `).get();
49
+ `)
50
+ .get();
47
51
  knowledgeBase = {
48
- recipes: { total: rStats.total, active: rStats.active, rules: rStats.rules, patterns: rStats.patterns, facts: rStats.facts },
52
+ recipes: {
53
+ total: rStats.total,
54
+ active: rStats.active,
55
+ rules: rStats.rules,
56
+ patterns: rStats.patterns,
57
+ facts: rStats.facts,
58
+ },
49
59
  candidates: { total: cPending.total, pending: cPending.pending },
50
60
  };
51
- } catch { /* 统计查询失败不影响 health */ }
61
+ } catch {
62
+ /* 统计查询失败不影响 health */
63
+ }
52
64
  }
53
65
  } catch (e) {
54
66
  issues.push(`database: ${e.message}`);
@@ -70,7 +82,9 @@ export async function health(ctx) {
70
82
  checks.vectorStore = true;
71
83
  if (vsStats) {
72
84
  knowledgeBase = knowledgeBase || {};
73
- knowledgeBase.vectorIndex = { documentCount: vsStats.documentCount ?? vsStats.totalDocuments ?? 0 };
85
+ knowledgeBase.vectorIndex = {
86
+ documentCount: vsStats.documentCount ?? vsStats.totalDocuments ?? 0,
87
+ };
74
88
  }
75
89
  }
76
90
  } catch (e) {
@@ -135,9 +149,9 @@ export function capabilities() {
135
149
  // 根据当前 tier 决定可见工具
136
150
  const tierName = process.env.ASD_MCP_TIER || 'agent';
137
151
  const maxTier = TIER_ORDER[tierName] ?? TIER_ORDER.agent;
138
- const visibleTools = TOOLS.filter(t => (TIER_ORDER[t.tier || 'agent'] ?? 0) <= maxTier);
152
+ const visibleTools = TOOLS.filter((t) => (TIER_ORDER[t.tier || 'agent'] ?? 0) <= maxTier);
139
153
 
140
- const tools = visibleTools.map(t => {
154
+ const tools = visibleTools.map((t) => {
141
155
  const props = t.inputSchema.properties || {};
142
156
  const requiredSet = new Set(t.inputSchema.required || []);
143
157
  const params = Object.entries(props).map(([key, schema]) => ({
@@ -185,9 +199,25 @@ export function capabilities() {
185
199
  byCategory,
186
200
  tools,
187
201
  workflows: [
188
- { name: '知识查询', steps: ['search(推荐首选,auto mode 融合)', 'knowledge op=get', 'knowledge op=confirm_usage'], tips: '精确匹配用 mode=keyword,需意图+会话上下文用 mode=context' },
202
+ {
203
+ name: '知识查询',
204
+ steps: [
205
+ 'search(推荐首选,auto mode 融合)',
206
+ 'knowledge op=get',
207
+ 'knowledge op=confirm_usage',
208
+ ],
209
+ tips: '精确匹配用 mode=keyword,需意图+会话上下文用 mode=context',
210
+ },
189
211
  { name: '单条知识提交', steps: ['submit_knowledge(内置校验+去重)'] },
190
- { name: '批量 Target 扫描', steps: ['structure op=targets', 'structure op=files', '(Agent 分析)', 'submit_knowledge_batch'] },
212
+ {
213
+ name: '批量 Target 扫描',
214
+ steps: [
215
+ 'structure op=targets',
216
+ 'structure op=files',
217
+ '(Agent 分析)',
218
+ 'submit_knowledge_batch',
219
+ ],
220
+ },
191
221
  { name: '冷启动', steps: ['bootstrap op=knowledge', 'bootstrap op=refine'] },
192
222
  { name: '代码审计', steps: ['guard (code/files)', 'knowledge op=list kind=rule'] },
193
223
  ],