spindb 0.7.3 → 0.7.5
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.
- package/cli/commands/backup.ts +1 -30
- package/cli/commands/clone.ts +0 -6
- package/cli/commands/connect.ts +0 -16
- package/cli/commands/create.ts +4 -55
- package/cli/commands/delete.ts +0 -6
- package/cli/commands/edit.ts +0 -26
- package/cli/commands/info.ts +0 -20
- package/cli/commands/list.ts +0 -9
- package/cli/commands/logs.ts +0 -12
- package/cli/commands/menu/backup-handlers.ts +14 -63
- package/cli/commands/menu/container-handlers.ts +30 -37
- package/cli/commands/menu/engine-handlers.ts +0 -20
- package/cli/commands/menu/index.ts +2 -7
- package/cli/commands/menu/shell-handlers.ts +0 -11
- package/cli/commands/menu/sql-handlers.ts +0 -3
- package/cli/commands/restore.ts +2 -28
- package/cli/commands/run.ts +0 -11
- package/cli/commands/start.ts +2 -10
- package/cli/commands/stop.ts +0 -5
- package/cli/commands/url.ts +0 -9
- package/package.json +1 -1
package/cli/commands/edit.ts
CHANGED
|
@@ -8,16 +8,10 @@ import { promptContainerSelect } from '../ui/prompts'
|
|
|
8
8
|
import { createSpinner } from '../ui/spinner'
|
|
9
9
|
import { error, warning, success } from '../ui/theme'
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Validate container name format
|
|
13
|
-
*/
|
|
14
11
|
function isValidName(name: string): boolean {
|
|
15
12
|
return /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
/**
|
|
19
|
-
* Prompt for what to edit when no options provided
|
|
20
|
-
*/
|
|
21
15
|
async function promptEditAction(): Promise<'name' | 'port' | null> {
|
|
22
16
|
const { action } = await inquirer.prompt<{ action: string }>([
|
|
23
17
|
{
|
|
@@ -36,9 +30,6 @@ async function promptEditAction(): Promise<'name' | 'port' | null> {
|
|
|
36
30
|
return action as 'name' | 'port'
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
/**
|
|
40
|
-
* Prompt for new container name
|
|
41
|
-
*/
|
|
42
33
|
async function promptNewName(currentName: string): Promise<string | null> {
|
|
43
34
|
const { newName } = await inquirer.prompt<{ newName: string }>([
|
|
44
35
|
{
|
|
@@ -64,9 +55,6 @@ async function promptNewName(currentName: string): Promise<string | null> {
|
|
|
64
55
|
return newName
|
|
65
56
|
}
|
|
66
57
|
|
|
67
|
-
/**
|
|
68
|
-
* Prompt for new port
|
|
69
|
-
*/
|
|
70
58
|
async function promptNewPort(currentPort: number): Promise<number | null> {
|
|
71
59
|
const { newPort } = await inquirer.prompt<{ newPort: number }>([
|
|
72
60
|
{
|
|
@@ -90,7 +78,6 @@ async function promptNewPort(currentPort: number): Promise<number | null> {
|
|
|
90
78
|
return null
|
|
91
79
|
}
|
|
92
80
|
|
|
93
|
-
// Double-check availability and warn (user already confirmed via validation)
|
|
94
81
|
const portAvailable = await portManager.isPortAvailable(newPort)
|
|
95
82
|
if (!portAvailable) {
|
|
96
83
|
console.log(
|
|
@@ -116,7 +103,6 @@ export const editCommand = new Command('edit')
|
|
|
116
103
|
try {
|
|
117
104
|
let containerName = name
|
|
118
105
|
|
|
119
|
-
// Interactive selection if no name provided
|
|
120
106
|
if (!containerName) {
|
|
121
107
|
const containers = await containerManager.list()
|
|
122
108
|
|
|
@@ -133,14 +119,12 @@ export const editCommand = new Command('edit')
|
|
|
133
119
|
containerName = selected
|
|
134
120
|
}
|
|
135
121
|
|
|
136
|
-
// Get container config
|
|
137
122
|
const config = await containerManager.getConfig(containerName)
|
|
138
123
|
if (!config) {
|
|
139
124
|
console.error(error(`Container "${containerName}" not found`))
|
|
140
125
|
process.exit(1)
|
|
141
126
|
}
|
|
142
127
|
|
|
143
|
-
// If no options provided, prompt for what to edit
|
|
144
128
|
if (options.name === undefined && options.port === undefined) {
|
|
145
129
|
const action = await promptEditAction()
|
|
146
130
|
if (!action) return
|
|
@@ -162,9 +146,7 @@ export const editCommand = new Command('edit')
|
|
|
162
146
|
}
|
|
163
147
|
}
|
|
164
148
|
|
|
165
|
-
// Handle rename
|
|
166
149
|
if (options.name) {
|
|
167
|
-
// Validate new name
|
|
168
150
|
if (!isValidName(options.name)) {
|
|
169
151
|
console.error(
|
|
170
152
|
error(
|
|
@@ -174,7 +156,6 @@ export const editCommand = new Command('edit')
|
|
|
174
156
|
process.exit(1)
|
|
175
157
|
}
|
|
176
158
|
|
|
177
|
-
// Check if new name already exists
|
|
178
159
|
const exists = await containerManager.exists(options.name, {
|
|
179
160
|
engine: config.engine,
|
|
180
161
|
})
|
|
@@ -183,7 +164,6 @@ export const editCommand = new Command('edit')
|
|
|
183
164
|
process.exit(1)
|
|
184
165
|
}
|
|
185
166
|
|
|
186
|
-
// Check if container is running
|
|
187
167
|
const running = await processManager.isRunning(containerName, {
|
|
188
168
|
engine: config.engine,
|
|
189
169
|
})
|
|
@@ -196,7 +176,6 @@ export const editCommand = new Command('edit')
|
|
|
196
176
|
process.exit(1)
|
|
197
177
|
}
|
|
198
178
|
|
|
199
|
-
// Rename the container
|
|
200
179
|
const spinner = createSpinner(
|
|
201
180
|
`Renaming "${containerName}" to "${options.name}"...`,
|
|
202
181
|
)
|
|
@@ -206,19 +185,15 @@ export const editCommand = new Command('edit')
|
|
|
206
185
|
|
|
207
186
|
spinner.succeed(`Renamed "${containerName}" to "${options.name}"`)
|
|
208
187
|
|
|
209
|
-
// Update containerName for subsequent operations
|
|
210
188
|
containerName = options.name
|
|
211
189
|
}
|
|
212
190
|
|
|
213
|
-
// Handle port change
|
|
214
191
|
if (options.port !== undefined) {
|
|
215
|
-
// Validate port
|
|
216
192
|
if (options.port < 1 || options.port > 65535) {
|
|
217
193
|
console.error(error('Port must be between 1 and 65535'))
|
|
218
194
|
process.exit(1)
|
|
219
195
|
}
|
|
220
196
|
|
|
221
|
-
// Check port availability (warning only)
|
|
222
197
|
const portAvailable = await portManager.isPortAvailable(options.port)
|
|
223
198
|
if (!portAvailable) {
|
|
224
199
|
console.log(
|
|
@@ -228,7 +203,6 @@ export const editCommand = new Command('edit')
|
|
|
228
203
|
)
|
|
229
204
|
}
|
|
230
205
|
|
|
231
|
-
// Update the config
|
|
232
206
|
const spinner = createSpinner(`Changing port to ${options.port}...`)
|
|
233
207
|
spinner.start()
|
|
234
208
|
|
package/cli/commands/info.ts
CHANGED
|
@@ -9,17 +9,11 @@ import { error, info, header } from '../ui/theme'
|
|
|
9
9
|
import { getEngineIcon } from '../constants'
|
|
10
10
|
import type { ContainerConfig } from '../../types'
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Format a date for display
|
|
14
|
-
*/
|
|
15
12
|
function formatDate(dateString: string): string {
|
|
16
13
|
const date = new Date(dateString)
|
|
17
14
|
return date.toLocaleString()
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
/**
|
|
21
|
-
* Get actual running status (not just config status)
|
|
22
|
-
*/
|
|
23
17
|
async function getActualStatus(
|
|
24
18
|
config: ContainerConfig,
|
|
25
19
|
): Promise<'running' | 'stopped'> {
|
|
@@ -29,9 +23,6 @@ async function getActualStatus(
|
|
|
29
23
|
return running ? 'running' : 'stopped'
|
|
30
24
|
}
|
|
31
25
|
|
|
32
|
-
/**
|
|
33
|
-
* Display info for a single container
|
|
34
|
-
*/
|
|
35
26
|
async function displayContainerInfo(
|
|
36
27
|
config: ContainerConfig,
|
|
37
28
|
options: { json?: boolean },
|
|
@@ -109,15 +100,11 @@ async function displayContainerInfo(
|
|
|
109
100
|
console.log()
|
|
110
101
|
}
|
|
111
102
|
|
|
112
|
-
/**
|
|
113
|
-
* Display summary info for all containers
|
|
114
|
-
*/
|
|
115
103
|
async function displayAllContainersInfo(
|
|
116
104
|
containers: ContainerConfig[],
|
|
117
105
|
options: { json?: boolean },
|
|
118
106
|
): Promise<void> {
|
|
119
107
|
if (options.json) {
|
|
120
|
-
// Get actual status for all containers
|
|
121
108
|
const containersWithStatus = await Promise.all(
|
|
122
109
|
containers.map(async (config) => {
|
|
123
110
|
const actualStatus = await getActualStatus(config)
|
|
@@ -142,7 +129,6 @@ async function displayAllContainersInfo(
|
|
|
142
129
|
console.log(header('All Containers'))
|
|
143
130
|
console.log()
|
|
144
131
|
|
|
145
|
-
// Table header
|
|
146
132
|
console.log(
|
|
147
133
|
chalk.gray(' ') +
|
|
148
134
|
chalk.bold.white('NAME'.padEnd(18)) +
|
|
@@ -154,7 +140,6 @@ async function displayAllContainersInfo(
|
|
|
154
140
|
)
|
|
155
141
|
console.log(chalk.gray(' ' + '─'.repeat(78)))
|
|
156
142
|
|
|
157
|
-
// Table rows
|
|
158
143
|
for (const container of containers) {
|
|
159
144
|
const actualStatus = await getActualStatus(container)
|
|
160
145
|
const statusDisplay =
|
|
@@ -178,7 +163,6 @@ async function displayAllContainersInfo(
|
|
|
178
163
|
|
|
179
164
|
console.log()
|
|
180
165
|
|
|
181
|
-
// Summary
|
|
182
166
|
const statusChecks = await Promise.all(
|
|
183
167
|
containers.map((c) => getActualStatus(c)),
|
|
184
168
|
)
|
|
@@ -192,7 +176,6 @@ async function displayAllContainersInfo(
|
|
|
192
176
|
)
|
|
193
177
|
console.log()
|
|
194
178
|
|
|
195
|
-
// Connection strings
|
|
196
179
|
console.log(chalk.bold.white(' Connection Strings:'))
|
|
197
180
|
console.log(chalk.gray(' ' + '─'.repeat(78)))
|
|
198
181
|
for (const container of containers) {
|
|
@@ -221,7 +204,6 @@ export const infoCommand = new Command('info')
|
|
|
221
204
|
return
|
|
222
205
|
}
|
|
223
206
|
|
|
224
|
-
// If name provided, show single container
|
|
225
207
|
if (name) {
|
|
226
208
|
const config = await containerManager.getConfig(name)
|
|
227
209
|
if (!config) {
|
|
@@ -232,7 +214,6 @@ export const infoCommand = new Command('info')
|
|
|
232
214
|
return
|
|
233
215
|
}
|
|
234
216
|
|
|
235
|
-
// If running interactively without name, ask if they want all or specific
|
|
236
217
|
if (!options.json && process.stdout.isTTY && containers.length > 1) {
|
|
237
218
|
const { choice } = await inquirer.prompt<{
|
|
238
219
|
choice: string
|
|
@@ -262,7 +243,6 @@ export const infoCommand = new Command('info')
|
|
|
262
243
|
return
|
|
263
244
|
}
|
|
264
245
|
|
|
265
|
-
// Non-interactive or only one container: show all
|
|
266
246
|
await displayAllContainersInfo(containers, options)
|
|
267
247
|
} catch (err) {
|
|
268
248
|
const e = err as Error
|
package/cli/commands/list.ts
CHANGED
|
@@ -6,9 +6,6 @@ import { info, error, formatBytes } from '../ui/theme'
|
|
|
6
6
|
import { getEngineIcon } from '../constants'
|
|
7
7
|
import type { ContainerConfig } from '../../types'
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Get database size for a container (only if running)
|
|
11
|
-
*/
|
|
12
9
|
async function getContainerSize(
|
|
13
10
|
container: ContainerConfig,
|
|
14
11
|
): Promise<number | null> {
|
|
@@ -32,7 +29,6 @@ export const listCommand = new Command('list')
|
|
|
32
29
|
const containers = await containerManager.list()
|
|
33
30
|
|
|
34
31
|
if (options.json) {
|
|
35
|
-
// Include sizes in JSON output
|
|
36
32
|
const containersWithSize = await Promise.all(
|
|
37
33
|
containers.map(async (container) => ({
|
|
38
34
|
...container,
|
|
@@ -48,10 +44,8 @@ export const listCommand = new Command('list')
|
|
|
48
44
|
return
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
// Fetch sizes for running containers in parallel
|
|
52
47
|
const sizes = await Promise.all(containers.map(getContainerSize))
|
|
53
48
|
|
|
54
|
-
// Table header
|
|
55
49
|
console.log()
|
|
56
50
|
console.log(
|
|
57
51
|
chalk.gray(' ') +
|
|
@@ -64,7 +58,6 @@ export const listCommand = new Command('list')
|
|
|
64
58
|
)
|
|
65
59
|
console.log(chalk.gray(' ' + '─'.repeat(73)))
|
|
66
60
|
|
|
67
|
-
// Table rows
|
|
68
61
|
for (let i = 0; i < containers.length; i++) {
|
|
69
62
|
const container = containers[i]
|
|
70
63
|
const size = sizes[i]
|
|
@@ -77,7 +70,6 @@ export const listCommand = new Command('list')
|
|
|
77
70
|
const engineIcon = getEngineIcon(container.engine)
|
|
78
71
|
const engineDisplay = `${engineIcon} ${container.engine}`
|
|
79
72
|
|
|
80
|
-
// Format size: show value if running, dash if stopped
|
|
81
73
|
const sizeDisplay = size !== null ? formatBytes(size) : chalk.gray('—')
|
|
82
74
|
|
|
83
75
|
console.log(
|
|
@@ -93,7 +85,6 @@ export const listCommand = new Command('list')
|
|
|
93
85
|
|
|
94
86
|
console.log()
|
|
95
87
|
|
|
96
|
-
// Summary
|
|
97
88
|
const running = containers.filter((c) => c.status === 'running').length
|
|
98
89
|
const stopped = containers.filter((c) => c.status !== 'running').length
|
|
99
90
|
console.log(
|
package/cli/commands/logs.ts
CHANGED
|
@@ -7,12 +7,8 @@ import { paths } from '../../config/paths'
|
|
|
7
7
|
import { promptContainerSelect } from '../ui/prompts'
|
|
8
8
|
import { error, warning, info } from '../ui/theme'
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Get the last N lines from a file content
|
|
12
|
-
*/
|
|
13
10
|
function getLastNLines(content: string, n: number): string {
|
|
14
11
|
const lines = content.split('\n')
|
|
15
|
-
// Filter empty trailing line if present
|
|
16
12
|
const nonEmptyLines =
|
|
17
13
|
lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines
|
|
18
14
|
return nonEmptyLines.slice(-n).join('\n')
|
|
@@ -32,7 +28,6 @@ export const logsCommand = new Command('logs')
|
|
|
32
28
|
try {
|
|
33
29
|
let containerName = name
|
|
34
30
|
|
|
35
|
-
// Interactive selection if no name provided
|
|
36
31
|
if (!containerName) {
|
|
37
32
|
const containers = await containerManager.list()
|
|
38
33
|
|
|
@@ -49,19 +44,16 @@ export const logsCommand = new Command('logs')
|
|
|
49
44
|
containerName = selected
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
// Get container config
|
|
53
47
|
const config = await containerManager.getConfig(containerName)
|
|
54
48
|
if (!config) {
|
|
55
49
|
console.error(error(`Container "${containerName}" not found`))
|
|
56
50
|
process.exit(1)
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
// Get log file path
|
|
60
53
|
const logPath = paths.getContainerLogPath(config.name, {
|
|
61
54
|
engine: config.engine,
|
|
62
55
|
})
|
|
63
56
|
|
|
64
|
-
// Check if log file exists
|
|
65
57
|
if (!existsSync(logPath)) {
|
|
66
58
|
console.log(
|
|
67
59
|
info(
|
|
@@ -71,7 +63,6 @@ export const logsCommand = new Command('logs')
|
|
|
71
63
|
return
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
// Open in editor if requested
|
|
75
66
|
if (options.editor) {
|
|
76
67
|
const editorCmd = process.env.EDITOR || 'vi'
|
|
77
68
|
const child = spawn(editorCmd, [logPath], {
|
|
@@ -91,14 +82,12 @@ export const logsCommand = new Command('logs')
|
|
|
91
82
|
return
|
|
92
83
|
}
|
|
93
84
|
|
|
94
|
-
// Follow mode using tail -f
|
|
95
85
|
if (options.follow) {
|
|
96
86
|
const lineCount = parseInt(options.lines || '50', 10)
|
|
97
87
|
const child = spawn('tail', ['-n', String(lineCount), '-f', logPath], {
|
|
98
88
|
stdio: 'inherit',
|
|
99
89
|
})
|
|
100
90
|
|
|
101
|
-
// Handle SIGINT gracefully
|
|
102
91
|
process.on('SIGINT', () => {
|
|
103
92
|
child.kill('SIGTERM')
|
|
104
93
|
process.exit(0)
|
|
@@ -110,7 +99,6 @@ export const logsCommand = new Command('logs')
|
|
|
110
99
|
return
|
|
111
100
|
}
|
|
112
101
|
|
|
113
|
-
// Default: read and output last N lines
|
|
114
102
|
const lineCount = parseInt(options.lines || '50', 10)
|
|
115
103
|
const content = await readFile(logPath, 'utf-8')
|
|
116
104
|
|