@botim/botim-cli 0.0.6 → 0.0.8
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/cli.js +287 -63
- package/dist/cli.mjs +6 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13,13 +13,46 @@ import { createReactApp, createVueApp, handleLogin, handleLogout, handleQRCode }
|
|
|
13
13
|
import { showMenuOrRequireAuth } from "./commands/auth/index.js";
|
|
14
14
|
import { displayExamples, displayQuickStart } from "./utils/help.js";
|
|
15
15
|
import { logger, displayErrorSync } from "./utils/logger.js";
|
|
16
|
-
import { isLoggedIn, getCurrentEnvironment, setCurrentEnvironment, getAllEnvironmentStatus } from "./utils/config.js";
|
|
16
|
+
import { isLoggedIn, getCurrentEnvironment, setCurrentEnvironment, getAllEnvironmentStatus, getPartnerId, getPartnerName, getUserToken } from "./utils/config.js";
|
|
17
17
|
import { setRuntimeEnvironment, parseEnvironment, getEnvironmentDisplayName } from "./utils/environment.js";
|
|
18
18
|
import { executeWithAuthRetry } from "./utils/auth-handler.js";
|
|
19
|
+
import { getConfigPath } from "./utils/config-sync.js";
|
|
20
|
+
import { switchToPartner } from "./utils/partner-switch.js";
|
|
21
|
+
import { fetchPartners } from "./utils/auth-api.js";
|
|
22
|
+
import { select } from "@inquirer/prompts";
|
|
19
23
|
import chalk from "chalk";
|
|
20
24
|
import fs from "fs-extra";
|
|
21
|
-
|
|
22
|
-
const
|
|
25
|
+
async function promptSelect(options) {
|
|
26
|
+
const ac = new AbortController();
|
|
27
|
+
const onKeypress = (_ch, key) => {
|
|
28
|
+
if (key?.name === "escape") {
|
|
29
|
+
ac.abort();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
process.stdin.on("keypress", onKeypress);
|
|
33
|
+
try {
|
|
34
|
+
return await select({
|
|
35
|
+
...options,
|
|
36
|
+
theme: {
|
|
37
|
+
helpMode: "always",
|
|
38
|
+
style: {
|
|
39
|
+
keysHelpTip: (keys) => {
|
|
40
|
+
keys.push(["esc", "back"]);
|
|
41
|
+
return keys.map(([key, desc]) => `\x1B[1m${key}\x1B[22m \x1B[2m${desc}\x1B[22m`).join("\x1B[2m \u2022 \x1B[22m");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, { signal: ac.signal });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error.name === "AbortPromptError") {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
} finally {
|
|
52
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const version = "0.0.8";
|
|
23
56
|
const program = new Command();
|
|
24
57
|
program.name("botim-cli").description("CLI tool to generate boilerplate code for React and Vue applications").version(version, "-v, --version", "Output the current version").option("--env <environment>", "Target environment: prod, uat, or beta (overrides default)", (value) => {
|
|
25
58
|
const env = parseEnvironment(value);
|
|
@@ -103,7 +136,7 @@ program.command("status").description("Show login status for all environments").
|
|
|
103
136
|
const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
|
|
104
137
|
console.log(` ${prodIndicator} Production${prodActive}`);
|
|
105
138
|
if (prodStatus.loggedIn && prodStatus.partnerName) {
|
|
106
|
-
console.log(chalk.gray(` Partner: ${prodStatus.partnerName}`));
|
|
139
|
+
console.log(chalk.gray(` Partner: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
|
|
107
140
|
} else if (!prodStatus.loggedIn) {
|
|
108
141
|
console.log(chalk.gray(" Not logged in"));
|
|
109
142
|
}
|
|
@@ -113,7 +146,7 @@ program.command("status").description("Show login status for all environments").
|
|
|
113
146
|
const uatActive = currentEnv === "uat" ? chalk.cyan(" (active)") : "";
|
|
114
147
|
console.log(` ${uatIndicator} UAT${uatActive}`);
|
|
115
148
|
if (uatStatus.loggedIn && uatStatus.partnerName) {
|
|
116
|
-
console.log(chalk.gray(` Partner: ${uatStatus.partnerName}`));
|
|
149
|
+
console.log(chalk.gray(` Partner: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
|
|
117
150
|
} else if (!uatStatus.loggedIn) {
|
|
118
151
|
console.log(chalk.gray(" Not logged in"));
|
|
119
152
|
}
|
|
@@ -123,20 +156,21 @@ program.command("status").description("Show login status for all environments").
|
|
|
123
156
|
const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
|
|
124
157
|
console.log(` ${betaIndicator} Beta${betaActive}`);
|
|
125
158
|
if (betaStatus.loggedIn && betaStatus.partnerName) {
|
|
126
|
-
console.log(chalk.gray(` Partner: ${betaStatus.partnerName}`));
|
|
159
|
+
console.log(chalk.gray(` Partner: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
|
|
127
160
|
} else if (!betaStatus.loggedIn) {
|
|
128
161
|
console.log(chalk.gray(" Not logged in"));
|
|
129
162
|
}
|
|
130
163
|
console.log("");
|
|
131
164
|
console.log(chalk.gray("Tips:"));
|
|
132
165
|
console.log(chalk.gray(" Switch environment: botim-cli config set env uat"));
|
|
166
|
+
console.log(chalk.gray(" Switch partner: botim-cli switch-partner"));
|
|
133
167
|
console.log(chalk.gray(" One-time override: botim-cli --env beta <command>"));
|
|
134
168
|
console.log(chalk.gray(" Login to beta: botim-cli --env beta login\n"));
|
|
135
169
|
});
|
|
136
170
|
program.command("auth").description("Access authenticated commands (requires login)").alias("authenticated").action(async () => {
|
|
137
171
|
await showMenuOrRequireAuth();
|
|
138
172
|
});
|
|
139
|
-
program.command("create-mp-app").description("Create a new Mini-Program app non-interactively (requires authentication)").alias("cmp").requiredOption("--projectName <name>", "Project folder name").option("--framework <framework>", "Template framework: react or vue", "react").option("--title <title>", "App title (default: derived from projectName)").option("--domainPrefix <prefix>", "Domain prefix (default: auto-selected)").option("--reviewNote <note>", "Review note for submission (default: auto-generated)").option("--creatorType <type>", "Creator type: hybrid or h5bridge", "hybrid").option("--website <url>", "Website URL (required if creatorType=h5bridge)").option("--shareText <text>", "Share card description (default: same as title)").option("--screenOrientation <orientation>", "Screen mode: fullscreen, immersive, or standard", "fullscreen").option("--apiLevel <version>", "API level version (default: latest available)").option("--audience <audience>", "Audience: 1=
|
|
173
|
+
program.command("create-mp-app").description("Create a new Mini-Program app non-interactively (requires authentication)").alias("cmp").requiredOption("--projectName <name>", "Project folder name").option("--framework <framework>", "Template framework: react or vue", "react").option("--title <title>", "App title (default: derived from projectName)").option("--domainPrefix <prefix>", "Domain prefix (default: auto-selected)").option("--reviewNote <note>", "Review note for submission (default: auto-generated)").option("--creatorType <type>", "Creator type: hybrid or h5bridge", "hybrid").option("--website <url>", "Website URL (required if creatorType=h5bridge)").option("--shareText <text>", "Share card description (default: same as title)").option("--screenOrientation <orientation>", "Screen mode: fullscreen, immersive, or standard", "fullscreen").option("--apiLevel <version>", "API level version (default: latest available)").option("--audience <audience>", "Audience: 1=Public or 2=Private", "1").addHelpText("after", `
|
|
140
174
|
|
|
141
175
|
Examples:
|
|
142
176
|
Basic usage with minimal options:
|
|
@@ -183,8 +217,8 @@ Screen Orientations:
|
|
|
183
217
|
standard - Standard page with title bar
|
|
184
218
|
|
|
185
219
|
Audience Options:
|
|
186
|
-
1 -
|
|
187
|
-
2 -
|
|
220
|
+
1 - Public (accessible to all users) (default)
|
|
221
|
+
2 - Private (only accessible to specific users)
|
|
188
222
|
`).action(async (options) => {
|
|
189
223
|
try {
|
|
190
224
|
const loggedIn = await isLoggedIn();
|
|
@@ -214,6 +248,71 @@ Audience Options:
|
|
|
214
248
|
process.exit(1);
|
|
215
249
|
}
|
|
216
250
|
});
|
|
251
|
+
program.command("register-mp-app").description("Register a new Mini-Program on platform only, no template (requires authentication)").alias("rmp").requiredOption("--title <title>", "App title").option("--domainPrefix <prefix>", "Domain prefix (default: auto-selected)").option("--appIdSuffix <suffix>", "App ID suffix (default: auto-generated)").option("--reviewNote <note>", "Review note for submission (default: auto-generated)").option("--creatorType <type>", "Creator type: hybrid or h5bridge", "hybrid").option("--website <url>", "Website URL (required if creatorType=h5bridge)").option("--shareText <text>", "Share card description (default: same as title)").option("--screenOrientation <orientation>", "Screen mode: fullscreen, immersive, or standard", "fullscreen").option("--apiLevel <version>", "API level version (default: latest available)").option("--audience <audience>", "Audience: 1=Public or 2=Private", "1").addHelpText("after", `
|
|
252
|
+
|
|
253
|
+
Examples:
|
|
254
|
+
Register with minimal options:
|
|
255
|
+
$ botim-cli register-mp-app --title "My App"
|
|
256
|
+
|
|
257
|
+
Register with all options:
|
|
258
|
+
$ botim-cli register-mp-app \\
|
|
259
|
+
--title "My App" \\
|
|
260
|
+
--domainPrefix me.botim.mp.test \\
|
|
261
|
+
--shareText "Explore my amazing app" \\
|
|
262
|
+
--screenOrientation immersive \\
|
|
263
|
+
--audience 2
|
|
264
|
+
|
|
265
|
+
Register an H5BRIDGE app:
|
|
266
|
+
$ botim-cli register-mp-app \\
|
|
267
|
+
--title "My Website" \\
|
|
268
|
+
--creatorType h5bridge \\
|
|
269
|
+
--website https://example.com \\
|
|
270
|
+
--shareText "Visit my website"
|
|
271
|
+
|
|
272
|
+
Use UAT environment:
|
|
273
|
+
$ botim-cli --env uat register-mp-app --title "My UAT App"
|
|
274
|
+
|
|
275
|
+
Creator Types:
|
|
276
|
+
hybrid - Fastest, local resources with full platform capabilities (default)
|
|
277
|
+
h5bridge - Standard, wraps a responsive HTML5 website (requires --website)
|
|
278
|
+
|
|
279
|
+
Screen Orientations:
|
|
280
|
+
fullscreen - Full screen with status bar visible (default)
|
|
281
|
+
immersive - Full screen with status bar hidden
|
|
282
|
+
standard - Standard page with title bar
|
|
283
|
+
|
|
284
|
+
Audience Options:
|
|
285
|
+
1 - Public (accessible to all users) (default)
|
|
286
|
+
2 - Private (only accessible to specific users)
|
|
287
|
+
`).action(async (options) => {
|
|
288
|
+
try {
|
|
289
|
+
const loggedIn = await isLoggedIn();
|
|
290
|
+
if (!loggedIn) {
|
|
291
|
+
const currentEnv = await getCurrentEnvironment();
|
|
292
|
+
const envDisplay = getEnvironmentDisplayName(currentEnv);
|
|
293
|
+
console.log(chalk.red(`
|
|
294
|
+
\u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "uat" ? "--env uat " : ""}login
|
|
295
|
+
`));
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
|
|
299
|
+
const command = authenticatedCommandRegistry.get("register-mp-app");
|
|
300
|
+
if (command) {
|
|
301
|
+
const processedOptions = {
|
|
302
|
+
...options,
|
|
303
|
+
audience: parseInt(options.audience, 10)
|
|
304
|
+
};
|
|
305
|
+
await executeWithAuthRetry(
|
|
306
|
+
() => command.execute(processedOptions),
|
|
307
|
+
{ commandName: "register-mp-app", retryAfterLogin: true }
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
logger.error("register-mp-app command failed", error);
|
|
312
|
+
displayErrorSync(error, "Register MP App failed");
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
217
316
|
program.command("init-mp-app").description("Initialize MP app in current directory (requires authentication)").alias("init-mp").action(async () => {
|
|
218
317
|
try {
|
|
219
318
|
const loggedIn = await isLoggedIn();
|
|
@@ -264,7 +363,7 @@ program.command("deploy-mp-app").description("Deploy MP app to server (requires
|
|
|
264
363
|
process.exit(1);
|
|
265
364
|
}
|
|
266
365
|
});
|
|
267
|
-
program.command("debug-mp-app").description("Debug MP app (requires authentication and
|
|
366
|
+
program.command("debug-mp-app").description("Debug MP app (requires authentication and config file)").alias("debug").action(async () => {
|
|
268
367
|
try {
|
|
269
368
|
const loggedIn = await isLoggedIn();
|
|
270
369
|
if (!loggedIn) {
|
|
@@ -289,6 +388,89 @@ program.command("debug-mp-app").description("Debug MP app (requires authenticati
|
|
|
289
388
|
process.exit(1);
|
|
290
389
|
}
|
|
291
390
|
});
|
|
391
|
+
program.command("switch-partner [partner-id]").description("Switch to a different partner without re-login").alias("sp").action(async (partnerId) => {
|
|
392
|
+
try {
|
|
393
|
+
const currentEnv = await getCurrentEnvironment();
|
|
394
|
+
const envDisplay = getEnvironmentDisplayName(currentEnv);
|
|
395
|
+
const loggedIn = await isLoggedIn();
|
|
396
|
+
if (!loggedIn) {
|
|
397
|
+
console.log(chalk.red(`
|
|
398
|
+
\u274C Authentication required for ${envDisplay}. Please login first using: botim-cli login
|
|
399
|
+
`));
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
const userToken = await getUserToken(currentEnv);
|
|
403
|
+
if (!userToken) {
|
|
404
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable partner switching.\n"));
|
|
405
|
+
console.log(chalk.gray("Run: botim-cli login\n"));
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
let selectedPartnerId = partnerId;
|
|
409
|
+
if (!selectedPartnerId) {
|
|
410
|
+
const ora = (await import("ora")).default;
|
|
411
|
+
const spinner = ora("Fetching partner list...").start();
|
|
412
|
+
let partnerList;
|
|
413
|
+
try {
|
|
414
|
+
partnerList = await fetchPartners({ userToken, env: currentEnv });
|
|
415
|
+
spinner.succeed("Partner list fetched");
|
|
416
|
+
} catch (error) {
|
|
417
|
+
spinner.fail("Failed to fetch partner list");
|
|
418
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F Could not fetch partner list. Your session may have expired.\n"));
|
|
419
|
+
console.log(chalk.gray("Run: botim-cli login\n"));
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
if (!partnerList || partnerList.length === 0) {
|
|
423
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F No partners found for your account.\n"));
|
|
424
|
+
process.exit(1);
|
|
425
|
+
}
|
|
426
|
+
const currentPartnerId2 = await getPartnerId(currentEnv);
|
|
427
|
+
const selected = await promptSelect({
|
|
428
|
+
message: "Select a partner:",
|
|
429
|
+
choices: partnerList.map((p) => ({
|
|
430
|
+
name: `${p.partnerInfo?.company_name || p.partner_id} (${p.partner_id})${p.partner_id === currentPartnerId2 ? chalk.cyan(" \u2190 current") : ""}`,
|
|
431
|
+
value: p.partner_id
|
|
432
|
+
}))
|
|
433
|
+
});
|
|
434
|
+
if (selected === null) {
|
|
435
|
+
process.exit(0);
|
|
436
|
+
}
|
|
437
|
+
selectedPartnerId = selected;
|
|
438
|
+
}
|
|
439
|
+
if (!selectedPartnerId) {
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
const currentPartnerId = await getPartnerId(currentEnv);
|
|
443
|
+
if (selectedPartnerId === currentPartnerId) {
|
|
444
|
+
const currentPartnerName = await getPartnerName(currentEnv);
|
|
445
|
+
console.log(chalk.gray(`
|
|
446
|
+
Already using partner: ${currentPartnerName || selectedPartnerId}
|
|
447
|
+
`));
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const result = await switchToPartner(selectedPartnerId, currentEnv);
|
|
451
|
+
if (result.success) {
|
|
452
|
+
console.log(chalk.green(`
|
|
453
|
+
\u2713 Switched to partner: ${result.partnerName}
|
|
454
|
+
`));
|
|
455
|
+
} else if (result.error === "partner-not-found") {
|
|
456
|
+
console.log(chalk.red(`
|
|
457
|
+
\u274C Partner ${selectedPartnerId} not found in your partner list.
|
|
458
|
+
`));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
} else if (result.error === "no-user-token" || result.error === "user-token-expired") {
|
|
461
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F Your session has expired. Please login again.\n"));
|
|
462
|
+
console.log(chalk.gray("Run: botim-cli login\n"));
|
|
463
|
+
process.exit(1);
|
|
464
|
+
} else {
|
|
465
|
+
console.log(chalk.red("\n\u274C Failed to switch partner. Please try logging in again.\n"));
|
|
466
|
+
process.exit(1);
|
|
467
|
+
}
|
|
468
|
+
} catch (error) {
|
|
469
|
+
logger.error("switch-partner command failed", error);
|
|
470
|
+
displayErrorSync(error, "Switch partner failed");
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
292
474
|
program.command("list-mp-permissions [app-id]").description("List permissions for a mini-program app (requires authentication)").alias("perms").action(async (appId) => {
|
|
293
475
|
try {
|
|
294
476
|
const loggedIn = await isLoggedIn();
|
|
@@ -530,19 +712,22 @@ async function showMainMenu() {
|
|
|
530
712
|
const currentEnv = await getCurrentEnvironment();
|
|
531
713
|
const envDisplay = getEnvironmentDisplayName(currentEnv);
|
|
532
714
|
const envColor = currentEnv === "production" ? chalk.green : chalk.yellow;
|
|
715
|
+
const currentPartnerName = await getPartnerName(currentEnv);
|
|
533
716
|
console.log(chalk.cyan.bold("\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
534
717
|
console.log(chalk.cyan.bold("\u2551 \u{1F680} Botim CLI Generator \u2551"));
|
|
535
718
|
console.log(chalk.cyan.bold(`\u2551 v${version.padEnd(32)}\u2551`));
|
|
536
|
-
console.log(chalk.cyan.bold(`\u2551 Environment: ${envColor(envDisplay.padEnd(
|
|
719
|
+
console.log(chalk.cyan.bold(`\u2551 Environment: ${envColor(envDisplay.padEnd(27))}\u2551`));
|
|
720
|
+
if (currentPartnerName) {
|
|
721
|
+
console.log(chalk.cyan.bold(`\u2551 Partner: ${chalk.white(currentPartnerName.padEnd(31))}\u2551`));
|
|
722
|
+
}
|
|
537
723
|
console.log(chalk.cyan.bold("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n"));
|
|
538
|
-
const inquirer = (await import("inquirer")).default;
|
|
539
724
|
const loggedIn = await isLoggedIn();
|
|
540
725
|
let authenticatedChoices = [];
|
|
541
726
|
if (loggedIn) {
|
|
542
727
|
const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
|
|
543
728
|
const commands = authenticatedCommandRegistry.getAll();
|
|
544
729
|
const currentDir = process.cwd();
|
|
545
|
-
const configFilePath =
|
|
730
|
+
const configFilePath = getConfigPath(currentDir, currentEnv);
|
|
546
731
|
const hasConfigFile = await fs.pathExists(configFilePath);
|
|
547
732
|
const filteredCommands = commands.filter((cmd) => {
|
|
548
733
|
if (cmd.hideFromMenu) {
|
|
@@ -551,7 +736,7 @@ async function showMainMenu() {
|
|
|
551
736
|
if (cmd.name === "deploy-mp-app" || cmd.name === "debug-mp-app") {
|
|
552
737
|
return hasConfigFile;
|
|
553
738
|
}
|
|
554
|
-
if (cmd.name === "create-mp-app" || cmd.name === "
|
|
739
|
+
if (cmd.name === "create-mp-app" || cmd.name === "register-mp-app") {
|
|
555
740
|
return !hasConfigFile;
|
|
556
741
|
}
|
|
557
742
|
return true;
|
|
@@ -574,20 +759,21 @@ async function showMainMenu() {
|
|
|
574
759
|
...authenticatedChoices,
|
|
575
760
|
{ name: "\u{1F4F1} Create a Mini-Program (Local)", value: "mini-program" },
|
|
576
761
|
{ name: "\u{1F504} Switch Environment", value: "switch-env" },
|
|
762
|
+
{ name: "\u{1F500} Switch Partner", value: "switch-partner" },
|
|
577
763
|
{ name: "\u{1F4CA} View Status", value: "status" },
|
|
578
764
|
{ name: "\u{1F6AA} Logout", value: "logout" },
|
|
579
765
|
{ name: "\u{1F4DA} View examples", value: "examples" },
|
|
580
766
|
{ name: "\u2753 Show help", value: "help" },
|
|
581
767
|
{ name: "\u{1F6AA} Exit", value: "exit" }
|
|
582
768
|
];
|
|
583
|
-
const
|
|
584
|
-
{
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
769
|
+
const action = await promptSelect({
|
|
770
|
+
message: loggedIn ? envColor(`\u2713 Authenticated [${envDisplay}]`) + " - What would you like to do?" : `[${envDisplay}] What would you like to do?`,
|
|
771
|
+
choices: loggedIn ? authenticatedChoices : unauthenticatedChoices
|
|
772
|
+
});
|
|
773
|
+
if (action === null) {
|
|
774
|
+
console.log(chalk.gray("\nGoodbye! \u{1F44B}\n"));
|
|
775
|
+
process.exit(0);
|
|
776
|
+
}
|
|
591
777
|
if (action.startsWith("auth:")) {
|
|
592
778
|
const commandName = action.replace("auth:", "");
|
|
593
779
|
const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
|
|
@@ -605,20 +791,14 @@ async function showMainMenu() {
|
|
|
605
791
|
}
|
|
606
792
|
}
|
|
607
793
|
} else if (action === "mini-program") {
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
name: "
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
new inquirer.Separator(),
|
|
617
|
-
{ name: "\u2190 Back to main menu", value: "back" }
|
|
618
|
-
]
|
|
619
|
-
}
|
|
620
|
-
]);
|
|
621
|
-
if (framework === "back") {
|
|
794
|
+
const framework = await promptSelect({
|
|
795
|
+
message: "Select a framework template:",
|
|
796
|
+
choices: [
|
|
797
|
+
{ name: "\u269B\uFE0F React - Modern React 18 with Vite", value: "react" },
|
|
798
|
+
{ name: "\u{1F596} Vue - Vue 3 with Composition API", value: "vue" }
|
|
799
|
+
]
|
|
800
|
+
});
|
|
801
|
+
if (framework === null) {
|
|
622
802
|
await showMainMenu();
|
|
623
803
|
} else if (framework === "react") {
|
|
624
804
|
console.log(chalk.cyan.bold(`
|
|
@@ -633,30 +813,24 @@ async function showMainMenu() {
|
|
|
633
813
|
}
|
|
634
814
|
} else if (action === "switch-env") {
|
|
635
815
|
const allStatus = await getAllEnvironmentStatus();
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
new inquirer.Separator(),
|
|
655
|
-
{ name: "\u2190 Back to main menu", value: "back" }
|
|
656
|
-
]
|
|
657
|
-
}
|
|
658
|
-
]);
|
|
659
|
-
if (newEnv === "back") {
|
|
816
|
+
const newEnv = await promptSelect({
|
|
817
|
+
message: "Select environment:",
|
|
818
|
+
choices: [
|
|
819
|
+
{
|
|
820
|
+
name: `Production ${allStatus.production.loggedIn ? chalk.green("\u2713 Logged in") : chalk.gray("(not logged in)")}${currentEnv === "production" ? chalk.cyan(" \u2190 current") : ""}`,
|
|
821
|
+
value: "production"
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
name: `UAT ${allStatus.uat.loggedIn ? chalk.green("\u2713 Logged in") : chalk.gray("(not logged in)")}${currentEnv === "uat" ? chalk.cyan(" \u2190 current") : ""}`,
|
|
825
|
+
value: "uat"
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
name: `Beta ${allStatus.beta.loggedIn ? chalk.green("\u2713 Logged in") : chalk.gray("(not logged in)")}${currentEnv === "beta" ? chalk.cyan(" \u2190 current") : ""}`,
|
|
829
|
+
value: "beta"
|
|
830
|
+
}
|
|
831
|
+
]
|
|
832
|
+
});
|
|
833
|
+
if (newEnv === null) {
|
|
660
834
|
await showMainMenu();
|
|
661
835
|
} else {
|
|
662
836
|
await setCurrentEnvironment(newEnv);
|
|
@@ -671,6 +845,56 @@ async function showMainMenu() {
|
|
|
671
845
|
}
|
|
672
846
|
await showMainMenu();
|
|
673
847
|
}
|
|
848
|
+
} else if (action === "switch-partner") {
|
|
849
|
+
const userToken = await getUserToken(currentEnv);
|
|
850
|
+
if (!userToken) {
|
|
851
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable partner switching.\n"));
|
|
852
|
+
await showMainMenu();
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const ora = (await import("ora")).default;
|
|
856
|
+
const spinner = ora("Fetching partner list...").start();
|
|
857
|
+
let partnerList;
|
|
858
|
+
try {
|
|
859
|
+
partnerList = await fetchPartners({ userToken, env: currentEnv });
|
|
860
|
+
spinner.succeed("Partner list fetched");
|
|
861
|
+
} catch {
|
|
862
|
+
spinner.fail("Failed to fetch partner list");
|
|
863
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F Could not fetch partner list. Your session may have expired.\n"));
|
|
864
|
+
await showMainMenu();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
if (!partnerList || partnerList.length === 0) {
|
|
868
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F No partners found for your account.\n"));
|
|
869
|
+
await showMainMenu();
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
const currentPartnerId = await getPartnerId(currentEnv);
|
|
873
|
+
const selectedPartnerId = await promptSelect({
|
|
874
|
+
message: "Select a partner:",
|
|
875
|
+
choices: partnerList.map((p) => ({
|
|
876
|
+
name: `${p.partnerInfo?.company_name || p.partner_id} (${p.partner_id})${p.partner_id === currentPartnerId ? chalk.cyan(" \u2190 current") : ""}`,
|
|
877
|
+
value: p.partner_id
|
|
878
|
+
}))
|
|
879
|
+
});
|
|
880
|
+
if (selectedPartnerId === null) {
|
|
881
|
+
await showMainMenu();
|
|
882
|
+
} else if (selectedPartnerId === currentPartnerId) {
|
|
883
|
+
console.log(chalk.gray("\nAlready using this partner.\n"));
|
|
884
|
+
await showMainMenu();
|
|
885
|
+
} else {
|
|
886
|
+
const result = await switchToPartner(selectedPartnerId, currentEnv);
|
|
887
|
+
if (result.success) {
|
|
888
|
+
console.log(chalk.green(`
|
|
889
|
+
\u2713 Switched to partner: ${result.partnerName}
|
|
890
|
+
`));
|
|
891
|
+
} else if (result.error === "no-user-token" || result.error === "user-token-expired") {
|
|
892
|
+
console.log(chalk.yellow("\n\u26A0\uFE0F Your session has expired. Please login again.\n"));
|
|
893
|
+
} else {
|
|
894
|
+
console.log(chalk.red("\n\u274C Failed to switch partner.\n"));
|
|
895
|
+
}
|
|
896
|
+
await showMainMenu();
|
|
897
|
+
}
|
|
674
898
|
} else if (action === "status") {
|
|
675
899
|
const allStatus = await getAllEnvironmentStatus();
|
|
676
900
|
console.log(chalk.cyan.bold(`
|
|
@@ -683,21 +907,21 @@ async function showMainMenu() {
|
|
|
683
907
|
const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
|
|
684
908
|
console.log(` ${prodIndicator} Production${prodActive}`);
|
|
685
909
|
if (prodStatus.loggedIn && prodStatus.partnerName) {
|
|
686
|
-
console.log(chalk.gray(` Partner: ${prodStatus.partnerName}`));
|
|
910
|
+
console.log(chalk.gray(` Partner: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
|
|
687
911
|
}
|
|
688
912
|
const uatStatus = allStatus.uat;
|
|
689
913
|
const uatIndicator = uatStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
690
914
|
const uatActive = currentEnv === "uat" ? chalk.cyan(" (active)") : "";
|
|
691
915
|
console.log(` ${uatIndicator} UAT${uatActive}`);
|
|
692
916
|
if (uatStatus.loggedIn && uatStatus.partnerName) {
|
|
693
|
-
console.log(chalk.gray(` Partner: ${uatStatus.partnerName}`));
|
|
917
|
+
console.log(chalk.gray(` Partner: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
|
|
694
918
|
}
|
|
695
919
|
const betaStatus = allStatus.beta;
|
|
696
920
|
const betaIndicator = betaStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
697
921
|
const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
|
|
698
922
|
console.log(` ${betaIndicator} Beta${betaActive}`);
|
|
699
923
|
if (betaStatus.loggedIn && betaStatus.partnerName) {
|
|
700
|
-
console.log(chalk.gray(` Partner: ${betaStatus.partnerName}`));
|
|
924
|
+
console.log(chalk.gray(` Partner: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
|
|
701
925
|
}
|
|
702
926
|
console.log("");
|
|
703
927
|
await showMainMenu();
|