@botim/botim-cli 0.0.9 → 0.1.1

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 CHANGED
@@ -1,13 +1,5 @@
1
1
  #!/usr/bin/env node
2
- {
3
- const origEmit = process.emit;
4
- process.emit = function(name, data, ...args) {
5
- if (name === "warning" && data && data.name === "DeprecationWarning") {
6
- return false;
7
- }
8
- return origEmit.call(process, name, data, ...args);
9
- };
10
- }
2
+ {const _origEmit=process.emit;process.emit=function(n,d,...a){if(n==='warning'&&d&&d.name==='DeprecationWarning')return false;return _origEmit.call(process,n,d,...a);};}
11
3
  import { Command } from "commander";
12
4
  import { createReactApp, createVueApp, handleLogin, handleLogout, handleQRCode } from "./commands/index.js";
13
5
  import { showMenuOrRequireAuth } from "./commands/auth/index.js";
@@ -19,6 +11,7 @@ import { executeWithAuthRetry } from "./utils/auth-handler.js";
19
11
  import { getConfigPath } from "./utils/config-sync.js";
20
12
  import { switchToPartner } from "./utils/partner-switch.js";
21
13
  import { fetchPartners } from "./utils/auth-api.js";
14
+ import { checkForUpdates, getUpdateCommand, runUpdate } from "./utils/update-checker.js";
22
15
  import { select } from "@inquirer/prompts";
23
16
  import chalk from "chalk";
24
17
  import fs from "fs-extra";
@@ -52,7 +45,17 @@ async function promptSelect(options) {
52
45
  process.stdin.removeListener("keypress", onKeypress);
53
46
  }
54
47
  }
55
- const version = "0.0.9";
48
+ const version = "0.1.1";
49
+ let updateInfo = null;
50
+ function displayUpdateBanner(info) {
51
+ if (!info.updateAvailable) return;
52
+ const border = chalk.yellow("\u2500".repeat(50));
53
+ console.log("");
54
+ console.log(border);
55
+ console.log(chalk.yellow(` Update available: ${chalk.gray(info.currentVersion)} \u2192 ${chalk.green.bold(info.latestVersion)}`));
56
+ console.log(chalk.yellow(` Run ${chalk.cyan(getUpdateCommand())} to update`));
57
+ console.log(border);
58
+ }
56
59
  const program = new Command();
