spindb 0.9.0 → 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 (49) hide show
  1. package/README.md +7 -0
  2. package/cli/commands/backup.ts +13 -11
  3. package/cli/commands/clone.ts +18 -8
  4. package/cli/commands/config.ts +29 -29
  5. package/cli/commands/connect.ts +51 -39
  6. package/cli/commands/create.ts +120 -43
  7. package/cli/commands/delete.ts +8 -8
  8. package/cli/commands/deps.ts +17 -15
  9. package/cli/commands/doctor.ts +16 -15
  10. package/cli/commands/edit.ts +115 -60
  11. package/cli/commands/engines.ts +50 -17
  12. package/cli/commands/info.ts +12 -8
  13. package/cli/commands/list.ts +34 -19
  14. package/cli/commands/logs.ts +24 -14
  15. package/cli/commands/menu/backup-handlers.ts +72 -49
  16. package/cli/commands/menu/container-handlers.ts +140 -80
  17. package/cli/commands/menu/engine-handlers.ts +145 -11
  18. package/cli/commands/menu/index.ts +4 -4
  19. package/cli/commands/menu/shell-handlers.ts +34 -31
  20. package/cli/commands/menu/sql-handlers.ts +22 -16
  21. package/cli/commands/menu/update-handlers.ts +19 -17
  22. package/cli/commands/restore.ts +105 -43
  23. package/cli/commands/run.ts +20 -18
  24. package/cli/commands/self-update.ts +5 -5
  25. package/cli/commands/start.ts +11 -9
  26. package/cli/commands/stop.ts +9 -9
  27. package/cli/commands/url.ts +12 -9
  28. package/cli/helpers.ts +49 -4
  29. package/cli/ui/prompts.ts +21 -8
  30. package/cli/ui/spinner.ts +4 -4
  31. package/cli/ui/theme.ts +4 -4
  32. package/core/binary-manager.ts +5 -1
  33. package/core/container-manager.ts +81 -30
  34. package/core/error-handler.ts +31 -0
  35. package/core/platform-service.ts +3 -3
  36. package/core/port-manager.ts +2 -0
  37. package/core/process-manager.ts +25 -3
  38. package/core/start-with-retry.ts +6 -6
  39. package/core/transaction-manager.ts +6 -6
  40. package/engines/mysql/backup.ts +53 -36
  41. package/engines/mysql/index.ts +59 -16
  42. package/engines/mysql/restore.ts +4 -4
  43. package/engines/mysql/version-validator.ts +2 -2
  44. package/engines/postgresql/binary-manager.ts +17 -17
  45. package/engines/postgresql/index.ts +13 -2
  46. package/engines/postgresql/restore.ts +2 -2
  47. package/engines/postgresql/version-validator.ts +2 -2
  48. package/engines/sqlite/index.ts +31 -9
  49. package/package.json +1 -1
@@ -9,7 +9,7 @@ import { paths } from '../../../config/paths'
9
9
  import { getSupportedEngines } from '../../../config/engine-defaults'
10
10
  import { checkEngineDependencies } from '../../../core/dependency-manager'
11
11
  import { createSpinner } from '../../ui/spinner'
12
- import { header, success, error, warning, info } from '../../ui/theme'
12
+ import { header, uiSuccess, uiError, uiWarning, uiInfo } from '../../ui/theme'
13
13
  import { pressEnterToContinue } from './shared'
14
14
  import { Engine } from '../../../types'
15
15
 
