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
@@ -0,0 +1,338 @@
1
+ /**
2
+ * @module PythonDiscoverer
3
+ * @description Python 项目结构发现器
4
+ *
5
+ * 检测信号: pyproject.toml, setup.py, setup.cfg, requirements.txt, *.py
6
+ * 支持: pyproject.toml (PEP 621), setup.py, src 布局, 平铺布局
7
+ */
8
+
9
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
10
+ import { basename, join, relative } from 'node:path';
11
+ import { ProjectDiscoverer } from './ProjectDiscoverer.js';
12
+
13
+ const EXCLUDE_DIRS = new Set([
14
+ '__pycache__',
15
+ '.venv',
16
+ 'venv',
17
+ '.tox',
18
+ '.git',
19
+ '.mypy_cache',
20
+ '.pytest_cache',
21
+ '.eggs',
22
+ 'dist',
23
+ 'build',
24
+ 'node_modules',
25
+ '.nox',
26
+ '.ruff_cache',
27
+ ]);
28
+
29
+ export class PythonDiscoverer extends ProjectDiscoverer {
30
+ #projectRoot = null;
31
+ #targets = [];
32
+ #depGraph = { nodes: [], edges: [] };
33
+ #projectName = null;
34
+
35
+ get id() {
36
+ return 'python';
37
+ }
38
+ get displayName() {
39
+ return 'Python (pip/poetry/pdm)';
40
+ }
41
+
42
+ async detect(projectRoot) {
43
+ let confidence = 0;
44
+ const reasons = [];
45
+
46
+ if (existsSync(join(projectRoot, 'pyproject.toml'))) {
47
+ confidence = 0.9;
48
+ reasons.push('pyproject.toml exists');
49
+ }
50
+ if (existsSync(join(projectRoot, 'setup.py'))) {
51
+ confidence = Math.max(confidence, 0.8);
52
+ reasons.push('setup.py exists');
53
+ }
54
+ if (existsSync(join(projectRoot, 'setup.cfg'))) {
55
+ confidence = Math.max(confidence, 0.8);
56
+ reasons.push('setup.cfg exists');
57
+ }
58
+ if (existsSync(join(projectRoot, 'requirements.txt'))) {
59
+ confidence = Math.max(confidence, 0.6);
60
+ reasons.push('requirements.txt exists');
61
+ }
62
+
63
+ // 检查是否有 .py 文件
64
+ if (confidence === 0) {
65
+ try {
66
+ const entries = readdirSync(projectRoot);
67
+ if (entries.some((e) => e.endsWith('.py'))) {
68
+ confidence = 0.4;
69
+ reasons.push('*.py files found at root');
70
+ }
71
+ } catch {
72
+ /* skip */
73
+ }
74
+ }
75
+
76
+ return {
77
+ match: confidence > 0,
78
+ confidence: Math.min(confidence, 1.0),
79
+ reason: reasons.join(', ') || 'No Python markers found',
80
+ };
81
+ }
82
+
83
+ async load(projectRoot) {
84
+ this.#projectRoot = projectRoot;
85
+ this.#targets = [];
86
+ this.#depGraph = { nodes: [], edges: [] };
87
+
88
+ // 解析 pyproject.toml(简易 TOML 解析)
89
+ const pyprojectPath = join(projectRoot, 'pyproject.toml');
90
+ let pyproject = null;
91
+ if (existsSync(pyprojectPath)) {
92
+ pyproject = this.#parsePyprojectToml(readFileSync(pyprojectPath, 'utf8'));
93
+ }
94
+
95
+ this.#projectName = pyproject?.project?.name || basename(projectRoot);
96
+
97
+ // 发现包目录
98
+ const packages = this.#discoverPackages(projectRoot, pyproject);
99
+
100
+ for (const pkg of packages) {
101
+ const framework = this.#detectFramework(projectRoot, pyproject);
102
+ this.#targets.push({
103
+ name: pkg.name,
104
+ path: pkg.path,
105
+ type: pkg.isTest ? 'test' : 'library',
106
+ language: 'python',
107
+ framework,
108
+ metadata: { pyproject },
109
+ });
110
+ this.#depGraph.nodes.push(pkg.name);
111
+ }
112
+
113
+ // 如果没有发现任何包, 以项目根为兜底
114
+ if (this.#targets.length === 0) {
115
+ this.#targets.push({
116
+ name: this.#projectName,
117
+ path: projectRoot,
118
+ type: 'library',
119
+ language: 'python',
120
+ framework: this.#detectFramework(projectRoot, pyproject),
121
+ metadata: { pyproject },
122
+ });
123
+ this.#depGraph.nodes.push(this.#projectName);
124
+ }
125
+
126
+ // 解析依赖
127
+ this.#parseDependencies(projectRoot, pyproject);
128
+ }
129
+
130
+ async listTargets() {
131
+ return this.#targets;
132
+ }
133
+
134
+ async getTargetFiles(target) {
135
+ const targetPath =
136
+ typeof target === 'string'
137
+ ? this.#targets.find((t) => t.name === target)?.path || this.#projectRoot
138
+ : target.path;
139
+
140
+ if (!targetPath || !existsSync(targetPath)) {
141
+ return [];
142
+ }
143
+
144
+ const files = [];
145
+ this.#collectPyFiles(targetPath, targetPath, files);
146
+ return files;
147
+ }
148
+
149
+ async getDependencyGraph() {
150
+ return this.#depGraph;
151
+ }
152
+
153
+ // ── 内部实现 ──
154
+
155
+ #discoverPackages(projectRoot, pyproject) {
156
+ const packages = [];
157
+
158
+ // src/ 布局优先
159
+ const srcDir = join(projectRoot, 'src');
160
+ if (existsSync(srcDir)) {
161
+ try {
162
+ const entries = readdirSync(srcDir, { withFileTypes: true });
163
+ for (const entry of entries) {
164
+ if (entry.isDirectory() && !entry.name.startsWith('.') && !entry.name.startsWith('_')) {
165
+ const pkgDir = join(srcDir, entry.name);
166
+ if (existsSync(join(pkgDir, '__init__.py'))) {
167
+ packages.push({ name: entry.name, path: pkgDir, isTest: false });
168
+ }
169
+ }
170
+ }
171
+ } catch {
172
+ /* skip */
173
+ }
174
+ }
175
+
176
+ // 平铺布局: 含 __init__.py 的顶层目录
177
+ if (packages.length === 0) {
178
+ try {
179
+ const entries = readdirSync(projectRoot, { withFileTypes: true });
180
+ for (const entry of entries) {
181
+ if (entry.isDirectory() && !entry.name.startsWith('.') && !EXCLUDE_DIRS.has(entry.name)) {
182
+ const pkgDir = join(projectRoot, entry.name);
183
+ if (existsSync(join(pkgDir, '__init__.py'))) {
184
+ const isTest = /^tests?$/.test(entry.name);
185
+ packages.push({ name: entry.name, path: pkgDir, isTest });
186
+ }
187
+ }
188
+ }
189
+ } catch {
190
+ /* skip */
191
+ }
192
+ }
193
+
194
+ // 检测 tests/ 目录
195
+ for (const testDir of ['tests', 'test']) {
196
+ const testPath = join(projectRoot, testDir);
197
+ if (existsSync(testPath) && !packages.some((p) => p.name === testDir)) {
198
+ packages.push({ name: testDir, path: testPath, isTest: true });
199
+ }
200
+ }
201
+
202
+ return packages;
203
+ }
204
+
205
+ #detectFramework(projectRoot, pyproject) {
206
+ const deps = this.#extractDependencyNames(projectRoot, pyproject);
207
+
208
+ if (deps.has('django')) {
209
+ return 'django';
210
+ }
211
+ if (deps.has('flask')) {
212
+ return 'flask';
213
+ }
214
+ if (deps.has('fastapi')) {
215
+ return 'fastapi';
216
+ }
217
+ if (deps.has('torch') || deps.has('tensorflow')) {
218
+ return 'ml';
219
+ }
220
+ if (deps.has('scrapy')) {
221
+ return 'scrapy';
222
+ }
223
+ if (deps.has('celery')) {
224
+ return 'celery';
225
+ }
226
+ return null;
227
+ }
228
+
229
+ #extractDependencyNames(projectRoot, pyproject) {
230
+ const names = new Set();
231
+
232
+ // From pyproject.toml
233
+ if (pyproject?.project?.dependencies) {
234
+ for (const dep of pyproject.project.dependencies) {
235
+ const name = dep
236
+ .replace(/[>=<![\]~;@\s].*/g, '')
237
+ .trim()
238
+ .toLowerCase();
239
+ if (name) {
240
+ names.add(name);
241
+ }
242
+ }
243
+ }
244
+
245
+ // From requirements.txt
246
+ const reqPath = join(projectRoot, 'requirements.txt');
247
+ if (existsSync(reqPath)) {
248
+ try {
249
+ const content = readFileSync(reqPath, 'utf8');
250
+ for (const line of content.split('\n')) {
251
+ const trimmed = line.trim();
252
+ if (trimmed && !trimmed.startsWith('#') && !trimmed.startsWith('-')) {
253
+ const name = trimmed
254
+ .replace(/[>=<![\]~;@\s].*/g, '')
255
+ .trim()
256
+ .toLowerCase();
257
+ if (name) {
258
+ names.add(name);
259
+ }
260
+ }
261
+ }
262
+ } catch {
263
+ /* skip */
264
+ }
265
+ }
266
+
267
+ return names;
268
+ }
269
+
270
+ #parseDependencies(projectRoot, pyproject) {
271
+ const names = this.#extractDependencyNames(projectRoot, pyproject);
272
+ const rootTarget = this.#targets[0]?.name;
273
+ if (!rootTarget) {
274
+ return;
275
+ }
276
+
277
+ for (const dep of names) {
278
+ this.#depGraph.edges.push({ from: rootTarget, to: dep, type: 'depends_on' });
279
+ }
280
+ }
281
+
282
+ #collectPyFiles(dir, rootDir, files, depth = 0) {
283
+ if (depth > 15) {
284
+ return;
285
+ }
286
+ try {
287
+ const entries = readdirSync(dir, { withFileTypes: true });
288
+ for (const entry of entries) {
289
+ if (entry.name.startsWith('.')) {
290
+ continue;
291
+ }
292
+ if (EXCLUDE_DIRS.has(entry.name)) {
293
+ continue;
294
+ }
295
+
296
+ const fullPath = join(dir, entry.name);
297
+ if (entry.isDirectory()) {
298
+ this.#collectPyFiles(fullPath, rootDir, files, depth + 1);
299
+ } else if (entry.isFile() && entry.name.endsWith('.py')) {
300
+ files.push({
301
+ name: entry.name,
302
+ path: fullPath,
303
+ relativePath: relative(rootDir, fullPath),
304
+ language: 'python',
305
+ });
306
+ }
307
+ }
308
+ } catch {
309
+ /* skip */
310
+ }
311
+ }
312
+
313
+ /**
314
+ * 简易 TOML 解析器 — 仅提取本项目需要的字段
315
+ * 不做完整 TOML 解析, 只用正则提取关键信息
316
+ */
317
+ #parsePyprojectToml(content) {
318
+ const result = { project: {} };
319
+
320
+ // [project] name
321
+ const nameMatch = content.match(/\[project\][\s\S]*?name\s*=\s*["']([^"']+)["']/);
322
+ if (nameMatch) {
323
+ result.project.name = nameMatch[1];
324
+ }
325
+
326
+ // [project] dependencies — 简化提取数组
327
+ const depsMatch = content.match(/\[project\][\s\S]*?dependencies\s*=\s*\[([\s\S]*?)\]/);
328
+ if (depsMatch) {
329
+ result.project.dependencies = [];
330
+ const items = depsMatch[1].matchAll(/["']([^"']+)["']/g);
331
+ for (const m of items) {
332
+ result.project.dependencies.push(m[1]);
333
+ }
334
+ }
335
+
336
+ return result;
337
+ }
338
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @deprecated Moved to lib/platform/ios/spm/SpmDiscoverer.js
3
+ * This re-export shim maintains backward compatibility.
4
+ */
5
+ export { SpmDiscoverer } from '../../platform/ios/spm/SpmDiscoverer.js';
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @module discovery/index
3
+ * @description ProjectDiscoverer 系统入口 — 初始化 Registry 并注册所有 Discoverer
4
+ */
5
+
6
+ import { DartDiscoverer } from './DartDiscoverer.js';
7
+ import { DiscovererRegistry } from './DiscovererRegistry.js';
8
+ import { GenericDiscoverer } from './GenericDiscoverer.js';
9
+ import { GoDiscoverer } from './GoDiscoverer.js';
10
+ import { JvmDiscoverer } from './JvmDiscoverer.js';
11
+ import { NodeDiscoverer } from './NodeDiscoverer.js';
12
+ import { PythonDiscoverer } from './PythonDiscoverer.js';
13
+ import { SpmDiscoverer } from './SpmDiscoverer.js';
14
+
15
+ /** @type {DiscovererRegistry|null} */
16
+ let _registry = null;
17
+
18
+ /**
19
+ * 获取全局 DiscovererRegistry 单例
20
+ * @returns {DiscovererRegistry}
21
+ */
22
+ export function getDiscovererRegistry() {
23
+ if (!_registry) {
24
+ _registry = new DiscovererRegistry();
25
+ _registry
26
+ .register(new SpmDiscoverer())
27
+ .register(new NodeDiscoverer())
28
+ .register(new PythonDiscoverer())
29
+ .register(new JvmDiscoverer())
30
+ .register(new GoDiscoverer())
31
+ .register(new DartDiscoverer())
32
+ .register(new GenericDiscoverer());
33
+ }
34
+ return _registry;
35
+ }
36
+
37
+ /**
38
+ * 重置 Registry(仅用于测试)
39
+ */
40
+ export function resetDiscovererRegistry() {
41
+ _registry = null;
42
+ }
43
+
44
+ export { DartDiscoverer } from './DartDiscoverer.js';
45
+ export { DiscovererRegistry } from './DiscovererRegistry.js';
46
+ export { GenericDiscoverer } from './GenericDiscoverer.js';
47
+ export { GoDiscoverer } from './GoDiscoverer.js';
48
+ export { JvmDiscoverer } from './JvmDiscoverer.js';
49
+ export { NodeDiscoverer } from './NodeDiscoverer.js';
50
+ // Re-exports
51
+ export { ProjectDiscoverer } from './ProjectDiscoverer.js';
52
+ export { PythonDiscoverer } from './PythonDiscoverer.js';
53
+ export { SpmDiscoverer } from './SpmDiscoverer.js';
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @module EnhancementPack
3
+ * @description 语言/框架特有增强能力包 — 接口定义
4
+ *
5
+ * 每个增强包负责:
6
+ * - 额外的 Bootstrap 维度
7
+ * - 额外的 Guard 规则
8
+ * - 额外的设计模式检测
9
+ * - SFC 预处理(.vue → 提取 <script>)
10
+ * - Reference Skill 路径
11
+ */
12
+
13
+ export class EnhancementPack {
14
+ /** 增强包 ID @returns {string} */
15
+ get id() {
16
+ throw new Error('Not implemented');
17
+ }
18
+
19
+ /** 适用条件 @returns {{ languages: string[], frameworks?: string[] }} */
20
+ get conditions() {
21
+ throw new Error('Not implemented');
22
+ }
23
+
24
+ /** 人类可读名称 @returns {string} */
25
+ get displayName() {
26
+ return this.id;
27
+ }
28
+
29
+ /**
30
+ * 额外的 Bootstrap 维度定义
31
+ * @returns {Array<object>}
32
+ */
33
+ getExtraDimensions() {
34
+ return [];
35
+ }
36
+
37
+ /**
38
+ * 额外的 Guard 规则
39
+ * @returns {Array<object>}
40
+ */
41
+ getGuardRules() {
42
+ return [];
43
+ }
44
+
45
+ /**
46
+ * 额外的设计模式检测
47
+ * @param {object} astSummary — analyzeFile/analyzeProject 的返回值
48
+ * @returns {Array<{ type: string, className?: string, line?: number, confidence: number }>}
49
+ */
50
+ detectPatterns(astSummary) {
51
+ return [];
52
+ }
53
+
54
+ /**
55
+ * SFC 预处理器 — 将非标准文件转换为可解析的脚本内容
56
+ * @param {string} content — 原始文件内容
57
+ * @param {string} ext — 文件扩展名 (含 .)
58
+ * @returns {{ content: string, lang: string } | null}
59
+ */
60
+ preprocessFile(content, ext) {
61
+ return null;
62
+ }
63
+
64
+ /**
65
+ * Reference Skill 路径(Bootstrap 时自动加载,相对于 skills/ 目录)
66
+ * @returns {string|null}
67
+ */
68
+ getReferenceSkillPath() {
69
+ return null;
70
+ }
71
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @module EnhancementRegistry
3
+ * @description 增强包注册与自动选择
4
+ *
5
+ * Bootstrap 完成 Phase 1 后,根据主语言 + 检测到的框架自动筛选增强包。
6
+ */
7
+
8
+ export class EnhancementRegistry {
9
+ /** @type {import('./EnhancementPack.js').EnhancementPack[]} */
10
+ #packs = [];
11
+
12
+ /**
13
+ * 注册增强包
14
+ * @param {import('./EnhancementPack.js').EnhancementPack} pack
15
+ */
16
+ register(pack) {
17
+ this.#packs.push(pack);
18
+ return this;
19
+ }
20
+
21
+ /**
22
+ * 根据语言和框架筛选适用的增强包
23
+ * @param {string} primaryLang
24
+ * @param {string[]} detectedFrameworks
25
+ * @returns {import('./EnhancementPack.js').EnhancementPack[]}
26
+ */
27
+ resolve(primaryLang, detectedFrameworks = []) {
28
+ return this.#packs.filter((pack) => {
29
+ const cond = pack.conditions;
30
+ if (!cond) {
31
+ return false;
32
+ }
33
+ const langMatch = !cond.languages || cond.languages.includes(primaryLang);
34
+ const fwMatch =
35
+ !cond.frameworks || cond.frameworks.some((f) => detectedFrameworks.includes(f));
36
+ return langMatch && (cond.frameworks ? fwMatch : true);
37
+ });
38
+ }
39
+
40
+ /**
41
+ * 获取所有已注册的增强包
42
+ * @returns {import('./EnhancementPack.js').EnhancementPack[]}
43
+ */
44
+ all() {
45
+ return [...this.#packs];
46
+ }
47
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Android Enhancement Pack
3
+ * 条件: { languages: ['kotlin', 'java'], frameworks: ['android'] }
4
+ */
5
+
6
+ import { EnhancementPack } from './EnhancementPack.js';
7
+
8
+ class AndroidEnhancement extends EnhancementPack {
9
+ get id() {
10
+ return 'android';
11
+ }
12
+ get displayName() {
13
+ return 'Android (Kotlin/Java) Enhancement';
14
+ }
15
+ get conditions() {
16
+ return { languages: ['kotlin', 'java'], frameworks: ['android'] };
17
+ }
18
+
19
+ getExtraDimensions() {
20
+ return [
21
+ {
22
+ id: 'android-lifecycle-scan',
23
+ label: 'Activity/Fragment 生命周期',
24
+ guide:
25
+ 'Activity/Fragment 生命周期方法合规检查、ViewModel 使用、LiveData/StateFlow 状态管理',
26
+ knowledgeTypes: ['architecture', 'best-practice'],
27
+ skillWorthy: true,
28
+ dualOutput: true,
29
+ skillMeta: {
30
+ name: 'project-android-lifecycle',
31
+ description:
32
+ 'Android lifecycle compliance and ViewModel patterns (auto-generated by enhancement)',
33
+ },
34
+ },
35
+ {
36
+ id: 'android-compose-scan',
37
+ label: 'Jetpack Compose 分析',
38
+ guide: '@Composable 函数组织与状态管理、remember/rememberSaveable 使用、Side Effect API',
39
+ knowledgeTypes: ['code-pattern'],
40
+ skillWorthy: true,
41
+ dualOutput: true,
42
+ skillMeta: {
43
+ name: 'project-android-compose',
44
+ description:
45
+ 'Jetpack Compose patterns and state management (auto-generated by enhancement)',
46
+ },
47
+ },
48
+ ];
49
+ }
50
+
51
+ detectPatterns(astSummary) {
52
+ const patterns = [];
53
+ for (const cls of astSummary.classes || []) {
54
+ // ViewModel
55
+ if (cls.superclass && /ViewModel$/.test(cls.superclass)) {
56
+ patterns.push({
57
+ type: 'android-viewmodel',
58
+ className: cls.name,
59
+ line: cls.line,
60
+ confidence: 0.9,
61
+ });
62
+ }
63
+ // Activity / Fragment
64
+ if (
65
+ cls.superclass &&
66
+ /Activity$|AppCompatActivity$|ComponentActivity$/.test(cls.superclass)
67
+ ) {
68
+ patterns.push({
69
+ type: 'android-activity',
70
+ className: cls.name,
71
+ line: cls.line,
72
+ confidence: 0.9,
73
+ });
74
+ }
75
+ if (cls.superclass && /Fragment$/.test(cls.superclass)) {
76
+ patterns.push({
77
+ type: 'android-fragment',
78
+ className: cls.name,
79
+ line: cls.line,
80
+ confidence: 0.9,
81
+ });
82
+ }
83
+ // Hilt DI
84
+ const annos = cls.annotations || [];
85
+ if (annos.some((a) => /@HiltAndroidApp|@AndroidEntryPoint/.test(a))) {
86
+ patterns.push({ type: 'hilt-di', className: cls.name, line: cls.line, confidence: 0.95 });
87
+ }
88
+ // Composable (class-level)
89
+ if (annos.some((a) => /@Composable/.test(a))) {
90
+ patterns.push({
91
+ type: 'composable',
92
+ className: cls.name,
93
+ line: cls.line,
94
+ confidence: 0.95,
95
+ });
96
+ }
97
+ }
98
+ return patterns;
99
+ }
100
+ }
101
+
102
+ export const pack = new AndroidEnhancement();
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Django Enhancement Pack
3
+ * 条件: { languages: ['python'], frameworks: ['django'] }
4
+ */
5
+
6
+ import { EnhancementPack } from './EnhancementPack.js';
7
+
8
+ class DjangoEnhancement extends EnhancementPack {
9
+ get id() {
10
+ return 'django';
11
+ }
12
+ get displayName() {
13
+ return 'Django Enhancement';
14
+ }
15
+ get conditions() {
16
+ return { languages: ['python'], frameworks: ['django'] };
17
+ }
18
+
19
+ getExtraDimensions() {
20
+ return [
21
+ {
22
+ id: 'django-model-scan',
23
+ label: 'Django Model 扫描',
24
+ guide:
25
+ 'Model 字段与关系扫描(ForeignKey/ManyToMany/OneToOne)、Manager 自定义、QuerySet 链路',
26
+ knowledgeTypes: ['architecture', 'code-pattern'],
27
+ skillWorthy: true,
28
+ dualOutput: true,
29
+ skillMeta: {
30
+ name: 'project-django-models',
31
+ description:
32
+ 'Django Model definitions, field relationships and custom managers (auto-generated by enhancement)',
33
+ },
34
+ },
35
+ ];
36
+ }
37
+
38
+ detectPatterns(astSummary) {
39
+ const patterns = [];
40
+ for (const cls of astSummary.classes || []) {
41
+ if (cls.superclass && /Model$/.test(cls.superclass)) {
42
+ patterns.push({
43
+ type: 'django-model',
44
+ className: cls.name,
45
+ line: cls.line,
46
+ confidence: 0.9,
47
+ });
48
+ }
49
+ if (cls.superclass && /View$|ViewSet$/.test(cls.superclass)) {
50
+ patterns.push({
51
+ type: 'django-view',
52
+ className: cls.name,
53
+ line: cls.line,
54
+ confidence: 0.85,
55
+ });
56
+ }
57
+ if (cls.superclass && /BaseCommand/.test(cls.superclass)) {
58
+ patterns.push({
59
+ type: 'django-management-command',
60
+ className: cls.name,
61
+ line: cls.line,
62
+ confidence: 0.9,
63
+ });
64
+ }
65
+ }
66
+ return patterns;
67
+ }
68
+ }
69
+
70
+ export const pack = new DjangoEnhancement();