sealos-cli 1.1.0 → 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/main.cjs CHANGED
@@ -47,940 +47,1033 @@ var import_commander = require("commander");
47
47
  // src/lib/auth.ts
48
48
  var import_node_child_process = require("child_process");
49
49
  var import_node_fs = require("fs");
50
- var import_node_os = require("os");
50
+ var import_node_os2 = require("os");
51
51
  var import_node_path = require("path");
52
- var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
53
- var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
54
- var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
55
- var AUTH_METHOD_TOKEN = "token";
56
- var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
57
- function getAuthPaths(sealosDir = (0, import_node_path.join)((0, import_node_os.homedir)(), ".sealos")) {
58
- return {
59
- sealosDir,
60
- authPath: (0, import_node_path.join)(sealosDir, "auth.json"),
61
- kubeconfigPath: (0, import_node_path.join)(sealosDir, "kubeconfig")
62
- };
63
- }
64
- __name(getAuthPaths, "getAuthPaths");
65
- function normalizeRegion(region) {
66
- return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
67
- }
68
- __name(normalizeRegion, "normalizeRegion");
69
- function createDefaultAuthDependencies() {
70
- return {
71
- fetch,
72
- sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
73
- openBrowser,
74
- now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
75
- paths: getAuthPaths(),
76
- stderr: process.stderr
77
- };
78
- }
79
- __name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
80
- function withDeps(deps = {}) {
81
- return {
82
- ...createDefaultAuthDependencies(),
83
- ...deps
84
- };
85
- }
86
- __name(withDeps, "withDeps");
87
- function ensureSealosDir(paths) {
88
- (0, import_node_fs.mkdirSync)(paths.sealosDir, { recursive: true });
89
- }
90
- __name(ensureSealosDir, "ensureSealosDir");
91
- function saveAuth(auth, deps = {}) {
92
- const { paths } = withDeps(deps);
93
- ensureSealosDir(paths);
94
- (0, import_node_fs.writeFileSync)(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
95
- }
96
- __name(saveAuth, "saveAuth");
97
- function loadAuth(deps = {}) {
98
- const { paths } = withDeps(deps);
99
- if (!(0, import_node_fs.existsSync)(paths.authPath)) {
100
- throw new Error("Not authenticated. Please run: sealos-cli login");
101
- }
102
- return JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8"));
103
- }
104
- __name(loadAuth, "loadAuth");
105
- function getKubeconfigContent(deps = {}) {
106
- const { paths } = withDeps(deps);
107
- try {
108
- return (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
109
- } catch {
110
- return null;
52
+
53
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
54
+ var ANSI_BACKGROUND_OFFSET = 10;
55
+ var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
56
+ var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
57
+ var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
58
+ var styles = {
59
+ modifier: {
60
+ reset: [0, 0],
61
+ // 21 isn't widely supported and 22 does the same thing
62
+ bold: [1, 22],
63
+ dim: [2, 22],
64
+ italic: [3, 23],
65
+ underline: [4, 24],
66
+ overline: [53, 55],
67
+ inverse: [7, 27],
68
+ hidden: [8, 28],
69
+ strikethrough: [9, 29]
70
+ },
71
+ color: {
72
+ black: [30, 39],
73
+ red: [31, 39],
74
+ green: [32, 39],
75
+ yellow: [33, 39],
76
+ blue: [34, 39],
77
+ magenta: [35, 39],
78
+ cyan: [36, 39],
79
+ white: [37, 39],
80
+ // Bright color
81
+ blackBright: [90, 39],
82
+ gray: [90, 39],
83
+ // Alias of `blackBright`
84
+ grey: [90, 39],
85
+ // Alias of `blackBright`
86
+ redBright: [91, 39],
87
+ greenBright: [92, 39],
88
+ yellowBright: [93, 39],
89
+ blueBright: [94, 39],
90
+ magentaBright: [95, 39],
91
+ cyanBright: [96, 39],
92
+ whiteBright: [97, 39]
93
+ },
94
+ bgColor: {
95
+ bgBlack: [40, 49],
96
+ bgRed: [41, 49],
97
+ bgGreen: [42, 49],
98
+ bgYellow: [43, 49],
99
+ bgBlue: [44, 49],
100
+ bgMagenta: [45, 49],
101
+ bgCyan: [46, 49],
102
+ bgWhite: [47, 49],
103
+ // Bright color
104
+ bgBlackBright: [100, 49],
105
+ bgGray: [100, 49],
106
+ // Alias of `bgBlackBright`
107
+ bgGrey: [100, 49],
108
+ // Alias of `bgBlackBright`
109
+ bgRedBright: [101, 49],
110
+ bgGreenBright: [102, 49],
111
+ bgYellowBright: [103, 49],
112
+ bgBlueBright: [104, 49],
113
+ bgMagentaBright: [105, 49],
114
+ bgCyanBright: [106, 49],
115
+ bgWhiteBright: [107, 49]
111
116
  }
112
- }
113
- __name(getKubeconfigContent, "getKubeconfigContent");
114
- function getAuthHeaders(deps = {}) {
115
- const kubeconfig = getKubeconfigContent(deps);
116
- return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
117
- }
118
- __name(getAuthHeaders, "getAuthHeaders");
119
- function requireAuth(deps = {}) {
120
- const headers = getAuthHeaders(deps);
121
- if (!headers) {
122
- throw new Error('Authentication required. Please run "sealos-cli login" first.');
117
+ };
118
+ var modifierNames = Object.keys(styles.modifier);
119
+ var foregroundColorNames = Object.keys(styles.color);
120
+ var backgroundColorNames = Object.keys(styles.bgColor);
121
+ var colorNames = [...foregroundColorNames, ...backgroundColorNames];
122
+ function assembleStyles() {
123
+ const codes = /* @__PURE__ */ new Map();
124
+ for (const [groupName, group] of Object.entries(styles)) {
125
+ for (const [styleName, style] of Object.entries(group)) {
126
+ styles[styleName] = {
127
+ open: `\x1B[${style[0]}m`,
128
+ close: `\x1B[${style[1]}m`
129
+ };
130
+ group[styleName] = styles[styleName];
131
+ codes.set(style[0], style[1]);
132
+ }
133
+ Object.defineProperty(styles, groupName, {
134
+ value: group,
135
+ enumerable: false
136
+ });
123
137
  }
124
- return headers;
138
+ Object.defineProperty(styles, "codes", {
139
+ value: codes,
140
+ enumerable: false
141
+ });
142
+ styles.color.close = "\x1B[39m";
143
+ styles.bgColor.close = "\x1B[49m";
144
+ styles.color.ansi = wrapAnsi16();
145
+ styles.color.ansi256 = wrapAnsi256();
146
+ styles.color.ansi16m = wrapAnsi16m();
147
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
148
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
149
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
150
+ Object.defineProperties(styles, {
151
+ rgbToAnsi256: {
152
+ value(red2, green2, blue2) {
153
+ if (red2 === green2 && green2 === blue2) {
154
+ if (red2 < 8) {
155
+ return 16;
156
+ }
157
+ if (red2 > 248) {
158
+ return 231;
159
+ }
160
+ return Math.round((red2 - 8) / 247 * 24) + 232;
161
+ }
162
+ return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
163
+ },
164
+ enumerable: false
165
+ },
166
+ hexToRgb: {
167
+ value(hex) {
168
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
169
+ if (!matches) {
170
+ return [0, 0, 0];
171
+ }
172
+ let [colorString] = matches;
173
+ if (colorString.length === 3) {
174
+ colorString = [...colorString].map((character) => character + character).join("");
175
+ }
176
+ const integer = Number.parseInt(colorString, 16);
177
+ return [
178
+ /* eslint-disable no-bitwise */
179
+ integer >> 16 & 255,
180
+ integer >> 8 & 255,
181
+ integer & 255
182
+ /* eslint-enable no-bitwise */
183
+ ];
184
+ },
185
+ enumerable: false
186
+ },
187
+ hexToAnsi256: {
188
+ value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
189
+ enumerable: false
190
+ },
191
+ ansi256ToAnsi: {
192
+ value(code) {
193
+ if (code < 8) {
194
+ return 30 + code;
195
+ }
196
+ if (code < 16) {
197
+ return 90 + (code - 8);
198
+ }
199
+ let red2;
200
+ let green2;
201
+ let blue2;
202
+ if (code >= 232) {
203
+ red2 = ((code - 232) * 10 + 8) / 255;
204
+ green2 = red2;
205
+ blue2 = red2;
206
+ } else {
207
+ code -= 16;
208
+ const remainder = code % 36;
209
+ red2 = Math.floor(code / 36) / 5;
210
+ green2 = Math.floor(remainder / 6) / 5;
211
+ blue2 = remainder % 6 / 5;
212
+ }
213
+ const value = Math.max(red2, green2, blue2) * 2;
214
+ if (value === 0) {
215
+ return 30;
216
+ }
217
+ let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
218
+ if (value === 2) {
219
+ result += 60;
220
+ }
221
+ return result;
222
+ },
223
+ enumerable: false
224
+ },
225
+ rgbToAnsi: {
226
+ value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
227
+ enumerable: false
228
+ },
229
+ hexToAnsi: {
230
+ value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
231
+ enumerable: false
232
+ }
233
+ });
234
+ return styles;
125
235
  }
126
- __name(requireAuth, "requireAuth");
127
- function saveKubeconfig(kubeconfig, deps = {}) {
128
- const { paths } = withDeps(deps);
129
- ensureSealosDir(paths);
130
- (0, import_node_fs.writeFileSync)(paths.kubeconfigPath, kubeconfig, { mode: 384 });
236
+ __name(assembleStyles, "assembleStyles");
237
+ var ansiStyles = assembleStyles();
238
+ var ansi_styles_default = ansiStyles;
239
+
240
+ // node_modules/chalk/source/vendor/supports-color/index.js
241
+ var import_node_process = __toESM(require("process"), 1);
242
+ var import_node_os = __toESM(require("os"), 1);
243
+ var import_node_tty = __toESM(require("tty"), 1);
244
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
245
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
246
+ const position = argv.indexOf(prefix + flag);
247
+ const terminatorPosition = argv.indexOf("--");
248
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
131
249
  }
132
- __name(saveKubeconfig, "saveKubeconfig");
133
- function clearAuth(deps = {}) {
134
- const { paths } = withDeps(deps);
135
- (0, import_node_fs.rmSync)(paths.authPath, { force: true });
136
- (0, import_node_fs.rmSync)(paths.kubeconfigPath, { force: true });
250
+ __name(hasFlag, "hasFlag");
251
+ var { env } = import_node_process.default;
252
+ var flagForceColor;
253
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
254
+ flagForceColor = 0;
255
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
256
+ flagForceColor = 1;
137
257
  }
138
- __name(clearAuth, "clearAuth");
139
- function checkAuth(deps = {}) {
140
- const { paths } = withDeps(deps);
141
- if (!(0, import_node_fs.existsSync)(paths.kubeconfigPath)) {
142
- return { authenticated: false };
143
- }
144
- try {
145
- const kubeconfig = (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
146
- if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
147
- return { authenticated: false };
258
+ function envForceColor() {
259
+ if ("FORCE_COLOR" in env) {
260
+ if (env.FORCE_COLOR === "true") {
261
+ return 1;
148
262
  }
149
- const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
150
- return {
151
- authenticated: true,
152
- kubeconfig_path: paths.kubeconfigPath,
153
- region: auth.region || "unknown",
154
- workspace: auth.current_workspace?.id || "unknown"
155
- };
156
- } catch {
157
- return { authenticated: false };
263
+ if (env.FORCE_COLOR === "false") {
264
+ return 0;
265
+ }
266
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
158
267
  }
159
268
  }
160
- __name(checkAuth, "checkAuth");
161
- function getAuthInfo(deps = {}) {
162
- const { paths } = withDeps(deps);
163
- const status = checkAuth(deps);
164
- if (!status.authenticated) {
165
- return { authenticated: false };
269
+ __name(envForceColor, "envForceColor");
270
+ function translateLevel(level) {
271
+ if (level === 0) {
272
+ return false;
166
273
  }
167
- const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
168
274
  return {
169
- ...status,
170
- auth_method: auth.auth_method || "unknown",
171
- authenticated_at: auth.authenticated_at || "unknown",
172
- current_workspace: auth.current_workspace || null
275
+ level,
276
+ hasBasic: true,
277
+ has256: level >= 2,
278
+ has16m: level >= 3
173
279
  };
174
280
  }
175
- __name(getAuthInfo, "getAuthInfo");
176
- async function parseResponse(res) {
177
- return await res.json();
178
- }
179
- __name(parseResponse, "parseResponse");
180
- async function readErrorBody(res) {
181
- return await res.text().catch(() => "");
182
- }
183
- __name(readErrorBody, "readErrorBody");
184
- async function requestDeviceAuthorization(region, deps = {}) {
185
- const { fetch: fetchImpl } = withDeps(deps);
186
- const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
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
- })
193
- });
194
- if (!res.ok) {
195
- const body = await readErrorBody(res);
196
- throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
281
+ __name(translateLevel, "translateLevel");
282
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
283
+ const noFlagForceColor = envForceColor();
284
+ if (noFlagForceColor !== void 0) {
285
+ flagForceColor = noFlagForceColor;
197
286
  }
198
- return await parseResponse(res);
199
- }
200
- __name(requestDeviceAuthorization, "requestDeviceAuthorization");
201
- async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
202
- const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
203
- const maxWait = Math.min(expiresIn, 600) * 1e3;
204
- const deadline = now().getTime() + maxWait;
205
- let pollInterval = interval * 1e3;
206
- let lastLoggedMinute = -1;
207
- while (now().getTime() < deadline) {
208
- await sleep(pollInterval);
209
- const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
210
- if (remaining !== lastLoggedMinute && remaining > 0) {
211
- lastLoggedMinute = remaining;
212
- stderr.write(` Waiting for authorization... (${remaining} min remaining)
213
- `);
287
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
288
+ if (forceColor === 0) {
289
+ return 0;
290
+ }
291
+ if (sniffFlags) {
292
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
293
+ return 3;
214
294
  }
215
- const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
216
- method: "POST",
217
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
218
- body: new URLSearchParams({
219
- client_id: SEALOS_AUTH_CLIENT_ID,
220
- grant_type: DEVICE_GRANT_TYPE,
221
- device_code: deviceCode
222
- })
223
- });
224
- if (res.ok) {
225
- return await parseResponse(res);
295
+ if (hasFlag("color=256")) {
296
+ return 2;
226
297
  }
227
- const body = await res.json().catch(() => ({}));
228
- switch (body.error) {
229
- case "authorization_pending":
230
- break;
231
- case "slow_down":
232
- pollInterval += 5e3;
233
- break;
234
- case "access_denied":
235
- throw new Error("Authorization denied by user");
236
- case "expired_token":
237
- throw new Error("Device code expired. Please run login again.");
238
- default:
239
- throw new Error(`Token request failed: ${body.error || res.statusText}`);
298
+ }
299
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
300
+ return 1;
301
+ }
302
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
303
+ return 0;
304
+ }
305
+ const min = forceColor || 0;
306
+ if (env.TERM === "dumb") {
307
+ return min;
308
+ }
309
+ if (import_node_process.default.platform === "win32") {
310
+ const osRelease = import_node_os.default.release().split(".");
311
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
312
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
240
313
  }
314
+ return 1;
315
+ }
316
+ if ("CI" in env) {
317
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
318
+ return 3;
319
+ }
320
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
321
+ return 1;
322
+ }
323
+ return min;
324
+ }
325
+ if ("TEAMCITY_VERSION" in env) {
326
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
241
327
  }
242
- throw new Error("Authorization timed out (10 minutes). Please run login again.");
243
- }
244
- __name(pollForToken, "pollForToken");
245
- async function getRegionToken(region, globalToken, deps = {}) {
246
- const { fetch: fetchImpl } = withDeps(deps);
247
- const res = await fetchImpl(`${region}/api/auth/regionToken`, {
248
- method: "POST",
249
- headers: {
250
- Authorization: globalToken,
251
- "Content-Type": "application/json"
328
+ if (env.COLORTERM === "truecolor") {
329
+ return 3;
330
+ }
331
+ if (env.TERM === "xterm-kitty") {
332
+ return 3;
333
+ }
334
+ if (env.TERM === "xterm-ghostty") {
335
+ return 3;
336
+ }
337
+ if (env.TERM === "wezterm") {
338
+ return 3;
339
+ }
340
+ if ("TERM_PROGRAM" in env) {
341
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
342
+ switch (env.TERM_PROGRAM) {
343
+ case "iTerm.app": {
344
+ return version >= 3 ? 3 : 2;
345
+ }
346
+ case "Apple_Terminal": {
347
+ return 2;
348
+ }
252
349
  }
253
- });
254
- if (!res.ok) {
255
- const body = await readErrorBody(res);
256
- throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
257
350
  }
258
- return await parseResponse(res);
259
- }
260
- __name(getRegionToken, "getRegionToken");
261
- function normalizeWorkspaces(data) {
262
- const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
263
- return Array.isArray(namespaces) ? namespaces : [];
264
- }
265
- __name(normalizeWorkspaces, "normalizeWorkspaces");
266
- async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
267
- const { fetch: fetchImpl } = withDeps(deps);
268
- const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
269
- headers: { Authorization: regionalToken }
270
- });
271
- if (!res.ok) {
272
- const body = await readErrorBody(res);
273
- throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
351
+ if (/-256(color)?$/i.test(env.TERM)) {
352
+ return 2;
274
353
  }
275
- return normalizeWorkspaces(await parseResponse(res));
276
- }
277
- __name(listRemoteWorkspaces, "listRemoteWorkspaces");
278
- async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
279
- const { fetch: fetchImpl } = withDeps(deps);
280
- const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
281
- method: "POST",
282
- headers: {
283
- Authorization: regionalToken,
284
- "Content-Type": "application/json"
285
- },
286
- body: JSON.stringify({ ns_uid: nsUid })
287
- });
288
- if (!res.ok) {
289
- const body = await readErrorBody(res);
290
- throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
354
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
355
+ return 1;
291
356
  }