@@ -26,7 +26,7 @@ export async function handleCheckUpdate(): Promise<void> {
26
26
  if (!result) {
27
27
  spinner.fail('Could not reach npm registry')
28
28
  console.log()
29
- console.log(info('Check your internet connection and try again.'))
29
+ console.log(uiInfo('Check your internet connection and try again.'))
30
30
  console.log(chalk.gray(' Manual update: npm install -g spindb@latest'))
31
31
  console.log()
32
32
  await pressEnterToContinue()
@@ -66,27 +66,29 @@ export async function handleCheckUpdate(): Promise<void> {
66
66
  updateSpinner.succeed('Update complete')
67
67
  console.log()
68
68
  console.log(
69
- success(
69
+ uiSuccess(
70
70
  `Updated from ${updateResult.previousVersion} to ${updateResult.newVersion}`,
71
71
  ),
72
72
  )
73
73
  console.log()
74
74
  if (updateResult.previousVersion !== updateResult.newVersion) {
75
- console.log(warning('Please restart spindb to use the new version.'))
75
+ console.log(
76
+ uiWarning('Please restart spindb to use the new version.'),
77
+ )
76
78
  console.log()
77
79
  }
78
80
  } else {
79
81
  updateSpinner.fail('Update failed')
80
82
  console.log()
81
- console.log(error(updateResult.error || 'Unknown error'))
83
+ console.log(uiError(updateResult.error || 'Unknown error'))
82
84
  console.log()
83
- console.log(info('Manual update: npm install -g spindb@latest'))
85
+ console.log(uiInfo('Manual update: npm install -g spindb@latest'))
84
86
  }
85
87
  await pressEnterToContinue()
86
88
  } else if (action === 'disable') {
87
89
  await updateManager.setAutoCheckEnabled(false)
88
90
  console.log()
89
- console.log(info('Update checks disabled on startup.'))
91
+ console.log(uiInfo('Update checks disabled on startup.'))
90
92
  console.log(chalk.gray(' Re-enable with: spindb config update-check on'))
91
93
  console.log()
92
94
  await pressEnterToContinue()
@@ -138,7 +140,7 @@ async function checkConfiguration(): Promise<HealthCheckResult> {
138
140
  label: 'Refresh binary cache',
139
141
  handler: async () => {
140
142
  await configManager.refreshAllBinaries()
141
- console.log(success('Binary cache refreshed'))
143
+ console.log(uiSuccess('Binary cache refreshed'))
142
144
  },
143
145
  },
144
146
  }
@@ -150,12 +152,12 @@ async function checkConfiguration(): Promise<HealthCheckResult> {
150
152
  message: 'Configuration valid',
151
153
  details: [`Binary tools cached: ${binaryCount}`],
152
154
  }
153
- } catch (err) {
155
+ } catch (error) {
154
156
  return {
155
157
  name: 'Configuration',
156
158
  status: 'error',
157
159
  message: 'Configuration file is corrupted',
158
- details: [(err as Error).message],
160
+ details: [(error as Error).message],
159
161
  }
160
162
  }
161
163
  }
@@ -199,12 +201,12 @@ async function checkContainers(): Promise<HealthCheckResult> {
199
201
  message: `${containers.length} container(s)`,
200
202
  details,
201
203
  }
202
- } catch (err) {
204
+ } catch (error) {
203
205
  return {
204
206
  name: 'Containers',
205
207
  status: 'error',
206
208
  message: 'Failed to list containers',
207
- details: [(err as Error).message],
209
+ details: [(error as Error).message],
208
210
  }
209
211
  }
210
212
  }
@@ -233,7 +235,7 @@ async function checkSqliteRegistry(): Promise<HealthCheckResult> {
233
235
  label: 'Remove orphaned entries from registry',
234
236
  handler: async () => {
235
237
  const count = await sqliteRegistry.removeOrphans()
236
- console.log(success(`Removed ${count} orphaned entries`))
238
+ console.log(uiSuccess(`Removed ${count} orphaned entries`))
237
239
  },
238
240
  },
239
241
  }
@@ -244,12 +246,12 @@ async function checkSqliteRegistry(): Promise<HealthCheckResult> {
244
246
  status: 'ok',
245
247
  message: `${entries.length} database(s) registered, all files exist`,
246
248
  }
247
- } catch (err) {
249
+ } catch (error) {
248
250
  return {
249
251
  name: 'SQLite Registry',
250
252
  status: 'warning',
251
253
  message: 'Could not check registry',
252
- details: [(err as Error).message],
254
+ details: [(error as Error).message],
253
255
  }
254
256
  }
255
257
  }
@@ -279,12 +281,12 @@ async function checkBinaries(): Promise<HealthCheckResult> {
279
281
  message: hasWarning ? 'Some tools missing' : 'All tools available',
280
282
  details: results,
281
283
  }
282
- } catch (err) {
284
+ } catch (error) {
283
285
  return {
284
286
  name: 'Database Tools',
285
287
  status: 'error',
286
288
  message: 'Failed to check tools',
287
- details: [(err as Error).message],
289
+ details: [(error as Error).message],
288
290
  }
289
291
  }
