33 * Import memories from a JSON export file with duplicate prevention
44 * Usage: npx tsx scripts/import-memories.ts <input-file>
55 * Example: npx tsx scripts/import-memories.ts windows-memories.json
6+ *
7+ * This script uses the worker API instead of direct database access.
68 */
79
8- import Database from 'better-sqlite3' ;
910import { existsSync , readFileSync } from 'fs' ;
10- import { homedir } from 'os' ;
11- import { join } from 'path' ;
1211
13- interface ImportStats {
14- sessionsImported: number ;
15- sessionsSkipped: number ;
16- summariesImported: number ;
17- summariesSkipped: number ;
18- observationsImported: number ;
19- observationsSkipped: number ;
20- promptsImported: number ;
21- promptsSkipped: number ;
22- }
12+ const WORKER_PORT = process . env . CLAUDE_MEM_WORKER_PORT || 37777 ;
13+ const WORKER_URL = `http://127.0.0.1:${ WORKER_PORT } ` ;
2314
24- function importMemories ( inputFile : string ) {
15+ async function importMemories ( inputFile : string ) {
2516 if ( ! existsSync ( inputFile ) ) {
2617 console . error ( `❌ Input file not found: ${ inputFile } ` ) ;
2718 process . exit ( 1 ) ;
2819 }
2920
30- const dbPath = join ( homedir ( ) , '.claude-mem' , 'claude-mem.db' ) ;
31-
32- if ( ! existsSync ( dbPath ) ) {
33- console . error ( `❌ Database not found at: ${ dbPath } ` ) ;
34- process . exit ( 1 ) ;
35- }
36-
3721 // Read and parse export file
3822 const exportData = JSON . parse ( readFileSync ( inputFile , 'utf-8' ) ) ;
3923
@@ -47,190 +31,50 @@ function importMemories(inputFile: string) {
4731 console . log ( ` • ${ exportData . totalPrompts } prompts` ) ;
4832 console . log ( '' ) ;
4933
50- const db = new Database ( dbPath ) ;
51- const stats : ImportStats = {
52- sessionsImported : 0 ,
53- sessionsSkipped : 0 ,
54- summariesImported : 0 ,
55- summariesSkipped : 0 ,
56- observationsImported : 0 ,
57- observationsSkipped : 0 ,
58- promptsImported : 0 ,
59- promptsSkipped : 0
60- } ;
61-
34+ // Check if worker is running
6235 try {
63- // Prepare statements for duplicate checking
64- const checkSession = db . prepare ( 'SELECT id FROM sdk_sessions WHERE claude_session_id = ?' ) ;
65- const checkSummary = db . prepare ( 'SELECT id FROM session_summaries WHERE sdk_session_id = ?' ) ;
66- const checkObservation = db . prepare ( `
67- SELECT id FROM observations
68- WHERE sdk_session_id = ?
69- AND title = ?
70- AND created_at_epoch = ?
71- ` ) ;
72- const checkPrompt = db . prepare ( `
73- SELECT id FROM user_prompts
74- WHERE claude_session_id = ?
75- AND prompt_number = ?
76- ` ) ;
77-
78- // Prepare insert statements
79- const insertSession = db . prepare ( `
80- INSERT INTO sdk_sessions (
81- claude_session_id, sdk_session_id, project, user_prompt,
82- started_at, started_at_epoch, completed_at, completed_at_epoch,
83- status
84- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
85- ` ) ;
86-
87- const insertSummary = db . prepare ( `
88- INSERT INTO session_summaries (
89- sdk_session_id, project, request, investigated, learned,
90- completed, next_steps, files_read, files_edited, notes,
91- prompt_number, discovery_tokens, created_at, created_at_epoch
92- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
93- ` ) ;
94-
95- const insertObservation = db . prepare ( `
96- INSERT INTO observations (
97- sdk_session_id, project, text, type, title, subtitle,
98- facts, narrative, concepts, files_read, files_modified,
99- prompt_number, discovery_tokens, created_at, created_at_epoch
100- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
101- ` ) ;
102-
103- const insertPrompt = db . prepare ( `
104- INSERT INTO user_prompts (
105- claude_session_id, prompt_number, prompt_text,
106- created_at, created_at_epoch
107- ) VALUES (?, ?, ?, ?, ?)
108- ` ) ;
109-
110- // Import in transaction
111- db . transaction ( ( ) => {
112- // 1. Import sessions first (dependency for everything else)
113- console . log ( '🔄 Importing sessions...' ) ;
114- for ( const session of exportData . sessions ) {
115- const exists = checkSession . get ( session . claude_session_id ) ;
116- if ( exists ) {
117- stats . sessionsSkipped ++ ;
118- continue ;
119- }
120-
121- insertSession . run (
122- session . claude_session_id ,
123- session . sdk_session_id ,
124- session . project ,
125- session . user_prompt ,
126- session . started_at ,
127- session . started_at_epoch ,
128- session . completed_at ,
129- session . completed_at_epoch ,
130- session . status
131- ) ;
132- stats . sessionsImported ++ ;
133- }
134- console . log ( ` ✅ Imported: ${ stats . sessionsImported } , Skipped: ${ stats . sessionsSkipped } ` ) ;
135-
136- // 2. Import summaries (depends on sessions)
137- console . log ( '🔄 Importing summaries...' ) ;
138- for ( const summary of exportData . summaries ) {
139- const exists = checkSummary . get ( summary . sdk_session_id ) ;
140- if ( exists ) {
141- stats . summariesSkipped ++ ;
142- continue ;
143- }
144-
145- insertSummary . run (
146- summary . sdk_session_id ,
147- summary . project ,
148- summary . request ,
149- summary . investigated ,
150- summary . learned ,
151- summary . completed ,
152- summary . next_steps ,
153- summary . files_read ,
154- summary . files_edited ,
155- summary . notes ,
156- summary . prompt_number ,
157- summary . discovery_tokens || 0 ,
158- summary . created_at ,
159- summary . created_at_epoch
160- ) ;
161- stats . summariesImported ++ ;
162- }
163- console . log ( ` ✅ Imported: ${ stats . summariesImported } , Skipped: ${ stats . summariesSkipped } ` ) ;
164-
165- // 3. Import observations (depends on sessions)
166- console . log ( '🔄 Importing observations...' ) ;
167- for ( const obs of exportData . observations ) {
168- const exists = checkObservation . get (
169- obs . sdk_session_id ,
170- obs . title ,
171- obs . created_at_epoch
172- ) ;
173- if ( exists ) {
174- stats . observationsSkipped ++ ;
175- continue ;
176- }
177-
178- insertObservation . run (
179- obs . sdk_session_id ,
180- obs . project ,
181- obs . text ,
182- obs . type ,
183- obs . title ,
184- obs . subtitle ,
185- obs . facts ,
186- obs . narrative ,
187- obs . concepts ,
188- obs . files_read ,
189- obs . files_modified ,
190- obs . prompt_number ,
191- obs . discovery_tokens || 0 ,
192- obs . created_at ,
193- obs . created_at_epoch
194- ) ;
195- stats . observationsImported ++ ;
196- }
197- console . log ( ` ✅ Imported: ${ stats . observationsImported } , Skipped: ${ stats . observationsSkipped } ` ) ;
198-
199- // 4. Import prompts (depends on sessions)
200- console . log ( '🔄 Importing prompts...' ) ;
201- for ( const prompt of exportData . prompts ) {
202- const exists = checkPrompt . get (
203- prompt . claude_session_id ,
204- prompt . prompt_number
205- ) ;
206- if ( exists ) {
207- stats . promptsSkipped ++ ;
208- continue ;
209- }
210-
211- insertPrompt . run (
212- prompt . claude_session_id ,
213- prompt . prompt_number ,
214- prompt . prompt_text ,
215- prompt . created_at ,
216- prompt . created_at_epoch
217- ) ;
218- stats . promptsImported ++ ;
219- }
220- console . log ( ` ✅ Imported: ${ stats . promptsImported } , Skipped: ${ stats . promptsSkipped } ` ) ;
36+ const healthCheck = await fetch ( `${ WORKER_URL } /api/stats` ) ;
37+ if ( ! healthCheck . ok ) {
38+ throw new Error ( 'Worker not responding' ) ;
39+ }
40+ } catch ( error ) {
41+ console . error ( `❌ Worker not running at ${ WORKER_URL } ` ) ;
42+ console . error ( ' Please ensure the claude-mem worker is running.' ) ;
43+ process . exit ( 1 ) ;
44+ }
22145
222- } ) ( ) ;
46+ console . log ( '🔄 Importing via worker API...' ) ;
47+
48+ // Send import request to worker
49+ const response = await fetch ( `${ WORKER_URL } /api/import` , {
50+ method : 'POST' ,
51+ headers : {
52+ 'Content-Type' : 'application/json'
53+ } ,
54+ body : JSON . stringify ( {
55+ sessions : exportData . sessions || [ ] ,
56+ summaries : exportData . summaries || [ ] ,
57+ observations : exportData . observations || [ ] ,
58+ prompts : exportData . prompts || [ ]
59+ } )
60+ } ) ;
61+
62+ if ( ! response . ok ) {
63+ const errorText = await response . text ( ) ;
64+ console . error ( `❌ Import failed: ${ response . status } ${ response . statusText } ` ) ;
65+ console . error ( ` ${ errorText } ` ) ;
66+ process . exit ( 1 ) ;
67+ }
22368
224- console . log ( '\n✅ Import complete!' ) ;
225- console . log ( '📊 Summary:' ) ;
226- console . log ( ` Sessions: ${ stats . sessionsImported } imported, ${ stats . sessionsSkipped } skipped` ) ;
227- console . log ( ` Summaries: ${ stats . summariesImported } imported, ${ stats . summariesSkipped } skipped` ) ;
228- console . log ( ` Observations: ${ stats . observationsImported } imported, ${ stats . observationsSkipped } skipped` ) ;
229- console . log ( ` Prompts: ${ stats . promptsImported } imported, ${ stats . promptsSkipped } skipped` ) ;
69+ const result = await response . json ( ) ;
70+ const stats = result . stats ;
23071
231- } finally {
232- db . close ( ) ;
233- }
72+ console . log ( '\n✅ Import complete!' ) ;
73+ console . log ( '📊 Summary:' ) ;
74+ console . log ( ` Sessions: ${ stats . sessionsImported } imported, ${ stats . sessionsSkipped } skipped` ) ;
75+ console . log ( ` Summaries: ${ stats . summariesImported } imported, ${ stats . summariesSkipped } skipped` ) ;
76+ console . log ( ` Observations: ${ stats . observationsImported } imported, ${ stats . observationsSkipped } skipped` ) ;
77+ console . log ( ` Prompts: ${ stats . promptsImported } imported, ${ stats . promptsSkipped } skipped` ) ;
23478}
23579
23680// CLI interface
0 commit comments