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
@@ -20,7 +20,7 @@ import {
20
20
  import { platformService } from '../../../core/platform-service'
21
21
  import { getEngine } from '../../../engines'
22
22
  import { createSpinner } from '../../ui/spinner'
23
- import { error, warning, info, success } from '../../ui/theme'
23
+ import { uiError, uiWarning, uiInfo, uiSuccess } from '../../ui/theme'
24
24
  import { pressEnterToContinue } from './shared'
25
25
 
26
26
  export async function handleCopyConnectionString(
@@ -28,7 +28,7 @@ export async function handleCopyConnectionString(
28
28
  ): Promise<void> {
29
29
  const config = await containerManager.getConfig(containerName)
30
30
  if (!config) {
31
- console.error(error(`Container "${containerName}" not found`))
31
+ console.error(uiError(`Container "${containerName}" not found`))
32
32
  return
33
33
  }
34
34
 
@@ -39,10 +39,10 @@ export async function handleCopyConnectionString(
39
39
 
40
40
  console.log()
41
41
  if (copied) {
42
- console.log(success('Connection string copied to clipboard'))
42
+ console.log(uiSuccess('Connection string copied to clipboard'))
43
43
  console.log(chalk.gray(` ${connectionString}`))
44
44
  } else {
45
- console.log(warning('Could not copy to clipboard. Connection string:'))
45
+ console.log(uiWarning('Could not copy to clipboard. Connection string:'))
46
46
  console.log(chalk.cyan(` ${connectionString}`))
47
47
  }
48
48
  console.log()
@@ -59,7 +59,7 @@ export async function handleCopyConnectionString(
59
59
  export async function handleOpenShell(containerName: string): Promise<void> {
60
60
  const config = await containerManager.getConfig(containerName)
61
61
  if (!config) {
62
- console.error(error(`Container "${containerName}" not found`))
62
+ console.error(uiError(`Container "${containerName}" not found`))
63
63
  return
64
64
  }
65
65
 
@@ -69,12 +69,13 @@ export async function handleOpenShell(containerName: string): Promise<void> {
69
69
  const shellCheckSpinner = createSpinner('Checking available shells...')
70
70
  shellCheckSpinner.start()
71
71
 
72
- const [usqlInstalled, pgcliInstalled, mycliInstalled, litecliInstalled] = await Promise.all([
73
- isUsqlInstalled(),
74
- isPgcliInstalled(),
75
- isMycliInstalled(),
76
- isLitecliInstalled(),
77
- ])
72
+ const [usqlInstalled, pgcliInstalled, mycliInstalled, litecliInstalled] =
73
+ await Promise.all([
74
+ isUsqlInstalled(),
75
+ isPgcliInstalled(),
76
+ isMycliInstalled(),
77
+ isLitecliInstalled(),
78
+ ])
78
79
 
79
80
  shellCheckSpinner.stop()
80
81
  // Clear the spinner line
@@ -119,7 +120,9 @@ export async function handleOpenShell(containerName: string): Promise<void> {
119
120
  engineSpecificInstallValue = 'install-pgcli'
120
121
  }
121
122
 
122
- const choices: Array<{ name: string; value: ShellChoice } | inquirer.Separator> = [
123
+ const choices: Array<
124
+ { name: string; value: ShellChoice } | inquirer.Separator
125
+ > = [
123
126
  {
124
127
  name: `>_ Use default shell (${defaultShellName})`,
125
128
  value: 'default',
@@ -173,16 +176,16 @@ export async function handleOpenShell(containerName: string): Promise<void> {
173
176
 
174
177
  if (shellChoice === 'install-pgcli') {
175
178
  console.log()
176
- console.log(info('Installing pgcli for enhanced PostgreSQL shell...'))
179
+ console.log(uiInfo('Installing pgcli for enhanced PostgreSQL shell...'))
177
180
  const pm = await detectPackageManager()
178
181
  if (pm) {
179
182
  const result = await installPgcli(pm)
180
183
  if (result.success) {
181
- console.log(success('pgcli installed successfully!'))
184
+ console.log(uiSuccess('pgcli installed successfully!'))
182
185
  console.log()
183
186
  await launchShell(containerName, config, connectionString, 'pgcli')
184
187
  } else {
185
- console.error(error(`Failed to install pgcli: ${result.error}`))
188
+ console.error(uiError(`Failed to install pgcli: ${result.error}`))
186
189
  console.log()
187
190
  console.log(chalk.gray('Manual installation:'))
188
191
  for (const instruction of getPgcliManualInstructions()) {
@@ -192,7 +195,7 @@ export async function handleOpenShell(containerName: string): Promise<void> {
192
195
  await pressEnterToContinue()
193
196
  }
194
197
  } else {
195
- console.error(error('No supported package manager found'))
198
+ console.error(uiError('No supported package manager found'))
196
199
  console.log()
197
200
  console.log(chalk.gray('Manual installation:'))
198
201
  for (const instruction of getPgcliManualInstructions()) {
@@ -206,16 +209,16 @@ export async function handleOpenShell(containerName: string): Promise<void> {
206
209
 
207
210
  if (shellChoice === 'install-mycli') {
208
211
  console.log()
209
- console.log(info('Installing mycli for enhanced MySQL shell...'))
212
+ console.log(uiInfo('Installing mycli for enhanced MySQL shell...'))
210
213
  const pm = await detectPackageManager()
211
214
  if (pm) {
212
215
  const result = await installMycli(pm)
213
216
  if (result.success) {
214
- console.log(success('mycli installed successfully!'))
217
+ console.log(uiSuccess('mycli installed successfully!'))
215
218
  console.log()
216
219
  await launchShell(containerName, config, connectionString, 'mycli')
217
220
  } else {
218
- console.error(error(`Failed to install mycli: ${result.error}`))
221
+ console.error(uiError(`Failed to install mycli: ${result.error}`))
219
222
  console.log()
220
223
  console.log(chalk.gray('Manual installation:'))
221
224
  for (const instruction of getMycliManualInstructions()) {
@@ -225,7 +228,7 @@ export async function handleOpenShell(containerName: string): Promise<void> {
225
228
  await pressEnterToContinue()
226
229
  }
227
230
  } else {
228
- console.error(error('No supported package manager found'))
231
+ console.error(uiError('No supported package manager found'))
229
232
  console.log()
230
233
  console.log(chalk.gray('Manual installation:'))
231
234
  for (const instruction of getMycliManualInstructions()) {
@@ -239,16 +242,16 @@ export async function handleOpenShell(containerName: string): Promise<void> {
239
242
 
240
243
  if (shellChoice === 'install-usql') {
241
244
  console.log()
242
- console.log(info('Installing usql for enhanced shell experience...'))
245
+ console.log(uiInfo('Installing usql for enhanced shell experience...'))
243
246
  const pm = await detectPackageManager()
244
247
  if (pm) {
245
248
  const result = await installUsql(pm)
246
249
  if (result.success) {
247
- console.log(success('usql installed successfully!'))
250
+ console.log(uiSuccess('usql installed successfully!'))
248
251
  console.log()
249
252
  await launchShell(containerName, config, connectionString, 'usql')
250
253
  } else {
251
- console.error(error(`Failed to install usql: ${result.error}`))
254
+ console.error(uiError(`Failed to install usql: ${result.error}`))
252
255
  console.log()
253
256
  console.log(chalk.gray('Manual installation:'))
254
257
  for (const instruction of getUsqlManualInstructions()) {
@@ -258,7 +261,7 @@ export async function handleOpenShell(containerName: string): Promise<void> {
258
261
  await pressEnterToContinue()
259
262
  }
260
263
  } else {
261
- console.error(error('No supported package manager found'))
264
+ console.error(uiError('No supported package manager found'))
262
265
  console.log()
263
266
  console.log(chalk.gray('Manual installation:'))
264
267
  for (const instruction of getUsqlManualInstructions()) {
@@ -272,16 +275,16 @@ export async function handleOpenShell(containerName: string): Promise<void> {
272
275
 
273
276
  if (shellChoice === 'install-litecli') {
274
277
  console.log()
275
- console.log(info('Installing litecli for enhanced SQLite shell...'))
278
+ console.log(uiInfo('Installing litecli for enhanced SQLite shell...'))
276
279
  const pm = await detectPackageManager()
277
280
  if (pm) {
278
281
  const result = await installLitecli(pm)
279
282
  if (result.success) {
280
- console.log(success('litecli installed successfully!'))
283
+ console.log(uiSuccess('litecli installed successfully!'))
281
284
  console.log()
282
285
  await launchShell(containerName, config, connectionString, 'litecli')
283
286
  } else {
284
- console.error(error(`Failed to install litecli: ${result.error}`))
287
+ console.error(uiError(`Failed to install litecli: ${result.error}`))
285
288
  console.log()
286
289
  console.log(chalk.gray('Manual installation:'))
287
290
  for (const instruction of getLitecliManualInstructions()) {
@@ -291,7 +294,7 @@ export async function handleOpenShell(containerName: string): Promise<void> {
291
294
  await pressEnterToContinue()
292
295
  }
293
296
  } else {
294
- console.error(error('No supported package manager found'))
297
+ console.error(uiError('No supported package manager found'))
295
298
  console.log()
296
299
  console.log(chalk.gray('Manual installation:'))
297
300
  for (const instruction of getLitecliManualInstructions()) {
@@ -312,7 +315,7 @@ async function launchShell(
312
315
  connectionString: string,
313
316
  shellType: 'default' | 'usql' | 'pgcli' | 'mycli' | 'litecli',
314
317
  ): Promise<void> {
315
- console.log(info(`Connecting to ${containerName}...`))
318
+ console.log(uiInfo(`Connecting to ${containerName}...`))
316
319
  console.log()
317
320
 
318
321
  let shellCmd: string
@@ -386,7 +389,7 @@ async function launchShell(
386
389
 
387
390
  shellProcess.on('error', (err: NodeJS.ErrnoException) => {
388
391
  if (err.code === 'ENOENT') {
389
- console.log(warning(`${shellCmd} not found on your system.`))
392
+ console.log(uiWarning(`${shellCmd} not found on your system.`))
390
393
  console.log()
391
394
  console.log(chalk.gray(' Connect manually with:'))
392
395
  console.log(chalk.cyan(` ${connectionString}`))
@@ -394,7 +397,7 @@ async function launchShell(
394
397
  console.log(chalk.gray(` Install ${shellCmd}:`))
395
398
  console.log(chalk.cyan(` ${installHint}`))
396
399
  } else {
397
- console.log(error(`Failed to start ${shellCmd}: ${err.message}`))
400
+ console.log(uiError(`Failed to start ${shellCmd}: ${err.message}`))
398
401
  }
399
402
  settle()
400
403
  })
@@ -7,14 +7,17 @@ import { containerManager } from '../../../core/container-manager'
7
7
  import { getMissingDependencies } from '../../../core/dependency-manager'
8
8
  import { getEngine } from '../../../engines'
9
9
  import { paths } from '../../../config/paths'
10
- import { promptInstallDependencies, promptDatabaseSelect } from '../../ui/prompts'
11
- import { error, warning, info, success } from '../../ui/theme'
10
+ import {
11
+ promptInstallDependencies,
12
+ promptDatabaseSelect,
13
+ } from '../../ui/prompts'
14
+ import { uiError, uiWarning, uiInfo, uiSuccess } from '../../ui/theme'
12
15
  import { pressEnterToContinue } from './shared'
13
16
 
14
17
  export async function handleRunSql(containerName: string): Promise<void> {
15
18
  const config = await containerManager.getConfig(containerName)
16
19
  if (!config) {
17
- console.error(error(`Container "${containerName}" not found`))
20
+ console.error(uiError(`Container "${containerName}" not found`))
18
21
  return
19
22
  }
20
23
 
@@ -23,7 +26,7 @@ export async function handleRunSql(containerName: string): Promise<void> {
23
26
  let missingDeps = await getMissingDependencies(config.engine)
24
27
  if (missingDeps.length > 0) {
25
28
  console.log(
26
- warning(`Missing tools: ${missingDeps.map((d) => d.name).join(', ')}`),
29
+ uiWarning(`Missing tools: ${missingDeps.map((d) => d.name).join(', ')}`),
27
30
  )
28
31
 
29
32
  const installed = await promptInstallDependencies(
@@ -38,7 +41,7 @@ export async function handleRunSql(containerName: string): Promise<void> {
38
41
  missingDeps = await getMissingDependencies(config.engine)
39
42
  if (missingDeps.length > 0) {
40
43
  console.log(
41
- error(
44
+ uiError(
42
45
  `Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
43
46
  ),
44
47
  )
@@ -50,11 +53,14 @@ export async function handleRunSql(containerName: string): Promise<void> {
50
53
  }
51
54
 
52
55
  // Strip quotes that terminals add when drag-and-dropping files
53
- const stripQuotes = (path: string) =>
54
- path.replace(/^['"]|['"]$/g, '').trim()
56
+ const stripQuotes = (path: string) => path.replace(/^['"]|['"]$/g, '').trim()
55
57
 
56
58
  // Prompt for file path (empty input = go back)
57
- console.log(chalk.gray(' Drag & drop, enter path (abs or rel), or press Enter to go back'))
59
+ console.log(
60
+ chalk.gray(
61
+ ' Drag & drop, enter path (abs or rel), or press Enter to go back',
62
+ ),
63
+ )
58
64
  const { filePath: rawFilePath } = await inquirer.prompt<{
59
65
  filePath: string
60
66
  }>([
@@ -90,7 +96,7 @@ export async function handleRunSql(containerName: string): Promise<void> {
90
96
  }
91
97
 
92
98
  console.log()
93
- console.log(info(`Running SQL file against "${databaseName}"...`))
99
+ console.log(uiInfo(`Running SQL file against "${databaseName}"...`))
94
100
  console.log()
95
101
 
96
102
  try {
@@ -99,11 +105,11 @@ export async function handleRunSql(containerName: string): Promise<void> {
99
105
  database: databaseName,
100
106
  })
101
107
  console.log()
102
- console.log(success('SQL file executed successfully'))
103
- } catch (err) {
104
- const e = err as Error
108
+ console.log(uiSuccess('SQL file executed successfully'))
109
+ } catch (error) {
110
+ const e = error as Error
105
111
  console.log()
106
- console.log(error(`SQL execution failed: ${e.message}`))
112
+ console.log(uiError(`SQL execution failed: ${e.message}`))
107
113
  }
108
114
 
109
115
  console.log()
@@ -116,7 +122,7 @@ export async function handleRunSql(containerName: string): Promise<void> {
116
122
  export async function handleViewLogs(containerName: string): Promise<void> {
117
123
  const config = await containerManager.getConfig(containerName)
118
124
  if (!config) {
119
- console.error(error(`Container "${containerName}" not found`))
125
+ console.error(uiError(`Container "${containerName}" not found`))
120
126
  return
121
127
  }
122
128
 
@@ -126,7 +132,7 @@ export async function handleViewLogs(containerName: string): Promise<void> {
126
132
 
127
133
  if (!existsSync(logPath)) {
128
134
  console.log(
129
- info(
135
+ uiInfo(
130
136
  `No log file found for "${containerName}". The container may not have been started yet.`,
131
137
  ),
132
138
  )
@@ -194,7 +200,7 @@ export async function handleViewLogs(containerName: string): Promise<void> {
194
200
  const lineCount = action === 'tail-100' ? 100 : 50
195
201
  const content = await readFile(logPath, 'utf-8')
196
202
  if (content.trim() === '') {
197
- console.log(info('Log file is empty'))
203
+ console.log(uiInfo('Log file is empty'))
198
204
  } else {
199
205
  const lines = content.split('\n')
200
206
  const nonEmptyLines =
@@ -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,7 +11,7 @@ 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'
@@ -50,11 +50,13 @@ export const restoreCommand = new Command('restore')
50
50
  if (running.length === 0) {
51
51
  if (containers.length === 0) {
52
52
  console.log(
53
- warning('No containers found. Create one with: spindb create'),
53
+ uiWarning(
54
+ 'No containers found. Create one with: spindb create',
55
+ ),
54
56
  )
55
57
  } else {
56
58
  console.log(
57
- warning(
59
+ uiWarning(
58
60
  'No running containers. Start one first with: spindb start',
59
61
  ),
60
62
  )
@@ -72,7 +74,7 @@ export const restoreCommand = new Command('restore')
72
74
 
73
75
  const config = await containerManager.getConfig(containerName)
74
76
  if (!config) {
75
- console.error(error(`Container "${containerName}" not found`))
77
+ console.error(uiError(`Container "${containerName}" not found`))
76
78
  process.exit(1)
77
79
  }
78
80
 
@@ -83,7 +85,7 @@ export const restoreCommand = new Command('restore')
83
85
  })
84
86
  if (!running) {
85
87
  console.error(
86
- error(
88
+ uiError(
87
89
  `Container "${containerName}" is not running. Start it first.`,
88
90
  ),
89
91
  )
@@ -113,7 +115,7 @@ export const restoreCommand = new Command('restore')
113
115
  missingDeps = await getMissingDependencies(config.engine)
114
116
  if (missingDeps.length > 0) {
115
117
  console.error(
116
- error(
118
+ uiError(
117
119
  `Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
118
120
  ),
119
121
  )
@@ -134,7 +136,7 @@ export const restoreCommand = new Command('restore')
134
136
 
135
137
  if (engineName === 'postgresql' && !isPgUrl) {
136
138
  console.error(
137
- error(
139
+ uiError(
138
140
  'Connection string must start with postgresql:// or postgres:// for PostgreSQL containers',
139
141
  ),
140
142
  )
@@ -143,7 +145,7 @@ export const restoreCommand = new Command('restore')
143
145
 
144
146
  if (engineName === 'mysql' && !isMysqlUrl) {
145
147
  console.error(
146
- error(
148
+ uiError(
147
149
  'Connection string must start with mysql:// for MySQL containers',
148
150
  ),
149
151
  )
@@ -152,7 +154,7 @@ export const restoreCommand = new Command('restore')
152
154
 
153
155
  if (!isPgUrl && !isMysqlUrl) {
154
156
  console.error(
155
- error(
157
+ uiError(
156
158
  'Connection string must start with postgresql://, postgres://, or mysql://',
157
159
  ),
158
160
  )
@@ -181,8 +183,8 @@ export const restoreCommand = new Command('restore')
181
183
  dumpSpinner.succeed('Dump created from remote database')
182
184
  backupPath = tempDumpPath
183
185
  dumpSuccess = true
184
- } catch (err) {
185
- const e = err as Error
186
+ } catch (error) {
187
+ const e = error as Error
186
188
  dumpSpinner.fail('Failed to create dump')
187
189
 
188
190
  const dumpTool = engineName === 'mysql' ? 'mysqldump' : 'pg_dump'
@@ -201,19 +203,19 @@ export const restoreCommand = new Command('restore')
201
203
  }
202
204
 
203
205
  console.log()
204
- console.error(error(`${dumpTool} error:`))
206
+ console.error(uiError(`${dumpTool} error:`))
205
207
  console.log(chalk.gray(` ${e.message}`))
206
208
  process.exit(1)
207
209
  }
208
210
  }
209
211
 
210
212
  if (!dumpSuccess) {
211
- console.error(error('Failed to create dump after retries'))
213
+ console.error(uiError('Failed to create dump after retries'))
212
214
  process.exit(1)
213
215
  }
214
216
  } else {
215
217
  if (!backupPath) {
216
- console.error(error('Backup file path is required'))
218
+ console.error(uiError('Backup file path is required'))
217
219
  console.log(
218
220
  chalk.gray(' Usage: spindb restore <container> <backup-file>'),
219
221
  )
@@ -226,7 +228,7 @@ export const restoreCommand = new Command('restore')
226
228
  }
227
229
 
228
230
  if (!existsSync(backupPath)) {
229
- console.error(error(`Backup file not found: ${backupPath}`))
231
+ console.error(uiError(`Backup file not found: ${backupPath}`))
230
232
  process.exit(1)
231
233
  }
232
234
  }
@@ -237,7 +239,7 @@ export const restoreCommand = new Command('restore')
237
239
  }
238
240
 
239
241
  if (!backupPath) {
240
- console.error(error('No backup path specified'))
242
+ console.error(uiError('No backup path specified'))
241
243
  process.exit(1)
242
244
  }
243
245
 
@@ -347,7 +349,7 @@ export const restoreCommand = new Command('restore')
347
349
  databaseName,
348
350
  )
349
351
  console.log()
350
- console.log(success(`Database "${databaseName}" restored`))
352
+ console.log(uiSuccess(`Database "${databaseName}" restored`))
351
353
  console.log()
352
354
  console.log(chalk.gray(' Connection string:'))
353
355
  console.log(chalk.cyan(` ${connectionString}`))
@@ -365,8 +367,8 @@ export const restoreCommand = new Command('restore')
365
367
  chalk.cyan(` spindb connect ${containerName} -d ${databaseName}`),
366
368
  )
367
369
  console.log()
368
- } catch (err) {
369
- const e = err as Error
370
+ } catch (error) {
371
+ const e = error as Error
370
372
 
371
373
  const missingToolPatterns = [
372
374
  'pg_restore not found',
@@ -391,7 +393,7 @@ export const restoreCommand = new Command('restore')
391
393
  process.exit(1)
392
394
  }
393
395
 
394
- console.error(error(e.message))
396
+ console.error(uiError(e.message))
395
397
  process.exit(1)
396
398
  } finally {
397
399
  if (tempDumpPath) {