spindb 0.9.1 → 0.9.2

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.
Files changed (44) hide show
  1. package/cli/commands/backup.ts +13 -11
  2. package/cli/commands/clone.ts +14 -10
  3. package/cli/commands/config.ts +29 -29
  4. package/cli/commands/connect.ts +51 -39
  5. package/cli/commands/create.ts +59 -32
  6. package/cli/commands/delete.ts +8 -8
  7. package/cli/commands/deps.ts +17 -15
  8. package/cli/commands/doctor.ts +11 -11
  9. package/cli/commands/edit.ts +108 -55
  10. package/cli/commands/engines.ts +17 -15
  11. package/cli/commands/info.ts +8 -6
  12. package/cli/commands/list.ts +31 -16
  13. package/cli/commands/logs.ts +15 -11
  14. package/cli/commands/menu/backup-handlers.ts +52 -47
  15. package/cli/commands/menu/container-handlers.ts +120 -78
  16. package/cli/commands/menu/engine-handlers.ts +21 -11
  17. package/cli/commands/menu/index.ts +4 -4
  18. package/cli/commands/menu/shell-handlers.ts +34 -31
  19. package/cli/commands/menu/sql-handlers.ts +22 -16
  20. package/cli/commands/menu/update-handlers.ts +19 -17
  21. package/cli/commands/restore.ts +22 -20
  22. package/cli/commands/run.ts +20 -18
  23. package/cli/commands/self-update.ts +5 -5
  24. package/cli/commands/start.ts +11 -9
  25. package/cli/commands/stop.ts +9 -9
  26. package/cli/commands/url.ts +12 -9
  27. package/cli/helpers.ts +9 -4
  28. package/cli/ui/prompts.ts +12 -5
  29. package/cli/ui/spinner.ts +4 -4
  30. package/cli/ui/theme.ts +4 -4
  31. package/core/binary-manager.ts +5 -1
  32. package/core/container-manager.ts +5 -5
  33. package/core/platform-service.ts +3 -3
  34. package/core/start-with-retry.ts +6 -6
  35. package/core/transaction-manager.ts +6 -6
  36. package/engines/mysql/index.ts +11 -11
  37. package/engines/mysql/restore.ts +4 -4
  38. package/engines/mysql/version-validator.ts +2 -2
  39. package/engines/postgresql/binary-manager.ts +17 -17
  40. package/engines/postgresql/index.ts +7 -2
  41. package/engines/postgresql/restore.ts +2 -2
  42. package/engines/postgresql/version-validator.ts +2 -2
  43. package/engines/sqlite/index.ts +21 -8
  44. package/package.json +1 -1
@@ -1,6 +1,13 @@
1
1
  import chalk from 'chalk'
2
2
  import inquirer from 'inquirer'
3
- import { existsSync, renameSync, statSync, mkdirSync, copyFileSync, unlinkSync } from 'fs'
3
+ import {
4
+ existsSync,
5
+ renameSync,
6
+ statSync,
7
+ mkdirSync,
8
+ copyFileSync,
9
+ unlinkSync,
10
+ } from 'fs'
4
11
  import { dirname, basename, join, resolve } from 'path'
5
12
  import { homedir } from 'os'
6
13
  import { containerManager } from '../../../core/container-manager'
