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
|
@@ -11,19 +11,19 @@
|
|
|
11
11
|
* @module pipeline/orchestrator
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import path from 'node:path';
|
|
15
14
|
import fs from 'node:fs/promises';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import Logger from '../../../../../infrastructure/logging/Logger.js';
|
|
16
17
|
import { AnalystAgent } from '../../../../../service/chat/AnalystAgent.js';
|
|
18
|
+
import { EpisodicConsolidator } from '../../../../../service/chat/EpisodicConsolidator.js';
|
|
17
19
|
import { ProducerAgent } from '../../../../../service/chat/ProducerAgent.js';
|
|
18
|
-
import {
|
|
20
|
+
import { ProjectSemanticMemory } from '../../../../../service/chat/ProjectSemanticMemory.js';
|
|
21
|
+
import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
|
|
19
22
|
import { DimensionContext, parseDimensionDigest } from './dimension-context.js';
|
|
20
23
|
import { EpisodicMemory } from './EpisodicMemory.js';
|
|
21
|
-
import { ToolResultCache } from './ToolResultCache.js';
|
|
22
|
-
import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
|
|
23
|
-
import { ProjectSemanticMemory } from '../../../../../service/chat/ProjectSemanticMemory.js';
|
|
24
|
-
import { EpisodicConsolidator } from '../../../../../service/chat/EpisodicConsolidator.js';
|
|
25
24
|
import { IncrementalBootstrap } from './IncrementalBootstrap.js';
|
|
26
|
-
import
|
|
25
|
+
import { ToolResultCache } from './ToolResultCache.js';
|
|
26
|
+
import { TierScheduler } from './tier-scheduler.js';
|
|
27
27
|
|
|
28
28
|
const logger = Logger.getInstance();
|
|
29
29
|
|
|
@@ -47,7 +47,7 @@ async function saveDimensionCheckpoint(projectRoot, sessionId, dimId, result, di
|
|
|
47
47
|
await fs.mkdir(checkpointDir, { recursive: true });
|
|
48
48
|
await fs.writeFile(
|
|
49
49
|
path.join(checkpointDir, `${dimId}.json`),
|
|
50
|
-
JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() })
|
|
50
|
+
JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() })
|
|
51
51
|
);
|
|
52
52
|
} catch (err) {
|
|
53
53
|
logger.warn(`[Bootstrap-v3] checkpoint save failed for "${dimId}": ${err.message}`);
|
|
@@ -66,16 +66,22 @@ async function loadCheckpoints(projectRoot) {
|
|
|
66
66
|
const files = await fs.readdir(checkpointDir).catch(() => []);
|
|
67
67
|
const now = Date.now();
|
|
68
68
|
for (const file of files) {
|
|
69
|
-
if (!file.endsWith('.json'))
|
|
69
|
+
if (!file.endsWith('.json')) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
70
72
|
try {
|
|
71
73
|
const content = await fs.readFile(path.join(checkpointDir, file), 'utf-8');
|
|
72
74
|
const data = JSON.parse(content);
|
|
73
|
-
if (data.completedAt &&
|
|
75
|
+
if (data.completedAt && now - data.completedAt < CHECKPOINT_TTL_MS) {
|
|
74
76
|
checkpoints.set(data.dimId, data);
|
|
75
77
|
}
|
|
76
|
-
} catch {
|
|
78
|
+
} catch {
|
|
79
|
+
/* skip corrupt checkpoint */
|
|
80
|
+
}
|
|
77
81
|
}
|
|
78
|
-
} catch {
|
|
82
|
+
} catch {
|
|
83
|
+
/* checkpoint dir doesn't exist */
|
|
84
|
+
}
|
|
79
85
|
return checkpoints;
|
|
80
86
|
}
|
|
81
87
|
|
|
@@ -87,7 +93,9 @@ async function clearCheckpoints(projectRoot) {
|
|
|
87
93
|
try {
|
|
88
94
|
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
89
95
|
await fs.rm(checkpointDir, { recursive: true, force: true });
|
|
90
|
-
} catch {
|
|
96
|
+
} catch {
|
|
97
|
+
/* ignore */
|
|
98
|
+
}
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -98,11 +106,7 @@ const DIMENSION_CONFIGS_V3 = {
|
|
|
98
106
|
'project-profile': {
|
|
99
107
|
label: '项目概貌',
|
|
100
108
|
guide: '分析项目的整体结构、技术栈、模块划分和入口点。',
|
|
101
|
-
focusAreas: [
|
|
102
|
-
'项目结构和模块划分',
|
|
103
|
-
'技术栈和框架依赖',
|
|
104
|
-
'核心入口点和启动流程',
|
|
105
|
-
],
|
|
109
|
+
focusAreas: ['项目结构和模块划分', '技术栈和框架依赖', '核心入口点和启动流程'],
|
|
106
110
|
outputType: 'dual',
|
|
107
111
|
allowedKnowledgeTypes: ['architecture'],
|
|
108
112
|
},
|
|
@@ -140,7 +144,7 @@ const DIMENSION_CONFIGS_V3 = {
|
|
|
140
144
|
outputType: 'dual',
|
|
141
145
|
allowedKnowledgeTypes: ['code-standard', 'code-style'],
|
|
142
146
|
},
|
|
143
|
-
|
|
147
|
+
architecture: {
|
|
144
148
|
label: '架构模式',
|
|
145
149
|
guide: '分析项目的分层架构、模块职责和依赖关系。',
|
|
146
150
|
focusAreas: [
|
|
@@ -200,6 +204,57 @@ const DIMENSION_CONFIGS_V3 = {
|
|
|
200
204
|
outputType: 'skill',
|
|
201
205
|
allowedKnowledgeTypes: ['boundary-constraint', 'code-standard'],
|
|
202
206
|
},
|
|
207
|
+
|
|
208
|
+
// ── 语言条件维度(v3.1: 多语言支持)──────────────────────
|
|
209
|
+
|
|
210
|
+
'module-export-scan': {
|
|
211
|
+
label: '模块导出分析',
|
|
212
|
+
guide: '分析 TS/JS 模块的导出结构和 public API surface。',
|
|
213
|
+
focusAreas: [
|
|
214
|
+
'barrel export 结构和 re-export 链路',
|
|
215
|
+
'public API surface 合规性',
|
|
216
|
+
'tree-shaking 兼容性',
|
|
217
|
+
'循环依赖检测',
|
|
218
|
+
],
|
|
219
|
+
outputType: 'dual',
|
|
220
|
+
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
221
|
+
},
|
|
222
|
+
'framework-convention-scan': {
|
|
223
|
+
label: '框架约定扫描',
|
|
224
|
+
guide: '分析前端框架约定(组件结构、状态管理、路由)。',
|
|
225
|
+
focusAreas: [
|
|
226
|
+
'组件目录结构和命名约定',
|
|
227
|
+
'状态管理模式 (Redux/Vuex/Pinia/Zustand)',
|
|
228
|
+
'路由约定和数据获取模式',
|
|
229
|
+
'样式约定 (CSS Module/Tailwind/CSS-in-JS)',
|
|
230
|
+
],
|
|
231
|
+
outputType: 'dual',
|
|
232
|
+
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
233
|
+
},
|
|
234
|
+
'python-package-scan': {
|
|
235
|
+
label: 'Python 包结构分析',
|
|
236
|
+
guide: '分析 Python 包的导入风格、类型标注和 __init__.py 策略。',
|
|
237
|
+
focusAreas: [
|
|
238
|
+
'__init__.py 导出策略和 __all__ 定义',
|
|
239
|
+
'相对/绝对导入风格',
|
|
240
|
+
'type hints 覆盖率和 Protocol 使用',
|
|
241
|
+
'decorator 使用模式',
|
|
242
|
+
],
|
|
243
|
+
outputType: 'dual',
|
|
244
|
+
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
245
|
+
},
|
|
246
|
+
'jvm-annotation-scan': {
|
|
247
|
+
label: '注解/Annotation 扫描',
|
|
248
|
+
guide: '扫描 Java/Kotlin 项目中的 DI、ORM、API 注解使用模式。',
|
|
249
|
+
focusAreas: [
|
|
250
|
+
'DI 注解 (@Inject/@Autowired/@Component)',
|
|
251
|
+
'ORM 注解 (@Entity/@Table/@Column)',
|
|
252
|
+
'API 注解 (@RestController/@RequestMapping)',
|
|
253
|
+
'自定义注解和元编程模式',
|
|
254
|
+
],
|
|
255
|
+
outputType: 'dual',
|
|
256
|
+
allowedKnowledgeTypes: ['code-pattern', 'architecture'],
|
|
257
|
+
},
|
|
203
258
|
};
|
|
204
259
|
|
|
205
260
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -251,7 +306,7 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
|
251
306
|
}
|
|
252
307
|
}
|
|
253
308
|
// 统计关键词
|
|
254
|
-
const words = (f.finding || '').split(/[\s,,。.]+/).filter(w => w.length > 3);
|
|
309
|
+
const words = (f.finding || '').split(/[\s,,。.]+/).filter((w) => w.length > 3);
|
|
255
310
|
for (const w of words) {
|
|
256
311
|
keywordMentions[w] = (keywordMentions[w] || 0) + 1;
|
|
257
312
|
}
|
|
@@ -262,18 +317,14 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
|
262
317
|
// 多维度引用的文件 = 跨维度热点
|
|
263
318
|
for (const [file, count] of Object.entries(fileMentions)) {
|
|
264
319
|
if (count >= 2) {
|
|
265
|
-
crossDimensionPatterns.push(
|
|
266
|
-
`文件 "${file}" 被 ${count} 个维度引用 — 可能是系统核心组件`
|
|
267
|
-
);
|
|
320
|
+
crossDimensionPatterns.push(`文件 "${file}" 被 ${count} 个维度引用 — 可能是系统核心组件`);
|
|
268
321
|
}
|
|
269
322
|
}
|
|
270
323
|
|
|
271
324
|
// 多维度提及的关键词
|
|
272
325
|
for (const [word, count] of Object.entries(keywordMentions)) {
|
|
273
326
|
if (count >= 3) {
|
|
274
|
-
crossDimensionPatterns.push(
|
|
275
|
-
`关键词 "${word}" 出现 ${count} 次 — 跨维度关联主题`
|
|
276
|
-
);
|
|
327
|
+
crossDimensionPatterns.push(`关键词 "${word}" 出现 ${count} 次 — 跨维度关联主题`);
|
|
277
328
|
}
|
|
278
329
|
}
|
|
279
330
|
|
|
@@ -324,14 +375,22 @@ function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
|
324
375
|
*/
|
|
325
376
|
export async function fillDimensionsV3(fillContext) {
|
|
326
377
|
const {
|
|
327
|
-
ctx,
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
378
|
+
ctx,
|
|
379
|
+
dimensions,
|
|
380
|
+
taskManager,
|
|
381
|
+
sessionId,
|
|
382
|
+
projectRoot,
|
|
383
|
+
depGraphData,
|
|
384
|
+
guardAudit,
|
|
385
|
+
primaryLang,
|
|
386
|
+
astProjectSummary,
|
|
387
|
+
incrementalPlan, // v5.0: 增量 Bootstrap 计划 (from bootstrap.js)
|
|
331
388
|
} = fillContext;
|
|
332
389
|
|
|
333
390
|
const isIncremental = incrementalPlan?.canIncremental && incrementalPlan?.mode === 'incremental';
|
|
334
|
-
logger.info(
|
|
391
|
+
logger.info(
|
|
392
|
+
`[Bootstrap-v3] ═══ fillDimensionsV3 entered — ${isIncremental ? 'INCREMENTAL' : 'FULL'} pipeline`
|
|
393
|
+
);
|
|
335
394
|
|
|
336
395
|
let allFiles = fillContext.allFiles;
|
|
337
396
|
fillContext.allFiles = null;
|
|
@@ -342,9 +401,15 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
342
401
|
let chatAgent = null;
|
|
343
402
|
try {
|
|
344
403
|
chatAgent = ctx.container.get('chatAgent');
|
|
345
|
-
if (chatAgent && !chatAgent.hasRealAI)
|
|
346
|
-
|
|
347
|
-
|
|
404
|
+
if (chatAgent && !chatAgent.hasRealAI) {
|
|
405
|
+
chatAgent = null;
|
|
406
|
+
}
|
|
407
|
+
if (chatAgent) {
|
|
408
|
+
chatAgent.resetGlobalSubmittedTitles();
|
|
409
|
+
}
|
|
410
|
+
} catch {
|
|
411
|
+
/* not available */
|
|
412
|
+
}
|
|
348
413
|
|
|
349
414
|
if (!chatAgent) {
|
|
350
415
|
logger.info('[Bootstrap-v3] AI not available — aborting v3 pipeline');
|
|
@@ -368,7 +433,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
368
433
|
});
|
|
369
434
|
if (projectGraph) {
|
|
370
435
|
const overview = projectGraph.getOverview();
|
|
371
|
-
logger.info(
|
|
436
|
+
logger.info(
|
|
437
|
+
`[Bootstrap-v3] ProjectGraph: ${overview.totalClasses} classes, ${overview.totalProtocols} protocols (${overview.buildTimeMs}ms)`
|
|
438
|
+
);
|
|
372
439
|
}
|
|
373
440
|
} catch (e) {
|
|
374
441
|
logger.warn(`[Bootstrap-v3] ProjectGraph build failed: ${e.message}`);
|
|
@@ -386,7 +453,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
386
453
|
// 项目信息
|
|
387
454
|
const projectInfo = {
|
|
388
455
|
name: path.basename(projectRoot),
|
|
389
|
-
lang: primaryLang || '
|
|
456
|
+
lang: primaryLang || 'unknown',
|
|
390
457
|
fileCount: allFiles?.length || 0,
|
|
391
458
|
};
|
|
392
459
|
|
|
@@ -408,7 +475,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
408
475
|
if (isIncremental && incrementalPlan.restoredEpisodic) {
|
|
409
476
|
episodicMemory = incrementalPlan.restoredEpisodic;
|
|
410
477
|
const restoredDims = episodicMemory.getCompletedDimensions();
|
|
411
|
-
logger.info(
|
|
478
|
+
logger.info(
|
|
479
|
+
`[Bootstrap-v3] Restored EpisodicMemory: ${restoredDims.length} dims [${restoredDims.join(', ')}]`
|
|
480
|
+
);
|
|
412
481
|
|
|
413
482
|
// 同步恢复 DimensionContext 的 digests (兼容)
|
|
414
483
|
for (const dimId of restoredDims) {
|
|
@@ -440,7 +509,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
440
509
|
if (smStats.total > 0) {
|
|
441
510
|
logger.info(
|
|
442
511
|
`[Bootstrap-v3] Loaded ${smStats.total} semantic memories from previous bootstrap ` +
|
|
443
|
-
|
|
512
|
+
`(fact: ${smStats.byType.fact || 0}, insight: ${smStats.byType.insight || 0}, preference: ${smStats.byType.preference || 0})`
|
|
444
513
|
);
|
|
445
514
|
}
|
|
446
515
|
}
|
|
@@ -473,10 +542,8 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
473
542
|
const enableParallel = process.env.ASD_PARALLEL_BOOTSTRAP !== 'false';
|
|
474
543
|
const scheduler = new TierScheduler();
|
|
475
544
|
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
.map(d => d.id)
|
|
479
|
-
.filter(id => DIMENSION_CONFIGS_V3[id]);
|
|
545
|
+
// 包含所有维度(含 Enhancement Pack 动态追加的维度)
|
|
546
|
+
const activeDimIds = dimensions.map((d) => d.id);
|
|
480
547
|
|
|
481
548
|
// v5.0: 增量模式 — 仅执行受影响维度, 跳过未变更维度
|
|
482
549
|
const incrementalSkippedDims = [];
|
|
@@ -495,12 +562,14 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
495
562
|
if (incrementalSkippedDims.length > 0) {
|
|
496
563
|
logger.info(
|
|
497
564
|
`[Bootstrap-v3] ⏩ Incremental skip: [${incrementalSkippedDims.join(', ')}] ` +
|
|
498
|
-
|
|
565
|
+
`(using historical results)`
|
|
499
566
|
);
|
|
500
567
|
}
|
|
501
568
|
}
|
|
502
569
|
|
|
503
|
-
logger.info(
|
|
570
|
+
logger.info(
|
|
571
|
+
`[Bootstrap-v3] Active dimensions: [${activeDimIds.join(', ')}], concurrency=${enableParallel ? concurrency : 1}${isIncremental ? `, incremental skip: [${incrementalSkippedDims.join(', ')}]` : ''}`
|
|
572
|
+
);
|
|
504
573
|
|
|
505
574
|
// ── P3: 断点续传 — 加载有效 checkpoints ──
|
|
506
575
|
const completedCheckpoints = await loadCheckpoints(projectRoot);
|
|
@@ -585,27 +654,43 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
585
654
|
referencedFiles: restoredFiles,
|
|
586
655
|
candidatesSummary: [],
|
|
587
656
|
});
|
|
588
|
-
logger.info(
|
|
657
|
+
logger.info(
|
|
658
|
+
`[Bootstrap-v3] ✅ Checkpoint "${dimId}": analysisText restored (${cp.analysisText.length} chars) — Skill generation enabled`
|
|
659
|
+
);
|
|
589
660
|
}
|
|
590
661
|
|
|
591
662
|
return cpResult;
|
|
592
663
|
}
|
|
593
664
|
|
|
594
|
-
const dim = dimensions.find(d => d.id === dimId);
|
|
595
|
-
|
|
596
|
-
if (!dim || !v3Config) {
|
|
665
|
+
const dim = dimensions.find((d) => d.id === dimId);
|
|
666
|
+
if (!dim) {
|
|
597
667
|
return { candidateCount: 0, error: 'dimension not found' };
|
|
598
668
|
}
|
|
599
669
|
|
|
600
|
-
// 合并 v3 配置和原始维度配置
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
670
|
+
// 合并 v3 配置和原始维度配置
|
|
671
|
+
// Enhancement Pack 动态维度可能不在 DIMENSION_CONFIGS_V3 中 — 从 dim 本身构建配置
|
|
672
|
+
const v3Config = DIMENSION_CONFIGS_V3[dimId];
|
|
673
|
+
const dimConfig = v3Config
|
|
674
|
+
? {
|
|
675
|
+
...v3Config,
|
|
676
|
+
id: dimId,
|
|
677
|
+
skillWorthy: dim.skillWorthy,
|
|
678
|
+
dualOutput: dim.dualOutput,
|
|
679
|
+
skillMeta: dim.skillMeta,
|
|
680
|
+
knowledgeTypes: dim.knowledgeTypes || v3Config.allowedKnowledgeTypes,
|
|
681
|
+
}
|
|
682
|
+
: {
|
|
683
|
+
id: dimId,
|
|
684
|
+
label: dim.label,
|
|
685
|
+
guide: dim.guide || '',
|
|
686
|
+
focusAreas: dim.focusAreas || [dim.guide || ''].filter(Boolean),
|
|
687
|
+
outputType: dim.dualOutput ? 'dual' : dim.skillWorthy ? 'skill' : 'candidate',
|
|
688
|
+
allowedKnowledgeTypes: dim.knowledgeTypes || [],
|
|
689
|
+
skillWorthy: dim.skillWorthy,
|
|
690
|
+
dualOutput: dim.dualOutput,
|
|
691
|
+
skillMeta: dim.skillMeta,
|
|
692
|
+
knowledgeTypes: dim.knowledgeTypes || [],
|
|
693
|
+
};
|
|
609
694
|
|
|
610
695
|
// Session 有效性检查
|
|
611
696
|
if (taskManager && !taskManager.isSessionValid(sessionId)) {
|
|
@@ -637,7 +722,8 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
637
722
|
codeEntityGraph: codeEntityGraphInst,
|
|
638
723
|
}),
|
|
639
724
|
new Promise((_, reject) =>
|
|
640
|
-
setTimeout(() => reject(new Error(`Analyst timeout for "${dimId}"`)),
|
|
725
|
+
setTimeout(() => reject(new Error(`Analyst timeout for "${dimId}"`)), 300_000)
|
|
726
|
+
),
|
|
641
727
|
]);
|
|
642
728
|
|
|
643
729
|
// v4.0: 蒸馏 Working → Episodic
|
|
@@ -652,9 +738,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
652
738
|
|
|
653
739
|
logger.info(
|
|
654
740
|
`[Bootstrap-v3] Analyst "${dimId}": ${analysisReport.analysisText.length} chars, ` +
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
741
|
+
`${analysisReport.referencedFiles.length} files, ` +
|
|
742
|
+
`${distilled.keyFindings.length} key findings, ` +
|
|
743
|
+
`${distilled.totalObservations} observations (${Date.now() - dimStartTime}ms)`
|
|
658
744
|
);
|
|
659
745
|
|
|
660
746
|
// ── Phase 2: Producer (如果需要候选输出) ──
|
|
@@ -662,18 +748,34 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
662
748
|
// v3 优先使用 DIMENSION_CONFIGS_V3 的 outputType,回退到 baseDimension 的 skillWorthy/dualOutput
|
|
663
749
|
const v3OutputType = DIMENSION_CONFIGS_V3[dimId]?.outputType;
|
|
664
750
|
const needsCandidates = v3OutputType
|
|
665
|
-
? v3OutputType !== 'skill'
|
|
666
|
-
:
|
|
751
|
+
? v3OutputType !== 'skill' // 'dual' 或 'candidate' 都产出候选
|
|
752
|
+
: !dimConfig.skillWorthy || dimConfig.dualOutput;
|
|
753
|
+
|
|
754
|
+
// 先保存 Analyst 结果,确保即使 Producer 失败也能生成 Skill
|
|
755
|
+
dimensionCandidates[dimId] = {
|
|
756
|
+
analysisReport,
|
|
757
|
+
producerResult,
|
|
758
|
+
};
|
|
667
759
|
|
|
668
760
|
if (needsCandidates && analysisReport.analysisText.length >= 100) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
761
|
+
try {
|
|
762
|
+
producerResult = await Promise.race([
|
|
763
|
+
producerAgent.produce(analysisReport, dimConfig, projectInfo, { sessionId }),
|
|
764
|
+
new Promise((_, reject) =>
|
|
765
|
+
setTimeout(() => reject(new Error(`Producer timeout for "${dimId}"`)), 180_000)
|
|
766
|
+
),
|
|
767
|
+
]);
|
|
768
|
+
|
|
769
|
+
candidateResults.created += producerResult.candidateCount;
|
|
770
|
+
// 更新 dimensionCandidates 以包含 Producer 结果
|
|
771
|
+
dimensionCandidates[dimId].producerResult = producerResult;
|
|
772
|
+
logger.info(
|
|
773
|
+
`[Bootstrap-v3] Producer "${dimId}": ${producerResult.candidateCount} candidates (${Date.now() - dimStartTime}ms total)`
|
|
774
|
+
);
|
|
775
|
+
} catch (producerErr) {
|
|
776
|
+
logger.error(`[Bootstrap-v3] Producer "${dimId}" failed: ${producerErr.message} — Analyst result preserved for Skill generation`);
|
|
777
|
+
candidateResults.errors.push({ dimId, error: `Producer: ${producerErr.message}` });
|
|
778
|
+
}
|
|
677
779
|
}
|
|
678
780
|
|
|
679
781
|
// ── Phase 3: 记录 DimensionDigest ──
|
|
@@ -690,7 +792,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
690
792
|
episodicMemory.addDimensionDigest(dimId, digest);
|
|
691
793
|
|
|
692
794
|
// 记录到 DimensionContext + EpisodicMemory
|
|
693
|
-
for (const tc of
|
|
795
|
+
for (const tc of producerResult.toolCalls || []) {
|
|
694
796
|
const tool = tc.tool || tc.name;
|
|
695
797
|
if (tool === 'submit_knowledge' || tool === 'submit_with_check') {
|
|
696
798
|
const candidateSummary = {
|
|
@@ -704,19 +806,14 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
704
806
|
}
|
|
705
807
|
}
|
|
706
808
|
|
|
707
|
-
// 保存分析结果供 Skill 生成
|
|
708
|
-
dimensionCandidates[dimId] = {
|
|
709
|
-
analysisReport,
|
|
710
|
-
producerResult,
|
|
711
|
-
};
|
|
712
|
-
|
|
713
809
|
taskManager?.markTaskCompleted(dimId, {
|
|
714
810
|
type: needsCandidates ? 'candidate' : 'skill',
|
|
715
811
|
extracted: producerResult.candidateCount,
|
|
716
812
|
created: producerResult.candidateCount,
|
|
717
813
|
status: 'v3-complete',
|
|
718
814
|
durationMs: Date.now() - dimStartTime,
|
|
719
|
-
toolCallCount:
|
|
815
|
+
toolCallCount:
|
|
816
|
+
(analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
|
|
720
817
|
});
|
|
721
818
|
|
|
722
819
|
// P4.1: 聚合 token 用量
|
|
@@ -733,7 +830,8 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
733
830
|
analysisChars: analysisReport.analysisText.length,
|
|
734
831
|
referencedFiles: analysisReport.referencedFiles.length,
|
|
735
832
|
durationMs: Date.now() - dimStartTime,
|
|
736
|
-
toolCallCount:
|
|
833
|
+
toolCallCount:
|
|
834
|
+
(analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
|
|
737
835
|
tokenUsage: dimTokenUsage,
|
|
738
836
|
// P3+: 保存 analysisText 供 checkpoint 恢复后 Skill 生成使用
|
|
739
837
|
analysisText: analysisReport.analysisText,
|
|
@@ -747,7 +845,6 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
747
845
|
await saveDimensionCheckpoint(projectRoot, sessionId, dimId, dimResult, digest);
|
|
748
846
|
|
|
749
847
|
return dimResult;
|
|
750
|
-
|
|
751
848
|
} catch (err) {
|
|
752
849
|
logger.error(`[Bootstrap-v3] Dimension "${dimId}" failed: ${err.message}`);
|
|
753
850
|
candidateResults.errors.push({ dimId, error: err.message });
|
|
@@ -764,11 +861,14 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
764
861
|
if (enableParallel) {
|
|
765
862
|
const results = await scheduler.execute(executeDimension, {
|
|
766
863
|
concurrency,
|
|
864
|
+
activeDimIds,
|
|
767
865
|
shouldAbort: () => taskManager && !taskManager.isSessionValid(sessionId),
|
|
768
866
|
onTierComplete: (tierIndex, tierResults) => {
|
|
769
867
|
const tierStats = [...tierResults.values()];
|
|
770
868
|
const totalCandidates = tierStats.reduce((s, r) => s + (r.candidateCount || 0), 0);
|
|
771
|
-
logger.info(
|
|
869
|
+
logger.info(
|
|
870
|
+
`[Bootstrap-v3] Tier ${tierIndex + 1} complete: ${tierResults.size} dimensions, ${totalCandidates} candidates`
|
|
871
|
+
);
|
|
772
872
|
|
|
773
873
|
// v4.0: Tier 级 Reflection — 综合本 Tier 所有维度的发现
|
|
774
874
|
try {
|
|
@@ -776,8 +876,8 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
776
876
|
episodicMemory.addTierReflection(tierIndex, reflection);
|
|
777
877
|
logger.info(
|
|
778
878
|
`[Bootstrap-v3] Tier ${tierIndex + 1} reflection: ` +
|
|
779
|
-
|
|
780
|
-
|
|
879
|
+
`${reflection.topFindings.length} top findings, ` +
|
|
880
|
+
`${reflection.crossDimensionPatterns.length} patterns`
|
|
781
881
|
);
|
|
782
882
|
} catch (refErr) {
|
|
783
883
|
logger.warn(`[Bootstrap-v3] Tier ${tierIndex + 1} reflection failed: ${refErr.message}`);
|
|
@@ -785,25 +885,31 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
785
885
|
},
|
|
786
886
|
});
|
|
787
887
|
|
|
788
|
-
logger.info(
|
|
888
|
+
logger.info(
|
|
889
|
+
`[Bootstrap-v3] All tiers complete: ${results.size} dimensions in ${Date.now() - t0}ms`
|
|
890
|
+
);
|
|
789
891
|
// v4.0: 记录 EpisodicMemory 统计 + ToolResultCache 效率
|
|
790
892
|
const emStats = episodicMemory.getStats();
|
|
791
893
|
const cacheStats = toolResultCache.getStats();
|
|
792
894
|
logger.info(
|
|
793
895
|
`[Bootstrap-v3] Memory stats: ${emStats.completedDimensions} dims, ` +
|
|
794
|
-
|
|
795
|
-
|
|
896
|
+
`${emStats.totalFindings} findings, ${emStats.referencedFiles} files, ` +
|
|
897
|
+
`${emStats.crossReferences} cross-refs, ${emStats.tierReflections} reflections`
|
|
796
898
|
);
|
|
797
899
|
logger.info(
|
|
798
900
|
`[Bootstrap-v3] Cache stats: ${cacheStats.hitRate} hit rate, ` +
|
|
799
|
-
|
|
901
|
+
`${cacheStats.searchCacheSize} searches, ${cacheStats.fileCacheSize} files`
|
|
800
902
|
);
|
|
801
903
|
} else {
|
|
802
904
|
// 串行: 按 TierScheduler 内部顺序逐个执行
|
|
803
905
|
for (const tier of scheduler.getTiers()) {
|
|
804
906
|
for (const dimId of tier) {
|
|
805
|
-
if (!activeDimIds.includes(dimId))
|
|
806
|
-
|
|
907
|
+
if (!activeDimIds.includes(dimId)) {
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
if (taskManager && !taskManager.isSessionValid(sessionId)) {
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
807
913
|
await executeDimension(dimId);
|
|
808
914
|
}
|
|
809
915
|
}
|
|
@@ -822,19 +928,63 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
822
928
|
const { createSkill } = await import('../../skill.js');
|
|
823
929
|
|
|
824
930
|
for (const dim of dimensions) {
|
|
825
|
-
if (!dim.skillWorthy)
|
|
931
|
+
if (!dim.skillWorthy) {
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
826
934
|
const dimData = dimensionCandidates[dim.id];
|
|
827
|
-
if (!dimData?.analysisReport?.analysisText)
|
|
828
|
-
|
|
935
|
+
if (!dimData?.analysisReport?.analysisText) {
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
if (taskManager && !taskManager.isSessionValid(sessionId)) {
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
829
941
|
|
|
830
942
|
try {
|
|
831
943
|
const skillName = dim.skillMeta?.name || `project-${dim.id}`;
|
|
832
|
-
const skillDescription =
|
|
944
|
+
const skillDescription =
|
|
945
|
+
dim.skillMeta?.description || `Auto-generated skill for ${dim.label}`;
|
|
833
946
|
|
|
834
947
|
// v3: Analyst 分析文本就是高质量的 Skill 内容
|
|
835
948
|
const analysisText = dimData.analysisReport.analysisText;
|
|
836
949
|
const referencedFiles = dimData.analysisReport.referencedFiles || [];
|
|
837
950
|
|
|
951
|
+
// ── Skill 质量门控 ──
|
|
952
|
+
// 1. 文本过短(Analyst 产出空洞或仅 "请继续")
|
|
953
|
+
if (!analysisText || analysisText.trim().length < 100) {
|
|
954
|
+
logger.warn(
|
|
955
|
+
`[Bootstrap-v3] Skill "${dim.id}" skipped — analysisText too short (${analysisText?.trim().length || 0} chars)`
|
|
956
|
+
);
|
|
957
|
+
skillResults.failed++;
|
|
958
|
+
skillResults.errors.push({ dimId: dim.id, error: 'analysisText too short' });
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
// 2. 重复行检测(AI 陷入循环输出工具提示等)
|
|
962
|
+
const textLines = analysisText.split('\n').filter(l => l.trim().length > 0);
|
|
963
|
+
const uniqueLines = new Set(textLines.map(l => l.trim()));
|
|
964
|
+
const uniqueRatio = textLines.length > 0 ? uniqueLines.size / textLines.length : 1;
|
|
965
|
+
if (textLines.length > 20 && uniqueRatio < 0.3) {
|
|
966
|
+
logger.warn(
|
|
967
|
+
`[Bootstrap-v3] Skill "${dim.id}" skipped — heavy repetition (${uniqueLines.size}/${textLines.length} unique, ratio ${uniqueRatio.toFixed(2)})`
|
|
968
|
+
);
|
|
969
|
+
skillResults.failed++;
|
|
970
|
+
skillResults.errors.push({ dimId: dim.id, error: 'repetitive content detected' });
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
// 3. 内容中不包含项目特定标记(无 Markdown 标题、列表、代码块等结构化内容)
|
|
974
|
+
const hasStructure =
|
|
975
|
+
/^#{1,3}\s.+/m.test(analysisText) ||
|
|
976
|
+
/^\d+\.\s/m.test(analysisText) ||
|
|
977
|
+
/^[-*•]\s/m.test(analysisText) ||
|
|
978
|
+
/```[\s\S]*?```/.test(analysisText);
|
|
979
|
+
if (!hasStructure && analysisText.length < 500) {
|
|
980
|
+
logger.warn(
|
|
981
|
+
`[Bootstrap-v3] Skill "${dim.id}" skipped — no structured content detected`
|
|
982
|
+
);
|
|
983
|
+
skillResults.failed++;
|
|
984
|
+
skillResults.errors.push({ dimId: dim.id, error: 'no structured content' });
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
|
|
838
988
|
// 构建 Markdown Skill 内容
|
|
839
989
|
const skillContent = [
|
|
840
990
|
`# ${dim.label || dim.id}`,
|
|
@@ -844,9 +994,11 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
844
994
|
analysisText,
|
|
845
995
|
'',
|
|
846
996
|
referencedFiles.length > 0
|
|
847
|
-
? `## Referenced Files\n\n${referencedFiles.map(f => `- \`${f}\``).join('\n')}`
|
|
997
|
+
? `## Referenced Files\n\n${referencedFiles.map((f) => `- \`${f}\``).join('\n')}`
|
|
848
998
|
: '',
|
|
849
|
-
]
|
|
999
|
+
]
|
|
1000
|
+
.filter(Boolean)
|
|
1001
|
+
.join('\n');
|
|
850
1002
|
|
|
851
1003
|
const result = createSkill(ctx, {
|
|
852
1004
|
name: skillName,
|
|
@@ -917,7 +1069,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
917
1069
|
}
|
|
918
1070
|
}
|
|
919
1071
|
} catch (cegErr) {
|
|
920
|
-
logger.warn(
|
|
1072
|
+
logger.warn(
|
|
1073
|
+
`[Bootstrap-v3] Code Entity Graph relations failed (non-blocking): ${cegErr.message}`
|
|
1074
|
+
);
|
|
921
1075
|
}
|
|
922
1076
|
|
|
923
1077
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -941,16 +1095,18 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
941
1095
|
const smStats = semanticMemory.getStats();
|
|
942
1096
|
logger.info(
|
|
943
1097
|
`[Bootstrap-v3] Semantic Memory consolidation: ` +
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1098
|
+
`+${consolidationResult.total.added} ADD, ` +
|
|
1099
|
+
`~${consolidationResult.total.updated} UPDATE, ` +
|
|
1100
|
+
`⊕${consolidationResult.total.merged} MERGE | ` +
|
|
1101
|
+
`Total: ${smStats.total} memories (avg importance: ${smStats.avgImportance})`
|
|
948
1102
|
);
|
|
949
1103
|
} else {
|
|
950
1104
|
logger.warn('[Bootstrap-v3] Database not available — skipping Semantic Memory consolidation');
|
|
951
1105
|
}
|
|
952
1106
|
} catch (consolidateErr) {
|
|
953
|
-
logger.warn(
|
|
1107
|
+
logger.warn(
|
|
1108
|
+
`[Bootstrap-v3] Semantic Memory consolidation failed (non-blocking): ${consolidateErr.message}`
|
|
1109
|
+
);
|
|
954
1110
|
}
|
|
955
1111
|
|
|
956
1112
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -960,7 +1116,10 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
960
1116
|
|
|
961
1117
|
// P4.1: 汇总所有维度 token 用量
|
|
962
1118
|
const totalTokenUsage = { input: 0, output: 0 };
|
|
963
|
-
const totalToolCalls = Object.values(dimensionStats).reduce(
|
|
1119
|
+
const totalToolCalls = Object.values(dimensionStats).reduce(
|
|
1120
|
+
(sum, s) => sum + (s.toolCallCount || 0),
|
|
1121
|
+
0
|
|
1122
|
+
);
|
|
964
1123
|
for (const stat of Object.values(dimensionStats)) {
|
|
965
1124
|
if (stat.tokenUsage) {
|
|
966
1125
|
totalTokenUsage.input += stat.tokenUsage.input || 0;
|
|
@@ -968,19 +1127,29 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
968
1127
|
}
|
|
969
1128
|
}
|
|
970
1129
|
|
|
971
|
-
logger.info(
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1130
|
+
logger.info(
|
|
1131
|
+
[
|
|
1132
|
+
`[Bootstrap-v3] ═══ Pipeline complete ═══`,
|
|
1133
|
+
isIncremental
|
|
1134
|
+
? ` Mode: INCREMENTAL (${incrementalPlan.affectedDimensions.length} affected, ${incrementalSkippedDims.length} skipped)`
|
|
1135
|
+
: '',
|
|
1136
|
+
` Candidates: ${candidateResults.created} created, ${candidateResults.errors.length} errors`,
|
|
1137
|
+
` Skills: ${skillResults.created} created, ${skillResults.failed} failed`,
|
|
1138
|
+
consolidationResult
|
|
1139
|
+
? ` Semantic Memory: +${consolidationResult.total.added} ADD, ~${consolidationResult.total.updated} UPDATE, ⊕${consolidationResult.total.merged} MERGE`
|
|
1140
|
+
: '',
|
|
1141
|
+
` Time: ${totalTimeMs}ms (${(totalTimeMs / 1000).toFixed(1)}s)`,
|
|
1142
|
+
` Mode: ${enableParallel ? `parallel (concurrency=${concurrency})` : 'serial'}`,
|
|
1143
|
+
` Tokens: input=${totalTokenUsage.input}, output=${totalTokenUsage.output}`,
|
|
1144
|
+
` Tool calls: ${totalToolCalls}`,
|
|
1145
|
+
skippedDims.length > 0 ? ` Checkpoints restored: [${skippedDims.join(', ')}]` : '',
|
|
1146
|
+
incrementalSkippedDims.length > 0
|
|
1147
|
+
? ` Incremental skip: [${incrementalSkippedDims.join(', ')}]`
|
|
1148
|
+
: '',
|
|
1149
|
+
]
|
|
1150
|
+
.filter(Boolean)
|
|
1151
|
+
.join('\n')
|
|
1152
|
+
);
|
|
984
1153
|
|
|
985
1154
|
// P4.2: 生成冷启动报告
|
|
986
1155
|
try {
|
|
@@ -1007,25 +1176,31 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1007
1176
|
checkpoints: {
|
|
1008
1177
|
restored: skippedDims,
|
|
1009
1178
|
},
|
|
1010
|
-
incremental: isIncremental
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1179
|
+
incremental: isIncremental
|
|
1180
|
+
? {
|
|
1181
|
+
mode: 'incremental',
|
|
1182
|
+
affectedDimensions: incrementalPlan.affectedDimensions,
|
|
1183
|
+
skippedDimensions: incrementalSkippedDims,
|
|
1184
|
+
diff: incrementalPlan.diff
|
|
1185
|
+
? {
|
|
1186
|
+
added: incrementalPlan.diff.added.length,
|
|
1187
|
+
modified: incrementalPlan.diff.modified.length,
|
|
1188
|
+
deleted: incrementalPlan.diff.deleted.length,
|
|
1189
|
+
unchanged: incrementalPlan.diff.unchanged.length,
|
|
1190
|
+
}
|
|
1191
|
+
: null,
|
|
1192
|
+
reason: incrementalPlan.reason,
|
|
1193
|
+
}
|
|
1194
|
+
: null,
|
|
1195
|
+
semanticMemory: consolidationResult
|
|
1196
|
+
? {
|
|
1197
|
+
added: consolidationResult.total.added,
|
|
1198
|
+
updated: consolidationResult.total.updated,
|
|
1199
|
+
merged: consolidationResult.total.merged,
|
|
1200
|
+
skipped: consolidationResult.total.skipped,
|
|
1201
|
+
durationMs: consolidationResult.durationMs,
|
|
1202
|
+
}
|
|
1203
|
+
: null,
|
|
1029
1204
|
};
|
|
1030
1205
|
|
|
1031
1206
|
for (const [dimId, stat] of Object.entries(dimensionStats)) {
|
|
@@ -1042,7 +1217,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1042
1217
|
|
|
1043
1218
|
// Phase E: 附加 Code Entity Graph 拓扑到报告
|
|
1044
1219
|
try {
|
|
1045
|
-
const { CodeEntityGraph } = await import(
|
|
1220
|
+
const { CodeEntityGraph } = await import(
|
|
1221
|
+
'../../../../../service/knowledge/CodeEntityGraph.js'
|
|
1222
|
+
);
|
|
1046
1223
|
const db = ctx.container.get('database');
|
|
1047
1224
|
if (db) {
|
|
1048
1225
|
const ceg = new CodeEntityGraph(db, { projectRoot, logger });
|
|
@@ -1055,13 +1232,15 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1055
1232
|
hotNodes: topo.hotNodes?.slice(0, 5),
|
|
1056
1233
|
};
|
|
1057
1234
|
}
|
|
1058
|
-
} catch {
|
|
1235
|
+
} catch {
|
|
1236
|
+
/* non-blocking */
|
|
1237
|
+
}
|
|
1059
1238
|
|
|
1060
1239
|
const reportDir = path.join(projectRoot, '.autosnippet');
|
|
1061
1240
|
await fs.mkdir(reportDir, { recursive: true });
|
|
1062
1241
|
await fs.writeFile(
|
|
1063
1242
|
path.join(reportDir, 'bootstrap-report.json'),
|
|
1064
|
-
JSON.stringify(report, null, 2)
|
|
1243
|
+
JSON.stringify(report, null, 2)
|
|
1065
1244
|
);
|
|
1066
1245
|
logger.info(`[Bootstrap-v3] 📊 Bootstrap report saved to .autosnippet/bootstrap-report.json`);
|
|
1067
1246
|
} catch (reportErr) {
|
|
@@ -1105,11 +1284,13 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1105
1284
|
if (container.services.cursorDeliveryPipeline) {
|
|
1106
1285
|
const pipeline = container.get('cursorDeliveryPipeline');
|
|
1107
1286
|
const deliveryResult = await pipeline.deliver();
|
|
1108
|
-
logger.info(
|
|
1109
|
-
`
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1287
|
+
logger.info(
|
|
1288
|
+
`[Bootstrap-v3] 🚀 Cursor Delivery complete — ` +
|
|
1289
|
+
`A: ${deliveryResult.channelA.rulesCount} rules, ` +
|
|
1290
|
+
`B: ${deliveryResult.channelB.topicCount} topics, ` +
|
|
1291
|
+
`C: ${deliveryResult.channelC.synced} skills, ` +
|
|
1292
|
+
`D: ${deliveryResult.channelD?.documentsCount || 0} documents`
|
|
1293
|
+
);
|
|
1113
1294
|
}
|
|
1114
1295
|
} catch (deliveryErr) {
|
|
1115
1296
|
logger.warn(`[Bootstrap-v3] Cursor Delivery failed (non-blocking): ${deliveryErr.message}`);
|
|
@@ -1117,29 +1298,47 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1117
1298
|
|
|
1118
1299
|
// ── Repo Wiki: 自动生成项目文档 Wiki ──
|
|
1119
1300
|
try {
|
|
1120
|
-
const { getServiceContainer: getWikiContainer } = await import(
|
|
1301
|
+
const { getServiceContainer: getWikiContainer } = await import(
|
|
1302
|
+
'../../../../../injection/ServiceContainer.js'
|
|
1303
|
+
);
|
|
1121
1304
|
const wikiContainer = getWikiContainer();
|
|
1122
1305
|
const { WikiGenerator } = await import('../../../../../service/wiki/WikiGenerator.js');
|
|
1123
1306
|
|
|
1124
|
-
let
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
try {
|
|
1307
|
+
let moduleService = null,
|
|
1308
|
+
knowledgeService = null,
|
|
1309
|
+
codeEntityGraph = null;
|
|
1310
|
+
try {
|
|
1311
|
+
moduleService = wikiContainer.get('moduleService');
|
|
1312
|
+
} catch {
|
|
1313
|
+
/* optional */
|
|
1314
|
+
}
|
|
1315
|
+
try {
|
|
1316
|
+
knowledgeService = wikiContainer.get('knowledgeService');
|
|
1317
|
+
} catch {
|
|
1318
|
+
/* optional */
|
|
1319
|
+
}
|
|
1320
|
+
try {
|
|
1321
|
+
codeEntityGraph = wikiContainer.get('codeEntityGraph');
|
|
1322
|
+
} catch {
|
|
1323
|
+
/* optional */
|
|
1324
|
+
}
|
|
1128
1325
|
|
|
1129
1326
|
const wiki = new WikiGenerator({
|
|
1130
1327
|
projectRoot,
|
|
1131
|
-
|
|
1328
|
+
moduleService,
|
|
1132
1329
|
knowledgeService,
|
|
1133
|
-
projectGraph,
|
|
1330
|
+
projectGraph, // 来自 Step 0.5 构建的 ProjectGraph
|
|
1134
1331
|
codeEntityGraph,
|
|
1135
1332
|
aiProvider: wikiContainer.singletons?.aiProvider || null,
|
|
1136
1333
|
options: { language: process.env.ASD_WIKI_LANG || 'zh' },
|
|
1137
1334
|
});
|
|
1138
1335
|
const wikiResult = await wiki.generate();
|
|
1139
1336
|
if (wikiResult.success) {
|
|
1140
|
-
logger.info(
|
|
1141
|
-
`
|
|
1142
|
-
|
|
1337
|
+
logger.info(
|
|
1338
|
+
`[Bootstrap-v3] 📖 Wiki generated — ${wikiResult.filesGenerated} files, ` +
|
|
1339
|
+
`AI: ${wikiResult.aiComposed || 0}, Synced: ${wikiResult.syncedDocs || 0}, ` +
|
|
1340
|
+
`Dedup removed: ${wikiResult.dedup?.removed?.length || 0}`
|
|
1341
|
+
);
|
|
1143
1342
|
}
|
|
1144
1343
|
} catch (wikiErr) {
|
|
1145
1344
|
logger.warn(`[Bootstrap-v3] Wiki generation failed (non-blocking): ${wikiErr.message}`);
|