sealos-cli 1.1.1 → 1.1.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.
package/dist/bin/cli.mjs CHANGED
@@ -20,938 +20,1031 @@ import { execFileSync } from "child_process";
20
20
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
21
21
  import { homedir, platform } from "os";
22
22
  import { join } from "path";
23
- var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
24
- var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
25
- var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
26
- var AUTH_METHOD_TOKEN = "token";
27
- var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
28
- function getAuthPaths(sealosDir = join(homedir(), ".sealos")) {
29
- return {
30
- sealosDir,
31
- authPath: join(sealosDir, "auth.json"),
32
- kubeconfigPath: join(sealosDir, "kubeconfig")
33
- };
34
- }
35
- __name(getAuthPaths, "getAuthPaths");
36
- function normalizeRegion(region) {
37
- return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
38
- }
39
- __name(normalizeRegion, "normalizeRegion");
40
- function createDefaultAuthDependencies() {
41
- return {
42
- fetch,
43
- sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
44
- openBrowser,
45
- now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
46
- paths: getAuthPaths(),
47
- stderr: process.stderr
48
- };
49
- }
50
- __name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
51
- function withDeps(deps = {}) {
52
- return {
53
- ...createDefaultAuthDependencies(),
54
- ...deps
55
- };
56
- }
57
- __name(withDeps, "withDeps");
58
- function ensureSealosDir(paths) {
59
- mkdirSync(paths.sealosDir, { recursive: true });
60
- }
61
- __name(ensureSealosDir, "ensureSealosDir");
62
- function saveAuth(auth, deps = {}) {
63
- const { paths } = withDeps(deps);
64
- ensureSealosDir(paths);
65
- writeFileSync(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
66
- }
67
- __name(saveAuth, "saveAuth");
68
- function loadAuth(deps = {}) {
69
- const { paths } = withDeps(deps);
70
- if (!existsSync(paths.authPath)) {
71
- throw new Error("Not authenticated. Please run: sealos-cli login");
72
- }
73
- return JSON.parse(readFileSync(paths.authPath, "utf-8"));
74
- }
75
- __name(loadAuth, "loadAuth");
76
- function getKubeconfigContent(deps = {}) {
77
- const { paths } = withDeps(deps);
78
- try {
79
- return readFileSync(paths.kubeconfigPath, "utf-8");
80
- } catch {
81
- return null;
23
+
24
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
25
+ var ANSI_BACKGROUND_OFFSET = 10;
26
+ var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
27
+ var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
28
+ var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
29
+ var styles = {
30
+ modifier: {
31
+ reset: [0, 0],
32
+ // 21 isn't widely supported and 22 does the same thing
33
+ bold: [1, 22],
34
+ dim: [2, 22],
35
+ italic: [3, 23],
36
+ underline: [4, 24],
37
+ overline: [53, 55],
38
+ inverse: [7, 27],
39
+ hidden: [8, 28],
40
+ strikethrough: [9, 29]
41
+ },
42
+ color: {
43
+ black: [30, 39],
44
+ red: [31, 39],
45
+ green: [32, 39],
46
+ yellow: [33, 39],
47
+ blue: [34, 39],
48
+ magenta: [35, 39],
49
+ cyan: [36, 39],
50
+ white: [37, 39],
51
+ // Bright color
52
+ blackBright: [90, 39],
53
+ gray: [90, 39],
54
+ // Alias of `blackBright`
55
+ grey: [90, 39],
56
+ // Alias of `blackBright`
57
+ redBright: [91, 39],
58
+ greenBright: [92, 39],
59
+ yellowBright: [93, 39],
60
+ blueBright: [94, 39],
61
+ magentaBright: [95, 39],
62
+ cyanBright: [96, 39],
63
+ whiteBright: [97, 39]
64
+ },
65
+ bgColor: {
66
+ bgBlack: [40, 49],
67
+ bgRed: [41, 49],
68
+ bgGreen: [42, 49],
69
+ bgYellow: [43, 49],
70
+ bgBlue: [44, 49],
71
+ bgMagenta: [45, 49],
72
+ bgCyan: [46, 49],
73
+ bgWhite: [47, 49],
74
+ // Bright color
75
+ bgBlackBright: [100, 49],
76
+ bgGray: [100, 49],
77
+ // Alias of `bgBlackBright`
78
+ bgGrey: [100, 49],
79
+ // Alias of `bgBlackBright`
80
+ bgRedBright: [101, 49],
81
+ bgGreenBright: [102, 49],
82
+ bgYellowBright: [103, 49],
83
+ bgBlueBright: [104, 49],
84
+ bgMagentaBright: [105, 49],
85
+ bgCyanBright: [106, 49],
86
+ bgWhiteBright: [107, 49]
82
87
  }
83
- }
84
- __name(getKubeconfigContent, "getKubeconfigContent");
85
- function getAuthHeaders(deps = {}) {
86
- const kubeconfig = getKubeconfigContent(deps);
87
- return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
88
- }
89
- __name(getAuthHeaders, "getAuthHeaders");
90
- function requireAuth(deps = {}) {
91
- const headers = getAuthHeaders(deps);
92
- if (!headers) {
93
- throw new Error('Authentication required. Please run "sealos-cli login" first.');
88
+ };
89
+ var modifierNames = Object.keys(styles.modifier);
90
+ var foregroundColorNames = Object.keys(styles.color);
91
+ var backgroundColorNames = Object.keys(styles.bgColor);
92
+ var colorNames = [...foregroundColorNames, ...backgroundColorNames];
93
+ function assembleStyles() {
94
+ const codes = /* @__PURE__ */ new Map();
95
+ for (const [groupName, group] of Object.entries(styles)) {
96
+ for (const [styleName, style] of Object.entries(group)) {
97
+ styles[styleName] = {
98
+ open: `\x1B[${style[0]}m`,
99
+ close: `\x1B[${style[1]}m`
100
+ };
101
+ group[styleName] = styles[styleName];
102
+ codes.set(style[0], style[1]);
103
+ }
104
+ Object.defineProperty(styles, groupName, {
105
+ value: group,
106
+ enumerable: false
107
+ });
94
108
  }
95
- return headers;
109
+ Object.defineProperty(styles, "codes", {
110
+ value: codes,
111
+ enumerable: false
112
+ });
113
+ styles.color.close = "\x1B[39m";
114
+ styles.bgColor.close = "\x1B[49m";
115
+ styles.color.ansi = wrapAnsi16();
116
+ styles.color.ansi256 = wrapAnsi256();
117
+ styles.color.ansi16m = wrapAnsi16m();
118
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
119
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
120
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
121
+ Object.defineProperties(styles, {
122
+ rgbToAnsi256: {
123
+ value(red2, green2, blue2) {
124
+ if (red2 === green2 && green2 === blue2) {
125
+ if (red2 < 8) {
126
+ return 16;
127
+ }
128
+ if (red2 > 248) {
129
+ return 231;
130
+ }
131
+ return Math.round((red2 - 8) / 247 * 24) + 232;
132
+ }
133
+ return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
134
+ },
135
+ enumerable: false
136
+ },
137
+ hexToRgb: {
138
+ value(hex) {
139
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
140
+ if (!matches) {
141
+ return [0, 0, 0];
142
+ }
143
+ let [colorString] = matches;
144
+ if (colorString.length === 3) {
145
+ colorString = [...colorString].map((character) => character + character).join("");
146
+ }
147
+ const integer = Number.parseInt(colorString, 16);
148
+ return [
149
+ /* eslint-disable no-bitwise */
150
+ integer >> 16 & 255,
151
+ integer >> 8 & 255,
152
+ integer & 255
153
+ /* eslint-enable no-bitwise */
154
+ ];
155
+ },
156
+ enumerable: false
157
+ },
158
+ hexToAnsi256: {
159
+ value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
160
+ enumerable: false
161
+ },
162
+ ansi256ToAnsi: {
163
+ value(code) {
164
+ if (code < 8) {
165
+ return 30 + code;
166
+ }
167
+ if (code < 16) {
168
+ return 90 + (code - 8);
169
+ }
170
+ let red2;
171
+ let green2;
172
+ let blue2;
173
+ if (code >= 232) {
174
+ red2 = ((code - 232) * 10 + 8) / 255;
175
+ green2 = red2;
176
+ blue2 = red2;
177
+ } else {
178
+ code -= 16;
179
+ const remainder = code % 36;
180
+ red2 = Math.floor(code / 36) / 5;
181
+ green2 = Math.floor(remainder / 6) / 5;
182
+ blue2 = remainder % 6 / 5;
183
+ }
184
+ const value = Math.max(red2, green2, blue2) * 2;
185
+ if (value === 0) {
186
+ return 30;
187
+ }
188
+ let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
189
+ if (value === 2) {
190
+ result += 60;
191
+ }
192
+ return result;
193
+ },
194
+ enumerable: false
195
+ },
196
+ rgbToAnsi: {
197
+ value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
198
+ enumerable: false
199
+ },
200
+ hexToAnsi: {
201
+ value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
202
+ enumerable: false
203
+ }
204
+ });
205
+ return styles;
96
206
  }
97
- __name(requireAuth, "requireAuth");
98
- function saveKubeconfig(kubeconfig, deps = {}) {
99
- const { paths } = withDeps(deps);
100
- ensureSealosDir(paths);
101
- writeFileSync(paths.kubeconfigPath, kubeconfig, { mode: 384 });
207
+ __name(assembleStyles, "assembleStyles");
208
+ var ansiStyles = assembleStyles();
209
+ var ansi_styles_default = ansiStyles;
210
+
211
+ // node_modules/chalk/source/vendor/supports-color/index.js
212
+ import process2 from "process";
213
+ import os from "os";
214
+ import tty from "tty";
215
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
216
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
217
+ const position = argv.indexOf(prefix + flag);
218
+ const terminatorPosition = argv.indexOf("--");
219
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
102
220
  }
103
- __name(saveKubeconfig, "saveKubeconfig");
104
- function clearAuth(deps = {}) {
105
- const { paths } = withDeps(deps);
106
- rmSync(paths.authPath, { force: true });
107
- rmSync(paths.kubeconfigPath, { force: true });
221
+ __name(hasFlag, "hasFlag");
222
+ var { env } = process2;
223
+ var flagForceColor;
224
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
225
+ flagForceColor = 0;
226
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
227
+ flagForceColor = 1;
108
228
  }
109
- __name(clearAuth, "clearAuth");
110
- function checkAuth(deps = {}) {
111
- const { paths } = withDeps(deps);
112
- if (!existsSync(paths.kubeconfigPath)) {
113
- return { authenticated: false };
114
- }
115
- try {
116
- const kubeconfig = readFileSync(paths.kubeconfigPath, "utf-8");
117
- if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
118
- return { authenticated: false };
229
+ function envForceColor() {
230
+ if ("FORCE_COLOR" in env) {
231
+ if (env.FORCE_COLOR === "true") {
232
+ return 1;
119
233
  }
120
- const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
121
- return {
122
- authenticated: true,
123
- kubeconfig_path: paths.kubeconfigPath,
124
- region: auth.region || "unknown",
125
- workspace: auth.current_workspace?.id || "unknown"
126
- };
127
- } catch {
128
- return { authenticated: false };
234
+ if (env.FORCE_COLOR === "false") {
235
+ return 0;
236
+ }
237
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
129
238
  }
130
239
  }
131
- __name(checkAuth, "checkAuth");
132
- function getAuthInfo(deps = {}) {
133
- const { paths } = withDeps(deps);
134
- const status = checkAuth(deps);
135
- if (!status.authenticated) {
136
- return { authenticated: false };
240
+ __name(envForceColor, "envForceColor");
241
+ function translateLevel(level) {
242
+ if (level === 0) {
243
+ return false;
137
244
  }
138
- const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
139
245
  return {
140
- ...status,
141
- auth_method: auth.auth_method || "unknown",
142
- authenticated_at: auth.authenticated_at || "unknown",
143
- current_workspace: auth.current_workspace || null
246
+ level,
247
+ hasBasic: true,
248
+ has256: level >= 2,
249
+ has16m: level >= 3
144
250
  };
145
251
  }
146
- __name(getAuthInfo, "getAuthInfo");
147
- async function parseResponse(res) {
148
- return await res.json();
149
- }
150
- __name(parseResponse, "parseResponse");
151
- async function readErrorBody(res) {
152
- return await res.text().catch(() => "");
153
- }
154
- __name(readErrorBody, "readErrorBody");
155
- async function requestDeviceAuthorization(region, deps = {}) {
156
- const { fetch: fetchImpl } = withDeps(deps);
157
- const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
158
- method: "POST",
159
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
160
- body: new URLSearchParams({
161
- client_id: SEALOS_AUTH_CLIENT_ID,
162
- grant_type: DEVICE_GRANT_TYPE
163
- })
164
- });
165
- if (!res.ok) {
166
- const body = await readErrorBody(res);
167
- throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
252
+ __name(translateLevel, "translateLevel");
253
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
254
+ const noFlagForceColor = envForceColor();
255
+ if (noFlagForceColor !== void 0) {
256
+ flagForceColor = noFlagForceColor;
168
257
  }
169
- return await parseResponse(res);
170
- }
171
- __name(requestDeviceAuthorization, "requestDeviceAuthorization");
172
- async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
173
- const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
174
- const maxWait = Math.min(expiresIn, 600) * 1e3;
175
- const deadline = now().getTime() + maxWait;
176
- let pollInterval = interval * 1e3;
177
- let lastLoggedMinute = -1;
178
- while (now().getTime() < deadline) {
179
- await sleep(pollInterval);
180
- const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
181
- if (remaining !== lastLoggedMinute && remaining > 0) {
182
- lastLoggedMinute = remaining;
183
- stderr.write(` Waiting for authorization... (${remaining} min remaining)
184
- `);
258
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
259
+ if (forceColor === 0) {
260
+ return 0;
261
+ }
262
+ if (sniffFlags) {
263
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
264
+ return 3;
185
265
  }
186
- const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
187
- method: "POST",
188
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
189
- body: new URLSearchParams({
190
- client_id: SEALOS_AUTH_CLIENT_ID,
191
- grant_type: DEVICE_GRANT_TYPE,
192
- device_code: deviceCode
193
- })
194
- });
195
- if (res.ok) {
196
- return await parseResponse(res);
266
+ if (hasFlag("color=256")) {
267
+ return 2;
197
268
  }
198
- const body = await res.json().catch(() => ({}));
199
- switch (body.error) {
200
- case "authorization_pending":
201
- break;
202
- case "slow_down":
203
- pollInterval += 5e3;
204
- break;
205
- case "access_denied":
206
- throw new Error("Authorization denied by user");
207
- case "expired_token":
208
- throw new Error("Device code expired. Please run login again.");
209
- default:
210
- throw new Error(`Token request failed: ${body.error || res.statusText}`);
269
+ }
270
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
271
+ return 1;
272
+ }
273
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
274
+ return 0;
275
+ }
276
+ const min = forceColor || 0;
277
+ if (env.TERM === "dumb") {
278
+ return min;
279
+ }
280
+ if (process2.platform === "win32") {
281
+ const osRelease = os.release().split(".");
282
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
283
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
211
284
  }
285
+ return 1;
286
+ }
287
+ if ("CI" in env) {
288
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
289
+ return 3;
290
+ }
291
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
292
+ return 1;
293
+ }
294
+ return min;
295
+ }
296
+ if ("TEAMCITY_VERSION" in env) {
297
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
298
+ }
299
+ if (env.COLORTERM === "truecolor") {
300
+ return 3;
212
301
  }
213
- throw new Error("Authorization timed out (10 minutes). Please run login again.");
214
- }
215
- __name(pollForToken, "pollForToken");
216
- async function getRegionToken(region, globalToken, deps = {}) {
217
- const { fetch: fetchImpl } = withDeps(deps);
218
- const res = await fetchImpl(`${region}/api/auth/regionToken`, {
219
- method: "POST",
220
- headers: {
221
- Authorization: globalToken,
222
- "Content-Type": "application/json"
302
+ if (env.TERM === "xterm-kitty") {
303
+ return 3;
304
+ }
305
+ if (env.TERM === "xterm-ghostty") {
306
+ return 3;
307
+ }
308
+ if (env.TERM === "wezterm") {
309
+ return 3;
310
+ }
311
+ if ("TERM_PROGRAM" in env) {
312
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
313
+ switch (env.TERM_PROGRAM) {
314
+ case "iTerm.app": {
315
+ return version >= 3 ? 3 : 2;
316
+ }
317
+ case "Apple_Terminal": {
318
+ return 2;
319
+ }
223
320
  }
224
- });
225
- if (!res.ok) {
226
- const body = await readErrorBody(res);
227
- throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
228
321
  }
229
- return await parseResponse(res);
230
- }
231
- __name(getRegionToken, "getRegionToken");
232
- function normalizeWorkspaces(data) {
233
- const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
234
- return Array.isArray(namespaces) ? namespaces : [];
235
- }
236
- __name(normalizeWorkspaces, "normalizeWorkspaces");
237
- async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
238
- const { fetch: fetchImpl } = withDeps(deps);
239
- const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
240
- headers: { Authorization: regionalToken }
241
- });
242
- if (!res.ok) {
243
- const body = await readErrorBody(res);
244
- throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
322
+ if (/-256(color)?$/i.test(env.TERM)) {
323
+ return 2;
245
324
  }
246
- return normalizeWorkspaces(await parseResponse(res));
325
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
326
+ return 1;
327
+ }
328
+ if ("COLORTERM" in env) {
329
+ return 1;
330
+ }
331
+ return min;
247
332
  }
248
- __name(listRemoteWorkspaces, "listRemoteWorkspaces");
249
- async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
250
- const { fetch: fetchImpl } = withDeps(deps);
251
- const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
252
- method: "POST",
253
- headers: {
254
- Authorization: regionalToken,
255
- "Content-Type": "application/json"
256
- },
257
- body: JSON.stringify({ ns_uid: nsUid })
333
+ __name(_supportsColor, "_supportsColor");
334
+ function createSupportsColor(stream, options = {}) {
335
+ const level = _supportsColor(stream, {
336
+ streamIsTTY: stream && stream.isTTY,
337
+ ...options
258
338
  });
259
- if (!res.ok) {
260
- const body = await readErrorBody(res);
261
- throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
339
+ return translateLevel(level);
340
+ }
341
+ __name(createSupportsColor, "createSupportsColor");
342
+ var supportsColor = {
343
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
344
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
345
+ };
346
+ var supports_color_default = supportsColor;
347
+
348
+ // node_modules/chalk/source/utilities.js
349
+ function stringReplaceAll(string, substring, replacer) {
350
+ let index = string.indexOf(substring);
351
+ if (index === -1) {
352
+ return string;
262
353
  }
263
- return await parseResponse(res);
354
+ const substringLength = substring.length;
355
+ let endIndex = 0;
356
+ let returnValue = "";
357
+ do {
358
+ returnValue += string.slice(endIndex, index) + substring + replacer;
359
+ endIndex = index + substringLength;
360
+ index = string.indexOf(substring, endIndex);
361
+ } while (index !== -1);
362
+ returnValue += string.slice(endIndex);
363
+ return returnValue;
264
364
  }
265
- __name(switchRemoteWorkspace, "switchRemoteWorkspace");
266
- async function getKubeconfig(region, regionalToken, deps = {}) {
267
- const { fetch: fetchImpl } = withDeps(deps);
268
- const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
269
- headers: { Authorization: regionalToken }
270
- });
271
- if (!res.ok) {
272
- const body = await readErrorBody(res);
273
- throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
365
+ __name(stringReplaceAll, "stringReplaceAll");
366
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
367
+ let endIndex = 0;
368
+ let returnValue = "";
369
+ do {
370
+ const gotCR = string[index - 1] === "\r";
371
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
372
+ endIndex = index + 1;
373
+ index = string.indexOf("\n", endIndex);
374
+ } while (index !== -1);
375
+ returnValue += string.slice(endIndex);
376
+ return returnValue;
377
+ }
378
+ __name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
379
+
380
+ // node_modules/chalk/source/index.js
381
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
382
+ var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
383
+ var STYLER = /* @__PURE__ */ Symbol("STYLER");
384
+ var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
385
+ var levelMapping = [
386
+ "ansi",
387
+ "ansi",
388
+ "ansi256",
389
+ "ansi16m"
390
+ ];
391
+ var styles2 = /* @__PURE__ */ Object.create(null);
392
+ var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
393
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
394
+ throw new Error("The `level` option should be an integer from 0 to 3");
274
395
  }
