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
@@ -9,28 +9,77 @@
9
9
  * watcher.start();
10
10
  */
11
11
 
12
- import { watch as chokidarWatch } from 'chokidar';
13
- import { readFileSync, accessSync, statSync } from 'node:fs';
12
+ import { accessSync, readFileSync, statSync } from 'node:fs';
14
13
  import { basename, join, normalize } from 'node:path';
15
- import { detectTriggers, REGEX } from './DirectiveDetector.js';
16
- import { saveEventFilter } from './SaveEventFilter.js';
14
+ import { watch as chokidarWatch } from 'chokidar';
17
15
  import { FILE_WATCHER } from '../../shared/constants.js';
16
+ import { detectTriggers, REGEX } from './DirectiveDetector.js';
17
+ import { handleAlink } from './handlers/AlinkHandler.js';
18
18
 
19
19
  /* ── Handler imports ── */
20
20
  import { handleCreate } from './handlers/CreateHandler.js';
21
+ import { handleDraft } from './handlers/DraftHandler.js';
21
22
  import { handleGuard } from './handlers/GuardHandler.js';
22
- import { handleSearch } from './handlers/SearchHandler.js';
23
- import { handleAlink } from './handlers/AlinkHandler.js';
24
23
  import { handleHeader } from './handlers/HeaderHandler.js';
25
- import { handleDraft } from './handlers/DraftHandler.js';
24
+ import { handleSearch } from './handlers/SearchHandler.js';
25
+ import { saveEventFilter } from '../../platform/ios/xcode/SaveEventFilter.js';
26
26
 
27
27
  /* ────────── 配置 ────────── */
28
28
 
29
- const DEFAULT_FILE_PATTERN = ['**/*.m', '**/*.h', '**/*.swift', '**/_draft_*.md'];
29
+ const DEFAULT_FILE_PATTERN = [
30
+ // ObjC/Swift
31
+ '**/*.m',
32
+ '**/*.h',
33
+ '**/*.mm',
34
+ '**/*.swift',
35
+ // JS/TS
36
+ '**/*.js',
37
+ '**/*.ts',
38
+ '**/*.jsx',
39
+ '**/*.tsx',
40
+ '**/*.vue',
41
+ '**/*.svelte',
42
+ // Python
43
+ '**/*.py',
44
+ // JVM
45
+ '**/*.java',
46
+ '**/*.kt',
47
+ '**/*.kts',
48
+ // Other languages
49
+ '**/*.go',
50
+ '**/*.rs',
51
+ '**/*.rb',
52
+ // C/C++
53
+ '**/*.c',
54
+ '**/*.cpp',
55
+ '**/*.cc',
56
+ '**/*.hpp',
57
+ // Draft
58
+ '**/_draft_*.md',
59
+ ];
30
60
  const IGNORED = [
31
- '**/node_modules/**', '**/.git/**', '**/.mgit/**', '**/.easybox/**',
32
- '**/xcuserdata/**', '**/.build/**', '**/*.swp', '**/*.tmp', '**/*~.m', '**/*~.h',
33
- '**/DerivedData/**', '**/Pods/**', '**/Carthage/**',
61
+ '**/node_modules/**',
62
+ '**/.git/**',
63
+ '**/.mgit/**',
64
+ '**/.easybox/**',
65
+ '**/xcuserdata/**',
66
+ '**/.build/**',
67
+ '**/*.swp',
68
+ '**/*.tmp',
69
+ '**/*~.m',
70
+ '**/*~.h',
71
+ '**/DerivedData/**',
72
+ '**/Pods/**',
73
+ '**/Carthage/**',
74
+ '**/__pycache__/**',
75
+ '**/.venv/**',
76
+ '**/venv/**',
77
+ '**/build/**',
78
+ '**/target/**',
79
+ '**/.gradle/**',
80
+ '**/dist/**',
81
+ '**/.next/**',
82
+ '**/.nuxt/**',
34
83
  ];
35
84
  const DEBOUNCE_DELAY = FILE_WATCHER.DEBOUNCE_DELAY_MS;
36
85
 
