@botim/botim-cli 0.0.1 → 0.0.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.
Files changed (3) hide show
  1. package/dist/cli.js +201 -20
  2. package/dist/cli.mjs +2 -2
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4,17 +4,33 @@ import { createReactApp, createVueApp, handleLogin, handleLogout, handleQRCode }
4
4
  import { showMenuOrRequireAuth } from "./commands/auth/index.js";
5
5
  import { displayExamples, displayQuickStart } from "./utils/help.js";
6
6
  import { logger } from "./utils/logger.js";
7
- import { isLoggedIn } from "./utils/config.js";
7
+ import { isLoggedIn, getCurrentEnvironment, setCurrentEnvironment, getAllEnvironmentStatus } from "./utils/config.js";
8
+ import { setRuntimeEnvironment, parseEnvironment, getEnvironmentDisplayName } from "./utils/environment.js";
8
9
  import chalk from "chalk";
9
10
  import fs from "fs-extra";
10
11
  import path from "path";
11
- const version = "0.0.1";
12
+ const version = "0.0.3";
12
13
  const program = new Command();
13
- program.name("botim-cli").description("CLI tool to generate boilerplate code for React and Vue applications").version(version, "-v, --version", "Output the current version");
14
+ 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 or beta (overrides default)", (value) => {
15
+ const env = parseEnvironment(value);
16
+ if (!env) {
17
+ console.error(chalk.red(`
18
+ Invalid environment: ${value}. Valid values: prod, beta
19
+ `));
20
+ process.exit(1);
21
+ }
22
+ return env;
23
+ });
14
24
  program.configureHelp({
15
25
  sortSubcommands: true,
16
26
  sortOptions: true
17
27
  });
