autosnippet 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/README.md +230 -324
  2. package/bin/api-server.js +1 -1
  3. package/bin/cli.js +204 -244
  4. package/bin/mcp-server.js +5 -3
  5. package/config/knowledge-base.config.js +132 -132
  6. package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
  7. package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
  8. package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
  9. package/dashboard/dist/index.html +3 -3
  10. package/lib/bootstrap.js +8 -8
  11. package/lib/cli/AiScanService.js +86 -40
  12. package/lib/cli/KnowledgeSyncService.js +113 -74
  13. package/lib/cli/SetupService.js +439 -277
  14. package/lib/cli/UpgradeService.js +63 -100
  15. package/lib/core/AstAnalyzer.js +276 -597
  16. package/lib/core/ast/ProjectGraph.js +101 -40
  17. package/lib/core/ast/ensure-grammars.js +232 -0
  18. package/lib/core/ast/index.js +115 -0
  19. package/lib/core/ast/lang-dart.js +661 -0
  20. package/lib/core/ast/lang-go.js +530 -0
  21. package/lib/core/ast/lang-java.js +435 -0
  22. package/lib/core/ast/lang-javascript.js +272 -0
  23. package/lib/core/ast/lang-kotlin.js +423 -0
  24. package/lib/core/ast/lang-objc.js +388 -0
  25. package/lib/core/ast/lang-python.js +371 -0
  26. package/lib/core/ast/lang-swift.js +337 -0
  27. package/lib/core/ast/lang-typescript.js +503 -0
  28. package/lib/core/capability/CapabilityProbe.js +18 -9
  29. package/lib/core/constitution/Constitution.js +2 -3
  30. package/lib/core/constitution/ConstitutionValidator.js +65 -24
  31. package/lib/core/discovery/DartDiscoverer.js +534 -0
  32. package/lib/core/discovery/DiscovererRegistry.js +83 -0
  33. package/lib/core/discovery/GenericDiscoverer.js +225 -0
  34. package/lib/core/discovery/GoDiscoverer.js +541 -0
  35. package/lib/core/discovery/JvmDiscoverer.js +506 -0
  36. package/lib/core/discovery/NodeDiscoverer.js +466 -0
  37. package/lib/core/discovery/ProjectDiscoverer.js +93 -0
  38. package/lib/core/discovery/PythonDiscoverer.js +338 -0
  39. package/lib/core/discovery/SpmDiscoverer.js +5 -0
  40. package/lib/core/discovery/index.js +53 -0
  41. package/lib/core/enhancement/EnhancementPack.js +71 -0
  42. package/lib/core/enhancement/EnhancementRegistry.js +47 -0
  43. package/lib/core/enhancement/android-enhancement.js +102 -0
  44. package/lib/core/enhancement/django-enhancement.js +70 -0
  45. package/lib/core/enhancement/fastapi-enhancement.js +63 -0
  46. package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
  47. package/lib/core/enhancement/go-web-enhancement.js +201 -0
  48. package/lib/core/enhancement/index.js +65 -0
  49. package/lib/core/enhancement/node-server-enhancement.js +88 -0
  50. package/lib/core/enhancement/react-enhancement.js +86 -0
  51. package/lib/core/enhancement/spring-enhancement.js +112 -0
  52. package/lib/core/enhancement/vue-enhancement.js +96 -0
  53. package/lib/core/gateway/Gateway.js +8 -9
  54. package/lib/core/gateway/GatewayActionRegistry.js +1 -1
  55. package/lib/core/permission/PermissionManager.js +12 -8
  56. package/lib/domain/index.js +13 -9
  57. package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
  58. package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
  59. package/lib/domain/knowledge/Lifecycle.js +22 -22
  60. package/lib/domain/knowledge/index.js +9 -12
  61. package/lib/domain/knowledge/values/Constraints.js +31 -21
  62. package/lib/domain/knowledge/values/Content.js +21 -13
  63. package/lib/domain/knowledge/values/Quality.js +31 -18
  64. package/lib/domain/knowledge/values/Reasoning.js +20 -12
  65. package/lib/domain/knowledge/values/Relations.js +37 -25
  66. package/lib/domain/knowledge/values/Stats.js +18 -12
  67. package/lib/domain/knowledge/values/index.js +4 -3
  68. package/lib/domain/snippet/Snippet.js +35 -10
  69. package/lib/external/ai/AiFactory.js +48 -16
  70. package/lib/external/ai/AiProvider.js +184 -90
  71. package/lib/external/ai/providers/ClaudeProvider.js +25 -12
  72. package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
  73. package/lib/external/ai/providers/MockProvider.js +9 -3
  74. package/lib/external/ai/providers/OpenAiProvider.js +51 -29
  75. package/lib/external/mcp/McpServer.js +66 -36
  76. package/lib/external/mcp/errorHandler.js +23 -11
  77. package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
  78. package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
  79. package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
  80. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
  81. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
  82. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
  83. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
  84. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
  85. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
  86. package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
  87. package/lib/external/mcp/handlers/bootstrap.js +691 -168
  88. package/lib/external/mcp/handlers/browse.js +66 -22
  89. package/lib/external/mcp/handlers/candidate.js +118 -35
  90. package/lib/external/mcp/handlers/consolidated.js +49 -17
  91. package/lib/external/mcp/handlers/guard.js +104 -39
  92. package/lib/external/mcp/handlers/knowledge.js +60 -36
  93. package/lib/external/mcp/handlers/search.js +43 -14
  94. package/lib/external/mcp/handlers/skill.js +120 -45
  95. package/lib/external/mcp/handlers/structure.js +240 -86
  96. package/lib/external/mcp/handlers/system.js +42 -12
  97. package/lib/external/mcp/handlers/wiki.js +58 -33
  98. package/lib/external/mcp/tools.js +306 -123
  99. package/lib/http/HttpServer.js +72 -47
  100. package/lib/http/middleware/RateLimiter.js +5 -3
  101. package/lib/http/middleware/errorHandler.js +6 -1
  102. package/lib/http/middleware/requestLogger.js +14 -3
  103. package/lib/http/middleware/roleResolver.js +30 -23
  104. package/lib/http/routes/ai.js +387 -265
  105. package/lib/http/routes/auth.js +81 -61
  106. package/lib/http/routes/candidates.js +430 -320
  107. package/lib/http/routes/commands.js +289 -189
  108. package/lib/http/routes/extract.js +158 -125
  109. package/lib/http/routes/guardRules.js +309 -217
  110. package/lib/http/routes/knowledge.js +213 -154
  111. package/lib/http/routes/modules.js +578 -0
  112. package/lib/http/routes/monitoring.js +6 -6
  113. package/lib/http/routes/recipes.js +104 -93
  114. package/lib/http/routes/search.js +361 -305
  115. package/lib/http/routes/skills.js +145 -98
  116. package/lib/http/routes/snippets.js +42 -30
  117. package/lib/http/routes/spm.js +3 -405
  118. package/lib/http/routes/violations.js +113 -93
  119. package/lib/http/routes/wiki.js +211 -170
  120. package/lib/http/utils/routeHelpers.js +3 -1
  121. package/lib/http/utils/sse-sessions.js +16 -6
  122. package/lib/http/utils/sse.js +15 -5
  123. package/lib/infrastructure/audit/AuditLogger.js +5 -2
  124. package/lib/infrastructure/audit/AuditStore.js +10 -7
  125. package/lib/infrastructure/cache/CacheService.js +3 -1
  126. package/lib/infrastructure/cache/GraphCache.js +8 -4
  127. package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
  128. package/lib/infrastructure/config/ConfigLoader.js +9 -5
  129. package/lib/infrastructure/config/Defaults.js +30 -10
  130. package/lib/infrastructure/config/Paths.js +28 -8
  131. package/lib/infrastructure/config/TriggerSymbol.js +22 -10
  132. package/lib/infrastructure/database/DatabaseConnection.js +15 -10
  133. package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
  134. package/lib/infrastructure/external/ClipboardManager.js +6 -2
  135. package/lib/infrastructure/external/NativeUi.js +50 -43
  136. package/lib/infrastructure/external/OpenBrowser.js +14 -17
  137. package/lib/infrastructure/external/XcodeAutomation.js +14 -258
  138. package/lib/infrastructure/logging/Logger.js +46 -30
  139. package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
  140. package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
  141. package/lib/infrastructure/paths/HeaderResolver.js +25 -9
  142. package/lib/infrastructure/paths/PathFinder.js +34 -12
  143. package/lib/infrastructure/plugin/PluginManager.js +26 -8
  144. package/lib/infrastructure/realtime/RealtimeService.js +2 -2
  145. package/lib/infrastructure/vector/Chunker.js +22 -7
  146. package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
  147. package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
  148. package/lib/infrastructure/vector/VectorStore.js +28 -10
  149. package/lib/injection/ServiceContainer.js +247 -93
  150. package/lib/platform/ios/index.js +63 -0
  151. package/lib/platform/ios/routes/spm.js +437 -0
  152. package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
  153. package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
  154. package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
  155. package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
  156. package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
  157. package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
  158. package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
  159. package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
  160. package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
  161. package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
  162. package/lib/repository/base/BaseRepository.js +7 -9
  163. package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
  164. package/lib/repository/token/TokenUsageStore.js +4 -2
  165. package/lib/service/automation/ActionPipeline.js +1 -1
  166. package/lib/service/automation/AutomationOrchestrator.js +8 -4
  167. package/lib/service/automation/ContextCollector.js +7 -5
  168. package/lib/service/automation/DirectiveDetector.js +23 -16
  169. package/lib/service/automation/FileWatcher.js +112 -56
  170. package/lib/service/automation/TriggerResolver.js +6 -4
  171. package/lib/service/automation/handlers/AlinkHandler.js +24 -12
  172. package/lib/service/automation/handlers/CreateHandler.js +19 -20
  173. package/lib/service/automation/handlers/DraftHandler.js +14 -8
  174. package/lib/service/automation/handlers/GuardHandler.js +93 -63
  175. package/lib/service/automation/handlers/HeaderHandler.js +1 -6
  176. package/lib/service/automation/handlers/SearchHandler.js +155 -88
  177. package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
  178. package/lib/service/candidate/SimilarityService.js +25 -9
  179. package/lib/service/chat/AnalystAgent.js +50 -24
  180. package/lib/service/chat/CandidateGuardrail.js +143 -17
  181. package/lib/service/chat/ChatAgent.js +759 -243
  182. package/lib/service/chat/ContextWindow.js +116 -71
  183. package/lib/service/chat/ConversationStore.js +77 -36
  184. package/lib/service/chat/EpisodicConsolidator.js +47 -23
  185. package/lib/service/chat/HandoffProtocol.js +98 -22
  186. package/lib/service/chat/Memory.js +34 -14
  187. package/lib/service/chat/ProducerAgent.js +40 -20
  188. package/lib/service/chat/ProjectSemanticMemory.js +109 -78
  189. package/lib/service/chat/ReasoningLayer.js +148 -70
  190. package/lib/service/chat/ReasoningTrace.js +44 -32
  191. package/lib/service/chat/TaskPipeline.js +39 -19
  192. package/lib/service/chat/ToolRegistry.js +48 -29
  193. package/lib/service/chat/WorkingMemory.js +44 -18
  194. package/lib/service/chat/tools.js +1096 -494
  195. package/lib/service/context/RecipeExtractor.js +132 -51
  196. package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
  197. package/lib/service/cursor/KnowledgeCompressor.js +25 -22
  198. package/lib/service/cursor/RulesGenerator.js +13 -7
  199. package/lib/service/cursor/SkillsSyncer.js +77 -27
  200. package/lib/service/cursor/TokenBudget.js +2 -2
  201. package/lib/service/cursor/TopicClassifier.js +54 -20
  202. package/lib/service/guard/ComplianceReporter.js +55 -43
  203. package/lib/service/guard/ExclusionManager.js +67 -29
  204. package/lib/service/guard/GuardCheckEngine.js +381 -86
  205. package/lib/service/guard/GuardFeedbackLoop.js +22 -10
  206. package/lib/service/guard/GuardService.js +29 -19
  207. package/lib/service/guard/RuleLearner.js +55 -23
  208. package/lib/service/guard/SourceFileCollector.js +27 -20
  209. package/lib/service/guard/ViolationsStore.js +43 -38
  210. package/lib/service/knowledge/CodeEntityGraph.js +147 -82
  211. package/lib/service/knowledge/ConfidenceRouter.js +12 -10
  212. package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
  213. package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
  214. package/lib/service/knowledge/KnowledgeService.js +222 -112
  215. package/lib/service/module/ModuleService.js +969 -0
  216. package/lib/service/quality/FeedbackCollector.js +27 -15
  217. package/lib/service/quality/QualityScorer.js +78 -24
  218. package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
  219. package/lib/service/recipe/RecipeParser.js +78 -45
  220. package/lib/service/search/CoarseRanker.js +43 -28
  221. package/lib/service/search/CrossEncoderReranker.js +32 -21
  222. package/lib/service/search/InvertedIndex.js +21 -7
  223. package/lib/service/search/MultiSignalRanker.js +90 -28
  224. package/lib/service/search/RetrievalFunnel.js +45 -24
  225. package/lib/service/search/SearchEngine.js +255 -103
  226. package/lib/service/skills/EventAggregator.js +32 -15
  227. package/lib/service/skills/SignalCollector.js +140 -64
  228. package/lib/service/skills/SkillAdvisor.js +79 -42
  229. package/lib/service/skills/SkillHooks.js +16 -14
  230. package/lib/service/snippet/PlaceholderConverter.js +5 -0
  231. package/lib/service/snippet/SnippetFactory.js +116 -99
  232. package/lib/service/snippet/SnippetInstaller.js +234 -62
  233. package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
  234. package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
  235. package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
  236. package/lib/service/wiki/WikiGenerator.js +637 -263
  237. package/lib/shared/DimensionCopyRegistry.js +472 -0
  238. package/lib/shared/LanguageService.js +399 -0
  239. package/lib/shared/PathGuard.js +45 -28
  240. package/lib/shared/RecipeReadinessChecker.js +72 -12
  241. package/lib/shared/constants.js +41 -41
  242. package/lib/shared/errors/BaseError.js +2 -2
  243. package/lib/shared/errors/index.js +4 -4
  244. package/lib/shared/similarity.js +25 -8
  245. package/lib/shared/token-utils.js +6 -2
  246. package/lib/shared/utils/common.js +12 -4
  247. package/package.json +49 -13
  248. package/scripts/bench-real-projects.mjs +256 -0
  249. package/scripts/build-native-ui.js +30 -30
  250. package/scripts/clear-old-vector-index.js +5 -35
  251. package/scripts/clear-vector-cache.js +7 -37
  252. package/scripts/collect-test-project-stats.mjs +160 -0
  253. package/scripts/diagnose-mcp.js +41 -32
  254. package/scripts/ensure-parse-package.js +6 -9
  255. package/scripts/generate-recipe-drafts.js +116 -77
  256. package/scripts/init-db.js +3 -20
  257. package/scripts/init-snippets.js +305 -0
  258. package/scripts/init-vector-db.js +173 -170
  259. package/scripts/install-cursor-skill.js +148 -104
  260. package/scripts/install-full.js +8 -21
  261. package/scripts/install-vscode-copilot.js +146 -145
  262. package/scripts/migrate-md-to-knowledge.mjs +139 -151
  263. package/scripts/postinstall-safe.js +5 -17
  264. package/scripts/recipe-audit.js +106 -82
  265. package/scripts/release.js +283 -323
  266. package/scripts/setup-mcp-config.js +60 -52
  267. package/scripts/verify-context-api.js +20 -20
  268. package/skills/autosnippet-analysis/SKILL.md +10 -6
  269. package/skills/autosnippet-candidates/SKILL.md +27 -26
  270. package/skills/autosnippet-coldstart/SKILL.md +555 -38
  271. package/skills/autosnippet-concepts/SKILL.md +349 -337
  272. package/skills/autosnippet-create/SKILL.md +5 -5
  273. package/skills/autosnippet-reference-dart/SKILL.md +543 -0
  274. package/skills/autosnippet-reference-go/SKILL.md +539 -0
  275. package/skills/autosnippet-reference-java/SKILL.md +534 -0
  276. package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
  277. package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
  278. package/skills/autosnippet-reference-objc/SKILL.md +29 -6
  279. package/skills/autosnippet-reference-python/SKILL.md +800 -0
  280. package/skills/autosnippet-reference-swift/SKILL.md +70 -14
  281. package/skills/autosnippet-structure/SKILL.md +4 -4
  282. package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
  283. package/templates/recipes-setup/README.md +2 -2
  284. package/templates/recipes-setup/_template.md +1 -1
  285. package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
  286. package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
  287. package/resources/asd-entry/main.swift +0 -159
  288. package/scripts/build-asd-entry.js +0 -51
  289. package/scripts/init-xcode-snippets.js +0 -311
  290. package/template.json +0 -39