292
- return await parseResponse(res);
357
+ if ("COLORTERM" in env) {
358
+ return 1;
359
+ }
360
+ return min;
293
361
  }
294
- __name(switchRemoteWorkspace, "switchRemoteWorkspace");
295
- async function getKubeconfig(region, regionalToken, deps = {}) {
296
- const { fetch: fetchImpl } = withDeps(deps);
297
- const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
298
- headers: { Authorization: regionalToken }
362
+ __name(_supportsColor, "_supportsColor");
363
+ function createSupportsColor(stream, options = {}) {
364
+ const level = _supportsColor(stream, {
365
+ streamIsTTY: stream && stream.isTTY,
366
+ ...options
299
367
  });
300
- if (!res.ok) {
301
- const body = await readErrorBody(res);
302
- throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
368
+ return translateLevel(level);
369
+ }
370
+ __name(createSupportsColor, "createSupportsColor");
371
+ var supportsColor = {
372
+ stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
373
+ stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
374
+ };
375
+ var supports_color_default = supportsColor;
376
+
377
+ // node_modules/chalk/source/utilities.js
378
+ function stringReplaceAll(string, substring, replacer) {
379
+ let index = string.indexOf(substring);
380
+ if (index === -1) {
381
+ return string;
303
382
  }
304
- return await parseResponse(res);
383
+ const substringLength = substring.length;
384
+ let endIndex = 0;
385
+ let returnValue = "";
386
+ do {
387
+ returnValue += string.slice(endIndex, index) + substring + replacer;
388
+ endIndex = index + substringLength;
389
+ index = string.indexOf(substring, endIndex);
390
+ } while (index !== -1);
391
+ returnValue += string.slice(endIndex);
392
+ return returnValue;
305
393
  }
306
- __name(getKubeconfig, "getKubeconfig");
307
- function openBrowser(url) {
308
- const command = (0, import_node_os.platform)() === "darwin" ? "open" : (0, import_node_os.platform)() === "win32" ? "cmd" : "xdg-open";
309
- const args = (0, import_node_os.platform)() === "win32" ? ["/c", "start", "", url] : [url];
310
- (0, import_node_child_process.execFileSync)(command, args, { stdio: "ignore" });
394
+ __name(stringReplaceAll, "stringReplaceAll");
395
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
396
+ let endIndex = 0;
397
+ let returnValue = "";
398
+ do {
399
+ const gotCR = string[index - 1] === "\r";
400
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
401
+ endIndex = index + 1;
402
+ index = string.indexOf("\n", endIndex);
403
+ } while (index !== -1);
404
+ returnValue += string.slice(endIndex);
405
+ return returnValue;
311
406
  }
312
- __name(openBrowser, "openBrowser");
313
- async function loginWithToken(region, token, deps = {}) {
314
- const { now } = withDeps(deps);
315
- const normalizedRegion = normalizeRegion(region);
316
- saveAuth({
317
- region: normalizedRegion,
318
- regional_token: token,
319
- authenticated_at: now().toISOString(),
320
- auth_method: AUTH_METHOD_TOKEN
321
- }, deps);
322
- return {
323
- region: normalizedRegion,
324
- workspace: "unknown",
325
- limited: true
407
+ __name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
408
+
409
+ // node_modules/chalk/source/index.js
410
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
411
+ var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
412
+ var STYLER = /* @__PURE__ */ Symbol("STYLER");
413
+ var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
414
+ var levelMapping = [
415
+ "ansi",
416
+ "ansi",
417
+ "ansi256",
418
+ "ansi16m"
419
+ ];
420
+ var styles2 = /* @__PURE__ */ Object.create(null);
421
+ var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
422
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
423
+ throw new Error("The `level` option should be an integer from 0 to 3");
424
+ }
425
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
426
+ object.level = options.level === void 0 ? colorLevel : options.level;
427
+ }, "applyOptions");
428
+ var chalkFactory = /* @__PURE__ */ __name((options) => {
429
+ const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
430
+ applyOptions(chalk2, options);
431
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
432
+ return chalk2;
433
+ }, "chalkFactory");
434
+ function createChalk(options) {
435
+ return chalkFactory(options);
436
+ }
437
+ __name(createChalk, "createChalk");
438
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
439
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
440
+ styles2[styleName] = {
441
+ get() {
442
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
443
+ Object.defineProperty(this, styleName, { value: builder });
444
+ return builder;
445
+ }
326
446
  };
327
447
  }
