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
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
* @module EpisodicMemory
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import Logger from '../../../../../infrastructure/logging/Logger.js';
|
|
20
19
|
import fs from 'node:fs';
|
|
21
20
|
import path from 'node:path';
|
|
21
|
+
import Logger from '../../../../../infrastructure/logging/Logger.js';
|
|
22
22
|
|
|
23
23
|
// ──────────────────────────────────────────────────────────────
|
|
24
24
|
// 数据结构定义
|
|
@@ -136,7 +136,7 @@ export class EpisodicMemory {
|
|
|
136
136
|
});
|
|
137
137
|
|
|
138
138
|
// 自动提取文件级 Evidence
|
|
139
|
-
for (const f of
|
|
139
|
+
for (const f of report.findings || []) {
|
|
140
140
|
if (f.evidence) {
|
|
141
141
|
const filePath = f.evidence.split(':')[0]; // "file.m:123" → "file.m"
|
|
142
142
|
this.addEvidence(filePath, {
|
|
@@ -163,8 +163,8 @@ export class EpisodicMemory {
|
|
|
163
163
|
|
|
164
164
|
this.#logger.info(
|
|
165
165
|
`[EpisodicMemory] Stored report for "${dimId}": ` +
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
`${report.findings?.length || 0} findings, ` +
|
|
167
|
+
`${report.referencedFiles?.length || 0} files`
|
|
168
168
|
);
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -218,7 +218,9 @@ export class EpisodicMemory {
|
|
|
218
218
|
|
|
219
219
|
for (const [filePath, evidences] of this.#evidenceStore) {
|
|
220
220
|
for (const ev of evidences) {
|
|
221
|
-
if (dimId && ev.dimId !== dimId)
|
|
221
|
+
if (dimId && ev.dimId !== dimId) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
222
224
|
|
|
223
225
|
const matchesFile = filePath.toLowerCase().includes(lowerQuery);
|
|
224
226
|
const matchesFinding = (ev.finding || '').toLowerCase().includes(lowerQuery);
|
|
@@ -269,7 +271,7 @@ export class EpisodicMemory {
|
|
|
269
271
|
dimId,
|
|
270
272
|
completedAt: Date.now(),
|
|
271
273
|
analysisText: digest.summary || '',
|
|
272
|
-
findings: (digest.keyFindings || []).map(f => ({
|
|
274
|
+
findings: (digest.keyFindings || []).map((f) => ({
|
|
273
275
|
finding: typeof f === 'string' ? f : f.finding || '',
|
|
274
276
|
evidence: '',
|
|
275
277
|
importance: 5,
|
|
@@ -287,7 +289,7 @@ export class EpisodicMemory {
|
|
|
287
289
|
if (detail) {
|
|
288
290
|
// 避免重复
|
|
289
291
|
const exists = this.#crossReferences.some(
|
|
290
|
-
cr => cr.from === dimId && cr.to === targetDim
|
|
292
|
+
(cr) => cr.from === dimId && cr.to === targetDim
|
|
291
293
|
);
|
|
292
294
|
if (!exists) {
|
|
293
295
|
this.#crossReferences.push({
|
|
@@ -313,8 +315,8 @@ export class EpisodicMemory {
|
|
|
313
315
|
this.#tierReflections.push(reflection);
|
|
314
316
|
this.#logger.info(
|
|
315
317
|
`[EpisodicMemory] Tier ${tierIndex + 1} reflection: ` +
|
|
316
|
-
|
|
317
|
-
|
|
318
|
+
`${reflection.topFindings?.length || 0} top findings, ` +
|
|
319
|
+
`${reflection.crossDimensionPatterns?.length || 0} patterns`
|
|
318
320
|
);
|
|
319
321
|
}
|
|
320
322
|
|
|
@@ -324,7 +326,9 @@ export class EpisodicMemory {
|
|
|
324
326
|
* @returns {string|null} - 格式化的 Markdown 文本
|
|
325
327
|
*/
|
|
326
328
|
getRelevantReflections(currentDimId) {
|
|
327
|
-
if (this.#tierReflections.length === 0)
|
|
329
|
+
if (this.#tierReflections.length === 0) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
328
332
|
|
|
329
333
|
const parts = [];
|
|
330
334
|
for (const ref of this.#tierReflections) {
|
|
@@ -372,8 +376,9 @@ export class EpisodicMemory {
|
|
|
372
376
|
*/
|
|
373
377
|
buildContextForDimension(currentDimId, focusAreas = []) {
|
|
374
378
|
const parts = [];
|
|
375
|
-
const completedDims = [...this.#dimensionReports.entries()]
|
|
376
|
-
|
|
379
|
+
const completedDims = [...this.#dimensionReports.entries()].filter(
|
|
380
|
+
([id]) => id !== currentDimId
|
|
381
|
+
);
|
|
377
382
|
|
|
378
383
|
if (completedDims.length === 0 && this.#tierReflections.length === 0) {
|
|
379
384
|
return '';
|
|
@@ -389,18 +394,18 @@ export class EpisodicMemory {
|
|
|
389
394
|
if (report.digest?.summary) {
|
|
390
395
|
parts.push(report.digest.summary);
|
|
391
396
|
} else if (report.analysisText) {
|
|
392
|
-
parts.push(report.analysisText.substring(0, 300)
|
|
397
|
+
parts.push(`${report.analysisText.substring(0, 300)}…`);
|
|
393
398
|
}
|
|
394
399
|
|
|
395
400
|
// 选择与当前维度相关的 findings
|
|
396
|
-
const relevantFindings = this.#selectRelevantFindings(
|
|
397
|
-
report.findings, focusAreas, 5
|
|
398
|
-
);
|
|
401
|
+
const relevantFindings = this.#selectRelevantFindings(report.findings, focusAreas, 5);
|
|
399
402
|
if (relevantFindings.length > 0) {
|
|
400
403
|
parts.push('**具体发现**:');
|
|
401
404
|
for (const f of relevantFindings) {
|
|
402
405
|
let line = `- [${f.importance}/10] ${f.finding}`;
|
|
403
|
-
if (f.evidence)
|
|
406
|
+
if (f.evidence) {
|
|
407
|
+
line += ` _(${f.evidence})_`;
|
|
408
|
+
}
|
|
404
409
|
parts.push(line);
|
|
405
410
|
}
|
|
406
411
|
}
|
|
@@ -408,7 +413,9 @@ export class EpisodicMemory {
|
|
|
408
413
|
// 候选数量
|
|
409
414
|
const candidates = this.#submittedCandidates.get(dimId) || [];
|
|
410
415
|
if (candidates.length > 0) {
|
|
411
|
-
parts.push(
|
|
416
|
+
parts.push(
|
|
417
|
+
`已提交 ${candidates.length} 个候选: ${candidates.map((c) => c.title).join(', ')}`
|
|
418
|
+
);
|
|
412
419
|
}
|
|
413
420
|
}
|
|
414
421
|
|
|
@@ -429,9 +436,7 @@ export class EpisodicMemory {
|
|
|
429
436
|
}
|
|
430
437
|
|
|
431
438
|
// §3: 跨维度引用建议
|
|
432
|
-
const relevantCrossRefs = this.#crossReferences.filter(
|
|
433
|
-
cr => cr.to === currentDimId
|
|
434
|
-
);
|
|
439
|
+
const relevantCrossRefs = this.#crossReferences.filter((cr) => cr.to === currentDimId);
|
|
435
440
|
if (relevantCrossRefs.length > 0) {
|
|
436
441
|
parts.push(`### 其他维度对 ${currentDimId} 的建议`);
|
|
437
442
|
for (const cr of relevantCrossRefs) {
|
|
@@ -458,11 +463,13 @@ export class EpisodicMemory {
|
|
|
458
463
|
buildContextSnapshot(currentDimId) {
|
|
459
464
|
const previousDimensions = {};
|
|
460
465
|
for (const [dimId, report] of this.#dimensionReports) {
|
|
461
|
-
if (dimId === currentDimId)
|
|
466
|
+
if (dimId === currentDimId) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
462
469
|
previousDimensions[dimId] = report.digest || {
|
|
463
470
|
summary: report.analysisText?.substring(0, 300) || '',
|
|
464
471
|
candidateCount: report.candidatesSummary?.length || 0,
|
|
465
|
-
keyFindings: report.findings?.map(f => f.finding) || [],
|
|
472
|
+
keyFindings: report.findings?.map((f) => f.finding) || [],
|
|
466
473
|
crossRefs: {},
|
|
467
474
|
gaps: [],
|
|
468
475
|
};
|
|
@@ -491,11 +498,14 @@ export class EpisodicMemory {
|
|
|
491
498
|
version: 1,
|
|
492
499
|
savedAt: Date.now(),
|
|
493
500
|
dimensionReports: Object.fromEntries(
|
|
494
|
-
[...this.#dimensionReports].map(([k, v]) => [
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
501
|
+
[...this.#dimensionReports].map(([k, v]) => [
|
|
502
|
+
k,
|
|
503
|
+
{
|
|
504
|
+
...v,
|
|
505
|
+
// 不保存 analysisText 全文 (太大), 只保存 digest + findings
|
|
506
|
+
analysisText: v.analysisText?.substring(0, 500) || '',
|
|
507
|
+
},
|
|
508
|
+
])
|
|
499
509
|
),
|
|
500
510
|
crossReferences: this.#crossReferences,
|
|
501
511
|
tierReflections: this.#tierReflections,
|
|
@@ -509,7 +519,9 @@ export class EpisodicMemory {
|
|
|
509
519
|
'utf-8'
|
|
510
520
|
);
|
|
511
521
|
|
|
512
|
-
this.#logger.info(
|
|
522
|
+
this.#logger.info(
|
|
523
|
+
`[EpisodicMemory] Checkpoint saved: ${this.#dimensionReports.size} reports`
|
|
524
|
+
);
|
|
513
525
|
} catch (err) {
|
|
514
526
|
this.#logger.warn(`[EpisodicMemory] Failed to save checkpoint: ${err.message}`);
|
|
515
527
|
}
|
|
@@ -522,11 +534,16 @@ export class EpisodicMemory {
|
|
|
522
534
|
*/
|
|
523
535
|
async loadCheckpoint(projectRoot) {
|
|
524
536
|
const checkpointPath = path.join(
|
|
525
|
-
projectRoot,
|
|
537
|
+
projectRoot,
|
|
538
|
+
'.autosnippet',
|
|
539
|
+
'bootstrap-checkpoint',
|
|
540
|
+
'episodic-memory.json'
|
|
526
541
|
);
|
|
527
542
|
|
|
528
543
|
try {
|
|
529
|
-
if (!fs.existsSync(checkpointPath))
|
|
544
|
+
if (!fs.existsSync(checkpointPath)) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
530
547
|
|
|
531
548
|
const raw = fs.readFileSync(checkpointPath, 'utf-8');
|
|
532
549
|
const data = JSON.parse(raw);
|
|
@@ -561,7 +578,9 @@ export class EpisodicMemory {
|
|
|
561
578
|
}
|
|
562
579
|
}
|
|
563
580
|
|
|
564
|
-
this.#logger.info(
|
|
581
|
+
this.#logger.info(
|
|
582
|
+
`[EpisodicMemory] Checkpoint loaded: ${this.#dimensionReports.size} reports`
|
|
583
|
+
);
|
|
565
584
|
return true;
|
|
566
585
|
} catch (err) {
|
|
567
586
|
this.#logger.warn(`[EpisodicMemory] Failed to load checkpoint: ${err.message}`);
|
|
@@ -640,12 +659,18 @@ export class EpisodicMemory {
|
|
|
640
659
|
* @returns {object}
|
|
641
660
|
*/
|
|
642
661
|
getStats() {
|
|
643
|
-
const totalFindings = [...this.#dimensionReports.values()]
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const
|
|
648
|
-
|
|
662
|
+
const totalFindings = [...this.#dimensionReports.values()].reduce(
|
|
663
|
+
(sum, r) => sum + r.findings.length,
|
|
664
|
+
0
|
|
665
|
+
);
|
|
666
|
+
const totalEvidence = [...this.#evidenceStore.values()].reduce(
|
|
667
|
+
(sum, arr) => sum + arr.length,
|
|
668
|
+
0
|
|
669
|
+
);
|
|
670
|
+
const totalCandidates = [...this.#submittedCandidates.values()].reduce(
|
|
671
|
+
(sum, arr) => sum + arr.length,
|
|
672
|
+
0
|
|
673
|
+
);
|
|
649
674
|
|
|
650
675
|
return {
|
|
651
676
|
completedDimensions: this.#dimensionReports.size,
|
|
@@ -668,7 +693,9 @@ export class EpisodicMemory {
|
|
|
668
693
|
* @returns {Finding[]}
|
|
669
694
|
*/
|
|
670
695
|
#selectRelevantFindings(findings, focusAreas, limit) {
|
|
671
|
-
if (!findings || findings.length === 0)
|
|
696
|
+
if (!findings || findings.length === 0) {
|
|
697
|
+
return [];
|
|
698
|
+
}
|
|
672
699
|
|
|
673
700
|
if (!focusAreas || focusAreas.length === 0) {
|
|
674
701
|
// 无焦点领域: 按重要性排序
|
|
@@ -679,10 +706,12 @@ export class EpisodicMemory {
|
|
|
679
706
|
|
|
680
707
|
// 有焦点领域: 综合重要性 + 关键词匹配
|
|
681
708
|
return [...findings]
|
|
682
|
-
.map(f => {
|
|
683
|
-
const relevance = focusAreas.some(area =>
|
|
709
|
+
.map((f) => {
|
|
710
|
+
const relevance = focusAreas.some((area) =>
|
|
684
711
|
(f.finding || '').toLowerCase().includes(area.toLowerCase())
|
|
685
|
-
)
|
|
712
|
+
)
|
|
713
|
+
? 1
|
|
714
|
+
: 0;
|
|
686
715
|
return { ...f, _score: relevance * 10 + (f.importance || 5) };
|
|
687
716
|
})
|
|
688
717
|
.sort((a, b) => b._score - a._score)
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* @module pipeline/IncrementalBootstrap
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { EpisodicMemory } from './EpisodicMemory.js';
|
|
19
18
|
import { BootstrapSnapshot } from './BootstrapSnapshot.js';
|
|
19
|
+
import { EpisodicMemory } from './EpisodicMemory.js';
|
|
20
20
|
|
|
21
21
|
// ──────────────────────────────────────────────────────────────
|
|
22
22
|
// IncrementalBootstrap 类
|
|
@@ -85,14 +85,12 @@ export class IncrementalBootstrap {
|
|
|
85
85
|
|
|
86
86
|
this.#log(
|
|
87
87
|
`Diff: +${diff.added.length} added, ~${diff.modified.length} modified, ` +
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
`-${diff.deleted.length} deleted, =${diff.unchanged.length} unchanged ` +
|
|
89
|
+
`(ratio: ${(diff.changeRatio * 100).toFixed(1)}%)`
|
|
90
90
|
);
|
|
91
91
|
|
|
92
92
|
// 3. 推断受影响维度
|
|
93
|
-
const inference = this.#snapshot.inferAffectedDimensions(
|
|
94
|
-
previousSnapshot, diff, allDimIds
|
|
95
|
-
);
|
|
93
|
+
const inference = this.#snapshot.inferAffectedDimensions(previousSnapshot, diff, allDimIds);
|
|
96
94
|
|
|
97
95
|
if (inference.mode === 'full') {
|
|
98
96
|
this.#log(`Full rebuild recommended: ${inference.reason}`);
|
|
@@ -113,7 +111,9 @@ export class IncrementalBootstrap {
|
|
|
113
111
|
if (previousSnapshot.episodicData) {
|
|
114
112
|
try {
|
|
115
113
|
restoredEpisodic = EpisodicMemory.fromJSON(previousSnapshot.episodicData);
|
|
116
|
-
this.#log(
|
|
114
|
+
this.#log(
|
|
115
|
+
`Restored EpisodicMemory: ${restoredEpisodic.getCompletedDimensions().length} dimensions`
|
|
116
|
+
);
|
|
117
117
|
} catch (err) {
|
|
118
118
|
this.#log(`Failed to restore EpisodicMemory: ${err.message}`, 'warn');
|
|
119
119
|
}
|
|
@@ -121,7 +121,7 @@ export class IncrementalBootstrap {
|
|
|
121
121
|
|
|
122
122
|
this.#log(
|
|
123
123
|
`Incremental plan: ${inference.dimensions.length} affected, ` +
|
|
124
|
-
|
|
124
|
+
`${inference.skippedDimensions.length} skipped — ${inference.reason}`
|
|
125
125
|
);
|
|
126
126
|
|
|
127
127
|
return {
|
|
@@ -134,7 +134,6 @@ export class IncrementalBootstrap {
|
|
|
134
134
|
reason: inference.reason,
|
|
135
135
|
restoredEpisodic,
|
|
136
136
|
};
|
|
137
|
-
|
|
138
137
|
} catch (err) {
|
|
139
138
|
this.#log(`Incremental evaluation failed: ${err.message} — fallback to full`, 'warn');
|
|
140
139
|
return {
|
|
@@ -163,14 +162,7 @@ export class IncrementalBootstrap {
|
|
|
163
162
|
* @returns {string} 快照 ID
|
|
164
163
|
*/
|
|
165
164
|
saveSnapshot(params) {
|
|
166
|
-
const {
|
|
167
|
-
sessionId,
|
|
168
|
-
allFiles,
|
|
169
|
-
dimensionStats,
|
|
170
|
-
episodicMemory,
|
|
171
|
-
meta = {},
|
|
172
|
-
plan = null,
|
|
173
|
-
} = params;
|
|
165
|
+
const { sessionId, allFiles, dimensionStats, episodicMemory, meta = {}, plan = null } = params;
|
|
174
166
|
|
|
175
167
|
// 构建带 referencedFilesList 的 dimensionStats
|
|
176
168
|
const enrichedStats = { ...dimensionStats };
|
|
@@ -58,7 +58,9 @@ export class ToolResultCache {
|
|
|
58
58
|
if (this.#ttlMs > 0 && cleanupInterval > 0) {
|
|
59
59
|
this.#cleanupTimer = setInterval(() => this.#evictExpired(), cleanupInterval);
|
|
60
60
|
// 允许进程退出时不被 timer 阻塞
|
|
61
|
-
if (this.#cleanupTimer.unref)
|
|
61
|
+
if (this.#cleanupTimer.unref) {
|
|
62
|
+
this.#cleanupTimer.unref();
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -91,7 +93,7 @@ export class ToolResultCache {
|
|
|
91
93
|
const entry = this.#searchCache.get(pattern);
|
|
92
94
|
if (entry) {
|
|
93
95
|
// TTL 检查
|
|
94
|
-
if (this.#ttlMs > 0 &&
|
|
96
|
+
if (this.#ttlMs > 0 && Date.now() - entry.cachedAt > this.#ttlMs) {
|
|
95
97
|
this.#searchCache.delete(pattern);
|
|
96
98
|
this.#stats.evictions++;
|
|
97
99
|
this.#stats.misses++;
|
|
@@ -133,7 +135,7 @@ export class ToolResultCache {
|
|
|
133
135
|
const entry = this.#fileCache.get(filePath);
|
|
134
136
|
if (entry) {
|
|
135
137
|
// TTL 检查
|
|
136
|
-
if (this.#ttlMs > 0 &&
|
|
138
|
+
if (this.#ttlMs > 0 && Date.now() - entry.cachedAt > this.#ttlMs) {
|
|
137
139
|
this.#fileCache.delete(filePath);
|
|
138
140
|
this.#stats.evictions++;
|
|
139
141
|
this.#stats.misses++;
|
|
@@ -205,9 +207,10 @@ export class ToolResultCache {
|
|
|
205
207
|
getStats() {
|
|
206
208
|
return {
|
|
207
209
|
...this.#stats,
|
|
208
|
-
hitRate:
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
hitRate:
|
|
211
|
+
this.#stats.hits + this.#stats.misses > 0
|
|
212
|
+
? `${((this.#stats.hits / (this.#stats.hits + this.#stats.misses)) * 100).toFixed(1)}%`
|
|
213
|
+
: '0%',
|
|
211
214
|
searchCacheSize: this.#searchCache.size,
|
|
212
215
|
fileCacheSize: this.#fileCache.size,
|
|
213
216
|
};
|
|
@@ -241,18 +244,20 @@ export class ToolResultCache {
|
|
|
241
244
|
* @private
|
|
242
245
|
*/
|
|
243
246
|
#evictExpired() {
|
|
244
|
-
if (this.#ttlMs <= 0)
|
|
247
|
+
if (this.#ttlMs <= 0) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
245
250
|
const now = Date.now();
|
|
246
251
|
let evicted = 0;
|
|
247
252
|
|
|
248
253
|
for (const [key, entry] of this.#searchCache) {
|
|
249
|
-
if (
|
|
254
|
+
if (now - entry.cachedAt > this.#ttlMs) {
|
|
250
255
|
this.#searchCache.delete(key);
|
|
251
256
|
evicted++;
|
|
252
257
|
}
|
|
253
258
|
}
|
|
254
259
|
for (const [key, entry] of this.#fileCache) {
|
|
255
|
-
if (
|
|
260
|
+
if (now - entry.cachedAt > this.#ttlMs) {
|
|
256
261
|
this.#fileCache.delete(key);
|
|
257
262
|
evicted++;
|
|
258
263
|
}
|
|
@@ -91,7 +91,7 @@ export class DimensionContext {
|
|
|
91
91
|
return {
|
|
92
92
|
project: this.projectContext,
|
|
93
93
|
previousDimensions,
|
|
94
|
-
existingCandidates: this.submittedCandidates.map(c => ({
|
|
94
|
+
existingCandidates: this.submittedCandidates.map((c) => ({
|
|
95
95
|
dimId: c.dimId,
|
|
96
96
|
title: c.title,
|
|
97
97
|
subTopic: c.subTopic,
|
|
@@ -107,7 +107,7 @@ export class DimensionContext {
|
|
|
107
107
|
* @returns {Array<CandidateSummary>}
|
|
108
108
|
*/
|
|
109
109
|
getExistingCandidatesForDimension(dimId) {
|
|
110
|
-
return this.submittedCandidates.filter(c => c.dimId === dimId);
|
|
110
|
+
return this.submittedCandidates.filter((c) => c.dimId === dimId);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
@@ -117,7 +117,9 @@ export class DimensionContext {
|
|
|
117
117
|
* @returns {string}
|
|
118
118
|
*/
|
|
119
119
|
getDigestsSummaryText() {
|
|
120
|
-
if (this.completedDimensions.size === 0)
|
|
120
|
+
if (this.completedDimensions.size === 0) {
|
|
121
|
+
return '(尚无已完成维度)';
|
|
122
|
+
}
|
|
121
123
|
|
|
122
124
|
const lines = [];
|
|
123
125
|
for (const [id, digest] of this.completedDimensions) {
|
|
@@ -136,7 +138,7 @@ export class DimensionContext {
|
|
|
136
138
|
lines.push(`- 缺口: ${digest.gaps.join('; ')}`);
|
|
137
139
|
}
|
|
138
140
|
if (digest.remainingTasks?.length) {
|
|
139
|
-
lines.push(`- 遗留任务: ${digest.remainingTasks.map(t => t.signal || t).join('; ')}`);
|
|
141
|
+
lines.push(`- 遗留任务: ${digest.remainingTasks.map((t) => t.signal || t).join('; ')}`);
|
|
140
142
|
}
|
|
141
143
|
lines.push('');
|
|
142
144
|
}
|
|
@@ -180,7 +182,9 @@ export class DimensionContext {
|
|
|
180
182
|
* @returns {DimensionDigest|null}
|
|
181
183
|
*/
|
|
182
184
|
export function parseDimensionDigest(reply) {
|
|
183
|
-
if (!reply || typeof reply !== 'string')
|
|
185
|
+
if (!reply || typeof reply !== 'string') {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
184
188
|
|
|
185
189
|
// 尝试匹配 {"dimensionDigest": {...}} 格式
|
|
186
190
|
const jsonBlockRe = /```(?:json)?\s*\n?\s*(\{[\s\S]*?"dimensionDigest"[\s\S]*?\})\s*\n?\s*```/;
|
|
@@ -192,14 +196,18 @@ export function parseDimensionDigest(reply) {
|
|
|
192
196
|
match = reply.match(bareRe);
|
|
193
197
|
}
|
|
194
198
|
|
|
195
|
-
if (!match)
|
|
199
|
+
if (!match) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
196
202
|
|
|
197
203
|
try {
|
|
198
204
|
const parsed = JSON.parse(match[1]);
|
|
199
205
|
const digest = parsed.dimensionDigest || parsed;
|
|
200
206
|
|
|
201
207
|
// 验证必要字段
|
|
202
|
-
if (!digest.summary && !digest.candidateCount)
|
|
208
|
+
if (!digest.summary && !digest.candidateCount) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
203
211
|
|
|
204
212
|
return {
|
|
205
213
|
summary: digest.summary || '',
|