275
- return await parseResponse(res);
396
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
397
+ object.level = options.level === void 0 ? colorLevel : options.level;
398
+ }, "applyOptions");
399
+ var chalkFactory = /* @__PURE__ */ __name((options) => {
400
+ const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
401
+ applyOptions(chalk2, options);
402
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
403
+ return chalk2;
404
+ }, "chalkFactory");
405
+ function createChalk(options) {
406
+ return chalkFactory(options);
276
407
  }
277
- __name(getKubeconfig, "getKubeconfig");
278
- function openBrowser(url) {
279
- const command = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
280
- const args = platform() === "win32" ? ["/c", "start", "", url] : [url];
281
- execFileSync(command, args, { stdio: "ignore" });
408
+ __name(createChalk, "createChalk");
409
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
410
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
411
+ styles2[styleName] = {
412
+ get() {
413
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
414
+ Object.defineProperty(this, styleName, { value: builder });
415
+ return builder;
416
+ }
417
+ };
282
418
  }
283
- __name(openBrowser, "openBrowser");
284
- async function loginWithToken(region, token, deps = {}) {
285
- const { now } = withDeps(deps);
286
- const normalizedRegion = normalizeRegion(region);
287
- saveAuth({
288
- region: normalizedRegion,
289
- regional_token: token,
290
- authenticated_at: now().toISOString(),
291
- auth_method: AUTH_METHOD_TOKEN
292
- }, deps);
293
- return {
294
- region: normalizedRegion,
295
- workspace: "unknown",
296
- limited: true
419
+ styles2.visible = {
420
+ get() {
421
+ const builder = createBuilder(this, this[STYLER], true);
422
+ Object.defineProperty(this, "visible", { value: builder });
423
+ return builder;
424
+ }
425
+ };
426
+ var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
427
+ if (model === "rgb") {
428
+ if (level === "ansi16m") {
429
+ return ansi_styles_default[type].ansi16m(...arguments_);
430
+ }
431
+ if (level === "ansi256") {
432
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
433
+ }
434
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
435
+ }
436
+ if (model === "hex") {
437
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
438
+ }
439
+ return ansi_styles_default[type][model](...arguments_);
440
+ }, "getModelAnsi");
441
+ var usedModels = ["rgb", "hex", "ansi256"];
442
+ for (const model of usedModels) {
443
+ styles2[model] = {
444
+ get() {
445
+ const { level } = this;
446
+ return function(...arguments_) {
447
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
448
+ return createBuilder(this, styler, this[IS_EMPTY]);
449
+ };
450
+ }
451
+ };
452
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
453
+ styles2[bgModel] = {
454
+ get() {
455
+ const { level } = this;
456
+ return function(...arguments_) {
457
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
458
+ return createBuilder(this, styler, this[IS_EMPTY]);
459
+ };
460
+ }
297
461
  };
298
462
  }
