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
package/bin/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * AutoSnippet V2 CLI
5
- *
5
+ *
6
6
  * Usage:
7
7
  * asd setup - 初始化项目
8
8
  * asd coldstart - 冷启动知识库(9 维度分析 + AI 填充)
@@ -16,10 +16,10 @@
16
16
  * asd ui - 启动 Dashboard UI
17
17
  */
18
18
 
19
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
20
+ import { dirname, join, resolve } from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
19
22
  import { Command } from 'commander';
20
- import { readFileSync, existsSync } from 'fs';
21
- import { join, resolve, dirname, basename } from 'path';
22
- import { fileURLToPath } from 'url';
23
23
 
24
24
  const __filename = fileURLToPath(import.meta.url);
25
25
  const __dirname = dirname(__filename);
@@ -29,7 +29,9 @@ const pkg = existsSync(pkgPath) ? JSON.parse(readFileSync(pkgPath, 'utf8')) : {
29
29
  // ─── 进程级错误兜底 ────────────────────────────────────
30
30
  process.on('uncaughtException', (error) => {
31
31
  process.stderr.write(`[asd] Uncaught Exception: ${error.message}\n`);
32
- if (error.stack) process.stderr.write(`${error.stack}\n`);
32
+ if (error.stack) {
33
+ process.stderr.write(`${error.stack}\n`);
34
+ }
33
35
  process.exit(1);
34
36
  });
35
37
 
@@ -45,13 +47,10 @@ const handleSignal = (signal) => {
45
47
  process.exit(0);
46
48
  };
47
49
  process.on('SIGTERM', () => handleSignal('SIGTERM'));
48
- process.on('SIGINT', () => handleSignal('SIGINT'));
50
+ process.on('SIGINT', () => handleSignal('SIGINT'));
49
51
 
50
52
  const program = new Command();
51
- program
52
- .name('asd')
53
- .description('AutoSnippet V2 - AI 知识库管理工具')
54
- .version(pkg.version);
53
+ program.name('asd').description('AutoSnippet V2 - AI 知识库管理工具').version(pkg.version);
55
54
 
56
55
  // ─────────────────────────────────────────────────────
57
56
  // setup 命令
@@ -64,11 +63,11 @@ program
64
63
  .option('--seed', '预置示例 Recipe(冷启动推荐)')
65
64
  .action(async (opts) => {
66
65
  const { SetupService } = await import('../lib/cli/SetupService.js');
67
- const service = new SetupService({ projectRoot: resolve(opts.dir), force: opts.force, seed: opts.seed });
68
-
69
- console.log(`\n🚀 AutoSnippet V2 — 初始化工作空间`);
70
- console.log(` 项目: ${service.projectName}`);
71
- console.log(` 路径: ${service.projectRoot}\n`);
66
+ const service = new SetupService({
67
+ projectRoot: resolve(opts.dir),
68
+ force: opts.force,
69
+ seed: opts.seed,
70
+ });
72
71
 
73
72
  await service.run();
74
73
  service.printSummary();
@@ -88,12 +87,8 @@ program
88
87
  .option('--json', '以 JSON 格式输出结果')
89
88
  .action(async (opts) => {
90
89
  const projectRoot = resolve(opts.dir);
91
- console.log(`\n🚀 AutoSnippet — 冷启动知识库`);
92
- console.log(` 项目: ${basename(projectRoot)}`);
93
- console.log(` 路径: ${projectRoot}`);
94
- console.log(` 最大文件数: ${opts.maxFiles}`);
95
- if (opts.skipGuard) console.log(' Guard 审计: 跳过');
96
- console.log('');
90
+ if (opts.skipGuard) {
91
+ }
97
92
 
98
93
  try {
99
94
  const { bootstrap, container } = await initContainer({ projectRoot });
@@ -114,71 +109,45 @@ program
114
109
  spinner.stop();
115
110
 
116
111
  if (opts.json) {
117
- console.log(JSON.stringify(result, null, 2));
118
112
  } else {
119
113
  // 输出骨架报告
120
114
  const report = result.report || {};
121
- const targets = result.targets || [];
115
+ const _targets = result.targets || [];
122
116
  const langStats = result.languageStats || {};
123
117
  const guardSummary = result.guardSummary;
124
118
  const astSummary = result.astSummary;
125
- const bootstrapCandidates = result.bootstrapCandidates || {};
119
+ const _bootstrapCandidates = result.bootstrapCandidates || {};
126
120
  const framework = result.analysisFramework || {};
127
-
128
- console.log('✅ 冷启动骨架已创建\n');
129
-
130
- // 项目概况
131
- console.log('📊 项目概况');
132
- console.log(` Targets: ${targets.length}`);
133
- console.log(` 文件: ${report.totals?.files || 0}`);
134
- console.log(` 主语言: ${result.primaryLanguage || 'unknown'}`);
135
121
  if (Object.keys(langStats).length > 0) {
136
- const langParts = Object.entries(langStats)
122
+ const _langParts = Object.entries(langStats)
137
123
  .sort((a, b) => b[1] - a[1])
138
124
  .slice(0, 5)
139
125
  .map(([ext, count]) => `${ext}(${count})`);
140
- console.log(` 语言分布: ${langParts.join(', ')}`);
141
126
  }
142
127
 
143
128
  // AST 分析
144
129
  if (astSummary) {
145
- console.log(`\n🔬 AST 分析`);
146
- console.log(` 类: ${astSummary.classes}, 协议: ${astSummary.protocols}, Category: ${astSummary.categories}`);
147
130
  if (astSummary.metrics) {
148
- console.log(` 方法总数: ${astSummary.metrics.totalMethods}, 复杂方法: ${astSummary.metrics.complexMethods}`);
149
131
  }
150
132
  }
151
133
 
152
134
  // SPM 依赖
153
135
  if (report.phases?.spmDependencyGraph) {
154
- console.log(`\n📦 SPM 依赖`);
155
- console.log(` 依赖边: ${report.phases.spmDependencyGraph.edgesWritten}`);
156
136
  }
157
137
 
158
138
  // Guard 审计
159
139
  if (guardSummary) {
160
- console.log(`\n🛡️ Guard 审计`);
161
- console.log(` 违规: ${guardSummary.totalViolations} (${guardSummary.errors} errors, ${guardSummary.warnings} warnings)`);
162
140
  }
163
141
 
164
142
  // 维度分析框架
165
143
  if (framework.dimensions) {
166
- console.log(`\n📋 分析维度: ${framework.dimensions.length} 个`);
167
144
  for (const dim of framework.dimensions) {
168
- const type = dim.skillWorthy ? (dim.dualOutput ? 'Dual' : 'Skill') : 'Candidate';
169
- console.log(` • ${dim.label} [${type}]`);
145
+ const _type = dim.skillWorthy ? (dim.dualOutput ? 'Dual' : 'Skill') : 'Candidate';
170
146
  }
171
147
  }
172
-
173
- // AI 异步填充状态
174
- console.log(`\n🤖 AI 异步填充: ${result.asyncFill ? '已启动' : '未启用'}`);
175
148
  if (result.bootstrapSession) {
176
- const session = result.bootstrapSession;
177
- console.log(` 会话: ${session.id}`);
178
- console.log(` 任务: ${session.tasks?.length || 0} 个维度`);
149
+ const _session = result.bootstrapSession;
179
150
  }
180
-
181
- console.log('');
182
151
  }
183
152
 
184
153
  // 等待模式: 轮询 BootstrapTaskManager 直到所有维度完成
@@ -190,18 +159,22 @@ program
190
159
  const maxAttempts = 600; // 最多等 10 分钟(每秒轮询)
191
160
 
192
161
  while (attempts < maxAttempts) {
193
- await new Promise(r => setTimeout(r, 1000));
162
+ await new Promise((r) => setTimeout(r, 1000));
194
163
  attempts++;
195
164
 
196
165
  try {
197
166
  const taskManager = container.get('bootstrapTaskManager');
198
167
  const sessionStatus = taskManager.getSessionStatus();
199
168
 
200
- if (!sessionStatus || !sessionStatus.tasks) break;
169
+ if (!sessionStatus || !sessionStatus.tasks) {
170
+ break;
171
+ }
201
172
 
202
173
  const total = sessionStatus.tasks.length;
203
- const done = sessionStatus.tasks.filter(t => t.status === 'done' || t.status === 'error').length;
204
- const current = sessionStatus.tasks.find(t => t.status === 'running');
174
+ const done = sessionStatus.tasks.filter(
175
+ (t) => t.status === 'done' || t.status === 'error'
176
+ ).length;
177
+ const current = sessionStatus.tasks.find((t) => t.status === 'running');
205
178
  const statusText = current
206
179
  ? `[${done}/${total}] 正在处理: ${current.meta?.label || current.id}`
207
180
  : `[${done}/${total}] 等待中...`;
@@ -216,14 +189,11 @@ program
216
189
 
217
190
  // 输出各维度结果
218
191
  if (!opts.json) {
219
- const succeeded = sessionStatus.tasks.filter(t => t.status === 'done').length;
220
- const failed = sessionStatus.tasks.filter(t => t.status === 'error').length;
221
- console.log(` ✅ 成功: ${succeeded}, ❌ 失败: ${failed}`);
192
+ const _succeeded = sessionStatus.tasks.filter((t) => t.status === 'done').length;
193
+ const _failed = sessionStatus.tasks.filter((t) => t.status === 'error').length;
222
194
  for (const t of sessionStatus.tasks) {
223
- const icon = t.status === 'done' ? '✅' : '❌';
224
- console.log(` ${icon} ${t.meta?.label || t.id}`);
195
+ const _icon = t.status === 'done' ? '✅' : '❌';
225
196
  }
226
- console.log('');
227
197
  }
228
198
  break;
229
199
  }
@@ -236,16 +206,14 @@ program
236
206
  waitSpinner.warn('AI 填充超时(10 分钟),可通过 asd ui 查看进度');
237
207
  }
238
208
  } else if (!opts.json) {
239
- console.log('💡 后台 AI 正在逐维度填充知识,可通过以下方式查看进度:');
240
- console.log(' • asd ui -d . → Dashboard 实时查看');
241
- console.log(' • 再次运行 asd coldstart --wait 等待完成');
242
- console.log('');
243
209
  }
244
210
 
245
211
  await bootstrap.shutdown();
246
212
  } catch (err) {
247
213
  console.error(`\n❌ ${err.message}`);
248
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
214
+ if (process.env.ASD_DEBUG === '1') {
215
+ console.error(err.stack);
216
+ }
249
217
  process.exit(1);
250
218
  }
251
219
  });
@@ -262,12 +230,10 @@ program
262
230
  .option('--json', '以 JSON 格式输出')
263
231
  .action(async (target, opts) => {
264
232
  const projectRoot = resolve(opts.dir);
265
- console.log(`\n🔬 AutoSnippet AI Scan`);
266
- console.log(` 项目: ${basename(projectRoot)}`);
267
- if (target) console.log(` Target: ${target}`);
268
- console.log(` 最大文件数: ${opts.maxFiles}`);
269
- if (opts.dryRun) console.log(' 模式: dry-run(仅预览)');
270
- console.log('');
233
+ if (target) {
234
+ }
235
+ if (opts.dryRun) {
236
+ }
271
237
 
272
238
  try {
273
239
  const { bootstrap, container } = await initContainer({ projectRoot });
@@ -286,28 +252,23 @@ program
286
252
  spinner.stop();
287
253
 
288
254
  if (opts.json) {
289
- console.log(JSON.stringify(report, null, 2));
290
255
  } else {
291
- console.log(`\n✅ AI 扫描完成`);
292
- console.log(` 扫描文件: ${report.files}`);
293
- console.log(` 跳过: ${report.skipped}`);
294
- console.log(` 发布 Recipe: ${report.published}`);
295
256
  if (report.errors.length > 0) {
296
- console.log(`\n⚠️ ${report.errors.length} 个错误:`);
297
- for (const err of report.errors.slice(0, 10)) {
298
- console.log(` - ${err}`);
257
+ for (const _err of report.errors.slice(0, 10)) {
258
+ }
259
+ if (report.errors.length > 10) {
299
260
  }
300
- if (report.errors.length > 10) console.log(` ... 及其他 ${report.errors.length - 10} 个`);
301
261
  }
302
262
  if (!opts.dryRun && report.published > 0) {
303
- console.log(`\n📋 Recipe 已发布,可通过 asd search 或 Cursor Rules 使用`);
304
263
  }
305
264
  }
306
265
 
307
266
  await bootstrap.shutdown();
308
267
  } catch (err) {
309
268
  console.error(`\n❌ ${err.message}`);
310
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
269
+ if (process.env.ASD_DEBUG === '1') {
270
+ console.error(err.stack);
271
+ }
311
272
  process.exit(1);
312
273
  }
313
274
  });
@@ -332,14 +293,12 @@ program
332
293
  });
333
294
 
334
295
  if (results.items.length === 0) {
335
- console.log('No results found.');
336
296
  } else {
337
- console.log(`\n🔍 Found ${results.total} results (${results.mode} mode):\n`);
338
297
  for (const item of results.items) {
339
- const badge = item.type === 'recipe' ? '📘' : item.type === 'solution' ? '💡' : '🛡️';
340
- const score = item.score ? ` [${item.score}]` : '';
341
- console.log(` ${badge} ${item.title || item.id}${score}`);
342
- if (item.description) console.log(` ${item.description.slice(0, 80)}`);
298
+ const _badge = item.type === 'recipe' ? '📘' : item.type === 'solution' ? '💡' : '🛡️';
299
+ const _score = item.score ? ` [${item.score}]` : '';
300
+ if (item.description) {
301
+ }
343
302
  }
344
303
  }
345
304
 
@@ -375,23 +334,19 @@ program
375
334
  const violations = engine.checkCode(code, language, { scope: opts.scope });
376
335
 
377
336
  if (opts.json) {
378
- console.log(JSON.stringify({ file: filePath, language, violations }, null, 2));
379
337
  } else if (violations.length === 0) {
380
- console.log(`✅ No violations found in ${file} (${language})`);
381
338
  } else {
382
- const errors = violations.filter(v => v.severity === 'error');
383
- const warnings = violations.filter(v => v.severity === 'warning');
384
- console.log(`\n🛡️ ${file} (${language}): ${violations.length} violations`);
385
- console.log(` ${errors.length} errors, ${warnings.length} warnings\n`);
339
+ const _errors = violations.filter((v) => v.severity === 'error');
340
+ const _warnings = violations.filter((v) => v.severity === 'warning');
386
341
  for (const v of violations) {
387
- const icon = v.severity === 'error' ? '❌' : '⚠️';
388
- console.log(` ${icon} L${v.line} [${v.ruleId}] ${v.message}`);
389
- if (v.snippet) console.log(` ${v.snippet}`);
342
+ const _icon = v.severity === 'error' ? '❌' : '⚠️';
343
+ if (v.snippet) {
344
+ }
390
345
  }
391
346
  }
392
347
 
393
348
  await bootstrap.shutdown();
394
- process.exit(violations.some(v => v.severity === 'error') ? 1 : 0);
349
+ process.exit(violations.some((v) => v.severity === 'error') ? 1 : 0);
395
350
  } catch (err) {
396
351
  console.error('Error:', err.message);
397
352
  process.exit(1);
@@ -430,11 +385,9 @@ program
430
385
  if (opts.report === 'json') {
431
386
  const output = JSON.stringify(report, null, 2);
432
387
  if (opts.output) {
433
- const { writeFileSync } = await import('fs');
388
+ const { writeFileSync } = await import('node:fs');
434
389
  writeFileSync(opts.output, output, 'utf8');
435
- console.log(`Report written to ${opts.output}`);
436
390
  } else {
437
- console.log(output);
438
391
  }
439
392
  } else {
440
393
  reporter.printReport(report, { format: opts.report });
@@ -442,9 +395,8 @@ program
442
395
 
443
396
  // 如果也要写文件(非 JSON 格式)
444
397
  if (opts.output && opts.report !== 'json') {
445
- const { writeFileSync } = await import('fs');
398
+ const { writeFileSync } = await import('node:fs');
446
399
  writeFileSync(opts.output, JSON.stringify(report, null, 2), 'utf8');
447
- console.log(`Report data written to ${opts.output}`);
448
400
  }
449
401
 
450
402
  await bootstrap.shutdown();
@@ -456,7 +408,9 @@ program
456
408
  process.exit(0);
457
409
  } catch (err) {
458
410
  console.error('Error:', err.message);
459
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
411
+ if (process.env.ASD_DEBUG === '1') {
412
+ console.error(err.stack);
413
+ }
460
414
  process.exit(1);
461
415
  }
462
416
  });
