claude-brain 0.30.2 → 0.30.3
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 +241 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +29 -29
- package/package.json +7 -3
- 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/scripts/postinstall.mjs +531 -531
- package/src/automation/decision-detector.ts +452 -452
- 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 +210 -205
- package/src/cli/auto-setup.ts +75 -75
- package/src/cli/auto-start.ts +266 -266
- package/src/cli/bin.ts +264 -264
- package/src/cli/commands/autostart.ts +90 -90
- package/src/cli/commands/chroma.ts +578 -577
- package/src/cli/commands/export-training.ts +70 -70
- package/src/cli/commands/export.ts +130 -130
- package/src/cli/commands/git-hook.ts +183 -183
- package/src/cli/commands/hooks.ts +217 -217
- package/src/cli/commands/init.ts +123 -123
- package/src/cli/commands/install-mcp.ts +122 -111
- package/src/cli/commands/models.ts +979 -979
- package/src/cli/commands/pack.ts +200 -200
- package/src/cli/commands/refresh.ts +344 -339
- package/src/cli/commands/reindex.ts +120 -120
- package/src/cli/commands/serve.ts +466 -463
- package/src/cli/commands/start.ts +44 -44
- package/src/cli/commands/status.ts +220 -203
- package/src/cli/commands/uninstall-mcp.ts +45 -41
- package/src/cli/commands/update.ts +130 -124
- package/src/cli/migrate-chroma.ts +106 -106
- 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/code-intelligence/indexer.ts +352 -352
- package/src/code-intelligence/linker.ts +178 -178
- package/src/code-intelligence/parser.ts +484 -484
- package/src/code-intelligence/query.ts +291 -291
- package/src/code-intelligence/schema.ts +83 -83
- package/src/code-intelligence/types.ts +95 -95
- package/src/config/defaults.ts +52 -52
- package/src/config/home.ts +56 -56
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +192 -192
- package/src/config/schema.ts +446 -415
- package/src/config/validator.ts +182 -182
- package/src/context/assembler.ts +407 -400
- package/src/context/index.ts +79 -79
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +122 -121
- package/src/health/index.ts +233 -232
- package/src/hooks/brain-hook.ts +134 -131
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/claude-code-mastery.md +112 -112
- package/src/hooks/context-hook.ts +260 -245
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +211 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +306 -288
- package/src/hooks/interceptor-hook.ts +204 -201
- package/src/hooks/passive-classifier.ts +397 -397
- package/src/hooks/queue.ts +160 -129
- package/src/hooks/session-tracker.ts +312 -312
- package/src/hooks/types.ts +52 -52
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +7 -7
- package/src/intelligence/hf-downloader.ts +222 -222
- package/src/intelligence/hf-manifest.json +78 -78
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/inference-router.ts +762 -762
- package/src/intelligence/model-manager.ts +263 -245
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +213 -207
- package/src/intelligence/prediction/index.ts +7 -7
- package/src/intelligence/prediction/recommender.ts +276 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +243 -247
- package/src/intelligence/reasoning/index.ts +7 -7
- package/src/intelligence/temporal/evolution.ts +193 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +272 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/intelligence/tokenizer.ts +118 -118
- package/src/knowledge/entity-extractor.ts +447 -443
- 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 +166 -166
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +211 -192
- package/src/memory/chroma/collection-manager.ts +92 -92
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +177 -175
- 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 +319 -315
- package/src/memory/chroma/store.ts +755 -747
- package/src/memory/compression.ts +121 -121
- package/src/memory/consolidation/archiver.ts +162 -165
- package/src/memory/consolidation/merger.ts +182 -186
- package/src/memory/consolidation/scorer.ts +136 -136
- package/src/memory/database.ts +9 -0
- package/src/memory/dual-write.ts +145 -0
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +347 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/fts5-search.ts +692 -633
- package/src/memory/index.ts +943 -1060
- package/src/memory/migrations/add-fts5.ts +118 -108
- package/src/memory/patterns.ts +438 -438
- package/src/memory/pruning.ts +60 -60
- package/src/memory/schema.ts +88 -88
- package/src/memory/store.ts +911 -787
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- 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 -297
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +221 -221
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +221 -221
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +165 -165
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +203 -203
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +252 -252
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +189 -188
- package/src/retrieval/reranker/model.ts +99 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +454 -454
- package/src/routing/handlers/exploration-handler.ts +369 -0
- package/src/routing/handlers/index.ts +19 -0
- package/src/routing/handlers/memory-handler.ts +273 -0
- package/src/routing/handlers/mutation-handler.ts +241 -0
- package/src/routing/handlers/recall-handler.ts +642 -0
- package/src/routing/handlers/shared.ts +515 -0
- package/src/routing/handlers/types.ts +48 -0
- package/src/routing/intent-classifier.ts +552 -552
- package/src/routing/response-filter.ts +399 -391
- package/src/routing/router.ts +245 -2193
- package/src/routing/search-engine.ts +521 -514
- package/src/routing/types.ts +104 -94
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/auto-updater.ts +283 -276
- package/src/server/handlers/call-tool.ts +159 -159
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/auto-remember.ts +165 -165
- package/src/server/handlers/tools/brain.ts +86 -86
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/get-code-standards.ts +123 -123
- package/src/server/handlers/tools/get-corrections.ts +152 -152
- package/src/server/handlers/tools/get-patterns.ts +156 -156
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/index.ts +30 -30
- package/src/server/handlers/tools/init-project.ts +756 -756
- package/src/server/handlers/tools/list-projects.ts +126 -126
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +132 -132
- package/src/server/handlers/tools/record-correction.ts +131 -131
- package/src/server/handlers/tools/remember-decision.ts +168 -168
- package/src/server/handlers/tools/schemas.ts +179 -179
- package/src/server/handlers/tools/search-code.ts +122 -122
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/http-api.ts +215 -1229
- package/src/server/mcp-proxy.ts +85 -84
- package/src/server/mcp-server.ts +285 -284
- package/src/server/middleware/auth.ts +39 -0
- package/src/server/middleware/error-handler.ts +37 -0
- package/src/server/middleware/rate-limit.ts +53 -0
- package/src/server/middleware/validate.ts +42 -0
- package/src/server/pid-manager.ts +137 -136
- package/src/server/providers/resources.ts +581 -581
- package/src/server/routes/code.ts +228 -0
- package/src/server/routes/context.ts +26 -0
- package/src/server/routes/health.ts +19 -0
- package/src/server/routes/helpers.ts +100 -0
- package/src/server/routes/hooks.ts +197 -0
- package/src/server/routes/mcp.ts +47 -0
- package/src/server/routes/memory.ts +397 -0
- package/src/server/routes/models.ts +96 -0
- package/src/server/routes/projects.ts +89 -0
- package/src/server/routes/types.ts +21 -0
- package/src/server/schemas/api-schemas.ts +202 -0
- package/src/server/services.ts +720 -720
- package/src/server/utils/memory-indicator.ts +84 -84
- package/src/server/utils/response-formatter.ts +129 -129
- package/src/server/web-viewer.ts +1145 -1115
- package/src/setup/index.ts +38 -38
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.ts +666 -666
- package/src/tools/types.ts +412 -412
- package/src/training/data-store.ts +320 -298
- package/src/training/retrain-pipeline.ts +399 -394
- package/src/utils/error-handler.ts +136 -136
- package/src/utils/index.ts +58 -58
- package/src/utils/kill-port.ts +55 -53
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/safe-path.ts +43 -0
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/index.ts +4 -3
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +4 -1
- package/src/vault/reader.ts +44 -1
- package/src/vault/watcher.ts +24 -1
- package/src/vault/writer.ts +487 -413
- package/skills/persistent-memory/SKILL.md +0 -148
- package/skills/persistent-memory/references/tool-reference.md +0 -90
|
@@ -1,270 +1,270 @@
|
|
|
1
|
-
import type { Logger } from 'pino'
|
|
2
|
-
import type { Database } from 'bun:sqlite'
|
|
3
|
-
import type { ChromaMemoryStore } from './store'
|
|
4
|
-
import type { CollectionManager } from './collection-manager'
|
|
5
|
-
|
|
6
|
-
export interface MigrationStats {
|
|
7
|
-
totalDecisions: number
|
|
8
|
-
migratedDecisions: number
|
|
9
|
-
failedDecisions: number
|
|
10
|
-
totalMemories: number
|
|
11
|
-
migratedMemories: number
|
|
12
|
-
failedMemories: number
|
|
13
|
-
duration: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface MigrationOptions {
|
|
17
|
-
batchSize?: number
|
|
18
|
-
dryRun?: boolean
|
|
19
|
-
skipExisting?: boolean
|
|
20
|
-
validateAfter?: boolean
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class ChromaMigration {
|
|
24
|
-
private logger: Logger
|
|
25
|
-
private sqliteDb: Database
|
|
26
|
-
private chromaStore: ChromaMemoryStore
|
|
27
|
-
private collections: CollectionManager
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
logger: Logger,
|
|
31
|
-
sqliteDb: Database,
|
|
32
|
-
chromaStore: ChromaMemoryStore,
|
|
33
|
-
collections: CollectionManager
|
|
34
|
-
) {
|
|
35
|
-
this.logger = logger.child({ component: 'chroma-migration' })
|
|
36
|
-
this.sqliteDb = sqliteDb
|
|
37
|
-
this.chromaStore = chromaStore
|
|
38
|
-
this.collections = collections
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async migrate(options: MigrationOptions = {}): Promise<MigrationStats> {
|
|
42
|
-
const {
|
|
43
|
-
batchSize = 100,
|
|
44
|
-
dryRun = false,
|
|
45
|
-
skipExisting = true,
|
|
46
|
-
validateAfter = true
|
|
47
|
-
} = options
|
|
48
|
-
|
|
49
|
-
this.logger.info({ options }, 'Starting migration from SQLite to ChromaDB')
|
|
50
|
-
|
|
51
|
-
const startTime = Date.now()
|
|
52
|
-
|
|
53
|
-
const stats: MigrationStats = {
|
|
54
|
-
totalDecisions: 0,
|
|
55
|
-
migratedDecisions: 0,
|
|
56
|
-
failedDecisions: 0,
|
|
57
|
-
totalMemories: 0,
|
|
58
|
-
migratedMemories: 0,
|
|
59
|
-
failedMemories: 0,
|
|
60
|
-
duration: 0
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
await this.migrateDecisions(stats, batchSize, dryRun, skipExisting)
|
|
65
|
-
await this.migrateMemories(stats, batchSize, dryRun, skipExisting)
|
|
66
|
-
|
|
67
|
-
if (validateAfter && !dryRun) {
|
|
68
|
-
await this.validateMigration(stats)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
stats.duration = Date.now() - startTime
|
|
72
|
-
|
|
73
|
-
this.logger.info(
|
|
74
|
-
{ stats },
|
|
75
|
-
'Migration completed'
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
return stats
|
|
79
|
-
|
|
80
|
-
} catch (error) {
|
|
81
|
-
this.logger.error({ error }, 'Migration failed')
|
|
82
|
-
throw error
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private async migrateDecisions(
|
|
87
|
-
stats: MigrationStats,
|
|
88
|
-
batchSize: number,
|
|
89
|
-
dryRun: boolean,
|
|
90
|
-
skipExisting: boolean
|
|
91
|
-
): Promise<void> {
|
|
92
|
-
this.logger.info('Migrating decisions...')
|
|
93
|
-
|
|
94
|
-
const query = `
|
|
95
|
-
SELECT
|
|
96
|
-
d.id,
|
|
97
|
-
d.context,
|
|
98
|
-
d.decision,
|
|
99
|
-
d.reasoning,
|
|
100
|
-
d.alternatives,
|
|
101
|
-
d.outcome,
|
|
102
|
-
d.tags,
|
|
103
|
-
m.project,
|
|
104
|
-
m.created_at,
|
|
105
|
-
m.updated_at
|
|
106
|
-
FROM decisions d
|
|
107
|
-
JOIN memories m ON d.memory_id = m.id
|
|
108
|
-
`
|
|
109
|
-
|
|
110
|
-
const decisions = this.sqliteDb.query(query).all() as any[]
|
|
111
|
-
stats.totalDecisions = decisions.length
|
|
112
|
-
|
|
113
|
-
this.logger.info({ total: decisions.length }, 'Found decisions to migrate')
|
|
114
|
-
|
|
115
|
-
for (let i = 0; i < decisions.length; i += batchSize) {
|
|
116
|
-
const batch = decisions.slice(i, i + batchSize)
|
|
117
|
-
|
|
118
|
-
for (const decision of batch) {
|
|
119
|
-
try {
|
|
120
|
-
if (dryRun) {
|
|
121
|
-
this.logger.debug({ id: decision.id }, '[DRY RUN] Would migrate decision')
|
|
122
|
-
stats.migratedDecisions++
|
|
123
|
-
continue
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (skipExisting) {
|
|
127
|
-
const existing = await this.chromaStore.getDecision(decision.id)
|
|
128
|
-
if (existing) {
|
|
129
|
-
this.logger.debug({ id: decision.id }, 'Decision already exists, skipping')
|
|
130
|
-
stats.migratedDecisions++
|
|
131
|
-
continue
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let tags: string[] = []
|
|
136
|
-
try {
|
|
137
|
-
tags = JSON.parse(decision.tags || '[]')
|
|
138
|
-
} catch {
|
|
139
|
-
tags = []
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
await this.chromaStore.upsertDecision(decision.id, {
|
|
143
|
-
project: decision.project,
|
|
144
|
-
context: decision.context,
|
|
145
|
-
decision: decision.decision,
|
|
146
|
-
reasoning: decision.reasoning,
|
|
147
|
-
alternatives: decision.alternatives,
|
|
148
|
-
outcome: decision.outcome,
|
|
149
|
-
tags
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
stats.migratedDecisions++
|
|
153
|
-
|
|
154
|
-
} catch (error) {
|
|
155
|
-
this.logger.error(
|
|
156
|
-
{ error, id: decision.id },
|
|
157
|
-
'Failed to migrate decision'
|
|
158
|
-
)
|
|
159
|
-
stats.failedDecisions++
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
this.logger.info(
|
|
164
|
-
{ progress: `${Math.min(i + batchSize, decisions.length)}/${decisions.length}` },
|
|
165
|
-
'Decision migration progress'
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
private async migrateMemories(
|
|
171
|
-
stats: MigrationStats,
|
|
172
|
-
batchSize: number,
|
|
173
|
-
dryRun: boolean,
|
|
174
|
-
_skipExisting: boolean
|
|
175
|
-
): Promise<void> {
|
|
176
|
-
this.logger.info('Migrating memories...')
|
|
177
|
-
|
|
178
|
-
const query = `
|
|
179
|
-
SELECT
|
|
180
|
-
m.id,
|
|
181
|
-
m.project,
|
|
182
|
-
m.content,
|
|
183
|
-
m.metadata,
|
|
184
|
-
m.created_at,
|
|
185
|
-
m.updated_at
|
|
186
|
-
FROM memories m
|
|
187
|
-
LEFT JOIN decisions d ON d.memory_id = m.id
|
|
188
|
-
WHERE d.id IS NULL
|
|
189
|
-
`
|
|
190
|
-
|
|
191
|
-
const memories = this.sqliteDb.query(query).all() as any[]
|
|
192
|
-
stats.totalMemories = memories.length
|
|
193
|
-
|
|
194
|
-
this.logger.info({ total: memories.length }, 'Found memories to migrate')
|
|
195
|
-
|
|
196
|
-
for (let i = 0; i < memories.length; i += batchSize) {
|
|
197
|
-
const batch = memories.slice(i, i + batchSize)
|
|
198
|
-
|
|
199
|
-
for (const memory of batch) {
|
|
200
|
-
try {
|
|
201
|
-
if (dryRun) {
|
|
202
|
-
this.logger.debug({ id: memory.id }, '[DRY RUN] Would migrate memory')
|
|
203
|
-
stats.migratedMemories++
|
|
204
|
-
continue
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
let metadata: Record<string, any> = {}
|
|
208
|
-
try {
|
|
209
|
-
metadata = JSON.parse(memory.metadata || '{}')
|
|
210
|
-
} catch {
|
|
211
|
-
metadata = {}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
await this.chromaStore.storeMemory({
|
|
215
|
-
project: memory.project,
|
|
216
|
-
content: memory.content,
|
|
217
|
-
type: metadata.type || 'general',
|
|
218
|
-
source: 'migration',
|
|
219
|
-
confidence: metadata.confidence || 1.0,
|
|
220
|
-
metadata
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
stats.migratedMemories++
|
|
224
|
-
|
|
225
|
-
} catch (error) {
|
|
226
|
-
this.logger.error(
|
|
227
|
-
{ error, id: memory.id },
|
|
228
|
-
'Failed to migrate memory'
|
|
229
|
-
)
|
|
230
|
-
stats.failedMemories++
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
this.logger.info(
|
|
235
|
-
{ progress: `${Math.min(i + batchSize, memories.length)}/${memories.length}` },
|
|
236
|
-
'Memory migration progress'
|
|
237
|
-
)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
private async validateMigration(stats: MigrationStats): Promise<void> {
|
|
242
|
-
this.logger.info('Validating migration...')
|
|
243
|
-
|
|
244
|
-
const chromaStats = await this.collections.getStats()
|
|
245
|
-
|
|
246
|
-
if (chromaStats.decisions !== stats.migratedDecisions) {
|
|
247
|
-
this.logger.warn({
|
|
248
|
-
expected: stats.migratedDecisions,
|
|
249
|
-
actual: chromaStats.decisions
|
|
250
|
-
}, 'Decision count mismatch')
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (chromaStats.memories !== stats.migratedMemories) {
|
|
254
|
-
this.logger.warn({
|
|
255
|
-
expected: stats.migratedMemories,
|
|
256
|
-
actual: chromaStats.memories
|
|
257
|
-
}, 'Memory count mismatch')
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
this.logger.info('Migration validation complete')
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async rollback(): Promise<void> {
|
|
264
|
-
this.logger.warn('Rolling back ChromaDB migration...')
|
|
265
|
-
|
|
266
|
-
await this.collections.clearAll()
|
|
267
|
-
|
|
268
|
-
this.logger.info('Rollback complete - ChromaDB collections cleared')
|
|
269
|
-
}
|
|
270
|
-
}
|
|
1
|
+
import type { Logger } from 'pino'
|
|
2
|
+
import type { Database } from 'bun:sqlite'
|
|
3
|
+
import type { ChromaMemoryStore } from './store'
|
|
4
|
+
import type { CollectionManager } from './collection-manager'
|
|
5
|
+
|
|
6
|
+
export interface MigrationStats {
|
|
7
|
+
totalDecisions: number
|
|
8
|
+
migratedDecisions: number
|
|
9
|
+
failedDecisions: number
|
|
10
|
+
totalMemories: number
|
|
11
|
+
migratedMemories: number
|
|
12
|
+
failedMemories: number
|
|
13
|
+
duration: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface MigrationOptions {
|
|
17
|
+
batchSize?: number
|
|
18
|
+
dryRun?: boolean
|
|
19
|
+
skipExisting?: boolean
|
|
20
|
+
validateAfter?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ChromaMigration {
|
|
24
|
+
private logger: Logger
|
|
25
|
+
private sqliteDb: Database
|
|
26
|
+
private chromaStore: ChromaMemoryStore
|
|
27
|
+
private collections: CollectionManager
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
logger: Logger,
|
|
31
|
+
sqliteDb: Database,
|
|
32
|
+
chromaStore: ChromaMemoryStore,
|
|
33
|
+
collections: CollectionManager
|
|
34
|
+
) {
|
|
35
|
+
this.logger = logger.child({ component: 'chroma-migration' })
|
|
36
|
+
this.sqliteDb = sqliteDb
|
|
37
|
+
this.chromaStore = chromaStore
|
|
38
|
+
this.collections = collections
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async migrate(options: MigrationOptions = {}): Promise<MigrationStats> {
|
|
42
|
+
const {
|
|
43
|
+
batchSize = 100,
|
|
44
|
+
dryRun = false,
|
|
45
|
+
skipExisting = true,
|
|
46
|
+
validateAfter = true
|
|
47
|
+
} = options
|
|
48
|
+
|
|
49
|
+
this.logger.info({ options }, 'Starting migration from SQLite to ChromaDB')
|
|
50
|
+
|
|
51
|
+
const startTime = Date.now()
|
|
52
|
+
|
|
53
|
+
const stats: MigrationStats = {
|
|
54
|
+
totalDecisions: 0,
|
|
55
|
+
migratedDecisions: 0,
|
|
56
|
+
failedDecisions: 0,
|
|
57
|
+
totalMemories: 0,
|
|
58
|
+
migratedMemories: 0,
|
|
59
|
+
failedMemories: 0,
|
|
60
|
+
duration: 0
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await this.migrateDecisions(stats, batchSize, dryRun, skipExisting)
|
|
65
|
+
await this.migrateMemories(stats, batchSize, dryRun, skipExisting)
|
|
66
|
+
|
|
67
|
+
if (validateAfter && !dryRun) {
|
|
68
|
+
await this.validateMigration(stats)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
stats.duration = Date.now() - startTime
|
|
72
|
+
|
|
73
|
+
this.logger.info(
|
|
74
|
+
{ stats },
|
|
75
|
+
'Migration completed'
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return stats
|
|
79
|
+
|
|
80
|
+
} catch (error) {
|
|
81
|
+
this.logger.error({ error }, 'Migration failed')
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private async migrateDecisions(
|
|
87
|
+
stats: MigrationStats,
|
|
88
|
+
batchSize: number,
|
|
89
|
+
dryRun: boolean,
|
|
90
|
+
skipExisting: boolean
|
|
91
|
+
): Promise<void> {
|
|
92
|
+
this.logger.info('Migrating decisions...')
|
|
93
|
+
|
|
94
|
+
const query = `
|
|
95
|
+
SELECT
|
|
96
|
+
d.id,
|
|
97
|
+
d.context,
|
|
98
|
+
d.decision,
|
|
99
|
+
d.reasoning,
|
|
100
|
+
d.alternatives,
|
|
101
|
+
d.outcome,
|
|
102
|
+
d.tags,
|
|
103
|
+
m.project,
|
|
104
|
+
m.created_at,
|
|
105
|
+
m.updated_at
|
|
106
|
+
FROM decisions d
|
|
107
|
+
JOIN memories m ON d.memory_id = m.id
|
|
108
|
+
`
|
|
109
|
+
|
|
110
|
+
const decisions = this.sqliteDb.query(query).all() as any[]
|
|
111
|
+
stats.totalDecisions = decisions.length
|
|
112
|
+
|
|
113
|
+
this.logger.info({ total: decisions.length }, 'Found decisions to migrate')
|
|
114
|
+
|
|
115
|
+
for (let i = 0; i < decisions.length; i += batchSize) {
|
|
116
|
+
const batch = decisions.slice(i, i + batchSize)
|
|
117
|
+
|
|
118
|
+
for (const decision of batch) {
|
|
119
|
+
try {
|
|
120
|
+
if (dryRun) {
|
|
121
|
+
this.logger.debug({ id: decision.id }, '[DRY RUN] Would migrate decision')
|
|
122
|
+
stats.migratedDecisions++
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (skipExisting) {
|
|
127
|
+
const existing = await this.chromaStore.getDecision(decision.id)
|
|
128
|
+
if (existing) {
|
|
129
|
+
this.logger.debug({ id: decision.id }, 'Decision already exists, skipping')
|
|
130
|
+
stats.migratedDecisions++
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let tags: string[] = []
|
|
136
|
+
try {
|
|
137
|
+
tags = JSON.parse(decision.tags || '[]')
|
|
138
|
+
} catch {
|
|
139
|
+
tags = []
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await this.chromaStore.upsertDecision(decision.id, {
|
|
143
|
+
project: decision.project,
|
|
144
|
+
context: decision.context,
|
|
145
|
+
decision: decision.decision,
|
|
146
|
+
reasoning: decision.reasoning,
|
|
147
|
+
alternatives: decision.alternatives,
|
|
148
|
+
outcome: decision.outcome,
|
|
149
|
+
tags
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
stats.migratedDecisions++
|
|
153
|
+
|
|
154
|
+
} catch (error) {
|
|
155
|
+
this.logger.error(
|
|
156
|
+
{ error, id: decision.id },
|
|
157
|
+
'Failed to migrate decision'
|
|
158
|
+
)
|
|
159
|
+
stats.failedDecisions++
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.logger.info(
|
|
164
|
+
{ progress: `${Math.min(i + batchSize, decisions.length)}/${decisions.length}` },
|
|
165
|
+
'Decision migration progress'
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private async migrateMemories(
|
|
171
|
+
stats: MigrationStats,
|
|
172
|
+
batchSize: number,
|
|
173
|
+
dryRun: boolean,
|
|
174
|
+
_skipExisting: boolean
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
this.logger.info('Migrating memories...')
|
|
177
|
+
|
|
178
|
+
const query = `
|
|
179
|
+
SELECT
|
|
180
|
+
m.id,
|
|
181
|
+
m.project,
|
|
182
|
+
m.content,
|
|
183
|
+
m.metadata,
|
|
184
|
+
m.created_at,
|
|
185
|
+
m.updated_at
|
|
186
|
+
FROM memories m
|
|
187
|
+
LEFT JOIN decisions d ON d.memory_id = m.id
|
|
188
|
+
WHERE d.id IS NULL
|
|
189
|
+
`
|
|
190
|
+
|
|
191
|
+
const memories = this.sqliteDb.query(query).all() as any[]
|
|
192
|
+
stats.totalMemories = memories.length
|
|
193
|
+
|
|
194
|
+
this.logger.info({ total: memories.length }, 'Found memories to migrate')
|
|
195
|
+
|
|
196
|
+
for (let i = 0; i < memories.length; i += batchSize) {
|
|
197
|
+
const batch = memories.slice(i, i + batchSize)
|
|
198
|
+
|
|
199
|
+
for (const memory of batch) {
|
|
200
|
+
try {
|
|
201
|
+
if (dryRun) {
|
|
202
|
+
this.logger.debug({ id: memory.id }, '[DRY RUN] Would migrate memory')
|
|
203
|
+
stats.migratedMemories++
|
|
204
|
+
continue
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let metadata: Record<string, any> = {}
|
|
208
|
+
try {
|
|
209
|
+
metadata = JSON.parse(memory.metadata || '{}')
|
|
210
|
+
} catch {
|
|
211
|
+
metadata = {}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await this.chromaStore.storeMemory({
|
|
215
|
+
project: memory.project,
|
|
216
|
+
content: memory.content,
|
|
217
|
+
type: metadata.type || 'general',
|
|
218
|
+
source: 'migration',
|
|
219
|
+
confidence: metadata.confidence || 1.0,
|
|
220
|
+
metadata
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
stats.migratedMemories++
|
|
224
|
+
|
|
225
|
+
} catch (error) {
|
|
226
|
+
this.logger.error(
|
|
227
|
+
{ error, id: memory.id },
|
|
228
|
+
'Failed to migrate memory'
|
|
229
|
+
)
|
|
230
|
+
stats.failedMemories++
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.logger.info(
|
|
235
|
+
{ progress: `${Math.min(i + batchSize, memories.length)}/${memories.length}` },
|
|
236
|
+
'Memory migration progress'
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private async validateMigration(stats: MigrationStats): Promise<void> {
|
|
242
|
+
this.logger.info('Validating migration...')
|
|
243
|
+
|
|
244
|
+
const chromaStats = await this.collections.getStats()
|
|
245
|
+
|
|
246
|
+
if (chromaStats.decisions !== stats.migratedDecisions) {
|
|
247
|
+
this.logger.warn({
|
|
248
|
+
expected: stats.migratedDecisions,
|
|
249
|
+
actual: chromaStats.decisions
|
|
250
|
+
}, 'Decision count mismatch')
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (chromaStats.memories !== stats.migratedMemories) {
|
|
254
|
+
this.logger.warn({
|
|
255
|
+
expected: stats.migratedMemories,
|
|
256
|
+
actual: chromaStats.memories
|
|
257
|
+
}, 'Memory count mismatch')
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.logger.info('Migration validation complete')
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async rollback(): Promise<void> {
|
|
264
|
+
this.logger.warn('Rolling back ChromaDB migration...')
|
|
265
|
+
|
|
266
|
+
await this.collections.clearAll()
|
|
267
|
+
|
|
268
|
+
this.logger.info('Rollback complete - ChromaDB collections cleared')
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
export interface DecisionMetadata {
|
|
2
|
-
project: string
|
|
3
|
-
context: string
|
|
4
|
-
reasoning: string
|
|
5
|
-
alternatives?: string
|
|
6
|
-
outcome?: string
|
|
7
|
-
tags: string[]
|
|
8
|
-
created_at: string
|
|
9
|
-
updated_at: string
|
|
10
|
-
confidence?: number
|
|
11
|
-
source: 'manual' | 'auto-detected'
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface MemoryMetadata {
|
|
15
|
-
project: string
|
|
16
|
-
type: 'fact' | 'preference' | 'constraint' | 'goal' | 'general'
|
|
17
|
-
source: string
|
|
18
|
-
confidence: number
|
|
19
|
-
created_at: string
|
|
20
|
-
updated_at: string
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface PatternMetadata {
|
|
24
|
-
pattern_type: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
25
|
-
occurrences: number
|
|
26
|
-
projects: string[]
|
|
27
|
-
confidence: number
|
|
28
|
-
first_seen: string
|
|
29
|
-
last_seen: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface FeedbackMetadata {
|
|
33
|
-
memory_id: string
|
|
34
|
-
query_id: string
|
|
35
|
-
query: string
|
|
36
|
-
rating: 1 | 2 | 3 | 4 | 5
|
|
37
|
-
was_used: boolean
|
|
38
|
-
feedback_text?: string
|
|
39
|
-
project?: string
|
|
40
|
-
created_at: string
|
|
41
|
-
collection_type: 'decisions' | 'memories' | 'patterns' | 'corrections'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface EpisodeCollectionMetadata {
|
|
45
|
-
episode_id: string
|
|
46
|
-
project: string
|
|
47
|
-
status: 'active' | 'completed'
|
|
48
|
-
started_at: string
|
|
49
|
-
ended_at: string
|
|
50
|
-
message_count: number
|
|
51
|
-
token_count: number
|
|
52
|
-
key_topics: string
|
|
53
|
-
brief_summary: string
|
|
54
|
-
related_decisions: string
|
|
55
|
-
related_patterns: string
|
|
56
|
-
related_corrections: string
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const COLLECTIONS = {
|
|
60
|
-
DECISIONS: 'decisions',
|
|
61
|
-
MEMORIES: 'memories',
|
|
62
|
-
PATTERNS: 'patterns',
|
|
63
|
-
CORRECTIONS: 'corrections',
|
|
64
|
-
FEEDBACK: 'feedback',
|
|
65
|
-
EPISODES: 'episodes',
|
|
66
|
-
ARCHIVED_MEMORIES: 'archived_memories'
|
|
67
|
-
} as const
|
|
68
|
-
|
|
69
|
-
export type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS]
|
|
1
|
+
export interface DecisionMetadata {
|
|
2
|
+
project: string
|
|
3
|
+
context: string
|
|
4
|
+
reasoning: string
|
|
5
|
+
alternatives?: string
|
|
6
|
+
outcome?: string
|
|
7
|
+
tags: string[]
|
|
8
|
+
created_at: string
|
|
9
|
+
updated_at: string
|
|
10
|
+
confidence?: number
|
|
11
|
+
source: 'manual' | 'auto-detected'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MemoryMetadata {
|
|
15
|
+
project: string
|
|
16
|
+
type: 'fact' | 'preference' | 'constraint' | 'goal' | 'general'
|
|
17
|
+
source: string
|
|
18
|
+
confidence: number
|
|
19
|
+
created_at: string
|
|
20
|
+
updated_at: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PatternMetadata {
|
|
24
|
+
pattern_type: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
25
|
+
occurrences: number
|
|
26
|
+
projects: string[]
|
|
27
|
+
confidence: number
|
|
28
|
+
first_seen: string
|
|
29
|
+
last_seen: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface FeedbackMetadata {
|
|
33
|
+
memory_id: string
|
|
34
|
+
query_id: string
|
|
35
|
+
query: string
|
|
36
|
+
rating: 1 | 2 | 3 | 4 | 5
|
|
37
|
+
was_used: boolean
|
|
38
|
+
feedback_text?: string
|
|
39
|
+
project?: string
|
|
40
|
+
created_at: string
|
|
41
|
+
collection_type: 'decisions' | 'memories' | 'patterns' | 'corrections'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface EpisodeCollectionMetadata {
|
|
45
|
+
episode_id: string
|
|
46
|
+
project: string
|
|
47
|
+
status: 'active' | 'completed'
|
|
48
|
+
started_at: string
|
|
49
|
+
ended_at: string
|
|
50
|
+
message_count: number
|
|
51
|
+
token_count: number
|
|
52
|
+
key_topics: string
|
|
53
|
+
brief_summary: string
|
|
54
|
+
related_decisions: string
|
|
55
|
+
related_patterns: string
|
|
56
|
+
related_corrections: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const COLLECTIONS = {
|
|
60
|
+
DECISIONS: 'decisions',
|
|
61
|
+
MEMORIES: 'memories',
|
|
62
|
+
PATTERNS: 'patterns',
|
|
63
|
+
CORRECTIONS: 'corrections',
|
|
64
|
+
FEEDBACK: 'feedback',
|
|
65
|
+
EPISODES: 'episodes',
|
|
66
|
+
ARCHIVED_MEMORIES: 'archived_memories'
|
|
67
|
+
} as const
|
|
68
|
+
|
|
69
|
+
export type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS]
|