sealos-cli 1.1.1 → 1.1.3

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