@@ -37,7 +37,7 @@ export class BaseRepository {
37
37
  if (!this.#columnWhitelist) {
38
38
  try {
39
39
  const cols = this.db.prepare(`PRAGMA table_info(${this.tableName})`).all();
40
- this.#columnWhitelist = new Set(cols.map(c => c.name));
40
+ this.#columnWhitelist = new Set(cols.map((c) => c.name));
41
41
  } catch {
42
42
  this.#columnWhitelist = new Set();
43
43
  }
@@ -63,7 +63,7 @@ export class BaseRepository {
63
63
  SELECT * FROM ${this.tableName} WHERE id = ? LIMIT 1
64
64
  `);
65
65
  const row = stmt.get(id);
66
-
66
+
67
67
  if (!row) {
68
68
  return null;
69
69
  }
@@ -141,11 +141,7 @@ export class BaseRepository {
141
141
  // 获取分页数据
142
142
  query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
143
143
  const dataStmt = this.db.prepare(query);
144
- const data = dataStmt.all(
145
- ...params.slice(0, Object.keys(filters).length),
146
- pageSize,
147
- offset
148
- );
144
+ const data = dataStmt.all(...params.slice(0, Object.keys(filters).length), pageSize, offset);
149
145
 
150
146
  return {
151
147
  data: data.map((row) => this._mapRowToEntity(row)),
@@ -171,8 +167,10 @@ export class BaseRepository {
171
167
  try {
172
168
  const updateKeys = Object.keys(updates);
173
169
  const updateValues = Object.values(updates);
174
-
175
- for (const key of updateKeys) this._assertSafeColumn(key);
170
+
171
+ for (const key of updateKeys) {
172
+ this._assertSafeColumn(key);
173
+ }
176
174
  const setClause = updateKeys.map((key) => `${key} = ?`).join(', ');
177
175
  const query = `
178
176
  UPDATE ${this.tableName}
@@ -1,7 +1,7 @@
1
- import { BaseRepository } from '../base/BaseRepository.js';
2
- import { KnowledgeEntry, Lifecycle, inferKind } from '../../domain/knowledge/index.js';
1
+ import { inferKind, KnowledgeEntry } from '../../domain/knowledge/index.js';
3
2
  import Logger from '../../infrastructure/logging/Logger.js';
4
3
  import { safeJsonParse, safeJsonStringify, unixNow } from '../../shared/utils/common.js';
4
+ import { BaseRepository } from '../base/BaseRepository.js';
5
5
 
6
6
  /**
7
7
  * KnowledgeRepositoryImpl — 统一知识实体仓储实现
@@ -52,7 +52,9 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
52
52
  async update(id, updates) {
53
53
  try {
54
54
  const existing = await this.findById(id);
55
- if (!existing) throw new Error(`Knowledge entry not found: ${id}`);
55
+ if (!existing) {
56
+ throw new Error(`Knowledge entry not found: ${id}`);
57
+ }
56
58
 
57
59
  if (updates instanceof KnowledgeEntry) {
58
60
  const row = this._entityToRow(updates);
@@ -60,8 +62,11 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
60
62
  delete row.createdAt;
61
63
  row.updatedAt = unixNow();
62
64
 
63
- const setClauses = Object.keys(row).map(k => `${k} = ?`).join(', ');
64
- this.db.prepare(`UPDATE knowledge_entries SET ${setClauses} WHERE id = ?`)
65
+ const setClauses = Object.keys(row)
66
+ .map((k) => `${k} = ?`)
67
+ .join(', ');
68
+ this.db
69
+ .prepare(`UPDATE knowledge_entries SET ${setClauses} WHERE id = ?`)
65
70
  .run(...Object.values(row), id);
66
71
  return this.findById(id);
67
72
  }
@@ -76,8 +81,11 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
76
81
  delete row.id;
77
82
  delete row.createdAt;
78
83
 
79
- const setClauses = Object.keys(row).map(k => `${k} = ?`).join(', ');
80
- this.db.prepare(`UPDATE knowledge_entries SET ${setClauses} WHERE id = ?`)
84
+ const setClauses = Object.keys(row)
85
+ .map((k) => `${k} = ?`)
86
+ .join(', ');
87
+ this.db
88
+ .prepare(`UPDATE knowledge_entries SET ${setClauses} WHERE id = ?`)
81
89
  .run(...Object.values(row), id);
82
90
  return this.findById(id);
83
91
  } catch (error) {
@@ -125,7 +133,9 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
125
133
  }
126
134
 
127
135
  for (const [key, value] of Object.entries(normalFilters)) {
128
- if (value == null) continue;
136
+ if (value == null) {
137
+ continue;
138
+ }
129
139
  this._assertSafeColumn(key);
130
140
  conditions.push(`${key} = ?`);
131
141
  params.push(value);
@@ -133,14 +143,16 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
133
143
 
134
144
  if (_tagLike) {
135
145
  conditions.push(`tags LIKE ?`);
136
- const escaped = _tagLike.replace(/[%_\\]/g, ch => `\\${ch}`);
146
+ const escaped = _tagLike.replace(/[%_\\]/g, (ch) => `\\${ch}`);
137
147
  params.push(`%"${escaped}"%`);
138
148
  }
139
149
 
140
150
  if (_search) {
141
- const escaped = _search.replace(/[%_\\]/g, ch => `\\${ch}`);
151
+ const escaped = _search.replace(/[%_\\]/g, (ch) => `\\${ch}`);
142
152
  const like = `%${escaped}%`;
143
- conditions.push(`(title LIKE ? ESCAPE '\\' OR description LIKE ? ESCAPE '\\' OR trigger LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\' OR tags LIKE ? ESCAPE '\\')`);
153
+ conditions.push(
154
+ `(title LIKE ? ESCAPE '\\' OR description LIKE ? ESCAPE '\\' OR trigger LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\' OR tags LIKE ? ESCAPE '\\')`
155
+ );
144
156
  params.push(like, like, like, like, like);
145
157
  }
146
158
 
@@ -149,12 +161,15 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
149
161
  this._assertSafeColumn(orderBy);
150
162
  const orderClause = ` ORDER BY ${orderBy} ${order === 'ASC' ? 'ASC' : 'DESC'}`;
151
163
 
152
- const total = this.db.prepare(`SELECT COUNT(*) as count FROM knowledge_entries${where}`).get(...params).count;
153
- const data = this.db.prepare(`SELECT * FROM knowledge_entries${where}${orderClause} LIMIT ? OFFSET ?`)
164
+ const total = this.db
165
+ .prepare(`SELECT COUNT(*) as count FROM knowledge_entries${where}`)
166
+ .get(...params).count;
167
+ const data = this.db
168
+ .prepare(`SELECT * FROM knowledge_entries${where}${orderClause} LIMIT ? OFFSET ?`)
154
169
  .all(...params, pageSize, offset);
155
170
 
156
171
  return {
157
- data: data.map(row => this._rowToEntity(row)),
172
+ data: data.map((row) => this._rowToEntity(row)),
158
173
  pagination: { page, pageSize, total, pages: Math.ceil(total / pageSize) },
159
174
  };
160
175
  }
@@ -172,7 +187,9 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
172
187
  async findByKind(kind, options = {}) {
173
188
  const { lifecycle, ...pagination } = options;
174
189
  const filters = { kind };
175
- if (lifecycle) filters.lifecycle = lifecycle;
190
+ if (lifecycle) {
191
+ filters.lifecycle = lifecycle;
192
+ }
176
193
  return this.findWithPagination(filters, pagination);
177
194
  }
178
195
 
@@ -182,11 +199,13 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
182
199
  */
183
200
  async findActiveRules() {
184
201
  try {
185
- const rows = this.db.prepare(`
202
+ const rows = this.db
203
+ .prepare(`
186
204
  SELECT * FROM knowledge_entries
187
205
  WHERE kind = 'rule' AND lifecycle = 'active'
188
- `).all();
189
- return rows.map(row => this._rowToEntity(row));
206
+ `)
207
+ .all();
208
+ return rows.map((row) => this._rowToEntity(row));
190
209
  } catch (error) {
191
210
  this.logger.error('Error finding active rules', { error: error.message });
192
211
  throw error;
@@ -219,7 +238,8 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
219
238
  */
220
239
  async getStats() {
221
240
  try {
222
- return this.db.prepare(`
241
+ return this.db
242
+ .prepare(`
223
243
  SELECT
224
244
  COUNT(*) as total,
225
245
  SUM(CASE WHEN lifecycle = 'pending' THEN 1 ELSE 0 END) as pending,
@@ -229,7 +249,8 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
229
249
  SUM(CASE WHEN kind = 'pattern' THEN 1 ELSE 0 END) as patterns,
230
250
  SUM(CASE WHEN kind = 'fact' THEN 1 ELSE 0 END) as facts
231
251
  FROM knowledge_entries
232
- `).get();
252
+ `)
253
+ .get();
233
254
  } catch (error) {
234
255
  this.logger.error('Error getting knowledge stats', { error: error.message });
235
256
  throw error;
@@ -244,25 +265,27 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
244
265
  * @returns {KnowledgeEntry}
245
266
  */
246
267
  _rowToEntity(row) {
247
- if (!row) return null;
268
+ if (!row) {
269
+ return null;
270
+ }
248
271
 
249
272
  return new KnowledgeEntry({
250
273
  ...row,
251
274
  // JSON 列需要 parse
252
275
  lifecycleHistory: safeJsonParse(row.lifecycleHistory, []),
253
- tags: safeJsonParse(row.tags, []),
254
- content: safeJsonParse(row.content, {}),
255
- relations: safeJsonParse(row.relations, {}),
256
- constraints: safeJsonParse(row.constraints, {}),
257
- reasoning: safeJsonParse(row.reasoning, {}),
258
- quality: safeJsonParse(row.quality, {}),
259
- stats: safeJsonParse(row.stats, {}),
260
- headers: safeJsonParse(row.headers, []),
261
- headerPaths: safeJsonParse(row.headerPaths, []),
262
- agentNotes: safeJsonParse(row.agentNotes, null),
276
+ tags: safeJsonParse(row.tags, []),
277
+ content: safeJsonParse(row.content, {}),
278
+ relations: safeJsonParse(row.relations, {}),
279
+ constraints: safeJsonParse(row.constraints, {}),
280
+ reasoning: safeJsonParse(row.reasoning, {}),
281
+ quality: safeJsonParse(row.quality, {}),
282
+ stats: safeJsonParse(row.stats, {}),
283
+ headers: safeJsonParse(row.headers, []),
284
+ headerPaths: safeJsonParse(row.headerPaths, []),
285
+ agentNotes: safeJsonParse(row.agentNotes, null),
263
286
  // SQLite INTEGER → boolean
264
- autoApprovable: !!row.autoApprovable,
265
- includeHeaders: !!row.includeHeaders,
287
+ autoApprovable: !!row.autoApprovable,
288
+ includeHeaders: !!row.includeHeaders,
266
289
  });
267
290
  }
268
291
 
@@ -274,49 +297,49 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
274
297
  _entityToRow(e) {
275
298
  const now = unixNow();
276
299
  return {
277
- id: e.id,
278
- title: e.title,
279
- description: e.description || '',
280
- lifecycle: e.lifecycle,
281
- lifecycleHistory: safeJsonStringify(e.lifecycleHistory || [], '[]'),
282
- autoApprovable: e.autoApprovable ? 1 : 0,
283
- language: e.language,
284
- category: e.category,
285
- kind: e.kind || inferKind(e.knowledgeType),
286
- knowledgeType: e.knowledgeType || 'code-pattern',
287
- complexity: e.complexity || 'intermediate',
288
- scope: e.scope || null,
289
- difficulty: e.difficulty || null,
290
- tags: safeJsonStringify(e.tags || [], '[]'),
291
- trigger: e.trigger || '',
292
- topicHint: e.topicHint || '',
293
- whenClause: e.whenClause || '',
294
- doClause: e.doClause || '',
295
- dontClause: e.dontClause || '',
296
- coreCode: e.coreCode || '',
297
- content: safeJsonStringify(e.content || {}),
298
- relations: safeJsonStringify(e.relations || {}),
299
- constraints: safeJsonStringify(e.constraints || {}),
300
- reasoning: safeJsonStringify(e.reasoning || {}),
301
- quality: safeJsonStringify(e.quality || {}),
302
- stats: safeJsonStringify(e.stats || {}),
303
- headers: safeJsonStringify(e.headers || [], '[]'),
304
- headerPaths: safeJsonStringify(e.headerPaths || [], '[]'),
305
- moduleName: e.moduleName || null,
306
- includeHeaders: e.includeHeaders ? 1 : 0,
307
- agentNotes: e.agentNotes ? safeJsonStringify(e.agentNotes) : null,
308
- aiInsight: e.aiInsight || null,
309
- reviewedBy: e.reviewedBy || null,
310
- reviewedAt: e.reviewedAt || null,
311
- rejectionReason: e.rejectionReason || null,
312
- source: e.source || 'manual',
313
- sourceFile: e.sourceFile || null,
300
+ id: e.id,
301
+ title: e.title,
302
+ description: e.description || '',
303
+ lifecycle: e.lifecycle,
304
+ lifecycleHistory: safeJsonStringify(e.lifecycleHistory || [], '[]'),
305
+ autoApprovable: e.autoApprovable ? 1 : 0,
306
+ language: e.language,
307
+ category: e.category,
308
+ kind: e.kind || inferKind(e.knowledgeType),
309
+ knowledgeType: e.knowledgeType || 'code-pattern',
310
+ complexity: e.complexity || 'intermediate',
311
+ scope: e.scope || null,
312
+ difficulty: e.difficulty || null,
313
+ tags: safeJsonStringify(e.tags || [], '[]'),
314
+ trigger: e.trigger || '',
315
+ topicHint: e.topicHint || '',
316
+ whenClause: e.whenClause || '',
317
+ doClause: e.doClause || '',
318
+ dontClause: e.dontClause || '',
319
+ coreCode: e.coreCode || '',
320
+ content: safeJsonStringify(e.content || {}),
321
+ relations: safeJsonStringify(e.relations || {}),
322
+ constraints: safeJsonStringify(e.constraints || {}),
323
+ reasoning: safeJsonStringify(e.reasoning || {}),
324
+ quality: safeJsonStringify(e.quality || {}),
325
+ stats: safeJsonStringify(e.stats || {}),
326
+ headers: safeJsonStringify(e.headers || [], '[]'),
327
+ headerPaths: safeJsonStringify(e.headerPaths || [], '[]'),
328
+ moduleName: e.moduleName || null,
329
+ includeHeaders: e.includeHeaders ? 1 : 0,
330
+ agentNotes: e.agentNotes ? safeJsonStringify(e.agentNotes) : null,
331
+ aiInsight: e.aiInsight || null,
332
+ reviewedBy: e.reviewedBy || null,
333
+ reviewedAt: e.reviewedAt || null,
334
+ rejectionReason: e.rejectionReason || null,
335
+ source: e.source || 'manual',
336
+ sourceFile: e.sourceFile || null,
314
337
  sourceCandidateId: e.sourceCandidateId || null,
315
- createdBy: e.createdBy || 'system',
316
- createdAt: e.createdAt || now,
317
- updatedAt: e.updatedAt || now,
318
- publishedAt: e.publishedAt || null,
319
- publishedBy: e.publishedBy || null,
338
+ createdBy: e.createdBy || 'system',
339
+ createdAt: e.createdAt || now,
340
+ updatedAt: e.updatedAt || now,
341
+ publishedAt: e.publishedAt || null,
342
+ publishedBy: e.publishedBy || null,
320
343
  };
321
344
  }
322
345
 
@@ -81,7 +81,9 @@ export class TokenUsageStore {
81
81
  try {
82
82
  const now = Date.now();
83
83
  const total = (record.inputTokens || 0) + (record.outputTokens || 0);
84
- if (total === 0) return; // 跳过无消耗的调用
84
+ if (total === 0) {
85
+ return; // 跳过无消耗的调用
86
+ }
85
87
 
86
88
  this.#insertStmt.run(
87
89
  now,
@@ -94,7 +96,7 @@ export class TokenUsageStore {
94
96
  total,
95
97
  record.durationMs || null,
96
98
  record.toolCalls || 0,
97
- record.sessionId || null,
99
+ record.sessionId || null
98
100
  );
99
101
 
100
102
  // 写入后使缓存失效
@@ -6,7 +6,7 @@
6
6
  import Logger from '../../infrastructure/logging/Logger.js';
7
7
 
8
8
  export class ActionPipeline {
9
- #actions; // Map<type, handler>
9
+ #actions; // Map<type, handler>
10
10
  #logger;
11
11
 
12
12
  constructor() {
@@ -4,9 +4,9 @@
4
4
  */
5
5
 
6
6
  import Logger from '../../infrastructure/logging/Logger.js';
7
- import { TriggerResolver } from './TriggerResolver.js';
8
- import { ContextCollector } from './ContextCollector.js';
9
7
  import { ActionPipeline } from './ActionPipeline.js';
8
+ import { ContextCollector } from './ContextCollector.js';
9
+ import { TriggerResolver } from './TriggerResolver.js';
10
10
 
11
11
  export class AutomationOrchestrator {
12
12
  #triggerResolver;
@@ -33,7 +33,9 @@ export class AutomationOrchestrator {
33
33
  const resolvedTrigger = this.#triggerResolver.resolve(trigger);
34
34
  const collectedContext = this.#contextCollector.collect(context);
35
35
 
36
- this.#logger.info(`[AutomationOrchestrator] run type=${resolvedTrigger.type} name=${resolvedTrigger.name || ''}`);
36
+ this.#logger.info(
37
+ `[AutomationOrchestrator] run type=${resolvedTrigger.type} name=${resolvedTrigger.name || ''}`
38
+ );
37
39
 
38
40
  const pipelineResult = await this.#pipeline.execute(resolvedTrigger, collectedContext);
39
41
 
@@ -44,7 +46,9 @@ export class AutomationOrchestrator {
44
46
  timestamp: new Date().toISOString(),
45
47
  };
46
48
  this.#history.push(record);
47
- if (this.#history.length > 200) this.#history = this.#history.slice(-200);
49
+ if (this.#history.length > 200) {
50
+ this.#history = this.#history.slice(-200);
51
+ }
48
52
 
49
53
  return { ...pipelineResult, resolvedTrigger };
50
54
  }
@@ -3,8 +3,9 @@
3
3
  * 收集并规范化自动化执行所需的上下文信息
4
4
  */
5
5
 
6
- export class ContextCollector {
6
+ import { LanguageService } from '../../shared/LanguageService.js';
7
7
 
8
+ export class ContextCollector {
8
9
  /**
9
10
  * 收集上下文
10
11
  * @param {object} rawContext - 原始上下文
@@ -27,9 +28,10 @@ export class ContextCollector {
27
28
  }
28
29
 
29
30
  #detectLanguage(filePath) {
30
- if (!filePath) return null;
31
- const ext = filePath.split('.').pop()?.toLowerCase();
32
- const map = { swift: 'swift', m: 'objc', h: 'objc', js: 'javascript', ts: 'typescript', py: 'python' };
33
- return map[ext] || null;
31
+ if (!filePath) {
32
+ return null;
33
+ }
34
+ const lang = LanguageService.inferLang(filePath);
35
+ return lang === 'unknown' ? null : lang;
34
36
  }
35
37
  }
@@ -5,10 +5,8 @@
5
5
  * V2 ESM 版本,对应 V1 DirectiveDetector.js
6
6
  */
7
7
 
8
- import {
9
- TRIGGER_SYMBOL,
10
- stripTriggerPrefix,
11
- } from '../../infrastructure/config/TriggerSymbol.js';
8
+ import { stripTriggerPrefix, TRIGGER_SYMBOL } from '../../infrastructure/config/TriggerSymbol.js';
9
+ import { LanguageService } from '../../shared/LanguageService.js';
12
10
 
13
11
  /**
14
12
  * 指令标记常量
@@ -43,6 +41,15 @@ export const REGEX = {
43
41
  DRAFT_FILE: /^_draft_.*\.md$/i,
44
42
  };
45
43
 
44
+ /**
45
+ * 推断文件语言 —— 委托给 LanguageService
46
+ * @param {string} filename
47
+ * @returns {string}
48
+ */
49
+ function _inferLanguage(filename) {
50
+ return LanguageService.inferLang(filename);
51
+ }
52
+
46
53
  /**
47
54
  * 检测文件内容中的所有触发指令
48
55
  *
@@ -50,12 +57,15 @@ export const REGEX = {
50
57
  * @param {string} filename 文件名
51
58
  * @returns {{ importArray: string[], headerLine: string|null, alinkLine: string|null,
52
59
  * createLine: string|null, createOption: string|null,
53
- * guardLine: string|null, searchLine: string|null, isSwift: boolean }}
60
+ * guardLine: string|null, searchLine: string|null, isSwift: boolean, language: string }}
54
61
  */
55
62
  export function detectTriggers(data, filename) {
56
- const isSwift = filename.endsWith('.swift');
63
+ const language = _inferLanguage(filename);
64
+ const isSwift = language === 'swift';
65
+ // Import/header 自动插入目前仅支持 ObjC/Swift(Xcode 工作流)
66
+ const isApple = isSwift || language === 'objectivec';
57
67
  const currImportReg = isSwift ? REGEX.IMPORT_SWIFT : REGEX.IMPORT_OBJC;
58
- const currHeaderReg = isSwift ? REGEX.HEADER_SWIFT : REGEX.HEADER_OBJC;
68
+ const _currHeaderReg = isSwift ? REGEX.HEADER_SWIFT : REGEX.HEADER_OBJC;
59
69
 
60
70
  const triggers = {
61
71
  importArray: [],
@@ -65,7 +75,8 @@ export function detectTriggers(data, filename) {
65
75
  createOption: null,
66
76
  guardLine: null,
67
77
  searchLine: null,
68
- isSwift,
78
+ isSwift, // backward compat
79
+ language, // v3.1 多语言标识
69
80
  };
70
81
 
71
82
  const lines = data.split('\n');
@@ -73,8 +84,8 @@ export function detectTriggers(data, filename) {
73
84
  const lineVal = line.trim();
74
85
  const normalizedLineVal = stripTriggerPrefix(lineVal);
75
86
 
76
- // import 收集
77
- if (currImportReg.test(lineVal)) {
87
+ // import 收集(仅 ObjC/Swift — Xcode 头文件工作流)
88
+ if (isApple && currImportReg.test(lineVal)) {
78
89
  triggers.importArray.push(lineVal);
79
90
  }
80
91
 
@@ -84,10 +95,7 @@ export function detectTriggers(data, filename) {
84
95
  }
85
96
 
86
97
  // alink 指令
87
- if (
88
- lineVal.startsWith(TRIGGER_SYMBOL) &&
89
- lineVal.endsWith(TRIGGER_SYMBOL + MARKS.ALINK)
90
- ) {
98
+ if (lineVal.startsWith(TRIGGER_SYMBOL) && lineVal.endsWith(TRIGGER_SYMBOL + MARKS.ALINK)) {
91
99
  triggers.alinkLine = lineVal;
92
100
  }
93
101
 
@@ -95,8 +103,7 @@ export function detectTriggers(data, filename) {
95
103
  const createMatch = normalizedLineVal.match(REGEX.CREATE_LINE);
96
104
  if (createMatch) {
97
105
  triggers.createLine = lineVal;
98
- triggers.createOption =
99
- createMatch[1] === '-c' ? 'c' : createMatch[1] === '-f' ? 'f' : null;
106
+ triggers.createOption = createMatch[1] === '-c' ? 'c' : createMatch[1] === '-f' ? 'f' : null;
100
107
  }
101
108
 
102
109
  // guard/audit 指令