290
292
  }
@@ -11,11 +11,13 @@ import {
11
11
  promptInstallDependencies,
12
12
  } from '../ui/prompts'
13
13
  import { createSpinner } from '../ui/spinner'
14
- import { success, error, warning } from '../ui/theme'
14
+ import { uiSuccess, uiError, uiWarning } from '../ui/theme'
15
15
  import { tmpdir } from 'os'
16
16
  import { join } from 'path'
17
17
  import { getMissingDependencies } from '../../core/dependency-manager'
18
18
  import { platformService } from '../../core/platform-service'
19
+ import { TransactionManager } from '../../core/transaction-manager'
20
+ import { logDebug } from '../../core/error-handler'
19
21
 
20
22
  export const restoreCommand = new Command('restore')
21
23
  .description('Restore a backup to a container')
@@ -48,11 +50,13 @@ export const restoreCommand = new Command('restore')
48
50
  if (running.length === 0) {
49
51
  if (containers.length === 0) {
50
52
  console.log(
51
- warning('No containers found. Create one with: spindb create'),
53
+ uiWarning(
54
+ 'No containers found. Create one with: spindb create',
55
+ ),
52
56
  )
53
57
  } else {
54
58
  console.log(
55
- warning(
59
+ uiWarning(
56
60
  'No running containers. Start one first with: spindb start',
57
61
  ),
58
62
  )
@@ -70,7 +74,7 @@ export const restoreCommand = new Command('restore')
70
74
 
71
75
  const config = await containerManager.getConfig(containerName)
72
76
  if (!config) {
73
- console.error(error(`Container "${containerName}" not found`))
77
+ console.error(uiError(`Container "${containerName}" not found`))
74
78
  process.exit(1)
75
79
  }
76
80
 
@@ -81,7 +85,7 @@ export const restoreCommand = new Command('restore')
81
85
  })
82
86
  if (!running) {
83
87
  console.error(
84
- error(
88
+ uiError(
85
89
  `Container "${containerName}" is not running. Start it first.`,
86
90
  ),
87
91
  )
@@ -111,7 +115,7 @@ export const restoreCommand = new Command('restore')
111
115
  missingDeps = await getMissingDependencies(config.engine)
112
116
  if (missingDeps.length > 0) {
113
117
  console.error(
114
- error(
118
+ uiError(
115
119
  `Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
116
120
  ),
117
121
  )
@@ -132,7 +136,7 @@ export const restoreCommand = new Command('restore')
132
136
 
133
137
  if (engineName === 'postgresql' && !isPgUrl) {
134
138
  console.error(
135
- error(
139
+ uiError(
136
140
  'Connection string must start with postgresql:// or postgres:// for PostgreSQL containers',
137
141
  ),
138
142
  )
@@ -141,7 +145,7 @@ export const restoreCommand = new Command('restore')
141
145
 
142
146
  if (engineName === 'mysql' && !isMysqlUrl) {
143
147
  console.error(
144
- error(
148
+ uiError(
145
149
  'Connection string must start with mysql:// for MySQL containers',
146
150
  ),
147
151
  )
@@ -150,7 +154,7 @@ export const restoreCommand = new Command('restore')
150
154
 
151
155
  if (!isPgUrl && !isMysqlUrl) {
152
156
  console.error(
153
- error(
157
+ uiError(
154
158
  'Connection string must start with postgresql://, postgres://, or mysql://',
155
159
  ),
156
160
  )
@@ -179,8 +183,8 @@ export const restoreCommand = new Command('restore')
179
183
  dumpSpinner.succeed('Dump created from remote database')
180
184
  backupPath = tempDumpPath
181
185
  dumpSuccess = true
182
- } catch (err) {
183
- const e = err as Error
186
+ } catch (error) {
187
+ const e = error as Error
184
188
  dumpSpinner.fail('Failed to create dump')
185
189
 
186
190
  const dumpTool = engineName === 'mysql' ? 'mysqldump' : 'pg_dump'
@@ -199,19 +203,19 @@ export const restoreCommand = new Command('restore')
199
203
  }
200
204
 
201
205
  console.log()
202
- console.error(error(`${dumpTool} error:`))
206
+ console.error(uiError(`${dumpTool} error:`))
203
207
  console.log(chalk.gray(` ${e.message}`))
204
208
  process.exit(1)
205
209
  }
206
210
  }
207
211
 
208
212
  if (!dumpSuccess) {
209
- console.error(error('Failed to create dump after retries'))
213
+ console.error(uiError('Failed to create dump after retries'))
210
214
  process.exit(1)
211
215
  }
212
216
  } else {
213
217
  if (!backupPath) {
214
- console.error(error('Backup file path is required'))
218
+ console.error(uiError('Backup file path is required'))
215
219
  console.log(
216
220
  chalk.gray(' Usage: spindb restore <container> <backup-file>'),
217
221
  )
@@ -224,7 +228,7 @@ export const restoreCommand = new Command('restore')
224
228
  }
225
229
 
226
230
  if (!existsSync(backupPath)) {
227
- console.error(error(`Backup file not found: ${backupPath}`))
231
+ console.error(uiError(`Backup file not found: ${backupPath}`))
228
232
  process.exit(1)
229
233
  }
230
234
  }
@@ -235,7 +239,7 @@ export const restoreCommand = new Command('restore')
235
239
  }
236
240
 
237
241
  if (!backupPath) {
238
- console.error(error('No backup path specified'))
242
+ console.error(uiError('No backup path specified'))
239
243
  process.exit(1)
240
244
  }
241
245
 
@@ -245,41 +249,99 @@ export const restoreCommand = new Command('restore')
245
249
  const format = await engine.detectBackupFormat(backupPath)
246
250
  detectSpinner.succeed(`Detected: ${format.description}`)
247
251
 
252
+ // Use TransactionManager to ensure database is cleaned up on restore failure
253
+ const tx = new TransactionManager()
254
+ let databaseCreated = false
255
+
248
256
  const dbSpinner = createSpinner(
249
257
  `Creating database "${databaseName}"...`,
250
258
  )
251
259
  dbSpinner.start()
252
260
 
253
- await engine.createDatabase(config, databaseName)
254
- dbSpinner.succeed(`Database "${databaseName}" ready`)
261
+ try {
262
+ await engine.createDatabase(config, databaseName)
263
+ databaseCreated = true
264
+ dbSpinner.succeed(`Database "${databaseName}" ready`)
265
+
266
+ // Register rollback to drop database if restore fails
267
+ tx.addRollback({
268
+ description: `Drop database "${databaseName}"`,
269
+ execute: async () => {
270
+ try {
271
+ await engine.dropDatabase(config, databaseName)
272
+ logDebug(`Rolled back: dropped database "${databaseName}"`)
273
+ } catch (dropErr) {
274
+ logDebug(
275
+ `Failed to drop database during rollback: ${dropErr instanceof Error ? dropErr.message : String(dropErr)}`,
276
+ )
277
+ }
278
+ },
279
+ })
280
+
281
+ await containerManager.addDatabase(containerName, databaseName)
282
+
283
+ // Register rollback to remove database from container tracking
284
+ tx.addRollback({
285
+ description: `Remove "${databaseName}" from container tracking`,
286
+ execute: async () => {
287
+ try {
288
+ await containerManager.removeDatabase(
289
+ containerName,
290
+ databaseName,
291
+ )
292
+ logDebug(
293
+ `Rolled back: removed "${databaseName}" from container tracking`,
294
+ )
295
+ } catch (removeErr) {
296
+ logDebug(
297
+ `Failed to remove database from tracking during rollback: ${removeErr instanceof Error ? removeErr.message : String(removeErr)}`,
298
+ )
299
+ }
300
+ },
301
+ })
255
302
 
256
- await containerManager.addDatabase(containerName, databaseName)
303
+ const restoreSpinner = createSpinner('Restoring backup...')
304
+ restoreSpinner.start()
257
305
 
258
- const restoreSpinner = createSpinner('Restoring backup...')
259
- restoreSpinner.start()
306
+ const result = await engine.restore(config, backupPath, {
307
+ database: databaseName,
308
+ createDatabase: false,
309
+ })
260
310
 
261
- const result = await engine.restore(config, backupPath, {
262
- database: databaseName,
263
- createDatabase: false,
264
- })
311
+ // Check if restore completely failed (non-zero code with no data restored)
312
+ if (result.code !== 0 && result.stderr?.includes('FATAL')) {
313
+ restoreSpinner.fail('Restore failed')
314
+ throw new Error(result.stderr || 'Restore failed with fatal error')
315
+ }
265
316
 
266
- if (result.code === 0 || !result.stderr) {
267
- restoreSpinner.succeed('Backup restored successfully')
268
- } else {
269
- // pg_restore often returns warnings even on success
270
- restoreSpinner.warn('Restore completed with warnings')
271
- if (result.stderr) {
272
- console.log(chalk.yellow('\n Warnings:'))
273
- const lines = result.stderr.split('\n').slice(0, 5)
274
- lines.forEach((line) => {
275
- if (line.trim()) {
276
- console.log(chalk.gray(` ${line}`))
317
+ if (result.code === 0) {
318
+ restoreSpinner.succeed('Backup restored successfully')
319
+ } else {
320
+ // pg_restore often returns warnings even on success
321
+ restoreSpinner.warn('Restore completed with warnings')
322
+ if (result.stderr) {
323
+ console.log(chalk.yellow('\n Warnings:'))
324
+ const lines = result.stderr.split('\n').slice(0, 5)
325
+ lines.forEach((line) => {
326
+ if (line.trim()) {
327
+ console.log(chalk.gray(` ${line}`))
328
+ }
329
+ })
330
+ if (result.stderr.split('\n').length > 5) {
331
+ console.log(chalk.gray(' ...'))
277
332
  }
278
- })
279
- if (result.stderr.split('\n').length > 5) {
280
- console.log(chalk.gray(' ...'))
281
333
  }
282
334
  }
335
+
336
+ // Restore succeeded - commit transaction (clear rollback actions)
337
+ tx.commit()
338
+ } catch (restoreErr) {
339
+ // Restore failed - execute rollbacks to clean up created database
340
+ if (databaseCreated) {
341
+ console.log(chalk.yellow('\n Cleaning up after failed restore...'))
342
+ await tx.rollback()
343
+ }
344
+ throw restoreErr
283
345
  }
284
346
 
285
347
  const connectionString = engine.getConnectionString(
@@ -287,7 +349,7 @@ export const restoreCommand = new Command('restore')
287
349
  databaseName,
288
350
  )
289
351
  console.log()
290
- console.log(success(`Database "${databaseName}" restored`))
352
+ console.log(uiSuccess(`Database "${databaseName}" restored`))
291
353
  console.log()
292
354
  console.log(chalk.gray(' Connection string:'))
293
355
  console.log(chalk.cyan(` ${connectionString}`))
@@ -305,8 +367,8 @@ export const restoreCommand = new Command('restore')
305
367
  chalk.cyan(` spindb connect ${containerName} -d ${databaseName}`),
306
368
  )
307
369
  console.log()
308
- } catch (err) {
309
- const e = err as Error
370
+ } catch (error) {
371
+ const e = error as Error
310
372
 
311
373
  const missingToolPatterns = [
312
374
  'pg_restore not found',
@@ -331,7 +393,7 @@ export const restoreCommand = new Command('restore')
331
393
  process.exit(1)
332
394
  }
333
395
 
334
- console.error(error(e.message))
396
+ console.error(uiError(e.message))
335
397
  process.exit(1)
336
398
  } finally {
337
399
  if (tempDumpPath) {
@@ -5,7 +5,7 @@ import { containerManager } from '../../core/container-manager'
5
5
  import { processManager } from '../../core/process-manager'
6
6
  import { getEngine } from '../../engines'
7
7
  import { promptInstallDependencies } from '../ui/prompts'
8
- import { error, warning } from '../ui/theme'
8
+ import { uiError, uiWarning } from '../ui/theme'
9
9
  import { getMissingDependencies } from '../../core/dependency-manager'
10
10
  import { Engine } from '../../types'
11
11
 
@@ -26,7 +26,7 @@ export const runCommand = new Command('run')
26
26
 
27
27
  const config = await containerManager.getConfig(containerName)
28
28
  if (!config) {
29
- console.error(error(`Container "${containerName}" not found`))
29
+ console.error(uiError(`Container "${containerName}" not found`))
30
30
  process.exit(1)
31
31
  }
32
32
 
@@ -36,9 +36,7 @@ export const runCommand = new Command('run')
36
36
  if (engineName === Engine.SQLite) {
37
37
  if (!existsSync(config.database)) {
38
38
  console.error(
39
- error(
40
- `SQLite database file not found: ${config.database}`,
41
- ),
39
+ uiError(`SQLite database file not found: ${config.database}`),
42
40
  )
43
41
  process.exit(1)
44
42
  }
@@ -49,7 +47,7 @@ export const runCommand = new Command('run')
49
47
  })
50
48
  if (!running) {
51
49
  console.error(
52
- error(
50
+ uiError(
53
51
  `Container "${containerName}" is not running. Start it first with: spindb start ${containerName}`,
54
52
  ),
55
53
  )
@@ -59,16 +57,16 @@ export const runCommand = new Command('run')
59
57
 
60
58
  if (file && options.sql) {
61
59
  console.error(
62
- error('Cannot specify both a file and --sql option. Choose one.'),
60
+ uiError('Cannot specify both a file and --sql option. Choose one.'),
63
61
  )
64
62
  process.exit(1)
65
63
  }
66
64
 
67
65
  if (!file && !options.sql) {
68
- console.error(error('Must provide either a SQL file or --sql option'))
69
- console.log(
70
- chalk.gray(' Usage: spindb run <container> <file.sql>'),
66
+ console.error(
67
+ uiError('Must provide either a SQL file or --sql option'),
71
68
  )
69
+ console.log(chalk.gray(' Usage: spindb run <container> <file.sql>'))
72
70
  console.log(
73
71
  chalk.gray(' or: spindb run <container> --sql "SELECT ..."'),
74
72
  )
@@ -76,7 +74,7 @@ export const runCommand = new Command('run')
76
74
  }
77
75
 
78
76
  if (file && !existsSync(file)) {
79
- console.error(error(`SQL file not found: ${file}`))
77
+ console.error(uiError(`SQL file not found: ${file}`))
80
78
  process.exit(1)
81
79
  }
82
80
 
@@ -85,7 +83,7 @@ export const runCommand = new Command('run')
85
83
  let missingDeps = await getMissingDependencies(engineName)
86
84
  if (missingDeps.length > 0) {
87
85
  console.log(
88
- warning(
86
+ uiWarning(
89
87
  `Missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
90
88
  ),
91
89
  )
@@ -102,7 +100,7 @@ export const runCommand = new Command('run')
102
100
  missingDeps = await getMissingDependencies(engineName)
103
101
  if (missingDeps.length > 0) {
104
102
  console.error(
105
- error(
103
+ uiError(
106
104
  `Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
107
105
  ),
108
106
  )
@@ -120,8 +118,8 @@ export const runCommand = new Command('run')
120
118
  sql: options.sql,
121
119
  database,
122
120
  })
123
- } catch (err) {
124
- const e = err as Error
121
+ } catch (error) {
122
+ const e = error as Error
125
123
 
126
124
  const missingToolPatterns = [
127
125
  'psql not found',
@@ -138,8 +136,12 @@ export const runCommand = new Command('run')
138
136
  .replace(' not found', '')
139
137
  .replace(' client', '')
140
138
  // Determine engine from the missing tool name
141
- const toolEngine = missingTool === 'mysql' ? Engine.MySQL : Engine.PostgreSQL
142
- const installed = await promptInstallDependencies(missingTool, toolEngine)
139
+ const toolEngine =
140
+ missingTool === 'mysql' ? Engine.MySQL : Engine.PostgreSQL
141
+ const installed = await promptInstallDependencies(
142
+ missingTool,
143
+ toolEngine,
144
+ )
143
145
  if (installed) {
144
146
  console.log(
145
147
  chalk.yellow(' Please re-run your command to continue.'),
@@ -148,7 +150,7 @@ export const runCommand = new Command('run')
148
150
  process.exit(1)
149
151
  }
150
152
 
151
- console.error(error(e.message))
153
+ console.error(uiError(e.message))
152
154
  process.exit(1)
153
155
  }
154
156
  },
@@ -3,7 +3,7 @@ import chalk from 'chalk'
3
3
  import inquirer from 'inquirer'
4
4
  import { updateManager } from '../../core/update-manager'
5
5
  import { createSpinner } from '../ui/spinner'
6
- import { success, error, info, header } from '../ui/theme'
6
+ import { uiSuccess, uiError, uiInfo, header } from '../ui/theme'
7
7
 
8
8
  export const selfUpdateCommand = new Command('self-update')
9
9
  .alias('update')
@@ -24,7 +24,7 @@ export const selfUpdateCommand = new Command('self-update')
24
24
  if (!result) {
25
25
  checkSpinner.fail('Could not reach npm registry')
26
26
  console.log()
27
- console.log(info('Check your internet connection and try again.'))
27
+ console.log(uiInfo('Check your internet connection and try again.'))
28
28
  console.log(chalk.gray(' Manual update: npm install -g spindb@latest'))
29
29
  process.exit(1)
30
30
  }
@@ -84,7 +84,7 @@ export const selfUpdateCommand = new Command('self-update')
84
84
  updateSpinner.succeed('Update complete')
85
85
  console.log()
86
86
  console.log(
87
- success(
87
+ uiSuccess(
88
88
  `Updated from ${updateResult.previousVersion} to ${updateResult.newVersion}`,
89
89
  ),
90
90
  )
@@ -100,9 +100,9 @@ export const selfUpdateCommand = new Command('self-update')
100
100
  } else {
101
101
  updateSpinner.fail('Update failed')
102
102
  console.log()
103
- console.log(error(updateResult.error || 'Unknown error'))
103
+ console.log(uiError(updateResult.error || 'Unknown error'))
104
104
  console.log()
105
- console.log(info('Manual update: npm install -g spindb@latest'))
105
+ console.log(uiInfo('Manual update: npm install -g spindb@latest'))
106
106
  process.exit(1)
107
107
  }
108
108
  },
@@ -7,7 +7,7 @@ import { getEngine } from '../../engines'
7
7
  import { getEngineDefaults } from '../../config/defaults'
8
8
  import { promptContainerSelect } from '../ui/prompts'
9
9
  import { createSpinner } from '../ui/spinner'
10
- import { error, warning } from '../ui/theme'
10
+ import { uiError, uiWarning } from '../ui/theme'
11
11
 
12
12
  export const startCommand = new Command('start')
13
13
  .description('Start a container')
@@ -23,10 +23,10 @@ export const startCommand = new Command('start')
23
23
  if (stopped.length === 0) {
24
24
  if (containers.length === 0) {
25
25
  console.log(
26
- warning('No containers found. Create one with: spindb create'),
26
+ uiWarning('No containers found. Create one with: spindb create'),
27
27
  )
28
28
  } else {
29
- console.log(warning('All containers are already running'))
29
+ console.log(uiWarning('All containers are already running'))
30
30
  }
31
31
  return
32
32
  }
@@ -41,7 +41,7 @@ export const startCommand = new Command('start')
41
41
 
42
42
  const config = await containerManager.getConfig(containerName)
43
43
  if (!config) {
44
- console.error(error(`Container "${containerName}" not found`))
44
+ console.error(uiError(`Container "${containerName}" not found`))
45
45
  process.exit(1)
46
46
  }
47
47
 
@@ -51,7 +51,9 @@ export const startCommand = new Command('start')
51
51
  engine: engineName,
52
52
  })
53
53
  if (running) {
54
- console.log(warning(`Container "${containerName}" is already running`))
54
+ console.log(
55
+ uiWarning(`Container "${containerName}" is already running`),
56
+ )
55
57
  return
56
58
  }
57
59
 
@@ -72,7 +74,7 @@ export const startCommand = new Command('start')
72
74
  if (!result.success) {
73
75
  spinner.fail(`Failed to start "${containerName}"`)
74
76
  if (result.error) {
75
- console.error(error(result.error.message))
77
+ console.error(uiError(result.error.message))
76
78
  }
77
79
  process.exit(1)
78
80
  }
@@ -110,9 +112,9 @@ export const startCommand = new Command('start')
110
112
  console.log(chalk.gray(' Connect with:'))
111
113
  console.log(chalk.cyan(` spindb connect ${containerName}`))
112
114
  console.log()
113
- } catch (err) {
114
- const e = err as Error
115
- console.error(error(e.message))
115
+ } catch (error) {
116
+ const e = error as Error
117
+ console.error(uiError(e.message))
116
118
  process.exit(1)
117
119
  }
118
120
  })