sealos-cli 1.1.1 → 1.1.2

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