328
- __name(loginWithToken, "loginWithToken");
329
- async function loginWithDeviceFlow(region, deps = {}) {
330
- const fullDeps = withDeps(deps);
331
- const normalizedRegion = normalizeRegion(region);
332
- const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
333
- const {
334
- device_code: deviceCode,
335
- user_code: userCode,
336
- verification_uri: verificationUri,
337
- verification_uri_complete: verificationUriComplete,
338
- expires_in: expiresIn,
339
- interval = 5
340
- } = deviceAuth;
341
- const url = verificationUriComplete || verificationUri;
342
- fullDeps.stderr.write(`
343
- Please open the following URL in your browser to authorize:
344
-
345
- ${url}
346
-
347
- Authorization code: ${userCode}
348
- Expires in: ${Math.floor(expiresIn / 60)} minutes
349
-
350
- Waiting for authorization...
351
- `);
352
- if (url) {
353
- try {
354
- fullDeps.openBrowser(url);
355
- fullDeps.stderr.write("Browser opened automatically.\n");
356
- } catch {
357
- fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
448
+ styles2.visible = {
449
+ get() {
450
+ const builder = createBuilder(this, this[STYLER], true);
451
+ Object.defineProperty(this, "visible", { value: builder });
452
+ return builder;
453
+ }
454
+ };
455
+ var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
456
+ if (model === "rgb") {
457
+ if (level === "ansi16m") {
458
+ return ansi_styles_default[type].ansi16m(...arguments_);
459
+ }
460
+ if (level === "ansi256") {
461
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
462
+ }
463
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
464
+ }
465
+ if (model === "hex") {
466
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
467
+ }
468
+ return ansi_styles_default[type][model](...arguments_);
469
+ }, "getModelAnsi");
470
+ var usedModels = ["rgb", "hex", "ansi256"];
471
+ for (const model of usedModels) {
472
+ styles2[model] = {
473
+ get() {
474
+ const { level } = this;
475
+ return function(...arguments_) {
476
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
477
+ return createBuilder(this, styler, this[IS_EMPTY]);
478
+ };
479
+ }
480
+ };
481
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
482
+ styles2[bgModel] = {
483
+ get() {
484
+ const { level } = this;
485
+ return function(...arguments_) {
486
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
487
+ return createBuilder(this, styler, this[IS_EMPTY]);
488
+ };
489
+ }
490
+ };
491
+ }
492
+ var proto = Object.defineProperties(() => {
493
+ }, {
494
+ ...styles2,
495
+ level: {
496
+ enumerable: true,
497
+ get() {
498
+ return this[GENERATOR].level;
499
+ },
500
+ set(level) {
501
+ this[GENERATOR].level = level;
358
502
  }
359
503
  }
360
- const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
361
- const accessToken = tokenResponse.access_token;
362
- if (!accessToken) {
363
- throw new Error("Token response missing access_token");
504
+ });
505
+ var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
506
+ let openAll;
507
+ let closeAll;
508
+ if (parent === void 0) {
509
+ openAll = open;
510
+ closeAll = close;
511
+ } else {
512
+ openAll = parent.openAll + open;
513
+ closeAll = close + parent.closeAll;
364
514
  }
365
- fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
366
- const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
367
- const regionalToken = regionData.data?.token;
368
- const kubeconfig = regionData.data?.kubeconfig;
369
- if (!regionalToken) {
370
- throw new Error("Region token response missing data.token field");
515
+ return {
516
+ open,
517
+ close,
518
+ openAll,
519
+ closeAll,
520
+ parent
521
+ };
522
+ }, "createStyler");
523
+ var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
524
+ const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
525
+ Object.setPrototypeOf(builder, proto);
526
+ builder[GENERATOR] = self;
527
+ builder[STYLER] = _styler;
528
+ builder[IS_EMPTY] = _isEmpty;
529
+ return builder;
530
+ }, "createBuilder");
531
+ var applyStyle = /* @__PURE__ */ __name((self, string) => {
532
+ if (self.level <= 0 || !string) {
533
+ return self[IS_EMPTY] ? "" : string;
371
534
  }
372
- if (!kubeconfig) {
373
- throw new Error("Region token response missing data.kubeconfig field");
535
+ let styler = self[STYLER];
536
+ if (styler === void 0) {
537
+ return string;
374
538
  }
375
- let currentWorkspace;
376
- try {
377
- const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
378
- currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
379
- } catch {
380
- currentWorkspace = void 0;
539
+ const { openAll, closeAll } = styler;
540
+ if (string.includes("\x1B")) {
541
+ while (styler !== void 0) {
542
+ string = stringReplaceAll(string, styler.close, styler.open);
543
+ styler = styler.parent;
544
+ }
381
545
  }
382
- saveKubeconfig(kubeconfig, fullDeps);
383
- saveAuth({
384
- region: normalizedRegion,
385
- access_token: accessToken,
386
- regional_token: regionalToken,
387
- authenticated_at: fullDeps.now().toISOString(),
388
- auth_method: AUTH_METHOD_DEVICE_GRANT,
389
- ...currentWorkspace ? {
390
- current_workspace: {
391
- uid: currentWorkspace.uid,
392
- id: currentWorkspace.id,
393
- teamName: currentWorkspace.teamName
394
- }
395
- } : {}
396
- }, fullDeps);
397
- fullDeps.stderr.write("Authentication successful!\n");
398
- return {
399
- kubeconfig_path: fullDeps.paths.kubeconfigPath,
400
- region: normalizedRegion,
401
- workspace: currentWorkspace?.id || "default"
402
- };
403
- }
404
- __name(loginWithDeviceFlow, "loginWithDeviceFlow");
405
- async function listWorkspaces(deps = {}) {
406
- const auth = loadAuth(deps);
407
- if (!auth.regional_token) {
408
- throw new Error("No regional_token found. Please run: sealos-cli login");
546
+ const lfIndex = string.indexOf("\n");
547
+ if (lfIndex !== -1) {
548
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
409
549
  }
410
- const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
411
- return {
412
- current: auth.current_workspace?.id || null,
413
- workspaces: workspaces.map((workspace) => ({
414
- uid: workspace.uid,
415
- id: workspace.id,
416
- teamName: workspace.teamName,
417
- role: workspace.role,
418
- nstype: workspace.nstype
419
- }))
420
- };
421
- }
422
- __name(listWorkspaces, "listWorkspaces");
423
- async function switchWorkspace(target, deps = {}) {
424
- if (!target) {
425
- throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
550
+ return openAll + string + closeAll;
551
+ }, "applyStyle");
552
+ Object.defineProperties(createChalk.prototype, styles2);
553
+ var chalk = createChalk();
554
+ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
555
+ var source_default = chalk;
556
+
557
+ // src/lib/errors.ts
558
+ var CliError = class extends Error {
559
+ constructor(message, exitCode = 1) {
560
+ super(message);
561
+ this.exitCode = exitCode;
562
+ this.name = "CliError";
426
563
  }
427
- const fullDeps = withDeps(deps);
428
- const auth = loadAuth(fullDeps);
429
- if (!auth.regional_token) {
430
- throw new Error("No regional_token found. Please run: sealos-cli login");
564
+ exitCode;
565
+ static {
566
+ __name(this, "CliError");
431
567
  }
432
- const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
433
- if (workspaces.length === 0) {
434
- throw new Error("No workspaces found");
568
+ };
569
+ var AuthError = class extends CliError {
570
+ static {
571
+ __name(this, "AuthError");
435
572
  }
436
- const targetLower = target.toLowerCase();
437
- const match = workspaces.find(
438
- (workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
439
- );
440
- if (!match?.uid) {
441
- const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
442
- throw new Error(`No workspace matching "${target}". Available:
443
- ${available}`);
573
+ constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
574
+ super(message, 1);
575
+ this.name = "AuthError";
444
576
  }
445
- fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
446
- `);
447
- const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
448
- const newToken = switchData.data?.token;
449
- if (!newToken) {
450
- throw new Error("Switch response missing data.token");
577
+ };
578
+ var ConfigError = class extends CliError {
579
+ static {
580
+ __name(this, "ConfigError");
451
581
  }
452
- const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
453
- const kubeconfig = kubeconfigData.data?.kubeconfig;
454
- if (!kubeconfig) {
455
- throw new Error("Kubeconfig response missing data.kubeconfig");
582
+ constructor(message) {
583
+ super(message, 1);
584
+ this.name = "ConfigError";
456
585
  }
457
- const nextAuth = {
458
- ...auth,
459
- regional_token: newToken,
460
- current_workspace: {
461
- uid: match.uid,
462
- id: match.id,
463
- teamName: match.teamName
464
- }
465
- };
466
- saveAuth(nextAuth, fullDeps);
467
- saveKubeconfig(kubeconfig, fullDeps);
468
- fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
469
- `);
470
- return {
471
- workspace: {
472
- uid: match.uid,
473
- id: match.id,
474
- teamName: match.teamName
475
- },
476
- kubeconfig_path: fullDeps.paths.kubeconfigPath
477
- };
478
- }
479
- __name(switchWorkspace, "switchWorkspace");
480
-
481
- // node_modules/chalk/source/vendor/ansi-styles/index.js
482
- var ANSI_BACKGROUND_OFFSET = 10;
483
- var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
484
- var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
485
- var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
486
- var styles = {
487
- modifier: {
488
- reset: [0, 0],
489
- // 21 isn't widely supported and 22 does the same thing
490
- bold: [1, 22],
491
- dim: [2, 22],
492
- italic: [3, 23],
493
- underline: [4, 24],
494
- overline: [53, 55],
495
- inverse: [7, 27],
496
- hidden: [8, 28],
497
- strikethrough: [9, 29]
498
- },
499
- color: {
500
- black: [30, 39],
501
- red: [31, 39],
502
- green: [32, 39],
503
- yellow: [33, 39],
504
- blue: [34, 39],
505
- magenta: [35, 39],
506
- cyan: [36, 39],
507
- white: [37, 39],
508
- // Bright color
509
- blackBright: [90, 39],
510
- gray: [90, 39],
511
- // Alias of `blackBright`
512
- grey: [90, 39],
513
- // Alias of `blackBright`
514
- redBright: [91, 39],
515
- greenBright: [92, 39],
516
- yellowBright: [93, 39],
517
- blueBright: [94, 39],
518
- magentaBright: [95, 39],
519
- cyanBright: [96, 39],
520
- whiteBright: [97, 39]
521
- },
522
- bgColor: {
523
- bgBlack: [40, 49],
524
- bgRed: [41, 49],
525
- bgGreen: [42, 49],
526
- bgYellow: [43, 49],
527
- bgBlue: [44, 49],
528
- bgMagenta: [45, 49],
529
- bgCyan: [46, 49],
530
- bgWhite: [47, 49],
531
- // Bright color
532
- bgBlackBright: [100, 49],
533
- bgGray: [100, 49],
534
- // Alias of `bgBlackBright`
535
- bgGrey: [100, 49],
536
- // Alias of `bgBlackBright`
537
- bgRedBright: [101, 49],
538
- bgGreenBright: [102, 49],
539
- bgYellowBright: [103, 49],
540
- bgBlueBright: [104, 49],
541
- bgMagentaBright: [105, 49],
542
- bgCyanBright: [106, 49],
543
- bgWhiteBright: [107, 49]
586
+ };
587
+ var ApiError = class extends CliError {
588
+ constructor(message, statusCode, code, details) {
589
+ super(message, 1);
590
+ this.statusCode = statusCode;
591
+ this.code = code;
592
+ this.details = details;
593
+ this.name = "ApiError";
594
+ }
595
+ statusCode;
596
+ code;
597
+ details;
598
+ static {
599
+ __name(this, "ApiError");
544
600
  }
545
601
  };
546
- var modifierNames = Object.keys(styles.modifier);
547
- var foregroundColorNames = Object.keys(styles.color);
548
- var backgroundColorNames = Object.keys(styles.bgColor);
549
- var colorNames = [...foregroundColorNames, ...backgroundColorNames];
550
- function assembleStyles() {
551
- const codes = /* @__PURE__ */ new Map();
552
- for (const [groupName, group] of Object.entries(styles)) {
553
- for (const [styleName, style] of Object.entries(group)) {
554
- styles[styleName] = {
555
- open: `\x1B[${style[0]}m`,
556
- close: `\x1B[${style[1]}m`
557
- };
558
- group[styleName] = styles[styleName];
559
- codes.set(style[0], style[1]);
560
- }
561
- Object.defineProperty(styles, groupName, {
562
- value: group,
563
- enumerable: false
564
- });
602
+ function mapApiError(status, body) {
603
+ const message = body?.error?.message || `API request failed with status ${status}`;
604
+ if (status === 401) {
605
+ return new AuthError(message);
565
606
  }
566
- Object.defineProperty(styles, "codes", {
567
- value: codes,
568
- enumerable: false
569
- });
570
- styles.color.close = "\x1B[39m";
571
- styles.bgColor.close = "\x1B[49m";
572
- styles.color.ansi = wrapAnsi16();
573
- styles.color.ansi256 = wrapAnsi256();
574
- styles.color.ansi16m = wrapAnsi16m();
575
- styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
576
- styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
577
- styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
578
- Object.defineProperties(styles, {
579
- rgbToAnsi256: {
580
- value(red2, green2, blue2) {
581
- if (red2 === green2 && green2 === blue2) {
582
- if (red2 < 8) {
583
- return 16;
584
- }
585
- if (red2 > 248) {
586
- return 231;
587
- }
588
- return Math.round((red2 - 8) / 247 * 24) + 232;
589
- }
590
- return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
591
- },
592
- enumerable: false
593
- },
594
- hexToRgb: {
595
- value(hex) {
596
- const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
597
- if (!matches) {
598
- return [0, 0, 0];
599
- }
600
- let [colorString] = matches;
601
- if (colorString.length === 3) {
602
- colorString = [...colorString].map((character) => character + character).join("");
603
- }
604
- const integer = Number.parseInt(colorString, 16);
605
- return [
606
- /* eslint-disable no-bitwise */
607
- integer >> 16 & 255,
608
- integer >> 8 & 255,
609
- integer & 255
610
- /* eslint-enable no-bitwise */
611
- ];
612
- },
613
- enumerable: false
614
- },
615
- hexToAnsi256: {
616
- value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
617
- enumerable: false
618
- },
619
- ansi256ToAnsi: {
620
- value(code) {
621
- if (code < 8) {
622
- return 30 + code;
623
- }
624
- if (code < 16) {
625
- return 90 + (code - 8);
626
- }
627
- let red2;
628
- let green2;
629
- let blue2;
630
- if (code >= 232) {
631
- red2 = ((code - 232) * 10 + 8) / 255;
632
- green2 = red2;
633
- blue2 = red2;
634
- } else {
635
- code -= 16;
636
- const remainder = code % 36;
637
- red2 = Math.floor(code / 36) / 5;
638
- green2 = Math.floor(remainder / 6) / 5;
639
- blue2 = remainder % 6 / 5;
640
- }
641
- const value = Math.max(red2, green2, blue2) * 2;
642
- if (value === 0) {
643
- return 30;
644
- }
645
- let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
646
- if (value === 2) {
647
- result += 60;
607
+ return new ApiError(message, status, body?.error?.code, body?.error?.details);
608
+ }
609
+ __name(mapApiError, "mapApiError");
610
+ function handleError(error2) {
611
+ if (error2 instanceof ApiError) {
612
+ console.error(source_default.red("Error:"), error2.message);
613
+ if (error2.details) {
614
+ if (Array.isArray(error2.details)) {
615
+ for (const d of error2.details) {
616
+ console.error(source_default.yellow(` ${d.field}:`), d.message);
648
617
  }
649
- return result;
650
- },
651
- enumerable: false
652
- },
653
- rgbToAnsi: {
654
- value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
655
- enumerable: false
656
- },
657
- hexToAnsi: {
658
- value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
659
- enumerable: false
618
+ } else {
619
+ console.error(source_default.yellow(" Details:"), error2.details);
620
+ }
660
621
  }
661
- });
662
- return styles;
622
+ process.exit(error2.exitCode);
623
+ }
624
+ if (error2 instanceof CliError) {
625
+ console.error(source_default.red("Error:"), error2.message);
626
+ process.exit(error2.exitCode);
627
+ }
628
+ if (error2 instanceof Error) {
629
+ console.error(source_default.red("Error:"), error2.message);
630
+ if (process.env.DEBUG) {
631
+ console.error(error2.stack);
632
+ }
633
+ process.exit(1);
634
+ }
635
+ console.error(source_default.red("Error:"), "An unknown error occurred");
636
+ process.exit(1);
663
637
  }
664
- __name(assembleStyles, "assembleStyles");
665
- var ansiStyles = assembleStyles();
666
- var ansi_styles_default = ansiStyles;
638
+ __name(handleError, "handleError");
667
639
 
668
- // node_modules/chalk/source/vendor/supports-color/index.js
669
- var import_node_process = __toESM(require("process"), 1);
670
- var import_node_os2 = __toESM(require("os"), 1);
671
- var import_node_tty = __toESM(require("tty"), 1);
672
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
673
- const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
674
- const position = argv.indexOf(prefix + flag);
675
- const terminatorPosition = argv.indexOf("--");
676
- return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
640
+ // src/lib/auth.ts
641
+ var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
642
+ var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
643
+ var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
644
+ var AUTH_METHOD_TOKEN = "token";
645
+ var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
646
+ function getAuthPaths(sealosDir = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".sealos")) {
647
+ return {
648
+ sealosDir,
649
+ authPath: (0, import_node_path.join)(sealosDir, "auth.json"),
650
+ kubeconfigPath: (0, import_node_path.join)(sealosDir, "kubeconfig")
651
+ };
677
652
  }
678
- __name(hasFlag, "hasFlag");
679
- var { env } = import_node_process.default;
680
- var flagForceColor;
681
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
682
- flagForceColor = 0;
683
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
684
- flagForceColor = 1;
653
+ __name(getAuthPaths, "getAuthPaths");
654
+ function normalizeRegion(region) {
655
+ return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
656
+ }
657
+ __name(normalizeRegion, "normalizeRegion");
658
+ function createDefaultAuthDependencies() {
659
+ return {
660
+ fetch,
661
+ sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
662
+ openBrowser,
663
+ now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
664
+ paths: getAuthPaths(),
665
+ stderr: process.stderr
666
+ };
667
+ }
668
+ __name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
669
+ function withDeps(deps = {}) {
670
+ return {
671
+ ...createDefaultAuthDependencies(),
672
+ ...deps
673
+ };
674
+ }
675
+ __name(withDeps, "withDeps");
676
+ function ensureSealosDir(paths) {
677
+ (0, import_node_fs.mkdirSync)(paths.sealosDir, { recursive: true });
678
+ }
679
+ __name(ensureSealosDir, "ensureSealosDir");
680
+ function saveAuth(auth, deps = {}) {
681
+ const { paths } = withDeps(deps);
682
+ ensureSealosDir(paths);
683
+ (0, import_node_fs.writeFileSync)(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
684
+ }
685
+ __name(saveAuth, "saveAuth");
686
+ function loadAuth(deps = {}) {
687
+ const { paths } = withDeps(deps);
688
+ if (!(0, import_node_fs.existsSync)(paths.authPath)) {
689
+ throw new Error("Not authenticated. Please run: sealos-cli login");
690
+ }
691
+ return JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8"));
692
+ }
693
+ __name(loadAuth, "loadAuth");
694
+ function getKubeconfigContent(deps = {}) {
695
+ const { paths } = withDeps(deps);
696
+ try {
697
+ return (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
698
+ } catch {
699
+ return null;
700
+ }
701
+ }
702
+ __name(getKubeconfigContent, "getKubeconfigContent");
703
+ function getAuthHeaders(deps = {}) {
704
+ const kubeconfig = getKubeconfigContent(deps);
705
+ return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
706
+ }
707
+ __name(getAuthHeaders, "getAuthHeaders");
708
+ function requireAuth(deps = {}) {
709
+ const headers = getAuthHeaders(deps);
710
+ if (!headers) {
711
+ throw new Error('Authentication required. Please run "sealos-cli login" first.');
712
+ }
713
+ return headers;
714
+ }
715
+ __name(requireAuth, "requireAuth");
716
+ function saveKubeconfig(kubeconfig, deps = {}) {
717
+ const { paths } = withDeps(deps);
718
+ ensureSealosDir(paths);
719
+ (0, import_node_fs.writeFileSync)(paths.kubeconfigPath, kubeconfig, { mode: 384 });
685
720
  }
686
- function envForceColor() {
687
- if ("FORCE_COLOR" in env) {
688
- if (env.FORCE_COLOR === "true") {
689
- return 1;
690
- }
691
- if (env.FORCE_COLOR === "false") {
692
- return 0;
721
+ __name(saveKubeconfig, "saveKubeconfig");
722
+ function clearAuth(deps = {}) {
723
+ const { paths } = withDeps(deps);
724
+ (0, import_node_fs.rmSync)(paths.authPath, { force: true });
725
+ (0, import_node_fs.rmSync)(paths.kubeconfigPath, { force: true });
726
+ }
727
+ __name(clearAuth, "clearAuth");
728
+ function checkAuth(deps = {}) {
729
+ const { paths } = withDeps(deps);
730
+ if (!(0, import_node_fs.existsSync)(paths.kubeconfigPath)) {
731
+ return { authenticated: false };
732
+ }
733
+ try {
734
+ const kubeconfig = (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
735
+ if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
736
+ return { authenticated: false };
693
737
  }
694
- return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
738
+ const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
739
+ return {
740
+ authenticated: true,
741
+ kubeconfig_path: paths.kubeconfigPath,
742
+ region: auth.region || "unknown",
743
+ workspace: auth.current_workspace?.id || "unknown"
744
+ };
745
+ } catch {
746
+ return { authenticated: false };
695
747
  }
696
748
  }
697
- __name(envForceColor, "envForceColor");
698
- function translateLevel(level) {
699
- if (level === 0) {
700
- return false;
749
+ __name(checkAuth, "checkAuth");
750
+ function getAuthInfo(deps = {}) {
751
+ const { paths } = withDeps(deps);
752
+ const status = checkAuth(deps);
753
+ if (!status.authenticated) {
754
+ return { authenticated: false };
701
755
  }
756
+ const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
702
757
  return {
703
- level,
704
- hasBasic: true,
705
- has256: level >= 2,
706
- has16m: level >= 3
758
+ ...status,
759
+ auth_method: auth.auth_method || "unknown",
760
+ authenticated_at: auth.authenticated_at || "unknown",
761
+ current_workspace: auth.current_workspace || null
707
762
  };
708
763
  }
709
- __name(translateLevel, "translateLevel");
710
- function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
711
- const noFlagForceColor = envForceColor();
712
- if (noFlagForceColor !== void 0) {
713
- flagForceColor = noFlagForceColor;
714
- }
715
- const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
716
- if (forceColor === 0) {
717
- return 0;
718
- }
719
- if (sniffFlags) {
720
- if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
721
- return 3;
722
- }
723
- if (hasFlag("color=256")) {
724
- return 2;
725
- }
726
- }
727
- if ("TF_BUILD" in env && "AGENT_NAME" in env) {
728
- return 1;
729
- }
730
- if (haveStream && !streamIsTTY && forceColor === void 0) {
731
- return 0;
732
- }
733
- const min = forceColor || 0;
734
- if (env.TERM === "dumb") {
735
- return min;
736
- }
737
- if (import_node_process.default.platform === "win32") {
738
- const osRelease = import_node_os2.default.release().split(".");
739
- if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
740
- return Number(osRelease[2]) >= 14931 ? 3 : 2;
741
- }
742
- return 1;
743
- }
744
- if ("CI" in env) {
745
- if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
746
- return 3;
747
- }
748
- if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
749
- return 1;
750
- }
751
- return min;
752
- }
753
- if ("TEAMCITY_VERSION" in env) {
754
- return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
755
- }
756
- if (env.COLORTERM === "truecolor") {
757
- return 3;
758
- }
759
- if (env.TERM === "xterm-kitty") {
760
- return 3;
761
- }
762
- if (env.TERM === "xterm-ghostty") {
763
- return 3;
764
- }
765
- if (env.TERM === "wezterm") {
766
- return 3;
767
- }
768
- if ("TERM_PROGRAM" in env) {
769
- const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
770
- switch (env.TERM_PROGRAM) {
771
- case "iTerm.app": {
772
- return version >= 3 ? 3 : 2;
773
- }
774
- case "Apple_Terminal": {
775
- return 2;
776
- }
764
+ __name(getAuthInfo, "getAuthInfo");
765
+ async function parseResponse(res) {
766
+ const body = await res.json();
767
+ if (body && typeof body === "object" && typeof body.code === "number" && ![0, 200].includes(body.code)) {
768
+ const message = body.message || `Sealos API request failed with code ${body.code}`;
769
+ if (body.code === 401) {
770
+ throw new AuthError(`Authentication expired. Please run "sealos-cli login" again. (${message})`);
777
771
  }
772
+ throw new Error(message);
778
773
  }
779
- if (/-256(color)?$/i.test(env.TERM)) {
780
- return 2;
781
- }
782
- if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
783
- return 1;
784
- }
785
- if ("COLORTERM" in env) {
786
- return 1;
787
- }
788
- return min;
774
+ return body;
789
775
  }
790
- __name(_supportsColor, "_supportsColor");
791
- function createSupportsColor(stream, options = {}) {
792
- const level = _supportsColor(stream, {
793
- streamIsTTY: stream && stream.isTTY,
794
- ...options
795
- });
796
- return translateLevel(level);
776
+ __name(parseResponse, "parseResponse");
777
+ async function readErrorBody(res) {
778
+ return await res.text().catch(() => "");
797
779
  }
798
- __name(createSupportsColor, "createSupportsColor");
799
- var supportsColor = {
800
- stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
801
- stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
802
- };
803
- var supports_color_default = supportsColor;
804
-
805
- // node_modules/chalk/source/utilities.js
806
- function stringReplaceAll(string, substring, replacer) {
807
- let index = string.indexOf(substring);
808
- if (index === -1) {
809
- return string;
780
+ __name(readErrorBody, "readErrorBody");
781
+ async function requestDeviceAuthorization(region, deps = {}) {
782
+ const { fetch: fetchImpl } = withDeps(deps);
783
+ const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
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
+ })
790
+ });
791
+ if (!res.ok) {
792
+ const body = await readErrorBody(res);
793
+ throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
810
794
  }
811
- const substringLength = substring.length;
812
- let endIndex = 0;
813
- let returnValue = "";
814
- do {
815
- returnValue += string.slice(endIndex, index) + substring + replacer;
816
- endIndex = index + substringLength;
817
- index = string.indexOf(substring, endIndex);
818
- } while (index !== -1);
819
- returnValue += string.slice(endIndex);
820
- return returnValue;
821
- }
822
- __name(stringReplaceAll, "stringReplaceAll");
823
- function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
824
- let endIndex = 0;
825
- let returnValue = "";
826
- do {
827
- const gotCR = string[index - 1] === "\r";
828
- returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
829
- endIndex = index + 1;
830
- index = string.indexOf("\n", endIndex);
831
- } while (index !== -1);
832
- returnValue += string.slice(endIndex);
833
- return returnValue;
795
+ return await parseResponse(res);
834
796
  }
835
- __name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
836
-
837
- // node_modules/chalk/source/index.js
838
- var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
839
- var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
840
- var STYLER = /* @__PURE__ */ Symbol("STYLER");
841
- var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
842
- var levelMapping = [
843
- "ansi",
844
- "ansi",
845
- "ansi256",
846
- "ansi16m"
847
- ];
848
- var styles2 = /* @__PURE__ */ Object.create(null);
849
- var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
850
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
851
- throw new Error("The `level` option should be an integer from 0 to 3");
852
- }
853
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
854
- object.level = options.level === void 0 ? colorLevel : options.level;
855
- }, "applyOptions");
856
- var chalkFactory = /* @__PURE__ */ __name((options) => {
857
- const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
858
- applyOptions(chalk2, options);
859
- Object.setPrototypeOf(chalk2, createChalk.prototype);
860
- return chalk2;
861
- }, "chalkFactory");
862
- function createChalk(options) {
863
- return chalkFactory(options);
797
+ __name(requestDeviceAuthorization, "requestDeviceAuthorization");
798
+ async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
799
+ const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
800
+ const maxWait = Math.min(expiresIn, 600) * 1e3;
801
+ const deadline = now().getTime() + maxWait;
802
+ let pollInterval = interval * 1e3;
803
+ let lastLoggedMinute = -1;
804
+ while (now().getTime() < deadline) {
805
+ await sleep(pollInterval);
806
+ const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
807
+ if (remaining !== lastLoggedMinute && remaining > 0) {
808
+ lastLoggedMinute = remaining;
809
+ stderr.write(` Waiting for authorization... (${remaining} min remaining)
810
+ `);
811
+ }
812
+ const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
813
+ method: "POST",
814
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
815
+ body: new URLSearchParams({
816
+ client_id: SEALOS_AUTH_CLIENT_ID,
817
+ grant_type: DEVICE_GRANT_TYPE,
818
+ device_code: deviceCode
819
+ })
820
+ });
821
+ if (res.ok) {
822
+ return await parseResponse(res);
823
+ }
824
+ const body = await res.json().catch(() => ({}));
825
+ switch (body.error) {
826
+ case "authorization_pending":
827
+ break;
828
+ case "slow_down":
829
+ pollInterval += 5e3;
830
+ break;
831
+ case "access_denied":
832
+ throw new Error("Authorization denied by user");
833
+ case "expired_token":
834
+ throw new Error("Device code expired. Please run login again.");
835
+ default:
836
+ throw new Error(`Token request failed: ${body.error || res.statusText}`);
837
+ }
838
+ }
839
+ throw new Error("Authorization timed out (10 minutes). Please run login again.");
864
840
  }
865
- __name(createChalk, "createChalk");
866
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
867
- for (const [styleName, style] of Object.entries(ansi_styles_default)) {
868
- styles2[styleName] = {
869
- get() {
870
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
871
- Object.defineProperty(this, styleName, { value: builder });
872
- return builder;
841
+ __name(pollForToken, "pollForToken");
842
+ async function getRegionToken(region, globalToken, deps = {}) {
843
+ const { fetch: fetchImpl } = withDeps(deps);
844
+ const res = await fetchImpl(`${region}/api/auth/regionToken`, {
845
+ method: "POST",
846
+ headers: {
847
+ Authorization: globalToken,
848
+ "Content-Type": "application/json"
873
849
  }
874
- };
850
+ });
851
+ if (!res.ok) {
852
+ const body = await readErrorBody(res);
853
+ throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
854
+ }
855
+ return await parseResponse(res);
875
856
  }
876
- styles2.visible = {
877
- get() {
878
- const builder = createBuilder(this, this[STYLER], true);
879
- Object.defineProperty(this, "visible", { value: builder });
880
- return builder;
857
+ __name(getRegionToken, "getRegionToken");
858
+ function normalizeWorkspaces(data) {
859
+ const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
860
+ return Array.isArray(namespaces) ? namespaces : [];
861
+ }
862
+ __name(normalizeWorkspaces, "normalizeWorkspaces");
863
+ async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
864
+ const { fetch: fetchImpl } = withDeps(deps);
865
+ const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
866
+ headers: { Authorization: regionalToken }
867
+ });
868
+ if (!res.ok) {
869
+ const body = await readErrorBody(res);
870
+ throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
881
871
  }
882
- };
883
- var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
884
- if (model === "rgb") {
885
- if (level === "ansi16m") {
886
- return ansi_styles_default[type].ansi16m(...arguments_);
887
- }
888
- if (level === "ansi256") {
889
- return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
890
- }
891
- return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
872
+ return normalizeWorkspaces(await parseResponse(res));
873
+ }
874
+ __name(listRemoteWorkspaces, "listRemoteWorkspaces");
875
+ async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
876
+ const { fetch: fetchImpl } = withDeps(deps);
877
+ const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
878
+ method: "POST",
879
+ headers: {
880
+ Authorization: regionalToken,
881
+ "Content-Type": "application/json"
882
+ },
883
+ body: JSON.stringify({ ns_uid: nsUid })
884
+ });
885
+ if (!res.ok) {
886
+ const body = await readErrorBody(res);
887
+ throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
892
888
  }
893
- if (model === "hex") {
894
- return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
889
+ return await parseResponse(res);
890
+ }
891
+ __name(switchRemoteWorkspace, "switchRemoteWorkspace");
892
+ async function getKubeconfig(region, regionalToken, deps = {}) {
893
+ const { fetch: fetchImpl } = withDeps(deps);
894
+ const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
895
+ headers: { Authorization: regionalToken }
896
+ });
897
+ if (!res.ok) {
898
+ const body = await readErrorBody(res);
899
+ throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
895
900
  }
896
- return ansi_styles_default[type][model](...arguments_);
897
- }, "getModelAnsi");
898
- var usedModels = ["rgb", "hex", "ansi256"];
899
- for (const model of usedModels) {
900
- styles2[model] = {
901
- get() {
902
- const { level } = this;
903
- return function(...arguments_) {
904
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
905
- return createBuilder(this, styler, this[IS_EMPTY]);
906
- };
907
- }
908
- };
909
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
910
- styles2[bgModel] = {
911
- get() {
912
- const { level } = this;
913
- return function(...arguments_) {
914
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
915
- return createBuilder(this, styler, this[IS_EMPTY]);
916
- };
917
- }
901
+ return await parseResponse(res);
902
+ }
903
+ __name(getKubeconfig, "getKubeconfig");
904
+ function openBrowser(url) {
905
+ const command = (0, import_node_os2.platform)() === "darwin" ? "open" : (0, import_node_os2.platform)() === "win32" ? "cmd" : "xdg-open";
906
+ const args = (0, import_node_os2.platform)() === "win32" ? ["/c", "start", "", url] : [url];
907
+ (0, import_node_child_process.execFileSync)(command, args, { stdio: "ignore" });
908
+ }
909
+ __name(openBrowser, "openBrowser");
910
+ async function loginWithToken(region, token, deps = {}) {
911
+ const { now } = withDeps(deps);
912
+ const normalizedRegion = normalizeRegion(region);
913
+ saveAuth({
914
+ region: normalizedRegion,
915
+ regional_token: token,
916
+ authenticated_at: now().toISOString(),
917
+ auth_method: AUTH_METHOD_TOKEN
918
+ }, deps);
919
+ return {
920
+ region: normalizedRegion,
921
+ workspace: "unknown",
922
+ limited: true
918
923
  };
919
924
  }
920
- var proto = Object.defineProperties(() => {
921
- }, {
922
- ...styles2,
923
- level: {
924
- enumerable: true,
925
- get() {
926
- return this[GENERATOR].level;
927
- },
928
- set(level) {
929
- this[GENERATOR].level = level;
925
+ __name(loginWithToken, "loginWithToken");
926
+ async function loginWithDeviceFlow(region, deps = {}) {
927
+ const fullDeps = withDeps(deps);
928
+ const normalizedRegion = normalizeRegion(region);
929
+ const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
930
+ const {
931
+ device_code: deviceCode,
932
+ user_code: userCode,
933
+ verification_uri: verificationUri,
934
+ verification_uri_complete: verificationUriComplete,
935
+ expires_in: expiresIn,
936
+ interval = 5
937
+ } = deviceAuth;
938
+ const url = verificationUriComplete || verificationUri;
939
+ fullDeps.stderr.write(`
940
+ Please open the following URL in your browser to authorize:
941
+
942
+ ${url}
943
+
944
+ Authorization code: ${userCode}
945
+ Expires in: ${Math.floor(expiresIn / 60)} minutes
946
+
947
+ Waiting for authorization...
948
+ `);
949
+ if (url) {
950
+ try {
951
+ fullDeps.openBrowser(url);
952
+ fullDeps.stderr.write("Browser opened automatically.\n");
953
+ } catch {
954
+ fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
930
955
  }
931
956
  }
932
- });
933
- var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
934
- let openAll;
935
- let closeAll;
936
- if (parent === void 0) {
937
- openAll = open;
938
- closeAll = close;
939
- } else {
940
- openAll = parent.openAll + open;
941
- closeAll = close + parent.closeAll;
957
+ const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
958
+ const accessToken = tokenResponse.access_token;
959
+ if (!accessToken) {
960
+ throw new Error("Token response missing access_token");
961
+ }
962
+ fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
963
+ const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
964
+ const regionalToken = regionData.data?.token;
965
+ const kubeconfig = regionData.data?.kubeconfig;
966
+ if (!regionalToken) {
967
+ throw new Error("Region token response missing data.token field");
968
+ }
969
+ if (!kubeconfig) {
970
+ throw new Error("Region token response missing data.kubeconfig field");
971
+ }
972
+ let currentWorkspace;
973
+ try {
974
+ const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
975
+ currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
976
+ } catch {
977
+ currentWorkspace = void 0;
942
978
  }
979
+ saveKubeconfig(kubeconfig, fullDeps);
980
+ saveAuth({
981
+ region: normalizedRegion,
982
+ access_token: accessToken,
983
+ regional_token: regionalToken,
984
+ authenticated_at: fullDeps.now().toISOString(),
985
+ auth_method: AUTH_METHOD_DEVICE_GRANT,
986
+ ...currentWorkspace ? {
987
+ current_workspace: {
988
+ uid: currentWorkspace.uid,
989
+ id: currentWorkspace.id,
990
+ teamName: currentWorkspace.teamName
991
+ }
992
+ } : {}
993
+ }, fullDeps);
994
+ fullDeps.stderr.write("Authentication successful!\n");
943
995
  return {
944
- open,
945
- close,
946
- openAll,
947
- closeAll,
948
- parent
996
+ kubeconfig_path: fullDeps.paths.kubeconfigPath,
997
+ region: normalizedRegion,
998
+ workspace: currentWorkspace?.id || "default"
949
999
  };
950
- }, "createStyler");
951
- var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
952
- const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
953
- Object.setPrototypeOf(builder, proto);
954
- builder[GENERATOR] = self;
955
- builder[STYLER] = _styler;
956
- builder[IS_EMPTY] = _isEmpty;
957
- return builder;
958
- }, "createBuilder");
959
- var applyStyle = /* @__PURE__ */ __name((self, string) => {
960
- if (self.level <= 0 || !string) {
961
- return self[IS_EMPTY] ? "" : string;
1000
+ }
1001
+ __name(loginWithDeviceFlow, "loginWithDeviceFlow");
1002
+ async function listWorkspaces(deps = {}) {
1003
+ const auth = loadAuth(deps);
1004
+ if (!auth.regional_token) {
1005
+ throw new Error("No regional_token found. Please run: sealos-cli login");
1006
+ }
1007
+ const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
1008
+ return {
1009
+ current: auth.current_workspace?.id || null,
1010
+ workspaces: workspaces.map((workspace) => ({
1011
+ uid: workspace.uid,
1012
+ id: workspace.id,
1013
+ teamName: workspace.teamName,
1014
+ role: workspace.role,
1015
+ nstype: workspace.nstype
1016
+ }))
1017
+ };
1018
+ }
1019
+ __name(listWorkspaces, "listWorkspaces");
1020
+ async function switchWorkspace(target, deps = {}) {
1021
+ if (!target) {
1022
+ throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
962
1023
  }
963
- let styler = self[STYLER];
964
- if (styler === void 0) {
965
- return string;
1024
+ const fullDeps = withDeps(deps);
1025
+ const auth = loadAuth(fullDeps);
1026
+ if (!auth.regional_token) {
1027
+ throw new Error("No regional_token found. Please run: sealos-cli login");
966
1028
  }
967
- const { openAll, closeAll } = styler;
968
- if (string.includes("\x1B")) {
969
- while (styler !== void 0) {
970
- string = stringReplaceAll(string, styler.close, styler.open);
971
- styler = styler.parent;
972
- }
1029
+ const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
1030
+ if (workspaces.length === 0) {
1031
+ throw new Error("No workspaces found");
973
1032
  }
974
- const lfIndex = string.indexOf("\n");
975
- if (lfIndex !== -1) {
976
- string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
1033
+ const targetLower = target.toLowerCase();
1034
+ const match = workspaces.find(
1035
+ (workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
1036
+ );
1037
+ if (!match?.uid) {
1038
+ const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
1039
+ throw new Error(`No workspace matching "${target}". Available:
1040
+ ${available}`);
977
1041
  }
978
- return openAll + string + closeAll;
979
- }, "applyStyle");
980
- Object.defineProperties(createChalk.prototype, styles2);
981
- var chalk = createChalk();
982
- var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
983
- var source_default = chalk;
1042
+ fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
1043
+ `);
1044
+ const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
1045
+ const newToken = switchData.data?.token;
1046
+ if (!newToken) {
1047
+ throw new Error("Switch response missing data.token");
1048
+ }
1049
+ const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
1050
+ const kubeconfig = kubeconfigData.data?.kubeconfig;
1051
+ if (!kubeconfig) {
1052
+ throw new Error("Kubeconfig response missing data.kubeconfig");
1053
+ }
1054
+ const nextAuth = {
1055
+ ...auth,
1056
+ regional_token: newToken,
1057
+ current_workspace: {
1058
+ uid: match.uid,
1059
+ id: match.id,
1060
+ teamName: match.teamName
1061
+ }
1062
+ };
1063
+ saveAuth(nextAuth, fullDeps);
1064
+ saveKubeconfig(kubeconfig, fullDeps);
1065
+ fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
1066
+ `);
1067
+ return {
1068
+ workspace: {
1069
+ uid: match.uid,
1070
+ id: match.id,
1071
+ teamName: match.teamName
1072
+ },
1073
+ kubeconfig_path: fullDeps.paths.kubeconfigPath
1074
+ };
1075
+ }
1076
+ __name(switchWorkspace, "switchWorkspace");
984
1077
 
985
1078
  // src/lib/output.ts
986
1079
  var import_table = require("table");
@@ -3938,92 +4031,9 @@ function spinner(text) {
3938
4031
  }
3939
4032
  __name(spinner, "spinner");
3940
4033
 
3941
- // src/lib/errors.ts
3942
- var CliError = class extends Error {
3943
- constructor(message, exitCode = 1) {
3944
- super(message);
3945
- this.exitCode = exitCode;
3946
- this.name = "CliError";
3947
- }
3948
- exitCode;
3949
- static {
3950
- __name(this, "CliError");
3951
- }
3952
- };
3953
- var AuthError = class extends CliError {
3954
- static {
3955
- __name(this, "AuthError");
3956
- }
3957
- constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
3958
- super(message, 1);
3959
- this.name = "AuthError";
3960
- }
3961
- };
3962
- var ConfigError = class extends CliError {
3963
- static {
3964
- __name(this, "ConfigError");
3965
- }
3966
- constructor(message) {
3967
- super(message, 1);
3968
- this.name = "ConfigError";
3969
- }
3970
- };
3971
- var ApiError = class extends CliError {
3972
- constructor(message, statusCode, code, details) {
3973
- super(message, 1);
3974
- this.statusCode = statusCode;
3975
- this.code = code;
3976
- this.details = details;
3977
- this.name = "ApiError";
3978
- }
3979
- statusCode;
3980
- code;
3981
- details;
3982
- static {
3983
- __name(this, "ApiError");
3984
- }
3985
- };
3986
- function mapApiError(status, body) {
3987
- const message = body?.error?.message || `API request failed with status ${status}`;
3988
- if (status === 401) {
3989
- return new AuthError(message);
3990
- }
3991
- return new ApiError(message, status, body?.error?.code, body?.error?.details);
3992
- }
3993
- __name(mapApiError, "mapApiError");
3994
- function handleError(error2) {
3995
- if (error2 instanceof ApiError) {
3996
- console.error(source_default.red("Error:"), error2.message);
3997
- if (error2.details) {
3998
- if (Array.isArray(error2.details)) {
3999
- for (const d of error2.details) {
4000
- console.error(source_default.yellow(` ${d.field}:`), d.message);
4001
- }
4002
- } else {
4003
- console.error(source_default.yellow(" Details:"), error2.details);
4004
- }
4005
- }
4006
- process.exit(error2.exitCode);
4007
- }
4008
- if (error2 instanceof CliError) {
4009
- console.error(source_default.red("Error:"), error2.message);
4010
- process.exit(error2.exitCode);
4011
- }
4012
- if (error2 instanceof Error) {
4013
- console.error(source_default.red("Error:"), error2.message);
4014
- if (process.env.DEBUG) {
4015
- console.error(error2.stack);
4016
- }
4017
- process.exit(1);
4018
- }
4019
- console.error(source_default.red("Error:"), "An unknown error occurred");
4020
- process.exit(1);
4021
- }
4022
- __name(handleError, "handleError");
4023
-
4024
4034
  // src/commands/auth/login.ts
4025
4035
  function createLoginCommand() {
4026
- return new import_commander.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) => {
4036
+ return new import_commander.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) => {
4027
4037
  try {
4028
4038
  const result = options.token ? await loginWithToken(region, options.token) : await loginWithDeviceFlow(region);
4029
4039
  if (options.token) {
@@ -4048,14 +4058,32 @@ __name(createLoginCommand, "createLoginCommand");
4048
4058
  // src/commands/auth/logout.ts
4049
4059
  var import_commander2 = require("commander");
4050
4060
  function createLogoutCommand() {
4051
- return new import_commander2.Command("logout").description("Logout from Sealos Cloud").action(async () => {
4061
+ return new import_commander2.Command("logout").description("Logout from Sealos Cloud").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4052
4062
  try {
4053
4063
  const status = checkAuth();
4054
4064
  if (!status.authenticated) {
4065
+ if (options.output === "json") {
4066
+ outputJson({
4067
+ success: true,
4068
+ action: "logout",
4069
+ authenticated: false,
4070
+ changed: false
4071
+ });
4072
+ return;
4073
+ }
4055
4074
  warn("You are not logged in");
4056
4075
  return;
4057
4076
  }
4058
4077
  clearAuth();
4078
+ if (options.output === "json") {
4079
+ outputJson({
4080
+ success: true,
4081
+ action: "logout",
4082
+ authenticated: false,
4083
+ changed: true
4084
+ });
4085
+ return;
4086
+ }
4059
4087
  success2("Logged out from Sealos Cloud");
4060
4088
  } catch (error2) {
4061
4089
  handleError(error2);
@@ -4067,7 +4095,7 @@ __name(createLogoutCommand, "createLogoutCommand");
4067
4095
  // src/commands/auth/whoami.ts
4068
4096
  var import_commander3 = require("commander");
4069
4097
  function createWhoamiCommand() {
4070
- return new import_commander3.Command("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4098
+ return new import_commander3.Command("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4071
4099
  try {
4072
4100
  const authInfo = getAuthInfo();
4073
4101
  if (!authInfo.authenticated) {
@@ -4147,7 +4175,7 @@ function createAuthCommand() {
4147
4175
  handleError(error2);
4148
4176
  }
4149
4177
  });
4150
- authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4178
+ authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4151
4179
  try {
4152
4180
  const result = await listWorkspaces();
4153
4181
  if (options.output === "json") {
@@ -4169,7 +4197,7 @@ function createAuthCommand() {
4169
4197
  handleError(error2);
4170
4198
  }
4171
4199
  });
4172
- 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) => {
4200
+ 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) => {
4173
4201
  try {
4174
4202
  const result = await switchWorkspace(namespace);
4175
4203
  if (options.output === "json") {
@@ -4189,7 +4217,7 @@ __name(createAuthCommand, "createAuthCommand");
4189
4217
  var import_commander5 = require("commander");
4190
4218
  function createWorkspaceCommand() {
4191
4219
  const workspaceCmd = new import_commander5.Command("workspace").alias("ws").description("Manage workspaces");
4192
- 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) => {
4220
+ 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) => {
4193
4221
  try {
4194
4222
  const result = await switchWorkspace(namespace);
4195
4223
  if (options.output === "json") {
@@ -4201,7 +4229,7 @@ function createWorkspaceCommand() {
4201
4229
  handleError(error2);
4202
4230
  }
4203
4231
  });
4204
- workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4232
+ workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4205
4233
  try {
4206
4234
  const result = await listWorkspaces();
4207
4235
  if (options.output === "json") {
@@ -4223,7 +4251,7 @@ function createWorkspaceCommand() {
4223
4251
  handleError(error2);
4224
4252
  }
4225
4253
  });
4226
- workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "table").action(async (options) => {
4254
+ workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
4227
4255
  try {
4228
4256
  const authInfo = getAuthInfo();
4229
4257
  if (!authInfo.authenticated) {
@@ -5175,7 +5203,7 @@ function printTemplates(templates) {
5175
5203
  __name(printTemplates, "printTemplates");
5176
5204
  function createDevboxCommand() {
5177
5205
  const devboxCmd = new import_commander6.Command("devbox").alias("dev").description("Manage devbox instances");
5178
- devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
5206
+ devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
5179
5207
  const client = createDevboxClient();
5180
5208
  const { data, error: error2, response } = await client.GET("/devbox", {
5181
5209
  headers: ctx.auth
@@ -5188,7 +5216,7 @@ function createDevboxCommand() {
5188
5216
  }
5189
5217
  printDevboxList(data);
5190
5218
  }));
5191
- 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) => {
5219
+ 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) => {
5192
5220
  const client = createDevboxClient();
5193
5221
  const { data, error: error2, response } = await client.POST("/devbox", {
5194
5222
  headers: ctx.auth,
@@ -5203,7 +5231,7 @@ function createDevboxCommand() {
5203
5231
  ctx.spinner.succeed(`Devbox "${data.name}" created`);
5204
5232
  printCreateResult(data);
5205
5233
  }));
5206
- 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) => {
5234
+ 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) => {
5207
5235
  const client = createDevboxClient();
5208
5236
  const { data, error: error2, response } = await client.GET("/devbox/{name}", {
5209
5237
  headers: ctx.auth,
@@ -5219,7 +5247,7 @@ function createDevboxCommand() {
5219
5247
  }
5220
5248
  printDevboxDetail(data);
5221
5249
  }));
5222
- 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) => {
5250
+ 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) => {
5223
5251
  const client = createDevboxClient();
5224
5252
  const { error: error2, response } = await client.PATCH("/devbox/{name}", {
5225
5253
  headers: ctx.auth,
@@ -5229,9 +5257,20 @@ function createDevboxCommand() {
5229
5257
  body: buildUpdateDevboxBody(options)
5230
5258
  });
5231
5259
  if (error2) throw mapApiError(response.status, error2);
5260
+ if (options.output === "json") {
5261
+ ctx.spinner.stop();
5262
+ outputJson({
5263
+ success: true,
5264
+ action: "update",
5265
+ resource: "devbox",
5266
+ name,
5267
+ status: "requested"
5268
+ });
5269
+ return;
5270
+ }
5232
5271
  ctx.spinner.succeed(`Devbox "${name}" update requested`);
5233
5272
  }));
5234
- devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name) => {
5273
+ 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) => {
5235
5274
  const client = createDevboxClient();
5236
5275
  const { error: error2, response } = await client.DELETE("/devbox/{name}", {
5237
5276
  headers: ctx.auth,
@@ -5240,6 +5279,17 @@ function createDevboxCommand() {
5240
5279
  }
5241
5280
  });
5242
5281
  if (error2) throw mapApiError(response.status, error2);
5282
+ if (options.output === "json") {
5283
+ ctx.spinner.stop();
5284
+ outputJson({
5285
+ success: true,
5286
+ action: "delete",
5287
+ resource: "devbox",
5288
+ name,
5289
+ status: "deleted"
5290
+ });
5291
+ return;
5292
+ }
5243
5293
  ctx.spinner.succeed(`Devbox "${name}" deleted`);
5244
5294
  }));
5245
5295
  const lifecycleActions = [
@@ -5251,7 +5301,7 @@ function createDevboxCommand() {
5251
5301
  for (const action of lifecycleActions) {
5252
5302
  const command = devboxCmd.command(`${action.name} <name>`).description(`${action.name.charAt(0).toUpperCase()}${action.name.slice(1)} a devbox`);
5253
5303
  if (action.alias) command.alias(action.alias);
5254
- command.action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name) => {
5304
+ command.option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name, options) => {
5255
5305
  const client = createDevboxClient();
5256
5306
  const { error: error2, response } = await client.POST(action.endpoint, {
5257
5307
  headers: ctx.auth,
@@ -5261,10 +5311,21 @@ function createDevboxCommand() {
5261
5311
  body: {}
5262
5312
  });
5263
5313
  if (error2) throw mapApiError(response.status, error2);
5314
+ if (options.output === "json") {
5315
+ ctx.spinner.stop();
5316
+ outputJson({
5317
+ success: true,
5318
+ action: action.name,
5319
+ resource: "devbox",
5320
+ name,
5321
+ status: "requested"
5322
+ });
5323
+ return;
5324
+ }
5264
5325
  ctx.spinner.succeed(`Devbox "${name}" ${action.done}`);
5265
5326
  }));
5266
5327
  }
5267
- 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) => {
5328
+ 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) => {
5268
5329
  const client = createDevboxClient();
5269
5330
  const body = options.execCommand ? { execCommand: options.execCommand } : {};
5270
5331
  const { error: error2, response } = await client.POST("/devbox/{name}/autostart", {
@@ -5275,9 +5336,21 @@ function createDevboxCommand() {
5275
5336
  body
5276
5337
  });
5277
5338
  if (error2) throw mapApiError(response.status, error2);
5339
+ if (options.output === "json") {
5340
+ ctx.spinner.stop();
5341
+ outputJson({
5342
+ success: true,
5343
+ action: "autostart",
5344
+ resource: "devbox",
5345
+ name,
5346
+ execCommand: options.execCommand ?? null,
5347
+ status: "configured"
5348
+ });
5349
+ return;
5350
+ }
5278
5351
  ctx.spinner.succeed(`Autostart configured for "${name}"`);
5279
5352
  }));
5280
- 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) => {
5353
+ 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) => {
5281
5354
  const client = createDevboxClient();
5282
5355
  const { data, error: error2, response } = await client.GET("/devbox/{name}/monitor", {
5283
5356
  headers: ctx.auth,
@@ -5298,7 +5371,7 @@ function createDevboxCommand() {
5298
5371
  }
5299
5372
  printMonitor(data);
5300
5373
  }));
5301
- 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) => {
5374
+ 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) => {
5302
5375
  const client = createDevboxClient();
5303
5376
  const { data, error: error2, response } = await client.GET("/devbox/templates", {
5304
5377
  headers: ctx.auth
@@ -5312,7 +5385,7 @@ function createDevboxCommand() {
5312
5385
  printTemplates(data);
5313
5386
  }));
5314
5387
  const releasesCommand = devboxCmd.command("releases").description("Manage devbox releases");
5315
- 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) => {
5388
+ 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) => {
5316
5389
  const client = createDevboxClient();
5317
5390
  const { data, error: error2, response } = await client.GET("/devbox/{name}/releases", {
5318
5391
  headers: ctx.auth,
@@ -5328,7 +5401,7 @@ function createDevboxCommand() {
5328
5401
  }
5329
5402
  printReleases(data);
5330
5403
  }));
5331
- 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) => {
5404
+ 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) => {
5332
5405
  const client = createDevboxClient();
5333
5406
  const { data, error: error2, response } = await client.POST("/devbox/{name}/releases", {
5334
5407
  headers: ctx.auth,
@@ -5338,9 +5411,14 @@ function createDevboxCommand() {
5338
5411
  body: buildReleaseBody(options)
5339
5412
  });
5340
5413
  if (error2) throw mapApiError(response.status, error2);
5414
+ if (options.output === "json") {
5415
+ ctx.spinner.stop();
5416
+ outputJson(data);
5417
+ return;
5418
+ }
5341
5419
  ctx.spinner.succeed(`Release "${options.tag}" accepted for "${data.name}" (${data.status})`);
5342
5420
  }));
5343
- releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag) => {
5421
+ 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) => {
5344
5422
  const client = createDevboxClient();
5345
5423
  const { error: error2, response } = await client.DELETE("/devbox/{name}/releases/{tag}", {
5346
5424
  headers: ctx.auth,
@@ -5349,9 +5427,21 @@ function createDevboxCommand() {
5349
5427
  }
5350
5428
  });
5351
5429
  if (error2) throw mapApiError(response.status, error2);
5430
+ if (options.output === "json") {
5431
+ ctx.spinner.stop();
5432
+ outputJson({
5433
+ success: true,
5434
+ action: "delete",
5435
+ resource: "devbox-release",
5436
+ name,
5437
+ tag,
5438
+ status: "deleted"
5439
+ });
5440
+ return;
5441
+ }
5352
5442
  ctx.spinner.succeed(`Release "${tag}" deleted for "${name}"`);
5353
5443
  }));
5354
- releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag) => {
5444
+ 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) => {
5355
5445
  const client = createDevboxClient();
5356
5446
  const { error: error2, response } = await client.POST("/devbox/{name}/releases/{tag}/deploy", {
5357
5447
  headers: ctx.auth,
@@ -5360,9 +5450,21 @@ function createDevboxCommand() {
5360
5450
  }
5361
5451
  });
5362
5452
  if (error2) throw mapApiError(response.status, error2);
5453
+ if (options.output === "json") {
5454
+ ctx.spinner.stop();
5455
+ outputJson({
5456
+ success: true,
5457
+ action: "deploy",
5458
+ resource: "devbox-release",
5459
+ name,
5460
+ tag,
5461
+ status: "deployed"
5462
+ });
5463
+ return;
5464
+ }
5363
5465
  ctx.spinner.succeed(`Release "${tag}" deployed for "${name}"`);
5364
5466
  }));
5365
- 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) => {
5467
+ 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) => {
5366
5468
  const client = createDevboxClient();
5367
5469
  const { data, error: error2, response } = await client.GET("/devbox/{name}/deployments", {
5368
5470
  headers: ctx.auth,
@@ -5610,7 +5712,7 @@ function printConnectionDetail(connection) {
5610
5712
  __name(printConnectionDetail, "printConnectionDetail");
5611
5713
  function createDatabaseCommand() {
5612
5714
  const dbCmd = new import_commander7.Command("database").alias("db").description("Manage databases");
5613
- dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "table").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
5715
+ dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
5614
5716
  const client = createDatabaseClient();
5615
5717
  const { data, error: error2, response } = await client.GET("/databases", {
5616
5718
  headers: ctx.auth
@@ -5649,7 +5751,7 @@ function createDatabaseCommand() {
5649
5751
  }
5650
5752
  outputTable(rows);
5651
5753
  }));
5652
- 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) => {
5754
+ 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) => {
5653
5755
  const client = createDatabaseClient({ baseUrl: options.host });
5654
5756
  const { data, error: error2, response } = await client.GET("/databases/versions");
5655
5757
  if (error2) throw mapApiError(response.status, error2);
@@ -5685,7 +5787,7 @@ function createDatabaseCommand() {
5685
5787
  }
5686
5788
  outputTable(rows);
5687
5789
  }));
5688
- 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({
5790
+ 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({
5689
5791
  spinnerText: "Creating database..."
5690
5792
  }, async (ctx, type, options) => {
5691
5793
  const client = createDatabaseClient();
@@ -5720,7 +5822,7 @@ function createDatabaseCommand() {
5720
5822
  console.log(source_default.dim(` Provisioning status: ${data.status}`));
5721
5823
  console.log(source_default.dim(` Next: sealos-cli database get ${data.name}`));
5722
5824
  }));
5723
- 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) => {
5825
+ 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) => {
5724
5826
  const client = createDatabaseClient();
5725
5827
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
5726
5828
  headers: ctx.auth,
@@ -5736,7 +5838,7 @@ function createDatabaseCommand() {
5736
5838
  }
5737
5839
  printDatabaseDetail(data);
5738
5840
  }));
5739
- 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) => {
5841
+ 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) => {
5740
5842
  const client = createDatabaseClient();
5741
5843
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
5742
5844
  headers: ctx.auth,
@@ -5752,7 +5854,7 @@ function createDatabaseCommand() {
5752
5854
  }
5753
5855
  printConnectionDetail(data.connection);
5754
5856
  }));