@@ -65,11 +114,11 @@ export class FileWatcher {
65
114
  start() {
66
115
  const watchRoot = this.projectRoot;
67
116
  const filePattern = this.exts
68
- ? this.exts.map((e) => `**/*${e.startsWith('.') ? e : '.' + e}`)
117
+ ? this.exts.map((e) => `**/*${e.startsWith('.') ? e : `.${e}`}`)
69
118
  : DEFAULT_FILE_PATTERN;
70
119
 
71
120
  if (!this.quiet) {
72
- console.log(`✅ 文件监听已启动: ${watchRoot}`);
121
+ console.log('\n👁️ 文件监听已启动 Xcode 模式');
73
122
  }
74
123
 
75
124
  this._watcher = chokidarWatch(filePattern, {
@@ -77,7 +126,10 @@ export class FileWatcher {
77
126
  ignored: IGNORED,
78
127
  ignoreInitial: true,
79
128
  persistent: true,
80
- awaitWriteFinish: { stabilityThreshold: FILE_WATCHER.STABILITY_THRESHOLD_MS, pollInterval: FILE_WATCHER.POLL_INTERVAL_MS },
129
+ awaitWriteFinish: {
130
+ stabilityThreshold: FILE_WATCHER.STABILITY_THRESHOLD_MS,
131
+ pollInterval: FILE_WATCHER.POLL_INTERVAL_MS,
132
+ },
81
133
  usePolling: process.env.ASD_WATCH_POLLING === 'true',
82
134
  interval: FILE_WATCHER.POLL_INTERVAL_MS,
83
135
  binaryInterval: FILE_WATCHER.BINARY_INTERVAL_MS,
@@ -87,7 +139,6 @@ export class FileWatcher {
87
139
  const fullPath = join(watchRoot, relativePath);
88
140
 
89
141
  if (process.env.ASD_DEBUG === '1') {
90
- console.log(`[Watch] 检测到文件变化: ${relativePath}`);
91
142
  }
92
143
 
93
144
  if (this.pathPrefix && !normalize(relativePath).startsWith(normalize(this.pathPrefix))) {
@@ -104,11 +155,8 @@ export class FileWatcher {
104
155
  this._watcher.on('error', (err) => console.error('文件监听错误:', err.message));
105
156
  this._watcher.on('ready', () => {
106
157
  if (!this.quiet) {
107
- console.log('文件监听器已就绪,等待文件变更...');
108
158
  }
109
159
  if (process.env.ASD_DEBUG === '1') {
110
- console.log(`[Watch] 监听目录: ${watchRoot}`);
111
- console.log(`[Watch] 监听模式: ${filePattern.join(', ')}`);
112
160
  }
113
161
  });
114
162
 
@@ -147,7 +195,9 @@ export class FileWatcher {
147
195
  try {
148
196
  accessSync(fullPath);
149
197
  const stat = statSync(fullPath);
150
- if (stat.isDirectory() || stat.size > FILE_WATCHER.MAX_FILE_SIZE_BYTES) return;
198
+ if (stat.isDirectory() || stat.size > FILE_WATCHER.MAX_FILE_SIZE_BYTES) {
199
+ return;
200
+ }
151
201
  } catch {
152
202
  return;
153
203
  }
@@ -164,13 +214,11 @@ export class FileWatcher {
164
214
  const verdict = saveEventFilter.shouldProcess(fullPath, data);
165
215
  if (!verdict.process) {
166
216
  if (process.env.ASD_DEBUG === '1') {
167
- console.log(`[Watch] 保存事件已过滤 (${verdict.reason}): ${relativePath}`);
168
217
  }
169
218
  return;
170
219
  }
171
220
 
172
221
  if (process.env.ASD_DEBUG === '1') {
173
- console.log(`[Watch] 读取文件内容成功,检查指令...`);
174
222
  }
175
223
 
176
224
  const filename = basename(fullPath);
@@ -184,13 +232,6 @@ export class FileWatcher {
184
232
  const triggers = detectTriggers(data, filename);
185
233
 
186
234
  if (process.env.ASD_DEBUG === '1') {
187
- console.log(`[Watch] 指令检测结果:`, {
188
- createLine: !!triggers.createLine,
189
- guardLine: !!triggers.guardLine,
190
- searchLine: !!triggers.searchLine,
191
- alinkLine: !!triggers.alinkLine,
192
- headerLine: !!triggers.headerLine,
193
- });
194
235
  }
195
236
 
196
237
  // // as:c — 创建候选
@@ -212,7 +253,7 @@ export class FileWatcher {
212
253
  if (triggers.alinkLine) {
213
254
  clearTimeout(this._timeoutLink);
214
255
  this._timeoutLink = setTimeout(() => {
215
- handleAlink(triggers.alinkLine).catch(err => {
256
+ handleAlink(triggers.alinkLine).catch((err) => {
216
257
  console.warn(`[Watcher] alink handler failed: ${err.message}`);
217
258
  });
218
259
  }, DEBOUNCE_DELAY);
@@ -229,7 +270,13 @@ export class FileWatcher {
229
270
  if (isMatch) {
230
271
  clearTimeout(this._timeoutHead);
231
272
  this._timeoutHead = setTimeout(() => {
232
- handleHeader(this, fullPath, triggers.headerLine, triggers.importArray, triggers.isSwift).catch(err => {
273
+ handleHeader(
274
+ this,
275
+ fullPath,
276
+ triggers.headerLine,
277
+ triggers.importArray,
278
+ triggers.isSwift
279
+ ).catch((err) => {
233
280
  console.warn(`[Watcher] header handler failed: ${err.message}`);
234
281
  });
235
282
  }, DEBOUNCE_DELAY);
@@ -244,11 +291,13 @@ export class FileWatcher {
244
291
  */
245
292
  async _appendCandidates(items, source) {
246
293
  // 过滤空 title / 空 code 的无效条目
247
- const validItems = items.filter(item => {
294
+ const validItems = items.filter((item) => {
248
295
  const title = (item.title || '').trim();
249
296
  const code = (item.code || '').trim();
250
297
  if (!title || !code) {
251
- console.warn(`[Watcher] 跳过无效候选: title=${JSON.stringify(title)}, code length=${code.length}`);
298
+ console.warn(
299
+ `[Watcher] 跳过无效候选: title=${JSON.stringify(title)}, code length=${code.length}`
300
+ );
252
301
  return false;
253
302
  }
254
303
  return true;
@@ -265,20 +314,23 @@ export class FileWatcher {
265
314
  const knowledgeService = container.get('knowledgeService');
266
315
  const context = { userId: 'filewatcher' };
267
316
  for (const item of validItems) {
268
- await knowledgeService.create({
269
- content: {
270
- pattern: item.code || '',
317
+ await knowledgeService.create(
318
+ {
319
+ content: {
320
+ pattern: item.code || '',
321
+ },
322
+ language: item.language || 'objc',
323
+ category: item.category || 'Utility',
324
+ source: source || 'watch',
325
+ title: item.title,
326
+ description: item.summary || item.description || '',
327
+ moduleName: item.moduleName || 'watch-create',
328
+ trigger: item.trigger || '',
329
+ headers: item.headers || [],
330
+ tags: item.tags || [],
271
331
  },
272
- language: item.language || 'objc',
273
- category: item.category || 'Utility',
274
- source: source || 'watch',
275
- title: item.title,
276
- description: item.summary || item.description || '',
277
- moduleName: item.moduleName || 'watch-create',
278
- trigger: item.trigger || '',
279
- headers: item.headers || [],
280
- tags: item.tags || [],
281
- }, context);
332
+ context
333
+ );
282
334
  }
283
335
  return;
284
336
  } catch (err) {
@@ -305,7 +357,9 @@ export class FileWatcher {
305
357
  headers: item.headers || [],
306
358
  }),
307
359
  });
308
- if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
360
+ if (!resp.ok) {
361
+ throw new Error(`HTTP ${resp.status}`);
362
+ }
309
363
  }
310
364
  return;
311
365
  } catch (err) {
@@ -328,7 +382,7 @@ export class FileWatcher {
328
382
  relativePath,
329
383
  text
330
384
  );
331
- if (resolved && resolved.headers && resolved.headers.length > 0) {
385
+ if (resolved?.headers && resolved.headers.length > 0) {
332
386
  item.headers = resolved.headers;
333
387
  item.headerPaths = resolved.headerPaths;
334
388
  item.moduleName = resolved.moduleName;
@@ -347,9 +401,7 @@ export class FileWatcher {
347
401
  const url = `${base}${path}`;
348
402
  import('../../infrastructure/external/OpenBrowser.js')
349
403
  .then(({ openBrowserReuseTab }) => openBrowserReuseTab(url, base))
350
- .catch(() => {
351
- console.log(`💡 请手动访问: ${url}`);
352
- });
404
+ .catch(() => {});
353
405
  }
354
406
 
355
407
  /**
@@ -357,8 +409,8 @@ export class FileWatcher {
357
409
  */
358
410
  _notify(msg) {
359
411
  import('../../infrastructure/external/NativeUi.js')
360
- .then(NU => NU.notify(msg))
361
- .catch(() => console.log(`[AutoSnippet] ${msg}`));
412
+ .then((NU) => NU.notify(msg))
413
+ .catch(() => {});
362
414
  }
363
415
 
364
416
  /**
@@ -372,10 +424,14 @@ export class FileWatcher {
372
424
  key,
373
425
  setTimeout(() => {
374
426
  this._debounceTimers.delete(key);
375
- Promise.resolve().then(() => fn()).catch((err) => {
376
- console.error('[Watch] 处理文件失败:', err.message);
377
- if (process.env.ASD_DEBUG === '1') console.error(err.stack);
378
- });
427
+ Promise.resolve()
428
+ .then(() => fn())
429
+ .catch((err) => {
430
+ console.error('[Watch] 处理文件失败:', err.message);
431
+ if (process.env.ASD_DEBUG === '1') {
432
+ console.error(err.stack);
433
+ }
434
+ });
379
435
  }, DEBOUNCE_DELAY)
380
436
  );
381
437
  }
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  export class TriggerResolver {
7
-
8
7
  /**
9
8
  * 规范化触发器
10
9
  * @param {object|string} trigger
@@ -57,9 +56,12 @@ export class TriggerResolver {
57
56
 
58
57
  #mapDirectiveType(name) {
59
58
  const map = {
60
- search: 'search', s: 'search',
61
- create: 'create', c: 'create',
62
- audit: 'audit', a: 'audit',
59
+ search: 'search',
60
+ s: 'search',
61
+ create: 'create',
62
+ c: 'create',
63
+ audit: 'audit',
64
+ a: 'audit',
63
65
  include: 'injection',
64
66
  import: 'injection',
65
67
  alink: 'alink',
@@ -16,7 +16,10 @@ export async function handleAlink(alinkLine) {
16
16
  const alinkMark = 'alink';
17
17
 
18
18
  if (alinkLine.includes(TRIGGER_SYMBOL)) {
19
- const parts = alinkLine.split(TRIGGER_SYMBOL).map((p) => p.trim()).filter(Boolean);
19
+ const parts = alinkLine
20
+ .split(TRIGGER_SYMBOL)
21
+ .map((p) => p.trim())
22
+ .filter(Boolean);
20
23
  if (parts.length >= 2 && parts[parts.length - 1] === alinkMark) {
21
24
  completionKey = parts[parts.length - 2];
22
25
  }
@@ -32,10 +35,14 @@ export async function handleAlink(alinkLine) {
32
35
  if (db) {
33
36
  const rawDb = typeof db.getDb === 'function' ? db.getDb() : db;
34
37
  try {
35
- const row = rawDb.prepare(
36
- 'SELECT id FROM knowledge_entries WHERE trigger = ? AND lifecycle = \'active\' LIMIT 1',
37
- ).get(completionKey);
38
- if (row) recipeId = row.id;
38
+ const row = rawDb
39
+ .prepare(
40
+ "SELECT id FROM knowledge_entries WHERE trigger = ? AND lifecycle = 'active' LIMIT 1"
41
+ )
42
+ .get(completionKey);
43
+ if (row) {
44
+ recipeId = row.id;
45
+ }
39
46
  } catch {
40
47
  // DB 查询失败时回退到搜索
41
48
  }
@@ -43,12 +50,18 @@ export async function handleAlink(alinkLine) {
43
50
  // 若精确匹配失败,尝试模糊搜索
44
51
  if (!recipeId) {
45
52
  try {
46
- const escaped = completionKey.replace(/[%_\\]/g, ch => `\\${ch}`);
47
- const row = rawDb.prepare(
48
- "SELECT id FROM knowledge_entries WHERE (trigger LIKE ? ESCAPE '\\' OR title LIKE ? ESCAPE '\\') AND lifecycle = 'active' LIMIT 1",
49
- ).get(`%${escaped}%`, `%${escaped}%`);
50
- if (row) recipeId = row.id;
51
- } catch { /* silent */ }
53
+ const escaped = completionKey.replace(/[%_\\]/g, (ch) => `\\${ch}`);
54
+ const row = rawDb
55
+ .prepare(
56
+ "SELECT id FROM knowledge_entries WHERE (trigger LIKE ? ESCAPE '\\' OR title LIKE ? ESCAPE '\\') AND lifecycle = 'active' LIMIT 1"
57
+ )
58
+ .get(`%${escaped}%`, `%${escaped}%`);
59
+ if (row) {
60
+ recipeId = row.id;
61
+ }
62
+ } catch {
63
+ /* silent */
64
+ }
52
65
  }
53
66
  }
54
67
 
@@ -61,7 +74,6 @@ export async function handleAlink(alinkLine) {
61
74
 
62
75
  const open = (await import('open')).default;
63
76
  await open(url);
64
- console.log(`[alink] completionKey=${completionKey} → ${url}`);
65
77
  } catch (err) {
66
78
  console.warn(`[alink] Failed to open link: ${err.message}`);
67
79
  }
@@ -4,8 +4,9 @@
4
4
  */
5
5
 
6
6
  import { readFileSync, writeFileSync } from 'node:fs';
7
+ import { LanguageService } from '../../../shared/LanguageService.js';
7
8
  import { REGEX } from '../DirectiveDetector.js';
8
- import { saveEventFilter } from '../SaveEventFilter.js';
9
+ import { saveEventFilter } from '../../../platform/ios/xcode/SaveEventFilter.js';
9
10
 
10
11
  /**
11
12
  * 处理 // as:c 指令
@@ -51,18 +52,12 @@ export async function handleCreate(watcher, fullPath, relativePath, createOption
51
52
  // 3. 无 -c 选项:打开 Dashboard
52
53
  if (createOption !== 'c') {
53
54
  const autoScan = createOption === 'f' ? '&autoScan=1' : '';
54
- console.log(
55
- createOption === 'f'
56
- ? '[as:create -f] 已打开 Dashboard,自动执行 Scan File'
57
- : '[as:create] 已打开 Dashboard,请选择 Scan File 或 Use Copied Code'
58
- );
59
55
  watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}${autoScan}`);
60
56
  return;
61
57
  }
62
58
 
63
59
  // 4. -c 模式:剪贴板为空则打开 Dashboard
64
60
  if (textToExtract.length === 0) {
65
- console.log('[as:create -c] 剪贴板为空,已打开 Dashboard');
66
61
  watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}`);
67
62
  return;
68
63
  }
@@ -72,7 +67,9 @@ export async function handleCreate(watcher, fullPath, relativePath, createOption
72
67
  await silentCreateCandidate(watcher, textToExtract, relativePath);
73
68
  } catch (e) {
74
69
  console.warn('[Watcher] 静默创建候选失败,回退到打开浏览器:', e.message);
75
- watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}&source=clipboard`);
70
+ watcher._openDashboard(
71
+ `/?action=create&path=${encodeURIComponent(relativePath)}&source=clipboard`
72
+ );
76
73
  }
77
74
  }
78
75
 
@@ -89,7 +86,7 @@ async function silentCreateCandidate(watcher, text, relativePath) {
89
86
  summary: r.summary || r.description || '',
90
87
  trigger: r.trigger,
91
88
  category: r.category || 'Utility',
92
- language: r.language === 'swift' ? 'swift' : 'objc',
89
+ language: r.language || 'unknown',
93
90
  code: r.code,
94
91
  usageGuide: r.usageGuide || '',
95
92
  headers: r.headers || [],
@@ -97,7 +94,7 @@ async function silentCreateCandidate(watcher, text, relativePath) {
97
94
 
98
95
  // 先尝试批量解析(仅对 Recipe Markdown 格式有效)
99
96
  const allRecipes = parser.parseAll(text);
100
- const validRecipes = allRecipes.filter(r => r.title && r.title.trim());
97
+ const validRecipes = allRecipes.filter((r) => r.title?.trim());
101
98
  if (validRecipes.length > 0) {
102
99
  const items = normalize(validRecipes);
103
100
  await watcher._resolveHeadersIfNeeded(items[0], relativePath, text);
@@ -106,7 +103,6 @@ async function silentCreateCandidate(watcher, text, relativePath) {
106
103
  validRecipes.length === 1
107
104
  ? `已创建候选「${validRecipes[0].title}」,请在 Dashboard Candidates 页审核`
108
105
  : `已创建 ${validRecipes.length} 条候选,请在 Dashboard Candidates 页审核`;
109
- console.log(`✅ [as:create] ${msg}`);
110
106
  watcher._notify(msg);
111
107
  return;
112
108
  }
@@ -114,11 +110,10 @@ async function silentCreateCandidate(watcher, text, relativePath) {
114
110
  // 尝试单条解析
115
111
  if (parser.isCompleteRecipe(text)) {
116
112
  const one = parser.parse(text);
117
- if (one && one.title && one.title.trim()) {
113
+ if (one?.title?.trim()) {
118
114
  const item = normalize([one])[0];
119
115
  await watcher._resolveHeadersIfNeeded(item, relativePath, text);
120
116
  await watcher._appendCandidates([item], 'watch-create');
121
- console.log(`✅ [as:create] 已静默创建候选「${one.title}」,请在 Dashboard Candidates 页审核`);
122
117
  watcher._notify(`已创建候选「${one.title}」,请在 Candidates 页审核`);
123
118
  return;
124
119
  }
@@ -126,10 +121,11 @@ async function silentCreateCandidate(watcher, text, relativePath) {
126
121
 
127
122
  // -c 模式:剪贴板内容整体作为一条候选(不拆分)
128
123
  // 先用 AI 生成标题和摘要,code 保持剪贴板原文
129
- const lang = relativePath && /\.swift$/i.test(relativePath) ? 'swift' : 'objc';
124
+ const lang = relativePath ? (LanguageService.inferLang(relativePath) || 'unknown') : 'unknown';
125
+ const ext = LanguageService.extForLang(lang) || '.txt';
130
126
  const fileName = relativePath
131
127
  ? relativePath.split('/').pop()
132
- : `clipboard.${lang === 'swift' ? 'swift' : 'm'}`;
128
+ : `clipboard${ext}`;
133
129
 
134
130
  let title = fileName.replace(/\.\w+$/, '') || 'Clipboard Snippet';
135
131
  let summary = '';
@@ -154,7 +150,9 @@ async function silentCreateCandidate(watcher, text, relativePath) {
154
150
  tags = aiResult.tags || [];
155
151
  trigger = aiResult.trigger || '';
156
152
  }
157
- } catch { /* AI 不可用,使用默认值 */ }
153
+ } catch {
154
+ /* AI 不可用,使用默认值 */
155
+ }
158
156
 
159
157
  const item = {
160
158
  title,
@@ -163,7 +161,7 @@ async function silentCreateCandidate(watcher, text, relativePath) {
163
161
  trigger,
164
162
  category,
165
163
  language: lang,
166
- code: text, // 剪贴板原文整体
164
+ code: text, // 剪贴板原文整体
167
165
  usageGuide,
168
166
  headers,
169
167
  tags,
@@ -171,7 +169,6 @@ async function silentCreateCandidate(watcher, text, relativePath) {
171
169
 
172
170
  await watcher._resolveHeadersIfNeeded(item, relativePath, text);
173
171
  await watcher._appendCandidates([item], 'watch-create');
174
- console.log(`✅ [as:create -c] 已创建候选「${title}」,请在 Candidates 页审核`);
175
172
  watcher._notify(`已创建候选「${title}」,请在 Candidates 页审核`);
176
173
  }
177
174
 
@@ -179,7 +176,9 @@ async function silentCreateCandidate(watcher, text, relativePath) {
179
176
  * 查找 // as:c 的行号 (1-based)
180
177
  */
181
178
  export function findCreateLineNumber(content) {
182
- if (!content) return -1;
179
+ if (!content) {
180
+ return -1;
181
+ }
183
182
  const lines = content.split(/\r?\n/);
184
183
  for (let i = 0; i < lines.length; i++) {
185
184
  const t = lines[i].trim();
@@ -191,5 +190,5 @@ export function findCreateLineNumber(content) {
191
190
  }
192
191
 
193
192
  function _sleep(ms) {
194
- return new Promise(resolve => setTimeout(resolve, ms));
193
+ return new Promise((resolve) => setTimeout(resolve, ms));
195
194
  }
@@ -2,6 +2,8 @@
2
2
  * DraftHandler — 处理 _draft_*.md 文件保存
3
3
  */
4
4
 
5
+ import { LanguageService } from '../../../shared/LanguageService.js';
6
+
5
7
  /**
6
8
  * @param {import('../FileWatcher.js').FileWatcher} watcher
7
9
  * @param {string} fullPath
@@ -9,7 +11,9 @@
9
11
  * @param {string} content
10
12
  */
11
13
  export async function handleDraft(watcher, fullPath, relativePath, content) {
12
- if (!content || content.trim().length < 20) return;
14
+ if (!content || content.trim().length < 20) {
15
+ return;
16
+ }
13
17
 
14
18
  try {
15
19
  const { RecipeParser } = await import('../../recipe/RecipeParser.js');
@@ -21,7 +25,7 @@ export async function handleDraft(watcher, fullPath, relativePath, content) {
21
25
  summary: r.summary || r.description || '',
22
26
  trigger: r.trigger,
23
27
  category: r.category || 'Utility',
24
- language: r.language === 'swift' ? 'swift' : 'objc',
28
+ language: r.language || 'unknown',
25
29
  code: r.code,
26
30
  usageGuide: r.usageGuide || '',
27
31
  headers: r.headers || [],
@@ -35,7 +39,6 @@ export async function handleDraft(watcher, fullPath, relativePath, content) {
35
39
  allRecipes.length === 1
36
40
  ? `已创建候选「${allRecipes[0].title}」`
37
41
  : `已创建 ${allRecipes.length} 条候选`;
38
- console.log(`✅ [_draft] ${msg},请在 Dashboard Candidates 页审核`);
39
42
  watcher._notify(msg);
40
43
  return;
41
44
  }
@@ -45,7 +48,6 @@ export async function handleDraft(watcher, fullPath, relativePath, content) {
45
48
  if (one) {
46
49
  const item = normalize([one])[0];
47
50
  await watcher._appendCandidates([item], 'draft-file');
48
- console.log(`✅ [_draft] 已创建候选「${one.title}」`);
49
51
  watcher._notify(`已创建候选「${one.title}」`);
50
52
  return;
51
53
  }
@@ -56,14 +58,18 @@ export async function handleDraft(watcher, fullPath, relativePath, content) {
56
58
  const { getServiceContainer } = await import('../../../injection/ServiceContainer.js');
57
59
  const container = getServiceContainer();
58
60
  const chatAgent = container.get('chatAgent');
59
- const lang = /\.swift$/i.test(relativePath) ? 'swift' : 'objc';
60
- const result = await chatAgent.executeTool('summarize_code', { code: content, language: lang });
61
+ const lang = LanguageService.inferLang(relativePath) || 'unknown';
62
+ const result = await chatAgent.executeTool('summarize_code', {
63
+ code: content,
64
+ language: lang,
65
+ });
61
66
  if (result && !result.error && result.title && result.code) {
62
67
  await watcher._appendCandidates([result], 'draft-file');
63
- console.log(`✅ [_draft] 已创建候选「${result.title}」`);
64
68
  watcher._notify(`已创建候选「${result.title}」`);
65
69
  }
66
- } catch { /* ChatAgent 不可用 */ }
70
+ } catch {
71
+ /* ChatAgent 不可用 */
72
+ }
67
73
  } catch (e) {
68
74
  console.warn('[Watcher] 草稿文件解析失败:', e.message);
69
75
  }