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
|
@@ -85,14 +85,16 @@ export class CodeEntityGraph {
|
|
|
85
85
|
* @returns {GraphPopulateResult}
|
|
86
86
|
*/
|
|
87
87
|
populateFromAst(astSummary) {
|
|
88
|
-
if (!astSummary)
|
|
88
|
+
if (!astSummary) {
|
|
89
|
+
return { entitiesUpserted: 0, edgesCreated: 0, durationMs: 0 };
|
|
90
|
+
}
|
|
89
91
|
const t0 = Date.now();
|
|
90
92
|
let entities = 0;
|
|
91
93
|
let edges = 0;
|
|
92
94
|
|
|
93
95
|
const run = this.db.transaction(() => {
|
|
94
96
|
// ── 类 ──
|
|
95
|
-
for (const cls of
|
|
97
|
+
for (const cls of astSummary.classes || []) {
|
|
96
98
|
this.#upsertEntity({
|
|
97
99
|
entityId: cls.name,
|
|
98
100
|
entityType: cls.isCategory ? 'category' : 'class',
|
|
@@ -110,7 +112,7 @@ export class CodeEntityGraph {
|
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
// ── 协议 ──
|
|
113
|
-
for (const proto of
|
|
115
|
+
for (const proto of astSummary.protocols || []) {
|
|
114
116
|
this.#upsertEntity({
|
|
115
117
|
entityId: proto.name,
|
|
116
118
|
entityType: 'protocol',
|
|
@@ -126,7 +128,7 @@ export class CodeEntityGraph {
|
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
// ── Category ──
|
|
129
|
-
for (const cat of
|
|
131
|
+
for (const cat of astSummary.categories || []) {
|
|
130
132
|
const catId = `${cat.className}(${cat.categoryName})`;
|
|
131
133
|
this.#upsertEntity({
|
|
132
134
|
entityId: catId,
|
|
@@ -145,7 +147,7 @@ export class CodeEntityGraph {
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
// ── 继承/遵循/扩展 边 (从 AST inheritanceGraph) ──
|
|
148
|
-
for (const edge of
|
|
150
|
+
for (const edge of astSummary.inheritanceGraph || []) {
|
|
149
151
|
const fromType = this.#inferEntityType(edge.from, astSummary);
|
|
150
152
|
const toType = this.#inferEntityType(edge.to, astSummary);
|
|
151
153
|
this.#addEdge(edge.from, fromType, edge.to, toType, edge.type, {
|
|
@@ -187,7 +189,9 @@ export class CodeEntityGraph {
|
|
|
187
189
|
run();
|
|
188
190
|
|
|
189
191
|
const result = { entitiesUpserted: entities, edgesCreated: edges, durationMs: Date.now() - t0 };
|
|
190
|
-
this.log.info(
|
|
192
|
+
this.log.info(
|
|
193
|
+
`[CodeEntityGraph] AST populate: ${entities} entities, ${edges} edges (${result.durationMs}ms)`
|
|
194
|
+
);
|
|
191
195
|
return result;
|
|
192
196
|
}
|
|
193
197
|
|
|
@@ -201,12 +205,14 @@ export class CodeEntityGraph {
|
|
|
201
205
|
* @returns {GraphPopulateResult}
|
|
202
206
|
*/
|
|
203
207
|
populateFromSpm(depGraphData) {
|
|
204
|
-
if (!depGraphData)
|
|
208
|
+
if (!depGraphData) {
|
|
209
|
+
return { entitiesUpserted: 0, edgesCreated: 0, durationMs: 0 };
|
|
210
|
+
}
|
|
205
211
|
const t0 = Date.now();
|
|
206
212
|
let entities = 0;
|
|
207
213
|
|
|
208
214
|
const run = this.db.transaction(() => {
|
|
209
|
-
for (const node of
|
|
215
|
+
for (const node of depGraphData.nodes || []) {
|
|
210
216
|
this.#upsertEntity({
|
|
211
217
|
entityId: node.id || node.label || node,
|
|
212
218
|
entityType: 'module',
|
|
@@ -222,7 +228,9 @@ export class CodeEntityGraph {
|
|
|
222
228
|
run();
|
|
223
229
|
|
|
224
230
|
const result = { entitiesUpserted: entities, edgesCreated: 0, durationMs: Date.now() - t0 };
|
|
225
|
-
this.log.info(
|
|
231
|
+
this.log.info(
|
|
232
|
+
`[CodeEntityGraph] SPM populate: ${entities} module entities (${result.durationMs}ms)`
|
|
233
|
+
);
|
|
226
234
|
return result;
|
|
227
235
|
}
|
|
228
236
|
|
|
@@ -233,14 +241,18 @@ export class CodeEntityGraph {
|
|
|
233
241
|
* @returns {GraphPopulateResult}
|
|
234
242
|
*/
|
|
235
243
|
populateFromCandidateRelations(candidates) {
|
|
236
|
-
if (!candidates?.length)
|
|
244
|
+
if (!candidates?.length) {
|
|
245
|
+
return { entitiesUpserted: 0, edgesCreated: 0, durationMs: 0 };
|
|
246
|
+
}
|
|
237
247
|
const t0 = Date.now();
|
|
238
248
|
let edges = 0;
|
|
239
249
|
|
|
240
250
|
const run = this.db.transaction(() => {
|
|
241
251
|
for (const candidate of candidates) {
|
|
242
252
|
const title = candidate.title || candidate.id || '';
|
|
243
|
-
if (!title)
|
|
253
|
+
if (!title) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
244
256
|
|
|
245
257
|
// 处理 Relations 对象或扁平数组
|
|
246
258
|
let flatRelations;
|
|
@@ -252,7 +264,7 @@ export class CodeEntityGraph {
|
|
|
252
264
|
// 桶结构 → 扁平
|
|
253
265
|
flatRelations = [];
|
|
254
266
|
for (const [type, list] of Object.entries(candidate.relations)) {
|
|
255
|
-
for (const r of
|
|
267
|
+
for (const r of Array.isArray(list) ? list : []) {
|
|
256
268
|
flatRelations.push({ type, target: r.target, description: r.description });
|
|
257
269
|
}
|
|
258
270
|
}
|
|
@@ -261,7 +273,9 @@ export class CodeEntityGraph {
|
|
|
261
273
|
}
|
|
262
274
|
|
|
263
275
|
for (const rel of flatRelations) {
|
|
264
|
-
if (!rel.target)
|
|
276
|
+
if (!rel.target) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
265
279
|
// 映射关系类型到边类型
|
|
266
280
|
const relation = this.#mapRelationType(rel.type);
|
|
267
281
|
this.#addEdge(title, 'recipe', rel.target, 'recipe', relation, {
|
|
@@ -296,9 +310,9 @@ export class CodeEntityGraph {
|
|
|
296
310
|
if (entityType) {
|
|
297
311
|
row = this.stmts.getEntity.get(entityId, entityType, this.projectRoot);
|
|
298
312
|
} else {
|
|
299
|
-
row = this.db
|
|
300
|
-
`SELECT * FROM code_entities WHERE entity_id = ? AND project_root = ? LIMIT 1`
|
|
301
|
-
|
|
313
|
+
row = this.db
|
|
314
|
+
.prepare(`SELECT * FROM code_entities WHERE entity_id = ? AND project_root = ? LIMIT 1`)
|
|
315
|
+
.get(entityId, this.projectRoot);
|
|
302
316
|
}
|
|
303
317
|
return row ? this.#mapEntity(row) : null;
|
|
304
318
|
}
|
|
@@ -311,7 +325,7 @@ export class CodeEntityGraph {
|
|
|
311
325
|
*/
|
|
312
326
|
listEntities(entityType, limit = 200) {
|
|
313
327
|
const rows = this.stmts.listByType.all(entityType, this.projectRoot, limit);
|
|
314
|
-
return rows.map(r => this.#mapEntity(r));
|
|
328
|
+
return rows.map((r) => this.#mapEntity(r));
|
|
315
329
|
}
|
|
316
330
|
|
|
317
331
|
/**
|
|
@@ -332,7 +346,10 @@ export class CodeEntityGraph {
|
|
|
332
346
|
}
|
|
333
347
|
sql += ` ORDER BY name LIMIT ?`;
|
|
334
348
|
params.push(options.limit || 20);
|
|
335
|
-
return this.db
|
|
349
|
+
return this.db
|
|
350
|
+
.prepare(sql)
|
|
351
|
+
.all(...params)
|
|
352
|
+
.map((r) => this.#mapEntity(r));
|
|
336
353
|
}
|
|
337
354
|
|
|
338
355
|
/**
|
|
@@ -343,16 +360,20 @@ export class CodeEntityGraph {
|
|
|
343
360
|
* @returns {{ outgoing: EntityEdge[], incoming: EntityEdge[] }}
|
|
344
361
|
*/
|
|
345
362
|
getEntityEdges(entityId, entityType, direction = 'both') {
|
|
346
|
-
const outgoing =
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
363
|
+
const outgoing =
|
|
364
|
+
direction === 'both' || direction === 'out'
|
|
365
|
+
? this.db
|
|
366
|
+
.prepare(`SELECT * FROM knowledge_edges WHERE from_id = ? AND from_type = ?`)
|
|
367
|
+
.all(entityId, entityType)
|
|
368
|
+
.map(this.#mapEdge)
|
|
369
|
+
: [];
|
|
370
|
+
const incoming =
|
|
371
|
+
direction === 'both' || direction === 'in'
|
|
372
|
+
? this.db
|
|
373
|
+
.prepare(`SELECT * FROM knowledge_edges WHERE to_id = ? AND to_type = ?`)
|
|
374
|
+
.all(entityId, entityType)
|
|
375
|
+
.map(this.#mapEdge)
|
|
376
|
+
: [];
|
|
356
377
|
return { outgoing, incoming };
|
|
357
378
|
}
|
|
358
379
|
|
|
@@ -366,11 +387,15 @@ export class CodeEntityGraph {
|
|
|
366
387
|
const chain = [className];
|
|
367
388
|
let current = className;
|
|
368
389
|
for (let i = 0; i < maxDepth; i++) {
|
|
369
|
-
const parent = this.db
|
|
370
|
-
|
|
390
|
+
const parent = this.db
|
|
391
|
+
.prepare(
|
|
392
|
+
`SELECT to_id FROM knowledge_edges
|
|
371
393
|
WHERE from_id = ? AND from_type = 'class' AND relation = 'inherits' LIMIT 1`
|
|
372
|
-
|
|
373
|
-
|
|
394
|
+
)
|
|
395
|
+
.get(current);
|
|
396
|
+
if (!parent) {
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
374
399
|
chain.push(parent.to_id);
|
|
375
400
|
current = parent.to_id;
|
|
376
401
|
}
|
|
@@ -390,22 +415,27 @@ export class CodeEntityGraph {
|
|
|
390
415
|
const queue = [{ id: entityId, type: entityType, depth: 0 }];
|
|
391
416
|
|
|
392
417
|
// 类的子类/Category + 协议的遵循者
|
|
393
|
-
const relations =
|
|
394
|
-
? ['conforms', 'inherits']
|
|
395
|
-
: ['inherits', 'extends'];
|
|
418
|
+
const relations =
|
|
419
|
+
entityType === 'protocol' ? ['conforms', 'inherits'] : ['inherits', 'extends'];
|
|
396
420
|
|
|
397
421
|
while (queue.length > 0) {
|
|
398
422
|
const { id, type, depth } = queue.shift();
|
|
399
|
-
if (depth >= maxDepth)
|
|
423
|
+
if (depth >= maxDepth) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
400
426
|
const key = `${type}:${id}`;
|
|
401
|
-
if (visited.has(key))
|
|
427
|
+
if (visited.has(key)) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
402
430
|
visited.add(key);
|
|
403
431
|
|
|
404
432
|
for (const rel of relations) {
|
|
405
|
-
const children = this.db
|
|
406
|
-
|
|
433
|
+
const children = this.db
|
|
434
|
+
.prepare(
|
|
435
|
+
`SELECT from_id, from_type FROM knowledge_edges
|
|
407
436
|
WHERE to_id = ? AND to_type = ? AND relation = ?`
|
|
408
|
-
|
|
437
|
+
)
|
|
438
|
+
.all(id, type, rel);
|
|
409
439
|
|
|
410
440
|
for (const child of children) {
|
|
411
441
|
const childKey = `${child.from_type}:${child.from_id}`;
|
|
@@ -431,11 +461,13 @@ export class CodeEntityGraph {
|
|
|
431
461
|
* @returns {string[]}
|
|
432
462
|
*/
|
|
433
463
|
getConformances(className) {
|
|
434
|
-
const rows = this.db
|
|
435
|
-
|
|
464
|
+
const rows = this.db
|
|
465
|
+
.prepare(
|
|
466
|
+
`SELECT to_id FROM knowledge_edges
|
|
436
467
|
WHERE from_id = ? AND from_type IN ('class', 'category') AND relation = 'conforms'`
|
|
437
|
-
|
|
438
|
-
|
|
468
|
+
)
|
|
469
|
+
.all(className);
|
|
470
|
+
return rows.map((r) => r.to_id);
|
|
439
471
|
}
|
|
440
472
|
|
|
441
473
|
/**
|
|
@@ -453,18 +485,28 @@ export class CodeEntityGraph {
|
|
|
453
485
|
|
|
454
486
|
while (queue.length > 0) {
|
|
455
487
|
const { id, type, path } = queue.shift();
|
|
456
|
-
if (path.length >= maxDepth)
|
|
488
|
+
if (path.length >= maxDepth) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
457
491
|
|
|
458
492
|
const key = `${type}:${id}`;
|
|
459
|
-
if (visited.has(key))
|
|
493
|
+
if (visited.has(key)) {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
460
496
|
visited.add(key);
|
|
461
497
|
|
|
462
|
-
const neighbors = this.db
|
|
463
|
-
|
|
464
|
-
|
|
498
|
+
const neighbors = this.db
|
|
499
|
+
.prepare(
|
|
500
|
+
`SELECT to_id, to_type, relation, weight FROM knowledge_edges WHERE from_id = ? AND from_type = ?`
|
|
501
|
+
)
|
|
502
|
+
.all(id, type);
|
|
465
503
|
|
|
466
504
|
for (const n of neighbors) {
|
|
467
|
-
const step = {
|
|
505
|
+
const step = {
|
|
506
|
+
from: { id, type },
|
|
507
|
+
to: { id: n.to_id, type: n.to_type },
|
|
508
|
+
relation: n.relation,
|
|
509
|
+
};
|
|
468
510
|
const newPath = [...path, step];
|
|
469
511
|
|
|
470
512
|
if (n.to_id === toId && n.to_type === toType) {
|
|
@@ -491,17 +533,23 @@ export class CodeEntityGraph {
|
|
|
491
533
|
|
|
492
534
|
while (queue.length > 0) {
|
|
493
535
|
const { id, type, depth } = queue.shift();
|
|
494
|
-
if (depth >= maxDepth)
|
|
536
|
+
if (depth >= maxDepth) {
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
495
539
|
|
|
496
540
|
const key = `${type}:${id}`;
|
|
497
|
-
if (visited.has(key))
|
|
541
|
+
if (visited.has(key)) {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
498
544
|
visited.add(key);
|
|
499
545
|
|
|
500
546
|
// 找出所有"依赖/引用此实体"的上游
|
|
501
|
-
const dependents = this.db
|
|
502
|
-
|
|
547
|
+
const dependents = this.db
|
|
548
|
+
.prepare(
|
|
549
|
+
`SELECT from_id, from_type, relation FROM knowledge_edges
|
|
503
550
|
WHERE to_id = ? AND to_type = ?`
|
|
504
|
-
|
|
551
|
+
)
|
|
552
|
+
.all(id, type);
|
|
505
553
|
|
|
506
554
|
for (const dep of dependents) {
|
|
507
555
|
const depKey = `${dep.from_type}:${dep.from_id}`;
|
|
@@ -525,29 +573,33 @@ export class CodeEntityGraph {
|
|
|
525
573
|
* @returns {object}
|
|
526
574
|
*/
|
|
527
575
|
getTopology() {
|
|
528
|
-
const entityStats = this.db
|
|
529
|
-
|
|
576
|
+
const entityStats = this.db
|
|
577
|
+
.prepare(
|
|
578
|
+
`SELECT entity_type, COUNT(*) as count FROM code_entities
|
|
530
579
|
WHERE project_root = ? GROUP BY entity_type`
|
|
531
|
-
|
|
580
|
+
)
|
|
581
|
+
.all(this.projectRoot);
|
|
532
582
|
|
|
533
|
-
const edgeStats = this.db
|
|
534
|
-
`SELECT relation, COUNT(*) as count FROM knowledge_edges GROUP BY relation`
|
|
535
|
-
|
|
583
|
+
const edgeStats = this.db
|
|
584
|
+
.prepare(`SELECT relation, COUNT(*) as count FROM knowledge_edges GROUP BY relation`)
|
|
585
|
+
.all();
|
|
536
586
|
|
|
537
587
|
// 入度最高的实体 = 被依赖最多
|
|
538
|
-
const hotNodes = this.db
|
|
539
|
-
|
|
588
|
+
const hotNodes = this.db
|
|
589
|
+
.prepare(
|
|
590
|
+
`SELECT to_id, to_type, COUNT(*) as in_degree
|
|
540
591
|
FROM knowledge_edges
|
|
541
592
|
GROUP BY to_id, to_type
|
|
542
593
|
ORDER BY in_degree DESC LIMIT 15`
|
|
543
|
-
|
|
594
|
+
)
|
|
595
|
+
.all();
|
|
544
596
|
|
|
545
597
|
return {
|
|
546
|
-
entities: Object.fromEntries(entityStats.map(s => [s.entity_type, s.count])),
|
|
547
|
-
edges: Object.fromEntries(edgeStats.map(s => [s.relation, s.count])),
|
|
598
|
+
entities: Object.fromEntries(entityStats.map((s) => [s.entity_type, s.count])),
|
|
599
|
+
edges: Object.fromEntries(edgeStats.map((s) => [s.relation, s.count])),
|
|
548
600
|
totalEntities: entityStats.reduce((sum, s) => sum + s.count, 0),
|
|
549
601
|
totalEdges: edgeStats.reduce((sum, s) => sum + s.count, 0),
|
|
550
|
-
hotNodes: hotNodes.map(n => ({ id: n.to_id, type: n.to_type, inDegree: n.in_degree })),
|
|
602
|
+
hotNodes: hotNodes.map((n) => ({ id: n.to_id, type: n.to_type, inDegree: n.in_degree })),
|
|
551
603
|
};
|
|
552
604
|
}
|
|
553
605
|
|
|
@@ -560,10 +612,12 @@ export class CodeEntityGraph {
|
|
|
560
612
|
*/
|
|
561
613
|
generateContextForAgent(options = {}) {
|
|
562
614
|
const maxEntities = options.maxEntities || 30;
|
|
563
|
-
const
|
|
615
|
+
const _maxEdges = options.maxEdges || 50;
|
|
564
616
|
const topo = this.getTopology();
|
|
565
617
|
|
|
566
|
-
if (topo.totalEntities === 0)
|
|
618
|
+
if (topo.totalEntities === 0) {
|
|
619
|
+
return '';
|
|
620
|
+
}
|
|
567
621
|
|
|
568
622
|
const lines = [
|
|
569
623
|
'## 代码实体图谱 (Code Entity Graph)',
|
|
@@ -602,8 +656,10 @@ export class CodeEntityGraph {
|
|
|
602
656
|
lines.push('### 协议');
|
|
603
657
|
for (const p of protocols) {
|
|
604
658
|
const conformers = this.getDescendants(p.entityId, 'protocol', 1);
|
|
605
|
-
const cNames = conformers.map(c => c.id).slice(0, 5);
|
|
606
|
-
lines.push(
|
|
659
|
+
const cNames = conformers.map((c) => c.id).slice(0, 5);
|
|
660
|
+
lines.push(
|
|
661
|
+
`- \`${p.name}\` ← ${cNames.length > 0 ? cNames.map((n) => `\`${n}\``).join(', ') : '(无遵循者)'}`
|
|
662
|
+
);
|
|
607
663
|
}
|
|
608
664
|
lines.push('');
|
|
609
665
|
}
|
|
@@ -618,9 +674,11 @@ export class CodeEntityGraph {
|
|
|
618
674
|
const run = this.db.transaction(() => {
|
|
619
675
|
this.stmts.clearEntities.run(this.projectRoot);
|
|
620
676
|
// 只清除 AST 产出的边 (保留 recipe/module 边)
|
|
621
|
-
this.db
|
|
622
|
-
|
|
623
|
-
|
|
677
|
+
this.db
|
|
678
|
+
.prepare(
|
|
679
|
+
`DELETE FROM knowledge_edges WHERE metadata_json LIKE '%ast-bootstrap%' OR metadata_json LIKE '%ast-pattern-detection%'`
|
|
680
|
+
)
|
|
681
|
+
.run();
|
|
624
682
|
});
|
|
625
683
|
run();
|
|
626
684
|
this.log.info(`[CodeEntityGraph] Cleared entities for project: ${this.projectRoot}`);
|
|
@@ -675,9 +733,7 @@ export class CodeEntityGraph {
|
|
|
675
733
|
listByType: this.db.prepare(
|
|
676
734
|
`SELECT * FROM code_entities WHERE entity_type = ? AND project_root = ? ORDER BY name LIMIT ?`
|
|
677
735
|
),
|
|
678
|
-
clearEntities: this.db.prepare(
|
|
679
|
-
`DELETE FROM code_entities WHERE project_root = ?`
|
|
680
|
-
),
|
|
736
|
+
clearEntities: this.db.prepare(`DELETE FROM code_entities WHERE project_root = ?`),
|
|
681
737
|
addEdge: this.db.prepare(`
|
|
682
738
|
INSERT OR REPLACE INTO knowledge_edges (from_id, from_type, to_id, to_type, relation, weight, metadata_json, created_at, updated_at)
|
|
683
739
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
@@ -702,7 +758,7 @@ export class CodeEntityGraph {
|
|
|
702
758
|
JSON.stringify(entity.protocols || []),
|
|
703
759
|
JSON.stringify(entity.metadata || {}),
|
|
704
760
|
now,
|
|
705
|
-
now
|
|
761
|
+
now
|
|
706
762
|
);
|
|
707
763
|
}
|
|
708
764
|
|
|
@@ -710,10 +766,15 @@ export class CodeEntityGraph {
|
|
|
710
766
|
const now = Math.floor(Date.now() / 1000);
|
|
711
767
|
try {
|
|
712
768
|
this.stmts.addEdge.run(
|
|
713
|
-
fromId,
|
|
769
|
+
fromId,
|
|
770
|
+
fromType,
|
|
771
|
+
toId,
|
|
772
|
+
toType,
|
|
773
|
+
relation,
|
|
714
774
|
metadata.weight || 1.0,
|
|
715
775
|
JSON.stringify(metadata),
|
|
716
|
-
now,
|
|
776
|
+
now,
|
|
777
|
+
now
|
|
717
778
|
);
|
|
718
779
|
} catch (err) {
|
|
719
780
|
// Ignore duplicate edge errors
|
|
@@ -727,8 +788,12 @@ export class CodeEntityGraph {
|
|
|
727
788
|
* 从 AST 数据推断实体类型
|
|
728
789
|
*/
|
|
729
790
|
#inferEntityType(name, astSummary) {
|
|
730
|
-
if (astSummary.protocols?.some(p => p.name === name))
|
|
731
|
-
|
|
791
|
+
if (astSummary.protocols?.some((p) => p.name === name)) {
|
|
792
|
+
return 'protocol';
|
|
793
|
+
}
|
|
794
|
+
if (name.includes('(') && name.includes(')')) {
|
|
795
|
+
return 'category';
|
|
796
|
+
}
|
|
732
797
|
return 'class';
|
|
733
798
|
}
|
|
734
799
|
|
|
@@ -91,15 +91,15 @@ export class ConfidenceRouter {
|
|
|
91
91
|
if (this._qualityScorer) {
|
|
92
92
|
try {
|
|
93
93
|
const scorerInput = {
|
|
94
|
-
title:
|
|
95
|
-
trigger:
|
|
96
|
-
code:
|
|
97
|
-
language:
|
|
98
|
-
category:
|
|
99
|
-
summary:
|
|
94
|
+
title: entry.title,
|
|
95
|
+
trigger: entry.trigger,
|
|
96
|
+
code: entry.content?.pattern || entry.content?.markdown || '',
|
|
97
|
+
language: entry.language,
|
|
98
|
+
category: entry.category,
|
|
99
|
+
summary: entry.summaryCn || entry.summaryEn || '',
|
|
100
100
|
usageGuide: entry.usageGuideCn || entry.usageGuideEn || '',
|
|
101
|
-
headers:
|
|
102
|
-
tags:
|
|
101
|
+
headers: entry.headers || [],
|
|
102
|
+
tags: entry.tags || [],
|
|
103
103
|
};
|
|
104
104
|
const result = this._qualityScorer.score(scorerInput);
|
|
105
105
|
qualityScore = result.score;
|
|
@@ -143,13 +143,15 @@ export class ConfidenceRouter {
|
|
|
143
143
|
*/
|
|
144
144
|
_estimateContentLength(entry) {
|
|
145
145
|
const content = entry.content;
|
|
146
|
-
if (!content)
|
|
146
|
+
if (!content) {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
147
149
|
|
|
148
150
|
const parts = [
|
|
149
151
|
content.pattern,
|
|
150
152
|
content.rationale,
|
|
151
153
|
content.markdown,
|
|
152
|
-
...(content.steps || []).map(s => typeof s === 'string' ? s : s?.description || ''),
|
|
154
|
+
...(content.steps || []).map((s) => (typeof s === 'string' ? s : s?.description || '')),
|
|
153
155
|
].filter(Boolean);
|
|
154
156
|
|
|
155
157
|
return parts.reduce((sum, p) => sum + p.length, 0);
|