5755
- 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({
5857
+ 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({
5756
5858
  spinnerText: "Updating database..."
5757
5859
  }, async (ctx, name, options) => {
5758
5860
  const quota = buildQuota(options);
@@ -5768,9 +5870,20 @@ function createDatabaseCommand() {
5768
5870
  body: { quota }
5769
5871
  });
5770
5872
  if (error2) throw mapApiError(response.status, error2);
5873
+ if (options.output === "json") {
5874
+ ctx.spinner.stop();
5875
+ outputJson({
5876
+ success: true,
5877
+ action: "update",
5878
+ resource: "database",
5879
+ name,
5880
+ status: "requested"
5881
+ });
5882
+ return;
5883
+ }
5771
5884
  ctx.spinner.succeed(`Database "${name}" update requested`);
5772
5885
  }));
5773
- dbCmd.command("start <name>").description("Start a database").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name) => {
5886
+ 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) => {
5774
5887
  const client = createDatabaseClient();
5775
5888
  const { error: error2, response } = await client.POST("/databases/{databaseName}/start", {
5776
5889
  headers: ctx.auth,
@@ -5779,9 +5892,20 @@ function createDatabaseCommand() {
5779
5892
  }
5780
5893
  });
5781
5894
  if (error2) throw mapApiError(response.status, error2);
5895
+ if (options.output === "json") {
5896
+ ctx.spinner.stop();
5897
+ outputJson({
5898
+ success: true,
5899
+ action: "start",
5900
+ resource: "database",
5901
+ name,
5902
+ status: "requested"
5903
+ });
5904
+ return;
5905
+ }
5782
5906
  ctx.spinner.succeed(`Database "${name}" start requested`);
5783
5907
  }));
