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
|
@@ -22,10 +22,10 @@ import Logger from '../../infrastructure/logging/Logger.js';
|
|
|
22
22
|
|
|
23
23
|
/** 任务状态枚举 */
|
|
24
24
|
export const TaskStatus = Object.freeze({
|
|
25
|
-
SKELETON: 'skeleton',
|
|
26
|
-
FILLING:
|
|
27
|
-
COMPLETED: 'completed',
|
|
28
|
-
FAILED:
|
|
25
|
+
SKELETON: 'skeleton', // 骨架已创建,等待填充
|
|
26
|
+
FILLING: 'filling', // 内容正在填充中
|
|
27
|
+
COMPLETED: 'completed', // 填充完成
|
|
28
|
+
FAILED: 'failed', // 填充失败
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -36,19 +36,19 @@ class BootstrapSession {
|
|
|
36
36
|
this.id = sessionId;
|
|
37
37
|
this.startedAt = Date.now();
|
|
38
38
|
this.completedAt = null;
|
|
39
|
-
this.status = 'running';
|
|
40
|
-
this.tasks = new Map();
|
|
41
|
-
this.summary = null;
|
|
39
|
+
this.status = 'running'; // running | completed | failed
|
|
40
|
+
this.tasks = new Map(); // taskId → TaskInfo
|
|
41
|
+
this.summary = null; // 完成后的摘要
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
addTask(taskId, meta) {
|
|
45
45
|
this.tasks.set(taskId, {
|
|
46
46
|
id: taskId,
|
|
47
47
|
status: TaskStatus.SKELETON,
|
|
48
|
-
meta,
|
|
48
|
+
meta, // { type: 'dimension'|'skill', dimId, label, skillWorthy }
|
|
49
49
|
startedAt: null,
|
|
50
50
|
completedAt: null,
|
|
51
|
-
result: null,
|
|
51
|
+
result: null, // 填充结果摘要
|
|
52
52
|
error: null,
|
|
53
53
|
});
|
|
54
54
|
}
|
|
@@ -57,11 +57,21 @@ class BootstrapSession {
|
|
|
57
57
|
return this.tasks.get(taskId);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
get totalTasks() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
get
|
|
64
|
-
|
|
60
|
+
get totalTasks() {
|
|
61
|
+
return this.tasks.size;
|
|
62
|
+
}
|
|
63
|
+
get completedTasks() {
|
|
64
|
+
return [...this.tasks.values()].filter((t) => t.status === TaskStatus.COMPLETED).length;
|
|
65
|
+
}
|
|
66
|
+
get failedTasks() {
|
|
67
|
+
return [...this.tasks.values()].filter((t) => t.status === TaskStatus.FAILED).length;
|
|
68
|
+
}
|
|
69
|
+
get fillingTasks() {
|
|
70
|
+
return [...this.tasks.values()].filter((t) => t.status === TaskStatus.FILLING).length;
|
|
71
|
+
}
|
|
72
|
+
get skeletonTasks() {
|
|
73
|
+
return [...this.tasks.values()].filter((t) => t.status === TaskStatus.SKELETON).length;
|
|
74
|
+
}
|
|
65
75
|
|
|
66
76
|
get isAllDone() {
|
|
67
77
|
return this.skeletonTasks === 0 && this.fillingTasks === 0;
|
|
@@ -70,14 +80,18 @@ class BootstrapSession {
|
|
|
70
80
|
get totalToolCalls() {
|
|
71
81
|
let count = 0;
|
|
72
82
|
for (const t of this.tasks.values()) {
|
|
73
|
-
if (t.result?.toolCallCount)
|
|
83
|
+
if (t.result?.toolCallCount) {
|
|
84
|
+
count += t.result.toolCallCount;
|
|
85
|
+
}
|
|
74
86
|
}
|
|
75
87
|
return count;
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
get progress() {
|
|
79
91
|
const total = this.totalTasks;
|
|
80
|
-
if (total === 0)
|
|
92
|
+
if (total === 0) {
|
|
93
|
+
return 100;
|
|
94
|
+
}
|
|
81
95
|
return Math.round(((this.completedTasks + this.failedTasks) / total) * 100);
|
|
82
96
|
}
|
|
83
97
|
|
|
@@ -94,7 +108,7 @@ class BootstrapSession {
|
|
|
94
108
|
filling: this.fillingTasks,
|
|
95
109
|
skeleton: this.skeletonTasks,
|
|
96
110
|
totalToolCalls: this.totalToolCalls,
|
|
97
|
-
tasks: [...this.tasks.values()].map(t => ({
|
|
111
|
+
tasks: [...this.tasks.values()].map((t) => ({
|
|
98
112
|
id: t.id,
|
|
99
113
|
status: t.status,
|
|
100
114
|
meta: t.meta,
|
|
@@ -138,7 +152,9 @@ export class BootstrapTaskManager {
|
|
|
138
152
|
startSession(taskDefs) {
|
|
139
153
|
// ── 并发锁:如果上一个 session 还在运行,先中止 ──
|
|
140
154
|
if (this.isRunning) {
|
|
141
|
-
Logger.warn(
|
|
155
|
+
Logger.warn(
|
|
156
|
+
`[Bootstrap] Previous session ${this.#currentSession.id} still running — aborting before starting new session`
|
|
157
|
+
);
|
|
142
158
|
this.abortSession('Superseded by new bootstrap request');
|
|
143
159
|
}
|
|
144
160
|
|
|
@@ -152,7 +168,7 @@ export class BootstrapTaskManager {
|
|
|
152
168
|
Logger.info(`[Bootstrap] Session ${sessionId} started with ${taskDefs.length} tasks`);
|
|
153
169
|
this.#emit('bootstrap:started', {
|
|
154
170
|
sessionId,
|
|
155
|
-
tasks: taskDefs.map(t => ({ id: t.id, ...t.meta })),
|
|
171
|
+
tasks: taskDefs.map((t) => ({ id: t.id, ...t.meta })),
|
|
156
172
|
total: taskDefs.length,
|
|
157
173
|
startedAt: this.#currentSession.startedAt,
|
|
158
174
|
});
|
|
@@ -170,7 +186,9 @@ export class BootstrapTaskManager {
|
|
|
170
186
|
*/
|
|
171
187
|
abortSession(reason = 'Aborted by user') {
|
|
172
188
|
const session = this.#currentSession;
|
|
173
|
-
if (!session || session.status !== 'running')
|
|
189
|
+
if (!session || session.status !== 'running') {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
174
192
|
|
|
175
193
|
// 将未完成的任务全部标记 FAILED
|
|
176
194
|
for (const task of session.tasks.values()) {
|
|
@@ -196,8 +214,12 @@ export class BootstrapTaskManager {
|
|
|
196
214
|
this.#emit('bootstrap:all-completed', {
|
|
197
215
|
sessionId: session.id,
|
|
198
216
|
summary: session.summary,
|
|
199
|
-
tasks: [...session.tasks.values()].map(t => ({
|
|
200
|
-
id: t.id,
|
|
217
|
+
tasks: [...session.tasks.values()].map((t) => ({
|
|
218
|
+
id: t.id,
|
|
219
|
+
status: t.status,
|
|
220
|
+
meta: t.meta,
|
|
221
|
+
result: t.result,
|
|
222
|
+
error: t.error,
|
|
201
223
|
})),
|
|
202
224
|
});
|
|
203
225
|
}
|
|
@@ -214,10 +236,12 @@ export class BootstrapTaskManager {
|
|
|
214
236
|
isSessionValid(sessionId) {
|
|
215
237
|
// Session 在 running 或 completed 状态都有效 — completed 表示维度填充完成,
|
|
216
238
|
// 但 Phase 5.5 Skills 生成仍需运行。只有被新 session 替代时才无效。
|
|
217
|
-
return
|
|
239
|
+
return (
|
|
240
|
+
this.#currentSession?.id === sessionId &&
|
|
218
241
|
(this.#currentSession?.status === 'running' ||
|
|
219
|
-
|
|
220
|
-
|
|
242
|
+
this.#currentSession?.status === 'completed' ||
|
|
243
|
+
this.#currentSession?.status === 'completed_with_errors')
|
|
244
|
+
);
|
|
221
245
|
}
|
|
222
246
|
|
|
223
247
|
/**
|
|
@@ -225,9 +249,13 @@ export class BootstrapTaskManager {
|
|
|
225
249
|
*/
|
|
226
250
|
markTaskFilling(taskId) {
|
|
227
251
|
const session = this.#currentSession;
|
|
228
|
-
if (!session)
|
|
252
|
+
if (!session) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
229
255
|
const task = session.getTask(taskId);
|
|
230
|
-
if (!task)
|
|
256
|
+
if (!task) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
231
259
|
|
|
232
260
|
task.status = TaskStatus.FILLING;
|
|
233
261
|
task.startedAt = Date.now();
|
|
@@ -248,15 +276,21 @@ export class BootstrapTaskManager {
|
|
|
248
276
|
*/
|
|
249
277
|
markTaskCompleted(taskId, result = {}) {
|
|
250
278
|
const session = this.#currentSession;
|
|
251
|
-
if (!session)
|
|
279
|
+
if (!session) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
252
282
|
const task = session.getTask(taskId);
|
|
253
|
-
if (!task)
|
|
283
|
+
if (!task) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
254
286
|
|
|
255
287
|
task.status = TaskStatus.COMPLETED;
|
|
256
288
|
task.completedAt = Date.now();
|
|
257
289
|
task.result = result;
|
|
258
290
|
|
|
259
|
-
Logger.info(
|
|
291
|
+
Logger.info(
|
|
292
|
+
`[Bootstrap] Task "${taskId}" completed (${session.completedTasks}/${session.totalTasks})`
|
|
293
|
+
);
|
|
260
294
|
this.#emit('bootstrap:task-completed', {
|
|
261
295
|
sessionId: session.id,
|
|
262
296
|
taskId,
|
|
@@ -280,9 +314,13 @@ export class BootstrapTaskManager {
|
|
|
280
314
|
*/
|
|
281
315
|
markTaskFailed(taskId, error) {
|
|
282
316
|
const session = this.#currentSession;
|
|
283
|
-
if (!session)
|
|
317
|
+
if (!session) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
284
320
|
const task = session.getTask(taskId);
|
|
285
|
-
if (!task)
|
|
321
|
+
if (!task) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
286
324
|
|
|
287
325
|
task.status = TaskStatus.FAILED;
|
|
288
326
|
task.completedAt = Date.now();
|
|
@@ -347,7 +385,9 @@ export class BootstrapTaskManager {
|
|
|
347
385
|
|
|
348
386
|
#finishSession() {
|
|
349
387
|
const session = this.#currentSession;
|
|
350
|
-
if (!session)
|
|
388
|
+
if (!session) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
351
391
|
|
|
352
392
|
session.status = session.failedTasks > 0 ? 'completed_with_errors' : 'completed';
|
|
353
393
|
session.completedAt = Date.now();
|
|
@@ -359,12 +399,14 @@ export class BootstrapTaskManager {
|
|
|
359
399
|
};
|
|
360
400
|
|
|
361
401
|
const durationSec = ((session.completedAt - session.startedAt) / 1000).toFixed(1);
|
|
362
|
-
Logger.info(
|
|
402
|
+
Logger.info(
|
|
403
|
+
`[Bootstrap] Session ${session.id} finished: ${session.completedTasks} completed, ${session.failedTasks} failed (${durationSec}s)`
|
|
404
|
+
);
|
|
363
405
|
|
|
364
406
|
this.#emit('bootstrap:all-completed', {
|
|
365
407
|
sessionId: session.id,
|
|
366
408
|
summary: session.summary,
|
|
367
|
-
tasks: [...session.tasks.values()].map(t => ({
|
|
409
|
+
tasks: [...session.tasks.values()].map((t) => ({
|
|
368
410
|
id: t.id,
|
|
369
411
|
status: t.status,
|
|
370
412
|
meta: t.meta,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { getProjectRecipesPath } from '../../infrastructure/config/Paths.js';
|
|
4
|
-
import {
|
|
4
|
+
import { jaccardSimilarity, tokenizeForSimilarity } from '../../shared/similarity.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* SimilarityService — 轻量级 Recipe 相似度检测
|
|
@@ -12,12 +12,18 @@ import { tokenizeForSimilarity, jaccardSimilarity } from '../../shared/similarit
|
|
|
12
12
|
* 计算候选与单个 Recipe 的综合相似度
|
|
13
13
|
*/
|
|
14
14
|
function computeSimilarity(candidate, recipe) {
|
|
15
|
-
const titleSim = jaccardSimilarity(
|
|
15
|
+
const titleSim = jaccardSimilarity(
|
|
16
|
+
tokenizeForSimilarity(candidate.title),
|
|
17
|
+
tokenizeForSimilarity(recipe.title)
|
|
18
|
+
);
|
|
16
19
|
const summarySim = jaccardSimilarity(
|
|
17
20
|
tokenizeForSimilarity(candidate.summary || candidate.description),
|
|
18
|
-
tokenizeForSimilarity(recipe.summary || recipe.description)
|
|
21
|
+
tokenizeForSimilarity(recipe.summary || recipe.description)
|
|
22
|
+
);
|
|
23
|
+
const codeSim = jaccardSimilarity(
|
|
24
|
+
tokenizeForSimilarity(candidate.code, 3),
|
|
25
|
+
tokenizeForSimilarity(recipe.code, 3)
|
|
19
26
|
);
|
|
20
|
-
const codeSim = jaccardSimilarity(tokenizeForSimilarity(candidate.code, 3), tokenizeForSimilarity(recipe.code, 3));
|
|
21
27
|
// 加权: title 30%, summary 30%, code 40%
|
|
22
28
|
return titleSim * 0.3 + summarySim * 0.3 + codeSim * 0.4;
|
|
23
29
|
}
|
|
@@ -27,11 +33,15 @@ function computeSimilarity(candidate, recipe) {
|
|
|
27
33
|
*/
|
|
28
34
|
function loadRecipesFromDisk(recipesDir) {
|
|
29
35
|
const recipes = [];
|
|
30
|
-
if (!fs.existsSync(recipesDir))
|
|
36
|
+
if (!fs.existsSync(recipesDir)) {
|
|
37
|
+
return recipes;
|
|
38
|
+
}
|
|
31
39
|
|
|
32
40
|
const walk = (dir) => {
|
|
33
41
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
-
if (entry.name.startsWith('.'))
|
|
42
|
+
if (entry.name.startsWith('.')) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
35
45
|
const full = path.join(dir, entry.name);
|
|
36
46
|
if (entry.isDirectory()) {
|
|
37
47
|
walk(full);
|
|
@@ -39,7 +49,7 @@ function loadRecipesFromDisk(recipesDir) {
|
|
|
39
49
|
try {
|
|
40
50
|
const content = fs.readFileSync(full, 'utf8');
|
|
41
51
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
42
|
-
const
|
|
52
|
+
const _fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
43
53
|
const codeMatch = content.match(/```\w*\n([\s\S]*?)```/);
|
|
44
54
|
const summaryMatch = content.match(/summary[_cn]*:\s*(.+)/i);
|
|
45
55
|
recipes.push({
|
|
@@ -48,7 +58,9 @@ function loadRecipesFromDisk(recipesDir) {
|
|
|
48
58
|
summary: summaryMatch?.[1]?.trim() || '',
|
|
49
59
|
code: codeMatch?.[1]?.trim() || '',
|
|
50
60
|
});
|
|
51
|
-
} catch {
|
|
61
|
+
} catch {
|
|
62
|
+
/* skip unreadable */
|
|
63
|
+
}
|
|
52
64
|
}
|
|
53
65
|
}
|
|
54
66
|
};
|
|
@@ -73,7 +85,11 @@ export function findSimilarRecipes(projectRoot, candidate, opts = {}) {
|
|
|
73
85
|
for (const recipe of recipes) {
|
|
74
86
|
const sim = computeSimilarity(candidate, recipe);
|
|
75
87
|
if (sim >= threshold) {
|
|
76
|
-
results.push({
|
|
88
|
+
results.push({
|
|
89
|
+
file: recipe.file,
|
|
90
|
+
title: recipe.title,
|
|
91
|
+
similarity: Math.round(sim * 1000) / 1000,
|
|
92
|
+
});
|
|
77
93
|
}
|
|
78
94
|
}
|
|
79
95
|
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* @module AnalystAgent
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { buildAnalysisReport, analysisQualityGate, buildRetryPrompt } from './HandoffProtocol.js';
|
|
16
15
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
16
|
+
import { analysisQualityGate, buildAnalysisReport, buildRetryPrompt } from './HandoffProtocol.js';
|
|
17
17
|
|
|
18
18
|
// ──────────────────────────────────────────────────────────────────
|
|
19
19
|
// System Prompt — Analyst 专用 (~100 tokens)
|
|
@@ -77,12 +77,12 @@ const ANALYST_TOOLS = [
|
|
|
77
77
|
// ──────────────────────────────────────────────────────────────────
|
|
78
78
|
|
|
79
79
|
const ANALYST_BUDGET = {
|
|
80
|
-
maxIterations: 24,
|
|
81
|
-
searchBudget: 18,
|
|
82
|
-
searchBudgetGrace: 10,
|
|
83
|
-
maxSubmits: 0,
|
|
80
|
+
maxIterations: 24, // was 18 — 大项目维度需要充足探索轮次
|
|
81
|
+
searchBudget: 18, // was 14 — 匹配更大探索空间
|
|
82
|
+
searchBudgetGrace: 10, // was 8
|
|
83
|
+
maxSubmits: 0, // Analyst 不提交候选
|
|
84
84
|
softSubmitLimit: 0,
|
|
85
|
-
idleRoundsToExit: 2,
|
|
85
|
+
idleRoundsToExit: 2, // 减少空转
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -99,11 +99,20 @@ const ANALYST_BUDGET = {
|
|
|
99
99
|
* @param {object} [codeEntityGraph] — CodeEntityGraph 实例 (Phase E 代码实体图谱)
|
|
100
100
|
* @returns {string}
|
|
101
101
|
*/
|
|
102
|
-
function buildAnalystPrompt(
|
|
102
|
+
function buildAnalystPrompt(
|
|
103
|
+
dimConfig,
|
|
104
|
+
projectInfo,
|
|
105
|
+
dimensionContext,
|
|
106
|
+
episodicMemory,
|
|
107
|
+
semanticMemory,
|
|
108
|
+
codeEntityGraph
|
|
109
|
+
) {
|
|
103
110
|
const parts = [];
|
|
104
111
|
|
|
105
112
|
// §1 任务描述
|
|
106
|
-
parts.push(
|
|
113
|
+
parts.push(
|
|
114
|
+
`分析项目 ${projectInfo.name} (${projectInfo.lang}, ${projectInfo.fileCount} 个文件) 的 ${dimConfig.label}。`
|
|
115
|
+
);
|
|
107
116
|
|
|
108
117
|
// §2 维度指引
|
|
109
118
|
if (dimConfig.guide) {
|
|
@@ -112,7 +121,7 @@ function buildAnalystPrompt(dimConfig, projectInfo, dimensionContext, episodicMe
|
|
|
112
121
|
|
|
113
122
|
// §3 探索焦点
|
|
114
123
|
if (dimConfig.focusAreas?.length > 0) {
|
|
115
|
-
parts.push(`重点关注:\n${dimConfig.focusAreas.map(f => `- ${f}`).join('\n')}`);
|
|
124
|
+
parts.push(`重点关注:\n${dimConfig.focusAreas.map((f) => `- ${f}`).join('\n')}`);
|
|
116
125
|
}
|
|
117
126
|
|
|
118
127
|
// §4 输出要求
|
|
@@ -142,7 +151,8 @@ ${depthHint}
|
|
|
142
151
|
// 回退到 DimensionContext (兼容)
|
|
143
152
|
if (episodicMemory) {
|
|
144
153
|
const emContext = episodicMemory.buildContextForDimension(
|
|
145
|
-
dimConfig.id,
|
|
154
|
+
dimConfig.id,
|
|
155
|
+
dimConfig.focusAreas || []
|
|
146
156
|
);
|
|
147
157
|
if (emContext) {
|
|
148
158
|
parts.push(emContext);
|
|
@@ -183,7 +193,9 @@ ${depthHint}
|
|
|
183
193
|
if (section) {
|
|
184
194
|
parts.push(section);
|
|
185
195
|
}
|
|
186
|
-
} catch {
|
|
196
|
+
} catch {
|
|
197
|
+
/* SemanticMemory retrieval failed, non-critical */
|
|
198
|
+
}
|
|
187
199
|
}
|
|
188
200
|
|
|
189
201
|
// §9: 代码实体图谱 (Phase E) — 类/协议/Category 关系拓扑
|
|
@@ -194,7 +206,9 @@ ${depthHint}
|
|
|
194
206
|
parts.push(graphCtx);
|
|
195
207
|
parts.push('使用 query_code_graph 工具可以查询更详细的继承链、影响分析等。');
|
|
196
208
|
}
|
|
197
|
-
} catch {
|
|
209
|
+
} catch {
|
|
210
|
+
/* CodeEntityGraph context failed, non-critical */
|
|
211
|
+
}
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
return parts.join('\n\n');
|
|
@@ -243,22 +257,26 @@ export class AnalystAgent {
|
|
|
243
257
|
async analyze(dimConfig, projectInfo, options = {}) {
|
|
244
258
|
const dimId = dimConfig.id;
|
|
245
259
|
const prompt = buildAnalystPrompt(
|
|
246
|
-
dimConfig,
|
|
260
|
+
dimConfig,
|
|
261
|
+
projectInfo,
|
|
247
262
|
options.dimensionContext,
|
|
248
|
-
options.episodicMemory,
|
|
249
|
-
options.semanticMemory,
|
|
250
|
-
options.codeEntityGraph
|
|
263
|
+
options.episodicMemory, // v4.0: EpisodicMemory 增强
|
|
264
|
+
options.semanticMemory, // v4.1: ProjectSemanticMemory 历史记忆
|
|
265
|
+
options.codeEntityGraph // Phase E: CodeEntityGraph 代码实体图谱
|
|
251
266
|
);
|
|
252
267
|
|
|
253
|
-
this.#logger.info(
|
|
268
|
+
this.#logger.info(
|
|
269
|
+
`[AnalystAgent] ▶ analyzing dimension "${dimId}" — prompt ${prompt.length} chars`
|
|
270
|
+
);
|
|
254
271
|
|
|
255
272
|
let retries = 0;
|
|
256
273
|
let lastReport = null;
|
|
257
274
|
|
|
258
275
|
while (retries <= this.#maxRetries) {
|
|
259
|
-
const execPrompt =
|
|
260
|
-
|
|
261
|
-
|
|
276
|
+
const execPrompt =
|
|
277
|
+
retries === 0
|
|
278
|
+
? prompt
|
|
279
|
+
: `${prompt}\n\n${buildRetryPrompt(lastReport?._gateReason || 'Analysis too short')}`;
|
|
262
280
|
|
|
263
281
|
try {
|
|
264
282
|
const result = await this.#chatAgent.execute(execPrompt, {
|
|
@@ -293,13 +311,19 @@ export class AnalystAgent {
|
|
|
293
311
|
}
|
|
294
312
|
|
|
295
313
|
// 质量门控 — 传入 outputType 以调整门槛
|
|
296
|
-
const gate = analysisQualityGate(report, {
|
|
314
|
+
const gate = analysisQualityGate(report, {
|
|
315
|
+
outputType: dimConfig.outputType || 'analysis',
|
|
316
|
+
});
|
|
297
317
|
if (gate.pass) {
|
|
298
|
-
this.#logger.info(
|
|
318
|
+
this.#logger.info(
|
|
319
|
+
`[AnalystAgent] ✅ dimension "${dimId}" — ${report.analysisText.length} chars, ${report.referencedFiles.length} files referenced, ${report.metadata.toolCallCount} tool calls`
|
|
320
|
+
);
|
|
299
321
|
return report;
|
|
300
322
|
}
|
|
301
323
|
|
|
302
|
-
this.#logger.warn(
|
|
324
|
+
this.#logger.warn(
|
|
325
|
+
`[AnalystAgent] ⚠ Gate failed for "${dimId}": ${gate.reason} (action=${gate.action})`
|
|
326
|
+
);
|
|
303
327
|
|
|
304
328
|
if (gate.action === 'degrade') {
|
|
305
329
|
// 直接降级 — 不重试
|
|
@@ -320,7 +344,9 @@ export class AnalystAgent {
|
|
|
320
344
|
|
|
321
345
|
// 重试耗尽 — 返回最后一次结果
|
|
322
346
|
this.#logger.warn(`[AnalystAgent] Retries exhausted for "${dimId}" — returning last report`);
|
|
323
|
-
return
|
|
347
|
+
return (
|
|
348
|
+
lastReport || buildAnalysisReport({ reply: '', toolCalls: [] }, dimId, this.#projectGraph)
|
|
349
|
+
);
|
|
324
350
|
}
|
|
325
351
|
}
|
|
326
352
|
|