@@ -22,10 +29,10 @@ import {
22
29
  import { createSpinner } from '../../ui/spinner'
23
30
  import {
24
31
  header,
25
- success,
26
- error,
27
- warning,
28
- info,
32
+ uiSuccess,
33
+ uiError,
34
+ uiWarning,
35
+ uiInfo,
29
36
  connectionBox,
30
37
  formatBytes,
31
38
  } from '../../ui/theme'
@@ -69,7 +76,7 @@ export async function handleCreate(): Promise<void> {
69
76
  missingDeps = await getMissingDependencies(engine)
70
77
  if (missingDeps.length > 0) {
71
78
  console.log(
72
- error(
79
+ uiError(
73
80
  `Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
74
81
  ),
75
82
  )
@@ -94,13 +101,17 @@ export async function handleCreate(): Promise<void> {
94
101
 
95
102
  const isInstalled = await dbEngine.isBinaryInstalled(version)
96
103
  if (isInstalled) {
97
- binarySpinner.succeed(`${dbEngine.displayName} ${version} binaries ready (cached)`)
104
+ binarySpinner.succeed(
105
+ `${dbEngine.displayName} ${version} binaries ready (cached)`,
106
+ )
98
107
  } else {
99
108
  binarySpinner.text = `Downloading ${dbEngine.displayName} ${version} binaries...`
100
109
  await dbEngine.ensureBinaries(version, ({ message }) => {
101
110
  binarySpinner.text = message
102
111
  })
103
- binarySpinner.succeed(`${dbEngine.displayName} ${version} binaries downloaded`)
112
+ binarySpinner.succeed(
113
+ `${dbEngine.displayName} ${version} binaries downloaded`,
114
+ )
104
115
  }
105
116
  }
106
117
 
@@ -131,7 +142,9 @@ export async function handleCreate(): Promise<void> {
131
142
  path: sqlitePath, // SQLite file path (undefined for server databases)
132
143
  })
133
144
 
134
- initSpinner.succeed(isSQLite ? 'Database file created' : 'Database cluster initialized')
145
+ initSpinner.succeed(
146
+ isSQLite ? 'Database file created' : 'Database cluster initialized',
147
+ )
135
148
 
136
149
  // SQLite: show file path, no start needed
137
150
  if (isSQLite) {
@@ -139,13 +152,13 @@ export async function handleCreate(): Promise<void> {
139
152
  if (config) {
140
153
  const connectionString = dbEngine.getConnectionString(config)
141
154
  console.log()
142
- console.log(success('Database Created'))
155
+ console.log(uiSuccess('Database Created'))
143
156
  console.log()
144
157
  console.log(chalk.gray(` Container: ${containerName}`))
145
158
  console.log(chalk.gray(` Engine: ${dbEngine.displayName} ${version}`))
146
159
  console.log(chalk.gray(` File: ${config.database}`))
147
160
  console.log()
148
- console.log(success(`Available at ${config.database}`))
161
+ console.log(uiSuccess(`Available at ${config.database}`))
149
162
  console.log()
150
163
  console.log(chalk.gray(' Connection string:'))
151
164
  console.log(chalk.cyan(` ${connectionString}`))
@@ -199,14 +212,14 @@ export async function handleCreate(): Promise<void> {
199
212
  if (config) {
200
213
  const connectionString = dbEngine.getConnectionString(config)
201
214
  console.log()
202
- console.log(success('Database Created'))
215
+ console.log(uiSuccess('Database Created'))
203
216
  console.log()
204
217
  console.log(chalk.gray(` Container: ${containerName}`))
205
218
  console.log(chalk.gray(` Engine: ${dbEngine.displayName} ${version}`))
206
219
  console.log(chalk.gray(` Database: ${database}`))
207
220
  console.log(chalk.gray(` Port: ${port}`))
208
221
  console.log()
209
- console.log(success(`Running on port ${port}`))
222
+ console.log(uiSuccess(`Running on port ${port}`))
210
223
  console.log()
211
224
  console.log(chalk.gray(' Connection string:'))
212
225
  console.log(chalk.cyan(` ${connectionString}`))
@@ -235,12 +248,12 @@ export async function handleCreate(): Promise<void> {
235
248
  } else {
236
249
  console.log()
237
250
  console.log(
238
- warning(
251
+ uiWarning(
239
252
  `Port ${port} is currently in use. Container created but not started.`,
240
253
  ),
241
254
  )
242
255
  console.log(
243
- info(
256
+ uiInfo(
244
257
  `Start it later with: ${chalk.cyan(`spindb start ${containerName}`)}`,
245
258
  ),
246
259
  )
@@ -257,7 +270,7 @@ export async function handleList(
257
270
 
258
271
  if (containers.length === 0) {
259
272
  console.log(
260
- info('No containers found. Create one with the "Create" option.'),
273
+ uiInfo('No containers found. Create one with the "Create" option.'),
261
274
  )
262
275
  console.log()
263
276
 
@@ -302,19 +315,20 @@ export async function handleList(
302
315
 
303
316
  // SQLite uses available/missing, server databases use running/stopped
304
317
  const statusDisplay = isSQLite
305
- ? (container.status === 'running'
306
- ? chalk.blue('● available')
307
- : chalk.gray('○ missing'))
308
- : (container.status === 'running'
309
- ? chalk.green('● running')
310
- : chalk.gray('○ stopped'))
318
+ ? container.status === 'running'
319
+ ? chalk.blue('● available')
320
+ : chalk.gray('○ missing')
321
+ : container.status === 'running'
322
+ ? chalk.green('● running')
323
+ : chalk.gray('○ stopped')
311
324
 
312
325
  const sizeDisplay = size !== null ? formatBytes(size) : chalk.gray('—')
313
326
 
314
327
  // Truncate name if too long
315
- const displayName = container.name.length > 15
316
- ? container.name.slice(0, 14) + '…'
317
- : container.name
328
+ const displayName =
329
+ container.name.length > 15
330
+ ? container.name.slice(0, 14) + '…'
331
+ : container.name
318
332
 
319
333
  // SQLite shows dash instead of port
320
334
  const portDisplay = isSQLite ? '—' : String(container.port)
@@ -338,7 +352,9 @@ export async function handleList(
338
352
 
339
353
  const running = serverContainers.filter((c) => c.status === 'running').length
340
354
  const stopped = serverContainers.filter((c) => c.status !== 'running').length
341
- const available = sqliteContainers.filter((c) => c.status === 'running').length
355
+ const available = sqliteContainers.filter(
356
+ (c) => c.status === 'running',
357
+ ).length
342
358
  const missing = sqliteContainers.filter((c) => c.status !== 'running').length
343
359
 
344
360
  const parts: string[] = []
@@ -346,13 +362,13 @@ export async function handleList(
346
362
  parts.push(`${running} running, ${stopped} stopped`)
347
363
  }
348
364
  if (sqliteContainers.length > 0) {
349
- parts.push(`${available} SQLite available${missing > 0 ? `, ${missing} missing` : ''}`)
365
+ parts.push(
366
+ `${available} SQLite available${missing > 0 ? `, ${missing} missing` : ''}`,
367
+ )
350
368
  }
351
369
 
352
370
  console.log(
353
- chalk.gray(
354
- ` ${containers.length} container(s): ${parts.join('; ')}`,
355
- ),
371
+ chalk.gray(` ${containers.length} container(s): ${parts.join('; ')}`),
356
372
  )
357
373
 
358
374
  console.log()
@@ -361,8 +377,12 @@ export async function handleList(
361
377
  // Simpler selector - table already shows details
362
378
  const statusLabel =
363
379
  c.engine === Engine.SQLite
364
- ? (c.status === 'running' ? chalk.blue('● available') : chalk.gray('○ missing'))
365
- : (c.status === 'running' ? chalk.green('● running') : chalk.gray('○ stopped'))
380
+ ? c.status === 'running'
381
+ ? chalk.blue('● available')
382
+ : chalk.gray('○ missing')
383
+ : c.status === 'running'
384
+ ? chalk.green('● running')
385
+ : chalk.gray('○ stopped')
366
386
 
367
387
  return {
368
388
  name: `${c.name} ${statusLabel}`,
@@ -400,7 +420,7 @@ export async function showContainerSubmenu(
400
420
  ): Promise<void> {
401
421
  const config = await containerManager.getConfig(containerName)
402
422
  if (!config) {
403
- console.error(error(`Container "${containerName}" not found`))
423
+ console.error(uiError(`Container "${containerName}" not found`))
404
424
  return
405
425
  }
406
426
 
@@ -458,7 +478,11 @@ export async function showContainerSubmenu(
458
478
  ? `${chalk.blue('⌘')} Open shell`
459
479
  : chalk.gray('⌘ Open shell'),
460
480
  value: 'shell',
461
- disabled: canOpenShell ? false : (isSQLite ? 'Database file missing' : 'Start container first'),
481
+ disabled: canOpenShell
482
+ ? false
483
+ : isSQLite
484
+ ? 'Database file missing'
485
+ : 'Start container first',
462
486
  })
463
487
 
464
488
  // Run SQL - always enabled for SQLite (if file exists), server databases need to be running
@@ -468,7 +492,11 @@ export async function showContainerSubmenu(
468
492
  ? `${chalk.yellow('▷')} Run SQL file`
469
493
  : chalk.gray('▷ Run SQL file'),
470
494
  value: 'run-sql',
471
- disabled: canRunSql ? false : (isSQLite ? 'Database file missing' : 'Start container first'),
495
+ disabled: canRunSql
496
+ ? false
497
+ : isSQLite
498
+ ? 'Database file missing'
499
+ : 'Start container first',
472
500
  })
473
501
 
474
502
  // Edit container - SQLite can always edit (no running state), server databases must be stopped
@@ -491,9 +519,10 @@ export async function showContainerSubmenu(
491
519
  disabled: canClone ? false : 'Stop container first',
492
520
  })
493
521
 
494
- actionChoices.push(
495
- { name: `${chalk.magenta('⎘')} Copy connection string`, value: 'copy' },
496
- )
522
+ actionChoices.push({
523
+ name: `${chalk.magenta('⎘')} Copy connection string`,
524
+ value: 'copy',
525
+ })
497
526
 
498
527
  // View logs - not available for SQLite (no log file)
499
528
  if (!isSQLite) {
@@ -596,7 +625,7 @@ export async function handleStart(): Promise<void> {
596
625
  )
597
626
 
598
627
  if (stopped.length === 0) {
599
- console.log(warning('All containers are already running'))
628
+ console.log(uiWarning('All containers are already running'))
600
629
  return
601
630
  }
602
631
 
@@ -609,7 +638,7 @@ export async function handleStart(): Promise<void> {
609
638
 
610
639
  const config = await containerManager.getConfig(containerName)
611
640
  if (!config) {
612
- console.error(error(`Container "${containerName}" not found`))
641
+ console.error(uiError(`Container "${containerName}" not found`))
613
642
  return
614
643
  }
615
644
 
@@ -617,7 +646,7 @@ export async function handleStart(): Promise<void> {
617
646
  if (!portAvailable) {
618
647
  const { port: newPort } = await portManager.findAvailablePort()
619
648
  console.log(
620
- warning(`Port ${config.port} is in use, switching to port ${newPort}`),
649
+ uiWarning(`Port ${config.port} is in use, switching to port ${newPort}`),
621
650
  )
622
651
  config.port = newPort
623
652
  await containerManager.updateConfig(containerName, { port: newPort })
@@ -647,7 +676,7 @@ export async function handleStop(): Promise<void> {
647
676
  )
648
677
 
649
678
  if (running.length === 0) {
650
- console.log(warning('No running containers'))
679
+ console.log(uiWarning('No running containers'))
651
680
  return
652
681
  }
653
682
 
@@ -660,7 +689,7 @@ export async function handleStop(): Promise<void> {
660
689
 
661
690
  const config = await containerManager.getConfig(containerName)
662
691
  if (!config) {
663
- console.error(error(`Container "${containerName}" not found`))
692
+ console.error(uiError(`Container "${containerName}" not found`))
664
693
  return
665
694
  }
666
695
 
@@ -678,25 +707,25 @@ export async function handleStop(): Promise<void> {
678
707
  async function handleStartContainer(containerName: string): Promise<void> {
679
708
  const config = await containerManager.getConfig(containerName)
680
709
  if (!config) {
681
- console.error(error(`Container "${containerName}" not found`))
710
+ console.error(uiError(`Container "${containerName}" not found`))
682
711
  return
683
712
  }
684
713
 
685
714
  const portAvailable = await portManager.isPortAvailable(config.port)
686
715
  if (!portAvailable) {
687
716
  console.log(
688
- warning(
717
+ uiWarning(
689
718
  `Port ${config.port} is in use. Stop the process using it or change this container's port.`,
690
719
  ),
691
720
  )
692
721
  console.log()
693
722
  console.log(
694
- info(
723
+ uiInfo(
695
724
  'Tip: If you installed MariaDB via apt, it may have started a system service.',
696
725
  ),
697
726
  )
698
727
  console.log(
699
- info(
728
+ uiInfo(
700
729
  'Run: sudo systemctl stop mariadb && sudo systemctl disable mariadb',
701
730
  ),
702
731
  )
@@ -718,18 +747,18 @@ async function handleStartContainer(containerName: string): Promise<void> {
718
747
  console.log()
719
748
  console.log(chalk.gray(' Connection string:'))
720
749
  console.log(chalk.cyan(` ${connectionString}`))
721
- } catch (err) {
750
+ } catch (error) {
722
751
  spinner.fail(`Failed to start "${containerName}"`)
723
- const e = err as Error
752
+ const e = error as Error
724
753
  console.log()
725
- console.log(error(e.message))
754
+ console.log(uiError(e.message))
726
755
 
727
756
  const logPath = paths.getContainerLogPath(containerName, {
728
757
  engine: config.engine,
729
758
  })
730
759
  if (existsSync(logPath)) {
731
760
  console.log()
732
- console.log(info(`Check the log file for details: ${logPath}`))
761
+ console.log(uiInfo(`Check the log file for details: ${logPath}`))
733
762
  }
734
763
  }
735
764
  }
@@ -737,7 +766,7 @@ async function handleStartContainer(containerName: string): Promise<void> {
737
766
  async function handleStopContainer(containerName: string): Promise<void> {
738
767
  const config = await containerManager.getConfig(containerName)
739
768
  if (!config) {
740
- console.error(error(`Container "${containerName}" not found`))
769
+ console.error(uiError(`Container "${containerName}" not found`))
741
770
  return
742
771
  }
743
772
 
@@ -757,7 +786,7 @@ async function handleEditContainer(
757
786
  ): Promise<string | null> {
758
787
  const config = await containerManager.getConfig(containerName)
759
788
  if (!config) {
760
- console.error(error(`Container "${containerName}" not found`))
789
+ console.error(uiError(`Container "${containerName}" not found`))
761
790
  return null
762
791
  }
763
792
 
@@ -767,7 +796,9 @@ async function handleEditContainer(
767
796
  console.log(header(`Edit: ${containerName}`))
768
797
  console.log()
769
798
 
770
- const editChoices: Array<{ name: string; value: string } | inquirer.Separator> = [
799
+ const editChoices: Array<
800
+ { name: string; value: string } | inquirer.Separator
801
+ > = [
771
802
  {
772
803
  name: `Name: ${chalk.white(containerName)}`,
773
804
  value: 'name',
@@ -833,12 +864,12 @@ async function handleEditContainer(
833
864
  ])
834
865
 
835
866
  if (newName === containerName) {
836
- console.log(info('Name unchanged'))
867
+ console.log(uiInfo('Name unchanged'))
837
868
  return await handleEditContainer(containerName)
838
869
  }
839
870
 
840
871
  if (await containerManager.exists(newName)) {
841
- console.log(error(`Container "${newName}" already exists`))
872
+ console.log(uiError(`Container "${newName}" already exists`))
842
873
  return await handleEditContainer(containerName)
843
874
  }
844
875
 
@@ -872,21 +903,21 @@ async function handleEditContainer(
872
903
  ])
873
904
 
874
905
  if (newPort === config.port) {
875
- console.log(info('Port unchanged'))
906
+ console.log(uiInfo('Port unchanged'))
876
907
  return await handleEditContainer(containerName)
877
908
  }
878
909
 
879
910
  const portAvailable = await portManager.isPortAvailable(newPort)
880
911
  if (!portAvailable) {
881
912
  console.log(
882
- warning(
913
+ uiWarning(
883
914
  `Port ${newPort} is currently in use. You'll need to stop the process using it before starting this container.`,
884
915
  ),
885
916
  )
886
917
  }
887
918
 
888
919
  await containerManager.updateConfig(containerName, { port: newPort })
889
- console.log(success(`Changed port from ${config.port} to ${newPort}`))
920
+ console.log(uiSuccess(`Changed port from ${config.port} to ${newPort}`))
890
921
 
891
922
  // Continue editing
892
923
  return await handleEditContainer(containerName)
@@ -928,40 +959,43 @@ async function handleEditContainer(
928
959
  // - ends with /
929
960
  // - exists and is a directory
930
961
  // - doesn't have a database file extension (assume it's a directory path)
931
- const isDirectory = expandedPath.endsWith('/') ||
962
+ const isDirectory =
963
+ expandedPath.endsWith('/') ||
932
964
  (existsSync(expandedPath) && statSync(expandedPath).isDirectory()) ||
933
965
  !hasDbExtension
934
966
 
935
967
  let finalPath: string
936
968
  if (isDirectory) {
937
969
  // Remove trailing slash if present, then append filename
938
- const dirPath = expandedPath.endsWith('/') ? expandedPath.slice(0, -1) : expandedPath
970
+ const dirPath = expandedPath.endsWith('/')
971
+ ? expandedPath.slice(0, -1)
972
+ : expandedPath
939
973
  finalPath = join(dirPath, currentFileName)
940
974
  } else {
941
975
  finalPath = expandedPath
942
976
  }
943
977
 
944
978
  if (finalPath === config.database) {
945
- console.log(info('Location unchanged'))
979
+ console.log(uiInfo('Location unchanged'))
946
980
  return await handleEditContainer(containerName)
947
981
  }
948
982
 
949
983
  // Check if source file exists
950
984
  if (!existsSync(config.database)) {
951
- console.log(error(`Source file not found: ${config.database}`))
985
+ console.log(uiError(`Source file not found: ${config.database}`))
952
986
  return await handleEditContainer(containerName)
953
987
  }
954
988
 
955
989
  // Check if destination already exists
956
990
  if (existsSync(finalPath)) {
957
- console.log(error(`Destination file already exists: ${finalPath}`))
991
+ console.log(uiError(`Destination file already exists: ${finalPath}`))
958
992
  return await handleEditContainer(containerName)
959
993
  }
960
994
 
961
995
  // Check if destination directory exists
962
996
  const destDir = dirname(finalPath)
963
997
  if (!existsSync(destDir)) {
964
- console.log(warning(`Directory does not exist: ${destDir}`))
998
+ console.log(uiWarning(`Directory does not exist: ${destDir}`))
965
999
  const { createDir } = await inquirer.prompt<{ createDir: string }>([
966
1000
  {
967
1001
  type: 'list',
@@ -980,9 +1014,13 @@ async function handleEditContainer(
980
1014
 
981
1015
  try {
982
1016
  mkdirSync(destDir, { recursive: true })
983
- console.log(success(`Created directory: ${destDir}`))
984
- } catch (err) {
985
- console.log(error(`Failed to create directory: ${(err as Error).message}`))
1017
+ console.log(uiSuccess(`Created directory: ${destDir}`))
1018
+ } catch (mkdirError) {
1019
+ console.log(
1020
+ uiError(
1021
+ `Failed to create directory: ${(mkdirError as Error).message}`,
1022
+ ),
1023
+ )
986
1024
  return await handleEditContainer(containerName)
987
1025
  }
988
1026
  }
@@ -1020,15 +1058,17 @@ async function handleEditContainer(
1020
1058
  }
1021
1059
 
1022
1060
  // Update the container config and SQLite registry
1023
- await containerManager.updateConfig(containerName, { database: finalPath })
1061
+ await containerManager.updateConfig(containerName, {
1062
+ database: finalPath,
1063
+ })
1024
1064
  await sqliteRegistry.update(containerName, { filePath: finalPath })
1025
1065
  spinner.succeed(`Moved database to ${finalPath}`)
1026
1066
 
1027
1067
  // Wait for user to see success message before refreshing
1028
1068
  await pressEnterToContinue()
1029
- } catch (err) {
1069
+ } catch (error) {
1030
1070
  spinner.fail('Failed to move database file')
1031
- console.log(error((err as Error).message))
1071
+ console.log(uiError((error as Error).message))
1032
1072
  await pressEnterToContinue()
1033
1073
  }
1034
1074
 
@@ -1045,7 +1085,7 @@ async function handleCloneFromSubmenu(
1045
1085
  ): Promise<void> {
1046
1086
  const sourceConfig = await containerManager.getConfig(sourceName)
1047
1087
  if (!sourceConfig) {
1048
- console.log(error(`Container "${sourceName}" not found`))
1088
+ console.log(uiError(`Container "${sourceName}" not found`))
1049
1089
  return
1050
1090
  }
1051
1091
 
@@ -1066,8 +1106,10 @@ async function handleCloneFromSubmenu(
1066
1106
  ])
1067
1107
 
1068
1108
  // Check if target container already exists
1069
- if (await containerManager.exists(targetName, { engine: sourceConfig.engine })) {
1070
- console.log(error(`Container "${targetName}" already exists`))
1109
+ if (
1110
+ await containerManager.exists(targetName, { engine: sourceConfig.engine })
1111
+ ) {
1112
+ console.log(uiError(`Container "${targetName}" already exists`))
1071
1113
  return
1072
1114
  }
1073
1115
 
@@ -1086,9 +1128,9 @@ async function handleCloneFromSubmenu(
1086
1128
  console.log(connectionBox(targetName, connectionString, newConfig.port))
1087
1129
 
1088
1130
  await showContainerSubmenu(targetName, showMainMenu)
1089
- } catch (err) {
1131
+ } catch (error) {
1090
1132
  spinner.fail(`Failed to clone "${sourceName}"`)
1091
- console.log(error((err as Error).message))
1133
+ console.log(uiError((error as Error).message))
1092
1134
  await pressEnterToContinue()
1093
1135
  }
1094
1136
  }
@@ -1096,7 +1138,7 @@ async function handleCloneFromSubmenu(
1096
1138
  async function handleDelete(containerName: string): Promise<void> {
1097
1139
  const config = await containerManager.getConfig(containerName)
1098
1140
  if (!config) {
1099
- console.error(error(`Container "${containerName}" not found`))
1141
+ console.error(uiError(`Container "${containerName}" not found`))
1100
1142
  return
1101
1143
  }
1102
1144
 
@@ -1106,7 +1148,7 @@ async function handleDelete(containerName: string): Promise<void> {
1106
1148
  )
1107
1149
 
1108
1150
  if (!confirmed) {
1109
- console.log(warning('Deletion cancelled'))
1151
+ console.log(uiWarning('Deletion cancelled'))
1110
1152
  return
1111
1153
  }
1112
1154
 
@@ -4,7 +4,7 @@ import { rm } from 'fs/promises'
4
4
  import { containerManager } from '../../../core/container-manager'
5
5
  import { processManager } from '../../../core/process-manager'
6
6
  import { createSpinner } from '../../ui/spinner'
7
- import { header, error, warning, info, formatBytes } from '../../ui/theme'
7
+ import { header, uiError, uiWarning, uiInfo, formatBytes } from '../../ui/theme'
8
8
  import { promptConfirm } from '../../ui/prompts'
9
9
  import { getEngineIcon, ENGINE_ICONS } from '../../constants'
10
10
  import {
@@ -37,7 +37,7 @@ export async function handleEngines(): Promise<void> {
37
37
  const engines = await getInstalledEngines()
38
38
 
39
39
  if (engines.length === 0) {
40
- console.log(info('No engines installed yet.'))
40
+ console.log(uiInfo('No engines installed yet.'))
41
41
  console.log(
42
42
  chalk.gray(
43
43
  ' PostgreSQL engines are downloaded automatically when you create a container.',
@@ -128,7 +128,9 @@ export async function handleEngines(): Promise<void> {
128
128
  console.log(chalk.gray(` MySQL: system-installed at ${mysqlEngine.path}`))
129
129
  }
130
130
  if (sqliteEngine) {
131
- console.log(chalk.gray(` SQLite: system-installed at ${sqliteEngine.path}`))
131
+ console.log(
132
+ chalk.gray(` SQLite: system-installed at ${sqliteEngine.path}`),
133
+ )
132
134
  }
133
135
  console.log()
134
136
 
@@ -212,7 +214,7 @@ async function handleDeleteEngine(
212
214
  if (usingContainers.length > 0) {
213
215
  console.log()
214
216
  console.log(
215
- error(
217
+ uiError(
216
218
  `Cannot delete: ${usingContainers.length} container(s) are using ${engineName} ${engineVersion}`,
217
219
  ),
218
220
  )
@@ -238,7 +240,7 @@ async function handleDeleteEngine(
238
240
  )
239
241
 
240
242
  if (!confirmed) {
241
- console.log(warning('Deletion cancelled'))
243
+ console.log(uiWarning('Deletion cancelled'))
242
244
  return
243
245
  }
244
246
 
@@ -248,8 +250,8 @@ async function handleDeleteEngine(
248
250
  try {
249
251
  await rm(enginePath, { recursive: true, force: true })
250
252
  spinner.succeed(`Deleted ${engineName} ${engineVersion}`)
251
- } catch (err) {
252
- const e = err as Error
253
+ } catch (error) {
254
+ const e = error as Error
253
255
  spinner.fail(`Failed to delete: ${e.message}`)
254
256
  }
255
257
  }
@@ -272,7 +274,7 @@ async function handleMysqlInfo(mysqldPath: string): Promise<void> {
272
274
 
273
275
  if (mysqlContainers.length > 0) {
274
276
  console.log(
275
- warning(
277
+ uiWarning(
276
278
  `${mysqlContainers.length} container(s) are using ${displayName}:`,
277
279
  ),
278
280
  )
@@ -438,7 +440,9 @@ async function handleSqliteInfo(sqlitePath: string): Promise<void> {
438
440
  const sqliteContainers = containers.filter((c) => c.engine === 'sqlite')
439
441
 
440
442
  if (sqliteContainers.length > 0) {
441
- console.log(info(`${sqliteContainers.length} SQLite database(s) registered:`))
443
+ console.log(
444
+ uiInfo(`${sqliteContainers.length} SQLite database(s) registered:`),
445
+ )
442
446
  console.log()
443
447
  for (const c of sqliteContainers) {
444
448
  const status =
@@ -471,9 +475,15 @@ async function handleSqliteInfo(sqlitePath: string): Promise<void> {
471
475
 
472
476
  console.log(chalk.white(' Notes:'))
473
477
  console.log(chalk.gray(' ' + '─'.repeat(50)))
474
- console.log(chalk.gray(' • SQLite is typically pre-installed on macOS and most Linux distributions'))
478
+ console.log(
479
+ chalk.gray(
480
+ ' • SQLite is typically pre-installed on macOS and most Linux distributions',
481
+ ),
482
+ )
475
483
  console.log(chalk.gray(' • No server process - databases are just files'))
476
- console.log(chalk.gray(' • Use "spindb delete <name>" to unregister a database'))
484
+ console.log(
485
+ chalk.gray(' • Use "spindb delete <name>" to unregister a database'),
486
+ )
477
487
  console.log()
478
488
 
479
489
  await inquirer.prompt([
@@ -3,7 +3,7 @@ import chalk from 'chalk'
3
3
  import inquirer from 'inquirer'
4
4
  import { containerManager } from '../../../core/container-manager'
5
5
  import { promptInstallDependencies } from '../../ui/prompts'
6
- import { header, error } from '../../ui/theme'
6
+ import { header, uiError } from '../../ui/theme'
7
7
  import { getInstalledEngines } from '../../helpers'
8
8
  import {
9
9
  handleCreate,
@@ -156,8 +156,8 @@ export const menuCommand = new Command('menu')
156
156
  .action(async () => {
157
157
  try {
158
158
  await showMainMenu()
159
- } catch (err) {
160
- const e = err as Error
159
+ } catch (error) {
160
+ const e = error as Error
161
161
 
162
162
  // Check if this is a missing tool error
163
163
  if (
@@ -177,7 +177,7 @@ export const menuCommand = new Command('menu')
177
177
  process.exit(1)
178
178
  }
179
179
 
180
- console.error(error(e.message))
180
+ console.error(uiError(e.message))
181
181
  process.exit(1)
182
182
  }
183
183
  })