5784
- dbCmd.command("pause <name>").alias("stop").description("Pause a database").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name) => {
5908
+ 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) => {
5785
5909
  const client = createDatabaseClient();
5786
5910
  const { error: error2, response } = await client.POST("/databases/{databaseName}/pause", {
5787
5911
  headers: ctx.auth,
@@ -5790,9 +5914,20 @@ function createDatabaseCommand() {
5790
5914
  }
5791
5915
  });
5792
5916
  if (error2) throw mapApiError(response.status, error2);
5917
+ if (options.output === "json") {
5918
+ ctx.spinner.stop();
5919
+ outputJson({
5920
+ success: true,
5921
+ action: "pause",
5922
+ resource: "database",
5923
+ name,
5924
+ status: "requested"
5925
+ });
5926
+ return;
5927
+ }
5793
5928
  ctx.spinner.succeed(`Database "${name}" pause requested`);
5794
5929
  }));
5795
- dbCmd.command("restart <name>").description("Restart a database").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name) => {
5930
+ 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) => {
5796
5931
  const client = createDatabaseClient();
5797
5932
  const { error: error2, response } = await client.POST("/databases/{databaseName}/restart", {
5798
5933
  headers: ctx.auth,
@@ -5801,9 +5936,20 @@ function createDatabaseCommand() {
5801
5936
  }
5802
5937
  });
5803
5938
  if (error2) throw mapApiError(response.status, error2);
5939
+ if (options.output === "json") {
5940
+ ctx.spinner.stop();
5941
+ outputJson({
5942
+ success: true,
5943
+ action: "restart",
5944
+ resource: "database",
5945
+ name,
5946
+ status: "requested"
5947
+ });
5948
+ return;
5949
+ }
5804
5950
  ctx.spinner.succeed(`Database "${name}" restart requested`);
5805
5951
  }));
