sealos-cli 1.1.1 → 1.1.3
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/README.md +10 -3
- package/dist/bin/cli.cjs +1347 -994
- package/dist/bin/cli.mjs +1347 -994
- package/dist/main.cjs +1347 -994
- package/dist/main.mjs +1347 -994
- package/package.json +1 -1
- package/src/commands/auth/index.ts +2 -2
- package/src/commands/auth/login.ts +1 -1
- package/src/commands/auth/logout.ts +21 -2
- package/src/commands/auth/whoami.ts +1 -1
- package/src/commands/database/index.ts +345 -30
- package/src/commands/devbox/index.ts +108 -24
- package/src/commands/template/index.ts +42 -14
- package/src/commands/workspace/index.ts +3 -3
- package/src/lib/auth.ts +17 -1
|
@@ -33,6 +33,7 @@ interface DevboxUpdateOptions {
|
|
|
33
33
|
cpu?: string
|
|
34
34
|
memory?: string
|
|
35
35
|
port: string[]
|
|
36
|
+
output: string
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
interface DevboxReleaseOptions {
|
|
@@ -40,6 +41,7 @@ interface DevboxReleaseOptions {
|
|
|
40
41
|
description?: string
|
|
41
42
|
execCommand?: string
|
|
42
43
|
noStart?: boolean
|
|
44
|
+
output: string
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
function formatValue (value: unknown): string {
|
|
@@ -398,7 +400,7 @@ export function createDevboxCommand (): Command {
|
|
|
398
400
|
devboxCmd
|
|
399
401
|
.command('list')
|
|
400
402
|
.description('List all devboxes')
|
|
401
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
403
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
402
404
|
.action(withAuth({ spinnerText: 'Loading devboxes...' }, async (ctx, options: { output: string }) => {
|
|
403
405
|
const client = createDevboxClient()
|
|
404
406
|
const { data, error, response } = await client.GET('/devbox', {
|
|
@@ -427,7 +429,7 @@ export function createDevboxCommand (): Command {
|
|
|
427
429
|
.option('--env <NAME=VALUE>', 'Environment variable', collectOption, [] as string[])
|
|
428
430
|
.option('--secret-env <NAME=SECRET:KEY>', 'Environment variable from secret', collectOption, [] as string[])
|
|
429
431
|
.option('--autostart', 'Auto start devbox after creation')
|
|
430
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
432
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
431
433
|
.action(withAuth({ spinnerText: 'Creating devbox...' }, async (ctx, options: DevboxCreateOptions & { output: string }) => {
|
|
432
434
|
const client = createDevboxClient()
|
|
433
435
|
const { data, error, response } = await client.POST('/devbox', {
|
|
@@ -449,7 +451,7 @@ export function createDevboxCommand (): Command {
|
|
|
449
451
|
devboxCmd
|
|
450
452
|
.command('get <name>')
|
|
451
453
|
.description('Get devbox details')
|
|
452
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
454
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
453
455
|
.action(withAuth({ spinnerText: 'Loading devbox...' }, async (ctx, name: string, options: { output: string }) => {
|
|
454
456
|
const client = createDevboxClient()
|
|
455
457
|
const { data, error, response } = await client.GET('/devbox/{name}', {
|
|
@@ -475,6 +477,7 @@ export function createDevboxCommand (): Command {
|
|
|
475
477
|
.option('--cpu <cpu>', 'CPU cores')
|
|
476
478
|
.option('--memory <memory>', 'Memory in GB')
|
|
477
479
|
.option('--port <spec>', 'Port spec. Existing ports can include portName=...', collectOption, [] as string[])
|
|
480
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
478
481
|
.action(withAuth({ spinnerText: 'Updating devbox...' }, async (ctx, name: string, options: DevboxUpdateOptions) => {
|
|
479
482
|
const client = createDevboxClient()
|
|
480
483
|
const { error, response } = await client.PATCH('/devbox/{name}', {
|
|
@@ -486,6 +489,17 @@ export function createDevboxCommand (): Command {
|
|
|
486
489
|
})
|
|
487
490
|
|
|
488
491
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
492
|
+
if (options.output === 'json') {
|
|
493
|
+
ctx.spinner.stop()
|
|
494
|
+
outputJson({
|
|
495
|
+
success: true,
|
|
496
|
+
action: 'update',
|
|
497
|
+
resource: 'devbox',
|
|
498
|
+
name,
|
|
499
|
+
status: 'requested'
|
|
500
|
+
})
|
|
501
|
+
return
|
|
502
|
+
}
|
|
489
503
|
ctx.spinner.succeed(`Devbox "${name}" update requested`)
|
|
490
504
|
}))
|
|
491
505
|
|
|
@@ -493,7 +507,8 @@ export function createDevboxCommand (): Command {
|
|
|
493
507
|
.command('delete <name>')
|
|
494
508
|
.description('Delete a devbox')
|
|
495
509
|
.alias('rm')
|
|
496
|
-
.
|
|
510
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
511
|
+
.action(withAuth({ spinnerText: 'Deleting devbox...' }, async (ctx, name: string, options: { output: string }) => {
|
|
497
512
|
const client = createDevboxClient()
|
|
498
513
|
const { error, response } = await client.DELETE('/devbox/{name}', {
|
|
499
514
|
headers: ctx.auth,
|
|
@@ -503,6 +518,17 @@ export function createDevboxCommand (): Command {
|
|
|
503
518
|
})
|
|
504
519
|
|
|
505
520
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
521
|
+
if (options.output === 'json') {
|
|
522
|
+
ctx.spinner.stop()
|
|
523
|
+
outputJson({
|
|
524
|
+
success: true,
|
|
525
|
+
action: 'delete',
|
|
526
|
+
resource: 'devbox',
|
|
527
|
+
name,
|
|
528
|
+
status: 'deleted'
|
|
529
|
+
})
|
|
530
|
+
return
|
|
531
|
+
}
|
|
506
532
|
ctx.spinner.succeed(`Devbox "${name}" deleted`)
|
|
507
533
|
}))
|
|
508
534
|
|
|
@@ -520,26 +546,40 @@ export function createDevboxCommand (): Command {
|
|
|
520
546
|
|
|
521
547
|
if (action.alias) command.alias(action.alias)
|
|
522
548
|
|
|
523
|
-
command
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
549
|
+
command
|
|
550
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
551
|
+
.action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name: string, options: { output: string }) => {
|
|
552
|
+
const client = createDevboxClient()
|
|
553
|
+
const { error, response } = await client.POST(action.endpoint, {
|
|
554
|
+
headers: ctx.auth,
|
|
555
|
+
params: {
|
|
556
|
+
path: { name }
|
|
557
|
+
},
|
|
558
|
+
body: {}
|
|
559
|
+
} as any)
|
|
560
|
+
|
|
561
|
+
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
562
|
+
if (options.output === 'json') {
|
|
563
|
+
ctx.spinner.stop()
|
|
564
|
+
outputJson({
|
|
565
|
+
success: true,
|
|
566
|
+
action: action.name,
|
|
567
|
+
resource: 'devbox',
|
|
568
|
+
name,
|
|
569
|
+
status: 'requested'
|
|
570
|
+
})
|
|
571
|
+
return
|
|
572
|
+
}
|
|
573
|
+
ctx.spinner.succeed(`Devbox "${name}" ${action.done}`)
|
|
574
|
+
}))
|
|
536
575
|
}
|
|
537
576
|
|
|
538
577
|
devboxCmd
|
|
539
578
|
.command('autostart <name>')
|
|
540
579
|
.description('Configure devbox autostart')
|
|
541
580
|
.option('--exec-command <command>', 'Command to execute when the devbox starts')
|
|
542
|
-
.
|
|
581
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
582
|
+
.action(withAuth({ spinnerText: 'Configuring autostart...' }, async (ctx, name: string, options: { execCommand?: string; output: string }) => {
|
|
543
583
|
const client = createDevboxClient()
|
|
544
584
|
const body = options.execCommand ? { execCommand: options.execCommand } : {}
|
|
545
585
|
const { error, response } = await client.POST('/devbox/{name}/autostart', {
|
|
@@ -551,6 +591,18 @@ export function createDevboxCommand (): Command {
|
|
|
551
591
|
})
|
|
552
592
|
|
|
553
593
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
594
|
+
if (options.output === 'json') {
|
|
595
|
+
ctx.spinner.stop()
|
|
596
|
+
outputJson({
|
|
597
|
+
success: true,
|
|
598
|
+
action: 'autostart',
|
|
599
|
+
resource: 'devbox',
|
|
600
|
+
name,
|
|
601
|
+
execCommand: options.execCommand ?? null,
|
|
602
|
+
status: 'configured'
|
|
603
|
+
})
|
|
604
|
+
return
|
|
605
|
+
}
|
|
554
606
|
ctx.spinner.succeed(`Autostart configured for "${name}"`)
|
|
555
607
|
}))
|
|
556
608
|
|
|
@@ -560,7 +612,7 @@ export function createDevboxCommand (): Command {
|
|
|
560
612
|
.option('--start <timestamp>', 'Start timestamp in seconds or milliseconds')
|
|
561
613
|
.option('--end <timestamp>', 'End timestamp in seconds or milliseconds')
|
|
562
614
|
.option('--step <step>', 'Sampling interval, e.g. 2m')
|
|
563
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
615
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
564
616
|
.action(withAuth({ spinnerText: 'Loading monitor data...' }, async (
|
|
565
617
|
ctx,
|
|
566
618
|
name: string,
|
|
@@ -592,7 +644,7 @@ export function createDevboxCommand (): Command {
|
|
|
592
644
|
devboxCmd
|
|
593
645
|
.command('templates')
|
|
594
646
|
.description('List available devbox templates')
|
|
595
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
647
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
596
648
|
.action(withAuth({ spinnerText: 'Loading devbox templates...' }, async (ctx, options: { output: string }) => {
|
|
597
649
|
const client = createDevboxClient()
|
|
598
650
|
const { data, error, response } = await client.GET('/devbox/templates', {
|
|
@@ -616,7 +668,7 @@ export function createDevboxCommand (): Command {
|
|
|
616
668
|
releasesCommand
|
|
617
669
|
.command('list <name>')
|
|
618
670
|
.description('List devbox releases')
|
|
619
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
671
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
620
672
|
.action(withAuth({ spinnerText: 'Loading releases...' }, async (ctx, name: string, options: { output: string }) => {
|
|
621
673
|
const client = createDevboxClient()
|
|
622
674
|
const { data, error, response } = await client.GET('/devbox/{name}/releases', {
|
|
@@ -643,6 +695,7 @@ export function createDevboxCommand (): Command {
|
|
|
643
695
|
.option('--description <description>', 'Release description')
|
|
644
696
|
.option('--exec-command <command>', 'Autostart command after release restart')
|
|
645
697
|
.option('--no-start', 'Keep devbox stopped after the release build completes')
|
|
698
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
646
699
|
.action(withAuth({ spinnerText: 'Creating release...' }, async (ctx, name: string, options: DevboxReleaseOptions) => {
|
|
647
700
|
const client = createDevboxClient()
|
|
648
701
|
const { data, error, response } = await client.POST('/devbox/{name}/releases', {
|
|
@@ -654,6 +707,11 @@ export function createDevboxCommand (): Command {
|
|
|
654
707
|
})
|
|
655
708
|
|
|
656
709
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
710
|
+
if (options.output === 'json') {
|
|
711
|
+
ctx.spinner.stop()
|
|
712
|
+
outputJson(data)
|
|
713
|
+
return
|
|
714
|
+
}
|
|
657
715
|
ctx.spinner.succeed(`Release "${options.tag}" accepted for "${data.name}" (${data.status})`)
|
|
658
716
|
}))
|
|
659
717
|
|
|
@@ -661,7 +719,8 @@ export function createDevboxCommand (): Command {
|
|
|
661
719
|
.command('delete <name> <tag>')
|
|
662
720
|
.alias('rm')
|
|
663
721
|
.description('Delete a devbox release')
|
|
664
|
-
.
|
|
722
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
723
|
+
.action(withAuth({ spinnerText: 'Deleting release...' }, async (ctx, name: string, tag: string, options: { output: string }) => {
|
|
665
724
|
const client = createDevboxClient()
|
|
666
725
|
const { error, response } = await client.DELETE('/devbox/{name}/releases/{tag}', {
|
|
667
726
|
headers: ctx.auth,
|
|
@@ -671,13 +730,26 @@ export function createDevboxCommand (): Command {
|
|
|
671
730
|
})
|
|
672
731
|
|
|
673
732
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
733
|
+
if (options.output === 'json') {
|
|
734
|
+
ctx.spinner.stop()
|
|
735
|
+
outputJson({
|
|
736
|
+
success: true,
|
|
737
|
+
action: 'delete',
|
|
738
|
+
resource: 'devbox-release',
|
|
739
|
+
name,
|
|
740
|
+
tag,
|
|
741
|
+
status: 'deleted'
|
|
742
|
+
})
|
|
743
|
+
return
|
|
744
|
+
}
|
|
674
745
|
ctx.spinner.succeed(`Release "${tag}" deleted for "${name}"`)
|
|
675
746
|
}))
|
|
676
747
|
|
|
677
748
|
releasesCommand
|
|
678
749
|
.command('deploy <name> <tag>')
|
|
679
750
|
.description('Deploy a release to AppLaunchpad')
|
|
680
|
-
.
|
|
751
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
752
|
+
.action(withAuth({ spinnerText: 'Deploying release...' }, async (ctx, name: string, tag: string, options: { output: string }) => {
|
|
681
753
|
const client = createDevboxClient()
|
|
682
754
|
const { error, response } = await client.POST('/devbox/{name}/releases/{tag}/deploy', {
|
|
683
755
|
headers: ctx.auth,
|
|
@@ -687,13 +759,25 @@ export function createDevboxCommand (): Command {
|
|
|
687
759
|
})
|
|
688
760
|
|
|
689
761
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
762
|
+
if (options.output === 'json') {
|
|
763
|
+
ctx.spinner.stop()
|
|
764
|
+
outputJson({
|
|
765
|
+
success: true,
|
|
766
|
+
action: 'deploy',
|
|
767
|
+
resource: 'devbox-release',
|
|
768
|
+
name,
|
|
769
|
+
tag,
|
|
770
|
+
status: 'deployed'
|
|
771
|
+
})
|
|
772
|
+
return
|
|
773
|
+
}
|
|
690
774
|
ctx.spinner.succeed(`Release "${tag}" deployed for "${name}"`)
|
|
691
775
|
}))
|
|
692
776
|
|
|
693
777
|
devboxCmd
|
|
694
778
|
.command('deployments <name>')
|
|
695
779
|
.description('List deployed applications from a devbox')
|
|
696
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
780
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
697
781
|
.action(withAuth({ spinnerText: 'Loading deployments...' }, async (ctx, name: string, options: { output: string }) => {
|
|
698
782
|
const client = createDevboxClient()
|
|
699
783
|
const { data, error, response } = await client.GET('/devbox/{name}/deployments', {
|
|
@@ -2,7 +2,7 @@ import { Command } from 'commander'
|
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
4
|
import { createTemplateClient } from '../../lib/api-client.ts'
|
|
5
|
-
import { type ApiErrorBody, mapApiError } from '../../lib/errors.ts'
|
|
5
|
+
import { type ApiErrorBody, handleError, mapApiError } from '../../lib/errors.ts'
|
|
6
6
|
import { outputJson, outputTable } from '../../lib/output.ts'
|
|
7
7
|
import { withAuth, withErrorHandling } from '../../lib/with-auth.ts'
|
|
8
8
|
|
|
@@ -12,6 +12,7 @@ interface TemplateDeployOptions {
|
|
|
12
12
|
yaml?: string
|
|
13
13
|
set: string[]
|
|
14
14
|
dryRun?: boolean
|
|
15
|
+
output: string
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export type TemplateDeployMode = 'catalog' | 'raw'
|
|
@@ -82,18 +83,16 @@ export function resolveTemplateDeployMode (
|
|
|
82
83
|
options: TemplateDeployOptions,
|
|
83
84
|
stdinIsTTY: boolean = process.stdin.isTTY
|
|
84
85
|
): TemplateDeployMode {
|
|
85
|
-
const
|
|
86
|
+
const hasExplicitRawInput = !!(options.file || options.yaml)
|
|
87
|
+
const isRaw = hasExplicitRawInput || (!template && !stdinIsTTY)
|
|
86
88
|
|
|
87
|
-
if (template &&
|
|
88
|
-
throw new Error('Cannot specify both a template name and --file/--yaml
|
|
89
|
+
if (template && hasExplicitRawInput) {
|
|
90
|
+
throw new Error('Cannot specify both a template name and --file/--yaml. Use one or the other.')
|
|
89
91
|
}
|
|
90
92
|
if (!template && !isRaw) {
|
|
91
93
|
throw new Error('Provide a template name or use --file/--yaml/stdin to supply raw YAML.')
|
|
92
94
|
}
|
|
93
95
|
if (template) {
|
|
94
|
-
if (!options.name) {
|
|
95
|
-
throw new Error('--name is required when deploying from the template catalog.')
|
|
96
|
-
}
|
|
97
96
|
if (options.dryRun) {
|
|
98
97
|
throw new Error('--dry-run is only supported for raw template deploys (--file, --yaml, or stdin).')
|
|
99
98
|
}
|
|
@@ -108,7 +107,7 @@ export function buildCatalogTemplateDeployBody (
|
|
|
108
107
|
options: Pick<TemplateDeployOptions, 'name' | 'set'>
|
|
109
108
|
): { name: string; template: string; args?: Record<string, string> } {
|
|
110
109
|
const body: { name: string; template: string; args?: Record<string, string> } = {
|
|
111
|
-
name: options.name
|
|
110
|
+
name: options.name ?? template,
|
|
112
111
|
template
|
|
113
112
|
}
|
|
114
113
|
if (options.set.length > 0) {
|
|
@@ -208,6 +207,11 @@ export function createTemplateCommand (): Command {
|
|
|
208
207
|
|
|
209
208
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
210
209
|
|
|
210
|
+
if (deployOptions.output === 'json') {
|
|
211
|
+
ctx.spinner.stop()
|
|
212
|
+
outputJson(data)
|
|
213
|
+
return
|
|
214
|
+
}
|
|
211
215
|
ctx.spinner.succeed(`Instance "${data.name}" created successfully`)
|
|
212
216
|
printInstanceResult(data, { template: catalogTemplate })
|
|
213
217
|
return
|
|
@@ -224,6 +228,12 @@ export function createTemplateCommand (): Command {
|
|
|
224
228
|
|
|
225
229
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
226
230
|
|
|
231
|
+
if (deployOptions.output === 'json') {
|
|
232
|
+
ctx.spinner.stop()
|
|
233
|
+
outputJson(data)
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
|
|
227
237
|
if (deployOptions.dryRun) {
|
|
228
238
|
ctx.spinner.succeed('Raw template validation passed; no resources were created')
|
|
229
239
|
printInstanceResult(data, { raw: true, dryRun: true })
|
|
@@ -240,7 +250,7 @@ export function createTemplateCommand (): Command {
|
|
|
240
250
|
.description('List available templates')
|
|
241
251
|
.option('-c, --category <category>', 'Filter by category')
|
|
242
252
|
.option('-l, --language <language>', 'Language code (for example: en, zh)')
|
|
243
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
253
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
244
254
|
.action(withErrorHandling({ spinnerText: 'Loading templates...' }, async (ctx, options: { category?: string; language?: string; output: string }) => {
|
|
245
255
|
const client = createTemplateClient()
|
|
246
256
|
const { data, error, response } = await client.GET('/templates', {
|
|
@@ -281,7 +291,7 @@ export function createTemplateCommand (): Command {
|
|
|
281
291
|
.alias('describe')
|
|
282
292
|
.description('Get template details')
|
|
283
293
|
.option('-l, --language <language>', 'Language code (for example: en, zh)')
|
|
284
|
-
.option('-o, --output <format>', 'Output format (json|table)', '
|
|
294
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
285
295
|
.action(withErrorHandling({ spinnerText: 'Loading template...' }, async (ctx, name: string, options: { language?: string; output: string }) => {
|
|
286
296
|
const client = createTemplateClient()
|
|
287
297
|
const { data, error, response } = await client.GET('/templates/{name}', {
|
|
@@ -338,7 +348,8 @@ export function createTemplateCommand (): Command {
|
|
|
338
348
|
.command('delete <instance>')
|
|
339
349
|
.alias('rm')
|
|
340
350
|
.description('Delete a deployed template instance')
|
|
341
|
-
.
|
|
351
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
352
|
+
.action(withAuth({ spinnerText: 'Deleting template instance...' }, async (ctx, instance: string, options: { output: string }) => {
|
|
342
353
|
const client = createTemplateClient()
|
|
343
354
|
const { error, response } = await client.DELETE('/templates/instances/{instanceName}', {
|
|
344
355
|
headers: ctx.auth,
|
|
@@ -349,6 +360,17 @@ export function createTemplateCommand (): Command {
|
|
|
349
360
|
|
|
350
361
|
if (error) throw mapApiError(response.status, error as ApiErrorBody)
|
|
351
362
|
|
|
363
|
+
if (options.output === 'json') {
|
|
364
|
+
ctx.spinner.stop()
|
|
365
|
+
outputJson({
|
|
366
|
+
success: true,
|
|
367
|
+
action: 'delete',
|
|
368
|
+
resource: 'template-instance',
|
|
369
|
+
instance,
|
|
370
|
+
status: 'deleted'
|
|
371
|
+
})
|
|
372
|
+
return
|
|
373
|
+
}
|
|
352
374
|
ctx.spinner.succeed(`Instance "${instance}" deleted`)
|
|
353
375
|
}))
|
|
354
376
|
|
|
@@ -356,14 +378,16 @@ export function createTemplateCommand (): Command {
|
|
|
356
378
|
tplCmd
|
|
357
379
|
.command('deploy [template]')
|
|
358
380
|
.description('Deploy a template (from catalog or raw YAML)')
|
|
359
|
-
.option('--name <name>', 'Instance name (
|
|
381
|
+
.option('--name <name>', 'Instance name (defaults to the catalog template name)')
|
|
360
382
|
.option('--file <path>', 'Path to template YAML file')
|
|
361
383
|
.option('--yaml <yaml>', 'Template YAML string')
|
|
362
384
|
.option('--set <KEY=VALUE...>', 'Set template arguments', (val: string, prev: string[]) => [...prev, val], [] as string[])
|
|
363
385
|
.option('--dry-run', 'Validate raw template YAML without creating resources')
|
|
386
|
+
.option('-o, --output <format>', 'Output format (json|table)', 'json')
|
|
364
387
|
.addHelpText('after', `
|
|
365
388
|
Examples:
|
|
366
389
|
Catalog:
|
|
390
|
+
sealos-cli template deploy rybbit
|
|
367
391
|
sealos-cli template deploy perplexica --name my-app --set OPENAI_API_KEY=xxx
|
|
368
392
|
|
|
369
393
|
Raw:
|
|
@@ -372,8 +396,12 @@ Examples:
|
|
|
372
396
|
cat template.yaml | sealos-cli template deploy --dry-run
|
|
373
397
|
`)
|
|
374
398
|
.action(async (template: string | undefined, options: TemplateDeployOptions) => {
|
|
375
|
-
|
|
376
|
-
|
|
399
|
+
try {
|
|
400
|
+
const mode = resolveTemplateDeployMode(template, options)
|
|
401
|
+
await deployTemplate(template, options, mode)
|
|
402
|
+
} catch (error) {
|
|
403
|
+
handleError(error)
|
|
404
|
+
}
|
|
377
405
|
})
|
|
378
406
|
|
|
379
407
|
return tplCmd
|
|
@@ -12,7 +12,7 @@ export function createWorkspaceCommand (): Command {
|
|
|
12
12
|
.command('switch')
|
|
13
13
|
.description('Switch to another workspace')
|
|
14
14
|
.argument('<namespace>', 'Workspace id, uid, or team name')
|
|
15
|
-
.option('-o, --output <format>', 'Output format: json, table', '
|
|
15
|
+
.option('-o, --output <format>', 'Output format: json, table', 'json')
|
|
16
16
|
.action(async (namespace, options) => {
|
|
17
17
|
try {
|
|
18
18
|
const result = await switchWorkspace(namespace)
|
|
@@ -30,7 +30,7 @@ export function createWorkspaceCommand (): Command {
|
|
|
30
30
|
workspaceCmd
|
|
31
31
|
.command('list')
|
|
32
32
|
.description('List all workspaces')
|
|
33
|
-
.option('-o, --output <format>', 'Output format: json, table', '
|
|
33
|
+
.option('-o, --output <format>', 'Output format: json, table', 'json')
|
|
34
34
|
.action(async (options) => {
|
|
35
35
|
try {
|
|
36
36
|
const result = await listWorkspaces()
|
|
@@ -58,7 +58,7 @@ export function createWorkspaceCommand (): Command {
|
|
|
58
58
|
workspaceCmd
|
|
59
59
|
.command('current')
|
|
60
60
|
.description('Show current workspace')
|
|
61
|
-
.option('-o, --output <format>', 'Output format: json, table', '
|
|
61
|
+
.option('-o, --output <format>', 'Output format: json, table', 'json')
|
|
62
62
|
.action(async (options) => {
|
|
63
63
|
try {
|
|
64
64
|
const authInfo = getAuthInfo()
|
package/src/lib/auth.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node
|
|
|
3
3
|
import { homedir, platform } from 'node:os'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import type { SealosAuthData, SealosWorkspace } from '../types/index.ts'
|
|
6
|
+
import { AuthError } from './errors.ts'
|
|
6
7
|
|
|
7
8
|
export const SEALOS_AUTH_CLIENT_ID = 'af993c98-d19d-4bdc-b338-79b80dc4f8bf'
|
|
8
9
|
export const DEFAULT_SEALOS_REGION = 'https://usw-1.sealos.io'
|
|
@@ -64,6 +65,11 @@ interface KubeconfigResponse {
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
interface SealosApiEnvelope {
|
|
69
|
+
code?: number
|
|
70
|
+
message?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
export interface LoginResult {
|
|
68
74
|
kubeconfig_path?: string
|
|
69
75
|
region: string
|
|
@@ -236,7 +242,17 @@ export function getAuthInfo (deps: AuthDependencies = {}): AuthInfo {
|
|
|
236
242
|
}
|
|
237
243
|
|
|
238
244
|
async function parseResponse<T> (res: Response): Promise<T> {
|
|
239
|
-
|
|
245
|
+
const body = await res.json() as T & SealosApiEnvelope
|
|
246
|
+
if (body && typeof body === 'object' && typeof body.code === 'number' && ![0, 200].includes(body.code)) {
|
|
247
|
+
const message = body.message || `Sealos API request failed with code ${body.code}`
|
|
248
|
+
if (body.code === 401) {
|
|
249
|
+
throw new AuthError(`Authentication expired. Please run "sealos-cli login" again. (${message})`)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
throw new Error(message)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return body as T
|
|
240
256
|
}
|
|
241
257
|
|
|
242
258
|
async function readErrorBody (res: Response): Promise<string> {
|