28
+ program.hook("preAction", async (thisCommand) => {
29
+ const opts = thisCommand.opts();
30
+ if (opts.env) {
31
+ setRuntimeEnvironment(opts.env);
32
+ }
33
+ });
18
34
  program.command("create-react-app [project-name]").description("Create a new React application with Vite and TypeScript").alias("react").action(async (projectName) => {
19
35
  console.log(chalk.cyan.bold(`
20
36
  \u{1F680} Botim CLI v${version} - React App Generator
@@ -45,17 +61,57 @@ program.command("examples").description("Show usage examples and common patterns
45
61
  program.command("quick-start").description("Show quick start guide").alias("qs").action(() => {
46
62
  displayQuickStart();
47
63
  });
48
- program.command("login [login-url]").description("Login via browser and save authentication token").action(async (loginUrl) => {
64
+ program.command("login").description("Login via QR code and save authentication token").action(async () => {
65
+ const currentEnv = await getCurrentEnvironment();
66
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
67
+ const envColor = currentEnv === "beta" ? chalk.yellow : chalk.green;
68
+ console.log(chalk.cyan.bold(`
69
+ \u{1F510} Botim CLI v${version} - Login ${envColor(`[${envDisplay}]`)}
70
+ `));
71
+ await handleLogin();
72
+ });
73
+ program.command("logout").description("Logout and clear saved authentication token").option("--all", "Clear credentials for all environments").action(async (options) => {
74
+ const currentEnv = await getCurrentEnvironment();
75
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
76
+ const envColor = currentEnv === "beta" ? chalk.yellow : chalk.green;
49
77
  console.log(chalk.cyan.bold(`
50
- \u{1F510} Botim CLI v${version} - Login
78
+ \u{1F6AA} Botim CLI v${version} - Logout ${envColor(`[${envDisplay}]`)}
51
79
  `));
52
- await handleLogin(loginUrl);
80
+ await handleLogout(options);
53
81
  });
54
- program.command("logout").description("Logout and clear saved authentication token").action(async () => {
82
+ program.command("status").description("Show login status for all environments").action(async () => {
55
83
  console.log(chalk.cyan.bold(`
56
- \u{1F6AA} Botim CLI v${version} - Logout
84
+ \u{1F4CA} Botim CLI v${version} - Status
57
85
  `));
58
- await handleLogout();
86
+ const currentEnv = await getCurrentEnvironment();
87
+ const allStatus = await getAllEnvironmentStatus();
88
+ console.log(chalk.gray(`Current environment: ${chalk.white.bold(getEnvironmentDisplayName(currentEnv))}
89
+ `));
90
+ console.log(chalk.gray("Credentials:\n"));
91
+ const prodStatus = allStatus.production;
92
+ const prodIndicator = prodStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
93
+ const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
94
+ console.log(` ${prodIndicator} Production${prodActive}`);
95
+ if (prodStatus.loggedIn && prodStatus.partnerName) {
96
+ console.log(chalk.gray(` Partner: ${prodStatus.partnerName}`));
97
+ } else if (!prodStatus.loggedIn) {
98
+ console.log(chalk.gray(" Not logged in"));
99
+ }
100
+ console.log("");
101
+ const betaStatus = allStatus.beta;
102
+ const betaIndicator = betaStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
103
+ const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
104
+ console.log(` ${betaIndicator} Beta${betaActive}`);
105
+ if (betaStatus.loggedIn && betaStatus.partnerName) {
106
+ console.log(chalk.gray(` Partner: ${betaStatus.partnerName}`));
107
+ } else if (!betaStatus.loggedIn) {
108
+ console.log(chalk.gray(" Not logged in"));
109
+ }
110
+ console.log("");
111
+ console.log(chalk.gray("Tips:"));
112
+ console.log(chalk.gray(" Switch environment: botim-cli config set env beta"));
113
+ console.log(chalk.gray(" One-time override: botim-cli --env beta <command>"));
114
+ console.log(chalk.gray(" Login to beta: botim-cli --env beta login\n"));
59
115
  });
60
116
  program.command("auth").description("Access authenticated commands (requires login)").alias("authenticated").action(async () => {
61
117
  await showMenuOrRequireAuth();
@@ -94,6 +150,9 @@ Examples:
94
150
  --audience 1 \\
95
151
  --reviewNote "Internal testing app"
96
152
 
153
+ Use beta environment:
154
+ $ botim-cli --env beta create-mp-app --projectName my-beta-app
155
+
97
156
  Creator Types:
98
157
  hybrid - Fastest, local resources with full platform capabilities (default)
99
158
  h5bridge - Standard, wraps a responsive HTML5 website (requires --website)
@@ -109,7 +168,11 @@ Audience Options:
109
168
  `).action(async (options) => {
110
169
  const loggedIn = await isLoggedIn();
111
170
  if (!loggedIn) {
112
- console.log(chalk.red("\n\u274C Authentication required. Please login first using: botim-cli login\n"));
171
+ const currentEnv = await getCurrentEnvironment();
172
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
173
+ console.log(chalk.red(`
174
+ \u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "beta" ? "--env beta " : ""}login
175
+ `));
113
176
  process.exit(1);
114
177
  }
115
178
  const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
@@ -125,7 +188,11 @@ Audience Options:
125
188
  program.command("init-mp-app").description("Initialize MP app in current directory (requires authentication)").alias("init-mp").action(async () => {
126
189
  const loggedIn = await isLoggedIn();
127
190
  if (!loggedIn) {
128
- console.log(chalk.red("\n\u274C Authentication required. Please login first using: botim-cli login\n"));
191
+ const currentEnv = await getCurrentEnvironment();
192
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
193
+ console.log(chalk.red(`
194
+ \u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "beta" ? "--env beta " : ""}login
195
+ `));
129
196
  process.exit(1);
130
197
  }
131
198
  const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
@@ -137,7 +204,11 @@ program.command("init-mp-app").description("Initialize MP app in current directo
137
204
  program.command("deploy-mp-app").description("Deploy MP app to server (requires authentication)").alias("deploy").option("-w, --website <url>", "Website/Endpoint URL (required for H5BRIDGE apps)").option("-n, --note <note>", 'Review note (optional, defaults to "Deployed via CLI")').option("-t, --testflight", "Release to TestFlight (Beta) - this is the default for direct mode").option("-y, --yes", "Skip confirmation prompts (Note: Production releases require interactive mode)").action(async (options) => {
138
205
  const loggedIn = await isLoggedIn();
139
206
  if (!loggedIn) {
140
- console.log(chalk.red("\n\u274C Authentication required. Please login first using: botim-cli login\n"));
207
+ const currentEnv = await getCurrentEnvironment();
208
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
209
+ console.log(chalk.red(`
210
+ \u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "beta" ? "--env beta " : ""}login
211
+ `));
141
212
  process.exit(1);
142
213
  }
143
214
  const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
@@ -149,7 +220,11 @@ program.command("deploy-mp-app").description("Deploy MP app to server (requires
149
220
  program.command("debug-mp-app").description("Debug MP app (requires authentication and botim_config.json)").alias("debug").action(async () => {
150
221
  const loggedIn = await isLoggedIn();
151
222
  if (!loggedIn) {
152
- console.log(chalk.red("\n\u274C Authentication required. Please login first using: botim-cli login\n"));
223
+ const currentEnv = await getCurrentEnvironment();
224
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
225
+ console.log(chalk.red(`
226
+ \u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "beta" ? "--env beta " : ""}login
227
+ `));
153
228
  process.exit(1);
154
229
  }
155
230
  const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
@@ -161,7 +236,11 @@ program.command("debug-mp-app").description("Debug MP app (requires authenticati
161
236
  program.command("list-mp-permissions [app-id]").description("List permissions for a mini-program app (requires authentication)").alias("perms").action(async (appId) => {
162
237
  const loggedIn = await isLoggedIn();
163
238
  if (!loggedIn) {
164
- console.log(chalk.red("\n\u274C Authentication required. Please login first using: botim-cli login\n"));
239
+ const currentEnv = await getCurrentEnvironment();
240
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
241
+ console.log(chalk.red(`
242
+ \u274C Authentication required for ${envDisplay}. Please login first using: botim-cli ${currentEnv === "beta" ? "--env beta " : ""}login
243
+ `));
165
244
  process.exit(1);
166
245
  }
167
246
  const { authenticatedCommandRegistry } = await import("./commands/auth/index.js");
@@ -171,10 +250,32 @@ program.command("list-mp-permissions [app-id]").description("List permissions fo
171
250
  }
172
251
  });
173
252
  const configCommand = program.command("config").description("Manage CLI configuration");
174
- configCommand.command("set <key> <value>").description("Set a configuration value").action(async (key) => {
253
+ configCommand.command("set <key> <value>").description("Set a configuration value").action(async (key, value) => {
175
254
  console.log(chalk.cyan.bold(`
176
255
  \u2699\uFE0F Botim CLI v${version} - Configuration
177
256
  `));
257
+ if (key === "env" || key === "environment") {
258
+ const env = parseEnvironment(value);
259
+ if (!env) {
260
+ console.log(chalk.red(`\u274C Invalid environment: ${value}
261
+ `));
262
+ console.log(chalk.yellow("Valid values: prod, production, beta\n"));
263
+ process.exit(1);
264
+ }
265
+ await setCurrentEnvironment(env);
266
+ const envDisplay = getEnvironmentDisplayName(env);
267
+ console.log(chalk.green(`\u2713 Switched to ${envDisplay} environment
268
+ `));
269
+ const loggedIn = await isLoggedIn(env);
270
+ if (loggedIn) {
271
+ console.log(chalk.green(`\u2713 You are already logged in to ${envDisplay}
272
+ `));
273
+ } else {
274
+ console.log(chalk.yellow(`\u26A0 You are not logged in to ${envDisplay}. Run 'botim-cli login' to authenticate.
275
+ `));
276
+ }
277
+ return;
278
+ }
178
279
  if (key.startsWith("templateRepositoryUrl") || key.startsWith("templateRepositoryBranch")) {
179
280
  console.log(chalk.yellow("\u26A0\uFE0F Template repository URLs use built-in defaults (part of the project).\n"));
180
281
  console.log(chalk.gray("To override defaults, create a .env file in your project root or ~/.botim-cli/.env with:\n"));
@@ -186,7 +287,9 @@ configCommand.command("set <key> <value>").description("Set a configuration valu
186
287
  } else {
187
288
  console.log(chalk.red(`\u274C Unknown configuration key: ${key}
188
289
  `));
189
- console.log(chalk.yellow("Note: Template repository URLs are configured via .env file, not CLI commands.\n"));
290
+ console.log(chalk.yellow("Available keys:\n"));
291
+ console.log(chalk.yellow(" - env (or environment): Set default environment (prod, beta)\n"));
292
+ console.log(chalk.yellow("\nNote: Template repository URLs are configured via .env file, not CLI commands.\n"));
190
293
  process.exit(1);
191
294
  }
192
295
  });
@@ -199,6 +302,13 @@ configCommand.command("get <key>").description("Get a configuration value").acti
199
302
  console.log(chalk.cyan.bold(`
200
303
  \u2699\uFE0F Botim CLI v${version} - Configuration
201
304
  `));
305
+ if (key === "env" || key === "environment") {
306
+ const currentEnv = await getCurrentEnvironment();
307
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
308
+ console.log(chalk.green(`Current environment: ${envDisplay}
309
+ `));
310
+ return;
311
+ }
202
312
  if (key.startsWith("templateRepositoryUrl:")) {
203
313
  const framework = key.split(":")[1];
204
314
  const availableFrameworks = getAvailableFrameworks();
@@ -254,6 +364,7 @@ configCommand.command("get <key>").description("Get a configuration value").acti
254
364
  console.log(chalk.red(`\u274C Unknown configuration key: ${key}
255
365
  `));
256
366
  console.log(chalk.yellow("Available keys:\n"));
367
+ console.log(chalk.yellow(" - env (or environment): Get current environment\n"));
257
368
  console.log(chalk.yellow(" - templateRepositoryUrl (shows all frameworks from .env)\n"));
258
369
  console.log(chalk.yellow(" - templateRepositoryUrl:<framework> (e.g., templateRepositoryUrl:react)\n"));
259
370
  console.log(chalk.yellow(" - templateRepositoryBranch (shows all frameworks from .env)\n"));
@@ -270,6 +381,11 @@ configCommand.command("list").description("List all configuration values").actio
270
381
  const { getAvailableFrameworks } = await import("./utils/template-repositories.js");
271
382
  console.log(chalk.cyan.bold(`
272
383
  \u2699\uFE0F Botim CLI v${version} - Configuration
384
+ `));
385
+ const currentEnv = await getCurrentEnvironment();
386
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
387
+ console.log(chalk.gray("Environment Configuration:\n"));
388
+ console.log(chalk.white(` Current: ${envDisplay}
273
389
  `));
274
390
  const availableFrameworks = getAvailableFrameworks();
275
391
  console.log(chalk.gray("Template Repository Configuration:\n"));
@@ -346,9 +462,13 @@ program.on("command:*", function() {
346
462
  });
347
463
  async function showMainMenu() {
348
464
  try {
465
+ const currentEnv = await getCurrentEnvironment();
466
+ const envDisplay = getEnvironmentDisplayName(currentEnv);
467
+ const envColor = currentEnv === "beta" ? chalk.yellow : chalk.green;
349
468
  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"));
350
469
  console.log(chalk.cyan.bold("\u2551 \u{1F680} Botim CLI Generator \u2551"));
351
470
  console.log(chalk.cyan.bold(`\u2551 v${version.padEnd(32)}\u2551`));
471
+ console.log(chalk.cyan.bold(`\u2551 Environment: ${envColor(envDisplay.padEnd(26))}\u2551`));
352
472
  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"));
353
473
  const inquirer = (await import("inquirer")).default;
354
474
  const loggedIn = await isLoggedIn();
@@ -379,7 +499,8 @@ async function showMainMenu() {
379
499
  const unauthenticatedChoices = [
380
500
  { name: "\u{1F4F1} Create a Mini-Program (Local)", value: "mini-program" },
381
501
  { name: "\u{1F510} Login", value: "login" },
382
- // { name: '📱 Generate QR Code', value: 'qrcode' },
502
+ { name: "\u{1F504} Switch Environment", value: "switch-env" },
503
+ { name: "\u{1F4CA} View Status", value: "status" },
383
504
  { name: "\u{1F4DA} View examples", value: "examples" },
384
505
  { name: "\u2753 Show help", value: "help" },
385
506
  { name: "\u{1F6AA} Exit", value: "exit" }
@@ -387,7 +508,8 @@ async function showMainMenu() {
387
508
  authenticatedChoices = [
388
509
  ...authenticatedChoices,
389
510
  { name: "\u{1F4F1} Create a Mini-Program (Local)", value: "mini-program" },
390
- // { name: '📱 Generate QR Code', value: 'qrcode' },
511
+ { name: "\u{1F504} Switch Environment", value: "switch-env" },
512
+ { name: "\u{1F4CA} View Status", value: "status" },
391
513
  { name: "\u{1F6AA} Logout", value: "logout" },
392
514
  { name: "\u{1F4DA} View examples", value: "examples" },
393
515
  { name: "\u2753 Show help", value: "help" },
@@ -397,7 +519,7 @@ async function showMainMenu() {
397
519
  {
398
520
  type: "list",
399
521
  name: "action",
400
- message: loggedIn ? chalk.green("\u2713 Authenticated") + " - What would you like to do?" : "What would you like to do?",
522
+ message: loggedIn ? envColor(`\u2713 Authenticated [${envDisplay}]`) + " - What would you like to do?" : `[${envDisplay}] What would you like to do?`,
401
523
  choices: loggedIn ? authenticatedChoices : unauthenticatedChoices
402
524
  }
403
525
  ]);
@@ -440,6 +562,65 @@ async function showMainMenu() {
440
562
  `));
441
563
  await createVueApp();
442
564
  }
565
+ } else if (action === "switch-env") {
566
+ const allStatus = await getAllEnvironmentStatus();
567
+ const { newEnv } = await inquirer.prompt([
568
+ {
569
+ type: "list",
570
+ name: "newEnv",
571
+ message: "Select environment:",
572
+ choices: [
573
+ {
574
+ name: `Production ${allStatus.production.loggedIn ? chalk.green("\u2713 Logged in") : chalk.gray("(not logged in)")}${currentEnv === "production" ? chalk.cyan(" \u2190 current") : ""}`,
575
+ value: "production"
576
+ },
577
+ {
578
+ name: `Beta ${allStatus.beta.loggedIn ? chalk.green("\u2713 Logged in") : chalk.gray("(not logged in)")}${currentEnv === "beta" ? chalk.cyan(" \u2190 current") : ""}`,
579
+ value: "beta"
580
+ },
581
+ new inquirer.Separator(),
582
+ { name: "\u2190 Back to main menu", value: "back" }
583
+ ]
584
+ }
585
+ ]);
586
+ if (newEnv === "back") {
587
+ await showMainMenu();
588
+ } else {
589
+ await setCurrentEnvironment(newEnv);
590
+ const newEnvDisplay = getEnvironmentDisplayName(newEnv);
591
+ console.log(chalk.green(`
592
+ \u2713 Switched to ${newEnvDisplay} environment
593
+ `));
594
+ const newLoggedIn = await isLoggedIn(newEnv);
595
+ if (!newLoggedIn) {
596
+ console.log(chalk.yellow(`\u26A0 You are not logged in to ${newEnvDisplay}. Run 'botim-cli login' to authenticate.
597
+ `));
598
+ }
599
+ await showMainMenu();
600
+ }
601
+ } else if (action === "status") {
602
+ const allStatus = await getAllEnvironmentStatus();
603
+ console.log(chalk.cyan.bold(`
604
+ \u{1F4CA} Status
605
+ `));
606
+ console.log(chalk.gray(`Current environment: ${chalk.white.bold(envDisplay)}
607
+ `));
608
+ const prodStatus = allStatus.production;
609
+ const prodIndicator = prodStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
610
+ const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
611
+ console.log(` ${prodIndicator} Production${prodActive}`);
612
+ if (prodStatus.loggedIn && prodStatus.partnerName) {
613
+ console.log(chalk.gray(` Partner: ${prodStatus.partnerName}`));
614
+ }
615
+ const betaStatus = allStatus.beta;
616
+ const betaIndicator = betaStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
617
+ const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
618
+ console.log(` ${betaIndicator} Beta${betaActive}`);
619
+ if (betaStatus.loggedIn && betaStatus.partnerName) {
620
+ console.log(chalk.gray(` Partner: ${betaStatus.partnerName}`));
621
+ }
622
+ console.log("");
623
+ await showMainMenu();
443
624
  } else if (action === "login") {
444
625
  await handleLogin();
445
626
  const stillLoggedIn = await isLoggedIn();
@@ -450,7 +631,7 @@ async function showMainMenu() {
450
631
  } else if (action === "qrcode") {
451
632
  await handleQRCode();
452
633
  } else if (action === "logout") {
453
- await handleLogout();
634
+ await handleLogout({});
454
635
  await showMainMenu();
455
636
  } else if (action === "examples") {
456
637
  displayExamples();