autosnippet 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +655 -260
- 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
|
@@ -37,15 +37,28 @@
|
|
|
37
37
|
|
|
38
38
|
import fs from 'node:fs';
|
|
39
39
|
import path from 'node:path';
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
import {
|
|
41
|
+
analyzeProject,
|
|
42
|
+
isAvailable as astIsAvailable,
|
|
43
|
+
generateContextForAgent,
|
|
44
|
+
} from '../../../core/AstAnalyzer.js';
|
|
45
|
+
import { DimensionCopy } from '../../../shared/DimensionCopyRegistry.js';
|
|
46
|
+
import { LanguageService } from '../../../shared/LanguageService.js';
|
|
44
47
|
import pathGuard from '../../../shared/PathGuard.js';
|
|
45
|
-
|
|
48
|
+
import { envelope } from '../envelope.js';
|
|
49
|
+
import {
|
|
50
|
+
clearCheckpoints,
|
|
51
|
+
clearSnapshots,
|
|
52
|
+
fillDimensionsV3,
|
|
53
|
+
} from './bootstrap/pipeline/orchestrator.js';
|
|
46
54
|
// ── Sub-modules ──
|
|
47
|
-
import {
|
|
48
|
-
|
|
55
|
+
import {
|
|
56
|
+
enhanceDimensions,
|
|
57
|
+
extractSkillDimensionGuides,
|
|
58
|
+
loadBootstrapSkills,
|
|
59
|
+
} from './bootstrap/skills.js';
|
|
60
|
+
import { buildLanguageExtension, detectPrimaryLanguage, inferLang } from './LanguageExtensions.js';
|
|
61
|
+
import { inferFilePriority, inferTargetRole } from './TargetClassifier.js';
|
|
49
62
|
|
|
50
63
|
// Re-export for external consumers
|
|
51
64
|
export { loadBootstrapSkills };
|
|
@@ -95,21 +108,26 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
95
108
|
};
|
|
96
109
|
|
|
97
110
|
// ═══════════════════════════════════════════════════════════
|
|
98
|
-
// Phase 1:
|
|
111
|
+
// Phase 1: 文件收集(通过 DiscovererRegistry 自动选择项目类型)
|
|
99
112
|
// ═══════════════════════════════════════════════════════════
|
|
100
|
-
const {
|
|
101
|
-
const
|
|
102
|
-
await
|
|
103
|
-
|
|
113
|
+
const { getDiscovererRegistry } = await import('../../../core/discovery/index.js');
|
|
114
|
+
const registry = getDiscovererRegistry();
|
|
115
|
+
const discoverer = await registry.detect(projectRoot);
|
|
116
|
+
ctx.logger.info(`[Bootstrap] Project type: ${discoverer.displayName} (${discoverer.id})`);
|
|
117
|
+
|
|
118
|
+
await discoverer.load(projectRoot);
|
|
119
|
+
const allTargets = await discoverer.listTargets();
|
|
104
120
|
|
|
105
121
|
const seenPaths = new Set();
|
|
106
122
|
const allFiles = []; // { name, path, relativePath, content, targetName }
|
|
107
123
|
for (const t of allTargets) {
|
|
108
124
|
try {
|
|
109
|
-
const fileList = await
|
|
125
|
+
const fileList = await discoverer.getTargetFiles(t);
|
|
110
126
|
for (const f of fileList) {
|
|
111
127
|
const fp = typeof f === 'string' ? f : f.path;
|
|
112
|
-
if (seenPaths.has(fp))
|
|
128
|
+
if (seenPaths.has(fp)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
113
131
|
seenPaths.add(fp);
|
|
114
132
|
try {
|
|
115
133
|
const content = fs.readFileSync(fp, 'utf8');
|
|
@@ -120,14 +138,24 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
120
138
|
content,
|
|
121
139
|
targetName: typeof t === 'string' ? t : t.name,
|
|
122
140
|
});
|
|
123
|
-
} catch {
|
|
124
|
-
|
|
141
|
+
} catch {
|
|
142
|
+
/* skip unreadable */
|
|
143
|
+
}
|
|
144
|
+
if (allFiles.length >= maxFiles) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
125
147
|
}
|
|
126
|
-
} catch {
|
|
127
|
-
|
|
148
|
+
} catch {
|
|
149
|
+
/* skip target */
|
|
150
|
+
}
|
|
151
|
+
if (allFiles.length >= maxFiles) {
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
report.phases.fileCollection = {
|
|
157
|
+
discoverer: discoverer.id,
|
|
158
|
+
discovererName: discoverer.displayName,
|
|
131
159
|
targets: allTargets.length,
|
|
132
160
|
files: allFiles.length,
|
|
133
161
|
truncated: allFiles.length >= maxFiles,
|
|
@@ -142,13 +170,27 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
142
170
|
try {
|
|
143
171
|
const db = ctx.container.get('database');
|
|
144
172
|
if (db) {
|
|
145
|
-
const { IncrementalBootstrap } = await import(
|
|
173
|
+
const { IncrementalBootstrap } = await import(
|
|
174
|
+
'./bootstrap/pipeline/IncrementalBootstrap.js'
|
|
175
|
+
);
|
|
146
176
|
const ib = new IncrementalBootstrap(db, projectRoot, { logger: ctx.logger });
|
|
147
|
-
//
|
|
177
|
+
// 所有可能的维度 ID(动态维度在后面按语言过滤 + Enhancement Pack 追加)
|
|
148
178
|
const allDimIds = [
|
|
149
|
-
'project-profile',
|
|
150
|
-
'code-standard',
|
|
151
|
-
'
|
|
179
|
+
'project-profile',
|
|
180
|
+
'code-standard',
|
|
181
|
+
'code-pattern',
|
|
182
|
+
'architecture',
|
|
183
|
+
'best-practice',
|
|
184
|
+
'event-and-data-flow',
|
|
185
|
+
'agent-guidelines',
|
|
186
|
+
// 语言条件维度
|
|
187
|
+
'objc-deep-scan',
|
|
188
|
+
'category-scan',
|
|
189
|
+
'module-export-scan',
|
|
190
|
+
'framework-convention-scan',
|
|
191
|
+
'python-package-scan',
|
|
192
|
+
'jvm-annotation-scan',
|
|
193
|
+
'go-module-scan',
|
|
152
194
|
];
|
|
153
195
|
incrementalPlan = ib.evaluate(allFiles, allDimIds);
|
|
154
196
|
report.phases.incrementalEvaluation = {
|
|
@@ -157,25 +199,29 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
157
199
|
affectedDimensions: incrementalPlan.affectedDimensions,
|
|
158
200
|
skippedDimensions: incrementalPlan.skippedDimensions,
|
|
159
201
|
reason: incrementalPlan.reason,
|
|
160
|
-
diff: incrementalPlan.diff
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
202
|
+
diff: incrementalPlan.diff
|
|
203
|
+
? {
|
|
204
|
+
added: incrementalPlan.diff.added.length,
|
|
205
|
+
modified: incrementalPlan.diff.modified.length,
|
|
206
|
+
deleted: incrementalPlan.diff.deleted.length,
|
|
207
|
+
unchanged: incrementalPlan.diff.unchanged.length,
|
|
208
|
+
changeRatio: incrementalPlan.diff.changeRatio,
|
|
209
|
+
}
|
|
210
|
+
: null,
|
|
167
211
|
};
|
|
168
212
|
if (incrementalPlan.canIncremental) {
|
|
169
213
|
ctx.logger.info(
|
|
170
214
|
`[Bootstrap] 🔄 Incremental mode: ${incrementalPlan.affectedDimensions.length} affected, ` +
|
|
171
|
-
|
|
215
|
+
`${incrementalPlan.skippedDimensions.length} skipped — ${incrementalPlan.reason}`
|
|
172
216
|
);
|
|
173
217
|
} else {
|
|
174
218
|
ctx.logger.info(`[Bootstrap] Full mode: ${incrementalPlan.reason}`);
|
|
175
219
|
}
|
|
176
220
|
}
|
|
177
221
|
} catch (incErr) {
|
|
178
|
-
ctx.logger.warn(
|
|
222
|
+
ctx.logger.warn(
|
|
223
|
+
`[Bootstrap] Incremental evaluation failed (fallback to full): ${incErr.message}`
|
|
224
|
+
);
|
|
179
225
|
}
|
|
180
226
|
}
|
|
181
227
|
|
|
@@ -197,24 +243,73 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
197
243
|
// ═══════════════════════════════════════════════════════════
|
|
198
244
|
// Phase 1.5: AST 代码结构分析(Tree-sitter)
|
|
199
245
|
// ═══════════════════════════════════════════════════════════
|
|
246
|
+
|
|
247
|
+
// ── Phase 1.5a: 按需安装缺失的 tree-sitter 语法包 ──────────
|
|
248
|
+
let grammarInstallResult = null;
|
|
249
|
+
try {
|
|
250
|
+
const { ensureGrammars, inferLanguagesFromStats, reloadPlugins } = await import(
|
|
251
|
+
'../../../core/ast/ensure-grammars.js'
|
|
252
|
+
);
|
|
253
|
+
const neededLangs = inferLanguagesFromStats(langStats);
|
|
254
|
+
if (neededLangs.length > 0) {
|
|
255
|
+
grammarInstallResult = await ensureGrammars(neededLangs, { logger: ctx.logger });
|
|
256
|
+
if (grammarInstallResult.installed.length > 0) {
|
|
257
|
+
ctx.logger.info(
|
|
258
|
+
`[Bootstrap] Installed grammar packages: ${grammarInstallResult.installed.join(', ')} — reloading AST plugins`
|
|
259
|
+
);
|
|
260
|
+
await reloadPlugins();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 确保 AST 插件已加载(即使没有新安装语法包 — 首次启动时需要触发 loadPlugins)
|
|
264
|
+
await import('../../../core/ast/index.js');
|
|
265
|
+
} catch (e) {
|
|
266
|
+
ctx.logger.warn(`[Bootstrap] Grammar auto-install skipped: ${e.message}`);
|
|
267
|
+
}
|
|
268
|
+
report.phases.grammarEnsure = grammarInstallResult || { installed: [], skipped: [], failed: [] };
|
|
269
|
+
|
|
270
|
+
// ── Phase 1.5b: AST 分析 ──────────────────────────────────
|
|
200
271
|
let astProjectSummary = null;
|
|
201
272
|
let astContext = '';
|
|
202
273
|
const primaryLangEarly = detectPrimaryLanguage(langStats);
|
|
203
274
|
if (astIsAvailable() && primaryLangEarly) {
|
|
204
275
|
try {
|
|
205
|
-
const astFiles = allFiles.map(f => ({
|
|
276
|
+
const astFiles = allFiles.map((f) => ({
|
|
206
277
|
name: f.name,
|
|
207
278
|
relativePath: f.relativePath,
|
|
208
279
|
content: f.content,
|
|
209
280
|
}));
|
|
210
|
-
|
|
281
|
+
|
|
282
|
+
// SFC 预处理: 支持 .vue / .svelte 等框架特有文件的 <script> 提取
|
|
283
|
+
let sfcPreprocessor = null;
|
|
284
|
+
try {
|
|
285
|
+
const { initEnhancementRegistry } = await import('../../../core/enhancement/index.js');
|
|
286
|
+
const enhReg = await initEnhancementRegistry();
|
|
287
|
+
const allPacks = enhReg.all();
|
|
288
|
+
// 找到第一个提供 preprocessFile 的增强包
|
|
289
|
+
const preprocessPack = allPacks.find(
|
|
290
|
+
(p) => typeof p.preprocessFile === 'function'
|
|
291
|
+
);
|
|
292
|
+
if (preprocessPack) {
|
|
293
|
+
sfcPreprocessor = preprocessPack.preprocessFile.bind(preprocessPack);
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
/* Enhancement 未加载时跳过预处理 */
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
astProjectSummary = analyzeProject(astFiles, primaryLangEarly, {
|
|
300
|
+
preprocessFile: sfcPreprocessor,
|
|
301
|
+
});
|
|
211
302
|
astContext = generateContextForAgent(astProjectSummary);
|
|
212
|
-
ctx.logger.info(
|
|
303
|
+
ctx.logger.info(
|
|
304
|
+
`[Bootstrap] AST analysis: ${astProjectSummary.classes.length} classes, ${astProjectSummary.protocols.length} protocols, ${astProjectSummary.categories.length} categories, ${Object.keys(astProjectSummary.patternStats).length} patterns`
|
|
305
|
+
);
|
|
213
306
|
} catch (e) {
|
|
214
307
|
ctx.logger.warn(`[Bootstrap] AST analysis failed (graceful degradation): ${e.message}`);
|
|
215
308
|
}
|
|
216
309
|
} else {
|
|
217
|
-
ctx.logger.info(
|
|
310
|
+
ctx.logger.info(
|
|
311
|
+
`[Bootstrap] AST analysis skipped: tree-sitter ${astIsAvailable() ? 'available' : 'not available'}, lang=${primaryLangEarly}`
|
|
312
|
+
);
|
|
218
313
|
}
|
|
219
314
|
report.phases.astAnalysis = {
|
|
220
315
|
available: astIsAvailable(),
|
|
@@ -238,7 +333,7 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
238
333
|
codeEntityResult = ceg.populateFromAst(astProjectSummary);
|
|
239
334
|
ctx.logger.info(
|
|
240
335
|
`[Bootstrap] Code Entity Graph: ${codeEntityResult.entitiesUpserted} entities, ` +
|
|
241
|
-
|
|
336
|
+
`${codeEntityResult.edgesCreated} edges (${codeEntityResult.durationMs}ms)`
|
|
242
337
|
);
|
|
243
338
|
}
|
|
244
339
|
} catch (e) {
|
|
@@ -252,39 +347,48 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
252
347
|
};
|
|
253
348
|
|
|
254
349
|
// ═══════════════════════════════════════════════════════════
|
|
255
|
-
// Phase 2:
|
|
350
|
+
// Phase 2: 依赖关系 → knowledge_edges
|
|
256
351
|
// ═══════════════════════════════════════════════════════════
|
|
257
352
|
let depEdgesWritten = 0;
|
|
258
353
|
let depGraphData = null;
|
|
259
354
|
try {
|
|
260
355
|
const knowledgeGraphService = ctx.container.get('knowledgeGraphService');
|
|
261
|
-
depGraphData = await
|
|
356
|
+
depGraphData = await discoverer.getDependencyGraph();
|
|
262
357
|
if (knowledgeGraphService) {
|
|
263
|
-
for (const edge of
|
|
358
|
+
for (const edge of depGraphData.edges || []) {
|
|
264
359
|
const result = knowledgeGraphService.addEdge(
|
|
265
|
-
edge.from,
|
|
266
|
-
|
|
360
|
+
edge.from,
|
|
361
|
+
'module',
|
|
362
|
+
edge.to,
|
|
363
|
+
'module',
|
|
364
|
+
'depends_on',
|
|
365
|
+
{ weight: 1.0, source: `${discoverer.id}-bootstrap` }
|
|
267
366
|
);
|
|
268
|
-
if (result.success)
|
|
367
|
+
if (result.success) {
|
|
368
|
+
depEdgesWritten++;
|
|
369
|
+
}
|
|
269
370
|
}
|
|
270
371
|
}
|
|
271
372
|
} catch (e) {
|
|
272
|
-
ctx.logger.warn(`[Bootstrap]
|
|
373
|
+
ctx.logger.warn(`[Bootstrap] DepGraph failed: ${e.message}`);
|
|
273
374
|
}
|
|
274
|
-
report.phases.
|
|
375
|
+
report.phases.dependencyGraph = { edgesWritten: depEdgesWritten };
|
|
275
376
|
|
|
276
|
-
// Phase 2.1:
|
|
377
|
+
// Phase 2.1: Module 实体节点写入 Code Entity Graph
|
|
277
378
|
if (depGraphData?.nodes?.length > 0) {
|
|
278
379
|
try {
|
|
279
380
|
const { CodeEntityGraph } = await import('../../../service/knowledge/CodeEntityGraph.js');
|
|
280
381
|
const db = ctx.container.get('database');
|
|
281
382
|
if (db) {
|
|
282
383
|
const ceg = new CodeEntityGraph(db, { projectRoot });
|
|
283
|
-
|
|
284
|
-
|
|
384
|
+
// populateFromSpm 接受通用的 { nodes, edges } 结构,不仅限于 SPM
|
|
385
|
+
const depResult = ceg.populateFromSpm(depGraphData);
|
|
386
|
+
ctx.logger.info(
|
|
387
|
+
`[Bootstrap] Code Entity Graph modules: ${depResult.entitiesUpserted} entities`
|
|
388
|
+
);
|
|
285
389
|
}
|
|
286
390
|
} catch (e) {
|
|
287
|
-
ctx.logger.warn(`[Bootstrap] Code Entity Graph
|
|
391
|
+
ctx.logger.warn(`[Bootstrap] Code Entity Graph modules failed: ${e.message}`);
|
|
288
392
|
}
|
|
289
393
|
}
|
|
290
394
|
|
|
@@ -297,13 +401,13 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
297
401
|
const { GuardCheckEngine } = await import('../../../service/guard/GuardCheckEngine.js');
|
|
298
402
|
const db = ctx.container.get('database');
|
|
299
403
|
const engine = new GuardCheckEngine(db);
|
|
300
|
-
const guardFiles = allFiles.map(f => ({ path: f.path, content: f.content }));
|
|
404
|
+
const guardFiles = allFiles.map((f) => ({ path: f.path, content: f.content }));
|
|
301
405
|
guardAudit = engine.auditFiles(guardFiles, { scope: 'project' });
|
|
302
406
|
|
|
303
407
|
// 写入 ViolationsStore
|
|
304
408
|
try {
|
|
305
409
|
const violationsStore = ctx.container.get('violationsStore');
|
|
306
|
-
for (const fileResult of
|
|
410
|
+
for (const fileResult of guardAudit.files || []) {
|
|
307
411
|
if (fileResult.violations.length > 0) {
|
|
308
412
|
violationsStore.appendRun({
|
|
309
413
|
filePath: fileResult.filePath,
|
|
@@ -312,27 +416,31 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
312
416
|
});
|
|
313
417
|
}
|
|
314
418
|
}
|
|
315
|
-
} catch {
|
|
419
|
+
} catch {
|
|
420
|
+
/* ViolationsStore not available */
|
|
421
|
+
}
|
|
316
422
|
} catch (e) {
|
|
317
423
|
ctx.logger.warn(`[Bootstrap] Guard audit failed: ${e.message}`);
|
|
318
424
|
}
|
|
319
425
|
}
|
|
320
426
|
report.phases.guardAudit = {
|
|
321
427
|
totalViolations: guardAudit?.summary?.totalViolations || 0,
|
|
322
|
-
filesWithViolations: (guardAudit?.files || []).filter(f => f.violations.length > 0).length,
|
|
428
|
+
filesWithViolations: (guardAudit?.files || []).filter((f) => f.violations.length > 0).length,
|
|
323
429
|
skipped: skipGuard,
|
|
324
430
|
};
|
|
325
431
|
report.totals.guardViolations = guardAudit?.summary?.totalViolations || 0;
|
|
326
432
|
report.totals.graphEdges = depEdgesWritten;
|
|
327
433
|
|
|
328
|
-
const
|
|
434
|
+
const _elapsed = Date.now() - t0;
|
|
329
435
|
|
|
330
436
|
// ═══════════════════════════════════════════════════════════
|
|
331
437
|
// Phase 4: 构建响应 — filesByTarget + analysisFramework
|
|
332
438
|
// ═══════════════════════════════════════════════════════════
|
|
333
439
|
const targetFileMap = {};
|
|
334
440
|
for (const f of allFiles) {
|
|
335
|
-
if (!targetFileMap[f.targetName])
|
|
441
|
+
if (!targetFileMap[f.targetName]) {
|
|
442
|
+
targetFileMap[f.targetName] = [];
|
|
443
|
+
}
|
|
336
444
|
const lines = f.content.split('\n');
|
|
337
445
|
targetFileMap[f.targetName].push({
|
|
338
446
|
name: f.name,
|
|
@@ -370,17 +478,23 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
370
478
|
const skillsEnhanced = Object.keys(skillGuides).length > 0;
|
|
371
479
|
|
|
372
480
|
if (skillsEnhanced) {
|
|
373
|
-
ctx.logger.info(
|
|
481
|
+
ctx.logger.info(
|
|
482
|
+
`[Bootstrap] Skill dimension guides extracted for: ${Object.keys(skillGuides).join(', ')}`
|
|
483
|
+
);
|
|
374
484
|
// 输出每个 guide 的前 80 字符用于诊断
|
|
375
485
|
for (const [dimId, guide] of Object.entries(skillGuides)) {
|
|
376
486
|
ctx.logger.debug(`[Bootstrap] Skill guide [${dimId}]: ${guide.substring(0, 80)}...`);
|
|
377
487
|
}
|
|
378
488
|
// 输出 sectionMap 诊断
|
|
379
489
|
for (const [dimId, sections] of Object.entries(skillSections)) {
|
|
380
|
-
ctx.logger.debug(
|
|
490
|
+
ctx.logger.debug(
|
|
491
|
+
`[Bootstrap] Skill sections [${dimId}]: ${sections.length} section(s) — ${sections.map((s) => s.title).join(', ')}`
|
|
492
|
+
);
|
|
381
493
|
}
|
|
382
494
|
} else {
|
|
383
|
-
ctx.logger.warn(
|
|
495
|
+
ctx.logger.warn(
|
|
496
|
+
'[Bootstrap] No skill dimension guides extracted — Skills may not match expected format'
|
|
497
|
+
);
|
|
384
498
|
}
|
|
385
499
|
|
|
386
500
|
report.phases.skillLoading = {
|
|
@@ -398,41 +512,278 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
398
512
|
// ⑧ ⑨ 提前到 ⑥ 前面执行 → deep-scan / category-scan 的中间结果
|
|
399
513
|
// 通过 PipelineContext 缓存,供 project-profile 复用,避免重复扫描
|
|
400
514
|
const baseDimensions = [
|
|
401
|
-
//
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
//
|
|
419
|
-
{
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
//
|
|
426
|
-
{
|
|
427
|
-
|
|
515
|
+
// ── 通用维度(所有语言共享)──────────────────────────────────
|
|
516
|
+
|
|
517
|
+
// ① 代码规范(Dual: Skill + Candidate)
|
|
518
|
+
{
|
|
519
|
+
id: 'code-standard',
|
|
520
|
+
label: '代码规范',
|
|
521
|
+
guide:
|
|
522
|
+
'命名约定(类名前缀/方法签名风格/API 命名)、注释风格(语言/格式/MARK 分段)、文件组织规范',
|
|
523
|
+
knowledgeTypes: ['code-standard', 'code-style'],
|
|
524
|
+
skillWorthy: true,
|
|
525
|
+
dualOutput: true,
|
|
526
|
+
skillMeta: {
|
|
527
|
+
name: 'project-code-standard',
|
|
528
|
+
description:
|
|
529
|
+
'Project coding standards and naming conventions (auto-generated by bootstrap)',
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
// ② 代码模式(Candidate)
|
|
533
|
+
{
|
|
534
|
+
id: 'code-pattern',
|
|
535
|
+
label: '设计模式与代码惯例',
|
|
536
|
+
guide: '单例/委托/Category·Extension/工厂/Builder/观察者/Coordinator 模式、继承关系',
|
|
537
|
+
knowledgeTypes: ['code-pattern', 'code-relation', 'inheritance'],
|
|
538
|
+
},
|
|
539
|
+
// ③ 架构模式(Dual: Skill + Candidate)
|
|
540
|
+
{
|
|
541
|
+
id: 'architecture',
|
|
542
|
+
label: '架构模式',
|
|
543
|
+
guide: '分层架构、模块职责与边界、依赖图、导入约束规则',
|
|
544
|
+
knowledgeTypes: ['architecture', 'module-dependency', 'boundary-constraint'],
|
|
545
|
+
skillWorthy: true,
|
|
546
|
+
dualOutput: true,
|
|
547
|
+
skillMeta: {
|
|
548
|
+
name: 'project-architecture',
|
|
549
|
+
description:
|
|
550
|
+
'Project architecture layers, module boundaries and dependency graph (auto-generated by bootstrap)',
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
// ④ 最佳实践(Candidate)
|
|
554
|
+
{
|
|
555
|
+
id: 'best-practice',
|
|
556
|
+
label: '最佳实践',
|
|
557
|
+
guide: '错误处理、并发安全、内存管理、日志规范、测试模式',
|
|
558
|
+
knowledgeTypes: ['best-practice'],
|
|
559
|
+
},
|
|
560
|
+
// ⑤ 事件与数据流(Candidate)
|
|
561
|
+
{
|
|
562
|
+
id: 'event-and-data-flow',
|
|
563
|
+
label: '事件与数据流',
|
|
564
|
+
guide:
|
|
565
|
+
'事件传播(Delegate/Notification/Block·Closure/Target-Action)、数据状态管理(KVO/属性观察/响应式/持久化)',
|
|
566
|
+
knowledgeTypes: ['call-chain', 'data-flow'],
|
|
567
|
+
},
|
|
568
|
+
// ⑥ 项目特征(Dual: Skill + Candidate)
|
|
569
|
+
{
|
|
570
|
+
id: 'project-profile',
|
|
571
|
+
label: '项目特征',
|
|
572
|
+
guide:
|
|
573
|
+
'技术栈、目录结构、三方依赖枚举与用途、Extension/Category 分类聚合、自定义基类层级与全局定义(宏/typealias/PCH)、系统事件 hook 与生命周期入口、基础设施服务注册表、Runtime 与语言互操作',
|
|
574
|
+
knowledgeTypes: ['architecture'],
|
|
575
|
+
skillWorthy: true,
|
|
576
|
+
dualOutput: true,
|
|
577
|
+
skillMeta: {
|
|
578
|
+
name: 'project-profile',
|
|
579
|
+
description:
|
|
580
|
+
'Project tech stack, module structure, third-party dependencies, base extensions/classes, event hooks, infrastructure services, and runtime/interop features (auto-generated by bootstrap)',
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
// ⑦ Agent 开发注意事项(Skill)
|
|
584
|
+
{
|
|
585
|
+
id: 'agent-guidelines',
|
|
586
|
+
label: 'Agent开发注意事项',
|
|
587
|
+
guide:
|
|
588
|
+
'三大核心原则(严谨性/深度特征挖掘/完整性)、命名强制、线程安全、内存约束、已废弃 API 标记、架构约束注释、TODO/FIXME',
|
|
589
|
+
knowledgeTypes: ['boundary-constraint', 'code-standard'],
|
|
590
|
+
skillWorthy: true,
|
|
591
|
+
skillMeta: {
|
|
592
|
+
name: 'project-agent-guidelines',
|
|
593
|
+
description:
|
|
594
|
+
'Mandatory coding rules, deprecated APIs and agent constraints for this project (auto-generated by bootstrap)',
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
|
|
598
|
+
// ── 语言条件维度(按 conditions 过滤)──────────────────────
|
|
599
|
+
|
|
600
|
+
// ⑧ ObjC/Swift 深度扫描
|
|
601
|
+
{
|
|
602
|
+
id: 'objc-deep-scan',
|
|
603
|
+
label: '深度扫描(常量/Hook)',
|
|
604
|
+
guide:
|
|
605
|
+
'全量扫描 #define 值宏/函数宏、extern/static 常量、Method Swizzling hook 对(Agent 必须使用项目常量,修改被 hook 方法前必须查阅 hook 清单)',
|
|
606
|
+
knowledgeTypes: ['code-standard', 'code-pattern'],
|
|
607
|
+
conditions: { languages: ['objectivec', 'swift'] },
|
|
608
|
+
skillWorthy: true,
|
|
609
|
+
dualOutput: true,
|
|
610
|
+
skillMeta: {
|
|
611
|
+
name: 'project-objc-deep-scan',
|
|
612
|
+
description:
|
|
613
|
+
'Project #define macros, static constants, and Method Swizzling hooks (auto-generated by bootstrap)',
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
// ⑨ Foundation/UIKit Category/Extension 专项扫描
|
|
617
|
+
{
|
|
618
|
+
id: 'category-scan',
|
|
619
|
+
label: '基础类分类方法扫描',
|
|
620
|
+
guide:
|
|
621
|
+
'Foundation/UIKit Category/Extension 逐方法清单(含完整实现代码与项目使用频次),仅扫描基础类分类、不含业务代码(Agent 遇到同等功能必须使用项目已有分类方法,禁止重复实现)',
|
|
622
|
+
knowledgeTypes: ['code-standard', 'code-pattern'],
|
|
623
|
+
conditions: { languages: ['objectivec', 'swift'] },
|
|
624
|
+
skillWorthy: true,
|
|
625
|
+
dualOutput: true,
|
|
626
|
+
skillMeta: {
|
|
627
|
+
name: 'project-category-scan',
|
|
628
|
+
description:
|
|
629
|
+
'Foundation/UIKit Category and Extension methods with implementations and usage patterns — base classes only, no business code (auto-generated by bootstrap)',
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
|
|
633
|
+
// ⑩ TS/JS 模块导出分析
|
|
634
|
+
{
|
|
635
|
+
id: 'module-export-scan',
|
|
636
|
+
label: '模块导出分析',
|
|
637
|
+
guide: 'barrel export 结构、re-export 链路、public API surface、tree-shaking 合规性',
|
|
638
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
639
|
+
conditions: { languages: ['typescript', 'javascript'] },
|
|
640
|
+
skillWorthy: true,
|
|
641
|
+
dualOutput: true,
|
|
642
|
+
skillMeta: {
|
|
643
|
+
name: 'project-module-exports',
|
|
644
|
+
description: 'Module export structure and public API surface (auto-generated by bootstrap)',
|
|
645
|
+
},
|
|
646
|
+
},
|
|
647
|
+
// ⑪ TS/JS 框架约定扫描
|
|
648
|
+
{
|
|
649
|
+
id: 'framework-convention-scan',
|
|
650
|
+
label: '框架约定扫描',
|
|
651
|
+
guide: '组件目录结构、状态管理约定、路由约定、样式约定、数据获取模式',
|
|
652
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
653
|
+
conditions: {
|
|
654
|
+
languages: ['typescript', 'javascript'],
|
|
655
|
+
frameworks: ['react', 'vue', 'angular', 'nextjs', 'nuxt'],
|
|
656
|
+
},
|
|
657
|
+
skillWorthy: true,
|
|
658
|
+
dualOutput: true,
|
|
659
|
+
skillMeta: {
|
|
660
|
+
name: 'project-framework-conventions',
|
|
661
|
+
description: 'Framework-specific conventions and patterns (auto-generated by bootstrap)',
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
|
|
665
|
+
// ⑫ Python 包结构分析
|
|
666
|
+
{
|
|
667
|
+
id: 'python-package-scan',
|
|
668
|
+
label: 'Python 包结构分析',
|
|
669
|
+
guide:
|
|
670
|
+
'__init__.py 导出策略、相对/绝对导入风格、type hints 覆盖率、decorator 使用模式、__all__ 定义',
|
|
671
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
672
|
+
conditions: { languages: ['python'] },
|
|
673
|
+
skillWorthy: true,
|
|
674
|
+
dualOutput: true,
|
|
675
|
+
skillMeta: {
|
|
676
|
+
name: 'project-python-structure',
|
|
677
|
+
description:
|
|
678
|
+
'Python package structure, import patterns and type hint coverage (auto-generated by bootstrap)',
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
|
|
682
|
+
// ⑬ Java/Kotlin 注解扫描
|
|
683
|
+
{
|
|
684
|
+
id: 'jvm-annotation-scan',
|
|
685
|
+
label: '注解/Annotation 扫描',
|
|
686
|
+
guide:
|
|
687
|
+
'DI 注解(@Inject/@Autowired/@Component)、ORM 注解(@Entity/@Table)、API 注解(@RestController/@RequestMapping)、自定义注解、元编程模式',
|
|
688
|
+
knowledgeTypes: ['code-pattern', 'architecture'],
|
|
689
|
+
conditions: { languages: ['java', 'kotlin'] },
|
|
690
|
+
skillWorthy: true,
|
|
691
|
+
dualOutput: true,
|
|
692
|
+
skillMeta: {
|
|
693
|
+
name: 'project-jvm-annotations',
|
|
694
|
+
description:
|
|
695
|
+
'Annotation/DI usage patterns and meta-programming (auto-generated by bootstrap)',
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
|
|
699
|
+
// ⑭ Go 模块结构分析
|
|
700
|
+
{
|
|
701
|
+
id: 'go-module-scan',
|
|
702
|
+
label: 'Go 模块结构分析',
|
|
703
|
+
guide:
|
|
704
|
+
'go.mod 依赖图、internal 包隔离边界、cmd/ 入口点枚举、build tags/constraints、interface 分布与实现关系、init() 函数清单',
|
|
705
|
+
knowledgeTypes: ['architecture', 'code-pattern'],
|
|
706
|
+
conditions: { languages: ['go'] },
|
|
707
|
+
skillWorthy: true,
|
|
708
|
+
dualOutput: true,
|
|
709
|
+
skillMeta: {
|
|
710
|
+
name: 'project-go-module-structure',
|
|
711
|
+
description:
|
|
712
|
+
'Go module structure, internal packages, build tags and interface distribution (auto-generated by bootstrap)',
|
|
713
|
+
},
|
|
714
|
+
},
|
|
428
715
|
];
|
|
429
716
|
|
|
717
|
+
// ── 根据项目主语言和框架过滤条件维度 ──────────────────────
|
|
718
|
+
const detectedFrameworks = allTargets
|
|
719
|
+
.map((t) => (typeof t === 'object' ? t.framework : null))
|
|
720
|
+
.filter(Boolean);
|
|
721
|
+
const activeDimensions = _resolveActiveDimensions(
|
|
722
|
+
baseDimensions,
|
|
723
|
+
primaryLang,
|
|
724
|
+
detectedFrameworks
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
// ── Enhancement Pack 动态追加维度 + Guard 规则 ─────────────
|
|
728
|
+
const enhancementPackInfo = [];
|
|
729
|
+
const enhancementGuardRules = [];
|
|
730
|
+
const enhancementPatterns = [];
|
|
731
|
+
try {
|
|
732
|
+
const { initEnhancementRegistry } = await import('../../../core/enhancement/index.js');
|
|
733
|
+
const enhReg = await initEnhancementRegistry();
|
|
734
|
+
const matchedPacks = enhReg.resolve(primaryLang, detectedFrameworks);
|
|
735
|
+
for (const pack of matchedPacks) {
|
|
736
|
+
enhancementPackInfo.push({ id: pack.id, displayName: pack.displayName });
|
|
737
|
+
// 追加额外维度
|
|
738
|
+
const extraDims = pack.getExtraDimensions();
|
|
739
|
+
for (const dim of extraDims) {
|
|
740
|
+
// 避免与 baseDimensions 中已有的 id 重复
|
|
741
|
+
if (!activeDimensions.some((d) => d.id === dim.id)) {
|
|
742
|
+
activeDimensions.push(dim);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
// 收集 Guard 规则
|
|
746
|
+
const guardRules = pack.getGuardRules();
|
|
747
|
+
if (guardRules.length > 0) {
|
|
748
|
+
enhancementGuardRules.push(...guardRules);
|
|
749
|
+
}
|
|
750
|
+
// 收集 AST 模式检测
|
|
751
|
+
if (astProjectSummary) {
|
|
752
|
+
try {
|
|
753
|
+
const patterns = pack.detectPatterns(astProjectSummary);
|
|
754
|
+
if (patterns.length > 0) {
|
|
755
|
+
enhancementPatterns.push(...patterns.map((p) => ({ ...p, source: pack.id })));
|
|
756
|
+
}
|
|
757
|
+
} catch {
|
|
758
|
+
/* graceful degradation */
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (matchedPacks.length > 0) {
|
|
763
|
+
ctx.logger.info(
|
|
764
|
+
`[Bootstrap] Enhancement packs matched: ${matchedPacks.map((p) => p.id).join(', ')} → +${activeDimensions.length - baseDimensions.length} extra dims, ${enhancementGuardRules.length} guard rules, ${enhancementPatterns.length} patterns`
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
} catch (enhErr) {
|
|
768
|
+
ctx.logger.warn(`[Bootstrap] Enhancement pack loading skipped: ${enhErr.message}`);
|
|
769
|
+
}
|
|
770
|
+
report.phases.enhancementPacks = {
|
|
771
|
+
matched: enhancementPackInfo,
|
|
772
|
+
extraDimensions: enhancementPackInfo.length,
|
|
773
|
+
guardRules: enhancementGuardRules.length,
|
|
774
|
+
patterns: enhancementPatterns.length,
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// 按项目语言画像注入差异化文案(支持多语言项目)
|
|
778
|
+
const langProfile = LanguageService.detectProfile(langStats);
|
|
779
|
+
DimensionCopy.applyMulti(activeDimensions, langProfile.primary, langProfile.secondary);
|
|
780
|
+
|
|
430
781
|
// 用 Skill 内容增强维度 guide(共享层增强点)
|
|
431
|
-
const dimensions = enhanceDimensions(
|
|
782
|
+
const dimensions = enhanceDimensions(activeDimensions, skillGuides, skillSections);
|
|
432
783
|
|
|
433
784
|
const responseData = {
|
|
434
785
|
report,
|
|
435
|
-
targets: allTargets.map(t => {
|
|
786
|
+
targets: allTargets.map((t) => {
|
|
436
787
|
const name = typeof t === 'string' ? t : t.name;
|
|
437
788
|
return {
|
|
438
789
|
name,
|
|
@@ -448,65 +799,102 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
448
799
|
Object.entries(targetFileMap).map(([target, files]) => {
|
|
449
800
|
const sorted = [...files].sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
450
801
|
const top = sorted.slice(0, 10);
|
|
451
|
-
return [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
802
|
+
return [
|
|
803
|
+
target,
|
|
804
|
+
{
|
|
805
|
+
totalFiles: files.length,
|
|
806
|
+
topFiles: top.map(({ content, ...meta }) => meta),
|
|
807
|
+
...(files.length > 10 ? { truncated: true } : {}),
|
|
808
|
+
},
|
|
809
|
+
];
|
|
456
810
|
})
|
|
457
811
|
),
|
|
458
|
-
dependencyGraph: depGraphData
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
812
|
+
dependencyGraph: depGraphData
|
|
813
|
+
? {
|
|
814
|
+
nodes: (depGraphData.nodes || []).map((n) => ({
|
|
815
|
+
id: typeof n === 'string' ? n : n.id,
|
|
816
|
+
label: typeof n === 'string' ? n : n.label,
|
|
817
|
+
})),
|
|
818
|
+
edges: depGraphData.edges || [],
|
|
819
|
+
}
|
|
820
|
+
: null,
|
|
465
821
|
languageStats: langStats,
|
|
466
822
|
primaryLanguage: primaryLang,
|
|
823
|
+
secondaryLanguages: langProfile.secondary,
|
|
824
|
+
isMultiLang: langProfile.isMultiLang,
|
|
467
825
|
languageExtension: buildLanguageExtension(primaryLang),
|
|
468
|
-
guardSummary: guardAudit
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
826
|
+
guardSummary: guardAudit
|
|
827
|
+
? {
|
|
828
|
+
totalViolations: guardAudit.summary?.totalViolations || 0,
|
|
829
|
+
errors: guardAudit.summary?.errors || 0,
|
|
830
|
+
warnings: guardAudit.summary?.warnings || 0,
|
|
831
|
+
}
|
|
832
|
+
: null,
|
|
473
833
|
guardViolationFiles: guardAudit
|
|
474
|
-
? (guardAudit.files || [])
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
834
|
+
? (guardAudit.files || [])
|
|
835
|
+
.filter((f) => f.violations.length > 0)
|
|
836
|
+
.map((f) => ({
|
|
837
|
+
filePath: f.filePath,
|
|
838
|
+
violations: f.violations.map((v) => ({
|
|
839
|
+
ruleId: v.ruleId,
|
|
840
|
+
severity: v.severity,
|
|
841
|
+
message: v.message,
|
|
842
|
+
line: v.line,
|
|
843
|
+
})),
|
|
844
|
+
}))
|
|
478
845
|
: [],
|
|
479
846
|
|
|
480
847
|
// 9 维度分析框架(4 Skill-only + 2 dualOutput + 3 Candidate-only)
|
|
481
848
|
// 注意:anti-pattern 已移除,代码问题由 Guard 独立处理
|
|
482
849
|
analysisFramework: {
|
|
483
850
|
dimensions,
|
|
484
|
-
skillWorthyDimensions: dimensions.filter(d => d.skillWorthy).map(d => d.id),
|
|
485
|
-
candidateOnlyDimensions: dimensions.filter(d => !d.skillWorthy).map(d => d.id),
|
|
486
|
-
candidateRequiredFields: [
|
|
851
|
+
skillWorthyDimensions: dimensions.filter((d) => d.skillWorthy).map((d) => d.id),
|
|
852
|
+
candidateOnlyDimensions: dimensions.filter((d) => !d.skillWorthy).map((d) => d.id),
|
|
853
|
+
candidateRequiredFields: [
|
|
854
|
+
'title',
|
|
855
|
+
'code',
|
|
856
|
+
'language',
|
|
857
|
+
'category',
|
|
858
|
+
'knowledgeType',
|
|
859
|
+
'reasoning',
|
|
860
|
+
],
|
|
487
861
|
submissionTool: 'autosnippet_submit_knowledge_batch',
|
|
488
|
-
expectedOutput:
|
|
862
|
+
expectedOutput: `候选知识(微观代码维度:code-pattern/best-practice/event-and-data-flow + 语言条件扫描)+ Project Skills(宏观叙事维度:code-standard/architecture/project-profile/agent-guidelines + 语言条件扫描)— 共 ${dimensions.length} 个维度`,
|
|
489
863
|
},
|
|
490
864
|
|
|
491
865
|
// AST 代码结构分析上下文(供 ChatAgent 使用)
|
|
492
866
|
astContext: astContext || null,
|
|
493
|
-
astSummary: astProjectSummary
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
867
|
+
astSummary: astProjectSummary
|
|
868
|
+
? {
|
|
869
|
+
classes: astProjectSummary.classes.length,
|
|
870
|
+
protocols: astProjectSummary.protocols.length,
|
|
871
|
+
categories: astProjectSummary.categories.length,
|
|
872
|
+
patterns: Object.keys(astProjectSummary.patternStats || {}),
|
|
873
|
+
metrics: astProjectSummary.projectMetrics
|
|
874
|
+
? {
|
|
875
|
+
totalMethods: astProjectSummary.projectMetrics.totalMethods,
|
|
876
|
+
avgMethodsPerClass: astProjectSummary.projectMetrics.avgMethodsPerClass,
|
|
877
|
+
maxNestingDepth: astProjectSummary.projectMetrics.maxNestingDepth,
|
|
878
|
+
complexMethods: astProjectSummary.projectMetrics.complexMethods?.length || 0,
|
|
879
|
+
longMethods: astProjectSummary.projectMetrics.longMethods?.length || 0,
|
|
880
|
+
}
|
|
881
|
+
: null,
|
|
882
|
+
}
|
|
883
|
+
: null,
|
|
884
|
+
|
|
885
|
+
// Enhancement Pack 检测到的额外模式
|
|
886
|
+
enhancementPacks:
|
|
887
|
+
enhancementPackInfo.length > 0
|
|
888
|
+
? {
|
|
889
|
+
matched: enhancementPackInfo,
|
|
890
|
+
patterns: enhancementPatterns,
|
|
891
|
+
guardRules: enhancementGuardRules.length,
|
|
892
|
+
}
|
|
893
|
+
: null,
|
|
506
894
|
|
|
507
895
|
// 引导 Agent 下一步操作
|
|
508
896
|
nextSteps: [
|
|
509
|
-
|
|
897
|
+
`✅ Bootstrap 骨架已创建,${dimensions.length} 个维度的 AI 分析任务已在后台启动。`,
|
|
510
898
|
'',
|
|
511
899
|
'== 后台自动执行中 ==',
|
|
512
900
|
'后台 AI pipeline 正在逐维度分析代码并创建候选(Analyst → Producer 双 Agent 模式)。',
|
|
@@ -519,7 +907,10 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
519
907
|
'4. 使用 autosnippet_skill({ operation: "load", name }) 加载自动生成的 Project Skills',
|
|
520
908
|
'',
|
|
521
909
|
'== 宏观维度 → Project Skills ==',
|
|
522
|
-
|
|
910
|
+
`宏观维度(${dimensions
|
|
911
|
+
.filter((d) => d.skillWorthy)
|
|
912
|
+
.map((d) => d.id)
|
|
913
|
+
.join('/')})`,
|
|
523
914
|
'自动生成 Project Skill 到 AutoSnippet/skills/,可通过 autosnippet_skill({ operation: "load" }) 加载。',
|
|
524
915
|
],
|
|
525
916
|
};
|
|
@@ -534,7 +925,7 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
534
925
|
// ═══════════════════════════════════════════════════════════
|
|
535
926
|
|
|
536
927
|
// 构建任务定义列表
|
|
537
|
-
const taskDefs = dimensions.map(dim => ({
|
|
928
|
+
const taskDefs = dimensions.map((dim) => ({
|
|
538
929
|
id: dim.id,
|
|
539
930
|
meta: {
|
|
540
931
|
type: dim.skillWorthy ? 'skill' : 'candidate',
|
|
@@ -551,7 +942,9 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
551
942
|
const taskManager = ctx.container.get('bootstrapTaskManager');
|
|
552
943
|
bootstrapSession = taskManager.startSession(taskDefs);
|
|
553
944
|
} catch (e) {
|
|
554
|
-
ctx.logger.warn(
|
|
945
|
+
ctx.logger.warn(
|
|
946
|
+
`[Bootstrap] BootstrapTaskManager init failed (graceful degradation): ${e.message}`
|
|
947
|
+
);
|
|
555
948
|
}
|
|
556
949
|
|
|
557
950
|
// 立即构建骨架响应
|
|
@@ -575,7 +968,13 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
575
968
|
astProjectSummary,
|
|
576
969
|
skillContext,
|
|
577
970
|
skillsEnhanced,
|
|
578
|
-
taskManager: (() => {
|
|
971
|
+
taskManager: (() => {
|
|
972
|
+
try {
|
|
973
|
+
return ctx.container.get('bootstrapTaskManager');
|
|
974
|
+
} catch {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
})(),
|
|
579
978
|
sessionId: bootstrapSession?.id || null,
|
|
580
979
|
projectRoot,
|
|
581
980
|
// v5.0: 增量 Bootstrap 计划
|
|
@@ -585,7 +984,7 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
585
984
|
// 使用 setImmediate 避免阻塞 HTTP 响应
|
|
586
985
|
setImmediate(() => {
|
|
587
986
|
ctx.logger.info(`[Bootstrap] Dispatching v3 AI-First pipeline`);
|
|
588
|
-
fillDimensionsV3(fillContext).catch(e => {
|
|
987
|
+
fillDimensionsV3(fillContext).catch((e) => {
|
|
589
988
|
ctx.logger.error(`[Bootstrap] Async fill (v3) failed: ${e.message}`);
|
|
590
989
|
});
|
|
591
990
|
});
|
|
@@ -593,16 +992,23 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
593
992
|
// ── SkillHooks: onBootstrapStarted (fire-and-forget) ──
|
|
594
993
|
try {
|
|
595
994
|
const skillHooks = ctx.container.get('skillHooks');
|
|
596
|
-
skillHooks
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
995
|
+
skillHooks
|
|
996
|
+
.run(
|
|
997
|
+
'onBootstrapComplete',
|
|
998
|
+
{
|
|
999
|
+
filesScanned: allFiles.length,
|
|
1000
|
+
targetsFound: allTargets.length,
|
|
1001
|
+
candidatesCreated: 0, // 异步填充中,初始为 0
|
|
1002
|
+
candidatesFailed: 0,
|
|
1003
|
+
autoSkillsCreated: 0,
|
|
1004
|
+
autoSkills: [],
|
|
1005
|
+
},
|
|
1006
|
+
{ projectRoot: ctx.container.get('database')?.filename || '' }
|
|
1007
|
+
)
|
|
604
1008
|
.catch(() => {}); // fire-and-forget
|
|
605
|
-
} catch {
|
|
1009
|
+
} catch {
|
|
1010
|
+
/* skillHooks not available */
|
|
1011
|
+
}
|
|
606
1012
|
|
|
607
1013
|
return envelope({
|
|
608
1014
|
success: true,
|
|
@@ -629,7 +1035,11 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
629
1035
|
const aiProvider = ctx.container.get('aiProvider');
|
|
630
1036
|
|
|
631
1037
|
if (!aiProvider) {
|
|
632
|
-
return envelope({
|
|
1038
|
+
return envelope({
|
|
1039
|
+
success: false,
|
|
1040
|
+
message: 'AI provider not configured',
|
|
1041
|
+
errorCode: 'MISSING_AI_PROVIDER',
|
|
1042
|
+
});
|
|
633
1043
|
}
|
|
634
1044
|
|
|
635
1045
|
// 接入 BootstrapTaskManager 双通道推送 refine:* 事件
|
|
@@ -637,7 +1047,9 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
637
1047
|
try {
|
|
638
1048
|
const taskManager = ctx.container.get('bootstrapTaskManager');
|
|
639
1049
|
onProgress = (eventName, data) => taskManager.emitProgress(eventName, data);
|
|
640
|
-
} catch {
|
|
1050
|
+
} catch {
|
|
1051
|
+
/* optional */
|
|
1052
|
+
}
|
|
641
1053
|
|
|
642
1054
|
// 1. 收集待润色条目
|
|
643
1055
|
let entries;
|
|
@@ -645,21 +1057,39 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
645
1057
|
entries = [];
|
|
646
1058
|
for (const id of args.candidateIds) {
|
|
647
1059
|
const e = await knowledgeService.get(id);
|
|
648
|
-
if (e)
|
|
1060
|
+
if (e) {
|
|
1061
|
+
entries.push(typeof e.toJSON === 'function' ? e.toJSON() : e);
|
|
1062
|
+
}
|
|
649
1063
|
}
|
|
650
1064
|
} else {
|
|
651
|
-
const result = await knowledgeService.list(
|
|
652
|
-
|
|
1065
|
+
const result = await knowledgeService.list(
|
|
1066
|
+
{ lifecycle: 'pending', source: 'bootstrap' },
|
|
1067
|
+
{ page: 1, pageSize: 200 }
|
|
1068
|
+
);
|
|
1069
|
+
entries = (result.items || []).map((e) => (typeof e.toJSON === 'function' ? e.toJSON() : e));
|
|
653
1070
|
}
|
|
654
1071
|
|
|
655
1072
|
if (entries.length === 0) {
|
|
656
|
-
return envelope({
|
|
1073
|
+
return envelope({
|
|
1074
|
+
success: true,
|
|
1075
|
+
data: { refined: 0, total: 0, errors: [], results: [] },
|
|
1076
|
+
meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
|
|
1077
|
+
});
|
|
657
1078
|
}
|
|
658
1079
|
|
|
659
|
-
onProgress?.('refine:started', { total: entries.length, candidateIds: entries.map(e => e.id) });
|
|
1080
|
+
onProgress?.('refine:started', { total: entries.length, candidateIds: entries.map((e) => e.id) });
|
|
660
1081
|
|
|
661
|
-
// 2.
|
|
662
|
-
|
|
1082
|
+
// 2. 收集已发布 Recipe 标题(关联关系只能指向已发布 Recipe,不能在候选之间互关联)
|
|
1083
|
+
let publishedTitles = [];
|
|
1084
|
+
try {
|
|
1085
|
+
const published = await knowledgeService.list(
|
|
1086
|
+
{ lifecycle: 'active' },
|
|
1087
|
+
{ page: 1, pageSize: 200 }
|
|
1088
|
+
);
|
|
1089
|
+
publishedTitles = (published.items || []).map((e) => e.title).filter(Boolean);
|
|
1090
|
+
} catch { /* ignore */ }
|
|
1091
|
+
|
|
1092
|
+
// 3. 逐条 AI 润色
|
|
663
1093
|
const results = [];
|
|
664
1094
|
const errors = [];
|
|
665
1095
|
let refined = 0;
|
|
@@ -667,7 +1097,13 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
667
1097
|
|
|
668
1098
|
for (const entry of entries) {
|
|
669
1099
|
processed++;
|
|
670
|
-
onProgress?.('refine:item-started', {
|
|
1100
|
+
onProgress?.('refine:item-started', {
|
|
1101
|
+
candidateId: entry.id,
|
|
1102
|
+
title: entry.title,
|
|
1103
|
+
current: processed,
|
|
1104
|
+
total: entries.length,
|
|
1105
|
+
progress: Math.round(((processed - 1) / entries.length) * 100),
|
|
1106
|
+
});
|
|
671
1107
|
|
|
672
1108
|
try {
|
|
673
1109
|
const before = {
|
|
@@ -685,7 +1121,7 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
685
1121
|
|
|
686
1122
|
const refineInstruction = args.userPrompt
|
|
687
1123
|
? args.userPrompt
|
|
688
|
-
: '
|
|
1124
|
+
: '请改善描述使其更专业简洁,补充高阶架构洞察';
|
|
689
1125
|
|
|
690
1126
|
const prompt = `你是一位高级代码知识管理专家。请改进以下知识条目。
|
|
691
1127
|
|
|
@@ -736,7 +1172,7 @@ ${before.aiInsight || '(空)'}
|
|
|
736
1172
|
【agentNotes】Agent 笔记
|
|
737
1173
|
${JSON.stringify(before.agentNotes || [])}
|
|
738
1174
|
|
|
739
|
-
|
|
1175
|
+
${publishedTitles.length > 0 ? `已发布的 Recipe: ${publishedTitles.slice(0, 20).join(', ')}` : '(尚无已发布的 Recipe)'}
|
|
740
1176
|
|
|
741
1177
|
## 润色指令
|
|
742
1178
|
|
|
@@ -747,7 +1183,8 @@ ${refineInstruction}
|
|
|
747
1183
|
1. 只修改需要改进的字段,未涉及的必须原样返回。
|
|
748
1184
|
2. tags 采用合并策略(保留原有 + 补充新建议),不要删除已有标签。
|
|
749
1185
|
3. relations 为 object 格式,key 为关系类型(如 inherits/implements/calls/depends_on/extends/related),value 为 string[]。
|
|
750
|
-
4.
|
|
1186
|
+
4. relations 只能指向已发布的 Recipe,不能在候选之间建立关联。如果没有已发布的 Recipe,relations 应保持为空 {}。
|
|
1187
|
+
5. 每个 key 都必须存在,key 名称必须与上述完全一致。
|
|
751
1188
|
|
|
752
1189
|
仅返回 JSON,不要添加任何其他文字或代码块标记。`;
|
|
753
1190
|
|
|
@@ -755,39 +1192,77 @@ ${refineInstruction}
|
|
|
755
1192
|
|
|
756
1193
|
if (!parsed) {
|
|
757
1194
|
errors.push({ id: entry.id, title: entry.title, error: 'AI returned no valid JSON' });
|
|
758
|
-
onProgress?.('refine:item-failed', {
|
|
1195
|
+
onProgress?.('refine:item-failed', {
|
|
1196
|
+
candidateId: entry.id,
|
|
1197
|
+
title: entry.title,
|
|
1198
|
+
error: 'No valid JSON',
|
|
1199
|
+
current: processed,
|
|
1200
|
+
total: entries.length,
|
|
1201
|
+
progress: Math.round((processed / entries.length) * 100),
|
|
1202
|
+
});
|
|
759
1203
|
continue;
|
|
760
1204
|
}
|
|
761
1205
|
|
|
762
1206
|
if (args.dryRun) {
|
|
763
1207
|
results.push({ id: entry.id, title: entry.title, preview: parsed });
|
|
764
|
-
onProgress?.('refine:item-completed', {
|
|
1208
|
+
onProgress?.('refine:item-completed', {
|
|
1209
|
+
candidateId: entry.id,
|
|
1210
|
+
title: entry.title,
|
|
1211
|
+
refined: false,
|
|
1212
|
+
current: processed,
|
|
1213
|
+
total: entries.length,
|
|
1214
|
+
progress: Math.round((processed / entries.length) * 100),
|
|
1215
|
+
});
|
|
765
1216
|
continue;
|
|
766
1217
|
}
|
|
767
1218
|
|
|
768
1219
|
// ─── key 别名归一化(与 candidates.js 保持一致) ───
|
|
769
1220
|
const KEY_ALIASES = {
|
|
770
|
-
summary: 'description',
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1221
|
+
summary: 'description',
|
|
1222
|
+
desc: 'description',
|
|
1223
|
+
content: 'pattern',
|
|
1224
|
+
design: 'rationale',
|
|
1225
|
+
designRationale: 'rationale',
|
|
1226
|
+
markdownDoc: 'markdown',
|
|
1227
|
+
doc: 'markdown',
|
|
1228
|
+
tag: 'tags',
|
|
1229
|
+
label: 'tags',
|
|
1230
|
+
labels: 'tags',
|
|
774
1231
|
score: 'confidence',
|
|
775
|
-
ai_insight: 'aiInsight',
|
|
776
|
-
|
|
1232
|
+
ai_insight: 'aiInsight',
|
|
1233
|
+
insight: 'aiInsight',
|
|
1234
|
+
aiinsight: 'aiInsight',
|
|
1235
|
+
agent_notes: 'agentNotes',
|
|
1236
|
+
notes: 'agentNotes',
|
|
1237
|
+
agentnotes: 'agentNotes',
|
|
777
1238
|
relation: 'relations',
|
|
778
1239
|
};
|
|
779
|
-
const VALID_KEYS = new Set([
|
|
1240
|
+
const VALID_KEYS = new Set([
|
|
1241
|
+
'description',
|
|
1242
|
+
'pattern',
|
|
1243
|
+
'markdown',
|
|
1244
|
+
'rationale',
|
|
1245
|
+
'tags',
|
|
1246
|
+
'confidence',
|
|
1247
|
+
'aiInsight',
|
|
1248
|
+
'agentNotes',
|
|
1249
|
+
'relations',
|
|
1250
|
+
]);
|
|
780
1251
|
const normalized = {};
|
|
781
1252
|
for (const [key, value] of Object.entries(parsed)) {
|
|
782
1253
|
if (VALID_KEYS.has(key)) {
|
|
783
1254
|
normalized[key] = value;
|
|
784
1255
|
} else {
|
|
785
1256
|
const mapped = KEY_ALIASES[key] || KEY_ALIASES[key.toLowerCase?.()];
|
|
786
|
-
if (mapped && !(mapped in normalized))
|
|
1257
|
+
if (mapped && !(mapped in normalized)) {
|
|
1258
|
+
normalized[mapped] = value;
|
|
1259
|
+
}
|
|
787
1260
|
}
|
|
788
1261
|
}
|
|
789
1262
|
for (const k of VALID_KEYS) {
|
|
790
|
-
if (!(k in normalized))
|
|
1263
|
+
if (!(k in normalized)) {
|
|
1264
|
+
normalized[k] = before[k];
|
|
1265
|
+
}
|
|
791
1266
|
}
|
|
792
1267
|
|
|
793
1268
|
// 构建更新数据
|
|
@@ -806,7 +1281,10 @@ ${refineInstruction}
|
|
|
806
1281
|
changed = true;
|
|
807
1282
|
}
|
|
808
1283
|
}
|
|
809
|
-
if (
|
|
1284
|
+
if (
|
|
1285
|
+
typeof normalized.confidence === 'number' &&
|
|
1286
|
+
normalized.confidence !== before.confidence
|
|
1287
|
+
) {
|
|
810
1288
|
updateData.reasoning = { ...(entry.reasoning || {}), confidence: normalized.confidence };
|
|
811
1289
|
changed = true;
|
|
812
1290
|
}
|
|
@@ -853,11 +1331,31 @@ ${refineInstruction}
|
|
|
853
1331
|
refined++;
|
|
854
1332
|
}
|
|
855
1333
|
|
|
856
|
-
results.push({
|
|
857
|
-
|
|
1334
|
+
results.push({
|
|
1335
|
+
id: entry.id,
|
|
1336
|
+
title: entry.title,
|
|
1337
|
+
refined: changed,
|
|
1338
|
+
fields: Object.keys(parsed),
|
|
1339
|
+
});
|
|
1340
|
+
onProgress?.('refine:item-completed', {
|
|
1341
|
+
candidateId: entry.id,
|
|
1342
|
+
title: entry.title,
|
|
1343
|
+
refined: changed,
|
|
1344
|
+
current: processed,
|
|
1345
|
+
total: entries.length,
|
|
1346
|
+
progress: Math.round((processed / entries.length) * 100),
|
|
1347
|
+
refinedSoFar: refined,
|
|
1348
|
+
});
|
|
858
1349
|
} catch (err) {
|
|
859
1350
|
errors.push({ id: entry.id, title: entry.title, error: err.message });
|
|
860
|
-
onProgress?.('refine:item-failed', {
|
|
1351
|
+
onProgress?.('refine:item-failed', {
|
|
1352
|
+
candidateId: entry.id,
|
|
1353
|
+
title: entry.title,
|
|
1354
|
+
error: err.message,
|
|
1355
|
+
current: processed,
|
|
1356
|
+
total: entries.length,
|
|
1357
|
+
progress: Math.round((processed / entries.length) * 100),
|
|
1358
|
+
});
|
|
861
1359
|
}
|
|
862
1360
|
}
|
|
863
1361
|
|
|
@@ -875,3 +1373,28 @@ ${refineInstruction}
|
|
|
875
1373
|
meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
|
|
876
1374
|
});
|
|
877
1375
|
}
|
|
1376
|
+
|
|
1377
|
+
// ══════════════════════════════════════════════════════════════════
|
|
1378
|
+
// 内部辅助 — 维度条件化
|
|
1379
|
+
// ══════════════════════════════════════════════════════════════════
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* 根据项目主语言和检测到的框架过滤条件维度
|
|
1383
|
+
* @param {Array} allDimensions 所有维度定义(含 conditions 字段)
|
|
1384
|
+
* @param {string} primaryLang 主语言
|
|
1385
|
+
* @param {string[]} detectedFrameworks 检测到的框架
|
|
1386
|
+
* @returns {Array} 适用的维度列表
|
|
1387
|
+
*/
|
|
1388
|
+
function _resolveActiveDimensions(allDimensions, primaryLang, detectedFrameworks = []) {
|
|
1389
|
+
return allDimensions.filter((dim) => {
|
|
1390
|
+
if (!dim.conditions) {
|
|
1391
|
+
return true; // 无条件 → 通用维度
|
|
1392
|
+
}
|
|
1393
|
+
const langMatch = !dim.conditions.languages || dim.conditions.languages.includes(primaryLang);
|
|
1394
|
+
const fwMatch =
|
|
1395
|
+
!dim.conditions.frameworks ||
|
|
1396
|
+
dim.conditions.frameworks.some((f) => detectedFrameworks.includes(f));
|
|
1397
|
+
// languages 必须匹配;frameworks 为可选增强(有 frameworks 条件时必须至少命中一个)
|
|
1398
|
+
return langMatch && (dim.conditions.frameworks ? fwMatch : true);
|
|
1399
|
+
});
|
|
1400
|
+
}
|