@@ -23,7 +23,7 @@ import * as readline from "readline";
2323import { fileURLToPath } from "url" ;
2424import { getGitmemDir , getInstallId } from "../services/gitmem-dir.js" ;
2525import { validateLicense , clearLicenseCache } from "../services/license.js" ;
26- import { hasLocalData , migrateLocalToSupabase , archiveLocalData } from "./migrate-local.js" ;
26+ import { hasLocalData , hasPreMigrationData , migrateLocalToSupabase , reimportFromBackups , archiveLocalData } from "./migrate-local.js" ;
2727
2828function createReadline ( ) : readline . Interface {
2929 return readline . createInterface ( {
@@ -536,62 +536,106 @@ export async function main(args: string[]): Promise<void> {
536536 // Clear any stale license cache
537537 clearLicenseCache ( ) ;
538538
539- // Step 7: Migrate local data to Supabase (free → pro upgrade)
540- if ( supabaseUrl && supabaseKey && missingTables . length === 0 && hasLocalData ( gitmemDir ) ) {
541- console . log ( "Migrating Local Data" ) ;
542- console . log ( " Found existing local data from free tier..." ) ;
543- console . log ( "" ) ;
544-
545- const migrationResult = await migrateLocalToSupabase ( {
546- supabaseUrl,
547- supabaseKey,
548- gitmemDir,
549- onProgress : ( msg ) => console . log ( msg ) ,
550- } ) ;
551-
552- // Report results
553- const collections = Object . keys ( migrationResult . migrated ) ;
554- let totalMigrated = 0 ;
555- let totalSkipped = 0 ;
556- let totalErrors = 0 ;
557-
558- for ( const col of collections ) {
559- const m = migrationResult . migrated [ col ] ;
560- const s = migrationResult . skipped [ col ] ;
561- const e = migrationResult . errors [ col ] ?. length || 0 ;
562- totalMigrated += m ;
563- totalSkipped += s ;
564- totalErrors += e ;
565- if ( m > 0 ) {
566- console . log ( ` ✓ ${ col } : ${ m } records migrated${ s > 0 ? ` (${ s } skipped)` : "" } ` ) ;
539+ // Ensure .gitmem/ is in .gitignore (prevents credential exposure)
540+ try {
541+ const projectRoot = process . cwd ( ) ;
542+ const gitignorePath = path . join ( projectRoot , ".gitignore" ) ;
543+ if ( fs . existsSync ( path . join ( projectRoot , ".git" ) ) ) {
544+ let gitignore = "" ;
545+ if ( fs . existsSync ( gitignorePath ) ) {
546+ gitignore = fs . readFileSync ( gitignorePath , "utf-8" ) ;
547+ }
548+ if ( ! gitignore . split ( "\n" ) . some ( line => line . trim ( ) === ".gitmem/" || line . trim ( ) === ".gitmem" ) ) {
549+ const separator = gitignore . length > 0 && ! gitignore . endsWith ( "\n" ) ? "\n" : "" ;
550+ fs . appendFileSync ( gitignorePath , `${ separator } \n# GitMem local data (contains credentials)\n.gitmem/\n` ) ;
551+ console . log ( " ✓ Added .gitmem/ to .gitignore" ) ;
567552 }
568553 }
554+ } catch {
555+ // Non-fatal — warn but don't block activation
556+ console . log ( " ⚠ Could not update .gitignore — manually add .gitmem/ to prevent credential exposure" ) ;
557+ }
569558
570- // Show errors if any
571- if ( totalErrors > 0 ) {
559+ // Step 7: Migrate local data to Supabase (free → pro upgrade)
560+ // Handles three scenarios:
561+ // A) Fresh upgrade: .json files exist → migrate and archive
562+ // B) Re-activation after failed migration: .pre-migration backups exist → reimport
563+ // C) Already migrated: neither exists → skip
564+ if ( supabaseUrl && supabaseKey && missingTables . length === 0 ) {
565+ const hasLive = hasLocalData ( gitmemDir ) ;
566+ const hasBackups = hasPreMigrationData ( gitmemDir ) ;
567+
568+ if ( hasLive || hasBackups ) {
569+ if ( hasLive ) {
570+ console . log ( "Migrating Local Data" ) ;
571+ console . log ( " Found existing local data from free tier..." ) ;
572+ } else {
573+ console . log ( "Re-importing From Backups" ) ;
574+ console . log ( " Found .pre-migration backup files from a previous upgrade..." ) ;
575+ }
572576 console . log ( "" ) ;
577+
578+ const migrationResult = hasLive
579+ ? await migrateLocalToSupabase ( {
580+ supabaseUrl,
581+ supabaseKey,
582+ gitmemDir,
583+ onProgress : ( msg ) => console . log ( msg ) ,
584+ } )
585+ : await reimportFromBackups ( {
586+ supabaseUrl,
587+ supabaseKey,
588+ gitmemDir,
589+ onProgress : ( msg ) => console . log ( msg ) ,
590+ } ) ;
591+
592+ // Report results
593+ const collections = Object . keys ( migrationResult . migrated ) ;
594+ let totalMigrated = 0 ;
595+ let totalSkipped = 0 ;
596+ let totalErrors = 0 ;
597+
573598 for ( const col of collections ) {
574- for ( const err of migrationResult . errors [ col ] || [ ] ) {
575- console . log ( ` ⚠ ${ col } : ${ err } ` ) ;
599+ const m = migrationResult . migrated [ col ] ;
600+ const s = migrationResult . skipped [ col ] ;
601+ const e = migrationResult . errors [ col ] ?. length || 0 ;
602+ totalMigrated += m ;
603+ totalSkipped += s ;
604+ totalErrors += e ;
605+ if ( m > 0 || s > 0 ) {
606+ console . log ( ` ${ m > 0 ? "✓" : "⚠" } ${ col } : ${ m } migrated${ s > 0 ? `, ${ s } failed` : "" } ` ) ;
576607 }
577608 }
578- }
579609
580- if ( totalMigrated > 0 ) {
581- console . log ( "" ) ;
582- console . log ( ` ✓ Migrated ${ totalMigrated } records to Supabase` ) ;
610+ // Show ALL errors
611+ if ( totalErrors > 0 ) {
612+ console . log ( "" ) ;
613+ for ( const col of collections ) {
614+ for ( const err of migrationResult . errors [ col ] || [ ] ) {
615+ console . log ( ` ⚠ ${ col } : ${ err } ` ) ;
616+ }
617+ }
618+ }
583619
584- // Archive local files so they aren't re-read
585- const archived = archiveLocalData ( gitmemDir ) ;
586- if ( archived . length > 0 ) {
587- console . log ( ` ✓ Local files archived (${ archived . join ( ", " ) } .json → .pre-migration)` ) ;
620+ if ( totalMigrated > 0 ) {
621+ console . log ( "" ) ;
622+ console . log ( ` ✓ Migrated ${ totalMigrated } records to Supabase` ) ;
623+
624+ if ( hasLive ) {
625+ // Archive local files so they aren't re-read
626+ const archived = archiveLocalData ( gitmemDir ) ;
627+ if ( archived . length > 0 ) {
628+ console . log ( ` ✓ Local files archived (${ archived . join ( ", " ) } .json → .pre-migration)` ) ;
629+ }
630+ }
631+ } else if ( migrationResult . hasLocalData ) {
632+ console . log ( " ⚠ Migration encountered errors. Local data preserved." ) ;
633+ console . log ( " Check .gitmem/migration.log for details." ) ;
634+ console . log ( " Fix issues and re-run: npx gitmem-mcp activate" ) ;
588635 }
589- } else if ( migrationResult . hasLocalData ) {
590- console . log ( " ⚠ Migration encountered errors. Local data preserved." ) ;
591- console . log ( " Re-run activate after resolving issues." ) ;
592- }
593636
594- console . log ( "" ) ;
637+ console . log ( "" ) ;
638+ }
595639 }
596640
597641 // Summary
0 commit comments