autosnippet 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/README.md +230 -324
  2. package/bin/api-server.js +1 -1
  3. package/bin/cli.js +204 -244
  4. package/bin/mcp-server.js +5 -3
  5. package/config/knowledge-base.config.js +132 -132
  6. package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
  7. package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
  8. package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
  9. package/dashboard/dist/index.html +3 -3
  10. package/lib/bootstrap.js +8 -8
  11. package/lib/cli/AiScanService.js +86 -40
  12. package/lib/cli/KnowledgeSyncService.js +113 -74
  13. package/lib/cli/SetupService.js +439 -277
  14. package/lib/cli/UpgradeService.js +63 -100
  15. package/lib/core/AstAnalyzer.js +276 -597
  16. package/lib/core/ast/ProjectGraph.js +101 -40
  17. package/lib/core/ast/ensure-grammars.js +232 -0
  18. package/lib/core/ast/index.js +115 -0
  19. package/lib/core/ast/lang-dart.js +661 -0
  20. package/lib/core/ast/lang-go.js +530 -0
  21. package/lib/core/ast/lang-java.js +435 -0
  22. package/lib/core/ast/lang-javascript.js +272 -0
  23. package/lib/core/ast/lang-kotlin.js +423 -0
  24. package/lib/core/ast/lang-objc.js +388 -0
  25. package/lib/core/ast/lang-python.js +371 -0
  26. package/lib/core/ast/lang-swift.js +337 -0
  27. package/lib/core/ast/lang-typescript.js +503 -0
  28. package/lib/core/capability/CapabilityProbe.js +18 -9
  29. package/lib/core/constitution/Constitution.js +2 -3
  30. package/lib/core/constitution/ConstitutionValidator.js +65 -24
  31. package/lib/core/discovery/DartDiscoverer.js +534 -0
  32. package/lib/core/discovery/DiscovererRegistry.js +83 -0
  33. package/lib/core/discovery/GenericDiscoverer.js +225 -0
  34. package/lib/core/discovery/GoDiscoverer.js +541 -0
  35. package/lib/core/discovery/JvmDiscoverer.js +506 -0
  36. package/lib/core/discovery/NodeDiscoverer.js +466 -0
  37. package/lib/core/discovery/ProjectDiscoverer.js +93 -0
  38. package/lib/core/discovery/PythonDiscoverer.js +338 -0
  39. package/lib/core/discovery/SpmDiscoverer.js +5 -0
  40. package/lib/core/discovery/index.js +53 -0
  41. package/lib/core/enhancement/EnhancementPack.js +71 -0
  42. package/lib/core/enhancement/EnhancementRegistry.js +47 -0
  43. package/lib/core/enhancement/android-enhancement.js +102 -0
  44. package/lib/core/enhancement/django-enhancement.js +70 -0
  45. package/lib/core/enhancement/fastapi-enhancement.js +63 -0
  46. package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
  47. package/lib/core/enhancement/go-web-enhancement.js +201 -0
  48. package/lib/core/enhancement/index.js +65 -0
  49. package/lib/core/enhancement/node-server-enhancement.js +88 -0
  50. package/lib/core/enhancement/react-enhancement.js +86 -0
  51. package/lib/core/enhancement/spring-enhancement.js +112 -0
  52. package/lib/core/enhancement/vue-enhancement.js +96 -0
  53. package/lib/core/gateway/Gateway.js +8 -9
  54. package/lib/core/gateway/GatewayActionRegistry.js +1 -1
  55. package/lib/core/permission/PermissionManager.js +12 -8
  56. package/lib/domain/index.js +13 -9
  57. package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
  58. package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
  59. package/lib/domain/knowledge/Lifecycle.js +22 -22
  60. package/lib/domain/knowledge/index.js +9 -12
  61. package/lib/domain/knowledge/values/Constraints.js +31 -21
  62. package/lib/domain/knowledge/values/Content.js +21 -13
  63. package/lib/domain/knowledge/values/Quality.js +31 -18
  64. package/lib/domain/knowledge/values/Reasoning.js +20 -12
  65. package/lib/domain/knowledge/values/Relations.js +37 -25
  66. package/lib/domain/knowledge/values/Stats.js +18 -12
  67. package/lib/domain/knowledge/values/index.js +4 -3
  68. package/lib/domain/snippet/Snippet.js +35 -10
  69. package/lib/external/ai/AiFactory.js +48 -16
  70. package/lib/external/ai/AiProvider.js +184 -90
  71. package/lib/external/ai/providers/ClaudeProvider.js +25 -12
  72. package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
  73. package/lib/external/ai/providers/MockProvider.js +9 -3
  74. package/lib/external/ai/providers/OpenAiProvider.js +51 -29
  75. package/lib/external/mcp/McpServer.js +66 -36
  76. package/lib/external/mcp/errorHandler.js +23 -11
  77. package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
  78. package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
  79. package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
  80. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
  81. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
  82. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
  83. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
  84. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
  85. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
  86. package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
  87. package/lib/external/mcp/handlers/bootstrap.js +691 -168
  88. package/lib/external/mcp/handlers/browse.js +66 -22
  89. package/lib/external/mcp/handlers/candidate.js +118 -35
  90. package/lib/external/mcp/handlers/consolidated.js +49 -17
  91. package/lib/external/mcp/handlers/guard.js +104 -39
  92. package/lib/external/mcp/handlers/knowledge.js +60 -36
  93. package/lib/external/mcp/handlers/search.js +43 -14
  94. package/lib/external/mcp/handlers/skill.js +120 -45
  95. package/lib/external/mcp/handlers/structure.js +240 -86
  96. package/lib/external/mcp/handlers/system.js +42 -12
  97. package/lib/external/mcp/handlers/wiki.js +58 -33
  98. package/lib/external/mcp/tools.js +306 -123
  99. package/lib/http/HttpServer.js +72 -47
  100. package/lib/http/middleware/RateLimiter.js +5 -3
  101. package/lib/http/middleware/errorHandler.js +6 -1
  102. package/lib/http/middleware/requestLogger.js +14 -3
  103. package/lib/http/middleware/roleResolver.js +30 -23
  104. package/lib/http/routes/ai.js +387 -265
  105. package/lib/http/routes/auth.js +81 -61
  106. package/lib/http/routes/candidates.js +430 -320
  107. package/lib/http/routes/commands.js +289 -189
  108. package/lib/http/routes/extract.js +158 -125
  109. package/lib/http/routes/guardRules.js +309 -217
  110. package/lib/http/routes/knowledge.js +213 -154
  111. package/lib/http/routes/modules.js +578 -0
  112. package/lib/http/routes/monitoring.js +6 -6
  113. package/lib/http/routes/recipes.js +104 -93
  114. package/lib/http/routes/search.js +361 -305
  115. package/lib/http/routes/skills.js +145 -98
  116. package/lib/http/routes/snippets.js +42 -30
  117. package/lib/http/routes/spm.js +3 -405
  118. package/lib/http/routes/violations.js +113 -93
  119. package/lib/http/routes/wiki.js +211 -170
  120. package/lib/http/utils/routeHelpers.js +3 -1
  121. package/lib/http/utils/sse-sessions.js +16 -6
  122. package/lib/http/utils/sse.js +15 -5
  123. package/lib/infrastructure/audit/AuditLogger.js +5 -2
  124. package/lib/infrastructure/audit/AuditStore.js +10 -7
  125. package/lib/infrastructure/cache/CacheService.js +3 -1
  126. package/lib/infrastructure/cache/GraphCache.js +8 -4
  127. package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
  128. package/lib/infrastructure/config/ConfigLoader.js +9 -5
  129. package/lib/infrastructure/config/Defaults.js +30 -10
  130. package/lib/infrastructure/config/Paths.js +28 -8
  131. package/lib/infrastructure/config/TriggerSymbol.js +22 -10
  132. package/lib/infrastructure/database/DatabaseConnection.js +15 -10
  133. package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
  134. package/lib/infrastructure/external/ClipboardManager.js +6 -2
  135. package/lib/infrastructure/external/NativeUi.js +50 -43
  136. package/lib/infrastructure/external/OpenBrowser.js +14 -17
  137. package/lib/infrastructure/external/XcodeAutomation.js +14 -258
  138. package/lib/infrastructure/logging/Logger.js +46 -30
  139. package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
  140. package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
  141. package/lib/infrastructure/paths/HeaderResolver.js +25 -9
  142. package/lib/infrastructure/paths/PathFinder.js +34 -12
  143. package/lib/infrastructure/plugin/PluginManager.js +26 -8
  144. package/lib/infrastructure/realtime/RealtimeService.js +2 -2
  145. package/lib/infrastructure/vector/Chunker.js +22 -7
  146. package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
  147. package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
  148. package/lib/infrastructure/vector/VectorStore.js +28 -10
  149. package/lib/injection/ServiceContainer.js +247 -93
  150. package/lib/platform/ios/index.js +63 -0
  151. package/lib/platform/ios/routes/spm.js +437 -0
  152. package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
  153. package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
  154. package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
  155. package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
  156. package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
  157. package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
  158. package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
  159. package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
  160. package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
  161. package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
  162. package/lib/repository/base/BaseRepository.js +7 -9
  163. package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
  164. package/lib/repository/token/TokenUsageStore.js +4 -2
  165. package/lib/service/automation/ActionPipeline.js +1 -1
  166. package/lib/service/automation/AutomationOrchestrator.js +8 -4
  167. package/lib/service/automation/ContextCollector.js +7 -5
  168. package/lib/service/automation/DirectiveDetector.js +23 -16
  169. package/lib/service/automation/FileWatcher.js +112 -56
  170. package/lib/service/automation/TriggerResolver.js +6 -4
  171. package/lib/service/automation/handlers/AlinkHandler.js +24 -12
  172. package/lib/service/automation/handlers/CreateHandler.js +19 -20
  173. package/lib/service/automation/handlers/DraftHandler.js +14 -8
  174. package/lib/service/automation/handlers/GuardHandler.js +93 -63
  175. package/lib/service/automation/handlers/HeaderHandler.js +1 -6
  176. package/lib/service/automation/handlers/SearchHandler.js +155 -88
  177. package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
  178. package/lib/service/candidate/SimilarityService.js +25 -9
  179. package/lib/service/chat/AnalystAgent.js +50 -24
  180. package/lib/service/chat/CandidateGuardrail.js +143 -17
  181. package/lib/service/chat/ChatAgent.js +655 -260
  182. package/lib/service/chat/ContextWindow.js +116 -71
  183. package/lib/service/chat/ConversationStore.js +77 -36
  184. package/lib/service/chat/EpisodicConsolidator.js +47 -23
  185. package/lib/service/chat/HandoffProtocol.js +98 -22
  186. package/lib/service/chat/Memory.js +34 -14
  187. package/lib/service/chat/ProducerAgent.js +40 -20
  188. package/lib/service/chat/ProjectSemanticMemory.js +109 -78
  189. package/lib/service/chat/ReasoningLayer.js +148 -70
  190. package/lib/service/chat/ReasoningTrace.js +44 -32
  191. package/lib/service/chat/TaskPipeline.js +39 -19
  192. package/lib/service/chat/ToolRegistry.js +48 -29
  193. package/lib/service/chat/WorkingMemory.js +44 -18
  194. package/lib/service/chat/tools.js +1096 -494
  195. package/lib/service/context/RecipeExtractor.js +132 -51
  196. package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
  197. package/lib/service/cursor/KnowledgeCompressor.js +25 -22
  198. package/lib/service/cursor/RulesGenerator.js +13 -7
  199. package/lib/service/cursor/SkillsSyncer.js +77 -27
  200. package/lib/service/cursor/TokenBudget.js +2 -2
  201. package/lib/service/cursor/TopicClassifier.js +54 -20
  202. package/lib/service/guard/ComplianceReporter.js +55 -43
  203. package/lib/service/guard/ExclusionManager.js +67 -29
  204. package/lib/service/guard/GuardCheckEngine.js +381 -86
  205. package/lib/service/guard/GuardFeedbackLoop.js +22 -10
  206. package/lib/service/guard/GuardService.js +29 -19
  207. package/lib/service/guard/RuleLearner.js +55 -23
  208. package/lib/service/guard/SourceFileCollector.js +27 -20
  209. package/lib/service/guard/ViolationsStore.js +43 -38
  210. package/lib/service/knowledge/CodeEntityGraph.js +147 -82
  211. package/lib/service/knowledge/ConfidenceRouter.js +12 -10
  212. package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
  213. package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
  214. package/lib/service/knowledge/KnowledgeService.js +222 -112
  215. package/lib/service/module/ModuleService.js +969 -0
  216. package/lib/service/quality/FeedbackCollector.js +27 -15
  217. package/lib/service/quality/QualityScorer.js +78 -24
  218. package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
  219. package/lib/service/recipe/RecipeParser.js +78 -45
  220. package/lib/service/search/CoarseRanker.js +43 -28
  221. package/lib/service/search/CrossEncoderReranker.js +32 -21
  222. package/lib/service/search/InvertedIndex.js +21 -7
  223. package/lib/service/search/MultiSignalRanker.js +90 -28
  224. package/lib/service/search/RetrievalFunnel.js +45 -24
  225. package/lib/service/search/SearchEngine.js +255 -103
  226. package/lib/service/skills/EventAggregator.js +32 -15
  227. package/lib/service/skills/SignalCollector.js +140 -64
  228. package/lib/service/skills/SkillAdvisor.js +79 -42
  229. package/lib/service/skills/SkillHooks.js +16 -14
  230. package/lib/service/snippet/PlaceholderConverter.js +5 -0
  231. package/lib/service/snippet/SnippetFactory.js +116 -99
  232. package/lib/service/snippet/SnippetInstaller.js +234 -62
  233. package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
  234. package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
  235. package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
  236. package/lib/service/wiki/WikiGenerator.js +637 -263
  237. package/lib/shared/DimensionCopyRegistry.js +472 -0
  238. package/lib/shared/LanguageService.js +399 -0
  239. package/lib/shared/PathGuard.js +45 -28
  240. package/lib/shared/RecipeReadinessChecker.js +72 -12
  241. package/lib/shared/constants.js +41 -41
  242. package/lib/shared/errors/BaseError.js +2 -2
  243. package/lib/shared/errors/index.js +4 -4
  244. package/lib/shared/similarity.js +25 -8
  245. package/lib/shared/token-utils.js +6 -2
  246. package/lib/shared/utils/common.js +12 -4
  247. package/package.json +49 -13
  248. package/scripts/bench-real-projects.mjs +256 -0
  249. package/scripts/build-native-ui.js +30 -30
  250. package/scripts/clear-old-vector-index.js +5 -35
  251. package/scripts/clear-vector-cache.js +7 -37
  252. package/scripts/collect-test-project-stats.mjs +160 -0
  253. package/scripts/diagnose-mcp.js +41 -32
  254. package/scripts/ensure-parse-package.js +6 -9
  255. package/scripts/generate-recipe-drafts.js +116 -77
  256. package/scripts/init-db.js +3 -20
  257. package/scripts/init-snippets.js +305 -0
  258. package/scripts/init-vector-db.js +173 -170
  259. package/scripts/install-cursor-skill.js +148 -104
  260. package/scripts/install-full.js +8 -21
  261. package/scripts/install-vscode-copilot.js +146 -145
  262. package/scripts/migrate-md-to-knowledge.mjs +139 -151
  263. package/scripts/postinstall-safe.js +5 -17
  264. package/scripts/recipe-audit.js +106 -82
  265. package/scripts/release.js +283 -323
  266. package/scripts/setup-mcp-config.js +60 -52
  267. package/scripts/verify-context-api.js +20 -20
  268. package/skills/autosnippet-analysis/SKILL.md +10 -6
  269. package/skills/autosnippet-candidates/SKILL.md +27 -26
  270. package/skills/autosnippet-coldstart/SKILL.md +555 -38
  271. package/skills/autosnippet-concepts/SKILL.md +349 -337
  272. package/skills/autosnippet-create/SKILL.md +5 -5
  273. package/skills/autosnippet-reference-dart/SKILL.md +543 -0
  274. package/skills/autosnippet-reference-go/SKILL.md +539 -0
  275. package/skills/autosnippet-reference-java/SKILL.md +534 -0
  276. package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
  277. package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
  278. package/skills/autosnippet-reference-objc/SKILL.md +29 -6
  279. package/skills/autosnippet-reference-python/SKILL.md +800 -0
  280. package/skills/autosnippet-reference-swift/SKILL.md +70 -14
  281. package/skills/autosnippet-structure/SKILL.md +4 -4
  282. package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
  283. package/templates/recipes-setup/README.md +2 -2
  284. package/templates/recipes-setup/_template.md +1 -1
  285. package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
  286. package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
  287. package/resources/asd-entry/main.swift +0 -159
  288. package/scripts/build-asd-entry.js +0 -51
  289. package/scripts/init-xcode-snippets.js +0 -311
  290. package/template.json +0 -39
