@jvittechs/jai1-cli 0.1.102 → 0.1.103

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command61 } from "commander";
4
+ import { Command as Command60 } from "commander";
5
5
 
6
6
  // src/errors/index.ts
7
7
  var Jai1Error = class extends Error {
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
33
33
  // package.json
34
34
  var package_default = {
35
35
  name: "@jvittechs/jai1-cli",
36
- version: "0.1.102",
36
+ version: "0.1.103",
37
37
  description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
38
38
  type: "module",
39
39
  bin: {
@@ -82,11 +82,16 @@ var package_default = {
82
82
  "@inquirer/prompts": "^8.0.2",
83
83
  "adm-zip": "^0.5.16",
84
84
  bcryptjs: "^2.4.3",
85
+ boxen: "^8.0.1",
86
+ chalk: "^5.6.2",
85
87
  "cli-progress": "^3.12.0",
88
+ "cli-table3": "^0.6.5",
86
89
  clipboardy: "^4.0.0",
87
90
  commander: "^12.1.0",
88
91
  cronstrue: "^2.50.0",
89
92
  execa: "^9.6.1",
93
+ figlet: "^1.9.4",
94
+ "gradient-string": "^3.0.0",
90
95
  "gray-matter": "^4.0.3",
91
96
  ignore: "^7.0.5",
92
97
  ink: "^5.0.1",
@@ -107,6 +112,8 @@ var package_default = {
107
112
  },
108
113
  devDependencies: {
109
114
  "@changesets/cli": "^2.27.7",
115
+ "@types/figlet": "^1.7.0",
116
+ "@types/gradient-string": "^1.1.6",
110
117
  "@types/node": "^24.10.1",
111
118
  "@types/react": "^18.3.12",
112
119
  "@typescript-eslint/eslint-plugin": "^8.6.0",
@@ -261,6 +268,8 @@ function showUpdateNotification(latestVersion) {
261
268
 
262
269
  // src/commands/framework/auth.ts
263
270
  import { Command } from "commander";
271
+ import chalk from "chalk";
272
+ import boxen from "boxen";
264
273
 
265
274
  // src/services/tracking.service.ts
266
275
  import { platform, release, arch, hostname, homedir as homedir2 } from "os";
@@ -360,7 +369,7 @@ async function trackActionSync(action, detail) {
360
369
 
361
370
  // src/commands/framework/auth.ts
362
371
  function createAuthCommand() {
363
- const cmd = new Command("auth").description("Authenticate and configure jai1-client").option("--api-url <url>", "Jai1 Store API URL").option("--access-key <key>", "Your access key").action(async (options) => {
372
+ const cmd = new Command("auth").description("X\xE1c th\u1EF1c v\xE0 c\u1EA5u h\xECnh jai1-client").option("--api-url <url>", "Jai1 Store API URL").option("--access-key <key>", "Your access key").action(async (options) => {
364
373
  await handleAuth(options);
365
374
  });
366
375
  return cmd;
@@ -372,21 +381,31 @@ async function handleAuth(options) {
372
381
  let isInteractive = false;
373
382
  const existingConfig = await configService.load();
374
383
  if (existingConfig) {
375
- console.log("\u26A0\uFE0F Configuration already exists at:", configService.getConfigPath());
376
- console.log(" Run this command again with new values to overwrite.");
377
- console.log("");
384
+ console.log(
385
+ chalk.yellow("\u26A0\uFE0F C\u1EA5u h\xECnh \u0111\xE3 t\u1ED3n t\u1EA1i t\u1EA1i:"),
386
+ chalk.dim(configService.getConfigPath())
387
+ );
388
+ console.log(
389
+ chalk.dim(" Ch\u1EA1y l\u1EA1i l\u1EC7nh n\xE0y v\u1EDBi gi\xE1 tr\u1ECB m\u1EDBi \u0111\u1EC3 ghi \u0111\xE8.\n")
390
+ );
378
391
  }
379
392
  if (options.apiUrl && options.accessKey) {
380
393
  apiUrl = options.apiUrl;
381
394
  accessKey = options.accessKey;
382
395
  } else if (options.apiUrl || options.accessKey) {
383
396
  throw new ValidationError(
384
- "Both --api-url and --access-key are required in non-interactive mode"
397
+ "C\u1EA7n c\u1EA3 --api-url v\xE0 --access-key trong non-interactive mode"
385
398
  );
386
399
  } else {
387
400
  isInteractive = true;
388
- console.log("\u{1F680} Jai1 Client Setup");
389
- console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
401
+ console.log(
402
+ boxen(chalk.cyan.bold("\u{1F680} Jai1 Client Setup"), {
403
+ padding: { left: 1, right: 1, top: 0, bottom: 0 },
404
+ borderStyle: "round",
405
+ borderColor: "cyan"
406
+ })
407
+ );
408
+ console.log();
390
409
  const readline = await import("readline");
391
410
  const rl = readline.createInterface({
392
411
  input: process.stdin,
@@ -399,23 +418,25 @@ async function handleAuth(options) {
399
418
  });
400
419
  });
401
420
  };
402
- apiUrl = await question("API URL (https://store.jai1.io): ");
421
+ apiUrl = await question(
422
+ chalk.dim("API URL") + chalk.gray(" (https://store.jai1.io): ")
423
+ );
403
424
  if (!apiUrl) {
404
425
  apiUrl = "https://store.jai1.io";
405
426
  }
406
- accessKey = await question("Access Key: ");
427
+ accessKey = await question(chalk.dim("Access Key: "));
407
428
  if (!accessKey) {
408
429
  rl.close();
409
- throw new ValidationError("Access key is required");
430
+ throw new ValidationError("Access key l\xE0 b\u1EAFt bu\u1ED9c");
410
431
  }
411
432
  rl.close();
412
433
  }
413
434
  try {
414
435
  new URL(apiUrl);
415
436
  } catch {
416
- throw new ValidationError("Invalid API URL format");
437
+ throw new ValidationError("\u0110\u1ECBnh d\u1EA1ng API URL kh\xF4ng h\u1EE3p l\u1EC7");
417
438
  }
418
- console.log("\nValidating access key...");
439
+ console.log(chalk.dim("\n\u0110ang x\xE1c th\u1EF1c access key..."));
419
440
  await configService.save({
420
441
  apiUrl,
421
442
  accessKey,
@@ -427,13 +448,22 @@ async function handleAuth(options) {
427
448
  mode: isInteractive ? "interactive" : "non-interactive",
428
449
  isReconfig: !!existingConfig
429
450
  });
430
- console.log("\u2713 Configuration saved to", configService.getConfigPath());
431
- console.log("");
432
- console.log("You're all set! Run 'jai1 check' to check for updates.");
451
+ console.log(
452
+ chalk.green("\u2713 C\u1EA5u h\xECnh \u0111\xE3 l\u01B0u t\u1EA1i"),
453
+ chalk.dim(configService.getConfigPath())
454
+ );
455
+ console.log();
456
+ console.log(
457
+ chalk.dim("B\u1EA1n \u0111\xE3 s\u1EB5n s\xE0ng! Ch\u1EA1y"),
458
+ chalk.cyan("'jai1 check'"),
459
+ chalk.dim("\u0111\u1EC3 ki\u1EC3m tra c\u1EADp nh\u1EADt.")
460
+ );
433
461
  }
434
462
 
435
463
  // src/commands/status.ts
436
464
  import { Command as Command2 } from "commander";
465
+ import chalk2 from "chalk";
466
+ import boxen2 from "boxen";
437
467
 
438
468
  // src/services/components.service.ts
439
469
  import { promises as fs2 } from "fs";
@@ -696,7 +726,7 @@ import { promises as fs3 } from "fs";
696
726
  import { join as join3 } from "path";
697
727
  import { homedir as homedir4 } from "os";
698
728
  function createStatusCommand() {
699
- const cmd = new Command2("status").description("Show configuration and installed components status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
729
+ const cmd = new Command2("status").description("Hi\u1EC3n th\u1ECB tr\u1EA1ng th\xE1i c\u1EA5u h\xECnh v\xE0 components").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
700
730
  await handleStatus(options);
701
731
  });
702
732
  return cmd;
@@ -726,28 +756,38 @@ async function handleStatus(options) {
726
756
  console.log(JSON.stringify(info, null, 2));
727
757
  return;
728
758
  }
729
- console.log("\u{1F4CA} Jai1 Client Status");
730
- console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
731
- console.log("\u{1F527} Configuration");
732
- console.log(` Config: ${info.configPath}`);
733
- console.log(` API URL: ${info.apiUrl}`);
734
- console.log(` Access Key: ${info.accessKey}`);
735
- console.log();
736
- console.log("\u{1F4E6} Framework");
737
- console.log(` Version: ${info.version}`);
738
- console.log(` Updated: ${info.lastUpdated}`);
739
- console.log(` Location: ${info.frameworkPath}`);
740
- console.log();
741
- console.log("\u{1F4C1} Project");
742
- console.log(` .jai1/ exists: ${info.projectStatus.exists ? "\u2713" : "\u2717"}`);
759
+ console.log(
760
+ boxen2(chalk2.cyan.bold("\u{1F4CA} Jai1 Client Status"), {
761
+ padding: { left: 1, right: 1, top: 0, bottom: 0 },
762
+ borderStyle: "round",
763
+ borderColor: "cyan"
764
+ })
765
+ );
766
+ console.log(chalk2.bold("\n\u{1F527} C\u1EA5u h\xECnh"));
767
+ console.log(` ${chalk2.dim("Config:")} ${info.configPath}`);
768
+ console.log(` ${chalk2.dim("API URL:")} ${info.apiUrl}`);
769
+ console.log(` ${chalk2.dim("Access Key:")} ${chalk2.yellow(info.accessKey)}`);
770
+ console.log(chalk2.bold("\n\u{1F4E6} Framework"));
771
+ console.log(` ${chalk2.dim("Version:")} ${chalk2.green(info.version)}`);
772
+ console.log(` ${chalk2.dim("Updated:")} ${info.lastUpdated}`);
773
+ console.log(` ${chalk2.dim("Location:")} ${info.frameworkPath}`);
774
+ console.log(chalk2.bold("\n\u{1F4C1} Project"));
775
+ const existsIcon = info.projectStatus.exists ? chalk2.green("\u2713") : chalk2.red("\u2717");
776
+ console.log(` ${chalk2.dim(".jai1/ exists:")} ${existsIcon}`);
743
777
  if (info.projectStatus.exists) {
744
- console.log(` Components: ${componentCount} installed`);
778
+ console.log(
779
+ ` ${chalk2.dim("Components:")} ${chalk2.cyan(componentCount)} installed`
780
+ );
745
781
  }
746
782
  console.log();
747
783
  if (!info.projectStatus.exists) {
748
- console.log('\u{1F4A1} Run "jai1 apply" to install components for this project.');
784
+ console.log(
785
+ chalk2.dim('\u{1F4A1} Ch\u1EA1y "jai1 apply" \u0111\u1EC3 c\xE0i components cho project n\xE0y.')
786
+ );
749
787
  } else if (componentCount > 0) {
750
- console.log('\u{1F4A1} Run "jai1 check" to check for component updates.');
788
+ console.log(
789
+ chalk2.dim('\u{1F4A1} Ch\u1EA1y "jai1 check" \u0111\u1EC3 ki\u1EC3m tra c\u1EADp nh\u1EADt components.')
790
+ );
751
791
  }
752
792
  }
753
793
  function maskKey(key) {
@@ -1663,6 +1703,7 @@ async function nonInteractiveApply(config, items, options) {
1663
1703
  // src/commands/update.ts
1664
1704
  import { Command as Command4 } from "commander";
1665
1705
  import { confirm } from "@inquirer/prompts";
1706
+ import chalk3 from "chalk";
1666
1707
  function createUpdateCommand() {
1667
1708
  return new Command4("update").description("Update installed components to latest versions").option("--force", "Force update even if files are modified locally").action(async (options) => {
1668
1709
  await handleUpdate(options);
@@ -1678,19 +1719,21 @@ async function handleUpdate(options) {
1678
1719
  const installed = await componentsService.getInstalled();
1679
1720
  const filepaths = Object.keys(installed);
1680
1721
  if (filepaths.length === 0) {
1681
- console.log('No components installed. Run "jai1 apply" to add components.');
1722
+ console.log(chalk3.yellow("\u{1F4E6} Ch\u01B0a c\xF3 components n\xE0o \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t."));
1723
+ console.log(chalk3.dim(' Ch\u1EA1y "jai1 apply" \u0111\u1EC3 th\xEAm components.'));
1682
1724
  return;
1683
1725
  }
1684
- console.log("\u{1F50D} Checking for updates...");
1726
+ console.log(chalk3.cyan("\u{1F50D} \u0110ang ki\u1EC3m tra c\u1EADp nh\u1EADt..."));
1685
1727
  try {
1686
1728
  const checksums = await componentsService.getChecksums(config, filepaths);
1687
1729
  const updates = [];
1688
1730
  const upToDate = [];
1731
+ const deprecated = [];
1689
1732
  for (const fp of filepaths) {
1690
1733
  const current = installed[fp];
1691
1734
  const latest = checksums[fp];
1692
1735
  if (!latest) {
1693
- console.log(`\u26A0\uFE0F ${fp}: Component not found on server (deprecated?)`);
1736
+ deprecated.push(fp);
1694
1737
  continue;
1695
1738
  }
1696
1739
  if (current.checksum !== latest.checksum) {
@@ -1699,64 +1742,84 @@ async function handleUpdate(options) {
1699
1742
  upToDate.push(fp);
1700
1743
  }
1701
1744
  }
1745
+ if (deprecated.length > 0) {
1746
+ console.log(chalk3.yellow("\n\u26A0\uFE0F Components kh\xF4ng c\xF2n tr\xEAn server (deprecated):"));
1747
+ for (const fp of deprecated) {
1748
+ console.log(chalk3.dim(` - ${fp}`));
1749
+ }
1750
+ }
1702
1751
  if (updates.length === 0) {
1703
- console.log("\u2705 All components are up to date.");
1752
+ console.log(chalk3.green("\n\u2705 T\u1EA5t c\u1EA3 components \u0111\xE3 l\xE0 phi\xEAn b\u1EA3n m\u1EDBi nh\u1EA5t."));
1753
+ if (upToDate.length > 0) {
1754
+ console.log(chalk3.dim(` ${upToDate.length} component(s) \u0111\xE3 c\u1EADp nh\u1EADt.`));
1755
+ }
1704
1756
  return;
1705
1757
  }
1706
- console.log(`
1707
- \u{1F4E6} Found ${updates.length} updates:`);
1758
+ console.log(chalk3.cyan(`
1759
+ \u{1F4E6} T\xECm th\u1EA5y ${chalk3.bold(updates.length)} c\u1EADp nh\u1EADt:`));
1708
1760
  for (const fp of updates) {
1709
1761
  const current = installed[fp];
1710
1762
  const latest = checksums[fp];
1711
- console.log(` - ${fp} (v${current.version} \u2192 v${latest.version})`);
1763
+ console.log(
1764
+ ` ${chalk3.white(fp)} ` + chalk3.dim(`v${current.version}`) + chalk3.cyan(" \u2192 ") + chalk3.green(`v${latest.version}`)
1765
+ );
1712
1766
  }
1713
1767
  console.log();
1714
1768
  if (!options.force) {
1715
- const shouldUpdate = await confirm({ message: "Update now?", default: true });
1716
- if (!shouldUpdate) return;
1769
+ const shouldUpdate = await confirm({ message: "C\u1EADp nh\u1EADt ngay?", default: true });
1770
+ if (!shouldUpdate) {
1771
+ console.log(chalk3.dim("\u0110\xE3 h\u1EE7y c\u1EADp nh\u1EADt."));
1772
+ return;
1773
+ }
1717
1774
  }
1718
1775
  const targetDir = process.cwd() + "/.jai1";
1719
1776
  let updatedCount = 0;
1720
1777
  const backupPaths = [];
1778
+ console.log();
1721
1779
  for (const fp of updates) {
1722
1780
  try {
1723
- console.log(`\u{1F4E5} Updating ${fp}...`);
1781
+ process.stdout.write(chalk3.cyan(`\u{1F4E5} \u0110ang c\u1EADp nh\u1EADt ${chalk3.white(fp)}...`));
1724
1782
  const backupPath = await componentsService.backupFile(fp, targetDir);
1725
1783
  if (backupPath) {
1726
1784
  backupPaths.push(backupPath);
1727
- const displayPath = backupPath.split(".jai1_backup/")[1];
1728
- console.log(` Backed up: .../${displayPath}`);
1729
1785
  }
1730
1786
  await componentsService.install(config, fp, targetDir);
1731
- console.log(`\u2705 Updated`);
1787
+ console.log(chalk3.green(" \u2713"));
1732
1788
  updatedCount++;
1733
1789
  } catch (error) {
1734
- console.log(`\u274C Failed to update ${fp}: ${error instanceof Error ? error.message : "Unknown error"}`);
1790
+ console.log(chalk3.red(" \u2717"));
1791
+ console.log(chalk3.red(` L\u1ED7i: ${error instanceof Error ? error.message : "Unknown error"}`));
1735
1792
  }
1736
1793
  }
1737
- console.log(`
1738
- \u2705 Update complete: ${updatedCount}/${updates.length} updated.`);
1794
+ console.log();
1795
+ if (updatedCount === updates.length) {
1796
+ console.log(chalk3.green(`\u2705 Ho\xE0n t\u1EA5t: ${updatedCount}/${updates.length} \u0111\xE3 c\u1EADp nh\u1EADt.`));
1797
+ } else {
1798
+ console.log(chalk3.yellow(`\u26A0\uFE0F Ho\xE0n t\u1EA5t: ${updatedCount}/${updates.length} \u0111\xE3 c\u1EADp nh\u1EADt.`));
1799
+ }
1739
1800
  if (backupPaths.length > 0) {
1740
- console.log(`
1741
- \u{1F4C1} Backups created in .jai1_backup/`);
1742
- const cleanBackups = await confirm({ message: "Clear these backups?", default: false });
1801
+ console.log(chalk3.dim(`
1802
+ \u{1F4C1} \u0110\xE3 t\u1EA1o backup t\u1EA1i .jai1_backup/`));
1803
+ const cleanBackups = await confirm({ message: "X\xF3a c\xE1c backup n\xE0y?", default: false });
1743
1804
  if (cleanBackups) {
1744
1805
  await componentsService.clearBackups(process.cwd());
1745
- console.log("\u{1F5D1}\uFE0F Backups cleared.");
1806
+ console.log(chalk3.green("\u{1F5D1}\uFE0F \u0110\xE3 x\xF3a backups."));
1746
1807
  } else {
1747
- console.log('\u{1F4A1} Run "jai1 clean" to remove them later.');
1808
+ console.log(chalk3.dim('\u{1F4A1} Ch\u1EA1y "jai1 clean" \u0111\u1EC3 x\xF3a sau.'));
1748
1809
  }
1749
1810
  }
1750
1811
  trackAction("components_update", { count: updatedCount });
1751
1812
  } catch (error) {
1752
- throw new Error(`Update check failed: ${error instanceof Error ? error.message : "Unknown error"}`);
1813
+ throw new Error(`Ki\u1EC3m tra c\u1EADp nh\u1EADt th\u1EA5t b\u1EA1i: ${error instanceof Error ? error.message : "Unknown error"}`);
1753
1814
  }
1754
1815
  }
1755
1816
 
1756
1817
  // src/commands/framework/check.ts
1757
1818
  import { Command as Command5 } from "commander";
1819
+ import chalk4 from "chalk";
1820
+ import Table from "cli-table3";
1758
1821
  function createCheckCommand() {
1759
- const cmd = new Command5("check").description("Check for framework updates").option("--json", "Output as JSON").action(async (options) => {
1822
+ const cmd = new Command5("check").description("Ki\u1EC3m tra c\u1EADp nh\u1EADt framework").option("--json", "Output as JSON").action(async (options) => {
1760
1823
  await handleCheck(options);
1761
1824
  });
1762
1825
  return cmd;
@@ -1771,10 +1834,12 @@ async function handleCheck(options) {
1771
1834
  const installed = await componentsService.getInstalled();
1772
1835
  const filepaths = Object.keys(installed);
1773
1836
  if (filepaths.length === 0) {
1774
- console.log('No components installed. Run "jai1 apply" to get started.');
1837
+ console.log(
1838
+ chalk4.yellow('Ch\u01B0a c\xF3 components n\xE0o. Ch\u1EA1y "jai1 apply" \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u.')
1839
+ );
1775
1840
  return;
1776
1841
  }
1777
- console.log("Checking for updates...\n");
1842
+ console.log(chalk4.dim("\u0110ang ki\u1EC3m tra c\u1EADp nh\u1EADt...\n"));
1778
1843
  try {
1779
1844
  const checksums = await componentsService.getChecksums(config, filepaths);
1780
1845
  const updates = [];
@@ -1791,31 +1856,82 @@ async function handleCheck(options) {
1791
1856
  upToDate.push(fp);
1792
1857
  }
1793
1858
  }
1794
- console.log(`\u{1F4CC} Components status:`);
1795
- for (const fp of updates) {
1796
- const current = installed[fp];
1797
- const latest = checksums[fp];
1798
- console.log(` ${fp} v${current.version} \u2192 v${latest.version} \u26A0\uFE0F UPDATE`);
1859
+ if (options.json) {
1860
+ console.log(
1861
+ JSON.stringify(
1862
+ {
1863
+ updates: updates.map((fp) => ({
1864
+ path: fp,
1865
+ currentVersion: installed[fp].version,
1866
+ latestVersion: checksums[fp].version
1867
+ })),
1868
+ upToDate: upToDate.length,
1869
+ total: filepaths.length
1870
+ },
1871
+ null,
1872
+ 2
1873
+ )
1874
+ );
1875
+ return;
1876
+ }
1877
+ console.log(chalk4.bold("\u{1F4CC} Tr\u1EA1ng th\xE1i Components:\n"));
1878
+ if (updates.length > 0) {
1879
+ const table = new Table({
1880
+ head: [
1881
+ chalk4.bold("Component"),
1882
+ chalk4.bold("Hi\u1EC7n t\u1EA1i"),
1883
+ chalk4.bold("M\u1EDBi nh\u1EA5t"),
1884
+ chalk4.bold("Tr\u1EA1ng th\xE1i")
1885
+ ],
1886
+ style: {
1887
+ head: ["cyan"],
1888
+ border: ["gray"]
1889
+ }
1890
+ });
1891
+ for (const fp of updates) {
1892
+ const current = installed[fp];
1893
+ const latest = checksums[fp];
1894
+ table.push([
1895
+ fp,
1896
+ `v${current.version}`,
1897
+ chalk4.green(`v${latest.version}`),
1898
+ chalk4.yellow("\u26A0\uFE0F C\u1EA6N C\u1EACP NH\u1EACT")
1899
+ ]);
1900
+ }
1901
+ console.log(table.toString());
1799
1902
  }
1903
+ console.log();
1800
1904
  if (updates.length === 0 && upToDate.length > 0) {
1801
- console.log(` \u2713 All ${upToDate.length} components up to date.`);
1905
+ console.log(
1906
+ chalk4.green(`\u2713 T\u1EA5t c\u1EA3 ${upToDate.length} components \u0111\xE3 c\u1EADp nh\u1EADt.`)
1907
+ );
1802
1908
  } else if (upToDate.length > 0) {
1803
- console.log(` \u2713 ${upToDate.length} components up to date.`);
1909
+ console.log(chalk4.dim(`\u2713 ${upToDate.length} components \u0111\xE3 c\u1EADp nh\u1EADt.`));
1804
1910
  }
1805
- console.log();
1806
1911
  if (updates.length > 0) {
1807
- console.log(`Status: ${updates.length} component(s) update available!`);
1808
- console.log(`Run 'jai1 update' to update.`);
1912
+ console.log(
1913
+ chalk4.yellow(`
1914
+ \u26A0\uFE0F ${updates.length} component(s) c\xF3 b\u1EA3n c\u1EADp nh\u1EADt!`)
1915
+ );
1916
+ console.log(
1917
+ chalk4.dim("Ch\u1EA1y"),
1918
+ chalk4.cyan("'jai1 update'"),
1919
+ chalk4.dim("\u0111\u1EC3 c\u1EADp nh\u1EADt.")
1920
+ );
1809
1921
  } else {
1810
- console.log(`Status: \u2705 All good!`);
1922
+ console.log(chalk4.green("\n\u2705 M\u1ECDi th\u1EE9 \u0111\xE3 \u0111\u01B0\u1EE3c c\u1EADp nh\u1EADt!"));
1811
1923
  }
1812
1924
  } catch (error) {
1813
- console.error("Error checking updates:", error instanceof Error ? error.message : error);
1925
+ console.error(
1926
+ chalk4.red("L\u1ED7i ki\u1EC3m tra c\u1EADp nh\u1EADt:"),
1927
+ error instanceof Error ? error.message : error
1928
+ );
1814
1929
  }
1815
1930
  }
1816
1931
 
1817
1932
  // src/commands/ide/index.ts
1818
1933
  import { Command as Command10 } from "commander";
1934
+ import chalk5 from "chalk";
1819
1935
 
1820
1936
  // src/commands/ide/context.ts
1821
1937
  import React10 from "react";
@@ -3552,19 +3668,38 @@ function getConfidenceEmoji(confidence) {
3552
3668
  }
3553
3669
 
3554
3670
  // src/commands/ide/index.ts
3671
+ function showIdeHelp() {
3672
+ console.log(chalk5.bold.cyan("\u{1F5A5}\uFE0F jai1 ide") + chalk5.dim(" - IDE integration v\xE0 c\u1EA5u h\xECnh"));
3673
+ console.log();
3674
+ console.log(chalk5.bold("C\xE1c l\u1EC7nh:"));
3675
+ console.log(` ${chalk5.cyan("context")} Duy\u1EC7t v\xE0 kh\xE1m ph\xE1 IDE context`);
3676
+ console.log(` ${chalk5.cyan("setup")} C\u1EA5u h\xECnh IDE settings (VSCode optimizations)`);
3677
+ console.log(` ${chalk5.cyan("sync")} \u0110\u1ED3ng b\u1ED9 .jai1 content \u0111\u1EBFn IDE directories`);
3678
+ console.log(` ${chalk5.cyan("status")} Hi\u1EC3n th\u1ECB c\xE1c IDE \u0111\u01B0\u1EE3c ph\xE1t hi\u1EC7n v\xE0 tr\u1EA1ng th\xE1i`);
3679
+ console.log();
3680
+ console.log(chalk5.bold("IDEs \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3:"));
3681
+ console.log(chalk5.dim(" Cursor, Windsurf, VSCode, Trae, Claude"));
3682
+ console.log();
3683
+ console.log(chalk5.bold("V\xED d\u1EE5:"));
3684
+ console.log(chalk5.dim(" $ jai1 ide status"));
3685
+ console.log(chalk5.dim(" $ jai1 ide setup --optimize"));
3686
+ console.log(chalk5.dim(" $ jai1 ide sync"));
3687
+ console.log(chalk5.dim(" $ jai1 ide context"));
3688
+ console.log();
3689
+ console.log(chalk5.dim('Ch\u1EA1y "jai1 ide <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
3690
+ }
3555
3691
  function createIdeCommand() {
3556
- const ideCommand = new Command10("ide").description("IDE integration and configuration commands");
3692
+ const ideCommand = new Command10("ide").description("IDE integration and configuration commands").action(() => {
3693
+ showIdeHelp();
3694
+ });
3557
3695
  ideCommand.addCommand(createContextSubcommand());
3558
3696
  ideCommand.addCommand(createSetupSubcommand());
3559
3697
  ideCommand.addCommand(createSyncSubcommand());
3560
3698
  ideCommand.addCommand(createStatusSubcommand());
3561
- ideCommand.action(() => {
3562
- ideCommand.help();
3563
- });
3564
3699
  return ideCommand;
3565
3700
  }
3566
3701
 
3567
- // src/commands/learn.ts
3702
+ // src/commands/guide.ts
3568
3703
  import React20 from "react";
3569
3704
  import { render as render3 } from "ink";
3570
3705
  import { Command as Command11 } from "commander";
@@ -4419,9 +4554,12 @@ var GuideApp = ({ initialTopic, onExit }) => {
4419
4554
  return /* @__PURE__ */ React19.createElement(Box11, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React19.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text12, { bold: true, color: "magenta" }, "\u{1F393} Jai1 Guide"), /* @__PURE__ */ React19.createElement(Text12, { dimColor: true }, " - Trung t\xE2m h\u01B0\u1EDBng d\u1EABn Agentic Coding")), renderContent(), /* @__PURE__ */ React19.createElement(Box11, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React19.createElement(Text12, { dimColor: true }, currentTopic === "menu" ? "[\u2191\u2193] Ch\u1ECDn \xB7 [Enter] M\u1EDF \xB7 [q] Tho\xE1t" : "[\u2191\u2193/PgUp/PgDn] Cu\u1ED9n \xB7 [Esc/\u2190] Quay l\u1EA1i \xB7 [q] Tho\xE1t")));
4420
4555
  };
4421
4556
 
4422
- // src/commands/learn.ts
4423
- function createLearnCommand() {
4424
- const cmd = new Command11("learn").description("Interactive Agentic Coding learning center").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
4557
+ // src/commands/guide.ts
4558
+ function createGuideCommand() {
4559
+ const cmd = new Command11("guide").description("Trung t\xE2m h\u1ECDc Agentic Coding (interactive)").option(
4560
+ "--topic <topic>",
4561
+ "M\u1EDF topic c\u1EE5 th\u1EC3 (intro, rules, workflows, prompts, skills)"
4562
+ ).action(async (options) => {
4425
4563
  const { waitUntilExit } = render3(
4426
4564
  React20.createElement(GuideApp, {
4427
4565
  initialTopic: options.topic,
@@ -6086,6 +6224,8 @@ function createChatCommand() {
6086
6224
 
6087
6225
  // src/commands/openai-keys.ts
6088
6226
  import { Command as Command13 } from "commander";
6227
+ import chalk6 from "chalk";
6228
+ import boxen3 from "boxen";
6089
6229
  function maskKey2(key) {
6090
6230
  if (key.length <= 8) return "****";
6091
6231
  return key.slice(0, 8) + "****" + key.slice(-4);
@@ -6097,45 +6237,59 @@ async function handleOpenAiKeysCommand(options) {
6097
6237
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
6098
6238
  }
6099
6239
  const service = new LlmProxyService(config);
6100
- console.log("\u{1F4E1} Jai1 LLM Proxy - OpenAI Compatible API");
6101
- console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
6102
- console.log("\u{1F511} API Credentials");
6103
- console.log(` BASE_URL: ${service.getBaseUrl()}`);
6104
- console.log(` API_KEY: ${options.full ? service.getApiKey() : maskKey2(service.getApiKey())}
6105
- `);
6240
+ console.log(
6241
+ boxen3(chalk6.cyan.bold("\u{1F4E1} Jai1 LLM Proxy - OpenAI Compatible API"), {
6242
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
6243
+ borderStyle: "round",
6244
+ borderColor: "cyan"
6245
+ })
6246
+ );
6247
+ console.log();
6248
+ console.log(chalk6.bold("\u{1F511} API Credentials"));
6249
+ console.log(` ${chalk6.dim("BASE_URL:")} ${chalk6.white(service.getBaseUrl())}`);
6250
+ console.log(
6251
+ ` ${chalk6.dim("API_KEY:")} ${options.full ? chalk6.green(service.getApiKey()) : chalk6.yellow(maskKey2(service.getApiKey()))}`
6252
+ );
6253
+ console.log();
6106
6254
  try {
6107
6255
  const [models, limits] = await Promise.all([
6108
6256
  service.getModelsWithUsage(),
6109
6257
  service.getLimits()
6110
6258
  ]);
6111
6259
  const allowedModels = models.filter((m) => m.allowed);
6112
- console.log("\u{1F4E6} Available Models");
6260
+ console.log(chalk6.bold("\u{1F4E6} Available Models"));
6113
6261
  if (allowedModels.length === 0) {
6114
- console.log(" No models available\n");
6262
+ console.log(chalk6.dim(" Kh\xF4ng c\xF3 models kh\u1EA3 d\u1EE5ng"));
6115
6263
  } else {
6116
- allowedModels.forEach((model) => {
6117
- const usageText = model.dailyLimit !== void 0 && model.usedToday !== void 0 ? ` (${model.usedToday}/${model.dailyLimit} today)` : "";
6118
- console.log(` \u2713 ${model.id}${usageText}`);
6119
- });
6120
- console.log();
6264
+ for (const model of allowedModels) {
6265
+ const usageText = model.dailyLimit !== void 0 && model.usedToday !== void 0 ? chalk6.dim(` (${model.usedToday}/${model.dailyLimit} h\xF4m nay)`) : "";
6266
+ console.log(` ${chalk6.green("\u2713")} ${chalk6.white(model.id)}${usageText}`);
6267
+ }
6121
6268
  }
6269
+ console.log();
6122
6270
  const defaultModel = allowedModels[0]?.id || "gpt-4o";
6123
- console.log("\u{1F4DD} Sample cURL\n");
6271
+ console.log(chalk6.bold("\u{1F4DD} Sample cURL"));
6272
+ console.log();
6124
6273
  const curlSample = options.full ? service.generateFullCurlSample(defaultModel) : service.generateCurlSample(defaultModel);
6125
6274
  const curlLines = curlSample.split("\n");
6126
- curlLines.forEach((line) => console.log(` ${line}`));
6275
+ for (const line of curlLines) {
6276
+ console.log(chalk6.dim(` ${line}`));
6277
+ }
6127
6278
  console.log();
6128
- console.log("\u{1F4A1} Usage:");
6129
- console.log(" - Use as drop-in replacement for OpenAI API");
6130
- console.log(" - Compatible with: OpenAI SDK, LangChain, LlamaIndex, etc.");
6131
- console.log(' - Run "jai1 chat" for interactive mode');
6132
- console.log(' - Run "jai1 openai-keys --full" to show full API key');
6279
+ console.log(chalk6.bold("\u{1F4A1} C\xE1ch s\u1EED d\u1EE5ng"));
6280
+ console.log(chalk6.dim(" - Thay th\u1EBF OpenAI API URL v\xE0 API Key"));
6281
+ console.log(chalk6.dim(" - T\u01B0\u01A1ng th\xEDch: OpenAI SDK, LangChain, LlamaIndex, v.v."));
6282
+ console.log(chalk6.dim(' - Ch\u1EA1y "jai1 chat" \u0111\u1EC3 chat tr\u1EF1c ti\u1EBFp'));
6283
+ if (!options.full) {
6284
+ console.log(chalk6.dim(' - Ch\u1EA1y "jai1 openai-keys --full" \u0111\u1EC3 hi\u1EC3n th\u1ECB API key \u0111\u1EA7y \u0111\u1EE7'));
6285
+ }
6133
6286
  } catch (error) {
6134
- console.error(
6135
- "\n\u274C Failed to fetch API info:",
6136
- error instanceof Error ? error.message : String(error)
6287
+ console.log();
6288
+ console.log(
6289
+ chalk6.red("\u274C L\u1ED7i khi l\u1EA5y th\xF4ng tin API:"),
6290
+ chalk6.dim(error instanceof Error ? error.message : String(error))
6137
6291
  );
6138
- console.log('\n\u{1F4A1} Check your API URL and access key with "jai1 status"');
6292
+ console.log(chalk6.dim('\n\u{1F4A1} Ki\u1EC3m tra API URL v\xE0 access key v\u1EDBi "jai1 status"'));
6139
6293
  }
6140
6294
  }
6141
6295
  function createOpenAiKeysCommand() {
@@ -6147,23 +6301,29 @@ function createOpenAiKeysCommand() {
6147
6301
 
6148
6302
  // src/commands/stats.ts
6149
6303
  import { Command as Command14 } from "commander";
6304
+ import Table2 from "cli-table3";
6305
+ import chalk7 from "chalk";
6150
6306
  async function handleStatsCommand() {
6151
6307
  const configService = new ConfigService();
6152
6308
  const config = await configService.load();
6153
6309
  if (!config) {
6154
- throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Vui l\xF2ng ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
6310
+ throw new ValidationError(
6311
+ 'Ch\u01B0a x\xE1c th\u1EF1c. Vui l\xF2ng ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.'
6312
+ );
6155
6313
  }
6156
6314
  const service = new LlmProxyService(config);
6157
- console.log("\u{1F4CA} Th\u1ED1ng K\xEA S\u1EED D\u1EE5ng LLM");
6158
- console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
6315
+ console.log(chalk7.bold("\n\u{1F4CA} Th\u1ED1ng K\xEA S\u1EED D\u1EE5ng LLM"));
6316
+ console.log(chalk7.dim("\u2500".repeat(45)));
6159
6317
  try {
6160
6318
  const [limits, usage7Days, usageToday] = await Promise.all([
6161
6319
  service.getLimits(),
6162
6320
  service.getUsage(7),
6163
6321
  service.getUsage(1)
6164
6322
  ]);
6165
- const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Ho_Chi_Minh" });
6166
- console.log("\u{1F4C5} Kho\u1EA3ng th\u1EDDi gian: 7 ng\xE0y qua\n");
6323
+ const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", {
6324
+ timeZone: "Asia/Ho_Chi_Minh"
6325
+ });
6326
+ console.log(chalk7.cyan("\n\u{1F4C5} Kho\u1EA3ng th\u1EDDi gian: 7 ng\xE0y qua\n"));
6167
6327
  const usageByModel = /* @__PURE__ */ new Map();
6168
6328
  let total7DaysRequests = 0;
6169
6329
  usage7Days.data?.forEach((record) => {
@@ -6183,36 +6343,55 @@ async function handleStatsCommand() {
6183
6343
  modelData.today = record.count;
6184
6344
  }
6185
6345
  });
6186
- console.log("\u{1F4C8} T\u1ED5ng quan s\u1EED d\u1EE5ng");
6187
- console.log(` T\u1ED5ng s\u1ED1 y\xEAu c\u1EA7u (7 ng\xE0y): ${total7DaysRequests}
6346
+ console.log(chalk7.bold("\u{1F4C8} T\u1ED5ng quan s\u1EED d\u1EE5ng"));
6347
+ console.log(` T\u1ED5ng s\u1ED1 y\xEAu c\u1EA7u (7 ng\xE0y): ${chalk7.green(total7DaysRequests)}
6188
6348
  `);
6189
- console.log("\u{1F4E6} Th\u1ED1ng k\xEA theo model\n");
6190
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
6191
- console.log("\u2502 Model \u2502 H\xF4m nay \u2502 Gi\u1EDBi h\u1EA1n \u2502 T\u1ED5ng 7 ng\xE0y \u2502");
6192
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
6349
+ console.log(chalk7.bold("\u{1F4E6} Th\u1ED1ng k\xEA theo model\n"));
6350
+ const table = new Table2({
6351
+ head: [
6352
+ chalk7.bold("Model"),
6353
+ chalk7.bold("H\xF4m nay"),
6354
+ chalk7.bold("Gi\u1EDBi h\u1EA1n"),
6355
+ chalk7.bold("T\u1ED5ng 7 ng\xE0y")
6356
+ ],
6357
+ style: {
6358
+ head: ["cyan"],
6359
+ border: ["gray"]
6360
+ },
6361
+ colWidths: [35, 14, 14, 14]
6362
+ });
6193
6363
  const allowedModels = limits.effectiveAllowedModels || [];
6194
6364
  const rateLimits = limits.effectiveRateLimits || {};
6195
6365
  if (allowedModels.length === 0) {
6196
- console.log("\u2502 Kh\xF4ng c\xF3 model n\xE0o kh\u1EA3 d\u1EE5ng \u2502");
6366
+ table.push([
6367
+ { colSpan: 4, content: chalk7.yellow("Kh\xF4ng c\xF3 model n\xE0o kh\u1EA3 d\u1EE5ng") }
6368
+ ]);
6197
6369
  } else {
6198
6370
  allowedModels.forEach((modelId) => {
6199
6371
  const usage = usageByModel.get(modelId) || { today: 0, total7Days: 0 };
6200
6372
  const limit = rateLimits[modelId] || rateLimits[modelId.toLowerCase()] || 0;
6201
- const modelCol = modelId.padEnd(31);
6202
- const todayCol = `${usage.today}/${limit}`.padEnd(12);
6203
- const limitCol = `${limit}/ng\xE0y`.padEnd(12);
6204
- const totalCol = String(usage.total7Days).padEnd(12);
6205
- console.log(`\u2502 ${modelCol} \u2502 ${todayCol} \u2502 ${limitCol} \u2502 ${totalCol} \u2502`);
6373
+ const usagePercent = limit > 0 ? usage.today / limit : 0;
6374
+ let todayDisplay = `${usage.today}/${limit}`;
6375
+ if (usagePercent >= 0.9) {
6376
+ todayDisplay = chalk7.red(todayDisplay);
6377
+ } else if (usagePercent >= 0.7) {
6378
+ todayDisplay = chalk7.yellow(todayDisplay);
6379
+ } else {
6380
+ todayDisplay = chalk7.green(todayDisplay);
6381
+ }
6382
+ table.push([modelId, todayDisplay, `${limit}/ng\xE0y`, String(usage.total7Days)]);
6206
6383
  });
6207
6384
  }
6208
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
6209
- console.log('\n\u{1F4A1} M\u1EB9o: Ch\u1EA1y "jai1 openai-keys" \u0111\u1EC3 xem danh s\xE1ch model kh\u1EA3 d\u1EE5ng');
6385
+ console.log(table.toString());
6386
+ console.log(
6387
+ chalk7.dim('\n\u{1F4A1} M\u1EB9o: Ch\u1EA1y "jai1 openai-keys" \u0111\u1EC3 xem danh s\xE1ch model kh\u1EA3 d\u1EE5ng')
6388
+ );
6210
6389
  } catch (error) {
6211
6390
  console.error(
6212
- "\n\u274C Kh\xF4ng th\u1EC3 l\u1EA5y th\u1ED1ng k\xEA:",
6391
+ chalk7.red("\n\u274C Kh\xF4ng th\u1EC3 l\u1EA5y th\u1ED1ng k\xEA:"),
6213
6392
  error instanceof Error ? error.message : String(error)
6214
6393
  );
6215
- console.log('\n\u{1F4A1} Ki\u1EC3m tra k\u1EBFt n\u1ED1i API v\u1EDBi "jai1 status"');
6394
+ console.log(chalk7.dim('\n\u{1F4A1} Ki\u1EC3m tra k\u1EBFt n\u1ED1i API v\u1EDBi "jai1 status"'));
6216
6395
  }
6217
6396
  }
6218
6397
  function createStatsCommand() {
@@ -6579,6 +6758,7 @@ function createTranslateCommand() {
6579
6758
 
6580
6759
  // src/commands/image/index.ts
6581
6760
  import { Command as Command20 } from "commander";
6761
+ import chalk8 from "chalk";
6582
6762
 
6583
6763
  // src/commands/image/gen.ts
6584
6764
  import { Command as Command16 } from "commander";
@@ -6852,8 +7032,28 @@ function createImageDeleteCommand() {
6852
7032
  }
6853
7033
 
6854
7034
  // src/commands/image/index.ts
7035
+ function showImageHelp() {
7036
+ console.log(chalk8.bold.cyan("\u{1F3A8} jai1 image") + chalk8.dim(" - Image generation commands"));
7037
+ console.log();
7038
+ console.log(chalk8.yellow("\u26A0\uFE0F Coming Soon - T\xEDnh n\u0103ng \u0111ang ph\xE1t tri\u1EC3n"));
7039
+ console.log();
7040
+ console.log(chalk8.bold("C\xE1c l\u1EC7nh:"));
7041
+ console.log(` ${chalk8.cyan("gen")} T\u1EA1o \u1EA3nh t\u1EEB prompt`);
7042
+ console.log(` ${chalk8.cyan("list")} Li\u1EC7t k\xEA c\xE1c \u1EA3nh \u0111\xE3 t\u1EA1o`);
7043
+ console.log(` ${chalk8.cyan("info")} Xem th\xF4ng tin \u1EA3nh`);
7044
+ console.log(` ${chalk8.cyan("delete")} X\xF3a \u1EA3nh`);
7045
+ console.log();
7046
+ console.log(chalk8.bold("V\xED d\u1EE5:"));
7047
+ console.log(chalk8.dim(' $ jai1 image gen "a cute cat"'));
7048
+ console.log(chalk8.dim(" $ jai1 image list"));
7049
+ console.log(chalk8.dim(" $ jai1 image info <image-id>"));
7050
+ console.log();
7051
+ console.log(chalk8.dim('Ch\u1EA1y "jai1 image <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
7052
+ }
6855
7053
  function createImageCommand() {
6856
- const cmd = new Command20("image").description("Image generation commands (Coming Soon)");
7054
+ const cmd = new Command20("image").description("Image generation commands (Coming Soon)").action(() => {
7055
+ showImageHelp();
7056
+ });
6857
7057
  cmd.addCommand(createImageGenCommand());
6858
7058
  cmd.addCommand(createImageListCommand());
6859
7059
  cmd.addCommand(createImageInfoCommand());
@@ -7078,6 +7278,7 @@ function createFeedbackCommand() {
7078
7278
 
7079
7279
  // src/commands/utils/index.ts
7080
7280
  import { Command as Command35 } from "commander";
7281
+ import chalk9 from "chalk";
7081
7282
 
7082
7283
  // src/commands/utils/password.ts
7083
7284
  import { Command as Command22 } from "commander";
@@ -9394,18 +9595,44 @@ async function runInteractiveMode() {
9394
9595
  }
9395
9596
 
9396
9597
  // src/commands/utils/index.ts
9598
+ function showUtilsHelp() {
9599
+ console.log(chalk9.bold.cyan("\u{1F6E0}\uFE0F jai1 utils") + chalk9.dim(" - Developer utilities"));
9600
+ console.log();
9601
+ console.log(chalk9.bold("M\xE3 h\xF3a & B\u1EA3o m\u1EADt:"));
9602
+ console.log(` ${chalk9.cyan("password")} T\u1EA1o m\u1EADt kh\u1EA9u ng\u1EABu nhi\xEAn`);
9603
+ console.log(` ${chalk9.cyan("uuid")} T\u1EA1o UUID v4`);
9604
+ console.log(` ${chalk9.cyan("hash")} Hash text (MD5/SHA/bcrypt)`);
9605
+ console.log(` ${chalk9.cyan("jwt")} Decode/encode JWT tokens`);
9606
+ console.log();
9607
+ console.log(chalk9.bold("Encoding:"));
9608
+ console.log(` ${chalk9.cyan("base64-encode")} Encode sang Base64`);
9609
+ console.log(` ${chalk9.cyan("base64-decode")} Decode t\u1EEB Base64`);
9610
+ console.log(` ${chalk9.cyan("url-encode")} Encode URL components`);
9611
+ console.log(` ${chalk9.cyan("url-decode")} Decode URL components`);
9612
+ console.log();
9613
+ console.log(chalk9.bold("Th\u1EDDi gian:"));
9614
+ console.log(` ${chalk9.cyan("unix-time")} Chuy\u1EC3n \u0111\u1ED5i unix timestamp`);
9615
+ console.log(` ${chalk9.cyan("timezone")} Chuy\u1EC3n \u0111\u1ED5i m\xFAi gi\u1EDD`);
9616
+ console.log(` ${chalk9.cyan("cron")} Parse cron expressions`);
9617
+ console.log();
9618
+ console.log(chalk9.bold("Kh\xE1c:"));
9619
+ console.log(` ${chalk9.cyan("http")} G\u1EEDi HTTP requests`);
9620
+ console.log(` ${chalk9.cyan("markdown-preview")} Xem tr\u01B0\u1EDBc file markdown`);
9621
+ console.log();
9622
+ console.log(chalk9.bold("Ch\u1EBF \u0111\u1ED9 Interactive:"));
9623
+ console.log(chalk9.dim(" $ jai1 utils -i"));
9624
+ console.log(chalk9.dim(" $ jai1 utils --interactive"));
9625
+ console.log();
9626
+ console.log(chalk9.bold("V\xED d\u1EE5:"));
9627
+ console.log(chalk9.dim(" $ jai1 utils password --length 24"));
9628
+ console.log(chalk9.dim(" $ jai1 utils uuid --count 5"));
9629
+ console.log(chalk9.dim(' $ jai1 utils hash "text" --algorithm sha256'));
9630
+ console.log(chalk9.dim(" $ jai1 utils http https://api.example.com"));
9631
+ console.log();
9632
+ console.log(chalk9.dim('Ch\u1EA1y "jai1 utils <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
9633
+ }
9397
9634
  function createUtilsCommand() {
9398
- const utilsCommand = new Command35("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
9399
- Interactive Mode:
9400
- $ jai1 utils --interactive
9401
- $ jai1 utils -i
9402
-
9403
- Quick Usage:
9404
- $ jai1 utils password --length 24
9405
- $ jai1 utils uuid --count 5
9406
- $ jai1 utils hash "text" --algorithm sha256
9407
- $ jai1 utils http https://api.example.com
9408
- `);
9635
+ const utilsCommand = new Command35("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode");
9409
9636
  utilsCommand.addCommand(createPasswordCommand());
9410
9637
  utilsCommand.addCommand(createUuidCommand());
9411
9638
  utilsCommand.addCommand(createHashCommand());
@@ -9423,7 +9650,7 @@ Quick Usage:
9423
9650
  if (options.interactive) {
9424
9651
  await runInteractiveMode();
9425
9652
  } else {
9426
- utilsCommand.help();
9653
+ showUtilsHelp();
9427
9654
  }
9428
9655
  });
9429
9656
  return utilsCommand;
@@ -9431,6 +9658,7 @@ Quick Usage:
9431
9658
 
9432
9659
  // src/commands/deps/index.ts
9433
9660
  import { Command as Command37 } from "commander";
9661
+ import chalk10 from "chalk";
9434
9662
 
9435
9663
  // src/commands/deps/upgrade.ts
9436
9664
  import { Command as Command36 } from "commander";
@@ -9826,17 +10054,34 @@ function displayUpgradeTable(packages) {
9826
10054
  }
9827
10055
 
9828
10056
  // src/commands/deps/index.ts
10057
+ function showDepsHelp() {
10058
+ console.log(chalk10.bold.cyan("\u{1F4E6} jai1 deps") + chalk10.dim(" - Qu\u1EA3n l\xFD dependencies trong project"));
10059
+ console.log();
10060
+ console.log(chalk10.bold("C\xE1c l\u1EC7nh:"));
10061
+ console.log(` ${chalk10.cyan("upgrade")} N\xE2ng c\u1EA5p dependencies l\xEAn phi\xEAn b\u1EA3n m\u1EDBi nh\u1EA5t`);
10062
+ console.log();
10063
+ console.log(chalk10.bold("V\xED d\u1EE5:"));
10064
+ console.log(chalk10.dim(" $ jai1 deps upgrade"));
10065
+ console.log(chalk10.dim(" $ jai1 deps upgrade --dry-run"));
10066
+ console.log();
10067
+ console.log(chalk10.dim('Ch\u1EA1y "jai1 deps <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
10068
+ }
9829
10069
  function createDepsCommand() {
9830
- const depsCommand = new Command37("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
10070
+ const depsCommand = new Command37("deps").description("Qu\u1EA3n l\xFD dependencies trong project").action(() => {
10071
+ showDepsHelp();
10072
+ });
9831
10073
  depsCommand.addCommand(createDepsUpgradeCommand());
9832
10074
  return depsCommand;
9833
10075
  }
9834
10076
 
9835
10077
  // src/commands/kit/index.ts
9836
10078
  import { Command as Command41 } from "commander";
10079
+ import chalk12 from "chalk";
9837
10080
 
9838
10081
  // src/commands/kit/list.ts
9839
10082
  import { Command as Command38 } from "commander";
10083
+ import chalk11 from "chalk";
10084
+ import Table3 from "cli-table3";
9840
10085
 
9841
10086
  // src/services/starter-kit.service.ts
9842
10087
  import { promises as fs14 } from "fs";
@@ -9909,13 +10154,18 @@ function createKitListCommand() {
9909
10154
  if (!config) {
9910
10155
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
9911
10156
  }
10157
+ console.log(chalk11.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch starter kits..."));
10158
+ console.log();
9912
10159
  const kitService = new StarterKitService();
9913
10160
  const kits = await kitService.list(config, {
9914
10161
  category: options.category,
9915
10162
  search: options.search
9916
10163
  });
9917
10164
  if (kits.length === 0) {
9918
- console.log("No starter kits found.");
10165
+ console.log(chalk11.yellow("Kh\xF4ng t\xECm th\u1EA5y starter kits n\xE0o."));
10166
+ if (options.category || options.search) {
10167
+ console.log(chalk11.dim("Th\u1EED b\u1ECF filter \u0111\u1EC3 xem t\u1EA5t c\u1EA3."));
10168
+ }
9919
10169
  return;
9920
10170
  }
9921
10171
  const byCategory = {};
@@ -9925,17 +10175,41 @@ function createKitListCommand() {
9925
10175
  }
9926
10176
  byCategory[kit.category].push(kit);
9927
10177
  }
9928
- console.log("\u{1F4E6} Available Starter Kits:\n");
9929
- for (const [category, categoryKits] of Object.entries(byCategory)) {
9930
- console.log(`${category.charAt(0).toUpperCase() + category.slice(1)}:`);
10178
+ const categoryOrder = ["frontend", "backend", "fullstack"];
10179
+ const sortedCategories = Object.keys(byCategory).sort((a, b) => {
10180
+ const indexA = categoryOrder.indexOf(a);
10181
+ const indexB = categoryOrder.indexOf(b);
10182
+ if (indexA === -1 && indexB === -1) return a.localeCompare(b);
10183
+ if (indexA === -1) return 1;
10184
+ if (indexB === -1) return -1;
10185
+ return indexA - indexB;
10186
+ });
10187
+ for (const category of sortedCategories) {
10188
+ const categoryKits = byCategory[category];
10189
+ const categoryIcon = category === "frontend" ? "\u{1F3A8}" : category === "backend" ? "\u2699\uFE0F" : category === "fullstack" ? "\u{1F680}" : "\u{1F4E6}";
10190
+ console.log(
10191
+ chalk11.bold(`${categoryIcon} ${category.charAt(0).toUpperCase() + category.slice(1)}`)
10192
+ );
10193
+ const table = new Table3({
10194
+ head: [
10195
+ chalk11.cyan("Slug"),
10196
+ chalk11.cyan("M\xF4 t\u1EA3"),
10197
+ chalk11.cyan("Version")
10198
+ ],
10199
+ style: { head: [], border: ["gray"] }
10200
+ });
9931
10201
  for (const kit of categoryKits) {
9932
- const tags = kit.tags.length > 0 ? ` [${kit.tags.join(", ")}]` : "";
9933
- console.log(
9934
- ` ${kit.slug.padEnd(20)} ${kit.description.slice(0, 50).padEnd(52)} v${kit.version}${tags}`
9935
- );
10202
+ table.push([
10203
+ chalk11.white(kit.slug),
10204
+ chalk11.dim(kit.description.slice(0, 50)),
10205
+ chalk11.green(`v${kit.version}`)
10206
+ ]);
9936
10207
  }
10208
+ console.log(table.toString());
9937
10209
  console.log();
9938
10210
  }
10211
+ console.log(chalk11.dim(`T\u1ED5ng c\u1ED9ng: ${kits.length} starter kit(s)`));
10212
+ console.log(chalk11.dim('\n\u{1F4A1} Ch\u1EA1y "jai1 kit create <slug>" \u0111\u1EC3 t\u1EA1o project m\u1EDBi'));
9939
10213
  });
9940
10214
  }
9941
10215
 
@@ -10207,9 +10481,25 @@ async function getAllFiles(dir) {
10207
10481
  }
10208
10482
 
10209
10483
  // src/commands/kit/index.ts
10484
+ function showKitHelp() {
10485
+ console.log(chalk12.bold.cyan("\u{1F4E6} jai1 kit") + chalk12.dim(" - Qu\u1EA3n l\xFD starter kits"));
10486
+ console.log();
10487
+ console.log(chalk12.bold("C\xE1c l\u1EC7nh:"));
10488
+ console.log(` ${chalk12.cyan("list")} Li\u1EC7t k\xEA c\xE1c starter kits c\xF3 s\u1EB5n`);
10489
+ console.log(` ${chalk12.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t starter kit`);
10490
+ console.log(` ${chalk12.cyan("create")} T\u1EA1o project m\u1EDBi t\u1EEB starter kit`);
10491
+ console.log();
10492
+ console.log(chalk12.bold("V\xED d\u1EE5:"));
10493
+ console.log(chalk12.dim(" $ jai1 kit list"));
10494
+ console.log(chalk12.dim(" $ jai1 kit list --category frontend"));
10495
+ console.log(chalk12.dim(" $ jai1 kit info next-tw4-shadcn"));
10496
+ console.log(chalk12.dim(" $ jai1 kit create next-tw4-shadcn my-project"));
10497
+ console.log();
10498
+ console.log(chalk12.dim('Ch\u1EA1y "jai1 kit <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
10499
+ }
10210
10500
  function createKitCommand() {
10211
10501
  const cmd = new Command41("kit").description("Manage starter kits for new projects").action(() => {
10212
- cmd.help();
10502
+ showKitHelp();
10213
10503
  });
10214
10504
  cmd.addCommand(createKitListCommand());
10215
10505
  cmd.addCommand(createKitInfoCommand());
@@ -10219,9 +10509,12 @@ function createKitCommand() {
10219
10509
 
10220
10510
  // src/commands/rules/index.ts
10221
10511
  import { Command as Command48 } from "commander";
10512
+ import chalk14 from "chalk";
10222
10513
 
10223
10514
  // src/commands/rules/list.ts
10224
10515
  import { Command as Command42 } from "commander";
10516
+ import chalk13 from "chalk";
10517
+ import Table4 from "cli-table3";
10225
10518
  function createRulesListCommand() {
10226
10519
  return new Command42("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
10227
10520
  const configService = new ConfigService();
@@ -10229,7 +10522,8 @@ function createRulesListCommand() {
10229
10522
  if (!config) {
10230
10523
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
10231
10524
  }
10232
- console.log("\u{1F4CB} Fetching available rule presets...\n");
10525
+ console.log(chalk13.cyan("\u{1F4CB} \u0110ang t\u1EA3i danh s\xE1ch rule presets..."));
10526
+ console.log();
10233
10527
  try {
10234
10528
  const response = await fetch(`${config.apiUrl}/api/rules/presets`, {
10235
10529
  headers: {
@@ -10245,33 +10539,43 @@ function createRulesListCommand() {
10245
10539
  return;
10246
10540
  }
10247
10541
  if (data.total === 0) {
10248
- console.log("No presets available.");
10542
+ console.log(chalk13.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
10249
10543
  return;
10250
10544
  }
10251
- console.log(`Found ${data.total} preset${data.total > 1 ? "s" : ""}:
10252
- `);
10545
+ console.log(
10546
+ chalk13.green(`\u2713 T\xECm th\u1EA5y ${chalk13.bold(data.total)} preset${data.total > 1 ? "s" : ""}`)
10547
+ );
10548
+ console.log();
10253
10549
  for (const preset of data.presets) {
10254
- console.log(`\u{1F4E6} ${preset.slug}`);
10255
- console.log(` Name: ${preset.name}`);
10256
- console.log(` Description: ${preset.description}`);
10257
- console.log(` Version: ${preset.version}`);
10550
+ console.log(chalk13.bold.cyan(`\u{1F4E6} ${preset.slug}`));
10551
+ const table = new Table4({
10552
+ style: { head: [], border: ["gray"], compact: true },
10553
+ colWidths: [15, 55]
10554
+ });
10555
+ table.push(
10556
+ [chalk13.dim("T\xEAn"), chalk13.white(preset.name)],
10557
+ [chalk13.dim("M\xF4 t\u1EA3"), chalk13.white(preset.description)],
10558
+ [chalk13.dim("Version"), chalk13.green(`v${preset.version}`)]
10559
+ );
10258
10560
  const stackParts = [];
10259
10561
  if (preset.stack.frontend) stackParts.push(preset.stack.frontend);
10260
10562
  if (preset.stack.backend) stackParts.push(preset.stack.backend);
10261
10563
  if (preset.stack.css) stackParts.push(preset.stack.css);
10262
10564
  if (preset.stack.database) stackParts.push(preset.stack.database);
10263
10565
  if (stackParts.length > 0) {
10264
- console.log(` Stack: ${stackParts.join(" + ")}`);
10566
+ table.push([chalk13.dim("Stack"), chalk13.yellow(stackParts.join(" + "))]);
10265
10567
  }
10266
- console.log(` Tags: ${preset.tags.join(", ")}`);
10267
- console.log(` Downloads: ${preset.downloads}`);
10268
- console.log("");
10568
+ table.push(
10569
+ [chalk13.dim("Tags"), chalk13.dim(preset.tags.join(", ") || "-")],
10570
+ [chalk13.dim("Downloads"), chalk13.white(preset.downloads.toString())]
10571
+ );
10572
+ console.log(table.toString());
10573
+ console.log();
10269
10574
  }
10270
- console.log(`
10271
- \u2139\uFE0F Use 'jai1 rules init --preset=<slug>' to apply a preset`);
10575
+ console.log(chalk13.dim('\u{1F4A1} Ch\u1EA1y "jai1 rules init --preset=<slug>" \u0111\u1EC3 \xE1p d\u1EE5ng preset'));
10272
10576
  } catch (error) {
10273
10577
  throw new Error(
10274
- `Failed to list presets: ${error instanceof Error ? error.message : String(error)}`
10578
+ `L\u1ED7i khi t\u1EA3i presets: ${error instanceof Error ? error.message : String(error)}`
10275
10579
  );
10276
10580
  }
10277
10581
  });
@@ -11570,8 +11874,29 @@ async function checkIdeFilesExist(ideId, format) {
11570
11874
  }
11571
11875
 
11572
11876
  // src/commands/rules/index.ts
11877
+ function showRulesHelp() {
11878
+ console.log(chalk14.bold.cyan("\u{1F4CB} jai1 rules") + chalk14.dim(" - Qu\u1EA3n l\xFD rule presets cho AI agents"));
11879
+ console.log();
11880
+ console.log(chalk14.bold("C\xE1c l\u1EC7nh:"));
11881
+ console.log(` ${chalk14.cyan("list")} Li\u1EC7t k\xEA c\xE1c presets c\xF3 s\u1EB5n`);
11882
+ console.log(` ${chalk14.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t preset`);
11883
+ console.log(` ${chalk14.cyan("init")} Kh\u1EDFi t\u1EA1o rules t\u1EEB preset`);
11884
+ console.log(` ${chalk14.cyan("apply")} \xC1p d\u1EE5ng preset v\xE0o project`);
11885
+ console.log(` ${chalk14.cyan("sync")} \u0110\u1ED3ng b\u1ED9 rules v\u1EDBi server`);
11886
+ console.log(` ${chalk14.cyan("restore")} Kh\xF4i ph\u1EE5c rules t\u1EEB backup`);
11887
+ console.log();
11888
+ console.log(chalk14.bold("V\xED d\u1EE5:"));
11889
+ console.log(chalk14.dim(" $ jai1 rules list"));
11890
+ console.log(chalk14.dim(" $ jai1 rules info react-typescript"));
11891
+ console.log(chalk14.dim(" $ jai1 rules init --preset=react-typescript"));
11892
+ console.log(chalk14.dim(" $ jai1 rules apply react-typescript"));
11893
+ console.log();
11894
+ console.log(chalk14.dim('Ch\u1EA1y "jai1 rules <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
11895
+ }
11573
11896
  function createRulesCommand() {
11574
- const rulesCommand = new Command48("rules").description("Manage rule presets for AI agents");
11897
+ const rulesCommand = new Command48("rules").description("Manage rule presets for AI agents").action(() => {
11898
+ showRulesHelp();
11899
+ });
11575
11900
  rulesCommand.addCommand(createRulesListCommand());
11576
11901
  rulesCommand.addCommand(createRulesInitCommand());
11577
11902
  rulesCommand.addCommand(createRulesApplyCommand());
@@ -13296,31 +13621,12 @@ async function resetSettings2(groupKeys) {
13296
13621
  console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
13297
13622
  }
13298
13623
 
13299
- // src/commands/guide.ts
13624
+ // src/commands/context.ts
13300
13625
  import React40 from "react";
13301
13626
  import { render as render6 } from "ink";
13302
13627
  import { Command as Command58 } from "commander";
13303
- function createGuideCommand() {
13304
- const cmd = new Command58("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
13305
- const { waitUntilExit } = render6(
13306
- React40.createElement(GuideApp, {
13307
- initialTopic: options.topic,
13308
- onExit: () => {
13309
- process.exit(0);
13310
- }
13311
- })
13312
- );
13313
- await waitUntilExit();
13314
- });
13315
- return cmd;
13316
- }
13317
-
13318
- // src/commands/context.ts
13319
- import React41 from "react";
13320
- import { render as render7 } from "ink";
13321
- import { Command as Command59 } from "commander";
13322
13628
  function createContextCommand() {
13323
- const cmd = new Command59("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
13629
+ const cmd = new Command58("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
13324
13630
  let initialIDE;
13325
13631
  if (options.ide) {
13326
13632
  const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
@@ -13345,8 +13651,8 @@ function createContextCommand() {
13345
13651
  await printStats2();
13346
13652
  return;
13347
13653
  }
13348
- const { waitUntilExit } = render7(
13349
- React41.createElement(ContextApp, {
13654
+ const { waitUntilExit } = render6(
13655
+ React40.createElement(ContextApp, {
13350
13656
  initialIDE,
13351
13657
  initialType,
13352
13658
  onExit: () => {
@@ -13397,10 +13703,10 @@ async function printStats2() {
13397
13703
  }
13398
13704
 
13399
13705
  // src/commands/migrate-ide.ts
13400
- import { Command as Command60 } from "commander";
13706
+ import { Command as Command59 } from "commander";
13401
13707
  import { checkbox as checkbox8, confirm as confirm16 } from "@inquirer/prompts";
13402
13708
  function createMigrateIdeCommand() {
13403
- const cmd = new Command60("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
13709
+ const cmd = new Command59("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
13404
13710
  await runMigrateIde(options);
13405
13711
  });
13406
13712
  return cmd;
@@ -13505,8 +13811,56 @@ async function runMigrateIde(options) {
13505
13811
  console.log("");
13506
13812
  }
13507
13813
 
13814
+ // src/utils/help-formatter.ts
13815
+ import boxen4 from "boxen";
13816
+ import chalk15 from "chalk";
13817
+ import gradient from "gradient-string";
13818
+ import figlet from "figlet";
13819
+ function showCustomHelp(version) {
13820
+ const title = figlet.textSync("JAI1", { font: "Small" });
13821
+ console.log(gradient.pastel(title));
13822
+ console.log(
13823
+ boxen4(chalk15.cyan(`Agentic Coding CLI v${version}`), {
13824
+ padding: { left: 1, right: 1, top: 0, bottom: 0 },
13825
+ borderStyle: "round",
13826
+ borderColor: "cyan"
13827
+ })
13828
+ );
13829
+ console.log(chalk15.bold("\n\u{1F527} Thi\u1EBFt l\u1EADp & Th\xF4ng tin"));
13830
+ console.log(" auth X\xE1c th\u1EF1c v\xE0 c\u1EA5u h\xECnh jai1-client");
13831
+ console.log(" status Hi\u1EC3n th\u1ECB tr\u1EA1ng th\xE1i c\u1EA5u h\xECnh");
13832
+ console.log(" guide Trung t\xE2m h\u1ECDc Agentic Coding");
13833
+ console.log(chalk15.bold("\n\u{1F4E6} Qu\u1EA3n l\xFD Components"));
13834
+ console.log(" apply C\xE0i \u0111\u1EB7t components (interactive)");
13835
+ console.log(" update C\u1EADp nh\u1EADt components \u0111\xE3 c\xE0i");
13836
+ console.log(" check Ki\u1EC3m tra c\u1EADp nh\u1EADt t\u1EEB server");
13837
+ console.log(chalk15.bold("\n\u{1F5A5}\uFE0F IDE & T\xEDch h\u1EE3p"));
13838
+ console.log(" ide L\u1EC7nh c\u1EA5u h\xECnh IDE");
13839
+ console.log(" chat Chat AI v\u1EDBi Jai1 LLM Proxy");
13840
+ console.log(" openai-keys Th\xF4ng tin API credentials");
13841
+ console.log(chalk15.bold("\n\u{1F916} AI Tools"));
13842
+ console.log(" translate D\u1ECBch v\u0103n b\u1EA3n/file b\u1EB1ng AI");
13843
+ console.log(" image T\u1EA1o \u1EA3nh (Coming Soon)");
13844
+ console.log(" stats Th\u1ED1ng k\xEA s\u1EED d\u1EE5ng LLM");
13845
+ console.log(" feedback G\u1EEDi b\xE1o c\xE1o/\u0111\u1EC1 xu\u1EA5t");
13846
+ console.log(chalk15.bold("\n\u{1F4C1} Project"));
13847
+ console.log(" kit Qu\u1EA3n l\xFD starter kits");
13848
+ console.log(" rules Qu\u1EA3n l\xFD rule presets");
13849
+ console.log(" deps Qu\u1EA3n l\xFD dependencies");
13850
+ console.log(" redmine Redmine context sync");
13851
+ console.log(chalk15.bold("\n\u2699\uFE0F B\u1EA3o tr\xEC"));
13852
+ console.log(" upgrade C\u1EADp nh\u1EADt jai1-client");
13853
+ console.log(" clean D\u1ECDn d\u1EB9p cache/backup");
13854
+ console.log(" utils Developer utilities");
13855
+ console.log(chalk15.dim("\nS\u1EED d\u1EE5ng: jai1 [l\u1EC7nh] --help \u0111\u1EC3 xem chi ti\u1EBFt"));
13856
+ }
13857
+ function showUnknownCommand(commandName) {
13858
+ console.error(chalk15.red(`\u274C L\u1EC7nh kh\xF4ng t\u1ED3n t\u1EA1i: ${commandName}`));
13859
+ console.error(chalk15.dim("\nG\u1EE3i \xFD: Ch\u1EA1y jai1 --help \u0111\u1EC3 xem danh s\xE1ch l\u1EC7nh"));
13860
+ }
13861
+
13508
13862
  // src/cli.ts
13509
- var program = new Command61();
13863
+ var program = new Command60();
13510
13864
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
13511
13865
  console.log(package_default.version);
13512
13866
  if (!process.argv.includes("--skip-update-check")) {
@@ -13514,15 +13868,20 @@ if (process.argv.includes("-v") || process.argv.includes("--version")) {
13514
13868
  }
13515
13869
  process.exit(0);
13516
13870
  }
13517
- program.name("jai1").description("Jai1 Framework Management CLI");
13518
- program.option("--verbose", "Enable verbose logging").option("--json", "Output results as JSON").option("--skip-update-check", "Skip checking for client updates");
13871
+ program.name("jai1").description("Jai1 Framework Management CLI").configureHelp({
13872
+ formatHelp: () => {
13873
+ showCustomHelp(package_default.version);
13874
+ return "";
13875
+ }
13876
+ });
13877
+ program.option("--verbose", "Enable verbose logging", false).option("--json", "Output results as JSON", false).option("--skip-update-check", "Skip checking for client updates", false);
13519
13878
  program.addCommand(createAuthCommand());
13520
13879
  program.addCommand(createStatusCommand());
13521
13880
  program.addCommand(createApplyCommand());
13522
13881
  program.addCommand(createUpdateCommand());
13523
13882
  program.addCommand(createCheckCommand());
13524
13883
  program.addCommand(createIdeCommand());
13525
- program.addCommand(createLearnCommand());
13884
+ program.addCommand(createGuideCommand());
13526
13885
  program.addCommand(createChatCommand());
13527
13886
  program.addCommand(createOpenAiKeysCommand());
13528
13887
  program.addCommand(createStatsCommand());
@@ -13535,9 +13894,9 @@ program.addCommand(createKitCommand());
13535
13894
  program.addCommand(createRulesCommand());
13536
13895
  program.addCommand(createUpgradeCommand());
13537
13896
  program.addCommand(createCleanCommand());
13538
- var redmineCommand = new Command61("redmine").description("Redmine context sync commands");
13897
+ var redmineCommand = new Command60("redmine").description("Redmine context sync commands");
13539
13898
  redmineCommand.addCommand(createRedmineCheckCommand());
13540
- var syncCommand = new Command61("sync").description("Sync Redmine issues to markdown files");
13899
+ var syncCommand = new Command60("sync").description("Sync Redmine issues to markdown files");
13541
13900
  syncCommand.addCommand(createSyncIssueCommand());
13542
13901
  syncCommand.addCommand(createSyncProjectCommand());
13543
13902
  redmineCommand.addCommand(syncCommand);
@@ -13546,54 +13905,10 @@ program.addCommand(createInfoCommand(), { hidden: true });
13546
13905
  program.addCommand(createSelfUpdateCommand(), { hidden: true });
13547
13906
  program.addCommand(createClearBackupsCommand(), { hidden: true });
13548
13907
  program.addCommand(createVSCodeCommand(), { hidden: true });
13549
- program.addCommand(createGuideCommand(), { hidden: true });
13550
13908
  program.addCommand(createContextCommand(), { hidden: true });
13551
13909
  program.addCommand(createMigrateIdeCommand(), { hidden: true });
13552
13910
  program.on("command:*", (operands) => {
13553
- console.error(`\u274C Unknown command: ${operands[0]}`);
13554
- console.error("\nAvailable commands:");
13555
- console.error("");
13556
- console.error(" \u{1F527} Setup & Info");
13557
- console.error(" auth Authenticate and configure jai1-client");
13558
- console.error(" status Show configuration and installed components");
13559
- console.error("");
13560
- console.error(" \u{1F4E6} Components");
13561
- console.error(" apply Install/apply components (interactive UI)");
13562
- console.error(" update Update installed components");
13563
- console.error(" check Check for component updates");
13564
- console.error("");
13565
- console.error(" \u{1F5A5}\uFE0F IDE");
13566
- console.error(" ide context Browse and explore IDE context");
13567
- console.error(" ide setup Configure IDE settings");
13568
- console.error(" ide sync Sync .jai1 content to IDEs");
13569
- console.error("");
13570
- console.error(" \u{1F4DA} Learning");
13571
- console.error(" learn Interactive Agentic Coding guide");
13572
- console.error("");
13573
- console.error(" \u{1F916} LLM Proxy");
13574
- console.error(" chat Interactive AI chat");
13575
- console.error(" openai-keys Show OpenAI-compatible API credentials");
13576
- console.error(" stats Show LLM usage statistics and limits");
13577
- console.error(" translate Translate text, files, or folders using AI");
13578
- console.error("");
13579
- console.error(" \u{1F6E0}\uFE0F Developer Utilities");
13580
- console.error(" deps Manage project dependencies");
13581
- console.error(" utils Developer tools (password, uuid, hash, jwt, etc.)");
13582
- console.error("");
13583
- console.error(" \u{1F4CB} Rule Presets");
13584
- console.error(" rules list List available rule presets");
13585
- console.error(" rules init Apply preset to project");
13586
- console.error(" rules sync Regenerate outputs after editing");
13587
- console.error(" rules info Show current preset information");
13588
- console.error("");
13589
- console.error(" \u{1F527} Maintenance");
13590
- console.error(" upgrade Upgrade jai1-client to latest version");
13591
- console.error(" clean Clean up backups and cache");
13592
- console.error("");
13593
- console.error(" \u{1F517} Integrations");
13594
- console.error(" redmine Redmine integration commands");
13595
- console.error("");
13596
- console.error('Use "jai1 --help" for more information.');
13911
+ showUnknownCommand(operands[0]);
13597
13912
  process.exit(1);
13598
13913
  });
13599
13914
  process.on("unhandledRejection", (error) => {