@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 +555 -240
- package/dist/cli.js.map +1 -1
- package/package.json +8 -1
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
|
|
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.
|
|
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("
|
|
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(
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
"
|
|
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(
|
|
389
|
-
|
|
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(
|
|
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
|
|
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("
|
|
437
|
+
throw new ValidationError("\u0110\u1ECBnh d\u1EA1ng API URL kh\xF4ng h\u1EE3p l\u1EC7");
|
|
417
438
|
}
|
|
418
|
-
console.log("\
|
|
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(
|
|
431
|
-
|
|
432
|
-
|
|
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("
|
|
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(
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
console.log("\u{
|
|
737
|
-
console.log(`
|
|
738
|
-
console.log(`
|
|
739
|
-
console.log(`
|
|
740
|
-
console.log();
|
|
741
|
-
console.log("
|
|
742
|
-
console.log(`
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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}
|
|
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
|
-
|
|
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
|
|
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}
|
|
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(
|
|
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: "
|
|
1716
|
-
if (!shouldUpdate)
|
|
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
|
-
|
|
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(
|
|
1787
|
+
console.log(chalk3.green(" \u2713"));
|
|
1732
1788
|
updatedCount++;
|
|
1733
1789
|
} catch (error) {
|
|
1734
|
-
console.log(
|
|
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
|
-
|
|
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}
|
|
1742
|
-
const cleanBackups = await confirm({ message: "
|
|
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
|
|
1806
|
+
console.log(chalk3.green("\u{1F5D1}\uFE0F \u0110\xE3 x\xF3a backups."));
|
|
1746
1807
|
} else {
|
|
1747
|
-
console.log('\u{1F4A1}
|
|
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(`
|
|
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("
|
|
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(
|
|
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("
|
|
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
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
1808
|
-
|
|
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(
|
|
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(
|
|
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/
|
|
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/
|
|
4423
|
-
function
|
|
4424
|
-
const cmd = new Command11("
|
|
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(
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
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("
|
|
6262
|
+
console.log(chalk6.dim(" Kh\xF4ng c\xF3 models kh\u1EA3 d\u1EE5ng"));
|
|
6115
6263
|
} else {
|
|
6116
|
-
|
|
6117
|
-
const usageText = model.dailyLimit !== void 0 && model.usedToday !== void 0 ? ` (${model.usedToday}/${model.dailyLimit}
|
|
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
|
|
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
|
-
|
|
6275
|
+
for (const line of curlLines) {
|
|
6276
|
+
console.log(chalk6.dim(` ${line}`));
|
|
6277
|
+
}
|
|
6127
6278
|
console.log();
|
|
6128
|
-
console.log("\u{1F4A1}
|
|
6129
|
-
console.log(" -
|
|
6130
|
-
console.log(" -
|
|
6131
|
-
console.log(' -
|
|
6132
|
-
|
|
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.
|
|
6135
|
-
|
|
6136
|
-
|
|
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}
|
|
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(
|
|
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
|
|
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", {
|
|
6166
|
-
|
|
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
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
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
|
-
|
|
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
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
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(
|
|
6209
|
-
console.log(
|
|
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")
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
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
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
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
|
-
|
|
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}
|
|
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("
|
|
10542
|
+
console.log(chalk13.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
|
|
10249
10543
|
return;
|
|
10250
10544
|
}
|
|
10251
|
-
console.log(
|
|
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
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
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
|
-
|
|
10566
|
+
table.push([chalk13.dim("Stack"), chalk13.yellow(stackParts.join(" + "))]);
|
|
10265
10567
|
}
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
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
|
-
`
|
|
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/
|
|
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
|
|
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 } =
|
|
13349
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
13897
|
+
var redmineCommand = new Command60("redmine").description("Redmine context sync commands");
|
|
13539
13898
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
13540
|
-
var syncCommand = new
|
|
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
|
-
|
|
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) => {
|