5806
- dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name) => {
5952
+ 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) => {
5807
5953
  const client = createDatabaseClient();
5808
5954
  const { error: error2, response } = await client.DELETE("/databases/{databaseName}", {
5809
5955
  headers: ctx.auth,
@@ -5812,9 +5958,20 @@ function createDatabaseCommand() {
5812
5958
  }
5813
5959
  });
5814
5960
  if (error2) throw mapApiError(response.status, error2);
5961
+ if (options.output === "json") {
5962
+ ctx.spinner.stop();
5963
+ outputJson({
5964
+ success: true,
5965
+ action: "delete",
5966
+ resource: "database",
5967
+ name,
5968
+ status: "requested"
5969
+ });
5970
+ return;
5971
+ }
5815
5972
  ctx.spinner.succeed(`Database "${name}" delete requested`);
5816
5973
  }));
5817
- 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) => {
5974
+ 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) => {
5818
5975
  const client = createDatabaseClient();
5819
5976
  const { data, error: error2, response } = await client.GET("/databases/{databaseName}/backups", {
5820
5977
  headers: ctx.auth,
@@ -5848,7 +6005,7 @@ function createDatabaseCommand() {
5848
6005
  }
5849
6006
  outputTable(rows);
5850
6007
  }));
5851
- dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").action(withAuth({
6008
+ 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({
5852
6009
  spinnerText: "Creating backup..."
5853
6010
  }, async (ctx, name, options) => {
5854
6011
  const client = createDatabaseClient();
@@ -5863,11 +6020,23 @@ function createDatabaseCommand() {
5863
6020
  body
5864
6021
  });
5865
6022
  if (error2) throw mapApiError(response.status, error2);
6023
+ if (options.output === "json") {
6024
+ ctx.spinner.stop();
6025
+ outputJson({
6026
+ success: true,
6027
+ action: "backup",
6028
+ resource: "database",
6029
+ name,
6030
+ backupName: options.name ?? null,
6031
+ status: "requested"
6032
+ });
6033
+ return;
6034
+ }
5866
6035
  ctx.spinner.succeed(`Backup requested for database "${name}"`);
5867
6036
  }));
