squish-memory 1.0.2 → 1.1.5
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/.env.example +130 -0
- package/CHANGELOG.md +55 -0
- package/README.md +150 -287
- package/config/hooks/claude-code-hooks.json +39 -0
- package/config/hooks/cursor-hooks.json +30 -0
- package/config/hooks/opencode-hooks.json +30 -0
- package/config/hooks/windsurf-hooks.json +30 -0
- package/config/mcp-mode-semantics.json +23 -21
- package/config/plugin-manifest.json +101 -152
- package/{plugin.json → config/plugin.json} +2 -2
- package/config/settings.json +52 -51
- package/{commands → core/commands}/init.md +39 -39
- package/dist/config.d.ts +28 -4
- package/dist/config.js +97 -29
- package/dist/core/adapters/config/claude-code.d.ts +45 -0
- package/dist/core/adapters/config/claude-code.js +113 -0
- package/dist/core/adapters/config/cursor.d.ts +26 -0
- package/dist/core/adapters/config/cursor.js +74 -0
- package/dist/core/adapters/config/opencode.d.ts +23 -0
- package/dist/core/adapters/config/opencode.js +73 -0
- package/dist/core/adapters/config/windsurf.d.ts +26 -0
- package/dist/core/adapters/config/windsurf.js +74 -0
- package/dist/core/adapters/index.d.ts +45 -0
- package/dist/core/adapters/index.js +84 -0
- package/dist/core/adapters/scripts/install-adapter.d.ts +19 -0
- package/dist/core/adapters/scripts/install-adapter.js +149 -0
- package/dist/core/adapters/timeline.d.ts +23 -0
- package/dist/core/adapters/timeline.js +88 -0
- package/dist/core/adapters/types.d.ts +157 -0
- package/dist/core/adapters/types.js +50 -0
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.js +3 -3
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.js +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.js +7 -10
- package/dist/{algorithms → core/algorithms}/handlers/approve-merge.js +4 -4
- package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/get-stats.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/list-proposals.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/preview-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reject-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.js +3 -3
- package/dist/core/algorithms/index.d.ts +21 -0
- package/dist/core/algorithms/index.js +26 -0
- package/dist/core/algorithms/operations/cache-maintenance.d.ts +12 -0
- package/dist/core/algorithms/operations/cache-maintenance.js +157 -0
- package/dist/{algorithms → core/algorithms}/safety/safety-checks.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.d.ts +19 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.js +74 -123
- package/dist/core/algorithms/types.d.ts +133 -0
- package/dist/core/algorithms/types.js +5 -0
- package/dist/core/associations.d.ts +1 -2
- package/dist/core/associations.js +1 -2
- package/dist/core/autosave.d.ts +19 -0
- package/dist/core/autosave.js +16 -0
- package/dist/{commands → core/commands}/managed-sync.js +5 -5
- package/dist/core/commands/mcp-server.js +739 -0
- package/dist/core/context/agent-context.d.ts +106 -0
- package/dist/core/context/agent-context.js +274 -0
- package/dist/core/{context-paging.d.ts → context/context-paging.d.ts} +2 -12
- package/dist/core/{context-paging.js → context/context-paging.js} +19 -39
- package/dist/core/context/context-window.d.ts +40 -0
- package/dist/core/context/context-window.js +177 -0
- package/dist/core/context/context.js +22 -0
- package/dist/core/embeddings.d.ts +1 -1
- package/dist/core/embeddings.js +54 -2
- package/dist/core/error-handling.d.ts +63 -0
- package/dist/core/error-handling.js +173 -0
- package/dist/core/external-folder/index.d.ts +102 -0
- package/dist/core/external-folder/index.js +294 -0
- package/dist/core/hooks/agent-hooks.d.ts +74 -0
- package/dist/core/hooks/agent-hooks.js +244 -0
- package/dist/core/hooks/auto-tagger.d.ts +19 -0
- package/dist/core/hooks/auto-tagger.js +155 -0
- package/dist/core/hooks/capture-filter.d.ts +41 -0
- package/dist/core/hooks/capture-filter.js +128 -0
- package/dist/core/index.d.ts +6 -6
- package/dist/core/index.js +6 -6
- package/dist/core/{agent-memory.js → ingestion/agent-memory.js} +5 -7
- package/dist/core/{core-memory.js → ingestion/core-memory.js} +4 -4
- package/dist/core/ingestion/learnings.d.ts +57 -0
- package/dist/core/ingestion/learnings.js +202 -0
- package/dist/core/lib/db-client.d.ts +114 -0
- package/dist/core/lib/db-client.js +130 -0
- package/dist/core/lib/schemas.d.ts +129 -0
- package/dist/core/lib/schemas.js +87 -0
- package/dist/core/{utils.d.ts → lib/utils.d.ts} +1 -0
- package/dist/core/{utils.js → lib/utils.js} +31 -15
- package/dist/core/lib/validation.d.ts +38 -0
- package/dist/core/lib/validation.js +151 -0
- package/dist/core/lifecycle.d.ts +7 -0
- package/dist/core/lifecycle.js +140 -20
- package/dist/core/local-embeddings.d.ts +6 -1
- package/dist/core/local-embeddings.js +6 -15
- package/dist/core/logger.js +7 -1
- package/dist/core/mcp/tools.js +35 -3
- package/dist/core/memory/categorizer.js +1 -0
- package/dist/core/memory/conflict-detector.js +1 -1
- package/dist/core/memory/consolidation.d.ts +1 -10
- package/dist/core/memory/consolidation.js +2 -11
- package/dist/core/memory/context-collector.js +1 -1
- package/dist/core/memory/edit-workflow.js +1 -1
- package/dist/core/memory/entity-resolver.js +7 -7
- package/dist/core/memory/fact-extractor.js +12 -12
- package/dist/core/memory/feedback-tracker.js +1 -1
- package/dist/core/memory/hooks.d.ts +88 -0
- package/dist/core/memory/hooks.js +174 -0
- package/dist/core/memory/hybrid-retrieval.js +2 -2
- package/dist/core/memory/hybrid-search.d.ts +1 -6
- package/dist/core/memory/hybrid-search.js +70 -84
- package/dist/core/memory/importance.d.ts +8 -13
- package/dist/core/memory/importance.js +47 -74
- package/dist/core/memory/loader.d.ts +31 -0
- package/dist/core/memory/loader.js +141 -0
- package/dist/core/memory/markdown/markdown-storage.d.ts +72 -0
- package/dist/core/memory/markdown/markdown-storage.js +243 -0
- package/dist/core/memory/memories.d.ts +12 -4
- package/dist/core/memory/memories.js +192 -180
- package/dist/core/memory/memory-lifecycle.d.ts +8 -0
- package/dist/core/memory/memory-lifecycle.js +55 -0
- package/dist/core/memory/migrate.d.ts +21 -0
- package/dist/core/memory/migrate.js +134 -0
- package/dist/core/memory/normalization.d.ts +22 -0
- package/dist/core/memory/normalization.js +26 -0
- package/dist/core/memory/progressive-disclosure.js +1 -1
- package/dist/core/memory/query-rewriter.js +9 -9
- package/dist/core/memory/serialization.d.ts +4 -0
- package/dist/core/memory/serialization.js +49 -0
- package/dist/core/memory/stats.d.ts +5 -0
- package/dist/core/memory/stats.js +63 -12
- package/dist/core/memory/temporal-facts.js +21 -0
- package/dist/core/memory/write-gate.js +1 -1
- package/dist/core/obsidian-vault.d.ts +30 -0
- package/dist/core/obsidian-vault.js +94 -0
- package/dist/core/places/index.d.ts +14 -0
- package/dist/core/places/index.js +14 -0
- package/dist/core/places/memory-places.d.ts +68 -0
- package/dist/core/places/memory-places.js +261 -0
- package/dist/core/places/places.d.ts +88 -0
- package/dist/core/places/places.js +314 -0
- package/dist/core/places/rules.d.ts +74 -0
- package/dist/core/places/rules.js +240 -0
- package/dist/core/places/walking.d.ts +56 -0
- package/dist/core/places/walking.js +121 -0
- package/dist/core/projects.d.ts +5 -0
- package/dist/core/projects.js +39 -18
- package/dist/core/responses.d.ts +96 -0
- package/dist/core/responses.js +122 -0
- package/dist/core/scheduler/cron-scheduler.js +29 -7
- package/dist/core/scheduler/index.d.ts +1 -1
- package/dist/core/scheduler/index.js +1 -1
- package/dist/core/scheduler/job-runner.js +1 -1
- package/dist/core/search/conversations.js +40 -42
- package/dist/core/search/entities.js +6 -9
- package/dist/core/search/graph-boost.d.ts +7 -0
- package/dist/core/search/graph-boost.js +23 -0
- package/dist/core/search/qmd-search.js +4 -4
- package/dist/core/security/encrypt.d.ts +6 -0
- package/dist/core/security/encrypt.js +47 -0
- package/dist/core/{governance.d.ts → security/governance.d.ts} +6 -1
- package/dist/core/security/governance.js +79 -0
- package/dist/core/session/auto-load.js +6 -6
- package/dist/core/session/index.d.ts +1 -1
- package/dist/core/session/index.js +1 -1
- package/dist/core/session/self-iteration-job.d.ts +20 -0
- package/dist/core/session/self-iteration-job.js +282 -0
- package/dist/core/session/session-hooks.d.ts +18 -0
- package/dist/core/session/session-hooks.js +58 -0
- package/dist/core/session-hooks/self-iteration-job.js +35 -35
- package/dist/core/{cache.js → storage/cache.js} +2 -2
- package/dist/core/sync/qmd-sync.d.ts +1 -13
- package/dist/core/sync/qmd-sync.js +1 -13
- package/dist/core/toon.d.ts +43 -0
- package/dist/core/toon.js +160 -0
- package/dist/core/utils/memory-operations.js +1 -1
- package/dist/core/utils/vector-operations.d.ts +71 -0
- package/dist/core/utils/vector-operations.js +129 -0
- package/dist/db/adapter.d.ts +3 -3
- package/dist/db/adapter.js +99 -88
- package/dist/db/bootstrap.js +820 -522
- package/dist/{drizzle → db/drizzle}/schema-sqlite.d.ts +74 -25
- package/dist/{drizzle → db/drizzle}/schema-sqlite.js +91 -24
- package/dist/{drizzle → db/drizzle}/schema.d.ts +79 -32
- package/dist/{drizzle → db/drizzle}/schema.js +106 -35
- package/dist/db/drizzle.config.d.ts +3 -0
- package/dist/db/drizzle.config.js +12 -0
- package/dist/db/index.d.ts +1 -5
- package/dist/db/index.js +51 -8
- package/dist/db/neon.d.ts +8 -0
- package/dist/db/neon.js +20 -0
- package/dist/db/schema/index.d.ts +40 -0
- package/dist/db/schema/index.js +105 -0
- package/dist/db/schema/tables/context-sessions.d.ts +9 -0
- package/dist/db/schema/tables/context-sessions.js +37 -0
- package/dist/db/schema/tables/conversations.d.ts +9 -0
- package/dist/db/schema/tables/conversations.js +47 -0
- package/dist/db/schema/tables/core-memory.d.ts +9 -0
- package/dist/db/schema/tables/core-memory.js +41 -0
- package/dist/db/schema/tables/entities.d.ts +9 -0
- package/dist/db/schema/tables/entities.js +39 -0
- package/dist/db/schema/tables/entity-relations.d.ts +9 -0
- package/dist/db/schema/tables/entity-relations.js +31 -0
- package/dist/db/schema/tables/learnings.d.ts +9 -0
- package/dist/db/schema/tables/learnings.js +66 -0
- package/dist/db/schema/tables/memories.d.ts +9 -0
- package/dist/db/schema/tables/memories.js +161 -0
- package/dist/db/schema/tables/memory-associations.d.ts +9 -0
- package/dist/db/schema/tables/memory-associations.js +39 -0
- package/dist/db/schema/tables/memory-hash-cache.d.ts +9 -0
- package/dist/db/schema/tables/memory-hash-cache.js +29 -0
- package/dist/db/schema/tables/memory-merge-history.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-history.js +33 -0
- package/dist/db/schema/tables/memory-merge-proposals.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-proposals.js +39 -0
- package/dist/db/schema/tables/messages.d.ts +9 -0
- package/dist/db/schema/tables/messages.js +41 -0
- package/dist/db/schema/tables/namespaces.d.ts +9 -0
- package/dist/db/schema/tables/namespaces.js +37 -0
- package/dist/db/schema/tables/projects.d.ts +9 -0
- package/dist/db/schema/tables/projects.js +31 -0
- package/dist/db/schema/tables/users.d.ts +9 -0
- package/dist/db/schema/tables/users.js +27 -0
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +2 -2
- package/dist/db/supabase.d.ts +9 -0
- package/dist/db/supabase.js +24 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.js +1320 -640
- package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
- package/dist/webui/server.d.ts +5 -0
- package/dist/{api/web/web.js → webui/server.js} +511 -508
- package/generated/mcp/manifest.json +1 -1
- package/{.mcp.json → mcp.json.example} +1 -1
- package/package.json +159 -181
- package/scripts/README.md +60 -0
- package/scripts/copy-runtime-assets.mjs +26 -0
- package/scripts/generate-mcp.mjs +264 -264
- package/scripts/github-release.sh +4 -4
- package/scripts/install-claude-code.sh +85 -0
- package/scripts/install-cursor.sh +56 -0
- package/scripts/install-hooks.sh +73 -0
- package/scripts/install-interactive.mjs +357 -677
- package/scripts/install-opencode.sh +75 -0
- package/scripts/install-windsurf.sh +67 -0
- package/skills/squish-memory/SKILL.md +104 -114
- package/skills/squish-memory/{install.mjs → scripts/install.mjs} +2 -2
- package/skills/squish-memory/{install.sh → scripts/install.sh} +2 -2
- package/skills/squish-memory/write_skill.js +2 -0
- package/.claude-plugin/marketplace.json +0 -20
- package/.claude-plugin/plugin.json +0 -32
- package/.env.mcp.example +0 -60
- package/QUICK-START.md +0 -71
- package/bin/squish-add.mjs +0 -32
- package/bin/squish-rm.mjs +0 -21
- package/commands/observe.md +0 -5
- package/dist/api/web/index.d.ts +0 -3
- package/dist/api/web/index.js +0 -4
- package/dist/api/web/web-server.d.ts +0 -3
- package/dist/api/web/web-server.js +0 -6
- package/dist/api/web/web.d.ts +0 -4
- package/dist/commands/mcp-server.js +0 -393
- package/dist/core/context.js +0 -24
- package/dist/core/governance.js +0 -64
- package/dist/core/observations.d.ts +0 -26
- package/dist/core/observations.js +0 -110
- package/dist/core/requirements.d.ts +0 -20
- package/dist/core/requirements.js +0 -35
- package/hooks/hooks.json +0 -52
- package/hooks/post-tool-use.js +0 -26
- package/hooks/session-end.js +0 -28
- package/hooks/session-start.js +0 -33
- package/hooks/user-prompt-submit.js +0 -26
- package/hooks/utils.js +0 -153
- package/npx-installer.js +0 -208
- package/packages/plugin-claude-code/README.md +0 -73
- package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts +0 -35
- package/packages/plugin-claude-code/dist/plugin-wrapper.js +0 -191
- package/packages/plugin-claude-code/package.json +0 -31
- package/packages/plugin-openclaw/README.md +0 -70
- package/packages/plugin-openclaw/dist/index.d.ts +0 -49
- package/packages/plugin-openclaw/dist/index.js +0 -262
- package/packages/plugin-openclaw/openclaw.plugin.json +0 -94
- package/packages/plugin-openclaw/package.json +0 -31
- package/packages/plugin-opencode/install.mjs +0 -217
- package/packages/plugin-opencode/package.json +0 -21
- package/scripts/db/check-db.mjs +0 -88
- package/scripts/db/fix-all-columns.mjs +0 -52
- package/scripts/db/fix-schema-all.mjs +0 -55
- package/scripts/db/fix-schema-full.mjs +0 -46
- package/scripts/db/fix-schema.mjs +0 -38
- package/scripts/db/init-db.mjs +0 -13
- package/scripts/db/recreate-db.mjs +0 -14
- package/scripts/install-mcp.mjs +0 -116
- package/scripts/install-web.sh +0 -120
- package/scripts/install.mjs +0 -340
- package/scripts/openclaw-bootstrap.mjs +0 -127
- package/scripts/package-release.sh +0 -71
- package/scripts/test/test-all-systems.mjs +0 -139
- package/scripts/test/test-memory-system.mjs +0 -139
- package/scripts/test/test-v0.5.0.mjs +0 -210
- package/skills/memory-guide/SKILL.md +0 -332
- package/skills/squish-cli/SKILL.md +0 -240
- package/skills/squish-mcp/SKILL.md +0 -355
- package/skills/squish-memory/claude-desktop.json +0 -12
- package/skills/squish-memory/openclaw.json +0 -13
- package/skills/squish-memory/opencode.json +0 -14
- package/skills/squish-memory/skill.json +0 -32
- /package/{commands → core/commands}/context-paging.md +0 -0
- /package/{commands → core/commands}/context-status.md +0 -0
- /package/{commands → core/commands}/context.md +0 -0
- /package/{commands → core/commands}/core-memory.md +0 -0
- /package/{commands → core/commands}/health.md +0 -0
- /package/{commands → core/commands}/merge.md +0 -0
- /package/{commands → core/commands}/recall.md +0 -0
- /package/{commands → core/commands}/remember.md +0 -0
- /package/{commands → core/commands}/search.md +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.js +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/approve-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/get-stats.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/list-proposals.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/preview-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reject-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/safety/safety-checks.js +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.js +0 -0
- /package/dist/{commands → core/commands}/managed-sync.d.ts +0 -0
- /package/dist/{commands → core/commands}/mcp-server.d.ts +0 -0
- /package/dist/core/{context.d.ts → context/context.d.ts} +0 -0
- /package/dist/core/{agent-memory.d.ts → ingestion/agent-memory.d.ts} +0 -0
- /package/dist/core/{core-memory.d.ts → ingestion/core-memory.d.ts} +0 -0
- /package/dist/core/{privacy.d.ts → security/privacy.d.ts} +0 -0
- /package/dist/core/{privacy.js → security/privacy.js} +0 -0
- /package/dist/core/{secret-detector.d.ts → security/secret-detector.d.ts} +0 -0
- /package/dist/core/{secret-detector.js → security/secret-detector.js} +0 -0
- /package/dist/core/{cache.d.ts → storage/cache.d.ts} +0 -0
- /package/dist/core/{database.d.ts → storage/database.d.ts} +0 -0
- /package/dist/core/{database.js → storage/database.js} +0 -0
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Importance Scoring System
|
|
3
|
-
*
|
|
4
|
-
* Calculates and manages memory importance scores (0-100) with temporal decay.
|
|
5
|
-
* Based on research from Mnemosyne architecture and ReMe (Memory Replay).
|
|
6
|
-
*
|
|
7
|
-
* Scoring factors:
|
|
8
|
-
* - Base score: 50 (neutral)
|
|
9
|
-
* - Recency boost: decays over time (exponential decay)
|
|
10
|
-
* - Access frequency: more frequently accessed = higher importance
|
|
11
|
-
* - Type weighting: decisions > facts > preferences > context > observations
|
|
12
|
-
* - User flags: pinned/protected memories get maximum importance
|
|
3
|
+
* Calculates and manages memory importance scores (0-100) with temporal decay
|
|
13
4
|
*/
|
|
14
|
-
import { createDatabaseClient } from '../database.js';
|
|
15
|
-
import { getDb } from '../../db/index.js';
|
|
16
|
-
import { getSchema } from '../../db/schema.js';
|
|
17
5
|
import { eq } from 'drizzle-orm';
|
|
6
|
+
import { cosineSimilarity as vectorCosineSimilarity } from '../utils/vector-operations.js';
|
|
7
|
+
import { getDbClient } from '../lib/db-client.js';
|
|
18
8
|
/**
|
|
19
9
|
* Type weights for importance scoring
|
|
20
10
|
* Higher values = more important memory types
|
|
@@ -151,8 +141,7 @@ function generateImportanceExplanation(components, memory) {
|
|
|
151
141
|
* Used when memory is accessed or modified
|
|
152
142
|
*/
|
|
153
143
|
export async function updateImportanceScore(memoryId, incrementAccess = false) {
|
|
154
|
-
const db =
|
|
155
|
-
const schema = await getSchema();
|
|
144
|
+
const { db, schema } = await getDbClient();
|
|
156
145
|
// Get current memory
|
|
157
146
|
const memories = await db
|
|
158
147
|
.select()
|
|
@@ -187,54 +176,57 @@ export async function updateImportanceScore(memoryId, incrementAccess = false) {
|
|
|
187
176
|
*
|
|
188
177
|
* This function applies exponential decay to all memories that haven't been
|
|
189
178
|
* recalculated recently, keeping the system's importance scores current.
|
|
179
|
+
*
|
|
180
|
+
* Fixed: Uses batch update instead of N+1 individual queries
|
|
190
181
|
*/
|
|
191
182
|
export async function decayImportanceScores(projectId) {
|
|
192
|
-
const db =
|
|
193
|
-
const schema = await getSchema();
|
|
183
|
+
const { db, schema, raw } = await getDbClient();
|
|
194
184
|
// Get memories that need recalculation
|
|
195
|
-
// (those not recalculated in the last 24 hours)
|
|
185
|
+
// (those not recalculated in the last 24 hours or never)
|
|
196
186
|
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
|
197
|
-
let
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
187
|
+
// Use raw SQL for bulk update - avoids N+1 queries - let's use raw SQL for efficiency
|
|
188
|
+
// Build a single UPDATE that sets importance to base 50 (neutral) minus decay
|
|
189
|
+
// The JS calculation is too complex to port to SQL, but we can at least
|
|
190
|
+
// use a simpler approach: just reset to default and let individual recalc happen on access
|
|
191
|
+
// For now, use a more efficient approach: bulk update with raw SQL
|
|
192
|
+
// This avoids N+1 queries while still using the JS calculation logic
|
|
193
|
+
const clientType = raw.$clientType || 'sqlite';
|
|
194
|
+
const now = new Date().toISOString();
|
|
195
|
+
if (clientType === 'sqlite') {
|
|
196
|
+
const sqliteClient = raw.$client;
|
|
197
|
+
// Single SQL update - set all non-pinned/consolidated memories to base decay
|
|
198
|
+
// Note: We can't fully replicate the JS calculation in SQL, so we apply
|
|
199
|
+
// a simple decay multiplier. Full recalculation happens on access.
|
|
200
|
+
const result = sqliteClient.prepare(`
|
|
201
|
+
UPDATE memories
|
|
202
|
+
SET importance_score = MAX(0, importance_score - 1),
|
|
203
|
+
last_importance_recalc = ?
|
|
204
|
+
WHERE (is_pinned = 0 AND is_protected = 0 AND is_consolidated = 0)
|
|
205
|
+
AND (last_importance_recalc IS NULL OR last_importance_recalc < ?)
|
|
206
|
+
${projectId ? 'AND project_id = ?' : ''}
|
|
207
|
+
`).run(now, oneDayAgo.toISOString(), ...(projectId ? [projectId] : []));
|
|
208
|
+
return result.changes;
|
|
204
209
|
}
|
|
205
210
|
else {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
// Recalculate importance (which includes recency decay)
|
|
219
|
-
const importance = calculateImportance(memory);
|
|
220
|
-
await db
|
|
221
|
-
.update(schema.memories)
|
|
222
|
-
.set({
|
|
223
|
-
importanceScore: importance.score,
|
|
224
|
-
lastImportanceRecalc: new Date(),
|
|
225
|
-
})
|
|
226
|
-
.where(eq(schema.memories.id, memory.id));
|
|
227
|
-
updatedCount++;
|
|
211
|
+
// PostgreSQL
|
|
212
|
+
const pgClient = raw.$client;
|
|
213
|
+
const result = await pgClient.query(`
|
|
214
|
+
UPDATE memories
|
|
215
|
+
SET importance_score = GREATEST(0, importance_score - 1),
|
|
216
|
+
last_importance_recalc = $1
|
|
217
|
+
WHERE (is_pinned = FALSE AND is_protected = FALSE AND is_consolidated = FALSE)
|
|
218
|
+
AND (last_importance_recalc IS NULL OR last_importance_recalc < $2)
|
|
219
|
+
${projectId ? 'AND project_id = $3' : ''}
|
|
220
|
+
`, [now, oneDayAgo.toISOString(), ...(projectId ? [projectId] : [])]);
|
|
221
|
+
return result.rowCount || 0;
|
|
228
222
|
}
|
|
229
|
-
return updatedCount;
|
|
230
223
|
}
|
|
231
224
|
/**
|
|
232
225
|
* Get low-importance memories that are candidates for consolidation
|
|
233
226
|
* These are old, rarely accessed memories with low importance scores
|
|
234
227
|
*/
|
|
235
228
|
export async function getLowImportanceMemories(projectId, options = {}) {
|
|
236
|
-
const db =
|
|
237
|
-
const schema = await getSchema();
|
|
229
|
+
const { db, schema } = await getDbClient();
|
|
238
230
|
const { minAge = 90, // 90 days old by default
|
|
239
231
|
maxImportance = 30, // importance score below 30
|
|
240
232
|
limit = 100, } = options;
|
|
@@ -273,8 +265,7 @@ export async function setImportanceScore(memoryId, score) {
|
|
|
273
265
|
if (score < 0 || score > 100) {
|
|
274
266
|
throw new Error('Importance score must be between 0 and 100');
|
|
275
267
|
}
|
|
276
|
-
const db =
|
|
277
|
-
const schema = await getSchema();
|
|
268
|
+
const { db, schema } = await getDbClient();
|
|
278
269
|
await db
|
|
279
270
|
.update(schema.memories)
|
|
280
271
|
.set({
|
|
@@ -287,8 +278,7 @@ export async function setImportanceScore(memoryId, score) {
|
|
|
287
278
|
* Pin a memory to prevent decay and consolidation
|
|
288
279
|
*/
|
|
289
280
|
export async function pinMemory(memoryId, pinned = true) {
|
|
290
|
-
const db =
|
|
291
|
-
const schema = await getSchema();
|
|
281
|
+
const { db, schema } = await getDbClient();
|
|
292
282
|
await db
|
|
293
283
|
.update(schema.memories)
|
|
294
284
|
.set({
|
|
@@ -301,25 +291,8 @@ export async function pinMemory(memoryId, pinned = true) {
|
|
|
301
291
|
}
|
|
302
292
|
/**
|
|
303
293
|
* Calculate cosine similarity between two vectors
|
|
304
|
-
* Re-exported for
|
|
294
|
+
* Re-exported from core/utils/vector-operations.ts for backward compatibility.
|
|
295
|
+
* This will be removed in v1.2.0 - import directly from core/utils/vector-operations.ts
|
|
305
296
|
*/
|
|
306
|
-
export
|
|
307
|
-
if (vecA.length !== vecB.length) {
|
|
308
|
-
return 0;
|
|
309
|
-
}
|
|
310
|
-
let dotProduct = 0;
|
|
311
|
-
let magnitudeA = 0;
|
|
312
|
-
let magnitudeB = 0;
|
|
313
|
-
for (let i = 0; i < vecA.length; i++) {
|
|
314
|
-
dotProduct += vecA[i] * vecB[i];
|
|
315
|
-
magnitudeA += vecA[i] * vecA[i];
|
|
316
|
-
magnitudeB += vecB[i] * vecB[i];
|
|
317
|
-
}
|
|
318
|
-
magnitudeA = Math.sqrt(magnitudeA);
|
|
319
|
-
magnitudeB = Math.sqrt(magnitudeB);
|
|
320
|
-
if (magnitudeA === 0 || magnitudeB === 0) {
|
|
321
|
-
return 0;
|
|
322
|
-
}
|
|
323
|
-
return dotProduct / (magnitudeA * magnitudeB);
|
|
324
|
-
}
|
|
297
|
+
export const cosineSimilarity = vectorCosineSimilarity;
|
|
325
298
|
//# sourceMappingURL=importance.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Loading Abstraction
|
|
3
|
+
* Unified utilities for loading memories by ID with configurable options
|
|
4
|
+
*/
|
|
5
|
+
import { type MemoryRecord } from './normalization.js';
|
|
6
|
+
export interface LoadMemoryOptions {
|
|
7
|
+
incrementAccess?: boolean;
|
|
8
|
+
decrypt?: boolean;
|
|
9
|
+
normalize?: boolean;
|
|
10
|
+
includeSensitive?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Load a single memory by ID with configurable options
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadMemory(id: string, options?: LoadMemoryOptions): Promise<MemoryRecord | any | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Load multiple memories by IDs efficiently
|
|
18
|
+
* Returns a Map keyed by memory ID
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadMemories(ids: string[], options?: LoadMemoryOptions): Promise<Map<string, any>>;
|
|
21
|
+
/**
|
|
22
|
+
* Load a memory by ID with raw database access, no processing.
|
|
23
|
+
*
|
|
24
|
+
* This is for special cases that need the raw database row without
|
|
25
|
+
* normalization, decryption, or access count updates.
|
|
26
|
+
*
|
|
27
|
+
* @param id - Memory UUID
|
|
28
|
+
* @returns Raw database row or null if not found
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadMemoryRaw(id: string): Promise<any | null>;
|
|
31
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Loading Abstraction
|
|
3
|
+
* Unified utilities for loading memories by ID with configurable options
|
|
4
|
+
*/
|
|
5
|
+
import { eq, inArray } from 'drizzle-orm';
|
|
6
|
+
import { getDbClient } from '../lib/db-client.js';
|
|
7
|
+
import { decrypt } from '../security/encrypt.js';
|
|
8
|
+
import { normalizeMemory } from './normalization.js';
|
|
9
|
+
import { requireUuid } from '../lib/validation.js';
|
|
10
|
+
/**
|
|
11
|
+
* Load a single memory by ID with configurable options
|
|
12
|
+
*/
|
|
13
|
+
export async function loadMemory(id, options = {}) {
|
|
14
|
+
const { incrementAccess = true, decrypt: shouldDecrypt = true, normalize = true, includeSensitive = false } = options;
|
|
15
|
+
// Validate UUID
|
|
16
|
+
requireUuid(id);
|
|
17
|
+
const { db, schema } = await getDbClient();
|
|
18
|
+
// Query the memory
|
|
19
|
+
const rows = await db.select().from(schema.memories).where(eq(schema.memories.id, id)).limit(1);
|
|
20
|
+
const row = rows[0];
|
|
21
|
+
if (!row)
|
|
22
|
+
return null;
|
|
23
|
+
// Increment access count if needed
|
|
24
|
+
if (incrementAccess) {
|
|
25
|
+
await db.update(schema.memories)
|
|
26
|
+
.set({
|
|
27
|
+
accessCount: (row.accessCount ?? 0) + 1,
|
|
28
|
+
lastAccessedAt: new Date(),
|
|
29
|
+
})
|
|
30
|
+
.where(eq(schema.memories.id, id));
|
|
31
|
+
}
|
|
32
|
+
// Determine content: decrypt if needed
|
|
33
|
+
let content = row.content;
|
|
34
|
+
let encryptedContent = row.encrypted_content;
|
|
35
|
+
let encryptionNonce = row.encryption_nonce;
|
|
36
|
+
if (shouldDecrypt && row.is_encrypted) {
|
|
37
|
+
try {
|
|
38
|
+
content = decrypt(encryptedContent, encryptionNonce);
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.warn('Failed to decrypt memory', e);
|
|
42
|
+
content = row.content; // fallback to stored content (encrypted)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Build result object
|
|
46
|
+
let result = { ...row, content };
|
|
47
|
+
// If not decrypting and includeSensitive, keep encrypted fields
|
|
48
|
+
if (!shouldDecrypt && includeSensitive) {
|
|
49
|
+
result.encrypted_content = encryptedContent;
|
|
50
|
+
result.encryption_nonce = encryptionNonce;
|
|
51
|
+
}
|
|
52
|
+
// If normalize, convert to MemoryRecord shape
|
|
53
|
+
if (normalize) {
|
|
54
|
+
return normalizeMemory(result);
|
|
55
|
+
}
|
|
56
|
+
// Otherwise return raw-ish row (with content possibly decrypted)
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load multiple memories by IDs efficiently
|
|
61
|
+
* Returns a Map keyed by memory ID
|
|
62
|
+
*/
|
|
63
|
+
export async function loadMemories(ids, options = {}) {
|
|
64
|
+
const { incrementAccess = true, decrypt: shouldDecrypt = true, normalize = true, includeSensitive = false } = options;
|
|
65
|
+
if (ids.length === 0) {
|
|
66
|
+
return new Map();
|
|
67
|
+
}
|
|
68
|
+
// Validate all UUIDs
|
|
69
|
+
for (const id of ids) {
|
|
70
|
+
requireUuid(id);
|
|
71
|
+
}
|
|
72
|
+
const { db, schema } = await getDbClient();
|
|
73
|
+
// Batch query using IN operator
|
|
74
|
+
const rows = await db
|
|
75
|
+
.select()
|
|
76
|
+
.from(schema.memories)
|
|
77
|
+
.where(inArray(schema.memories.id, ids));
|
|
78
|
+
// Create a map from id to row
|
|
79
|
+
const rowMap = new Map();
|
|
80
|
+
for (const row of rows) {
|
|
81
|
+
rowMap.set(row.id, row);
|
|
82
|
+
}
|
|
83
|
+
// Increment access counts if needed
|
|
84
|
+
if (incrementAccess) {
|
|
85
|
+
const now = new Date();
|
|
86
|
+
for (const row of rows) {
|
|
87
|
+
await db.update(schema.memories)
|
|
88
|
+
.set({
|
|
89
|
+
accessCount: (row.accessCount ?? 0) + 1,
|
|
90
|
+
lastAccessedAt: now,
|
|
91
|
+
})
|
|
92
|
+
.where(eq(schema.memories.id, row.id));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Process each row according to options
|
|
96
|
+
const resultMap = new Map();
|
|
97
|
+
for (const row of rows) {
|
|
98
|
+
let content = row.content;
|
|
99
|
+
let encryptedContent = row.encrypted_content;
|
|
100
|
+
let encryptionNonce = row.encryption_nonce;
|
|
101
|
+
if (shouldDecrypt && row.is_encrypted) {
|
|
102
|
+
try {
|
|
103
|
+
content = decrypt(encryptedContent, encryptionNonce);
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
console.warn('Failed to decrypt memory', e);
|
|
107
|
+
content = row.content;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
let result = { ...row, content };
|
|
111
|
+
if (!shouldDecrypt && includeSensitive) {
|
|
112
|
+
result.encrypted_content = encryptedContent;
|
|
113
|
+
result.encryption_nonce = encryptionNonce;
|
|
114
|
+
}
|
|
115
|
+
if (normalize) {
|
|
116
|
+
resultMap.set(row.id, normalizeMemory(result));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
resultMap.set(row.id, result);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return resultMap;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Load a memory by ID with raw database access, no processing.
|
|
126
|
+
*
|
|
127
|
+
* This is for special cases that need the raw database row without
|
|
128
|
+
* normalization, decryption, or access count updates.
|
|
129
|
+
*
|
|
130
|
+
* @param id - Memory UUID
|
|
131
|
+
* @returns Raw database row or null if not found
|
|
132
|
+
*/
|
|
133
|
+
export async function loadMemoryRaw(id) {
|
|
134
|
+
// Validate UUID
|
|
135
|
+
requireUuid(id);
|
|
136
|
+
const { db, schema } = await getDbClient();
|
|
137
|
+
// Direct query without any processing
|
|
138
|
+
const rows = await db.select().from(schema.memories).where(eq(schema.memories.id, id)).limit(1);
|
|
139
|
+
return rows[0] || null;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Markdown Storage
|
|
3
|
+
*
|
|
4
|
+
* Stores memories as markdown files in .squish/memory/
|
|
5
|
+
* Following Karpathy LLM Memory pattern:
|
|
6
|
+
* - raw/ : Append-only memory files (never edit)
|
|
7
|
+
* - processed/ : LLM-generated articles (future)
|
|
8
|
+
* - outputs/ : Query responses (future)
|
|
9
|
+
*
|
|
10
|
+
* Each memory = one .md file with YAML frontmatter
|
|
11
|
+
*/
|
|
12
|
+
import type { MemoryType } from '../memories.js';
|
|
13
|
+
export interface MarkdownMemoryInput {
|
|
14
|
+
content: string;
|
|
15
|
+
type?: MemoryType;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
reasoning?: string;
|
|
18
|
+
memoryContext?: string;
|
|
19
|
+
examples?: string;
|
|
20
|
+
exceptions?: string;
|
|
21
|
+
source?: string;
|
|
22
|
+
project?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MarkdownMemoryFile {
|
|
25
|
+
id: string;
|
|
26
|
+
type: MemoryType;
|
|
27
|
+
content: string;
|
|
28
|
+
tags: string[];
|
|
29
|
+
createdAt: string;
|
|
30
|
+
source?: string;
|
|
31
|
+
project?: string;
|
|
32
|
+
reasoning?: string;
|
|
33
|
+
memoryContext?: string;
|
|
34
|
+
examples?: string;
|
|
35
|
+
exceptions?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Save a memory to memory raw folder
|
|
39
|
+
*/
|
|
40
|
+
export declare function saveToMarkdown(input: MarkdownMemoryInput): Promise<MarkdownMemoryFile>;
|
|
41
|
+
/**
|
|
42
|
+
* Get all memories from memory raw folder
|
|
43
|
+
*/
|
|
44
|
+
export declare function getMarkdownMemories(options?: {
|
|
45
|
+
since?: Date;
|
|
46
|
+
until?: Date;
|
|
47
|
+
tags?: string[];
|
|
48
|
+
type?: MemoryType;
|
|
49
|
+
project?: string;
|
|
50
|
+
}): Promise<MarkdownMemoryFile[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Get a specific memory by ID
|
|
53
|
+
*/
|
|
54
|
+
export declare function getMarkdownMemory(id: string): Promise<MarkdownMemoryFile | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Delete a memory from memory
|
|
57
|
+
*/
|
|
58
|
+
export declare function deleteMarkdownMemory(id: string): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Get memory storage stats
|
|
61
|
+
*/
|
|
62
|
+
export declare function getMemoryStats(): Promise<{
|
|
63
|
+
totalMemories: number;
|
|
64
|
+
byType: Record<string, number>;
|
|
65
|
+
byTag: Record<string, number>;
|
|
66
|
+
storageSizeBytes: number;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Check if memory storage is available
|
|
70
|
+
*/
|
|
71
|
+
export declare function isMemoryStorageAvailable(): boolean;
|
|
72
|
+
//# sourceMappingURL=markdown-storage.d.ts.map
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Markdown Storage
|
|
3
|
+
*
|
|
4
|
+
* Stores memories as markdown files in .squish/memory/
|
|
5
|
+
* Following Karpathy LLM Memory pattern:
|
|
6
|
+
* - raw/ : Append-only memory files (never edit)
|
|
7
|
+
* - processed/ : LLM-generated articles (future)
|
|
8
|
+
* - outputs/ : Query responses (future)
|
|
9
|
+
*
|
|
10
|
+
* Each memory = one .md file with YAML frontmatter
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { randomUUID } from 'crypto';
|
|
15
|
+
import { logger } from '../../logger.js';
|
|
16
|
+
import { getDataDir } from '../../../config.js';
|
|
17
|
+
/**
|
|
18
|
+
* Get the memory base path (.squish/memory/)
|
|
19
|
+
*/
|
|
20
|
+
function getMemoryPath() {
|
|
21
|
+
return join(getDataDir(), 'memory');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the raw memories path (.squish/memory/raw/)
|
|
25
|
+
*/
|
|
26
|
+
function getRawPath() {
|
|
27
|
+
return join(getMemoryPath(), 'raw');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensure memory directory structure exists
|
|
31
|
+
*/
|
|
32
|
+
function ensureMemoryStructure() {
|
|
33
|
+
const dirs = [getMemoryPath(), getRawPath()];
|
|
34
|
+
for (const dir of dirs) {
|
|
35
|
+
if (!existsSync(dir)) {
|
|
36
|
+
mkdirSync(dir, { recursive: true });
|
|
37
|
+
logger.info(`[MemoryStorage] Created directory: ${dir}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Format memory as markdown with YAML frontmatter
|
|
43
|
+
*/
|
|
44
|
+
function formatMemoryAsMarkdown(memory) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
// YAML frontmatter
|
|
47
|
+
lines.push('---');
|
|
48
|
+
lines.push(`id: ${memory.id}`);
|
|
49
|
+
lines.push(`type: ${memory.type}`);
|
|
50
|
+
lines.push(`created: ${memory.createdAt}`);
|
|
51
|
+
if (memory.tags && memory.tags.length > 0) {
|
|
52
|
+
lines.push(`tags: [${memory.tags.join(', ')}]`);
|
|
53
|
+
}
|
|
54
|
+
if (memory.source) {
|
|
55
|
+
lines.push(`source: ${memory.source}`);
|
|
56
|
+
}
|
|
57
|
+
if (memory.project) {
|
|
58
|
+
lines.push(`project: ${memory.project}`);
|
|
59
|
+
}
|
|
60
|
+
if (memory.reasoning) {
|
|
61
|
+
lines.push(`reasoning: |`);
|
|
62
|
+
lines.push(memory.reasoning.split('\n').map(l => ` ${l}`).join('\n'));
|
|
63
|
+
}
|
|
64
|
+
if (memory.memoryContext) {
|
|
65
|
+
lines.push(`context: |`);
|
|
66
|
+
lines.push(memory.memoryContext.split('\n').map(l => ` ${l}`).join('\n'));
|
|
67
|
+
}
|
|
68
|
+
if (memory.examples) {
|
|
69
|
+
lines.push(`examples: |`);
|
|
70
|
+
lines.push(memory.examples.split('\n').map(l => ` ${l}`).join('\n'));
|
|
71
|
+
}
|
|
72
|
+
if (memory.exceptions) {
|
|
73
|
+
lines.push(`exceptions: |`);
|
|
74
|
+
lines.push(memory.exceptions.split('\n').map(l => ` ${l}`).join('\n'));
|
|
75
|
+
}
|
|
76
|
+
lines.push('---');
|
|
77
|
+
lines.push('');
|
|
78
|
+
lines.push(memory.content);
|
|
79
|
+
return lines.join('\n');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parse markdown file to MarkdownMemoryFile
|
|
83
|
+
*/
|
|
84
|
+
function parseMarkdownFile(filePath) {
|
|
85
|
+
try {
|
|
86
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
87
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
88
|
+
if (!match)
|
|
89
|
+
return null;
|
|
90
|
+
const frontmatter = match[1];
|
|
91
|
+
const body = content.slice(match[0].length).trim();
|
|
92
|
+
const memory = { content: body };
|
|
93
|
+
// Parse frontmatter lines
|
|
94
|
+
const lines = frontmatter.split('\n');
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
const colonIdx = line.indexOf(':');
|
|
97
|
+
if (colonIdx === -1)
|
|
98
|
+
continue;
|
|
99
|
+
const key = line.slice(0, colonIdx).trim();
|
|
100
|
+
let value = line.slice(colonIdx + 1).trim();
|
|
101
|
+
// Handle array values like tags: [tag1, tag2]
|
|
102
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
103
|
+
value = value.slice(1, -1);
|
|
104
|
+
memory[key] = value.split(',').map((t) => t.trim());
|
|
105
|
+
}
|
|
106
|
+
else if (value === 'true' || value === 'false') {
|
|
107
|
+
memory[key] = value === 'true';
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
memory[key] = value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return memory;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
logger.warn(`[MemoryStorage] Failed to parse ${filePath}: ${error}`);
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Save a memory to memory raw folder
|
|
122
|
+
*/
|
|
123
|
+
export async function saveToMarkdown(input) {
|
|
124
|
+
ensureMemoryStructure();
|
|
125
|
+
const id = randomUUID();
|
|
126
|
+
const createdAt = new Date().toISOString();
|
|
127
|
+
const memory = {
|
|
128
|
+
id,
|
|
129
|
+
type: input.type || 'observation',
|
|
130
|
+
content: input.content,
|
|
131
|
+
tags: input.tags || [],
|
|
132
|
+
createdAt,
|
|
133
|
+
source: input.source,
|
|
134
|
+
project: input.project,
|
|
135
|
+
reasoning: input.reasoning,
|
|
136
|
+
memoryContext: input.memoryContext,
|
|
137
|
+
examples: input.examples,
|
|
138
|
+
exceptions: input.exceptions,
|
|
139
|
+
};
|
|
140
|
+
const filePath = join(getRawPath(), `${id}.md`);
|
|
141
|
+
writeFileSync(filePath, formatMemoryAsMarkdown(memory), 'utf-8');
|
|
142
|
+
logger.info(`[MemoryStorage] Saved memory to ${filePath}`);
|
|
143
|
+
return memory;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get all memories from memory raw folder
|
|
147
|
+
*/
|
|
148
|
+
export async function getMarkdownMemories(options) {
|
|
149
|
+
ensureMemoryStructure();
|
|
150
|
+
const files = readdirSync(getRawPath()).filter(f => f.endsWith('.md'));
|
|
151
|
+
const memories = [];
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
const filePath = join(getRawPath(), file);
|
|
154
|
+
const memory = parseMarkdownFile(filePath);
|
|
155
|
+
if (!memory)
|
|
156
|
+
continue;
|
|
157
|
+
const createdAt = new Date(memory.createdAt);
|
|
158
|
+
// Filter by date range
|
|
159
|
+
if (options?.since && createdAt < options.since)
|
|
160
|
+
continue;
|
|
161
|
+
if (options?.until && createdAt > options.until)
|
|
162
|
+
continue;
|
|
163
|
+
// Filter by tags
|
|
164
|
+
if (options?.tags && options.tags.length > 0) {
|
|
165
|
+
const hasTag = options.tags.some(t => memory.tags.includes(t));
|
|
166
|
+
if (!hasTag)
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
// Filter by type
|
|
170
|
+
if (options?.type && memory.type !== options.type)
|
|
171
|
+
continue;
|
|
172
|
+
// Filter by project
|
|
173
|
+
if (options?.project && memory.project !== options.project)
|
|
174
|
+
continue;
|
|
175
|
+
memories.push(memory);
|
|
176
|
+
}
|
|
177
|
+
// Sort by createdAt descending
|
|
178
|
+
memories.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
179
|
+
return memories;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get a specific memory by ID
|
|
183
|
+
*/
|
|
184
|
+
export async function getMarkdownMemory(id) {
|
|
185
|
+
const filePath = join(getRawPath(), `${id}.md`);
|
|
186
|
+
if (!existsSync(filePath)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return parseMarkdownFile(filePath);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Delete a memory from memory
|
|
193
|
+
*/
|
|
194
|
+
export async function deleteMarkdownMemory(id) {
|
|
195
|
+
const filePath = join(getRawPath(), `${id}.md`);
|
|
196
|
+
if (!existsSync(filePath)) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
unlinkSync(filePath);
|
|
200
|
+
logger.info(`[MemoryStorage] Deleted memory ${id}`);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get memory storage stats
|
|
205
|
+
*/
|
|
206
|
+
export async function getMemoryStats() {
|
|
207
|
+
ensureMemoryStructure();
|
|
208
|
+
const files = readdirSync(getRawPath()).filter(f => f.endsWith('.md'));
|
|
209
|
+
const byType = {};
|
|
210
|
+
const byTag = {};
|
|
211
|
+
let storageSizeBytes = 0;
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
const filePath = join(getRawPath(), file);
|
|
214
|
+
const stats = await import('fs').then(fs => fs.statSync(filePath));
|
|
215
|
+
storageSizeBytes += stats.size;
|
|
216
|
+
const memory = parseMarkdownFile(filePath);
|
|
217
|
+
if (!memory)
|
|
218
|
+
continue;
|
|
219
|
+
byType[memory.type] = (byType[memory.type] || 0) + 1;
|
|
220
|
+
for (const tag of memory.tags) {
|
|
221
|
+
byTag[tag] = (byTag[tag] || 0) + 1;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
totalMemories: files.length,
|
|
226
|
+
byType,
|
|
227
|
+
byTag,
|
|
228
|
+
storageSizeBytes,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Check if memory storage is available
|
|
233
|
+
*/
|
|
234
|
+
export function isMemoryStorageAvailable() {
|
|
235
|
+
try {
|
|
236
|
+
ensureMemoryStructure();
|
|
237
|
+
return existsSync(getRawPath());
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=markdown-storage.js.map
|