@@ -471,36 +425,40 @@ program
471
425
  .option('--json', '以 JSON 格式输出')
472
426
  .action(async (opts) => {
473
427
  try {
474
- const { execSync } = await import('child_process');
428
+ const { execSync } = await import('node:child_process');
475
429
 
476
430
  // 获取 staged 文件列表
477
431
  let stagedFiles;
478
432
  try {
479
- stagedFiles = execSync('git diff --cached --name-only --diff-filter=ACM', { encoding: 'utf8' })
480
- .trim().split('\n').filter(Boolean);
481
- } catch (err) {
433
+ stagedFiles = execSync('git diff --cached --name-only --diff-filter=ACM', {
434
+ encoding: 'utf8',
435
+ })
436
+ .trim()
437
+ .split('\n')
438
+ .filter(Boolean);
439
+ } catch (_err) {
482
440
  console.error('❌ 无法获取 git staged 文件(是否在 git 仓库中?)');
483
441
  process.exit(1);
484
442
  }
485
443
 
486
444
  if (stagedFiles.length === 0) {
487
- console.log('✅ No staged files');
488
445
  process.exit(0);
489
446
  }
490
447
 
491
448
  // 过滤源文件
492
449
  const { SOURCE_EXTS } = await import('../lib/service/guard/SourceFileCollector.js');
493
- const { extname: _extname } = await import('path');
494
- const sourceFiles = stagedFiles.filter(f => SOURCE_EXTS.has(_extname(f).toLowerCase()));
450
+ const { extname: _extname } = await import('node:path');
451
+ const sourceFiles = stagedFiles.filter((f) => SOURCE_EXTS.has(_extname(f).toLowerCase()));
495
452
 
496
453
  if (sourceFiles.length === 0) {
497
- console.log('✅ No source files in staged changes');
498
454
  process.exit(0);
499
455
  }
500
456
 
501
457
  const { bootstrap, container } = await initContainer();
502
458
  const engine = container.get('guardCheckEngine');
503
- const { detectLanguage } = await import('../lib/service/guard/GuardCheckEngine.js');
459
+ const { detectLanguage: _detectLanguage } = await import(
460
+ '../lib/service/guard/GuardCheckEngine.js'
461
+ );
504
462
 
505
463
  // 读取文件内容并检查
506
464
  const files = [];
@@ -515,21 +473,15 @@ program
515
473
  const { summary } = result;
516
474
 
517
475
  if (opts.json) {
518
- console.log(JSON.stringify(result, null, 2));
519
476
  } else if (summary.totalViolations === 0) {
520
- console.log(`✅ ${summary.filesChecked} staged files passed Guard check`);
521
477
  } else {
522
- console.log(`\n🛡️ Guard check on ${summary.filesChecked} staged files:`);
523
- console.log(` ${summary.totalErrors} errors, ${summary.totalViolations - summary.totalErrors} warnings\n`);
524
-
525
- const filesWithIssues = result.files.filter(f => f.summary.total > 0);
478
+ const filesWithIssues = result.files.filter((f) => f.summary.total > 0);
526
479
  for (const file of filesWithIssues.slice(0, 10)) {
527
- console.log(` 📄 ${basename(file.filePath)} (${file.summary.errors}E / ${file.summary.warnings}W)`);
528
480
  for (const v of file.violations.slice(0, 5)) {
529
- const icon = v.severity === 'error' ? '❌' : '⚠️';
530
- console.log(` ${icon} L${v.line} [${v.ruleId}] ${v.message}`);
481
+ const _icon = v.severity === 'error' ? '❌' : '⚠️';
482
+ }
483
+ if (file.violations.length > 5) {
531
484
  }
532
- if (file.violations.length > 5) console.log(` ... ${file.violations.length - 5} more`);
533
485
  }
534
486
  }
535
487
 
@@ -537,7 +489,9 @@ program
537
489
  process.exit(summary.totalErrors > 0 ? 1 : 0);
538
490
  } catch (err) {
539
491
  console.error('Error:', err.message);
540
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
492
+ if (process.env.ASD_DEBUG === '1') {
493
+ console.error(err.stack);
494
+ }
541
495
  process.exit(1);
542
496
  }
543
497
  });
