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
|
@@ -32,23 +32,23 @@ import { jaccardSimilarity, tokenizeForSimilarity } from '../../shared/similarit
|
|
|
32
32
|
// ──────────────────────────────────────────────────────────────
|
|
33
33
|
|
|
34
34
|
/** 检索打分权重 (借鉴 Generative Agents) */
|
|
35
|
-
const WEIGHT_RECENCY
|
|
35
|
+
const WEIGHT_RECENCY = 0.2;
|
|
36
36
|
const WEIGHT_IMPORTANCE = 0.3;
|
|
37
|
-
const WEIGHT_RELEVANCE
|
|
37
|
+
const WEIGHT_RELEVANCE = 0.5;
|
|
38
38
|
|
|
39
39
|
/** Recency 半衰期 (天) — 7 天未访问的记忆分数下降一半 */
|
|
40
40
|
const RECENCY_HALF_LIFE_DAYS = 7;
|
|
41
41
|
|
|
42
42
|
/** 自然遗忘阈值 */
|
|
43
|
-
const ARCHIVE_DAYS
|
|
44
|
-
const FORGET_DAYS
|
|
43
|
+
const ARCHIVE_DAYS = 30; // 30 天未访问 + importance < 3 → 归档
|
|
44
|
+
const FORGET_DAYS = 90; // 90 天未访问 → 完全遗忘
|
|
45
45
|
|
|
46
46
|
/** 最大记忆条数 (防止无限膨胀) */
|
|
47
|
-
const MAX_MEMORIES
|
|
47
|
+
const MAX_MEMORIES = 500;
|
|
48
48
|
|
|
49
49
|
/** 相似度阈值 */
|
|
50
|
-
const SIMILARITY_UPDATE = 0.85;
|
|
51
|
-
const SIMILARITY_MERGE
|
|
50
|
+
const SIMILARITY_UPDATE = 0.85; // ≥85% 同义 → UPDATE
|
|
51
|
+
const SIMILARITY_MERGE = 0.6; // ≥60% 相关 → MERGE
|
|
52
52
|
|
|
53
53
|
// ──────────────────────────────────────────────────────────────
|
|
54
54
|
// ProjectSemanticMemory 类
|
|
@@ -70,7 +70,9 @@ export class ProjectSemanticMemory {
|
|
|
70
70
|
* @param {object} [opts.logger] — Logger 实例
|
|
71
71
|
*/
|
|
72
72
|
constructor(db, { logger } = {}) {
|
|
73
|
-
if (!db)
|
|
73
|
+
if (!db) {
|
|
74
|
+
throw new Error('ProjectSemanticMemory requires a database instance');
|
|
75
|
+
}
|
|
74
76
|
this.#db = typeof db?.getDb === 'function' ? db.getDb() : db;
|
|
75
77
|
this.#logger = logger || null;
|
|
76
78
|
|
|
@@ -137,7 +139,9 @@ export class ProjectSemanticMemory {
|
|
|
137
139
|
*/
|
|
138
140
|
update(id, updates) {
|
|
139
141
|
const existing = this.#stmts.getById.get(id);
|
|
140
|
-
if (!existing)
|
|
142
|
+
if (!existing) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
141
145
|
|
|
142
146
|
const now = new Date().toISOString();
|
|
143
147
|
const fields = [];
|
|
@@ -168,7 +172,9 @@ export class ProjectSemanticMemory {
|
|
|
168
172
|
params.tags = JSON.stringify(updates.tags);
|
|
169
173
|
}
|
|
170
174
|
|
|
171
|
-
if (fields.length === 0)
|
|
175
|
+
if (fields.length === 0) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
172
178
|
|
|
173
179
|
fields.push('updated_at = @updated_at');
|
|
174
180
|
params.updated_at = now;
|
|
@@ -268,7 +274,9 @@ export class ProjectSemanticMemory {
|
|
|
268
274
|
|
|
269
275
|
runConsolidate();
|
|
270
276
|
|
|
271
|
-
this.#log(
|
|
277
|
+
this.#log(
|
|
278
|
+
`Consolidation: +${stats.added} ADD, ~${stats.updated} UPDATE, ⊕${stats.merged} MERGE, =${stats.skipped} SKIP`
|
|
279
|
+
);
|
|
272
280
|
|
|
273
281
|
// 容量控制
|
|
274
282
|
this.#enforceCapacity();
|
|
@@ -293,19 +301,21 @@ export class ProjectSemanticMemory {
|
|
|
293
301
|
*/
|
|
294
302
|
retrieve(query, { limit = 10, source, type } = {}) {
|
|
295
303
|
const all = this.#getAllActive({ source, type });
|
|
296
|
-
if (all.length === 0)
|
|
304
|
+
if (all.length === 0) {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
297
307
|
|
|
298
308
|
const now = Date.now();
|
|
299
309
|
const lowerQuery = (query || '').toLowerCase();
|
|
300
310
|
const queryTokens = this.#tokenizeWords(lowerQuery);
|
|
301
311
|
|
|
302
|
-
const scored = all.map(m => {
|
|
312
|
+
const scored = all.map((m) => {
|
|
303
313
|
// Recency: 指数衰减 (半衰期 7 天)
|
|
304
314
|
const lastAccess = m.last_accessed_at
|
|
305
315
|
? new Date(m.last_accessed_at).getTime()
|
|
306
316
|
: new Date(m.updated_at).getTime();
|
|
307
317
|
const daysSinceAccess = (now - lastAccess) / 86400_000;
|
|
308
|
-
const recency = Math.exp(-daysSinceAccess * Math.LN2 / RECENCY_HALF_LIFE_DAYS);
|
|
318
|
+
const recency = Math.exp((-daysSinceAccess * Math.LN2) / RECENCY_HALF_LIFE_DAYS);
|
|
309
319
|
|
|
310
320
|
// Importance: 归一化到 0-1
|
|
311
321
|
const importance = (m.importance || 5) / 10;
|
|
@@ -313,9 +323,8 @@ export class ProjectSemanticMemory {
|
|
|
313
323
|
// Relevance: token overlap + 子串匹配
|
|
314
324
|
const relevance = this.#computeRelevance(lowerQuery, queryTokens, m.content);
|
|
315
325
|
|
|
316
|
-
const score =
|
|
317
|
-
|
|
318
|
-
+ WEIGHT_RELEVANCE * relevance;
|
|
326
|
+
const score =
|
|
327
|
+
WEIGHT_RECENCY * recency + WEIGHT_IMPORTANCE * importance + WEIGHT_RELEVANCE * relevance;
|
|
319
328
|
|
|
320
329
|
return {
|
|
321
330
|
...this.#deserialize(m),
|
|
@@ -347,7 +356,7 @@ export class ProjectSemanticMemory {
|
|
|
347
356
|
*/
|
|
348
357
|
search(content, { limit = 5 } = {}) {
|
|
349
358
|
const results = this.#findSimilar(content, null, limit);
|
|
350
|
-
return results.map(r => this.#deserialize(r));
|
|
359
|
+
return results.map((r) => this.#deserialize(r));
|
|
351
360
|
}
|
|
352
361
|
|
|
353
362
|
// ─── Prompt 生成 (兼容 Memory.js) ──────────────────────
|
|
@@ -381,12 +390,14 @@ export class ProjectSemanticMemory {
|
|
|
381
390
|
return scoreB - scoreA;
|
|
382
391
|
})
|
|
383
392
|
.slice(0, limit)
|
|
384
|
-
.map(m => this.#deserialize(m));
|
|
393
|
+
.map((m) => this.#deserialize(m));
|
|
385
394
|
}
|
|
386
395
|
|
|
387
|
-
if (memories.length === 0)
|
|
396
|
+
if (memories.length === 0) {
|
|
397
|
+
return '';
|
|
398
|
+
}
|
|
388
399
|
|
|
389
|
-
const lines = memories.map(m => {
|
|
400
|
+
const lines = memories.map((m) => {
|
|
390
401
|
const badge = m.importance >= 8 ? '⚠️' : m.importance >= 5 ? '📌' : '💡';
|
|
391
402
|
return `- ${badge} [${m.type}] ${m.content}`;
|
|
392
403
|
});
|
|
@@ -412,7 +423,7 @@ export class ProjectSemanticMemory {
|
|
|
412
423
|
return tB - tA;
|
|
413
424
|
})
|
|
414
425
|
.slice(0, limit);
|
|
415
|
-
return rows.map(r => ({
|
|
426
|
+
return rows.map((r) => ({
|
|
416
427
|
ts: r.updated_at,
|
|
417
428
|
type: r.type,
|
|
418
429
|
content: r.content,
|
|
@@ -432,7 +443,9 @@ export class ProjectSemanticMemory {
|
|
|
432
443
|
*/
|
|
433
444
|
append(entry) {
|
|
434
445
|
const content = (entry.content || '').trim().substring(0, 500);
|
|
435
|
-
if (!content)
|
|
446
|
+
if (!content) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
436
449
|
|
|
437
450
|
// 去重: 检查是否已有高相似度记忆
|
|
438
451
|
const similar = this.#findSimilar(content, entry.type, 1);
|
|
@@ -459,13 +472,13 @@ export class ProjectSemanticMemory {
|
|
|
459
472
|
*/
|
|
460
473
|
size({ source } = {}) {
|
|
461
474
|
if (source) {
|
|
462
|
-
return
|
|
463
|
-
|
|
464
|
-
|
|
475
|
+
return (
|
|
476
|
+
this.#db
|
|
477
|
+
.prepare('SELECT COUNT(*) as cnt FROM semantic_memories WHERE source = ?')
|
|
478
|
+
.get(source)?.cnt || 0
|
|
479
|
+
);
|
|
465
480
|
}
|
|
466
|
-
return this.#db.prepare(
|
|
467
|
-
'SELECT COUNT(*) as cnt FROM semantic_memories'
|
|
468
|
-
).get()?.cnt || 0;
|
|
481
|
+
return this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
|
|
469
482
|
}
|
|
470
483
|
|
|
471
484
|
// ─── 维护: 过期清理 + 容量控制 ────────────────────────
|
|
@@ -484,31 +497,36 @@ export class ProjectSemanticMemory {
|
|
|
484
497
|
|
|
485
498
|
const runCompact = this.#db.transaction(() => {
|
|
486
499
|
// 1. 删除 TTL 过期
|
|
487
|
-
const expiredResult = this.#db
|
|
488
|
-
'DELETE FROM semantic_memories WHERE expires_at IS NOT NULL AND expires_at < ?'
|
|
489
|
-
|
|
500
|
+
const expiredResult = this.#db
|
|
501
|
+
.prepare('DELETE FROM semantic_memories WHERE expires_at IS NOT NULL AND expires_at < ?')
|
|
502
|
+
.run(now);
|
|
490
503
|
stats.expired = expiredResult.changes;
|
|
491
504
|
|
|
492
505
|
// 2. 完全遗忘: 90 天未访问
|
|
493
506
|
const forgetThreshold = new Date(nowMs - FORGET_DAYS * 86400_000).toISOString();
|
|
494
|
-
const forgottenResult = this.#db
|
|
495
|
-
'DELETE FROM semantic_memories WHERE last_accessed_at < ? AND importance < 7'
|
|
496
|
-
|
|
507
|
+
const forgottenResult = this.#db
|
|
508
|
+
.prepare('DELETE FROM semantic_memories WHERE last_accessed_at < ? AND importance < 7')
|
|
509
|
+
.run(forgetThreshold);
|
|
497
510
|
stats.forgotten = forgottenResult.changes;
|
|
498
511
|
|
|
499
512
|
// 3. 归档: 30 天未访问 + 低重要性 → 降低 importance
|
|
500
513
|
const archiveThreshold = new Date(nowMs - ARCHIVE_DAYS * 86400_000).toISOString();
|
|
501
|
-
const archiveResult = this.#db
|
|
502
|
-
|
|
503
|
-
|
|
514
|
+
const archiveResult = this.#db
|
|
515
|
+
.prepare(
|
|
516
|
+
'UPDATE semantic_memories SET importance = MAX(1, importance - 1) WHERE last_accessed_at < ? AND importance < 3'
|
|
517
|
+
)
|
|
518
|
+
.run(archiveThreshold);
|
|
504
519
|
stats.archived = archiveResult.changes;
|
|
505
520
|
|
|
506
|
-
stats.remaining =
|
|
521
|
+
stats.remaining =
|
|
522
|
+
this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
|
|
507
523
|
});
|
|
508
524
|
|
|
509
525
|
runCompact();
|
|
510
526
|
|
|
511
|
-
this.#log(
|
|
527
|
+
this.#log(
|
|
528
|
+
`Compact: ${stats.expired} expired, ${stats.forgotten} forgotten, ${stats.archived} archived, ${stats.remaining} remaining`
|
|
529
|
+
);
|
|
512
530
|
return stats;
|
|
513
531
|
}
|
|
514
532
|
|
|
@@ -520,20 +538,19 @@ export class ProjectSemanticMemory {
|
|
|
520
538
|
*/
|
|
521
539
|
getStats() {
|
|
522
540
|
const total = this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
|
|
523
|
-
const byType = this.#db
|
|
524
|
-
'SELECT type, COUNT(*) as cnt FROM semantic_memories GROUP BY type'
|
|
525
|
-
|
|
526
|
-
const bySource = this.#db
|
|
527
|
-
'SELECT source, COUNT(*) as cnt FROM semantic_memories GROUP BY source'
|
|
528
|
-
|
|
529
|
-
const avgImportance =
|
|
530
|
-
'SELECT AVG(importance) as avg FROM semantic_memories'
|
|
531
|
-
).get()?.avg || 0;
|
|
541
|
+
const byType = this.#db
|
|
542
|
+
.prepare('SELECT type, COUNT(*) as cnt FROM semantic_memories GROUP BY type')
|
|
543
|
+
.all();
|
|
544
|
+
const bySource = this.#db
|
|
545
|
+
.prepare('SELECT source, COUNT(*) as cnt FROM semantic_memories GROUP BY source')
|
|
546
|
+
.all();
|
|
547
|
+
const avgImportance =
|
|
548
|
+
this.#db.prepare('SELECT AVG(importance) as avg FROM semantic_memories').get()?.avg || 0;
|
|
532
549
|
|
|
533
550
|
return {
|
|
534
551
|
total,
|
|
535
|
-
byType: Object.fromEntries(byType.map(r => [r.type, r.cnt])),
|
|
536
|
-
bySource: Object.fromEntries(bySource.map(r => [r.source, r.cnt])),
|
|
552
|
+
byType: Object.fromEntries(byType.map((r) => [r.type, r.cnt])),
|
|
553
|
+
bySource: Object.fromEntries(bySource.map((r) => [r.source, r.cnt])),
|
|
537
554
|
avgImportance: Math.round(avgImportance * 10) / 10,
|
|
538
555
|
};
|
|
539
556
|
}
|
|
@@ -543,9 +560,9 @@ export class ProjectSemanticMemory {
|
|
|
543
560
|
* @returns {number} 删除数量
|
|
544
561
|
*/
|
|
545
562
|
clearBootstrapMemories() {
|
|
546
|
-
const result = this.#db
|
|
547
|
-
"DELETE FROM semantic_memories WHERE source = 'bootstrap'"
|
|
548
|
-
|
|
563
|
+
const result = this.#db
|
|
564
|
+
.prepare("DELETE FROM semantic_memories WHERE source = 'bootstrap'")
|
|
565
|
+
.run();
|
|
549
566
|
this.#log(`Cleared ${result.changes} bootstrap memories`);
|
|
550
567
|
return result.changes;
|
|
551
568
|
}
|
|
@@ -556,9 +573,9 @@ export class ProjectSemanticMemory {
|
|
|
556
573
|
* 确保表存在 (用于 migration 未运行的情况)
|
|
557
574
|
*/
|
|
558
575
|
#ensureTable() {
|
|
559
|
-
const exists = this.#db
|
|
560
|
-
"SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_memories'"
|
|
561
|
-
|
|
576
|
+
const exists = this.#db
|
|
577
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_memories'")
|
|
578
|
+
.get();
|
|
562
579
|
|
|
563
580
|
if (!exists) {
|
|
564
581
|
this.#db.exec(`
|
|
@@ -602,13 +619,9 @@ export class ProjectSemanticMemory {
|
|
|
602
619
|
@source_dimension, @source_evidence, @bootstrap_session, @tags)
|
|
603
620
|
`),
|
|
604
621
|
|
|
605
|
-
getById: this.#db.prepare(
|
|
606
|
-
'SELECT * FROM semantic_memories WHERE id = ?'
|
|
607
|
-
),
|
|
622
|
+
getById: this.#db.prepare('SELECT * FROM semantic_memories WHERE id = ?'),
|
|
608
623
|
|
|
609
|
-
deleteById: this.#db.prepare(
|
|
610
|
-
'DELETE FROM semantic_memories WHERE id = ?'
|
|
611
|
-
),
|
|
624
|
+
deleteById: this.#db.prepare('DELETE FROM semantic_memories WHERE id = ?'),
|
|
612
625
|
|
|
613
626
|
touchAccess: this.#db.prepare(`
|
|
614
627
|
UPDATE semantic_memories
|
|
@@ -685,7 +698,9 @@ export class ProjectSemanticMemory {
|
|
|
685
698
|
#touchAccess(id) {
|
|
686
699
|
try {
|
|
687
700
|
this.#stmts.touchAccess.run({ id, now: new Date().toISOString() });
|
|
688
|
-
} catch {
|
|
701
|
+
} catch {
|
|
702
|
+
/* non-critical */
|
|
703
|
+
}
|
|
689
704
|
}
|
|
690
705
|
|
|
691
706
|
/**
|
|
@@ -706,11 +721,11 @@ export class ProjectSemanticMemory {
|
|
|
706
721
|
const contentTokens = tokenizeForSimilarity(lowerContent);
|
|
707
722
|
|
|
708
723
|
const scored = candidates
|
|
709
|
-
.map(row => {
|
|
724
|
+
.map((row) => {
|
|
710
725
|
const similarity = this.#computeSimilarity(contentTokens, lowerContent, row.content);
|
|
711
726
|
return { ...row, similarity, related_memories_raw: row.related_memories };
|
|
712
727
|
})
|
|
713
|
-
.filter(r => r.similarity > 0.1)
|
|
728
|
+
.filter((r) => r.similarity > 0.1)
|
|
714
729
|
.sort((a, b) => b.similarity - a.similarity);
|
|
715
730
|
|
|
716
731
|
return scored.slice(0, limit);
|
|
@@ -728,13 +743,17 @@ export class ProjectSemanticMemory {
|
|
|
728
743
|
const lowerB = (contentB || '').toLowerCase();
|
|
729
744
|
const tokensB = tokenizeForSimilarity(lowerB);
|
|
730
745
|
|
|
731
|
-
if (tokensA.size === 0 && tokensB.size === 0)
|
|
732
|
-
|
|
746
|
+
if (tokensA.size === 0 && tokensB.size === 0) {
|
|
747
|
+
return 1.0;
|
|
748
|
+
}
|
|
749
|
+
if (tokensA.size === 0 || tokensB.size === 0) {
|
|
750
|
+
return 0.0;
|
|
751
|
+
}
|
|
733
752
|
|
|
734
753
|
const jaccard = jaccardSimilarity(tokensA, tokensB);
|
|
735
754
|
|
|
736
755
|
// 子串包含加分
|
|
737
|
-
const containsBonus =
|
|
756
|
+
const containsBonus = lowerA.includes(lowerB) || lowerB.includes(lowerA) ? 0.3 : 0;
|
|
738
757
|
|
|
739
758
|
return Math.min(1.0, jaccard + containsBonus);
|
|
740
759
|
}
|
|
@@ -748,17 +767,23 @@ export class ProjectSemanticMemory {
|
|
|
748
767
|
* @returns {number} 0.0-1.0
|
|
749
768
|
*/
|
|
750
769
|
#computeRelevance(lowerQuery, queryTokens, content) {
|
|
751
|
-
if (!lowerQuery || !content)
|
|
770
|
+
if (!lowerQuery || !content) {
|
|
771
|
+
return 0;
|
|
772
|
+
}
|
|
752
773
|
|
|
753
774
|
const lowerContent = content.toLowerCase();
|
|
754
775
|
const contentTokens = this.#tokenizeWords(lowerContent);
|
|
755
776
|
|
|
756
|
-
if (queryTokens.size === 0)
|
|
777
|
+
if (queryTokens.size === 0) {
|
|
778
|
+
return 0;
|
|
779
|
+
}
|
|
757
780
|
|
|
758
781
|
// Token overlap
|
|
759
782
|
let matchCount = 0;
|
|
760
783
|
for (const t of queryTokens) {
|
|
761
|
-
if (contentTokens.has(t))
|
|
784
|
+
if (contentTokens.has(t)) {
|
|
785
|
+
matchCount++;
|
|
786
|
+
}
|
|
762
787
|
}
|
|
763
788
|
const tokenOverlap = matchCount / queryTokens.size;
|
|
764
789
|
|
|
@@ -783,12 +808,14 @@ export class ProjectSemanticMemory {
|
|
|
783
808
|
* @returns {Set<string>}
|
|
784
809
|
*/
|
|
785
810
|
#tokenizeWords(text) {
|
|
786
|
-
if (!text)
|
|
811
|
+
if (!text) {
|
|
812
|
+
return new Set();
|
|
813
|
+
}
|
|
787
814
|
return new Set(
|
|
788
815
|
text
|
|
789
816
|
.split(/[\s,;:!?。,;:!?\-_/\\|()[\]{}'"<>]+/)
|
|
790
|
-
.filter(t => t.length >= 2)
|
|
791
|
-
.map(t => t.toLowerCase())
|
|
817
|
+
.filter((t) => t.length >= 2)
|
|
818
|
+
.map((t) => t.toLowerCase())
|
|
792
819
|
);
|
|
793
820
|
}
|
|
794
821
|
|
|
@@ -832,16 +859,20 @@ export class ProjectSemanticMemory {
|
|
|
832
859
|
*/
|
|
833
860
|
#enforceCapacity() {
|
|
834
861
|
const count = this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
|
|
835
|
-
if (count <= MAX_MEMORIES)
|
|
862
|
+
if (count <= MAX_MEMORIES) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
836
865
|
|
|
837
866
|
const excess = count - MAX_MEMORIES;
|
|
838
|
-
this.#db
|
|
867
|
+
this.#db
|
|
868
|
+
.prepare(`
|
|
839
869
|
DELETE FROM semantic_memories WHERE id IN (
|
|
840
870
|
SELECT id FROM semantic_memories
|
|
841
871
|
ORDER BY importance ASC, access_count ASC, updated_at ASC
|
|
842
872
|
LIMIT ?
|
|
843
873
|
)
|
|
844
|
-
`)
|
|
874
|
+
`)
|
|
875
|
+
.run(excess);
|
|
845
876
|
|
|
846
877
|
this.#log(`Capacity enforced: removed ${excess} lowest-priority memories`);
|
|
847
878
|
}
|