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.
- package/README.md +230 -324
- package/bin/api-server.js +1 -1
- package/bin/cli.js +204 -244
- package/bin/mcp-server.js +5 -3
- package/config/knowledge-base.config.js +132 -132
- package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
- package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
- package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/bootstrap.js +8 -8
- package/lib/cli/AiScanService.js +86 -40
- package/lib/cli/KnowledgeSyncService.js +113 -74
- package/lib/cli/SetupService.js +439 -277
- package/lib/cli/UpgradeService.js +63 -100
- package/lib/core/AstAnalyzer.js +276 -597
- package/lib/core/ast/ProjectGraph.js +101 -40
- package/lib/core/ast/ensure-grammars.js +232 -0
- package/lib/core/ast/index.js +115 -0
- package/lib/core/ast/lang-dart.js +661 -0
- package/lib/core/ast/lang-go.js +530 -0
- package/lib/core/ast/lang-java.js +435 -0
- package/lib/core/ast/lang-javascript.js +272 -0
- package/lib/core/ast/lang-kotlin.js +423 -0
- package/lib/core/ast/lang-objc.js +388 -0
- package/lib/core/ast/lang-python.js +371 -0
- package/lib/core/ast/lang-swift.js +337 -0
- package/lib/core/ast/lang-typescript.js +503 -0
- package/lib/core/capability/CapabilityProbe.js +18 -9
- package/lib/core/constitution/Constitution.js +2 -3
- package/lib/core/constitution/ConstitutionValidator.js +65 -24
- package/lib/core/discovery/DartDiscoverer.js +534 -0
- package/lib/core/discovery/DiscovererRegistry.js +83 -0
- package/lib/core/discovery/GenericDiscoverer.js +225 -0
- package/lib/core/discovery/GoDiscoverer.js +541 -0
- package/lib/core/discovery/JvmDiscoverer.js +506 -0
- package/lib/core/discovery/NodeDiscoverer.js +466 -0
- package/lib/core/discovery/ProjectDiscoverer.js +93 -0
- package/lib/core/discovery/PythonDiscoverer.js +338 -0
- package/lib/core/discovery/SpmDiscoverer.js +5 -0
- package/lib/core/discovery/index.js +53 -0
- package/lib/core/enhancement/EnhancementPack.js +71 -0
- package/lib/core/enhancement/EnhancementRegistry.js +47 -0
- package/lib/core/enhancement/android-enhancement.js +102 -0
- package/lib/core/enhancement/django-enhancement.js +70 -0
- package/lib/core/enhancement/fastapi-enhancement.js +63 -0
- package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
- package/lib/core/enhancement/go-web-enhancement.js +201 -0
- package/lib/core/enhancement/index.js +65 -0
- package/lib/core/enhancement/node-server-enhancement.js +88 -0
- package/lib/core/enhancement/react-enhancement.js +86 -0
- package/lib/core/enhancement/spring-enhancement.js +112 -0
- package/lib/core/enhancement/vue-enhancement.js +96 -0
- package/lib/core/gateway/Gateway.js +8 -9
- package/lib/core/gateway/GatewayActionRegistry.js +1 -1
- package/lib/core/permission/PermissionManager.js +12 -8
- package/lib/domain/index.js +13 -9
- package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
- package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
- package/lib/domain/knowledge/Lifecycle.js +22 -22
- package/lib/domain/knowledge/index.js +9 -12
- package/lib/domain/knowledge/values/Constraints.js +31 -21
- package/lib/domain/knowledge/values/Content.js +21 -13
- package/lib/domain/knowledge/values/Quality.js +31 -18
- package/lib/domain/knowledge/values/Reasoning.js +20 -12
- package/lib/domain/knowledge/values/Relations.js +37 -25
- package/lib/domain/knowledge/values/Stats.js +18 -12
- package/lib/domain/knowledge/values/index.js +4 -3
- package/lib/domain/snippet/Snippet.js +35 -10
- package/lib/external/ai/AiFactory.js +48 -16
- package/lib/external/ai/AiProvider.js +184 -90
- package/lib/external/ai/providers/ClaudeProvider.js +25 -12
- package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
- package/lib/external/ai/providers/MockProvider.js +9 -3
- package/lib/external/ai/providers/OpenAiProvider.js +51 -29
- package/lib/external/mcp/McpServer.js +66 -36
- package/lib/external/mcp/errorHandler.js +23 -11
- package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
- package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
- package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
- package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
- package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
- package/lib/external/mcp/handlers/bootstrap.js +691 -168
- package/lib/external/mcp/handlers/browse.js +66 -22
- package/lib/external/mcp/handlers/candidate.js +118 -35
- package/lib/external/mcp/handlers/consolidated.js +49 -17
- package/lib/external/mcp/handlers/guard.js +104 -39
- package/lib/external/mcp/handlers/knowledge.js +60 -36
- package/lib/external/mcp/handlers/search.js +43 -14
- package/lib/external/mcp/handlers/skill.js +120 -45
- package/lib/external/mcp/handlers/structure.js +240 -86
- package/lib/external/mcp/handlers/system.js +42 -12
- package/lib/external/mcp/handlers/wiki.js +58 -33
- package/lib/external/mcp/tools.js +306 -123
- package/lib/http/HttpServer.js +72 -47
- package/lib/http/middleware/RateLimiter.js +5 -3
- package/lib/http/middleware/errorHandler.js +6 -1
- package/lib/http/middleware/requestLogger.js +14 -3
- package/lib/http/middleware/roleResolver.js +30 -23
- package/lib/http/routes/ai.js +387 -265
- package/lib/http/routes/auth.js +81 -61
- package/lib/http/routes/candidates.js +430 -320
- package/lib/http/routes/commands.js +289 -189
- package/lib/http/routes/extract.js +158 -125
- package/lib/http/routes/guardRules.js +309 -217
- package/lib/http/routes/knowledge.js +213 -154
- package/lib/http/routes/modules.js +578 -0
- package/lib/http/routes/monitoring.js +6 -6
- package/lib/http/routes/recipes.js +104 -93
- package/lib/http/routes/search.js +361 -305
- package/lib/http/routes/skills.js +145 -98
- package/lib/http/routes/snippets.js +42 -30
- package/lib/http/routes/spm.js +3 -405
- package/lib/http/routes/violations.js +113 -93
- package/lib/http/routes/wiki.js +211 -170
- package/lib/http/utils/routeHelpers.js +3 -1
- package/lib/http/utils/sse-sessions.js +16 -6
- package/lib/http/utils/sse.js +15 -5
- package/lib/infrastructure/audit/AuditLogger.js +5 -2
- package/lib/infrastructure/audit/AuditStore.js +10 -7
- package/lib/infrastructure/cache/CacheService.js +3 -1
- package/lib/infrastructure/cache/GraphCache.js +8 -4
- package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
- package/lib/infrastructure/config/ConfigLoader.js +9 -5
- package/lib/infrastructure/config/Defaults.js +30 -10
- package/lib/infrastructure/config/Paths.js +28 -8
- package/lib/infrastructure/config/TriggerSymbol.js +22 -10
- package/lib/infrastructure/database/DatabaseConnection.js +15 -10
- package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
- package/lib/infrastructure/external/ClipboardManager.js +6 -2
- package/lib/infrastructure/external/NativeUi.js +50 -43
- package/lib/infrastructure/external/OpenBrowser.js +14 -17
- package/lib/infrastructure/external/XcodeAutomation.js +14 -258
- package/lib/infrastructure/logging/Logger.js +46 -30
- package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
- package/lib/infrastructure/paths/HeaderResolver.js +25 -9
- package/lib/infrastructure/paths/PathFinder.js +34 -12
- package/lib/infrastructure/plugin/PluginManager.js +26 -8
- package/lib/infrastructure/realtime/RealtimeService.js +2 -2
- package/lib/infrastructure/vector/Chunker.js +22 -7
- package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
- package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
- package/lib/infrastructure/vector/VectorStore.js +28 -10
- package/lib/injection/ServiceContainer.js +247 -93
- package/lib/platform/ios/index.js +63 -0
- package/lib/platform/ios/routes/spm.js +437 -0
- package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
- package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
- package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
- package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
- package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
- package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
- package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
- package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
- package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
- package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
- package/lib/repository/base/BaseRepository.js +7 -9
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
- package/lib/repository/token/TokenUsageStore.js +4 -2
- package/lib/service/automation/ActionPipeline.js +1 -1
- package/lib/service/automation/AutomationOrchestrator.js +8 -4
- package/lib/service/automation/ContextCollector.js +7 -5
- package/lib/service/automation/DirectiveDetector.js +23 -16
- package/lib/service/automation/FileWatcher.js +112 -56
- package/lib/service/automation/TriggerResolver.js +6 -4
- package/lib/service/automation/handlers/AlinkHandler.js +24 -12
- package/lib/service/automation/handlers/CreateHandler.js +19 -20
- package/lib/service/automation/handlers/DraftHandler.js +14 -8
- package/lib/service/automation/handlers/GuardHandler.js +93 -63
- package/lib/service/automation/handlers/HeaderHandler.js +1 -6
- package/lib/service/automation/handlers/SearchHandler.js +155 -88
- package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
- package/lib/service/candidate/SimilarityService.js +25 -9
- package/lib/service/chat/AnalystAgent.js +50 -24
- package/lib/service/chat/CandidateGuardrail.js +143 -17
- package/lib/service/chat/ChatAgent.js +759 -243
- package/lib/service/chat/ContextWindow.js +116 -71
- package/lib/service/chat/ConversationStore.js +77 -36
- package/lib/service/chat/EpisodicConsolidator.js +47 -23
- package/lib/service/chat/HandoffProtocol.js +98 -22
- package/lib/service/chat/Memory.js +34 -14
- package/lib/service/chat/ProducerAgent.js +40 -20
- package/lib/service/chat/ProjectSemanticMemory.js +109 -78
- package/lib/service/chat/ReasoningLayer.js +148 -70
- package/lib/service/chat/ReasoningTrace.js +44 -32
- package/lib/service/chat/TaskPipeline.js +39 -19
- package/lib/service/chat/ToolRegistry.js +48 -29
- package/lib/service/chat/WorkingMemory.js +44 -18
- package/lib/service/chat/tools.js +1096 -494
- package/lib/service/context/RecipeExtractor.js +132 -51
- package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
- package/lib/service/cursor/KnowledgeCompressor.js +25 -22
- package/lib/service/cursor/RulesGenerator.js +13 -7
- package/lib/service/cursor/SkillsSyncer.js +77 -27
- package/lib/service/cursor/TokenBudget.js +2 -2
- package/lib/service/cursor/TopicClassifier.js +54 -20
- package/lib/service/guard/ComplianceReporter.js +55 -43
- package/lib/service/guard/ExclusionManager.js +67 -29
- package/lib/service/guard/GuardCheckEngine.js +381 -86
- package/lib/service/guard/GuardFeedbackLoop.js +22 -10
- package/lib/service/guard/GuardService.js +29 -19
- package/lib/service/guard/RuleLearner.js +55 -23
- package/lib/service/guard/SourceFileCollector.js +27 -20
- package/lib/service/guard/ViolationsStore.js +43 -38
- package/lib/service/knowledge/CodeEntityGraph.js +147 -82
- package/lib/service/knowledge/ConfidenceRouter.js +12 -10
- package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
- package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
- package/lib/service/knowledge/KnowledgeService.js +222 -112
- package/lib/service/module/ModuleService.js +969 -0
- package/lib/service/quality/FeedbackCollector.js +27 -15
- package/lib/service/quality/QualityScorer.js +78 -24
- package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
- package/lib/service/recipe/RecipeParser.js +78 -45
- package/lib/service/search/CoarseRanker.js +43 -28
- package/lib/service/search/CrossEncoderReranker.js +32 -21
- package/lib/service/search/InvertedIndex.js +21 -7
- package/lib/service/search/MultiSignalRanker.js +90 -28
- package/lib/service/search/RetrievalFunnel.js +45 -24
- package/lib/service/search/SearchEngine.js +255 -103
- package/lib/service/skills/EventAggregator.js +32 -15
- package/lib/service/skills/SignalCollector.js +140 -64
- package/lib/service/skills/SkillAdvisor.js +79 -42
- package/lib/service/skills/SkillHooks.js +16 -14
- package/lib/service/snippet/PlaceholderConverter.js +5 -0
- package/lib/service/snippet/SnippetFactory.js +116 -99
- package/lib/service/snippet/SnippetInstaller.js +234 -62
- package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
- package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
- package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
- package/lib/service/wiki/WikiGenerator.js +637 -263
- package/lib/shared/DimensionCopyRegistry.js +472 -0
- package/lib/shared/LanguageService.js +399 -0
- package/lib/shared/PathGuard.js +45 -28
- package/lib/shared/RecipeReadinessChecker.js +72 -12
- package/lib/shared/constants.js +41 -41
- package/lib/shared/errors/BaseError.js +2 -2
- package/lib/shared/errors/index.js +4 -4
- package/lib/shared/similarity.js +25 -8
- package/lib/shared/token-utils.js +6 -2
- package/lib/shared/utils/common.js +12 -4
- package/package.json +49 -13
- package/scripts/bench-real-projects.mjs +256 -0
- package/scripts/build-native-ui.js +30 -30
- package/scripts/clear-old-vector-index.js +5 -35
- package/scripts/clear-vector-cache.js +7 -37
- package/scripts/collect-test-project-stats.mjs +160 -0
- package/scripts/diagnose-mcp.js +41 -32
- package/scripts/ensure-parse-package.js +6 -9
- package/scripts/generate-recipe-drafts.js +116 -77
- package/scripts/init-db.js +3 -20
- package/scripts/init-snippets.js +305 -0
- package/scripts/init-vector-db.js +173 -170
- package/scripts/install-cursor-skill.js +148 -104
- package/scripts/install-full.js +8 -21
- package/scripts/install-vscode-copilot.js +146 -145
- package/scripts/migrate-md-to-knowledge.mjs +139 -151
- package/scripts/postinstall-safe.js +5 -17
- package/scripts/recipe-audit.js +106 -82
- package/scripts/release.js +283 -323
- package/scripts/setup-mcp-config.js +60 -52
- package/scripts/verify-context-api.js +20 -20
- package/skills/autosnippet-analysis/SKILL.md +10 -6
- package/skills/autosnippet-candidates/SKILL.md +27 -26
- package/skills/autosnippet-coldstart/SKILL.md +555 -38
- package/skills/autosnippet-concepts/SKILL.md +349 -337
- package/skills/autosnippet-create/SKILL.md +5 -5
- package/skills/autosnippet-reference-dart/SKILL.md +543 -0
- package/skills/autosnippet-reference-go/SKILL.md +539 -0
- package/skills/autosnippet-reference-java/SKILL.md +534 -0
- package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
- package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
- package/skills/autosnippet-reference-objc/SKILL.md +29 -6
- package/skills/autosnippet-reference-python/SKILL.md +800 -0
- package/skills/autosnippet-reference-swift/SKILL.md +70 -14
- package/skills/autosnippet-structure/SKILL.md +4 -4
- package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
- package/templates/recipes-setup/README.md +2 -2
- package/templates/recipes-setup/_template.md +1 -1
- package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
- package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
- package/resources/asd-entry/main.swift +0 -159
- package/scripts/build-asd-entry.js +0 -51
- package/scripts/init-xcode-snippets.js +0 -311
- package/template.json +0 -39
|
@@ -7,38 +7,16 @@
|
|
|
7
7
|
* - 主语言 → 语言扩展字段(分析维度、典型模式、反模式、Guard 规则等)
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import { LanguageService } from '../../../shared/LanguageService.js';
|
|
11
11
|
|
|
12
|
-
/** 根据文件扩展名推断语言 */
|
|
12
|
+
/** 根据文件扩展名推断语言 — 委托给 LanguageService(唯一来源) */
|
|
13
13
|
export function inferLang(filename) {
|
|
14
|
-
|
|
15
|
-
const map = {
|
|
16
|
-
'.swift': 'swift', '.m': 'objectivec', '.h': 'objectivec', '.mm': 'objectivec',
|
|
17
|
-
'.c': 'c', '.cpp': 'cpp', '.js': 'javascript', '.ts': 'typescript',
|
|
18
|
-
'.py': 'python', '.rb': 'ruby', '.java': 'java', '.kt': 'kotlin',
|
|
19
|
-
};
|
|
20
|
-
return map[ext] || 'unknown';
|
|
14
|
+
return LanguageService.inferLang(filename);
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
/** 从 langStats 推断主语言 —
|
|
17
|
+
/** 从 langStats 推断主语言 — 委托给 LanguageService(唯一来源) */
|
|
24
18
|
export function detectPrimaryLanguage(langStats) {
|
|
25
|
-
|
|
26
|
-
swift: 'swift', m: 'objectivec', h: 'objectivec', mm: 'objectivec',
|
|
27
|
-
c: 'c', cpp: 'cpp', js: 'javascript', ts: 'typescript', jsx: 'javascript', tsx: 'typescript',
|
|
28
|
-
py: 'python', rb: 'ruby', java: 'java', kt: 'kotlin', go: 'go', rs: 'rust',
|
|
29
|
-
dart: 'dart', cs: 'csharp',
|
|
30
|
-
};
|
|
31
|
-
// 按映射后的语言聚合计数,避免多扩展名语言(ObjC .h/.m/.mm)计数分散
|
|
32
|
-
const aggregated = {};
|
|
33
|
-
for (const [ext, count] of Object.entries(langStats)) {
|
|
34
|
-
const lang = langMap[ext] || ext;
|
|
35
|
-
aggregated[lang] = (aggregated[lang] || 0) + count;
|
|
36
|
-
}
|
|
37
|
-
let best = 'unknown', bestCount = 0;
|
|
38
|
-
for (const [lang, count] of Object.entries(aggregated)) {
|
|
39
|
-
if (count > bestCount) { best = lang; bestCount = count; }
|
|
40
|
-
}
|
|
41
|
-
return best;
|
|
19
|
+
return LanguageService.detectPrimary(langStats);
|
|
42
20
|
}
|
|
43
21
|
|
|
44
22
|
/**
|
|
@@ -59,10 +37,26 @@ export function buildLanguageExtension(lang) {
|
|
|
59
37
|
switch (lang) {
|
|
60
38
|
case 'swift':
|
|
61
39
|
base.extraDimensions = [
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
40
|
+
{
|
|
41
|
+
id: 'concurrency',
|
|
42
|
+
label: 'Swift Concurrency',
|
|
43
|
+
guide: 'async/await、Actor、@Sendable、TaskGroup、MainActor 用法',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'protocol-oriented',
|
|
47
|
+
label: '面向协议编程',
|
|
48
|
+
guide: 'Protocol 扩展、条件一致性、PAT (Protocol with Associated Type)',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'property-wrapper',
|
|
52
|
+
label: 'Property Wrapper',
|
|
53
|
+
guide: '@Published、@State、@Environment、自定义 Property Wrapper',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'value-semantics',
|
|
57
|
+
label: '值语义',
|
|
58
|
+
guide: 'struct vs class 决策、COW (Copy-on-Write)、Equatable/Hashable',
|
|
59
|
+
},
|
|
66
60
|
];
|
|
67
61
|
base.typicalPatterns = [
|
|
68
62
|
'Result<Success, Failure> 统一错误处理',
|
|
@@ -74,8 +68,16 @@ export function buildLanguageExtension(lang) {
|
|
|
74
68
|
];
|
|
75
69
|
base.commonAntiPatterns = [
|
|
76
70
|
{ bad: '强制 try! / as! 解包', why: '运行时 crash', fix: 'guard let / if let / do-catch' },
|
|
77
|
-
{
|
|
78
|
-
|
|
71
|
+
{
|
|
72
|
+
bad: 'DispatchQueue.main.async 更新 UI',
|
|
73
|
+
why: 'Swift Concurrency 下造成 data race',
|
|
74
|
+
fix: '@MainActor',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
bad: '闭包中不用 [weak self]',
|
|
78
|
+
why: '循环引用导致内存泄漏',
|
|
79
|
+
fix: '[weak self] / [unowned self]',
|
|
80
|
+
},
|
|
79
81
|
];
|
|
80
82
|
base.suggestedGuardRules = [
|
|
81
83
|
{ pattern: 'try!', severity: 'warning', message: '避免 force try,使用 do-catch' },
|
|
@@ -93,10 +95,26 @@ export function buildLanguageExtension(lang) {
|
|
|
93
95
|
|
|
94
96
|
case 'objectivec':
|
|
95
97
|
base.extraDimensions = [
|
|
96
|
-
{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
{
|
|
99
|
+
id: 'memory-management',
|
|
100
|
+
label: '内存管理',
|
|
101
|
+
guide: 'ARC 下的 strong/weak/unsafe_unretained、autorelease、dealloc 模式',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'category-extension',
|
|
105
|
+
label: 'Category/Extension',
|
|
106
|
+
guide: 'Category 方法命名冲突、Class Extension 私有属性',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'block-pattern',
|
|
110
|
+
label: 'Block 模式',
|
|
111
|
+
guide: 'Block 循环引用、__weak/__strong dance、Block 作为回调',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'nullability',
|
|
115
|
+
label: 'Nullability 标注',
|
|
116
|
+
guide: 'nullable/nonnull/NS_ASSUME_NONNULL、与 Swift 互操作',
|
|
117
|
+
},
|
|
100
118
|
];
|
|
101
119
|
base.typicalPatterns = [
|
|
102
120
|
'delegate + protocol 回调模式',
|
|
@@ -108,11 +126,23 @@ export function buildLanguageExtension(lang) {
|
|
|
108
126
|
];
|
|
109
127
|
base.commonAntiPatterns = [
|
|
110
128
|
{ bad: 'Block 内直接引用 self', why: '循环引用', fix: '__weak + __strong dance' },
|
|
111
|
-
{
|
|
112
|
-
|
|
129
|
+
{
|
|
130
|
+
bad: '头文件缺少 nullability 标注',
|
|
131
|
+
why: 'Swift 桥接时全部变为 optional',
|
|
132
|
+
fix: 'NS_ASSUME_NONNULL + 显式 nullable',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
bad: 'Category 方法不带前缀',
|
|
136
|
+
why: '与系统方法/其他库冲突',
|
|
137
|
+
fix: '加项目前缀如 xx_methodName',
|
|
138
|
+
},
|
|
113
139
|
];
|
|
114
140
|
base.suggestedGuardRules = [
|
|
115
|
-
{
|
|
141
|
+
{
|
|
142
|
+
pattern: '\\[self\\s',
|
|
143
|
+
severity: 'warning',
|
|
144
|
+
message: 'Block 内直接引用 self,考虑 __weak',
|
|
145
|
+
},
|
|
116
146
|
];
|
|
117
147
|
base.agentCautions = [
|
|
118
148
|
'ObjC 头文件必须包含 NS_ASSUME_NONNULL_BEGIN/END',
|
|
@@ -125,10 +155,29 @@ export function buildLanguageExtension(lang) {
|
|
|
125
155
|
case 'typescript':
|
|
126
156
|
case 'javascript':
|
|
127
157
|
base.extraDimensions = [
|
|
128
|
-
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
158
|
+
{
|
|
159
|
+
id: 'module-system',
|
|
160
|
+
label: '模块系统',
|
|
161
|
+
guide: 'ESM vs CJS、dynamic import、barrel export、tree-shaking',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
id: 'type-safety',
|
|
165
|
+
label: '类型安全',
|
|
166
|
+
guide:
|
|
167
|
+
lang === 'typescript'
|
|
168
|
+
? 'strict 模式、泛型、类型守卫、Utility Types'
|
|
169
|
+
: 'JSDoc 类型标注、.d.ts 声明',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: 'async-pattern',
|
|
173
|
+
label: '异步模式',
|
|
174
|
+
guide: 'Promise 链、async/await、Error 处理、AbortController',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'framework-convention',
|
|
178
|
+
label: '框架约定',
|
|
179
|
+
guide: 'React Hooks/Vue Composition/Node.js 中间件等框架特有模式',
|
|
180
|
+
},
|
|
132
181
|
];
|
|
133
182
|
base.typicalPatterns = [
|
|
134
183
|
'async/await + try-catch 错误处理',
|
|
@@ -157,9 +206,17 @@ export function buildLanguageExtension(lang) {
|
|
|
157
206
|
|
|
158
207
|
case 'python':
|
|
159
208
|
base.extraDimensions = [
|
|
160
|
-
{
|
|
209
|
+
{
|
|
210
|
+
id: 'type-hints',
|
|
211
|
+
label: '类型注解',
|
|
212
|
+
guide: 'typing 模块、Protocol、TypeVar、Generic、dataclass',
|
|
213
|
+
},
|
|
161
214
|
{ id: 'async-io', label: '异步 IO', guide: 'asyncio、aiohttp、async generators' },
|
|
162
|
-
{
|
|
215
|
+
{
|
|
216
|
+
id: 'package-structure',
|
|
217
|
+
label: '包结构',
|
|
218
|
+
guide: '__init__.py、相对导入、pyproject.toml',
|
|
219
|
+
},
|
|
163
220
|
];
|
|
164
221
|
base.typicalPatterns = [
|
|
165
222
|
'dataclass 数据建模',
|
|
@@ -205,8 +262,16 @@ export function buildLanguageExtension(lang) {
|
|
|
205
262
|
|
|
206
263
|
case 'java':
|
|
207
264
|
base.extraDimensions = [
|
|
208
|
-
{
|
|
209
|
-
|
|
265
|
+
{
|
|
266
|
+
id: 'concurrency',
|
|
267
|
+
label: '并发',
|
|
268
|
+
guide: 'synchronized、ExecutorService、CompletableFuture、虚拟线程 (21+)',
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
id: 'generics',
|
|
272
|
+
label: '泛型',
|
|
273
|
+
guide: '类型擦除、通配符 <? extends/super>、类型安全容器',
|
|
274
|
+
},
|
|
210
275
|
];
|
|
211
276
|
base.typicalPatterns = [
|
|
212
277
|
'Builder 模式',
|
|
@@ -224,8 +289,16 @@ export function buildLanguageExtension(lang) {
|
|
|
224
289
|
|
|
225
290
|
case 'go':
|
|
226
291
|
base.extraDimensions = [
|
|
227
|
-
{
|
|
228
|
-
|
|
292
|
+
{
|
|
293
|
+
id: 'goroutine',
|
|
294
|
+
label: 'Goroutine/Channel',
|
|
295
|
+
guide: '并发模式、channel、select、context 传播',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
id: 'error-handling',
|
|
299
|
+
label: '错误处理',
|
|
300
|
+
guide: 'error interface、errors.Is/As、sentinel errors、%w wrap',
|
|
301
|
+
},
|
|
229
302
|
{ id: 'interface', label: '接口设计', guide: '隐式实现、小接口、io.Reader/Writer 组合' },
|
|
230
303
|
];
|
|
231
304
|
base.typicalPatterns = [
|
|
@@ -244,9 +317,21 @@ export function buildLanguageExtension(lang) {
|
|
|
244
317
|
|
|
245
318
|
case 'rust':
|
|
246
319
|
base.extraDimensions = [
|
|
247
|
-
{
|
|
248
|
-
|
|
249
|
-
|
|
320
|
+
{
|
|
321
|
+
id: 'ownership',
|
|
322
|
+
label: '所有权/借用',
|
|
323
|
+
guide: 'ownership、borrowing、lifetime、Clone vs Copy',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: 'error-handling',
|
|
327
|
+
label: '错误处理',
|
|
328
|
+
guide: 'Result<T,E>、? 操作符、thiserror/anyhow',
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
id: 'trait-system',
|
|
332
|
+
label: 'Trait 系统',
|
|
333
|
+
guide: 'trait bound、impl Trait、dyn Trait、derive 宏',
|
|
334
|
+
},
|
|
250
335
|
];
|
|
251
336
|
base.typicalPatterns = [
|
|
252
337
|
'Result<T, E> + ? 操作符',
|
|
@@ -9,18 +9,42 @@
|
|
|
9
9
|
/** 根据 Target 名称推断模块职责 */
|
|
10
10
|
export function inferTargetRole(targetName) {
|
|
11
11
|
const n = targetName.toLowerCase();
|
|
12
|
-
if (/core|kit|shared|common|foundation|base/i.test(n))
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (/
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
if (/core|kit|shared|common|foundation|base/i.test(n)) {
|
|
13
|
+
return 'core';
|
|
14
|
+
}
|
|
15
|
+
if (/service|manager|provider|repository|store/i.test(n)) {
|
|
16
|
+
return 'service';
|
|
17
|
+
}
|
|
18
|
+
if (/ui|view|screen|component|widget/i.test(n)) {
|
|
19
|
+
return 'ui';
|
|
20
|
+
}
|
|
21
|
+
if (/network|api|http|grpc|socket/i.test(n)) {
|
|
22
|
+
return 'networking';
|
|
23
|
+
}
|
|
24
|
+
if (/storage|database|cache|persist|realm|coredata/i.test(n)) {
|
|
25
|
+
return 'storage';
|
|
26
|
+
}
|
|
27
|
+
if (/test|spec|mock|stub|fake/i.test(n)) {
|
|
28
|
+
return 'test';
|
|
29
|
+
}
|
|
30
|
+
if (/app|main|launch|entry/i.test(n)) {
|
|
31
|
+
return 'app';
|
|
32
|
+
}
|
|
33
|
+
if (/router|coordinator|navigation/i.test(n)) {
|
|
34
|
+
return 'routing';
|
|
35
|
+
}
|
|
36
|
+
if (/util|helper|extension|tool/i.test(n)) {
|
|
37
|
+
return 'utility';
|
|
38
|
+
}
|
|
39
|
+
if (/model|entity|dto|schema/i.test(n)) {
|
|
40
|
+
return 'model';
|
|
41
|
+
}
|
|
42
|
+
if (/auth|login|session|token/i.test(n)) {
|
|
43
|
+
return 'auth';
|
|
44
|
+
}
|
|
45
|
+
if (/config|setting|environment|constant/i.test(n)) {
|
|
46
|
+
return 'config';
|
|
47
|
+
}
|
|
24
48
|
return 'feature';
|
|
25
49
|
}
|
|
26
50
|
|
|
@@ -28,11 +52,23 @@ export function inferTargetRole(targetName) {
|
|
|
28
52
|
export function inferFilePriority(filename) {
|
|
29
53
|
const n = filename.toLowerCase();
|
|
30
54
|
// High: core definitions, services, protocols, configs
|
|
31
|
-
if (
|
|
32
|
-
|
|
55
|
+
if (
|
|
56
|
+
/protocol|interface|delegate|service|manager|provider|config|constant|router|coordinator|factory|builder/i.test(
|
|
57
|
+
n
|
|
58
|
+
)
|
|
59
|
+
) {
|
|
60
|
+
return 'high';
|
|
61
|
+
}
|
|
62
|
+
if (/^(app|main|launch|entry|bootstrap)/i.test(n)) {
|
|
63
|
+
return 'high';
|
|
64
|
+
}
|
|
33
65
|
// Low: tests, extensions, helpers, generated
|
|
34
|
-
if (/test|spec|mock|stub|fake|\+|\bext\b|extension|helper|generated|\.pb\./i.test(n))
|
|
35
|
-
|
|
66
|
+
if (/test|spec|mock|stub|fake|\+|\bext\b|extension|helper|generated|\.pb\./i.test(n)) {
|
|
67
|
+
return 'low';
|
|
68
|
+
}
|
|
69
|
+
if (/readme|changelog|license/i.test(n)) {
|
|
70
|
+
return 'low';
|
|
71
|
+
}
|
|
36
72
|
// Medium: everything else
|
|
37
73
|
return 'medium';
|
|
38
74
|
}
|
|
@@ -46,7 +46,9 @@ export class BootstrapSnapshot {
|
|
|
46
46
|
* @param {object} [opts.logger]
|
|
47
47
|
*/
|
|
48
48
|
constructor(db, { logger } = {}) {
|
|
49
|
-
if (!db)
|
|
49
|
+
if (!db) {
|
|
50
|
+
throw new Error('BootstrapSnapshot requires a database instance');
|
|
51
|
+
}
|
|
50
52
|
this.#db = typeof db?.getDb === 'function' ? db.getDb() : db;
|
|
51
53
|
this.#logger = logger || null;
|
|
52
54
|
|
|
@@ -134,9 +136,12 @@ export class BootstrapSnapshot {
|
|
|
134
136
|
for (const [dimId, stat] of Object.entries(dimensionStats || {})) {
|
|
135
137
|
const refFiles = stat.referencedFilesList || [];
|
|
136
138
|
for (const filePath of refFiles) {
|
|
137
|
-
const rel =
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
const rel =
|
|
140
|
+
typeof filePath === 'string'
|
|
141
|
+
? filePath.startsWith('/')
|
|
142
|
+
? relative(projectRoot, filePath)
|
|
143
|
+
: filePath
|
|
144
|
+
: filePath;
|
|
140
145
|
this.#stmts.insertDimFile.run({
|
|
141
146
|
snapshot_id: id,
|
|
142
147
|
dim_id: dimId,
|
|
@@ -152,7 +157,9 @@ export class BootstrapSnapshot {
|
|
|
152
157
|
|
|
153
158
|
saveTransaction();
|
|
154
159
|
|
|
155
|
-
this.#log(
|
|
160
|
+
this.#log(
|
|
161
|
+
`Snapshot saved: ${id} (${allFiles.length} files, ${Object.keys(dimensionStats || {}).length} dims)`
|
|
162
|
+
);
|
|
156
163
|
return id;
|
|
157
164
|
}
|
|
158
165
|
|
|
@@ -182,7 +189,9 @@ export class BootstrapSnapshot {
|
|
|
182
189
|
*/
|
|
183
190
|
getLatest(projectRoot) {
|
|
184
191
|
const row = this.#stmts.getLatest.get(projectRoot);
|
|
185
|
-
if (!row)
|
|
192
|
+
if (!row) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
186
195
|
return this.#deserialize(row);
|
|
187
196
|
}
|
|
188
197
|
|
|
@@ -193,7 +202,9 @@ export class BootstrapSnapshot {
|
|
|
193
202
|
*/
|
|
194
203
|
getById(id) {
|
|
195
204
|
const row = this.#stmts.getById.get(id);
|
|
196
|
-
if (!row)
|
|
205
|
+
if (!row) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
197
208
|
return this.#deserialize(row);
|
|
198
209
|
}
|
|
199
210
|
|
|
@@ -204,8 +215,7 @@ export class BootstrapSnapshot {
|
|
|
204
215
|
* @returns {Array<object>}
|
|
205
216
|
*/
|
|
206
217
|
list(projectRoot, limit = 10) {
|
|
207
|
-
return this.#stmts.listByProject.all(projectRoot, limit)
|
|
208
|
-
.map(r => this.#deserialize(r));
|
|
218
|
+
return this.#stmts.listByProject.all(projectRoot, limit).map((r) => this.#deserialize(r));
|
|
209
219
|
}
|
|
210
220
|
|
|
211
221
|
// ─── 增量 Diff 计算 ──────────────────────────────────
|
|
@@ -244,7 +254,7 @@ export class BootstrapSnapshot {
|
|
|
244
254
|
}
|
|
245
255
|
|
|
246
256
|
// 已删除的文件
|
|
247
|
-
const deleted = Object.keys(oldHashes).filter(p => !(p in newHashes));
|
|
257
|
+
const deleted = Object.keys(oldHashes).filter((p) => !(p in newHashes));
|
|
248
258
|
|
|
249
259
|
const totalFiles = Object.keys(newHashes).length || 1;
|
|
250
260
|
const changedCount = added.length + modified.length + deleted.length;
|
|
@@ -269,8 +279,12 @@ export class BootstrapSnapshot {
|
|
|
269
279
|
* @returns {{ mode: 'incremental'|'full', dimensions: string[], skippedDimensions: string[], reason: string }}
|
|
270
280
|
*/
|
|
271
281
|
inferAffectedDimensions(snapshot, diff, allDimIds) {
|
|
272
|
-
const changeRatio =
|
|
273
|
-
(diff.added.length + diff.modified.length + diff.deleted.length
|
|
282
|
+
const changeRatio =
|
|
283
|
+
(diff.added.length + diff.modified.length + diff.deleted.length) /
|
|
284
|
+
(diff.added.length +
|
|
285
|
+
diff.modified.length +
|
|
286
|
+
diff.deleted.length +
|
|
287
|
+
(diff.unchanged?.length || 0) || 1);
|
|
274
288
|
|
|
275
289
|
// 变更超过 50% → 全量
|
|
276
290
|
if (changeRatio > FULL_REBUILD_THRESHOLD) {
|
|
@@ -322,8 +336,8 @@ export class BootstrapSnapshot {
|
|
|
322
336
|
affected.add('project-profile');
|
|
323
337
|
}
|
|
324
338
|
|
|
325
|
-
const dimensions = allDimIds.filter(d => affected.has(d));
|
|
326
|
-
const skippedDimensions = allDimIds.filter(d => !affected.has(d));
|
|
339
|
+
const dimensions = allDimIds.filter((d) => affected.has(d));
|
|
340
|
+
const skippedDimensions = allDimIds.filter((d) => !affected.has(d));
|
|
327
341
|
|
|
328
342
|
return {
|
|
329
343
|
mode: 'incremental',
|
|
@@ -344,7 +358,9 @@ export class BootstrapSnapshot {
|
|
|
344
358
|
const rows = this.#stmts.getDimFiles.all(snapshotId);
|
|
345
359
|
const map = {};
|
|
346
360
|
for (const row of rows) {
|
|
347
|
-
if (!map[row.dim_id])
|
|
361
|
+
if (!map[row.dim_id]) {
|
|
362
|
+
map[row.dim_id] = new Set();
|
|
363
|
+
}
|
|
348
364
|
map[row.dim_id].add(row.file_path);
|
|
349
365
|
}
|
|
350
366
|
return map;
|
|
@@ -376,19 +392,61 @@ export class BootstrapSnapshot {
|
|
|
376
392
|
dims.push('code-standard', 'architecture');
|
|
377
393
|
}
|
|
378
394
|
|
|
395
|
+
// TS/JS 相关
|
|
396
|
+
if (['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'vue', 'svelte'].includes(ext)) {
|
|
397
|
+
dims.push('module-export-scan', 'code-standard', 'architecture');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Python 相关
|
|
401
|
+
if (ext === 'py') {
|
|
402
|
+
dims.push('python-package-scan', 'code-standard', 'architecture');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Java/Kotlin 相关
|
|
406
|
+
if (['java', 'kt', 'kts'].includes(ext)) {
|
|
407
|
+
dims.push('jvm-annotation-scan', 'code-standard', 'architecture');
|
|
408
|
+
}
|
|
409
|
+
|
|
379
410
|
// 配置文件
|
|
380
|
-
if (
|
|
411
|
+
if (
|
|
412
|
+
['json', 'yaml', 'yml', 'plist', 'xcconfig', 'toml', 'properties', 'gradle'].includes(ext)
|
|
413
|
+
) {
|
|
381
414
|
dims.push('project-profile');
|
|
382
415
|
}
|
|
383
416
|
|
|
384
417
|
// 通用: 代码文件都可能影响 code-pattern 和 best-practice
|
|
385
|
-
if (
|
|
418
|
+
if (
|
|
419
|
+
[
|
|
420
|
+
'm',
|
|
421
|
+
'mm',
|
|
422
|
+
'h',
|
|
423
|
+
'swift',
|
|
424
|
+
'js',
|
|
425
|
+
'jsx',
|
|
426
|
+
'ts',
|
|
427
|
+
'tsx',
|
|
428
|
+
'mjs',
|
|
429
|
+
'cjs',
|
|
430
|
+
'py',
|
|
431
|
+
'java',
|
|
432
|
+
'kt',
|
|
433
|
+
'kts',
|
|
434
|
+
'go',
|
|
435
|
+
'rs',
|
|
436
|
+
'rb',
|
|
437
|
+
].includes(ext)
|
|
438
|
+
) {
|
|
386
439
|
dims.push('code-pattern', 'best-practice');
|
|
387
440
|
}
|
|
388
441
|
|
|
389
442
|
// 数据流相关
|
|
390
|
-
if (
|
|
391
|
-
|
|
443
|
+
if (
|
|
444
|
+
name.includes('manager') ||
|
|
445
|
+
name.includes('service') ||
|
|
446
|
+
name.includes('event') ||
|
|
447
|
+
name.includes('notification') ||
|
|
448
|
+
name.includes('delegate')
|
|
449
|
+
) {
|
|
392
450
|
dims.push('event-and-data-flow');
|
|
393
451
|
}
|
|
394
452
|
|
|
@@ -398,7 +456,10 @@ export class BootstrapSnapshot {
|
|
|
398
456
|
// ─── 内部方法 ─────────────────────────────────────────
|
|
399
457
|
|
|
400
458
|
#computeContentHash(content) {
|
|
401
|
-
return createHash('sha256')
|
|
459
|
+
return createHash('sha256')
|
|
460
|
+
.update(content || '')
|
|
461
|
+
.digest('hex')
|
|
462
|
+
.substring(0, 16);
|
|
402
463
|
}
|
|
403
464
|
|
|
404
465
|
#readFileContent(filePath) {
|