57
60
  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) => {
58
61
  const env = parseEnvironment(value);
@@ -136,7 +139,7 @@ program.command("status").description("Show login status for all environments").
136
139
  const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
137
140
  console.log(` ${prodIndicator} Production${prodActive}`);
138
141
  if (prodStatus.loggedIn && prodStatus.partnerName) {
139
- console.log(chalk.gray(` Partner: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
142
+ console.log(chalk.gray(` Team: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
140
143
  } else if (!prodStatus.loggedIn) {
141
144
  console.log(chalk.gray(" Not logged in"));
142
145
  }
@@ -146,7 +149,7 @@ program.command("status").description("Show login status for all environments").
146
149
  const uatActive = currentEnv === "uat" ? chalk.cyan(" (active)") : "";
147
150
  console.log(` ${uatIndicator} UAT${uatActive}`);
148
151
  if (uatStatus.loggedIn && uatStatus.partnerName) {
149
- console.log(chalk.gray(` Partner: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
152
+ console.log(chalk.gray(` Team: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
150
153
  } else if (!uatStatus.loggedIn) {
151
154
  console.log(chalk.gray(" Not logged in"));
152
155
  }
@@ -156,14 +159,14 @@ program.command("status").description("Show login status for all environments").
156
159
  const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
157
160
  console.log(` ${betaIndicator} Beta${betaActive}`);
158
161
  if (betaStatus.loggedIn && betaStatus.partnerName) {
159
- console.log(chalk.gray(` Partner: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
162
+ console.log(chalk.gray(` Team: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
160
163
  } else if (!betaStatus.loggedIn) {
161
164
  console.log(chalk.gray(" Not logged in"));
162
165
  }
163
166
  console.log("");
164
167
  console.log(chalk.gray("Tips:"));
165
168
  console.log(chalk.gray(" Switch environment: botim-cli config set env uat"));
166
- console.log(chalk.gray(" Switch partner: botim-cli switch-partner"));
169
+ console.log(chalk.gray(" Switch team: botim-cli switch-partner"));
167
170
  console.log(chalk.gray(" One-time override: botim-cli --env beta <command>"));
168
171
  console.log(chalk.gray(" Login to beta: botim-cli --env beta login\n"));
169
172
  });
@@ -388,7 +391,7 @@ program.command("debug-mp-app").description("Debug MP app (requires authenticati
388
391
  process.exit(1);
389
392
  }
390
393
  });
391
- program.command("switch-partner [partner-id]").description("Switch to a different partner without re-login").alias("sp").action(async (partnerId) => {
394
+ program.command("switch-partner [partner-id]").description("Switch to a different team without re-login").alias("sp").action(async (partnerId) => {
392
395
  try {
393
396
  const currentEnv = await getCurrentEnvironment();
394
397
  const envDisplay = getEnvironmentDisplayName(currentEnv);
@@ -401,31 +404,31 @@ program.command("switch-partner [partner-id]").description("Switch to a differen
401
404
  }
402
405
  const userToken = await getUserToken(currentEnv);
403
406
  if (!userToken) {
404
- console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable partner switching.\n"));
407
+ console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable team switching.\n"));
405
408
  console.log(chalk.gray("Run: botim-cli login\n"));
406
409
  process.exit(1);
407
410
  }
408
411
  let selectedPartnerId = partnerId;
409
412
  if (!selectedPartnerId) {
410
413
  const ora = (await import("ora")).default;
411
- const spinner = ora("Fetching partner list...").start();
414
+ const spinner = ora("Fetching team list...").start();
412
415
  let partnerList;
413
416
  try {
414
417
  partnerList = await fetchPartners({ userToken, env: currentEnv });
415
- spinner.succeed("Partner list fetched");
418
+ spinner.succeed("Team list fetched");
416
419
  } 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"));
420
+ spinner.fail("Failed to fetch team list");
421
+ console.log(chalk.yellow("\n\u26A0\uFE0F Could not fetch team list. Your session may have expired.\n"));
419
422
  console.log(chalk.gray("Run: botim-cli login\n"));
420
423
  process.exit(1);
421
424
  }
422
425
  if (!partnerList || partnerList.length === 0) {
423
- console.log(chalk.yellow("\n\u26A0\uFE0F No partners found for your account.\n"));
426
+ console.log(chalk.yellow("\n\u26A0\uFE0F No teams found for your account.\n"));
424
427
  process.exit(1);
425
428
  }
426
429
  const currentPartnerId2 = await getPartnerId(currentEnv);
427
430
  const selected = await promptSelect({
428
- message: "Select a partner:",
431
+ message: "Select a team:",
429
432
  choices: partnerList.map((p) => ({
430
433
  name: `${p.partnerInfo?.company_name || p.partner_id} (${p.partner_id})${p.partner_id === currentPartnerId2 ? chalk.cyan(" \u2190 current") : ""}`,
431
434
  value: p.partner_id
@@ -443,18 +446,18 @@ program.command("switch-partner [partner-id]").description("Switch to a differen
443
446
  if (selectedPartnerId === currentPartnerId) {
444
447
  const currentPartnerName = await getPartnerName(currentEnv);
445
448
  console.log(chalk.gray(`
446
- Already using partner: ${currentPartnerName || selectedPartnerId}
449
+ Already using team: ${currentPartnerName || selectedPartnerId}
447
450
  `));
448
451
  return;
449
452
  }
450
453
  const result = await switchToPartner(selectedPartnerId, currentEnv);
451
454
  if (result.success) {
452
455
  console.log(chalk.green(`
453
- \u2713 Switched to partner: ${result.partnerName}
456
+ \u2713 Switched to team: ${result.partnerName}
454
457
  `));
455
458
  } else if (result.error === "partner-not-found") {
456
459
  console.log(chalk.red(`
457
- \u274C Partner ${selectedPartnerId} not found in your partner list.
460
+ \u274C Team ${selectedPartnerId} not found in your team list.
458
461
  `));
459
462
  process.exit(1);
460
463
  } else if (result.error === "no-user-token" || result.error === "user-token-expired") {
@@ -462,12 +465,12 @@ Already using partner: ${currentPartnerName || selectedPartnerId}
462
465
  console.log(chalk.gray("Run: botim-cli login\n"));
463
466
  process.exit(1);
464
467
  } else {
465
- console.log(chalk.red("\n\u274C Failed to switch partner. Please try logging in again.\n"));
468
+ console.log(chalk.red("\n\u274C Failed to switch team. Please try logging in again.\n"));
466
469
  process.exit(1);
467
470
  }
468
471
  } catch (error) {
469
472
  logger.error("switch-partner command failed", error);
470
- displayErrorSync(error, "Switch partner failed");
473
+ displayErrorSync(error, "Switch team failed");
471
474
  process.exit(1);
472
475
  }
473
476
  });
@@ -678,6 +681,32 @@ program.command("clear-template-cache").description("Clear cached templates to f
678
681
  process.exit(1);
679
682
  }
680
683
  });
684
+ program.command("update").description("Update Botim CLI to the latest version").action(async () => {
685
+ console.log(chalk.cyan.bold(`
686
+ \u2B06\uFE0F Botim CLI v${version} - Update
687
+ `));
688
+ const info = updateInfo ?? await checkForUpdates();
689
+ if (!info.updateAvailable) {
690
+ console.log(chalk.green(`\u2713 You are already on the latest version (v${info.currentVersion})
691
+ `));
692
+ return;
693
+ }
694
+ console.log(chalk.yellow(`Update available: ${chalk.gray(info.currentVersion)} \u2192 ${chalk.green.bold(info.latestVersion)}
695
+ `));
696
+ console.log(chalk.gray(`Running: ${getUpdateCommand()}
697
+ `));
698
+ const success = runUpdate();
699
+ if (success) {
700
+ console.log(chalk.green(`
701
+ \u2713 Successfully updated to v${info.latestVersion}!
702
+ `));
703
+ } else {
704
+ console.log(chalk.red("\n\u274C Update failed. Try running manually:\n"));
705
+ console.log(chalk.cyan(` ${getUpdateCommand()}
706
+ `));
707
+ process.exit(1);
708
+ }
709
+ });
681
710
  program.command("logs").description("Show log file location or view recent logs").option("-t, --tail <lines>", "Show last N lines of log file", "50").action(async (options) => {
682
711
  const logPath = logger.getLogFilePath();
683
712
  const tailLines = parseInt(options.tail) || 50;
@@ -718,9 +747,13 @@ async function showMainMenu() {
718
747
  console.log(chalk.cyan.bold(`\u2551 v${version.padEnd(32)}\u2551`));
719
748
  console.log(chalk.cyan.bold(`\u2551 Environment: ${envColor(envDisplay.padEnd(27))}\u2551`));
720
749
  if (currentPartnerName) {
721
- console.log(chalk.cyan.bold(`\u2551 Partner: ${chalk.white(currentPartnerName.padEnd(31))}\u2551`));
750
+ console.log(chalk.cyan.bold(`\u2551 Team: ${chalk.white(currentPartnerName.padEnd(34))}\u2551`));
751
+ }
752
+ 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"));
753
+ if (updateInfo?.updateAvailable) {
754
+ displayUpdateBanner(updateInfo);
722
755
  }
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"));
756
+ console.log("");
724
757
  const loggedIn = await isLoggedIn();
725
758
  let authenticatedChoices = [];
726
759
  if (loggedIn) {
@@ -729,12 +762,15 @@ async function showMainMenu() {
729
762
  const currentDir = process.cwd();
730
763
  const configFilePath = getConfigPath(currentDir, currentEnv);
731
764
  const hasConfigFile = await fs.pathExists(configFilePath);
765
+ const { findAvailableConfigs } = await import("./utils/config-sync.js");
766
+ const availableConfigs = await findAvailableConfigs(currentDir);
767
+ const hasAnyConfigFile = availableConfigs.length > 0;
732
768
  const filteredCommands = commands.filter((cmd) => {
733
769
  if (cmd.hideFromMenu) {
734
770
  return false;
735
771
  }
736
772
  if (cmd.name === "deploy-mp-app" || cmd.name === "debug-mp-app") {
737
- return hasConfigFile;
773
+ return hasAnyConfigFile;
738
774
  }
739
775
  if (cmd.name === "create-mp-app" || cmd.name === "register-mp-app") {
740
776
  return !hasConfigFile;
@@ -746,21 +782,24 @@ async function showMainMenu() {
746
782
  value: `auth:${cmd.name}`
747
783
  }));
748
784
  }
785
+ const updateChoice = updateInfo?.updateAvailable ? [{ name: `\u2B06\uFE0F Update available (${chalk.gray(updateInfo.currentVersion)} \u2192 ${chalk.green(updateInfo.latestVersion)})`, value: "update" }] : [];
749
786
  const unauthenticatedChoices = [
750
- { name: "\u{1F4F1} Create a Mini-Program (Local)", value: "mini-program" },
787
+ { name: "\u{1F4F1} Create a Mini-Program Template (Local)", value: "mini-program" },
751
788
  { name: "\u{1F510} Login", value: "login" },
752
789
  { name: "\u{1F504} Switch Environment", value: "switch-env" },
753
790
  { name: "\u{1F4CA} View Status", value: "status" },
791
+ ...updateChoice,
754
792
  { name: "\u{1F4DA} View examples", value: "examples" },
755
793
  { name: "\u2753 Show help", value: "help" },
756
794
  { name: "\u{1F6AA} Exit", value: "exit" }
757
795
  ];
758
796
  authenticatedChoices = [
759
797
  ...authenticatedChoices,
760
- { name: "\u{1F4F1} Create a Mini-Program (Local)", value: "mini-program" },
798
+ { name: "\u{1F4F1} Create a Mini-Program Template (Local)", value: "mini-program" },
761
799
  { name: "\u{1F504} Switch Environment", value: "switch-env" },
762
- { name: "\u{1F500} Switch Partner", value: "switch-partner" },
800
+ { name: "\u{1F465} Switch Team", value: "switch-partner" },
763
801
  { name: "\u{1F4CA} View Status", value: "status" },
802
+ ...updateChoice,
764
803
  { name: "\u{1F6AA} Logout", value: "logout" },
765
804
  { name: "\u{1F4DA} View examples", value: "examples" },
766
805
  { name: "\u2753 Show help", value: "help" },
@@ -848,30 +887,30 @@ async function showMainMenu() {
848
887
  } else if (action === "switch-partner") {
849
888
  const userToken = await getUserToken(currentEnv);
850
889
  if (!userToken) {
851
- console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable partner switching.\n"));
890
+ console.log(chalk.yellow("\n\u26A0\uFE0F No user token available. Please login again to enable team switching.\n"));
852
891
  await showMainMenu();
853
892
  return;
854
893
  }
855
894
  const ora = (await import("ora")).default;
856
- const spinner = ora("Fetching partner list...").start();
895
+ const spinner = ora("Fetching team list...").start();
857
896
  let partnerList;
858
897
  try {
859
898
  partnerList = await fetchPartners({ userToken, env: currentEnv });
860
- spinner.succeed("Partner list fetched");
899
+ spinner.succeed("Team list fetched");
861
900
  } 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"));
901
+ spinner.fail("Failed to fetch team list");
902
+ console.log(chalk.yellow("\n\u26A0\uFE0F Could not fetch team list. Your session may have expired.\n"));
864
903
  await showMainMenu();
865
904
  return;
866
905
  }
867
906
  if (!partnerList || partnerList.length === 0) {
868
- console.log(chalk.yellow("\n\u26A0\uFE0F No partners found for your account.\n"));
907
+ console.log(chalk.yellow("\n\u26A0\uFE0F No teams found for your account.\n"));
869
908
  await showMainMenu();
870
909
  return;
871
910
  }
872
911
  const currentPartnerId = await getPartnerId(currentEnv);
873
912
  const selectedPartnerId = await promptSelect({
874
- message: "Select a partner:",
913
+ message: "Select a team:",
875
914
  choices: partnerList.map((p) => ({
876
915
  name: `${p.partnerInfo?.company_name || p.partner_id} (${p.partner_id})${p.partner_id === currentPartnerId ? chalk.cyan(" \u2190 current") : ""}`,
877
916
  value: p.partner_id
@@ -880,18 +919,18 @@ async function showMainMenu() {
880
919
  if (selectedPartnerId === null) {
881
920
  await showMainMenu();
882
921
  } else if (selectedPartnerId === currentPartnerId) {
883
- console.log(chalk.gray("\nAlready using this partner.\n"));
922
+ console.log(chalk.gray("\nAlready using this team.\n"));
884
923
  await showMainMenu();
885
924
  } else {
886
925
  const result = await switchToPartner(selectedPartnerId, currentEnv);
887
926
  if (result.success) {
888
927
  console.log(chalk.green(`
889
- \u2713 Switched to partner: ${result.partnerName}
928
+ \u2713 Switched to team: ${result.partnerName}
890
929
  `));
891
930
  } else if (result.error === "no-user-token" || result.error === "user-token-expired") {
892
931
  console.log(chalk.yellow("\n\u26A0\uFE0F Your session has expired. Please login again.\n"));
893
932
  } else {
894
- console.log(chalk.red("\n\u274C Failed to switch partner.\n"));
933
+ console.log(chalk.red("\n\u274C Failed to switch team.\n"));
895
934
  }
896
935
  await showMainMenu();
897
936
  }
@@ -907,21 +946,21 @@ async function showMainMenu() {
907
946
  const prodActive = currentEnv === "production" ? chalk.cyan(" (active)") : "";
908
947
  console.log(` ${prodIndicator} Production${prodActive}`);
909
948
  if (prodStatus.loggedIn && prodStatus.partnerName) {
910
- console.log(chalk.gray(` Partner: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
949
+ console.log(chalk.gray(` Team: ${prodStatus.partnerName}${prodStatus.partnerId ? ` (${prodStatus.partnerId})` : ""}`));
911
950
  }
912
951
  const uatStatus = allStatus.uat;
913
952
  const uatIndicator = uatStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
914
953
  const uatActive = currentEnv === "uat" ? chalk.cyan(" (active)") : "";
915
954
  console.log(` ${uatIndicator} UAT${uatActive}`);
916
955
  if (uatStatus.loggedIn && uatStatus.partnerName) {
917
- console.log(chalk.gray(` Partner: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
956
+ console.log(chalk.gray(` Team: ${uatStatus.partnerName}${uatStatus.partnerId ? ` (${uatStatus.partnerId})` : ""}`));
918
957
  }
919
958
  const betaStatus = allStatus.beta;
920
959
  const betaIndicator = betaStatus.loggedIn ? chalk.green("\u2713") : chalk.red("\u2717");
921
960
  const betaActive = currentEnv === "beta" ? chalk.cyan(" (active)") : "";
922
961
  console.log(` ${betaIndicator} Beta${betaActive}`);
923
962
  if (betaStatus.loggedIn && betaStatus.partnerName) {
924
- console.log(chalk.gray(` Partner: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
963
+ console.log(chalk.gray(` Team: ${betaStatus.partnerName}${betaStatus.partnerId ? ` (${betaStatus.partnerId})` : ""}`));
925
964
  }
926
965
  console.log("");
927
966
  await showMainMenu();
@@ -937,6 +976,23 @@ async function showMainMenu() {
937
976
  } else if (action === "logout") {
938
977
  await handleLogout({});
939
978
  await showMainMenu();
979
+ } else if (action === "update") {
980
+ console.log(chalk.cyan.bold(`
981
+ \u2B06\uFE0F Updating Botim CLI to v${updateInfo?.latestVersion}...
982
+ `));
983
+ const success = runUpdate();
984
+ if (success) {
985
+ console.log(chalk.green(`
986
+ \u2713 Successfully updated to v${updateInfo?.latestVersion}!
987
+ `));
988
+ console.log(chalk.gray("Please restart the CLI to use the new version.\n"));
989
+ process.exit(0);
990
+ } else {
991
+ console.log(chalk.red("\n\u274C Update failed. Try running manually:\n"));
992
+ console.log(chalk.cyan(` ${getUpdateCommand()}
993
+ `));
994
+ await showMainMenu();
995
+ }
940
996
  } else if (action === "examples") {
941
997
  displayExamples();
942
998
  await showMainMenu();
@@ -953,8 +1009,15 @@ async function showMainMenu() {
953
1009
  process.exit(1);
954
1010
  }
955
1011
  }
956
- if (!process.argv.slice(2).length) {
957
- showMainMenu();
958
- } else {
959
- program.parse(process.argv);
960
- }
1012
+ (async () => {
1013
+ updateInfo = await checkForUpdates();
1014
+ if (!process.argv.slice(2).length) {
1015
+ await showMainMenu();
1016
+ } else {
1017
+ if (updateInfo.updateAvailable) {
1018
+ displayUpdateBanner(updateInfo);
1019
+ console.log("");
1020
+ }
1021
+ program.parse(process.argv);
1022
+ }
1023
+ })();