@@ -5,22 +5,27 @@ import { v4 as uuidv4 } from 'uuid';
5
5
  *
6
6
  * 与 Recipe 的区别:
7
7
  * - Recipe: 抽象的知识模式 / 最佳实践
8
- * - Snippet: 具体的、可安装的代码片段(如 Xcode Snippet
8
+ * - Snippet: 具体的、可安装的代码片段(支持多 IDE: Xcode / VSCode / Cursor
9
9
  */
10
10
  export class Snippet {
11
11
  constructor(props) {
12
12
  this.id = props.id || uuidv4();
13
- this.identifier = props.identifier; // 唯一标识符(如 swift_guard_let
13
+ this.identifier = props.identifier; // 唯一标识符(如 com.autosnippet.guard-let
14
14
  this.title = props.title;
15
- this.language = props.language || 'swift';
15
+ this.language = props.language || 'unknown';
16
16
  this.category = props.category;
17
- this.completion = props.completion; // 自动补全触发词
17
+ this.completion = props.completion; // 自动补全触发词
18
18
  this.summary = props.summary || '';
19
- this.code = Array.isArray(props.code) ? props.code.join('\n') : (props.code || '');
19
+ this.code = Array.isArray(props.code) ? props.code.join('\n') : props.code || '';
20
20
 
21
- // Xcode integration
22
- this.installed = !!props.installed;
23
- this.installedPath = props.installedPath || null;
21
+ // IDE 安装状态
22
+ // targets = { xcode: { installed, path }, vscode: { installed, path } }
23
+ this.targets = props.targets || {};
24
+
25
+ // 向后兼容: 旧数据的 installed/installedPath 迁移到 targets.xcode
26
+ if (props.installed && !this.targets.xcode) {
27
+ this.targets.xcode = { installed: true, path: props.installedPath || null };
28
+ }
24
29
 
25
30
  // Source tracking
26
31
  this.sourceRecipeId = props.sourceRecipeId || null;
@@ -33,6 +38,25 @@ export class Snippet {
33
38
  this.updatedAt = props.updatedAt || Math.floor(Date.now() / 1000);
34
39
  }
35
40
 
41
+ /**
42
+ * 是否已安装到指定 IDE (不传则检查任意)
43
+ * @param {string} [target] — 'xcode' | 'vscode'
44
+ */
45
+ isInstalled(target) {
46
+ if (target) {
47
+ return !!this.targets[target]?.installed;
48
+ }
49
+ return Object.values(this.targets).some((t) => t?.installed);
50
+ }
51
+
52
+ /**
53
+ * 获取指定 IDE 的安装路径
54
+ * @param {string} target
55
+ */
56
+ getInstalledPath(target) {
57
+ return this.targets[target]?.path || null;
58
+ }
59
+
36
60
  /**
37
61
  * 验证 Snippet 完整性
38
62
  */
@@ -60,8 +84,9 @@ export class Snippet {
60
84
  completion: this.completion,
61
85
  summary: this.summary,
62
86
  code: this.code,
63
- installed: this.installed,
64
- installedPath: this.installedPath,
87
+ targets: this.targets,
88
+ // 向后兼容: 保留 installed 字段 (任意 IDE 已安装即为 true)
89
+ installed: this.isInstalled(),
65
90
  sourceRecipeId: this.sourceRecipeId,
66
91
  sourceCandidateId: this.sourceCandidateId,
67
92
  metadata: this.metadata,
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * AiFactory - AI 提供商工厂
3
- *
3
+ *
4
4
  * 根据配置/环境变量创建对应的 AI Provider 实例
5
5
  * 支持: google-gemini, openai, deepseek, claude, ollama, mock
6
6
  */
7
7
 
8
- import { GoogleGeminiProvider } from './providers/GoogleGeminiProvider.js';
9
- import { OpenAiProvider } from './providers/OpenAiProvider.js';
8
+ import Logger from '../../infrastructure/logging/Logger.js';
10
9
  import { ClaudeProvider } from './providers/ClaudeProvider.js';
10
+ import { GoogleGeminiProvider } from './providers/GoogleGeminiProvider.js';
11
11
  import { MockProvider } from './providers/MockProvider.js';
12
- import Logger from '../../infrastructure/logging/Logger.js';
12
+ import { OpenAiProvider } from './providers/OpenAiProvider.js';
13
13
 
14
14
  const PROVIDER_MAP = {
15
15
  google: GoogleGeminiProvider,
@@ -35,7 +35,9 @@ export function createProvider(options = {}) {
35
35
  const ProviderClass = PROVIDER_MAP[provider.toLowerCase()];
36
36
 
37
37
  if (!ProviderClass) {
38
- throw new Error(`Unknown AI provider: ${provider}. Supported: ${Object.keys(PROVIDER_MAP).join(', ')}`);
38
+ throw new Error(
39
+ `Unknown AI provider: ${provider}. Supported: ${Object.keys(PROVIDER_MAP).join(', ')}`
40
+ );
39
41
  }
40
42
 
41
43
  const config = { ...options };
@@ -69,9 +71,29 @@ export function autoDetectProvider() {
69
71
  const logger = Logger.getInstance();
70
72
  const explicit = process.env.ASD_AI_PROVIDER;
71
73
 
72
- if (explicit) {
73
- logger.debug(`AI provider explicitly set: ${explicit}`);
74
- return createProvider({ provider: explicit });
74
+ if (explicit && explicit.toLowerCase() !== 'auto') {
75
+ // 验证显式指定的 provider 是否有对应 API Key
76
+ const keyEnvMap = {
77
+ google: 'ASD_GOOGLE_API_KEY',
78
+ 'google-gemini': 'ASD_GOOGLE_API_KEY',
79
+ gemini: 'ASD_GOOGLE_API_KEY',
80
+ openai: 'ASD_OPENAI_API_KEY',
81
+ deepseek: 'ASD_DEEPSEEK_API_KEY',
82
+ claude: 'ASD_CLAUDE_API_KEY',
83
+ anthropic: 'ASD_CLAUDE_API_KEY',
84
+ ollama: null, // Ollama 不需要 key
85
+ mock: null,
86
+ };
87
+ const requiredKeyEnv = keyEnvMap[explicit.toLowerCase()];
88
+ if (requiredKeyEnv && !process.env[requiredKeyEnv]) {
89
+ logger.warn(
90
+ `[AiFactory] ASD_AI_PROVIDER=${explicit} 但 ${requiredKeyEnv} 未配置,尝试自动探测其他可用 provider…`
91
+ );
92
+ // 降级到自动探测,不直接 return
93
+ } else {
94
+ logger.debug(`AI provider explicitly set: ${explicit}`);
95
+ return createProvider({ provider: explicit });
96
+ }
75
97
  }
76
98
 
77
99
  // 按优先级探测
@@ -92,7 +114,7 @@ export function autoDetectProvider() {
92
114
  return createProvider({ provider: 'deepseek' });
93
115
  }
94
116
 
95
- logger.warn('No AI API key found, using mock provider');
117
+ logger.info('[AiFactory] 未找到任何 AI API Key,AI 功能已跳过。请在 .env 中配置 ASD_GOOGLE_API_KEY 等。');
96
118
  return createProvider({ provider: 'mock' });
97
119
  }
98
120
 
@@ -113,9 +135,13 @@ const PROVIDER_KEY_MAP = {
113
135
  export function getAvailableFallbacks(currentProvider) {
114
136
  const fallbacks = [];
115
137
  for (const [name, envKey] of Object.entries(PROVIDER_KEY_MAP)) {
116
- if (name === currentProvider) continue;
138
+ if (name === currentProvider) {
139
+ continue;
140
+ }
117
141
  const key = process.env[envKey];
118
- if (key && key.length > 0) fallbacks.push(name);
142
+ if (key && key.length > 0) {
143
+ fallbacks.push(name);
144
+ }
119
145
  }
120
146
  return fallbacks;
121
147
  }
@@ -125,8 +151,12 @@ export function getAvailableFallbacks(currentProvider) {
125
151
  */
126
152
  export function isGeoOrProviderError(err) {
127
153
  const msg = (err.message || '').toLowerCase();
128
- return /user location is not supported|failed_precondition|unsupported.*(region|country|location)|geo|blocked/i.test(msg)
129
- || (/permission.*denied|forbidden/i.test(msg) && !/rate.?limit|quota|429/i.test(msg));
154
+ return (
155
+ /user location is not supported|failed_precondition|unsupported.*(region|country|location)|geo|blocked/i.test(
156
+ msg
157
+ ) ||
158
+ (/permission.*denied|forbidden/i.test(msg) && !/rate.?limit|quota|429/i.test(msg))
159
+ );
130
160
  }
131
161
 
132
162
  /**
@@ -137,7 +167,9 @@ export function isGeoOrProviderError(err) {
137
167
  export async function getProviderWithFallback() {
138
168
  const logger = Logger.getInstance();
139
169
  const primary = autoDetectProvider();
140
- if (!primary) return null;
170
+ if (!primary) {
171
+ return null;
172
+ }
141
173
 
142
174
  const currentProvider = (process.env.ASD_AI_PROVIDER || 'google').toLowerCase();
143
175
 
@@ -202,10 +234,10 @@ export function getAiConfigInfo() {
202
234
 
203
235
  // 所有提供商的集中导出
204
236
  export { AiProvider } from './AiProvider.js';
205
- export { GoogleGeminiProvider } from './providers/GoogleGeminiProvider.js';
206
- export { OpenAiProvider } from './providers/OpenAiProvider.js';
207
237
  export { ClaudeProvider } from './providers/ClaudeProvider.js';
238
+ export { GoogleGeminiProvider } from './providers/GoogleGeminiProvider.js';
208
239
  export { MockProvider } from './providers/MockProvider.js';
240
+ export { OpenAiProvider } from './providers/OpenAiProvider.js';
209
241
 
210
242
  export default {
211
243
  createProvider,