5868
- dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").action(withAuth({
6037
+ dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
5869
6038
  spinnerText: "Deleting backup..."
5870
- }, async (ctx, databaseName, backupName) => {
6039
+ }, async (ctx, databaseName, backupName, options) => {
5871
6040
  const client = createDatabaseClient();
5872
6041
  const { error: error2, response } = await client.DELETE("/databases/{databaseName}/backups/{backupName}", {
5873
6042
  headers: ctx.auth,
@@ -5876,9 +6045,21 @@ function createDatabaseCommand() {
5876
6045
  }
5877
6046
  });
5878
6047
  if (error2) throw mapApiError(response.status, error2);
6048
+ if (options.output === "json") {
6049
+ ctx.spinner.stop();
6050
+ outputJson({
6051
+ success: true,
6052
+ action: "backup-delete",
6053
+ resource: "database-backup",
6054
+ databaseName,
6055
+ backupName,
6056
+ status: "deleted"
6057
+ });
6058
+ return;
6059
+ }
5879
6060
  ctx.spinner.succeed(`Backup "${backupName}" deleted`);
5880
6061
  }));
5881
- 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({
6062
+ 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({
5882
6063
  spinnerText: "Restoring database..."
5883
6064
  }, async (ctx, databaseName, options) => {
5884
6065
  const client = createDatabaseClient();
@@ -5893,9 +6074,22 @@ function createDatabaseCommand() {
5893
6074
  body
5894
6075
  });
5895
6076
  if (error2) throw mapApiError(response.status, error2);
6077
+ if (options.output === "json") {
6078
+ ctx.spinner.stop();
6079
+ outputJson({
6080
+ success: true,
6081
+ action: "restore",
6082
+ resource: "database",
6083
+ databaseName,
6084
+ backupName: options.from,
6085
+ restoredName: options.name ?? null,
6086
+ status: "requested"
6087
+ });
6088
+ return;
6089
+ }
5896
6090
  ctx.spinner.succeed(`Restore requested from backup "${options.from}"`);
5897
6091
  }));