299
- __name(loginWithToken, "loginWithToken");
300
- async function loginWithDeviceFlow(region, deps = {}) {
301
- const fullDeps = withDeps(deps);
302
- const normalizedRegion = normalizeRegion(region);
303
- const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
304
- const {
305
- device_code: deviceCode,
306
- user_code: userCode,
307
- verification_uri: verificationUri,
308
- verification_uri_complete: verificationUriComplete,
309
- expires_in: expiresIn,
310
- interval = 5
311
- } = deviceAuth;
312
- const url = verificationUriComplete || verificationUri;
313
- fullDeps.stderr.write(`
314
- Please open the following URL in your browser to authorize:
315
-
316
- ${url}
317
-
318
- Authorization code: ${userCode}
319
- Expires in: ${Math.floor(expiresIn / 60)} minutes
320
-
321
- Waiting for authorization...
322
- `);
323
- if (url) {
324
- try {
325
- fullDeps.openBrowser(url);
326
- fullDeps.stderr.write("Browser opened automatically.\n");
327
- } catch {
328
- fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
463
+ var proto = Object.defineProperties(() => {
464
+ }, {
465
+ ...styles2,
466
+ level: {
467
+ enumerable: true,
468
+ get() {
469
+ return this[GENERATOR].level;
470
+ },
471
+ set(level) {
472
+ this[GENERATOR].level = level;
329
473
  }
330
474
  }
331
- const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
332
- const accessToken = tokenResponse.access_token;
333
- if (!accessToken) {
334
- throw new Error("Token response missing access_token");
475
+ });
476
+ var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
477
+ let openAll;
478
+ let closeAll;
479
+ if (parent === void 0) {
480
+ openAll = open;
481
+ closeAll = close;
482
+ } else {
483
+ openAll = parent.openAll + open;
484
+ closeAll = close + parent.closeAll;
335
485
  }
336
- fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
337
- const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
338
- const regionalToken = regionData.data?.token;
339
- const kubeconfig = regionData.data?.kubeconfig;
340
- if (!regionalToken) {
341
- throw new Error("Region token response missing data.token field");
486
+ return {
487
+ open,
488
+ close,
489
+ openAll,
490
+ closeAll,
491
+ parent
492
+ };
493
+ }, "createStyler");
494
+ var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
495
+ const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
496
+ Object.setPrototypeOf(builder, proto);
497
+ builder[GENERATOR] = self;
498
+ builder[STYLER] = _styler;
499
+ builder[IS_EMPTY] = _isEmpty;
500
+ return builder;
501
+ }, "createBuilder");
502
+ var applyStyle = /* @__PURE__ */ __name((self, string) => {
503
+ if (self.level <= 0 || !string) {
504
+ return self[IS_EMPTY] ? "" : string;
342
505
  }
343
- if (!kubeconfig) {
344
- throw new Error("Region token response missing data.kubeconfig field");
506
+ let styler = self[STYLER];
507
+ if (styler === void 0) {
508
+ return string;
345
509
  }
346
- let currentWorkspace;
347
- try {
348
- const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
349
- currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
350
- } catch {
351
- currentWorkspace = void 0;
510
+ const { openAll, closeAll } = styler;
511
+ if (string.includes("\x1B")) {
512
+ while (styler !== void 0) {
513
+ string = stringReplaceAll(string, styler.close, styler.open);
514
+ styler = styler.parent;
515
+ }
352
516
  }
353
- saveKubeconfig(kubeconfig, fullDeps);
354
- saveAuth({
355
- region: normalizedRegion,
356
- access_token: accessToken,
357
- regional_token: regionalToken,
358
- authenticated_at: fullDeps.now().toISOString(),
359
- auth_method: AUTH_METHOD_DEVICE_GRANT,
360
- ...currentWorkspace ? {
361
- current_workspace: {
362
- uid: currentWorkspace.uid,
363
- id: currentWorkspace.id,
364
- teamName: currentWorkspace.teamName
365
- }
366
- } : {}
367
- }, fullDeps);
368
- fullDeps.stderr.write("Authentication successful!\n");
369
- return {
370
- kubeconfig_path: fullDeps.paths.kubeconfigPath,
371
- region: normalizedRegion,
372
- workspace: currentWorkspace?.id || "default"
373
- };
374
- }
375
- __name(loginWithDeviceFlow, "loginWithDeviceFlow");
376
- async function listWorkspaces(deps = {}) {
377
- const auth = loadAuth(deps);
378
- if (!auth.regional_token) {
379
- throw new Error("No regional_token found. Please run: sealos-cli login");
517
+ const lfIndex = string.indexOf("\n");
518
+ if (lfIndex !== -1) {
519
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
380
520
  }
381
- const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
382
- return {
383
- current: auth.current_workspace?.id || null,
384
- workspaces: workspaces.map((workspace) => ({
385
- uid: workspace.uid,
386
- id: workspace.id,
387
- teamName: workspace.teamName,
388
- role: workspace.role,
389
- nstype: workspace.nstype
390
- }))
391
- };
392
- }
393
- __name(listWorkspaces, "listWorkspaces");
394
- async function switchWorkspace(target, deps = {}) {
395
- if (!target) {
396
- throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
521
+ return openAll + string + closeAll;
522
+ }, "applyStyle");
523
+ Object.defineProperties(createChalk.prototype, styles2);
524
+ var chalk = createChalk();
525
+ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
526
+ var source_default = chalk;
527
+
528
+ // src/lib/errors.ts
529
+ var CliError = class extends Error {
530
+ constructor(message, exitCode = 1) {
531
+ super(message);
532
+ this.exitCode = exitCode;
533
+ this.name = "CliError";
397
534
  }
398
- const fullDeps = withDeps(deps);
399
- const auth = loadAuth(fullDeps);
400
- if (!auth.regional_token) {
401
- throw new Error("No regional_token found. Please run: sealos-cli login");
535
+ exitCode;
536
+ static {
537
+ __name(this, "CliError");
402
538
  }
403
- const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
404
- if (workspaces.length === 0) {
405
- throw new Error("No workspaces found");
539
+ };
540
+ var AuthError = class extends CliError {
541
+ static {
542
+ __name(this, "AuthError");
406
543
  }
407
- const targetLower = target.toLowerCase();
408
- const match = workspaces.find(
409
- (workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
410
- );
411
- if (!match?.uid) {
412
- const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
413
- throw new Error(`No workspace matching "${target}". Available:
414
- ${available}`);
544
+ constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
545
+ super(message, 1);
546
+ this.name = "AuthError";
415
547
  }
416
- fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
417
- `);
418
- const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
419
- const newToken = switchData.data?.token;
420
- if (!newToken) {
421
- throw new Error("Switch response missing data.token");
548
+ };
549
+ var ConfigError = class extends CliError {
550
+ static {
551
+ __name(this, "ConfigError");
422
552
  }
423
- const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
424
- const kubeconfig = kubeconfigData.data?.kubeconfig;
425
- if (!kubeconfig) {
426
- throw new Error("Kubeconfig response missing data.kubeconfig");
553
+ constructor(message) {
554
+ super(message, 1);
555
+ this.name = "ConfigError";
427
556
  }
428
- const nextAuth = {
429
- ...auth,
430
- regional_token: newToken,
431
- current_workspace: {
432
- uid: match.uid,
433
- id: match.id,
434
- teamName: match.teamName
435
- }
436
- };
437
- saveAuth(nextAuth, fullDeps);
438
- saveKubeconfig(kubeconfig, fullDeps);
439
- fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
440
- `);
441
- return {
442
- workspace: {
443
- uid: match.uid,
444
- id: match.id,
445
- teamName: match.teamName
446
- },
447
- kubeconfig_path: fullDeps.paths.kubeconfigPath
448
- };
449
- }
450
- __name(switchWorkspace, "switchWorkspace");
451
-
452
- // node_modules/chalk/source/vendor/ansi-styles/index.js
453
- var ANSI_BACKGROUND_OFFSET = 10;
454
- var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
455
- var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
456
- var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
457
- var styles = {
458
- modifier: {
459
- reset: [0, 0],
460
- // 21 isn't widely supported and 22 does the same thing
461
- bold: [1, 22],
462
- dim: [2, 22],
463
- italic: [3, 23],
464
- underline: [4, 24],
465
- overline: [53, 55],
466
- inverse: [7, 27],
467
- hidden: [8, 28],
468
- strikethrough: [9, 29]
469
- },
470
- color: {
471
- black: [30, 39],
472
- red: [31, 39],
473
- green: [32, 39],
474
- yellow: [33, 39],
475
- blue: [34, 39],
476
- magenta: [35, 39],
477
- cyan: [36, 39],
478
- white: [37, 39],
479
- // Bright color
480
- blackBright: [90, 39],
481
- gray: [90, 39],
482
- // Alias of `blackBright`
483
- grey: [90, 39],
484
- // Alias of `blackBright`
485
- redBright: [91, 39],
486
- greenBright: [92, 39],
487
- yellowBright: [93, 39],
488
- blueBright: [94, 39],
489
- magentaBright: [95, 39],
490
- cyanBright: [96, 39],
491
- whiteBright: [97, 39]
492
- },
493
- bgColor: {
494
- bgBlack: [40, 49],
495
- bgRed: [41, 49],
496
- bgGreen: [42, 49],
497
- bgYellow: [43, 49],
498
- bgBlue: [44, 49],
499
- bgMagenta: [45, 49],
500
- bgCyan: [46, 49],
501
- bgWhite: [47, 49],
502
- // Bright color
503
- bgBlackBright: [100, 49],
504
- bgGray: [100, 49],
505
- // Alias of `bgBlackBright`
506
- bgGrey: [100, 49],
507
- // Alias of `bgBlackBright`
508
- bgRedBright: [101, 49],
509
- bgGreenBright: [102, 49],
510
- bgYellowBright: [103, 49],
511
- bgBlueBright: [104, 49],
512
- bgMagentaBright: [105, 49],
513
- bgCyanBright: [106, 49],
514
- bgWhiteBright: [107, 49]
557
+ };
558
+ var ApiError = class extends CliError {
559
+ constructor(message, statusCode, code, details) {
560
+ super(message, 1);
561
+ this.statusCode = statusCode;
562
+ this.code = code;
563
+ this.details = details;
564
+ this.name = "ApiError";
565
+ }
566
+ statusCode;
567
+ code;
568
+ details;
569
+ static {
570
+ __name(this, "ApiError");
515
571
  }
516
572
  };
517
- var modifierNames = Object.keys(styles.modifier);
518
- var foregroundColorNames = Object.keys(styles.color);
519
- var backgroundColorNames = Object.keys(styles.bgColor);
520
- var colorNames = [...foregroundColorNames, ...backgroundColorNames];
521
- function assembleStyles() {
522
- const codes = /* @__PURE__ */ new Map();
523
- for (const [groupName, group] of Object.entries(styles)) {
524
- for (const [styleName, style] of Object.entries(group)) {
525
- styles[styleName] = {
526
- open: `\x1B[${style[0]}m`,
527
- close: `\x1B[${style[1]}m`
528
- };
529
- group[styleName] = styles[styleName];
530
- codes.set(style[0], style[1]);
531
- }
532
- Object.defineProperty(styles, groupName, {
533
- value: group,
534
- enumerable: false
535
- });
573
+ function mapApiError(status, body) {
574
+ const message = body?.error?.message || `API request failed with status ${status}`;
575
+ if (status === 401) {
576
+ return new AuthError(message);
536
577
  }
537
- Object.defineProperty(styles, "codes", {
538
- value: codes,
539
- enumerable: false
540
- });
541
- styles.color.close = "\x1B[39m";
542
- styles.bgColor.close = "\x1B[49m";
543
- styles.color.ansi = wrapAnsi16();
544
- styles.color.ansi256 = wrapAnsi256();
545
- styles.color.ansi16m = wrapAnsi16m();
546
- styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
547
- styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
548
- styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
549
- Object.defineProperties(styles, {
550
- rgbToAnsi256: {
551
- value(red2, green2, blue2) {
552
- if (red2 === green2 && green2 === blue2) {
553
- if (red2 < 8) {
554
- return 16;
555
- }
556
- if (red2 > 248) {
557
- return 231;
558
- }
559
- return Math.round((red2 - 8) / 247 * 24) + 232;
560
- }
561
- return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
562
- },
563
- enumerable: false
564
- },
565
- hexToRgb: {
566
- value(hex) {
567
- const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
568
- if (!matches) {
569
- return [0, 0, 0];
570
- }
571
- let [colorString] = matches;
572
- if (colorString.length === 3) {
573
- colorString = [...colorString].map((character) => character + character).join("");
574
- }
575
- const integer = Number.parseInt(colorString, 16);
576
- return [
577
- /* eslint-disable no-bitwise */
578
- integer >> 16 & 255,
579
- integer >> 8 & 255,
580
- integer & 255
581
- /* eslint-enable no-bitwise */
582
- ];
583
- },
584
- enumerable: false
585
- },
586
- hexToAnsi256: {
587
- value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
588
- enumerable: false
589
- },
590
- ansi256ToAnsi: {
591
- value(code) {
592
- if (code < 8) {
593
- return 30 + code;
594
- }
595
- if (code < 16) {
596
- return 90 + (code - 8);
597
- }
598
- let red2;
599
- let green2;
600
- let blue2;
601
- if (code >= 232) {
602
- red2 = ((code - 232) * 10 + 8) / 255;
603
- green2 = red2;
604
- blue2 = red2;
605
- } else {
606
- code -= 16;
607
- const remainder = code % 36;
608
- red2 = Math.floor(code / 36) / 5;
609
- green2 = Math.floor(remainder / 6) / 5;
610
- blue2 = remainder % 6 / 5;
611
- }
612
- const value = Math.max(red2, green2, blue2) * 2;
613
- if (value === 0) {
614
- return 30;
615
- }
616
- let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
617
- if (value === 2) {
618
- result += 60;
578
+ return new ApiError(message, status, body?.error?.code, body?.error?.details);
579
+ }
580
+ __name(mapApiError, "mapApiError");
581
+ function handleError(error2) {
582
+ if (error2 instanceof ApiError) {
583
+ console.error(source_default.red("Error:"), error2.message);
584
+ if (error2.details) {
585
+ if (Array.isArray(error2.details)) {
586
+ for (const d of error2.details) {
587
+ console.error(source_default.yellow(` ${d.field}:`), d.message);
619
588
  }
620
- return result;
621
- },
622
- enumerable: false
623
- },
624
- rgbToAnsi: {
625
- value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
626
- enumerable: false
627
- },
628
- hexToAnsi: {
629
- value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
630
- enumerable: false
589
+ } else {
590
+ console.error(source_default.yellow(" Details:"), error2.details);
591
+ }
631
592
  }
632
- });
633
- return styles;
593
+ process.exit(error2.exitCode);
594
+ }
595
+ if (error2 instanceof CliError) {
596
+ console.error(source_default.red("Error:"), error2.message);
597
+ process.exit(error2.exitCode);
598
+ }
599
+ if (error2 instanceof Error) {
600
+ console.error(source_default.red("Error:"), error2.message);
601
+ if (process.env.DEBUG) {
602
+ console.error(error2.stack);
603
+ }
604
+ process.exit(1);
605
+ }
606
+ console.error(source_default.red("Error:"), "An unknown error occurred");
607
+ process.exit(1);
634
608
  }
635
- __name(assembleStyles, "assembleStyles");
636
- var ansiStyles = assembleStyles();
637
- var ansi_styles_default = ansiStyles;
609
+ __name(handleError, "handleError");
638
610
 
639
- // node_modules/chalk/source/vendor/supports-color/index.js
640
- import process2 from "process";
641
- import os from "os";
642
- import tty from "tty";
643
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
644
- const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
645
- const position = argv.indexOf(prefix + flag);
646
- const terminatorPosition = argv.indexOf("--");
647
- return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
611
+ // src/lib/auth.ts
612
+ var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
613
+ var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
614
+ var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
615
+ var AUTH_METHOD_TOKEN = "token";
616
+ var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
617
+ function getAuthPaths(sealosDir = join(homedir(), ".sealos")) {
618
+ return {
619
+ sealosDir,
620
+ authPath: join(sealosDir, "auth.json"),
621
+ kubeconfigPath: join(sealosDir, "kubeconfig")
622
+ };
648
623
  }
649
- __name(hasFlag, "hasFlag");
650
- var { env } = process2;
651
- var flagForceColor;
652
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
653
- flagForceColor = 0;
654
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
655
- flagForceColor = 1;
624
+ __name(getAuthPaths, "getAuthPaths");
625
+ function normalizeRegion(region) {
626
+ return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
627
+ }
628
+ __name(normalizeRegion, "normalizeRegion");
629
+ function createDefaultAuthDependencies() {
630
+ return {
631
+ fetch,
632
+ sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
633
+ openBrowser,
634
+ now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
635
+ paths: getAuthPaths(),
636
+ stderr: process.stderr
637
+ };
638
+ }
639
+ __name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
640
+ function withDeps(deps = {}) {
641
+ return {
642
+ ...createDefaultAuthDependencies(),
643
+ ...deps
644
+ };
645
+ }
646
+ __name(withDeps, "withDeps");
647
+ function ensureSealosDir(paths) {
648
+ mkdirSync(paths.sealosDir, { recursive: true });
649
+ }
650
+ __name(ensureSealosDir, "ensureSealosDir");
651
+ function saveAuth(auth, deps = {}) {
652
+ const { paths } = withDeps(deps);
653
+ ensureSealosDir(paths);
654
+ writeFileSync(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
655
+ }
656
+ __name(saveAuth, "saveAuth");
657
+ function loadAuth(deps = {}) {
658
+ const { paths } = withDeps(deps);
659
+ if (!existsSync(paths.authPath)) {
660
+ throw new Error("Not authenticated. Please run: sealos-cli login");
661
+ }
662
+ return JSON.parse(readFileSync(paths.authPath, "utf-8"));
663
+ }
664
+ __name(loadAuth, "loadAuth");
665
+ function getKubeconfigContent(deps = {}) {
666
+ const { paths } = withDeps(deps);
667
+ try {
668
+ return readFileSync(paths.kubeconfigPath, "utf-8");
669
+ } catch {
670
+ return null;
671
+ }
672
+ }
673
+ __name(getKubeconfigContent, "getKubeconfigContent");
674
+ function getAuthHeaders(deps = {}) {
675
+ const kubeconfig = getKubeconfigContent(deps);
676
+ return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
677
+ }
678
+ __name(getAuthHeaders, "getAuthHeaders");
679
+ function requireAuth(deps = {}) {
680
+ const headers = getAuthHeaders(deps);
681
+ if (!headers) {
682
+ throw new Error('Authentication required. Please run "sealos-cli login" first.');
683
+ }
684
+ return headers;
685
+ }
686
+ __name(requireAuth, "requireAuth");
687
+ function saveKubeconfig(kubeconfig, deps = {}) {
688
+ const { paths } = withDeps(deps);
689
+ ensureSealosDir(paths);
690
+ writeFileSync(paths.kubeconfigPath, kubeconfig, { mode: 384 });
691
+ }
692
+ __name(saveKubeconfig, "saveKubeconfig");
693
+ function clearAuth(deps = {}) {
694
+ const { paths } = withDeps(deps);
695
+ rmSync(paths.authPath, { force: true });
696
+ rmSync(paths.kubeconfigPath, { force: true });
656
697
  }
657
- function envForceColor() {
658
- if ("FORCE_COLOR" in env) {
659
- if (env.FORCE_COLOR === "true") {
660
- return 1;
661
- }
662
- if (env.FORCE_COLOR === "false") {
663
- return 0;
698
+ __name(clearAuth, "clearAuth");
699
+ function checkAuth(deps = {}) {
700
+ const { paths } = withDeps(deps);
701
+ if (!existsSync(paths.kubeconfigPath)) {
702
+ return { authenticated: false };
703
+ }
704
+ try {
705
+ const kubeconfig = readFileSync(paths.kubeconfigPath, "utf-8");
706
+ if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
707
+ return { authenticated: false };
664
708
  }
665
- return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
709
+ const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
710
+ return {
711
+ authenticated: true,
712
+ kubeconfig_path: paths.kubeconfigPath,
713
+ region: auth.region || "unknown",
714
+ workspace: auth.current_workspace?.id || "unknown"
715
+ };
716
+ } catch {
717
+ return { authenticated: false };
666
718
  }
667
719
  }
668
- __name(envForceColor, "envForceColor");
669
- function translateLevel(level) {
670
- if (level === 0) {
671
- return false;
720
+ __name(checkAuth, "checkAuth");
721
+ function getAuthInfo(deps = {}) {
722
+ const { paths } = withDeps(deps);
723
+ const status = checkAuth(deps);
724
+ if (!status.authenticated) {
725
+ return { authenticated: false };
672
726
  }
727
+ const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
673
728
  return {
674
- level,
675
- hasBasic: true,
676
- has256: level >= 2,
677
- has16m: level >= 3
729
+ ...status,
730
+ auth_method: auth.auth_method || "unknown",
731
+ authenticated_at: auth.authenticated_at || "unknown",
732
+ current_workspace: auth.current_workspace || null
678
733
  };
679
734
  }
680
- __name(translateLevel, "translateLevel");
681
- function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
682
- const noFlagForceColor = envForceColor();
683
- if (noFlagForceColor !== void 0) {
684
- flagForceColor = noFlagForceColor;
685
- }
686
- const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
687
- if (forceColor === 0) {
688
- return 0;
689
- }
690
- if (sniffFlags) {
691
- if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
692
- return 3;
693
- }
694
- if (hasFlag("color=256")) {
695
- return 2;
696
- }
697
- }
698
- if ("TF_BUILD" in env && "AGENT_NAME" in env) {
699
- return 1;
700
- }
701
- if (haveStream && !streamIsTTY && forceColor === void 0) {
702
- return 0;
703
- }
704
- const min = forceColor || 0;
705
- if (env.TERM === "dumb") {
706
- return min;
707
- }
708
- if (process2.platform === "win32") {
709
- const osRelease = os.release().split(".");
710
- if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
711
- return Number(osRelease[2]) >= 14931 ? 3 : 2;
712
- }
713
- return 1;
714
- }
715
- if ("CI" in env) {
716
- if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
717
- return 3;
718
- }
719
- if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
720
- return 1;
721
- }
722
- return min;
723
- }
724
- if ("TEAMCITY_VERSION" in env) {
725
- return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
726
- }
727
- if (env.COLORTERM === "truecolor") {
728
- return 3;
729
- }
730
- if (env.TERM === "xterm-kitty") {
731
- return 3;
732
- }
733
- if (env.TERM === "xterm-ghostty") {
734
- return 3;
735
- }
736
- if (env.TERM === "wezterm") {
737
- return 3;
738
- }
739
- if ("TERM_PROGRAM" in env) {
740
- const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
741
- switch (env.TERM_PROGRAM) {
742
- case "iTerm.app": {
743
- return version >= 3 ? 3 : 2;
744
- }
745
- case "Apple_Terminal": {
746
- return 2;
747
- }
735
+ __name(getAuthInfo, "getAuthInfo");
736
+ async function parseResponse(res) {
737
+ const body = await res.json();
738
+ if (body && typeof body === "object" && typeof body.code === "number" && ![0, 200].includes(body.code)) {
739
+ const message = body.message || `Sealos API request failed with code ${body.code}`;
740
+ if (body.code === 401) {
741
+ throw new AuthError(`Authentication expired. Please run "sealos-cli login" again. (${message})`);
748
742
  }
743
+ throw new Error(message);
749
744
  }
750
- if (/-256(color)?$/i.test(env.TERM)) {
751
- return 2;
752
- }
753
- if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
754
- return 1;
755
- }
756
- if ("COLORTERM" in env) {
757
- return 1;
758
- }
759
- return min;
745
+ return body;
760
746
  }
761
- __name(_supportsColor, "_supportsColor");
762
- function createSupportsColor(stream, options = {}) {
763
- const level = _supportsColor(stream, {
764
- streamIsTTY: stream && stream.isTTY,
765
- ...options
766
- });
767
- return translateLevel(level);
747
+ __name(parseResponse, "parseResponse");
748
+ async function readErrorBody(res) {
749
+ return await res.text().catch(() => "");
768
750
  }
769
- __name(createSupportsColor, "createSupportsColor");
770
- var supportsColor = {
771
- stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
772
- stderr: createSupportsColor({ isTTY: tty.isatty(2) })
773
- };
774
- var supports_color_default = supportsColor;
775
-
776
- // node_modules/chalk/source/utilities.js
777
- function stringReplaceAll(string, substring, replacer) {
778
- let index = string.indexOf(substring);
779
- if (index === -1) {
780
- return string;
751
+ __name(readErrorBody, "readErrorBody");
752
+ async function requestDeviceAuthorization(region, deps = {}) {
753
+ const { fetch: fetchImpl } = withDeps(deps);
754
+ const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
755
+ method: "POST",
756
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
757
+ body: new URLSearchParams({
758
+ client_id: SEALOS_AUTH_CLIENT_ID,
759
+ grant_type: DEVICE_GRANT_TYPE
760
+ })
761
+ });
762
+ if (!res.ok) {
763
+ const body = await readErrorBody(res);
764
+ throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
781
765
  }
782
- const substringLength = substring.length;
783
- let endIndex = 0;
784
- let returnValue = "";
785
- do {
786
- returnValue += string.slice(endIndex, index) + substring + replacer;
787
- endIndex = index + substringLength;
788
- index = string.indexOf(substring, endIndex);
789
- } while (index !== -1);
790
- returnValue += string.slice(endIndex);
791
- return returnValue;
792
- }
793
- __name(stringReplaceAll, "stringReplaceAll");
794
- function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
795
- let endIndex = 0;
796
- let returnValue = "";
797
- do {
798
- const gotCR = string[index - 1] === "\r";
799
- returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
800
- endIndex = index + 1;
801
- index = string.indexOf("\n", endIndex);
802
- } while (index !== -1);
803
- returnValue += string.slice(endIndex);
804
- return returnValue;
766
+ return await parseResponse(res);
805
767
  }
806
- __name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
807
-
808
- // node_modules/chalk/source/index.js
809
- var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
810
- var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
811
- var STYLER = /* @__PURE__ */ Symbol("STYLER");
812
- var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
813
- var levelMapping = [
814
- "ansi",
815
- "ansi",
816
- "ansi256",
817
- "ansi16m"
818
- ];
819
- var styles2 = /* @__PURE__ */ Object.create(null);
820
- var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
821
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
822
- throw new Error("The `level` option should be an integer from 0 to 3");
823
- }
824
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
825
- object.level = options.level === void 0 ? colorLevel : options.level;
826
- }, "applyOptions");
827
- var chalkFactory = /* @__PURE__ */ __name((options) => {
828
- const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
829
- applyOptions(chalk2, options);
830
- Object.setPrototypeOf(chalk2, createChalk.prototype);
831
- return chalk2;
832
- }, "chalkFactory");
833
- function createChalk(options) {
834
- return chalkFactory(options);
768
+ __name(requestDeviceAuthorization, "requestDeviceAuthorization");
769
+ async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
770
+ const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
771
+ const maxWait = Math.min(expiresIn, 600) * 1e3;
772
+ const deadline = now().getTime() + maxWait;
773
+ let pollInterval = interval * 1e3;
774
+ let lastLoggedMinute = -1;
775
+ while (now().getTime() < deadline) {
776
+ await sleep(pollInterval);
777
+ const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
778
+ if (remaining !== lastLoggedMinute && remaining > 0) {
779
+ lastLoggedMinute = remaining;
780
+ stderr.write(` Waiting for authorization... (${remaining} min remaining)
781
+ `);
782
+ }
783
+ const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
784
+ method: "POST",
785
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
786
+ body: new URLSearchParams({
787
+ client_id: SEALOS_AUTH_CLIENT_ID,
788
+ grant_type: DEVICE_GRANT_TYPE,
789
+ device_code: deviceCode
790
+ })
791
+ });
792
+ if (res.ok) {
793
+ return await parseResponse(res);
794
+ }
795
+ const body = await res.json().catch(() => ({}));
796
+ switch (body.error) {
797
+ case "authorization_pending":
798
+ break;
799
+ case "slow_down":
800
+ pollInterval += 5e3;
801
+ break;
802
+ case "access_denied":
803
+ throw new Error("Authorization denied by user");
804
+ case "expired_token":
805
+ throw new Error("Device code expired. Please run login again.");
806
+ default:
807
+ throw new Error(`Token request failed: ${body.error || res.statusText}`);
808
+ }
809
+ }
810
+ throw new Error("Authorization timed out (10 minutes). Please run login again.");
835
811
  }
836
- __name(createChalk, "createChalk");
837
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
838
- for (const [styleName, style] of Object.entries(ansi_styles_default)) {
839
- styles2[styleName] = {
840
- get() {
841
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
842
- Object.defineProperty(this, styleName, { value: builder });
843
- return builder;
812
+ __name(pollForToken, "pollForToken");
813
+ async function getRegionToken(region, globalToken, deps = {}) {
814
+ const { fetch: fetchImpl } = withDeps(deps);
815
+ const res = await fetchImpl(`${region}/api/auth/regionToken`, {
816
+ method: "POST",
817
+ headers: {
818
+ Authorization: globalToken,
819
+ "Content-Type": "application/json"
844
820
  }
845
- };
821
+ });
822
+ if (!res.ok) {
823
+ const body = await readErrorBody(res);
824
+ throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
825
+ }
826
+ return await parseResponse(res);
846
827
  }
847
- styles2.visible = {
848
- get() {
849
- const builder = createBuilder(this, this[STYLER], true);
850
- Object.defineProperty(this, "visible", { value: builder });
851
- return builder;
828
+ __name(getRegionToken, "getRegionToken");
829
+ function normalizeWorkspaces(data) {
830
+ const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
831
+ return Array.isArray(namespaces) ? namespaces : [];
832
+ }
833
+ __name(normalizeWorkspaces, "normalizeWorkspaces");
834
+ async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
835
+ const { fetch: fetchImpl } = withDeps(deps);
836
+ const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
837
+ headers: { Authorization: regionalToken }
838
+ });
839
+ if (!res.ok) {
840
+ const body = await readErrorBody(res);
841
+ throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
852
842
  }
853
- };
854
- var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
855
- if (model === "rgb") {
856
- if (level === "ansi16m") {
857
- return ansi_styles_default[type].ansi16m(...arguments_);
858
- }
859
- if (level === "ansi256") {
860
- return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
861
- }
862
- return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
843
+ return normalizeWorkspaces(await parseResponse(res));
844
+ }
845
+ __name(listRemoteWorkspaces, "listRemoteWorkspaces");
846
+ async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
847
+ const { fetch: fetchImpl } = withDeps(deps);
848
+ const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
849
+ method: "POST",
850
+ headers: {
851
+ Authorization: regionalToken,
852
+ "Content-Type": "application/json"
853
+ },
854
+ body: JSON.stringify({ ns_uid: nsUid })
855
+ });
856
+ if (!res.ok) {
857
+ const body = await readErrorBody(res);
858
+ throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
863
859
  }
864
- if (model === "hex") {
865
- return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
860
+ return await parseResponse(res);
861
+ }
862
+ __name(switchRemoteWorkspace, "switchRemoteWorkspace");
863
+ async function getKubeconfig(region, regionalToken, deps = {}) {
864
+ const { fetch: fetchImpl } = withDeps(deps);
865
+ const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
866
+ headers: { Authorization: regionalToken }
867
+ });
868
+ if (!res.ok) {
869
+ const body = await readErrorBody(res);
870
+ throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
866
871
  }
867
- return ansi_styles_default[type][model](...arguments_);
868
- }, "getModelAnsi");
869
- var usedModels = ["rgb", "hex", "ansi256"];
870
- for (const model of usedModels) {
871
- styles2[model] = {
872
- get() {
873
- const { level } = this;
874
- return function(...arguments_) {
875
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
876
- return createBuilder(this, styler, this[IS_EMPTY]);
877
- };
878
- }
879
- };
880
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
881
- styles2[bgModel] = {
882
- get() {
883
- const { level } = this;
884
- return function(...arguments_) {
885
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
886
- return createBuilder(this, styler, this[IS_EMPTY]);
887
- };
888
- }
872
+ return await parseResponse(res);
873
+ }
874
+ __name(getKubeconfig, "getKubeconfig");
875
+ function openBrowser(url) {
876
+ const command = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
877
+ const args = platform() === "win32" ? ["/c", "start", "", url] : [url];
878
+ execFileSync(command, args, { stdio: "ignore" });
879
+ }
880
+ __name(openBrowser, "openBrowser");
881
+ async function loginWithToken(region, token, deps = {}) {
882
+ const { now } = withDeps(deps);
883
+ const normalizedRegion = normalizeRegion(region);
884
+ saveAuth({
885
+ region: normalizedRegion,
886
+ regional_token: token,
887
+ authenticated_at: now().toISOString(),
888
+ auth_method: AUTH_METHOD_TOKEN
889
+ }, deps);
890
+ return {
891
+ region: normalizedRegion,
892
+ workspace: "unknown",
893
+ limited: true
889
894
  };
890
895
  }
891
- var proto = Object.defineProperties(() => {
892
- }, {
893
- ...styles2,
894
- level: {
895
- enumerable: true,
896
- get() {
897
- return this[GENERATOR].level;
898
- },
899
- set(level) {
900
- this[GENERATOR].level = level;
896
+ __name(loginWithToken, "loginWithToken");
897
+ async function loginWithDeviceFlow(region, deps = {}) {
898
+ const fullDeps = withDeps(deps);
899
+ const normalizedRegion = normalizeRegion(region);
900
+ const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
901
+ const {
902
+ device_code: deviceCode,
903
+ user_code: userCode,
904
+ verification_uri: verificationUri,
905
+ verification_uri_complete: verificationUriComplete,
906
+ expires_in: expiresIn,
907
+ interval = 5
908
+ } = deviceAuth;
909
+ const url = verificationUriComplete || verificationUri;
910
+ fullDeps.stderr.write(`
911
+ Please open the following URL in your browser to authorize:
912
+
913
+ ${url}
914
+
915
+ Authorization code: ${userCode}
916
+ Expires in: ${Math.floor(expiresIn / 60)} minutes
917
+
918
+ Waiting for authorization...
919
+ `);
920
+ if (url) {
921
+ try {
922
+ fullDeps.openBrowser(url);
923
+ fullDeps.stderr.write("Browser opened automatically.\n");
924
+ } catch {
925
+ fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
901
926
  }
902
927
  }
903
- });
904
- var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
905
- let openAll;
906
- let closeAll;
907
- if (parent === void 0) {
908
- openAll = open;
909
- closeAll = close;
910
- } else {
911
- openAll = parent.openAll + open;
912
- closeAll = close + parent.closeAll;
928
+ const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
929
+ const accessToken = tokenResponse.access_token;
930
+ if (!accessToken) {
931
+ throw new Error("Token response missing access_token");
932
+ }
933
+ fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
934
+ const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
935
+ const regionalToken = regionData.data?.token;
936
+ const kubeconfig = regionData.data?.kubeconfig;
937
+ if (!regionalToken) {
938
+ throw new Error("Region token response missing data.token field");
939
+ }
940
+ if (!kubeconfig) {
941
+ throw new Error("Region token response missing data.kubeconfig field");
942
+ }
943
+ let currentWorkspace;
944
+ try {
945
+ const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
946
+ currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
947
+ } catch {
948
+ currentWorkspace = void 0;
913
949
  }
950
+ saveKubeconfig(kubeconfig, fullDeps);
951
+ saveAuth({
952
+ region: normalizedRegion,
953
+ access_token: accessToken,
954
+ regional_token: regionalToken,
955
+ authenticated_at: fullDeps.now().toISOString(),
956
+ auth_method: AUTH_METHOD_DEVICE_GRANT,
957
+ ...currentWorkspace ? {
958
+ current_workspace: {
959
+ uid: currentWorkspace.uid,
960
+ id: currentWorkspace.id,
961
+ teamName: currentWorkspace.teamName
962
+ }
963
+ } : {}
964
+ }, fullDeps);
965
+ fullDeps.stderr.write("Authentication successful!\n");
914
966
  return {
915
- open,
916
- close,
917
- openAll,
918
- closeAll,
919
- parent
967
+ kubeconfig_path: fullDeps.paths.kubeconfigPath,
968
+ region: normalizedRegion,
969
+ workspace: currentWorkspace?.id || "default"
920
970
  };
921
- }, "createStyler");
922
- var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
923
- const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
924
- Object.setPrototypeOf(builder, proto);
925
- builder[GENERATOR] = self;
926
- builder[STYLER] = _styler;
927
- builder[IS_EMPTY] = _isEmpty;
928
- return builder;
929
- }, "createBuilder");
930
- var applyStyle = /* @__PURE__ */ __name((self, string) => {
931
- if (self.level <= 0 || !string) {
932
- return self[IS_EMPTY] ? "" : string;
971
+ }
972
+ __name(loginWithDeviceFlow, "loginWithDeviceFlow");
973
+ async function listWorkspaces(deps = {}) {
974
+ const auth = loadAuth(deps);
975
+ if (!auth.regional_token) {
976
+ throw new Error("No regional_token found. Please run: sealos-cli login");
977
+ }
978
+ const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
979
+ return {
980
+ current: auth.current_workspace?.id || null,
981
+ workspaces: workspaces.map((workspace) => ({
982
+ uid: workspace.uid,
983
+ id: workspace.id,
984
+ teamName: workspace.teamName,
985
+ role: workspace.role,
986
+ nstype: workspace.nstype
987
+ }))
988
+ };
989
+ }
990
+ __name(listWorkspaces, "listWorkspaces");
991
+ async function switchWorkspace(target, deps = {}) {
992
+ if (!target) {
993
+ throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
933
994
  }
934
- let styler = self[STYLER];
935
- if (styler === void 0) {
936
- return string;
995
+ const fullDeps = withDeps(deps);
996
+ const auth = loadAuth(fullDeps);
997
+ if (!auth.regional_token) {
998
+ throw new Error("No regional_token found. Please run: sealos-cli login");
937
999
  }
938
- const { openAll, closeAll } = styler;
939
- if (string.includes("\x1B")) {
940
- while (styler !== void 0) {
941
- string = stringReplaceAll(string, styler.close, styler.open);
942
- styler = styler.parent;
943
- }
1000
+ const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
1001
+ if (workspaces.length === 0) {
1002
+ throw new Error("No workspaces found");
944
1003
  }
945
- const lfIndex = string.indexOf("\n");
946
- if (lfIndex !== -1) {
947
- string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
1004
+ const targetLower = target.toLowerCase();
1005
+ const match = workspaces.find(
1006
+ (workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
1007
+ );
1008
+ if (!match?.uid) {
1009
+ const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
1010
+ throw new Error(`No workspace matching "${target}". Available:
1011
+ ${available}`);
948
1012
  }
949
- return openAll + string + closeAll;
950
- }, "applyStyle");
951
- Object.defineProperties(createChalk.prototype, styles2);
952
- var chalk = createChalk();
953
- var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
954
- var source_default = chalk;
1013
+ fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
1014
+ `);
1015
+ const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
1016
+ const newToken = switchData.data?.token;
1017
+ if (!newToken) {
1018
+ throw new Error("Switch response missing data.token");
1019
+ }
1020
+ const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
1021
+ const kubeconfig = kubeconfigData.data?.kubeconfig;
1022
+ if (!kubeconfig) {
1023
+ throw new Error("Kubeconfig response missing data.kubeconfig");
1024
+ }
1025
+ const nextAuth = {
1026
+ ...auth,
1027
+ regional_token: newToken,
1028
+ current_workspace: {
1029
+ uid: match.uid,
1030
+ id: match.id,
1031
+ teamName: match.teamName
1032
+ }
1033
+ };
1034
+ saveAuth(nextAuth, fullDeps);
1035
+ saveKubeconfig(kubeconfig, fullDeps);
1036
+ fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
1037
+ `);
1038
+ return {
1039
+ workspace: {
1040
+ uid: match.uid,
1041
+ id: match.id,
1042
+ teamName: match.teamName
1043
+ },
1044
+ kubeconfig_path: fullDeps.paths.kubeconfigPath
1045
+ };
1046
+ }
1047
+ __name(switchWorkspace, "switchWorkspace");
955
1048
 
956
1049
  // src/lib/output.ts
957
1050
  import { table } from "table";
@@ -3909,92 +4002,9 @@ function spinner(text) {
3909
4002
  }
3910
4003
  __name(spinner, "spinner");
3911
4004
 
3912
- // src/lib/errors.ts
3913
- var CliError = class extends Error {
3914
- constructor(message, exitCode = 1) {
3915
- super(message);
3916
- this.exitCode = exitCode;
3917
- this.name = "CliError";
3918
- }
3919
- exitCode;
3920
- static {
3921
- __name(this, "CliError");
3922
- }
3923
- };
3924
- var AuthError = class extends CliError {
3925
- static {
3926
- __name(this, "AuthError");
3927
- }
3928
- constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
3929
- super(message, 1);
3930
- this.name = "AuthError";
3931
- }
3932
- };
3933
- var ConfigError = class extends CliError {
3934
- static {
3935
- __name(this, "ConfigError");
3936
- }
3937
- constructor(message) {
3938
- super(message, 1);
3939
- this.name = "ConfigError";
3940
- }
3941
- };
3942
- var ApiError = class extends CliError {
3943
- constructor(message, statusCode, code, details) {
3944
- super(message, 1);
3945
- this.statusCode = statusCode;
3946
- this.code = code;
3947
- this.details = details;
3948
- this.name = "ApiError";
3949
- }
3950
- statusCode;
3951
- code;
3952
- details;
3953
- static {
3954
- __name(this, "ApiError");
3955
- }
3956
- };
3957
- function mapApiError(status, body) {
3958
- const message = body?.error?.message || `API request failed with status ${status}`;
3959
- if (status === 401) {
3960
- return new AuthError(message);
3961
- }
3962
- return new ApiError(message, status, body?.error?.code, body?.error?.details);
3963
- }
3964
- __name(mapApiError, "mapApiError");
3965
- function handleError(error2) {
3966
- if (error2 instanceof ApiError) {
3967
- console.error(source_default.red("Error:"), error2.message);
3968
- if (error2.details) {
3969
- if (Array.isArray(error2.details)) {
3970
- for (const d of error2.details) {
3971
- console.error(source_default.yellow(` ${d.field}:`), d.message);
3972
- }
3973
- } else {
3974
- console.error(source_default.yellow(" Details:"), error2.details);
3975
- }
3976
- }
3977
- process.exit(error2.exitCode);
3978
- }
3979
- if (error2 instanceof CliError) {
3980
- console.error(source_default.red("Error:"), error2.message);
3981
- process.exit(error2.exitCode);
3982
- }
3983
- if (error2 instanceof Error) {
3984
- console.error(source_default.red("Error:"), error2.message);
3985
- if (process.env.DEBUG) {
3986
- console.error(error2.stack);
3987
- }
3988
- process.exit(1);
3989
- }
3990
- console.error(source_default.red("Error:"), "An unknown error occurred");
3991
- process.exit(1);
3992
- }
3993
- __name(handleError, "handleError");
3994
-
3995
4005
  // src/commands/auth/login.ts
3996
4006
  function createLoginCommand() {
3997
- return new Command("login").description("Login to Sealos Cloud").argument("[region]", "Sealos region URL (e.g., https://usw-1.sealos.io)").option("-t, --token <token>", "Store a regional token without OAuth device login").option("-o, --output <format>", "Output format: json, table", "table").action(async (region, options) => {
4007
+ return new Command("login").description("Login to Sealos Cloud").argument("[region]", "Sealos region URL (e.g., https://usw-1.sealos.io)").option("-t, --token <token>", "Store a regional token without OAuth device login").option("-o, --output <format>", "Output format: json, table", "json").action(async (region, options) => {
3998
4008
  try {
3999
4009
  const result = options.token ? await loginWithToken(region, options.token) : await loginWithDeviceFlow(region);
4000
4010
  if (options.token) {
@@ -4019,14 +4029,32 @@ __name(createLoginCommand, "createLoginCommand");
4019
4029
  // src/commands/auth/logout.ts
4020
4030
  import { Command as Command2 } from "commander";
4021
4031
  function createLogoutCommand() {
4022
- return new Command2("logout").description("Logout from Sealos Cloud").action(async () => {
4032
+ return new Command2("logout").description("Logout from Sealos Cloud").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4023
4033
  try {
4024
4034
  const status = checkAuth();
4025
4035
  if (!status.authenticated) {
4036
+ if (options.output === "json") {
4037
+ outputJson({
4038
+ success: true,
4039
+ action: "logout",
4040
+ authenticated: false,
4041
+ changed: false
4042
+ });
4043
+ return;
4044
+ }
4026
4045
  warn("You are not logged in");
4027
4046
  return;
4028
4047
  }
4029
4048
  clearAuth();
4049
+ if (options.output === "json") {
4050
+ outputJson({
4051
+ success: true,
4052
+ action: "logout",
4053
+ authenticated: false,
4054
+ changed: true
4055
+ });
4056
+ return;
4057
+ }
4030
4058
  success2("Logged out from Sealos Cloud");
4031
4059
  } catch (error2) {
4032
4060
  handleError(error2);
@@ -4038,7 +4066,7 @@ __name(createLogoutCommand, "createLogoutCommand");
4038
4066
  // src/commands/auth/whoami.ts
4039
4067
  import { Command as Command3 } from "commander";
4040
4068
  function createWhoamiCommand() {
4041
- return new Command3("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4069
+ return new Command3("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4042
4070
  try {
4043
4071
  const authInfo = getAuthInfo();
4044
4072
  if (!authInfo.authenticated) {
@@ -4118,7 +4146,7 @@ function createAuthCommand() {
4118
4146
  handleError(error2);
4119
4147
  }
4120
4148
  });
4121
- authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4149
+ authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4122
4150
  try {
4123
4151
  const result = await listWorkspaces();
4124
4152
  if (options.output === "json") {
@@ -4140,7 +4168,7 @@ function createAuthCommand() {
4140
4168
  handleError(error2);
4141
4169
  }
4142
4170
  });
4143
- authCmd.command("switch").description("Switch workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "table").action(async (namespace, options) => {
4171
+ authCmd.command("switch").description("Switch workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "json").action(async (namespace, options) => {
4144
4172
  try {
4145
4173
  const result = await switchWorkspace(namespace);
4146
4174
  if (options.output === "json") {
@@ -4160,7 +4188,7 @@ __name(createAuthCommand, "createAuthCommand");
4160
4188
  import { Command as Command5 } from "commander";
4161
4189
  function createWorkspaceCommand() {
4162
4190
  const workspaceCmd = new Command5("workspace").alias("ws").description("Manage workspaces");
4163
- workspaceCmd.command("switch").description("Switch to another workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "table").action(async (namespace, options) => {
4191
+ workspaceCmd.command("switch").description("Switch to another workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "json").action(async (namespace, options) => {
4164
4192
  try {
4165
4193
  const result = await switchWorkspace(namespace);
4166
4194
  if (options.output === "json") {
@@ -4172,7 +4200,7 @@ function createWorkspaceCommand() {
4172
4200
  handleError(error2);
4173
4201
  }
4174
4202
  });
4175
- workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4203
+ workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4176
4204
  try {
4177
4205
  const result = await listWorkspaces();
4178
4206
  if (options.output === "json") {
@@ -4194,7 +4222,7 @@ function createWorkspaceCommand() {
4194
4222
  handleError(error2);
4195
4223
  }
4196
4224
  });
4197
- workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4225
+ workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4198
4226
  try {
4199
4227
  const authInfo = getAuthInfo();
4200
4228
  if (!authInfo.authenticated) {
@@ -5146,7 +5174,7 @@ function printTemplates(templates) {
5146
5174
  __name(printTemplates, "printTemplates");
5147
5175
  function createDevboxCommand() {
5148
5176
  const devboxCmd = new Command6("devbox").alias("dev").description("Manage devbox instances");
5149
- devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
5177
+ devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
5150
5178
  const client = createDevboxClient();
5151
5179
  const { data, error: error2, response } = await client.GET("/devbox", {
5152
5180
  headers: ctx.auth
@@ -5159,7 +5187,7 @@ function createDevboxCommand() {
5159
5187
  }
5160
5188
  printDevboxList(data);
5161
5189
  }));
5162
- devboxCmd.command("create").description("Create a new devbox").requiredOption("--name <name>", "Devbox name").option("--runtime <runtime>", "Runtime environment name").option("--template <runtime>", "Alias for --runtime").option("--cpu <cpu>", "CPU cores", "1").option("--memory <memory>", "Memory in GB", "2").option("--port <spec>", "Port spec, e.g. 8080:http:public or number=8080,protocol=http", collectOption, []).option("--env <NAME=VALUE>", "Environment variable", collectOption, []).option("--secret-env <NAME=SECRET:KEY>", "Environment variable from secret", collectOption, []).option("--autostart", "Auto start devbox after creation").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Creating devbox..." }, async (ctx, options) => {
5190
+ devboxCmd.command("create").description("Create a new devbox").requiredOption("--name <name>", "Devbox name").option("--runtime <runtime>", "Runtime environment name").option("--template <runtime>", "Alias for --runtime").option("--cpu <cpu>", "CPU cores", "1").option("--memory <memory>", "Memory in GB", "2").option("--port <spec>", "Port spec, e.g. 8080:http:public or number=8080,protocol=http", collectOption, []).option("--env <NAME=VALUE>", "Environment variable", collectOption, []).option("--secret-env <NAME=SECRET:KEY>", "Environment variable from secret", collectOption, []).option("--autostart", "Auto start devbox after creation").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Creating devbox..." }, async (ctx, options) => {
5163
5191
  const client = createDevboxClient();
5164
5192
  const { data, error: error2, response } = await client.POST("/devbox", {
5165
5193
  headers: ctx.auth,
@@ -5174,7 +5202,7 @@ function createDevboxCommand() {
5174
5202
  ctx.spinner.succeed(`Devbox "${data.name}" created`);
5175
5203
  printCreateResult(data);
5176
5204
  }));
5177
- devboxCmd.command("get <name>").description("Get devbox details").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading devbox..." }, async (ctx, name, options) => {
5205
+ devboxCmd.command("get <name>").description("Get devbox details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devbox..." }, async (ctx, name, options) => {
5178
5206
  const client = createDevboxClient();
5179
5207
  const { data, error: error2, response } = await client.GET("/devbox/{name}", {
5180
5208
  headers: ctx.auth,
@@ -5190,7 +5218,7 @@ function createDevboxCommand() {
5190
5218
  }
5191
5219
  printDevboxDetail(data);
5192
5220
  }));
5193
- devboxCmd.command("update <name>").description("Update devbox resources or ports").option("--cpu <cpu>", "CPU cores").option("--memory <memory>", "Memory in GB").option("--port <spec>", "Port spec. Existing ports can include portName=...", collectOption, []).action(withAuth({ spinnerText: "Updating devbox..." }, async (ctx, name, options) => {
5221
+ devboxCmd.command("update <name>").description("Update devbox resources or ports").option("--cpu <cpu>", "CPU cores").option("--memory <memory>", "Memory in GB").option("--port <spec>", "Port spec. Existing ports can include portName=...", collectOption, []).option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Updating devbox..." }, async (ctx, name, options) => {
5194
5222
  const client = createDevboxClient();
5195
5223
  const { error: error2, response } = await client.PATCH("/devbox/{name}", {
5196
5224
  headers: ctx.auth,
@@ -5200,9 +5228,20 @@ function createDevboxCommand() {
5200
5228
  body: buildUpdateDevboxBody(options)
5201
5229
  });
5202
5230
  if (error2) throw mapApiError(response.status, error2);
5231
+ if (options.output === "json") {
5232
+ ctx.spinner.stop();
5233
+ outputJson({
5234
+ success: true,
5235
+ action: "update",
5236
+ resource: "devbox",
5237
+ name,
5238
+ status: "requested"
5239
+ });
5240
+ return;
5241
+ }
5203
5242
  ctx.spinner.succeed(`Devbox "${name}" update requested`);
5204
5243
  }));
5205
- devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name) => {
5244
+ devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name, options) => {
5206
5245
  const client = createDevboxClient();
5207
5246
  const { error: error2, response } = await client.DELETE("/devbox/{name}", {
5208
5247
  headers: ctx.auth,
@@ -5211,6 +5250,17 @@ function createDevboxCommand() {
5211
5250
  }
5212
5251
  });
5213
5252
  if (error2) throw mapApiError(response.status, error2);
5253
+ if (options.output === "json") {
5254
+ ctx.spinner.stop();
5255
+ outputJson({
5256
+ success: true,
5257
+ action: "delete",
5258
+ resource: "devbox",
5259
+ name,
5260
+ status: "deleted"
5261
+ });
5262
+ return;
5263
+ }
5214
5264
  ctx.spinner.succeed(`Devbox "${name}" deleted`);
5215
5265
  }));
5216
5266
  const lifecycleActions = [
@@ -5222,7 +5272,7 @@ function createDevboxCommand() {
5222
5272
  for (const action of lifecycleActions) {
5223
5273
  const command = devboxCmd.command(`${action.name} <name>`).description(`${action.name.charAt(0).toUpperCase()}${action.name.slice(1)} a devbox`);
5224
5274
  if (action.alias) command.alias(action.alias);
5225
- command.action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name) => {
5275
+ command.option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name, options) => {
5226
5276
  const client = createDevboxClient();
5227
5277
  const { error: error2, response } = await client.POST(action.endpoint, {
5228
5278
  headers: ctx.auth,
@@ -5232,10 +5282,21 @@ function createDevboxCommand() {
5232
5282
  body: {}
5233
5283
  });
5234
5284
  if (error2) throw mapApiError(response.status, error2);
5285
+ if (options.output === "json") {
5286
+ ctx.spinner.stop();
5287
+ outputJson({
5288
+ success: true,
5289
+ action: action.name,
5290
+ resource: "devbox",
5291
+ name,
5292
+ status: "requested"
5293
+ });
5294
+ return;
5295
+ }
5235
5296
  ctx.spinner.succeed(`Devbox "${name}" ${action.done}`);
5236
5297
  }));
5237
5298
  }
5238
- devboxCmd.command("autostart <name>").description("Configure devbox autostart").option("--exec-command <command>", "Command to execute when the devbox starts").action(withAuth({ spinnerText: "Configuring autostart..." }, async (ctx, name, options) => {
5299
+ devboxCmd.command("autostart <name>").description("Configure devbox autostart").option("--exec-command <command>", "Command to execute when the devbox starts").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Configuring autostart..." }, async (ctx, name, options) => {
5239
5300
  const client = createDevboxClient();
5240
5301
  const body = options.execCommand ? { execCommand: options.execCommand } : {};
5241
5302
  const { error: error2, response } = await client.POST("/devbox/{name}/autostart", {
@@ -5246,9 +5307,21 @@ function createDevboxCommand() {
5246
5307
  body
5247
5308
  });
5248
5309
  if (error2) throw mapApiError(response.status, error2);
5310
+ if (options.output === "json") {
5311
+ ctx.spinner.stop();
5312
+ outputJson({
5313
+ success: true,
5314
+ action: "autostart",
5315
+ resource: "devbox",
5316
+ name,
5317
+ execCommand: options.execCommand ?? null,
5318
+ status: "configured"
5319
+ });
5320
+ return;
5321
+ }
5249
5322
  ctx.spinner.succeed(`Autostart configured for "${name}"`);
5250
5323
  }));
5251
- devboxCmd.command("monitor <name>").description("Get devbox monitoring data").option("--start <timestamp>", "Start timestamp in seconds or milliseconds").option("--end <timestamp>", "End timestamp in seconds or milliseconds").option("--step <step>", "Sampling interval, e.g. 2m").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading monitor data..." }, async (ctx, name, options) => {
5324
+ devboxCmd.command("monitor <name>").description("Get devbox monitoring data").option("--start <timestamp>", "Start timestamp in seconds or milliseconds").option("--end <timestamp>", "End timestamp in seconds or milliseconds").option("--step <step>", "Sampling interval, e.g. 2m").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading monitor data..." }, async (ctx, name, options) => {
5252
5325
  const client = createDevboxClient();
5253
5326
  const { data, error: error2, response } = await client.GET("/devbox/{name}/monitor", {
5254
5327
  headers: ctx.auth,
@@ -5269,7 +5342,7 @@ function createDevboxCommand() {
5269
5342
  }
5270
5343
  printMonitor(data);
5271
5344
  }));
5272
- devboxCmd.command("templates").description("List available devbox templates").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading devbox templates..." }, async (ctx, options) => {
5345
+ devboxCmd.command("templates").description("List available devbox templates").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devbox templates..." }, async (ctx, options) => {
5273
5346
  const client = createDevboxClient();
5274
5347
  const { data, error: error2, response } = await client.GET("/devbox/templates", {
5275
5348
  headers: ctx.auth
@@ -5283,7 +5356,7 @@ function createDevboxCommand() {
5283
5356
  printTemplates(data);
5284
5357
  }));
5285
5358
  const releasesCommand = devboxCmd.command("releases").description("Manage devbox releases");
5286
- releasesCommand.command("list <name>").description("List devbox releases").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading releases..." }, async (ctx, name, options) => {
5359
+ releasesCommand.command("list <name>").description("List devbox releases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading releases..." }, async (ctx, name, options) => {
5287
5360
  const client = createDevboxClient();
5288
5361
  const { data, error: error2, response } = await client.GET("/devbox/{name}/releases", {
5289
5362
  headers: ctx.auth,
@@ -5299,7 +5372,7 @@ function createDevboxCommand() {
5299
5372
  }
5300
5373
  printReleases(data);
5301
5374
  }));
5302
- releasesCommand.command("create <name>").description("Create a devbox release").requiredOption("--tag <tag>", "Release tag").option("--description <description>", "Release description").option("--exec-command <command>", "Autostart command after release restart").option("--no-start", "Keep devbox stopped after the release build completes").action(withAuth({ spinnerText: "Creating release..." }, async (ctx, name, options) => {
5375
+ releasesCommand.command("create <name>").description("Create a devbox release").requiredOption("--tag <tag>", "Release tag").option("--description <description>", "Release description").option("--exec-command <command>", "Autostart command after release restart").option("--no-start", "Keep devbox stopped after the release build completes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Creating release..." }, async (ctx, name, options) => {
5303
5376
  const client = createDevboxClient();
5304
5377
  const { data, error: error2, response } = await client.POST("/devbox/{name}/releases", {
5305
5378
  headers: ctx.auth,
@@ -5309,9 +5382,14 @@ function createDevboxCommand() {
5309
5382
  body: buildReleaseBody(options)
5310
5383
  });
5311
5384
  if (error2) throw mapApiError(response.status, error2);
5385
+ if (options.output === "json") {
5386
+ ctx.spinner.stop();
5387
+ outputJson(data);
5388
+ return;
5389
+ }
5312
5390
  ctx.spinner.succeed(`Release "${options.tag}" accepted for "${data.name}" (${data.status})`);
5313
5391
  }));
5314
- releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag) => {
5392
+ releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag, options) => {
5315
5393
  const client = createDevboxClient();
5316
5394
  const { error: error2, response } = await client.DELETE("/devbox/{name}/releases/{tag}", {
5317
5395
  headers: ctx.auth,
@@ -5320,9 +5398,21 @@ function createDevboxCommand() {
5320
5398
  }
5321
5399
  });
5322
5400
  if (error2) throw mapApiError(response.status, error2);
5401
+ if (options.output === "json") {
5402
+ ctx.spinner.stop();
5403
+ outputJson({
5404
+ success: true,
5405
+ action: "delete",
5406
+ resource: "devbox-release",
5407
+ name,
5408
+ tag,
5409
+ status: "deleted"
5410
+ });
5411
+ return;
5412
+ }
5323
5413
  ctx.spinner.succeed(`Release "${tag}" deleted for "${name}"`);
5324
5414
  }));
5325
- releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag) => {
5415
+ releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag, options) => {
5326
5416
  const client = createDevboxClient();
5327
5417
  const { error: error2, response } = await client.POST("/devbox/{name}/releases/{tag}/deploy", {
5328
5418
  headers: ctx.auth,
@@ -5331,9 +5421,21 @@ function createDevboxCommand() {
5331
5421
  }
5332
5422
  });
5333
5423
  if (error2) throw mapApiError(response.status, error2);
5424
+ if (options.output === "json") {
5425
+ ctx.spinner.stop();
5426
+ outputJson({
5427
+ success: true,
5428
+ action: "deploy",
5429
+ resource: "devbox-release",
5430
+ name,
5431
+ tag,
5432
+ status: "deployed"
5433
+ });
5434
+ return;
5435
+ }
5334
5436
  ctx.spinner.succeed(`Release "${tag}" deployed for "${name}"`);
5335
5437
  }));
5336
- devboxCmd.command("deployments <name>").description("List deployed applications from a devbox").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading deployments..." }, async (ctx, name, options) => {
5438
+ devboxCmd.command("deployments <name>").description("List deployed applications from a devbox").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading deployments..." }, async (ctx, name, options) => {
5337
5439
  const client = createDevboxClient();
5338
5440
  const { data, error: error2, response } = await client.GET("/devbox/{name}/deployments", {
5339
5441
  headers: ctx.auth,
@@ -5581,7 +5683,7 @@ function printConnectionDetail(connection) {
5581
5683
  __name(printConnectionDetail, "printConnectionDetail");
5582
5684
  function createDatabaseCommand() {
5583
5685
  const dbCmd = new Command7("database").alias("db").description("Manage databases");
5584
- dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
5686
+ dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
5585
5687
  const client = createDatabaseClient();
5586
5688
  const { data, error: error2, response } = await client.GET("/databases", {
5587
5689
  headers: ctx.auth
@@ -5620,7 +5722,7 @@ function createDatabaseCommand() {
5620
5722
  }
5621
5723
  outputTable(rows);
5622
5724
  }));
5623
- dbCmd.command("versions").description("List supported database versions (public endpoint)").option("-o, --output <format>", "Output format (json|table)", "table").option("--host <host>", "Sealos region host for public version lookup, e.g. https://gzg.sealos.run").option("--type <type>", "Filter versions by database type").action(withErrorHandling({ spinnerText: "Loading versions..." }, async (ctx, options) => {
5725
+ dbCmd.command("versions").description("List supported database versions (public endpoint)").option("-o, --output <format>", "Output format (json|table)", "json").option("--host <host>", "Sealos region host for public version lookup, e.g. https://gzg.sealos.run").option("--type <type>", "Filter versions by database type").action(withErrorHandling({ spinnerText: "Loading versions..." }, async (ctx, options) => {
5624
5726
  const client = createDatabaseClient({ baseUrl: options.host });
5625
5727
  const { data, error: error2, response } = await client.GET("/databases/versions");
5626
5728
  if (error2) throw mapApiError(response.status, error2);
@@ -5656,7 +5758,7 @@ function createDatabaseCommand() {
5656
5758
  }
5657
5759
  outputTable(rows);
5658
5760
  }));
5659
- dbCmd.command("create <type>").description("Create a database").requiredOption("--name <name>", "Database name").option("--version <version>", "Database version").option("--cpu <cpu>", "CPU cores per replica", "1").option("--memory <memory>", "Memory in GB per replica", "1").option("--storage <storage>", "Storage in GB per replica", "3").option("--replicas <replicas>", "Replica count", "1").option("--termination-policy <policy>", "Termination policy (delete|wipeout)").option("--backup-start", "Enable automatic backups").option("--backup-type <type>", "Automatic backup frequency (day|hour|week)").option("--backup-week <day>", "Weekday for weekly backups", collectOption2, []).option("--backup-hour <hour>", "Backup hour (00-23)").option("--backup-minute <minute>", "Backup minute (00-59)").option("--backup-save-time <count>", "Retention count").option("--backup-save-type <type>", "Retention unit (days|hours|weeks|months)").option("--param <KEY=VALUE>", "Database parameter override", collectOption2, []).option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({
5761
+ dbCmd.command("create <type>").description("Create a database").requiredOption("--name <name>", "Database name").option("--version <version>", "Database version").option("--cpu <cpu>", "CPU cores per replica", "1").option("--memory <memory>", "Memory in GB per replica", "1").option("--storage <storage>", "Storage in GB per replica", "3").option("--replicas <replicas>", "Replica count", "1").option("--termination-policy <policy>", "Termination policy (delete|wipeout)").option("--backup-start", "Enable automatic backups").option("--backup-type <type>", "Automatic backup frequency (day|hour|week)").option("--backup-week <day>", "Weekday for weekly backups", collectOption2, []).option("--backup-hour <hour>", "Backup hour (00-23)").option("--backup-minute <minute>", "Backup minute (00-59)").option("--backup-save-time <count>", "Retention count").option("--backup-save-type <type>", "Retention unit (days|hours|weeks|months)").option("--param <KEY=VALUE>", "Database parameter override", collectOption2, []).option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5660
5762
  spinnerText: "Creating database..."
5661
5763
  }, async (ctx, type, options) => {
5662
5764
  const client = createDatabaseClient();
@@ -5691,7 +5793,7 @@ function createDatabaseCommand() {
5691
5793
  console.log(source_default.dim(` Provisioning status: ${data.status}`));
5692
5794
  console.log(source_default.dim(` Next: sealos-cli database get ${data.name}`));
5693
5795
  }));
5694
- dbCmd.command("get <name>").alias("describe").description("Get database details").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading database..." }, async (ctx, name, options) => {
5796
+ dbCmd.command("get <name>").alias("describe").description("Get database details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading database..." }, async (ctx, name, options) => {
5695
5797
  const client = createDatabaseClient();
5696
5798
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
5697
5799
  headers: ctx.auth,
@@ -5707,7 +5809,7 @@ function createDatabaseCommand() {
5707
5809
  }
5708
5810
  printDatabaseDetail(data);
5709
5811
  }));
5710
- dbCmd.command("connection <name>").description("Show database connection details").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading connection details..." }, async (ctx, name, options) => {
5812
+ dbCmd.command("connection <name>").description("Show database connection details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading connection details..." }, async (ctx, name, options) => {
5711
5813
  const client = createDatabaseClient();
5712
5814
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
5713
5815
  headers: ctx.auth,
@@ -5723,7 +5825,7 @@ function createDatabaseCommand() {
5723
5825
  }
5724
5826
  printConnectionDetail(data.connection);
5725
5827
  }));
5726
- dbCmd.command("update <name>").description("Update database resources").option("--cpu <cpu>", "CPU cores per replica").option("--memory <memory>", "Memory in GB per replica").option("--storage <storage>", "Storage in GB per replica").option("--replicas <replicas>", "Replica count").action(withAuth({
5828
+ dbCmd.command("update <name>").description("Update database resources").option("--cpu <cpu>", "CPU cores per replica").option("--memory <memory>", "Memory in GB per replica").option("--storage <storage>", "Storage in GB per replica").option("--replicas <replicas>", "Replica count").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5727
5829
  spinnerText: "Updating database..."
5728
5830
  }, async (ctx, name, options) => {
5729
5831
  const quota = buildQuota(options);
@@ -5739,9 +5841,20 @@ function createDatabaseCommand() {
5739
5841
  body: { quota }
5740
5842
  });
5741
5843
  if (error2) throw mapApiError(response.status, error2);
5844
+ if (options.output === "json") {
5845
+ ctx.spinner.stop();
5846
+ outputJson({
5847
+ success: true,
5848
+ action: "update",
5849
+ resource: "database",
5850
+ name,
5851
+ status: "requested"
5852
+ });
5853
+ return;
5854
+ }
5742
5855
  ctx.spinner.succeed(`Database "${name}" update requested`);
5743
5856
  }));
5744
- dbCmd.command("start <name>").description("Start a database").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name) => {
5857
+ dbCmd.command("start <name>").description("Start a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name, options) => {
5745
5858
  const client = createDatabaseClient();
5746
5859
  const { error: error2, response } = await client.POST("/databases/{databaseName}/start", {
5747
5860
  headers: ctx.auth,
@@ -5750,9 +5863,20 @@ function createDatabaseCommand() {
5750
5863
  }
5751
5864
  });
5752
5865
  if (error2) throw mapApiError(response.status, error2);
5866
+ if (options.output === "json") {
5867
+ ctx.spinner.stop();
5868
+ outputJson({
5869
+ success: true,
5870
+ action: "start",
5871
+ resource: "database",
5872
+ name,
5873
+ status: "requested"
5874
+ });
5875
+ return;
5876
+ }
5753
5877
  ctx.spinner.succeed(`Database "${name}" start requested`);
5754
5878
  }));
5755
- dbCmd.command("pause <name>").alias("stop").description("Pause a database").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name) => {
5879
+ dbCmd.command("pause <name>").alias("stop").description("Pause a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name, options) => {
5756
5880
  const client = createDatabaseClient();
5757
5881
  const { error: error2, response } = await client.POST("/databases/{databaseName}/pause", {
5758
5882
  headers: ctx.auth,
@@ -5761,9 +5885,20 @@ function createDatabaseCommand() {
5761
5885
  }
5762
5886
  });
5763
5887
  if (error2) throw mapApiError(response.status, error2);
5888
+ if (options.output === "json") {
5889
+ ctx.spinner.stop();
5890
+ outputJson({
5891
+ success: true,
5892
+ action: "pause",
5893
+ resource: "database",
5894
+ name,
5895
+ status: "requested"
5896
+ });
5897
+ return;
5898
+ }
5764
5899
  ctx.spinner.succeed(`Database "${name}" pause requested`);
5765
5900
  }));
5766
- dbCmd.command("restart <name>").description("Restart a database").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name) => {
5901
+ dbCmd.command("restart <name>").description("Restart a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name, options) => {
5767
5902
  const client = createDatabaseClient();
5768
5903
  const { error: error2, response } = await client.POST("/databases/{databaseName}/restart", {
5769
5904
  headers: ctx.auth,
@@ -5772,9 +5907,20 @@ function createDatabaseCommand() {
5772
5907
  }
5773
5908
  });
5774
5909
  if (error2) throw mapApiError(response.status, error2);
5910
+ if (options.output === "json") {
5911
+ ctx.spinner.stop();
5912
+ outputJson({
5913
+ success: true,
5914
+ action: "restart",
5915
+ resource: "database",
5916
+ name,
5917
+ status: "requested"
5918
+ });
5919
+ return;
5920
+ }
5775
5921
  ctx.spinner.succeed(`Database "${name}" restart requested`);
5776
5922
  }));
5777
- dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name) => {
5923
+ dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name, options) => {
5778
5924
  const client = createDatabaseClient();
5779
5925
  const { error: error2, response } = await client.DELETE("/databases/{databaseName}", {
5780
5926
  headers: ctx.auth,
@@ -5783,9 +5929,20 @@ function createDatabaseCommand() {
5783
5929
  }
5784
5930
  });
5785
5931
  if (error2) throw mapApiError(response.status, error2);
5932
+ if (options.output === "json") {
5933
+ ctx.spinner.stop();
5934
+ outputJson({
5935
+ success: true,
5936
+ action: "delete",
5937
+ resource: "database",
5938
+ name,
5939
+ status: "requested"
5940
+ });
5941
+ return;
5942
+ }
5786
5943
  ctx.spinner.succeed(`Database "${name}" delete requested`);
5787
5944
  }));
5788
- dbCmd.command("backups <name>").description("List backups for a database").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading backups..." }, async (ctx, name, options) => {
5945
+ dbCmd.command("backups <name>").description("List backups for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading backups..." }, async (ctx, name, options) => {
5789
5946
  const client = createDatabaseClient();
5790
5947
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}/backups", {
5791
5948
  headers: ctx.auth,
@@ -5819,7 +5976,7 @@ function createDatabaseCommand() {
5819
5976
  }
5820
5977
  outputTable(rows);
5821
5978
  }));
5822
- dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").action(withAuth({
5979
+ dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5823
5980
  spinnerText: "Creating backup..."
5824
5981
  }, async (ctx, name, options) => {
5825
5982
  const client = createDatabaseClient();
@@ -5834,11 +5991,23 @@ function createDatabaseCommand() {
5834
5991
  body
5835
5992
  });
5836
5993
  if (error2) throw mapApiError(response.status, error2);
5994
+ if (options.output === "json") {
5995
+ ctx.spinner.stop();
5996
+ outputJson({
5997
+ success: true,
5998
+ action: "backup",
5999
+ resource: "database",
6000
+ name,
6001
+ backupName: options.name ?? null,
6002
+ status: "requested"
6003
+ });
6004
+ return;
6005
+ }
5837
6006
  ctx.spinner.succeed(`Backup requested for database "${name}"`);
5838
6007
  }));
5839
- dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").action(withAuth({
6008
+ dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5840
6009
  spinnerText: "Deleting backup..."
5841
- }, async (ctx, databaseName, backupName) => {
6010
+ }, async (ctx, databaseName, backupName, options) => {
5842
6011
  const client = createDatabaseClient();
5843
6012
  const { error: error2, response } = await client.DELETE("/databases/{databaseName}/backups/{backupName}", {
5844
6013
  headers: ctx.auth,
@@ -5847,9 +6016,21 @@ function createDatabaseCommand() {
5847
6016
  }
5848
6017
  });
5849
6018
  if (error2) throw mapApiError(response.status, error2);
6019
+ if (options.output === "json") {
6020
+ ctx.spinner.stop();
6021
+ outputJson({
6022
+ success: true,
6023
+ action: "backup-delete",
6024
+ resource: "database-backup",
6025
+ databaseName,
6026
+ backupName,
6027
+ status: "deleted"
6028
+ });
6029
+ return;
6030
+ }
5850
6031
  ctx.spinner.succeed(`Backup "${backupName}" deleted`);
5851
6032
  }));
5852
- dbCmd.command("restore <databaseName>").description("Restore a database from a backup").requiredOption("--from <backupName>", "Backup name to restore from").option("--name <name>", "Name for the restored database").option("--replicas <replicas>", "Replica count for the restored database").action(withAuth({
6033
+ dbCmd.command("restore <databaseName>").description("Restore a database from a backup").requiredOption("--from <backupName>", "Backup name to restore from").option("--name <name>", "Name for the restored database").option("--replicas <replicas>", "Replica count for the restored database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5853
6034
  spinnerText: "Restoring database..."
5854
6035
  }, async (ctx, databaseName, options) => {
5855
6036
  const client = createDatabaseClient();
@@ -5864,9 +6045,22 @@ function createDatabaseCommand() {
5864
6045
  body
5865
6046
  });
5866
6047
  if (error2) throw mapApiError(response.status, error2);
6048
+ if (options.output === "json") {
6049
+ ctx.spinner.stop();
6050
+ outputJson({
6051
+ success: true,
6052
+ action: "restore",
6053
+ resource: "database",
6054
+ databaseName,
6055
+ backupName: options.from,
6056
+ restoredName: options.name ?? null,
6057
+ status: "requested"
6058
+ });
6059
+ return;
6060
+ }
5867
6061
  ctx.spinner.succeed(`Restore requested from backup "${options.from}"`);
5868
6062
  }));
5869
- dbCmd.command("enable-public <name>").description("Enable public access for a database").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name) => {
6063
+ dbCmd.command("enable-public <name>").description("Enable public access for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name, options) => {
5870
6064
  const client = createDatabaseClient();
5871
6065
  const { error: error2, response } = await client.POST("/databases/{databaseName}/enable-public", {
5872
6066
  headers: ctx.auth,
@@ -5875,9 +6069,20 @@ function createDatabaseCommand() {
5875
6069
  }
5876
6070
  });
5877
6071
  if (error2) throw mapApiError(response.status, error2);
6072
+ if (options.output === "json") {
6073
+ ctx.spinner.stop();
6074
+ outputJson({
6075
+ success: true,
6076
+ action: "enable-public",
6077
+ resource: "database",
6078
+ name,
6079
+ status: "enabled"
6080
+ });
6081
+ return;
6082
+ }
5878
6083
  ctx.spinner.succeed(`Public access enabled for "${name}"`);
5879
6084
  }));
5880
- dbCmd.command("disable-public <name>").description("Disable public access for a database").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name) => {
6085
+ dbCmd.command("disable-public <name>").description("Disable public access for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name, options) => {
5881
6086
  const client = createDatabaseClient();
5882
6087
  const { error: error2, response } = await client.POST("/databases/{databaseName}/disable-public", {
5883
6088
  headers: ctx.auth,
@@ -5886,9 +6091,20 @@ function createDatabaseCommand() {
5886
6091
  }
5887
6092
  });
5888
6093
  if (error2) throw mapApiError(response.status, error2);
6094
+ if (options.output === "json") {
6095
+ ctx.spinner.stop();
6096
+ outputJson({
6097
+ success: true,
6098
+ action: "disable-public",
6099
+ resource: "database",
6100
+ name,
6101
+ status: "disabled"
6102
+ });
6103
+ return;
6104
+ }
5889
6105
  ctx.spinner.succeed(`Public access disabled for "${name}"`);
5890
6106
  }));
5891
- dbCmd.command("logs <podName>").description("Get parsed database logs for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").requiredOption("--log-path <path>", 'Log path to read. Use "log-files" first to discover valid paths').option("--page <page>", "Page number", "1").option("--page-size <pageSize>", "Page size", "200").option("-o, --output <format>", "Output format (plain|json|table)", "plain").action(withAuth({
6107
+ dbCmd.command("logs <podName>").description("Get parsed database logs for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").requiredOption("--log-path <path>", 'Log path to read. Use "log-files" first to discover valid paths').option("--page <page>", "Page number", "1").option("--page-size <pageSize>", "Page size", "200").option("-o, --output <format>", "Output format (json|table|plain)", "json").action(withAuth({
5892
6108
  spinnerText: "Loading logs..."
5893
6109
  }, async (ctx, podName, options) => {
5894
6110
  const client = createDatabaseClient();
@@ -5925,7 +6141,7 @@ function createDatabaseCommand() {
5925
6141
  console.log(source_default.dim(`
5926
6142
  page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${String(data.data.metadata.hasMore)}`));
5927
6143
  }));
5928
- dbCmd.command("log-files <podName>").description("List database log files for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({
6144
+ dbCmd.command("log-files <podName>").description("List database log files for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5929
6145
  spinnerText: "Loading log files..."
5930
6146
  }, async (ctx, podName, options) => {
5931
6147
  const client = createDatabaseClient();
@@ -6119,6 +6335,11 @@ function createTemplateCommand() {
6119
6335
  body: body2
6120
6336
  });
6121
6337
  if (error3) throw mapApiError(response2.status, error3);
6338
+ if (deployOptions.output === "json") {
6339
+ ctx.spinner.stop();
6340
+ outputJson(data2);
6341
+ return;
6342
+ }
6122
6343
  ctx.spinner.succeed(`Instance "${data2.name}" created successfully`);
6123
6344
  printInstanceResult(data2, { template: catalogTemplate });
6124
6345
  return;
@@ -6130,6 +6351,11 @@ function createTemplateCommand() {
6130
6351
  body
6131
6352
  });
6132
6353
  if (error2) throw mapApiError(response.status, error2);
6354
+ if (deployOptions.output === "json") {
6355
+ ctx.spinner.stop();
6356
+ outputJson(data);
6357
+ return;
6358
+ }
6133
6359
  if (deployOptions.dryRun) {
6134
6360
  ctx.spinner.succeed("Raw template validation passed; no resources were created");
6135
6361
  printInstanceResult(data, { raw: true, dryRun: true });
@@ -6138,7 +6364,7 @@ function createTemplateCommand() {
6138
6364
  ctx.spinner.succeed(`Raw template deployed as "${data.name}"`);
6139
6365
  printInstanceResult(data, { raw: true });
6140
6366
  });
6141
- tplCmd.command("list").description("List available templates").option("-c, --category <category>", "Filter by category").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "table").action(withErrorHandling({ spinnerText: "Loading templates..." }, async (ctx, options) => {
6367
+ tplCmd.command("list").description("List available templates").option("-c, --category <category>", "Filter by category").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "json").action(withErrorHandling({ spinnerText: "Loading templates..." }, async (ctx, options) => {
6142
6368
  const client = createTemplateClient();
6143
6369
  const { data, error: error2, response } = await client.GET("/templates", {
6144
6370
  params: { query: options.language ? { language: options.language } : {} }
@@ -6166,7 +6392,7 @@ function createTemplateCommand() {
6166
6392
  }
6167
6393
  outputTable(rows);
6168
6394
  }));
6169
- tplCmd.command("get <name>").alias("describe").description("Get template details").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "table").action(withErrorHandling({ spinnerText: "Loading template..." }, async (ctx, name, options) => {
6395
+ tplCmd.command("get <name>").alias("describe").description("Get template details").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "json").action(withErrorHandling({ spinnerText: "Loading template..." }, async (ctx, name, options) => {
6170
6396
  const client = createTemplateClient();
6171
6397
  const { data, error: error2, response } = await client.GET("/templates/{name}", {
6172
6398
  params: {
@@ -6214,7 +6440,7 @@ function createTemplateCommand() {
6214
6440
  outputTable(argRows);
6215
6441
  }
6216
6442
  }));
6217
- tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance) => {
6443
+ tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance, options) => {
6218
6444
  const client = createTemplateClient();
6219
6445
  const { error: error2, response } = await client.DELETE("/templates/instances/{instanceName}", {
6220
6446
  headers: ctx.auth,
@@ -6223,9 +6449,20 @@ function createTemplateCommand() {
6223
6449
  }
6224
6450
  });
6225
6451
  if (error2) throw mapApiError(response.status, error2);
6452
+ if (options.output === "json") {
6453
+ ctx.spinner.stop();
6454
+ outputJson({
6455
+ success: true,
6456
+ action: "delete",
6457
+ resource: "template-instance",
6458
+ instance,
6459
+ status: "deleted"
6460
+ });
6461
+ return;
6462
+ }
6226
6463
  ctx.spinner.succeed(`Instance "${instance}" deleted`);
6227
6464
  }));
6228
- tplCmd.command("deploy [template]").description("Deploy a template (from catalog or raw YAML)").option("--name <name>", "Instance name (required when deploying from catalog)").option("--file <path>", "Path to template YAML file").option("--yaml <yaml>", "Template YAML string").option("--set <KEY=VALUE...>", "Set template arguments", (val, prev) => [...prev, val], []).option("--dry-run", "Validate raw template YAML without creating resources").addHelpText("after", `
6465
+ tplCmd.command("deploy [template]").description("Deploy a template (from catalog or raw YAML)").option("--name <name>", "Instance name (required when deploying from catalog)").option("--file <path>", "Path to template YAML file").option("--yaml <yaml>", "Template YAML string").option("--set <KEY=VALUE...>", "Set template arguments", (val, prev) => [...prev, val], []).option("--dry-run", "Validate raw template YAML without creating resources").option("-o, --output <format>", "Output format (json|table)", "json").addHelpText("after", `
6229
6466
  Examples:
6230
6467
  Catalog:
6231
6468
  sealos-cli template deploy perplexica --name my-app --set OPENAI_API_KEY=xxx
@@ -6247,7 +6484,7 @@ __name(createTemplateCommand, "createTemplateCommand");
6247
6484
  // package.json
6248
6485
  var package_default = {
6249
6486
  name: "sealos-cli",
6250
- version: "1.1.1",
6487
+ version: "1.1.2",
6251
6488
  description: "Official CLI tool for Sealos Cloud - Manage auth, workspaces, devboxes, databases, and templates",
6252
6489
  types: "dist/main.d.ts",
6253
6490
  type: "module",