claude-brain 0.14.2 → 0.14.4
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 +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
package/src/memory/database.ts
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database Connection Manager
|
|
3
|
-
* Phase 3: Memory and Embedding System
|
|
4
|
-
*
|
|
5
|
-
* Manages SQLite database connection for memory storage
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { Database } from 'bun:sqlite'
|
|
9
|
-
import path from 'node:path'
|
|
10
|
-
import fs from 'node:fs/promises'
|
|
11
|
-
import type { Logger } from 'pino'
|
|
12
|
-
import { MEMORY_SCHEMA } from './schema'
|
|
13
|
-
import type { DatabaseStats } from './types'
|
|
14
|
-
|
|
15
|
-
export class MemoryDatabase {
|
|
16
|
-
private db: Database | null = null
|
|
17
|
-
private logger: Logger
|
|
18
|
-
private dbPath: string
|
|
19
|
-
|
|
20
|
-
constructor(dbPath: string, logger: Logger) {
|
|
21
|
-
this.dbPath = dbPath
|
|
22
|
-
this.logger = logger.child({ component: 'memory-database' })
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Initialize database and create schema
|
|
27
|
-
*/
|
|
28
|
-
async initialize(): Promise<void> {
|
|
29
|
-
try {
|
|
30
|
-
// Ensure directory exists
|
|
31
|
-
await fs.mkdir(path.dirname(this.dbPath), { recursive: true })
|
|
32
|
-
|
|
33
|
-
// Open database
|
|
34
|
-
this.db = new Database(this.dbPath)
|
|
35
|
-
|
|
36
|
-
// Enable Write-Ahead Logging for better concurrency
|
|
37
|
-
this.db.run('PRAGMA journal_mode = WAL')
|
|
38
|
-
|
|
39
|
-
// Enable foreign keys
|
|
40
|
-
this.db.run('PRAGMA foreign_keys = ON')
|
|
41
|
-
|
|
42
|
-
// Create schema
|
|
43
|
-
this.db.exec(MEMORY_SCHEMA)
|
|
44
|
-
|
|
45
|
-
this.logger.info({ dbPath: this.dbPath }, 'Database initialized')
|
|
46
|
-
} catch (error) {
|
|
47
|
-
this.logger.error({ error, dbPath: this.dbPath }, 'Failed to initialize database')
|
|
48
|
-
throw error
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get the SQLite database instance
|
|
54
|
-
*/
|
|
55
|
-
getDb(): Database {
|
|
56
|
-
if (!this.db) {
|
|
57
|
-
throw new Error('Database not initialized. Call initialize() first.')
|
|
58
|
-
}
|
|
59
|
-
return this.db
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Close database connection
|
|
64
|
-
*/
|
|
65
|
-
close(): void {
|
|
66
|
-
if (this.db) {
|
|
67
|
-
this.db.close()
|
|
68
|
-
this.db = null
|
|
69
|
-
this.logger.info('Database closed')
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get database statistics
|
|
75
|
-
*/
|
|
76
|
-
getStats(): DatabaseStats {
|
|
77
|
-
if (!this.db) {
|
|
78
|
-
throw new Error('Database not initialized')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const memoriesCount = this.db.query('SELECT COUNT(*) as count FROM memories').get() as {
|
|
82
|
-
count: number
|
|
83
|
-
}
|
|
84
|
-
const decisionsCount = this.db.query('SELECT COUNT(*) as count FROM decisions').get() as {
|
|
85
|
-
count: number
|
|
86
|
-
}
|
|
87
|
-
const dbSize = this.db
|
|
88
|
-
.query(
|
|
89
|
-
'SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()'
|
|
90
|
-
)
|
|
91
|
-
.get() as { size: number }
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
memories: memoriesCount.count,
|
|
95
|
-
decisions: decisionsCount.count,
|
|
96
|
-
sizeBytes: dbSize.size,
|
|
97
|
-
sizeMB: (dbSize.size / 1024 / 1024).toFixed(2)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Run database health check
|
|
103
|
-
*/
|
|
104
|
-
async healthCheck(): Promise<boolean> {
|
|
105
|
-
try {
|
|
106
|
-
if (!this.db) {
|
|
107
|
-
return false
|
|
108
|
-
}
|
|
109
|
-
this.db.query('SELECT 1').get()
|
|
110
|
-
return true
|
|
111
|
-
} catch (error) {
|
|
112
|
-
this.logger.error({ error }, 'Database health check failed')
|
|
113
|
-
return false
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Vacuum database to reclaim space
|
|
119
|
-
*/
|
|
120
|
-
async vacuum(): Promise<void> {
|
|
121
|
-
try {
|
|
122
|
-
if (!this.db) {
|
|
123
|
-
throw new Error('Database not initialized')
|
|
124
|
-
}
|
|
125
|
-
this.db.run('VACUUM')
|
|
126
|
-
this.logger.info('Database vacuumed')
|
|
127
|
-
} catch (error) {
|
|
128
|
-
this.logger.error({ error }, 'Failed to vacuum database')
|
|
129
|
-
throw error
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Begin a transaction
|
|
135
|
-
*/
|
|
136
|
-
beginTransaction(): void {
|
|
137
|
-
if (!this.db) {
|
|
138
|
-
throw new Error('Database not initialized')
|
|
139
|
-
}
|
|
140
|
-
this.db.run('BEGIN TRANSACTION')
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Commit a transaction
|
|
145
|
-
*/
|
|
146
|
-
commit(): void {
|
|
147
|
-
if (!this.db) {
|
|
148
|
-
throw new Error('Database not initialized')
|
|
149
|
-
}
|
|
150
|
-
this.db.run('COMMIT')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Rollback a transaction
|
|
155
|
-
*/
|
|
156
|
-
rollback(): void {
|
|
157
|
-
if (!this.db) {
|
|
158
|
-
throw new Error('Database not initialized')
|
|
159
|
-
}
|
|
160
|
-
this.db.run('ROLLBACK')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Check if database is initialized
|
|
165
|
-
*/
|
|
166
|
-
isInitialized(): boolean {
|
|
167
|
-
return this.db !== null
|
|
168
|
-
}
|
|
169
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Database Connection Manager
|
|
3
|
+
* Phase 3: Memory and Embedding System
|
|
4
|
+
*
|
|
5
|
+
* Manages SQLite database connection for memory storage
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Database } from 'bun:sqlite'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import fs from 'node:fs/promises'
|
|
11
|
+
import type { Logger } from 'pino'
|
|
12
|
+
import { MEMORY_SCHEMA } from './schema'
|
|
13
|
+
import type { DatabaseStats } from './types'
|
|
14
|
+
|
|
15
|
+
export class MemoryDatabase {
|
|
16
|
+
private db: Database | null = null
|
|
17
|
+
private logger: Logger
|
|
18
|
+
private dbPath: string
|
|
19
|
+
|
|
20
|
+
constructor(dbPath: string, logger: Logger) {
|
|
21
|
+
this.dbPath = dbPath
|
|
22
|
+
this.logger = logger.child({ component: 'memory-database' })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize database and create schema
|
|
27
|
+
*/
|
|
28
|
+
async initialize(): Promise<void> {
|
|
29
|
+
try {
|
|
30
|
+
// Ensure directory exists
|
|
31
|
+
await fs.mkdir(path.dirname(this.dbPath), { recursive: true })
|
|
32
|
+
|
|
33
|
+
// Open database
|
|
34
|
+
this.db = new Database(this.dbPath)
|
|
35
|
+
|
|
36
|
+
// Enable Write-Ahead Logging for better concurrency
|
|
37
|
+
this.db.run('PRAGMA journal_mode = WAL')
|
|
38
|
+
|
|
39
|
+
// Enable foreign keys
|
|
40
|
+
this.db.run('PRAGMA foreign_keys = ON')
|
|
41
|
+
|
|
42
|
+
// Create schema
|
|
43
|
+
this.db.exec(MEMORY_SCHEMA)
|
|
44
|
+
|
|
45
|
+
this.logger.info({ dbPath: this.dbPath }, 'Database initialized')
|
|
46
|
+
} catch (error) {
|
|
47
|
+
this.logger.error({ error, dbPath: this.dbPath }, 'Failed to initialize database')
|
|
48
|
+
throw error
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the SQLite database instance
|
|
54
|
+
*/
|
|
55
|
+
getDb(): Database {
|
|
56
|
+
if (!this.db) {
|
|
57
|
+
throw new Error('Database not initialized. Call initialize() first.')
|
|
58
|
+
}
|
|
59
|
+
return this.db
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Close database connection
|
|
64
|
+
*/
|
|
65
|
+
close(): void {
|
|
66
|
+
if (this.db) {
|
|
67
|
+
this.db.close()
|
|
68
|
+
this.db = null
|
|
69
|
+
this.logger.info('Database closed')
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get database statistics
|
|
75
|
+
*/
|
|
76
|
+
getStats(): DatabaseStats {
|
|
77
|
+
if (!this.db) {
|
|
78
|
+
throw new Error('Database not initialized')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const memoriesCount = this.db.query('SELECT COUNT(*) as count FROM memories').get() as {
|
|
82
|
+
count: number
|
|
83
|
+
}
|
|
84
|
+
const decisionsCount = this.db.query('SELECT COUNT(*) as count FROM decisions').get() as {
|
|
85
|
+
count: number
|
|
86
|
+
}
|
|
87
|
+
const dbSize = this.db
|
|
88
|
+
.query(
|
|
89
|
+
'SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()'
|
|
90
|
+
)
|
|
91
|
+
.get() as { size: number }
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
memories: memoriesCount.count,
|
|
95
|
+
decisions: decisionsCount.count,
|
|
96
|
+
sizeBytes: dbSize.size,
|
|
97
|
+
sizeMB: (dbSize.size / 1024 / 1024).toFixed(2)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Run database health check
|
|
103
|
+
*/
|
|
104
|
+
async healthCheck(): Promise<boolean> {
|
|
105
|
+
try {
|
|
106
|
+
if (!this.db) {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
this.db.query('SELECT 1').get()
|
|
110
|
+
return true
|
|
111
|
+
} catch (error) {
|
|
112
|
+
this.logger.error({ error }, 'Database health check failed')
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Vacuum database to reclaim space
|
|
119
|
+
*/
|
|
120
|
+
async vacuum(): Promise<void> {
|
|
121
|
+
try {
|
|
122
|
+
if (!this.db) {
|
|
123
|
+
throw new Error('Database not initialized')
|
|
124
|
+
}
|
|
125
|
+
this.db.run('VACUUM')
|
|
126
|
+
this.logger.info('Database vacuumed')
|
|
127
|
+
} catch (error) {
|
|
128
|
+
this.logger.error({ error }, 'Failed to vacuum database')
|
|
129
|
+
throw error
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Begin a transaction
|
|
135
|
+
*/
|
|
136
|
+
beginTransaction(): void {
|
|
137
|
+
if (!this.db) {
|
|
138
|
+
throw new Error('Database not initialized')
|
|
139
|
+
}
|
|
140
|
+
this.db.run('BEGIN TRANSACTION')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Commit a transaction
|
|
145
|
+
*/
|
|
146
|
+
commit(): void {
|
|
147
|
+
if (!this.db) {
|
|
148
|
+
throw new Error('Database not initialized')
|
|
149
|
+
}
|
|
150
|
+
this.db.run('COMMIT')
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Rollback a transaction
|
|
155
|
+
*/
|
|
156
|
+
rollback(): void {
|
|
157
|
+
if (!this.db) {
|
|
158
|
+
throw new Error('Database not initialized')
|
|
159
|
+
}
|
|
160
|
+
this.db.run('ROLLBACK')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if database is initialized
|
|
165
|
+
*/
|
|
166
|
+
isInitialized(): boolean {
|
|
167
|
+
return this.db !== null
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedding Utility Functions
|
|
3
|
-
* Phase 3: Memory and Embedding System
|
|
4
|
-
*
|
|
5
|
-
* Helper functions for embedding conversion and manipulation
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Convert embedding array to Buffer for SQLite storage
|
|
10
|
-
* Stores as float32 array (4 bytes per number)
|
|
11
|
-
*/
|
|
12
|
-
export function embeddingToBuffer(embedding: number[]): Buffer {
|
|
13
|
-
const buffer = Buffer.allocUnsafe(embedding.length * 4) // 4 bytes per float32
|
|
14
|
-
for (let i = 0; i < embedding.length; i++) {
|
|
15
|
-
buffer.writeFloatLE(embedding[i]!, i * 4)
|
|
16
|
-
}
|
|
17
|
-
return buffer
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Convert Buffer or Uint8Array from SQLite to embedding array
|
|
22
|
-
* Reads float32 values from buffer
|
|
23
|
-
* Note: Bun's SQLite returns BLOBs as Uint8Array, not Buffer
|
|
24
|
-
*/
|
|
25
|
-
export function bufferToEmbedding(buffer: Buffer | Uint8Array): number[] {
|
|
26
|
-
// Convert Uint8Array to Buffer if needed (Bun SQLite returns Uint8Array for BLOBs)
|
|
27
|
-
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer)
|
|
28
|
-
|
|
29
|
-
const embedding: number[] = []
|
|
30
|
-
for (let i = 0; i < buf.length; i += 4) {
|
|
31
|
-
embedding.push(buf.readFloatLE(i))
|
|
32
|
-
}
|
|
33
|
-
return embedding
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Normalize embedding vector to unit length
|
|
38
|
-
* Required for accurate cosine similarity calculation
|
|
39
|
-
*/
|
|
40
|
-
export function normalizeEmbedding(embedding: number[]): number[] {
|
|
41
|
-
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0))
|
|
42
|
-
if (norm === 0) {
|
|
43
|
-
return embedding
|
|
44
|
-
}
|
|
45
|
-
return embedding.map((val) => val / norm)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Calculate euclidean distance between two embeddings
|
|
50
|
-
* Lower distance = more similar
|
|
51
|
-
*/
|
|
52
|
-
export function euclideanDistance(a: number[], b: number[]): number {
|
|
53
|
-
if (a.length !== b.length) {
|
|
54
|
-
throw new Error('Embeddings must have same dimensions')
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let sum = 0
|
|
58
|
-
for (let i = 0; i < a.length; i++) {
|
|
59
|
-
const diff = a[i]! - b[i]!
|
|
60
|
-
sum += diff * diff
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return Math.sqrt(sum)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Calculate dot product of two vectors
|
|
68
|
-
*/
|
|
69
|
-
export function dotProduct(a: number[], b: number[]): number {
|
|
70
|
-
if (a.length !== b.length) {
|
|
71
|
-
throw new Error('Vectors must have same dimensions')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let sum = 0
|
|
75
|
-
for (let i = 0; i < a.length; i++) {
|
|
76
|
-
sum += a[i]! * b[i]!
|
|
77
|
-
}
|
|
78
|
-
return sum
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Calculate magnitude (L2 norm) of a vector
|
|
83
|
-
*/
|
|
84
|
-
export function magnitude(v: number[]): number {
|
|
85
|
-
return Math.sqrt(v.reduce((sum, val) => sum + val * val, 0))
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Calculate cosine similarity between two embeddings
|
|
90
|
-
* Returns value between -1 and 1 (1 = identical, 0 = orthogonal, -1 = opposite)
|
|
91
|
-
*/
|
|
92
|
-
export function cosineSimilarity(a: number[], b: number[]): number {
|
|
93
|
-
if (a.length !== b.length) {
|
|
94
|
-
throw new Error('Embeddings must have same dimensions')
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let dotProd = 0
|
|
98
|
-
let normA = 0
|
|
99
|
-
let normB = 0
|
|
100
|
-
|
|
101
|
-
for (let i = 0; i < a.length; i++) {
|
|
102
|
-
dotProd += a[i]! * b[i]!
|
|
103
|
-
normA += a[i]! * a[i]!
|
|
104
|
-
normB += b[i]! * b[i]!
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const denominator = Math.sqrt(normA) * Math.sqrt(normB)
|
|
108
|
-
if (denominator === 0) {
|
|
109
|
-
return 0
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return dotProd / denominator
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Average multiple embeddings into a single embedding
|
|
117
|
-
* Useful for combining related content
|
|
118
|
-
*/
|
|
119
|
-
export function averageEmbeddings(embeddings: number[][]): number[] {
|
|
120
|
-
if (embeddings.length === 0) {
|
|
121
|
-
throw new Error('Cannot average empty array of embeddings')
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const firstEmbedding = embeddings[0]!
|
|
125
|
-
const dimensions = firstEmbedding.length
|
|
126
|
-
const result = new Array(dimensions).fill(0) as number[]
|
|
127
|
-
|
|
128
|
-
for (const embedding of embeddings) {
|
|
129
|
-
if (embedding.length !== dimensions) {
|
|
130
|
-
throw new Error('All embeddings must have same dimensions')
|
|
131
|
-
}
|
|
132
|
-
for (let i = 0; i < dimensions; i++) {
|
|
133
|
-
result[i]! += embedding[i]!
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const count = embeddings.length
|
|
138
|
-
return result.map((val) => val / count)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Find the top-k most similar embeddings to a query
|
|
143
|
-
* Returns indices sorted by similarity (descending)
|
|
144
|
-
*/
|
|
145
|
-
export function topKSimilar(
|
|
146
|
-
query: number[],
|
|
147
|
-
candidates: number[][],
|
|
148
|
-
k: number
|
|
149
|
-
): Array<{ index: number; similarity: number }> {
|
|
150
|
-
const similarities = candidates.map((candidate, index) => ({
|
|
151
|
-
index,
|
|
152
|
-
similarity: cosineSimilarity(query, candidate)
|
|
153
|
-
}))
|
|
154
|
-
|
|
155
|
-
return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, k)
|
|
156
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Embedding Utility Functions
|
|
3
|
+
* Phase 3: Memory and Embedding System
|
|
4
|
+
*
|
|
5
|
+
* Helper functions for embedding conversion and manipulation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Convert embedding array to Buffer for SQLite storage
|
|
10
|
+
* Stores as float32 array (4 bytes per number)
|
|
11
|
+
*/
|
|
12
|
+
export function embeddingToBuffer(embedding: number[]): Buffer {
|
|
13
|
+
const buffer = Buffer.allocUnsafe(embedding.length * 4) // 4 bytes per float32
|
|
14
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
15
|
+
buffer.writeFloatLE(embedding[i]!, i * 4)
|
|
16
|
+
}
|
|
17
|
+
return buffer
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert Buffer or Uint8Array from SQLite to embedding array
|
|
22
|
+
* Reads float32 values from buffer
|
|
23
|
+
* Note: Bun's SQLite returns BLOBs as Uint8Array, not Buffer
|
|
24
|
+
*/
|
|
25
|
+
export function bufferToEmbedding(buffer: Buffer | Uint8Array): number[] {
|
|
26
|
+
// Convert Uint8Array to Buffer if needed (Bun SQLite returns Uint8Array for BLOBs)
|
|
27
|
+
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer)
|
|
28
|
+
|
|
29
|
+
const embedding: number[] = []
|
|
30
|
+
for (let i = 0; i < buf.length; i += 4) {
|
|
31
|
+
embedding.push(buf.readFloatLE(i))
|
|
32
|
+
}
|
|
33
|
+
return embedding
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Normalize embedding vector to unit length
|
|
38
|
+
* Required for accurate cosine similarity calculation
|
|
39
|
+
*/
|
|
40
|
+
export function normalizeEmbedding(embedding: number[]): number[] {
|
|
41
|
+
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0))
|
|
42
|
+
if (norm === 0) {
|
|
43
|
+
return embedding
|
|
44
|
+
}
|
|
45
|
+
return embedding.map((val) => val / norm)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Calculate euclidean distance between two embeddings
|
|
50
|
+
* Lower distance = more similar
|
|
51
|
+
*/
|
|
52
|
+
export function euclideanDistance(a: number[], b: number[]): number {
|
|
53
|
+
if (a.length !== b.length) {
|
|
54
|
+
throw new Error('Embeddings must have same dimensions')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let sum = 0
|
|
58
|
+
for (let i = 0; i < a.length; i++) {
|
|
59
|
+
const diff = a[i]! - b[i]!
|
|
60
|
+
sum += diff * diff
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return Math.sqrt(sum)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Calculate dot product of two vectors
|
|
68
|
+
*/
|
|
69
|
+
export function dotProduct(a: number[], b: number[]): number {
|
|
70
|
+
if (a.length !== b.length) {
|
|
71
|
+
throw new Error('Vectors must have same dimensions')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let sum = 0
|
|
75
|
+
for (let i = 0; i < a.length; i++) {
|
|
76
|
+
sum += a[i]! * b[i]!
|
|
77
|
+
}
|
|
78
|
+
return sum
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Calculate magnitude (L2 norm) of a vector
|
|
83
|
+
*/
|
|
84
|
+
export function magnitude(v: number[]): number {
|
|
85
|
+
return Math.sqrt(v.reduce((sum, val) => sum + val * val, 0))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Calculate cosine similarity between two embeddings
|
|
90
|
+
* Returns value between -1 and 1 (1 = identical, 0 = orthogonal, -1 = opposite)
|
|
91
|
+
*/
|
|
92
|
+
export function cosineSimilarity(a: number[], b: number[]): number {
|
|
93
|
+
if (a.length !== b.length) {
|
|
94
|
+
throw new Error('Embeddings must have same dimensions')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let dotProd = 0
|
|
98
|
+
let normA = 0
|
|
99
|
+
let normB = 0
|
|
100
|
+
|
|
101
|
+
for (let i = 0; i < a.length; i++) {
|
|
102
|
+
dotProd += a[i]! * b[i]!
|
|
103
|
+
normA += a[i]! * a[i]!
|
|
104
|
+
normB += b[i]! * b[i]!
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB)
|
|
108
|
+
if (denominator === 0) {
|
|
109
|
+
return 0
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return dotProd / denominator
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Average multiple embeddings into a single embedding
|
|
117
|
+
* Useful for combining related content
|
|
118
|
+
*/
|
|
119
|
+
export function averageEmbeddings(embeddings: number[][]): number[] {
|
|
120
|
+
if (embeddings.length === 0) {
|
|
121
|
+
throw new Error('Cannot average empty array of embeddings')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const firstEmbedding = embeddings[0]!
|
|
125
|
+
const dimensions = firstEmbedding.length
|
|
126
|
+
const result = new Array(dimensions).fill(0) as number[]
|
|
127
|
+
|
|
128
|
+
for (const embedding of embeddings) {
|
|
129
|
+
if (embedding.length !== dimensions) {
|
|
130
|
+
throw new Error('All embeddings must have same dimensions')
|
|
131
|
+
}
|
|
132
|
+
for (let i = 0; i < dimensions; i++) {
|
|
133
|
+
result[i]! += embedding[i]!
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const count = embeddings.length
|
|
138
|
+
return result.map((val) => val / count)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Find the top-k most similar embeddings to a query
|
|
143
|
+
* Returns indices sorted by similarity (descending)
|
|
144
|
+
*/
|
|
145
|
+
export function topKSimilar(
|
|
146
|
+
query: number[],
|
|
147
|
+
candidates: number[][],
|
|
148
|
+
k: number
|
|
149
|
+
): Array<{ index: number; similarity: number }> {
|
|
150
|
+
const similarities = candidates.map((candidate, index) => ({
|
|
151
|
+
index,
|
|
152
|
+
similarity: cosineSimilarity(query, candidate)
|
|
153
|
+
}))
|
|
154
|
+
|
|
155
|
+
return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, k)
|
|
156
|
+
}
|