5898
- dbCmd.command("enable-public <name>").description("Enable public access for a database").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name) => {
6092
+ 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) => {
5899
6093
  const client = createDatabaseClient();
5900
6094
  const { error: error2, response } = await client.POST("/databases/{databaseName}/enable-public", {
5901
6095
  headers: ctx.auth,
@@ -5904,9 +6098,20 @@ function createDatabaseCommand() {
5904
6098
  }
5905
6099
  });
5906
6100
  if (error2) throw mapApiError(response.status, error2);
6101
+ if (options.output === "json") {
6102
+ ctx.spinner.stop();
6103
+ outputJson({
6104
+ success: true,
6105
+ action: "enable-public",
6106
+ resource: "database",
6107
+ name,
6108
+ status: "enabled"
6109
+ });
6110
+ return;
6111
+ }
5907
6112
  ctx.spinner.succeed(`Public access enabled for "${name}"`);
5908
6113
  }));
5909
- dbCmd.command("disable-public <name>").description("Disable public access for a database").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name) => {
6114
+ 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) => {
5910
6115
  const client = createDatabaseClient();
5911
6116
  const { error: error2, response } = await client.POST("/databases/{databaseName}/disable-public", {
5912
6117
  headers: ctx.auth,
@@ -5915,9 +6120,20 @@ function createDatabaseCommand() {
5915
6120
  }
5916
6121
  });
5917
6122
  if (error2) throw mapApiError(response.status, error2);
6123
+ if (options.output === "json") {
6124
+ ctx.spinner.stop();
6125
+ outputJson({
6126
+ success: true,
6127
+ action: "disable-public",
6128
+ resource: "database",
6129
+ name,
6130
+ status: "disabled"
6131
+ });
6132
+ return;
6133
+ }
5918
6134
  ctx.spinner.succeed(`Public access disabled for "${name}"`);
5919
6135
  }));
5920
- 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({
6136
+ 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({
5921
6137
  spinnerText: "Loading logs..."
5922
6138
  }, async (ctx, podName, options) => {
5923
6139
  const client = createDatabaseClient();
@@ -5954,7 +6170,7 @@ function createDatabaseCommand() {
5954
6170
  console.log(source_default.dim(`
5955
6171
  page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${String(data.data.metadata.hasMore)}`));
5956
6172
  }));
5957
- 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({
6173
+ 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({
5958
6174
  spinnerText: "Loading log files..."
5959
6175
  }, async (ctx, podName, options) => {
5960
6176
  const client = createDatabaseClient();
@@ -6148,6 +6364,11 @@ function createTemplateCommand() {
6148
6364
  body: body2
6149
6365
  });
6150
6366
  if (error3) throw mapApiError(response2.status, error3);
6367
+ if (deployOptions.output === "json") {
6368
+ ctx.spinner.stop();
6369
+ outputJson(data2);
6370
+ return;
6371
+ }
6151
6372
  ctx.spinner.succeed(`Instance "${data2.name}" created successfully`);
6152
6373
  printInstanceResult(data2, { template: catalogTemplate });
6153
6374
  return;
@@ -6159,6 +6380,11 @@ function createTemplateCommand() {
6159
6380
  body
6160
6381
  });
6161
6382
  if (error2) throw mapApiError(response.status, error2);
6383
+ if (deployOptions.output === "json") {
6384
+ ctx.spinner.stop();
6385
+ outputJson(data);
6386
+ return;
6387
+ }
6162
6388
  if (deployOptions.dryRun) {
6163
6389
  ctx.spinner.succeed("Raw template validation passed; no resources were created");
6164
6390
  printInstanceResult(data, { raw: true, dryRun: true });
@@ -6167,7 +6393,7 @@ function createTemplateCommand() {
6167
6393
  ctx.spinner.succeed(`Raw template deployed as "${data.name}"`);
6168
6394
  printInstanceResult(data, { raw: true });
6169
6395
  });
6170
- 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) => {
6396
+ 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) => {
6171
6397
  const client = createTemplateClient();
6172
6398
  const { data, error: error2, response } = await client.GET("/templates", {
6173
6399
  params: { query: options.language ? { language: options.language } : {} }
@@ -6195,7 +6421,7 @@ function createTemplateCommand() {
6195
6421
  }
6196
6422
  outputTable(rows);
6197
6423
  }));
6198
- 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) => {
6424
+ 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) => {
6199
6425
  const client = createTemplateClient();
6200
6426
  const { data, error: error2, response } = await client.GET("/templates/{name}", {
6201
6427
  params: {
@@ -6243,7 +6469,7 @@ function createTemplateCommand() {
6243
6469
  outputTable(argRows);
6244
6470
  }
6245
6471
  }));
6246
- tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance) => {
6472
+ 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) => {
6247
6473
  const client = createTemplateClient();
6248
6474
  const { error: error2, response } = await client.DELETE("/templates/instances/{instanceName}", {
6249
6475
  headers: ctx.auth,
@@ -6252,9 +6478,20 @@ function createTemplateCommand() {
6252
6478
  }
6253
6479
  });
6254
6480
  if (error2) throw mapApiError(response.status, error2);
6481
+ if (options.output === "json") {
6482
+ ctx.spinner.stop();
6483
+ outputJson({
6484
+ success: true,
6485
+ action: "delete",
6486
+ resource: "template-instance",
6487
+ instance,
6488
+ status: "deleted"
6489
+ });
6490
+ return;
6491
+ }
6255
6492
  ctx.spinner.succeed(`Instance "${instance}" deleted`);
6256
6493
  }));
6257
- 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", `
6494
+ 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", `
6258
6495
  Examples:
6259
6496
  Catalog:
6260
6497
  sealos-cli template deploy perplexica --name my-app --set OPENAI_API_KEY=xxx
@@ -6276,7 +6513,7 @@ __name(createTemplateCommand, "createTemplateCommand");
6276
6513
  // package.json
6277
6514
  var package_default = {
6278
6515
  name: "sealos-cli",
6279
- version: "1.1.0",
6516
+ version: "1.1.2",
6280
6517
  description: "Official CLI tool for Sealos Cloud - Manage auth, workspaces, devboxes, databases, and templates",
6281
6518
  types: "dist/main.d.ts",
6282
6519
  type: "module",