@@ -547,17 +501,13 @@ program
547
501
  // ─────────────────────────────────────────────────────
548
502
  program
549
503
  .command('watch')
550
- .description('启动文件监控(支持 // as:c、// as:s、// as:a 等指令)')
504
+
551
505
  .option('-d, --dir <path>', '监控目录', '.')
552
- .option('-e, --ext <exts>', '文件扩展名(逗号分隔)', '.swift,.m,.h')
506
+ .option('-e, --ext <exts>', '文件扩展名(逗号分隔,留空则自动检测)')
553
507
  .option('--guard', '自动运行 Guard 检查', true)
554
508
  .action(async (opts) => {
555
509
  try {
556
510
  const dir = resolve(opts.dir);
557
- console.log(`👁️ Watching ${dir} for changes...`);
558
- console.log(` Extensions: ${opts.ext}`);
559
- console.log(` Directives: // as:c (create), // as:s (search), // as:a (audit)`);
560
- console.log(' Press Ctrl+C to stop\n');
561
511
 
562
512
  let bootstrap;
563
513
  try {
@@ -571,8 +521,14 @@ program
571
521
  const Paths = await import('../lib/infrastructure/config/Paths.js');
572
522
  const specPath = Paths.getProjectSpecPath(dir);
573
523
 
524
+ // IDE + 扩展名自动检测
525
+ let exts = null;
526
+ if (opts.ext) {
527
+ exts = opts.ext.split(',').map((e) => e.trim());
528
+ }
529
+ // 不指定 --ext 时,FileWatcher 内部根据 IDE 检测结果使用默认模式
530
+
574
531
  const { FileWatcher } = await import('../lib/service/automation/FileWatcher.js');
575
- const exts = opts.ext.split(',').map(e => e.trim());
576
532
  const watcher = new FileWatcher(specPath, dir, {
577
533
  quiet: false,
578
534
  exts,
@@ -581,14 +537,15 @@ program
581
537
 
582
538
  // 优雅退出
583
539
  process.on('SIGINT', async () => {
584
- console.log('\n🛑 Stopping watcher...');
585
540
  await watcher.stop();
586
541
  await bootstrap.shutdown();
587
542
  process.exit(0);
588
543
  });
589
544
  } catch (err) {
590
545
  console.error('Error:', err.message);
591
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
546
+ if (process.env.ASD_DEBUG === '1') {
547
+ console.error(err.stack);
548
+ }
592
549
  process.exit(1);
593
550
  }
594
551
  });
@@ -602,7 +559,6 @@ program
602
559
  .option('-p, --port <port>', '端口', '3000')
603
560
  .option('-H, --host <host>', '绑定地址', '127.0.0.1')
604
561
  .action(async (opts) => {
605
- console.log(`🚀 Starting AutoSnippet V2 API server on ${opts.host}:${opts.port}...`);
606
562
  // 设置环境变量后启动 api-server
607
563
  process.env.PORT = opts.port;
608
564
  process.env.HOST = opts.host;
@@ -621,14 +577,10 @@ program
621
577
  .option('-d, --dir <directory>', '指定 AutoSnippet 项目目录(默认:当前目录)')
622
578
  .option('--api-only', '仅启动 API 服务(不启动前端)')
623
579
  .action(async (opts) => {
624
- const { spawn } = await import('child_process');
580
+ const { spawn } = await import('node:child_process');
625
581
 
626
582
  // 项目根目录:-d 选项 > 环境变量 ASD_CWD > 当前目录
627
583
  const projectRoot = opts.dir || process.env.ASD_CWD || process.cwd();
628
- console.log(`📂 Project root: ${projectRoot}`);
629
-
630
- // 1. 内联启动 API Server(不用 import api-server.js,避免其 process.exit 影响整个进程)
631
- console.log(`🚀 Starting API server on port ${opts.port}...`);
632
584
  const port = opts.port;
633
585
  const host = '127.0.0.1';
634
586
  process.env.PORT = port;
@@ -638,25 +590,27 @@ program
638
590
  try {
639
591
  const { default: HttpServer } = await import('../lib/http/HttpServer.js');
640
592
 
641
- const { bootstrap, container } = await initContainer({ projectRoot });
593
+ const { container } = await initContainer({ projectRoot });
642
594
 
643
595
  // 连接 EventBus → Gateway(供 SignalCollector 监听事件)
644
596
  try {
645
597
  const eventBus = container.get('eventBus');
646
598
  const gateway = container.get('gateway');
647
599
  gateway.eventBus = eventBus;
648
- } catch { /* EventBus 不可用不阻塞启动 */ }
600
+ } catch {
601
+ /* EventBus 不可用不阻塞启动 */
602
+ }
649
603
 
650
604
  httpServer = new HttpServer({ port, host });
651
605
  await httpServer.initialize();
652
606
  await httpServer.start();
653
607
 
654
- console.log(`✅ API server running at http://${host}:${port}`);
655
-
656
608
  // 启动 SignalCollector 后台 AI 分析服务
657
609
  try {
658
610
  const { SignalCollector } = await import('../lib/service/skills/SignalCollector.js');
659
- const { getRealtimeService } = await import('../lib/infrastructure/realtime/RealtimeService.js');
611
+ const { getRealtimeService } = await import(
612
+ '../lib/infrastructure/realtime/RealtimeService.js'
613
+ );
660
614
  const db = container.get('database');
661
615
  const chatAgent = container.get('chatAgent');
662
616
 
@@ -670,60 +624,119 @@ program
670
624
  try {
671
625
  const realtime = getRealtimeService();
672
626
  realtime.broadcastEvent('skill:suggestions', { suggestions });
673
- } catch { /* realtime 未就绪 */ }
627
+ } catch {
628
+ /* realtime 未就绪 */
629
+ }
674
630
  },
675
631
  });
676
632
  signalCollector.start();
677
633
  global._signalCollector = signalCollector;
678
- console.log(`🧠 SignalCollector started (mode=${signalCollector.getMode()}, AI-driven)`);
679
634
  } catch (scErr) {
680
635
  console.warn(`⚠️ SignalCollector failed to start: ${scErr.message}`);
681
- if (process.env.ASD_DEBUG === '1') console.error(scErr.stack);
636
+ if (process.env.ASD_DEBUG === '1') {
637
+ console.error(scErr.stack);
638
+ }
682
639
  }
683
640
 
684
- // 3. 启动文件监听器(监控 // as:c // as:s // as:a 等指令)
685
- try {
686
- const Paths = await import('../lib/infrastructure/config/Paths.js');
687
- const specPath = Paths.getProjectSpecPath(projectRoot);
688
- const isDebugMode = process.env.ASD_DEBUG === '1';
689
-
690
- // 设置 Dashboard URL 供 watcher 跳转浏览器使用
691
- // 生产模式用 API 同端口,开发模式用 vite dev 5173
692
- const dashDirCheck = join(__dirname, '..', 'dashboard');
693
- const isProductionDashboard = existsSync(join(dashDirCheck, 'dist', 'index.html')) && !existsSync(join(dashDirCheck, 'src'));
694
- if (!opts.apiOnly) {
695
- process.env.ASD_DASHBOARD_URL = isProductionDashboard
696
- ? `http://127.0.0.1:${port}`
697
- : `http://localhost:5173`;
698
- } else {
699
- process.env.ASD_DASHBOARD_URL = process.env.ASD_DASHBOARD_URL || `http://${host}:${port}`;
700
- }
641
+ // 3. 启动文件监听器(仅 iOS/macOS 项目 Xcode 工作流)
642
+ // VSCode 用户通过 AutoSnippet 扩展原生处理 as:s/as:c/as:a 指令
643
+ const isAppleProject = (() => {
644
+ try {
645
+ const entries = readdirSync(projectRoot, { withFileTypes: true });
646
+
647
+ // ── Level 1: 项目配置文件(确定性高)──
648
+ const hasAppleConfig = entries.some(
649
+ (e) =>
650
+ e.name === 'Package.swift' || // SPM
651
+ e.name === 'Podfile' || // CocoaPods
652
+ e.name === 'Cartfile' || // Carthage
653
+ e.name === 'project.yml' || // XcodeGen
654
+ e.name.endsWith('.xcodeproj') || // Xcode project
655
+ e.name.endsWith('.xcworkspace') // Xcode workspace
656
+ );
657
+ if (hasAppleConfig) return true;
658
+
659
+ // ── Level 2: 目录结构特征 ──
660
+ const hasAppleDir = entries.some(
661
+ (e) =>
662
+ e.isDirectory() &&
663
+ (e.name === 'Tuist' || // Tuist 项目
664
+ e.name === 'Pods' || // CocoaPods 产物
665
+ e.name === 'Carthage' || // Carthage 产物
666
+ e.name === 'DerivedData') // Xcode 构建产物
667
+ );
668
+ if (hasAppleDir) return true;
669
+
670
+ // ── Level 3: 向下扫一层(处理 monorepo 或 Sources/ 下有 .swift 的情况)──
671
+ const APPLE_EXTS = new Set(['.swift', '.m', '.mm', '.h']);
672
+ const SCAN_DIRS = ['Sources', 'Source', 'src', 'App', 'Classes', 'ios', 'iOS'];
673
+ for (const e of entries) {
674
+ // 根目录直接有 .swift/.m 文件
675
+ if (!e.isDirectory() && APPLE_EXTS.has(e.name.slice(e.name.lastIndexOf('.')))) {
676
+ return true;
677
+ }
678
+ // 常见源码目录下有 Apple 文件
679
+ if (e.isDirectory() && SCAN_DIRS.includes(e.name)) {
680
+ try {
681
+ const subEntries = readdirSync(join(projectRoot, e.name));
682
+ if (subEntries.some((f) => APPLE_EXTS.has(f.slice(f.lastIndexOf('.'))))) {
683
+ return true;
684
+ }
685
+ } catch { /* 读取失败忽略 */ }
686
+ }
687
+ }
701
688
 
702
- const { FileWatcher } = await import('../lib/service/automation/FileWatcher.js');
703
- const watcher = new FileWatcher(specPath, projectRoot, { quiet: !isDebugMode });
704
- watcher.start();
705
- console.log(`👁️ File watcher started for: ${projectRoot}`);
706
- if (isDebugMode) {
707
- console.log(` Spec path: ${specPath}`);
708
- console.log(` Dashboard URL: ${process.env.ASD_DASHBOARD_URL}`);
689
+ return false;
690
+ } catch {
691
+ return false;
709
692
  }
710
- } catch (watchErr) {
711
- console.warn(`⚠️ File watcher failed to start: ${watchErr.message}`);
712
- if (process.env.ASD_DEBUG === '1') {
713
- console.error(watchErr.stack);
693
+ })();
694
+
695
+ if (isAppleProject) {
696
+ try {
697
+ const Paths = await import('../lib/infrastructure/config/Paths.js');
698
+ const specPath = Paths.getProjectSpecPath(projectRoot);
699
+ const isDebugMode = process.env.ASD_DEBUG === '1';
700
+
701
+ // 设置 Dashboard URL 供 watcher 跳转浏览器使用
702
+ // 生产模式用 API 同端口,开发模式用 vite dev 5173
703
+ const dashDirCheck = join(__dirname, '..', 'dashboard');
704
+ const isProductionDashboard =
705
+ existsSync(join(dashDirCheck, 'dist', 'index.html')) &&
706
+ !existsSync(join(dashDirCheck, 'src'));
707
+ if (!opts.apiOnly) {
708
+ process.env.ASD_DASHBOARD_URL = isProductionDashboard
709
+ ? `http://127.0.0.1:${port}`
710
+ : `http://localhost:5173`;
711
+ } else {
712
+ process.env.ASD_DASHBOARD_URL = process.env.ASD_DASHBOARD_URL || `http://${host}:${port}`;
713
+ }
714
+
715
+ const { FileWatcher } = await import('../lib/service/automation/FileWatcher.js');
716
+ const watcher = new FileWatcher(specPath, projectRoot, { quiet: !isDebugMode });
717
+ watcher.start();
718
+ if (isDebugMode) {
719
+ }
720
+ } catch (watchErr) {
721
+ console.warn(`⚠️ File watcher failed to start: ${watchErr.message}`);
722
+ if (process.env.ASD_DEBUG === '1') {
723
+ console.error(watchErr.stack);
724
+ }
714
725
  }
726
+ } else if (process.env.ASD_DEBUG === '1') {
727
+ console.log('ℹ️ Non-Apple project — file watcher skipped (use VSCode extension instead)');
715
728
  }
716
-
717
729
  } catch (err) {
718
730
  console.error(`❌ API server failed to start: ${err.message}`);
719
731
  if (err.code === 'EADDRINUSE') {
720
- console.error(` Port ${port} is already in use. Kill it with: lsof -ti:${port} | xargs kill -9`);
732
+ console.error(
733
+ ` Port ${port} is already in use. Kill it with: lsof -ti:${port} | xargs kill -9`
734
+ );
721
735
  }
722
736
  process.exit(1);
723
737
  }
724
738
 
725
739
  if (opts.apiOnly) {
726
- console.log(` Docs: http://127.0.0.1:${port}/api-spec`);
727
740
  return;
728
741
  }
729
742
 
@@ -737,24 +750,21 @@ program
737
750
  // ── 生产模式:npm 安装的包,在 API 服务器上直接托管预构建产物 ──
738
751
  // 同端口同 origin → /api 路由自然可达,无跨域问题
739
752
  httpServer.mountDashboard(distDir);
740
- console.log(`🎨 Dashboard UI ready at http://127.0.0.1:${port}/`);
741
753
 
742
754
  if (opts.browser) {
743
755
  const open = (await import('open')).default;
744
756
  open(`http://127.0.0.1:${port}/`);
745
757
  }
746
-
747
758
  } else {
748
759
  // ── 开发模式:有源码,启动 Vite Dev Server ──
749
760
  if (!existsSync(join(dashboardDir, 'node_modules'))) {
750
- console.log('📦 Installing dashboard dependencies...');
751
761
  const install = spawn('npm', ['install'], { cwd: dashboardDir, stdio: 'inherit' });
752
762
  await new Promise((resolve, reject) => {
753
- install.on('close', code => code === 0 ? resolve() : reject(new Error(`npm install exited with ${code}`)));
763
+ install.on('close', (code) =>
764
+ code === 0 ? resolve() : reject(new Error(`npm install exited with ${code}`))
765
+ );
754
766
  });
755
767
  }
756
-
757
- console.log('🎨 Starting Dashboard (dev mode)...');
758
768
  const viteArgs = ['--host'];
759
769
  if (opts.browser) {
760
770
  viteArgs.push('--open');
@@ -770,7 +780,6 @@ program
770
780
  });
771
781
 
772
782
  process.on('SIGINT', () => {
773
- console.log('\n🛑 Stopping Dashboard...');
774
783
  vite.kill();
775
784
  process.exit(0);
776
785
  });
@@ -784,32 +793,19 @@ program
784
793
  .command('status')
785
794
  .description('检查环境状态')
786
795
  .action(async () => {
787
- console.log('\n📋 AutoSnippet V2 Status\n');
788
- console.log(` Version: ${pkg.version}`);
789
- console.log(` Node: ${process.version}`);
790
- console.log(` Platform: ${process.platform} ${process.arch}`);
791
-
792
796
  // AI 配置
793
797
  const { getAiConfigInfo } = await import('../lib/external/ai/AiFactory.js');
794
- const aiInfo = getAiConfigInfo();
795
- console.log(`\n AI Provider: ${aiInfo.provider}`);
796
- console.log(` AI Keys: ${Object.entries(aiInfo.keys).filter(([, v]) => v).map(([k]) => k).join(', ') || 'none'}`);
798
+ const _aiInfo = getAiConfigInfo();
797
799
 
798
800
  // 检查数据库
799
- const dbPath = join(process.cwd(), '.autosnippet', 'autosnippet.db');
800
- console.log(`\n Database: ${existsSync(dbPath) ? '✅ ' + dbPath : '❌ Not found'}`);
801
+ const _dbPath = join(process.cwd(), '.autosnippet', 'autosnippet.db');
801
802
 
802
803
  // 检查依赖
803
804
  for (const dep of ['better-sqlite3', 'commander', 'express']) {
804
805
  try {
805
806
  await import(dep);
806
- console.log(` ${dep}: ✅`);
807
- } catch {
808
- console.log(` ${dep}: ❌ not installed`);
809
- }
807
+ } catch {}
810
808
  }
811
-
812
- console.log('');
813
809
  });
814
810
 
815
811
  // ─────────────────────────────────────────────────────
@@ -825,10 +821,6 @@ program
825
821
  const { UpgradeService } = await import('../lib/cli/UpgradeService.js');
826
822
  const service = new UpgradeService({ projectRoot: resolve(opts.dir) });
827
823
 
828
- console.log(`\n🔄 AutoSnippet V2 — 升级 IDE 集成`);
829
- console.log(` 项目: ${service.projectName}`);
830
- console.log(` 路径: ${service.projectRoot}\n`);
831
-
832
824
  await service.run({
833
825
  skillsOnly: opts.skillsOnly,
834
826
  mcpOnly: opts.mcpOnly,
@@ -846,32 +838,17 @@ program
846
838
  .action(async (opts) => {
847
839
  const projectRoot = resolve(opts.dir);
848
840
 
849
- console.log(`\n🚀 AutoSnippet — Cursor Delivery Pipeline`);
850
- console.log(` 项目: ${basename(projectRoot)}`);
851
- console.log(` 路径: ${projectRoot}\n`);
852
-
853
841
  const { bootstrap, container } = await initContainer({ projectRoot });
854
842
  try {
855
843
  const pipeline = container.get('cursorDeliveryPipeline');
856
844
  const result = await pipeline.deliver();
857
-
858
- console.log(`✅ Cursor 交付物料生成完成\n`);
859
- console.log(` Channel A (Always-On Rules): ${result.channelA.rulesCount} 条规则 (${result.channelA.tokensUsed} tokens)`);
860
- console.log(` Channel B (Smart Rules): ${result.channelB.topicCount} 个主题, ${result.channelB.patternsCount} 个模式 (${result.channelB.totalTokens} tokens)`);
861
- console.log(` Channel C (Agent Skills): ${result.channelC.synced} 个 Skills 已同步`);
862
- console.log(` Channel D (Dev Documents): ${result.channelD?.documentsCount || 0} 篇文档`);
863
845
  if (result.channelC.errors > 0) {
864
- console.log(` ⚠️ ${result.channelC.errors} 个错误`);
865
846
  }
866
- console.log(`\n 总耗时: ${result.stats.duration}ms`);
867
847
 
868
848
  if (opts.verbose && result.channelB.topics) {
869
- console.log(`\n Channel B 主题明细:`);
870
- for (const [topic, info] of Object.entries(result.channelB.topics)) {
871
- console.log(` - ${topic}: ${info.patternsCount} patterns (${info.tokensUsed} tokens)`);
849
+ for (const [_topic, _info] of Object.entries(result.channelB.topics)) {
872
850
  }
873
851
  }
874
- console.log('');
875
852
  } finally {
876
853
  await bootstrap.shutdown?.();
877
854
  }
@@ -890,12 +867,8 @@ program
890
867
  const projectRoot = resolve(opts.dir);
891
868
  const { KnowledgeSyncService } = await import('../lib/cli/KnowledgeSyncService.js');
892
869
  const syncService = new KnowledgeSyncService(projectRoot);
893
-
894
- console.log(`\n🔄 AutoSnippet V3 — 同步 knowledge entries`);
895
- console.log(` 项目: ${basename(projectRoot)}`);
896
- console.log(` 路径: ${projectRoot}`);
897
- if (opts.dryRun) console.log(' 模式: dry-run(仅报告)');
898
- console.log('');
870
+ if (opts.dryRun) {
871
+ }
899
872
 
900
873
  // 通过 Bootstrap 打开目标项目的 DB
901
874
  const dbPath = join(projectRoot, '.autosnippet', 'autosnippet.db');
@@ -917,28 +890,15 @@ program
917
890
  force: opts.force,
918
891
  });
919
892
 
920
- // 输出报告
921
- console.log(`✅ Knowledge 同步完成`);
922
- console.log(` 扫描: ${report.synced + report.skipped} 文件`);
923
- console.log(` 新增: ${report.created}`);
924
- console.log(` 更新: ${report.updated}`);
925
- console.log(` 跳过: ${report.skipped}`);
926
-
927
893
  if (report.violations.length > 0) {
928
- console.log(`\n⚠️ 检测到 ${report.violations.length} 个手动编辑(已记入违规统计):`);
929
- for (const v of report.violations) {
930
- console.log(` - ${v}`);
894
+ for (const _v of report.violations) {
931
895
  }
932
896
  }
933
897
 
934
898
  if (report.orphaned.length > 0) {
935
- console.log(`\n🗑️ ${report.orphaned.length} 个孤儿条目已标记 deprecated:`);
936
- for (const id of report.orphaned) {
937
- console.log(` - ${id}`);
899
+ for (const _id of report.orphaned) {
938
900
  }
939
901
  }
940
-
941
- console.log('');
942
902
  } finally {
943
903
  await bootstrap.shutdown?.();
944
904
  }