@nalvietnam/avatar-cli 1.2.6 → 1.2.7
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/index.js
CHANGED
|
@@ -546,19 +546,19 @@ function applyUseGlobal(existing, source) {
|
|
|
546
546
|
...sourceModel ? { model: sourceModel } : {}
|
|
547
547
|
};
|
|
548
548
|
}
|
|
549
|
-
async function writeClaudeSettings(workspacePath,
|
|
549
|
+
async function writeClaudeSettings(workspacePath, input5) {
|
|
550
550
|
const path = getClaudeSettingsPath(workspacePath);
|
|
551
551
|
const existing = await readExistingSettings(path);
|
|
552
552
|
let merged;
|
|
553
|
-
switch (
|
|
553
|
+
switch (input5.provider) {
|
|
554
554
|
case "subscription":
|
|
555
|
-
merged = applySubscription(existing,
|
|
555
|
+
merged = applySubscription(existing, input5.model);
|
|
556
556
|
break;
|
|
557
557
|
case "llmlite":
|
|
558
|
-
merged = applyLLMLite(existing,
|
|
558
|
+
merged = applyLLMLite(existing, input5.apiKey, input5.baseUrl, input5.model);
|
|
559
559
|
break;
|
|
560
560
|
case "use-global":
|
|
561
|
-
merged = applyUseGlobal(existing,
|
|
561
|
+
merged = applyUseGlobal(existing, input5.sourceSettings);
|
|
562
562
|
break;
|
|
563
563
|
}
|
|
564
564
|
await writeJsonAtomic(path, merged, SECRET_FILE_MODE2);
|
|
@@ -1194,7 +1194,7 @@ async function applyFixes(checks) {
|
|
|
1194
1194
|
|
|
1195
1195
|
// src/commands/init.ts
|
|
1196
1196
|
import { basename, join as join16, relative as relative2, resolve } from "path";
|
|
1197
|
-
import { confirm as confirm3, input as
|
|
1197
|
+
import { confirm as confirm3, input as input4, select as select7 } from "@inquirer/prompts";
|
|
1198
1198
|
import boxen4 from "boxen";
|
|
1199
1199
|
|
|
1200
1200
|
// src/lib/prompt-recovery-action-on-failure.ts
|
|
@@ -1498,15 +1498,15 @@ var RepoAlreadyExistsError = class extends Error {
|
|
|
1498
1498
|
this.name = "RepoAlreadyExistsError";
|
|
1499
1499
|
}
|
|
1500
1500
|
};
|
|
1501
|
-
function executeGhRepoCreate(
|
|
1502
|
-
const fullName = `${
|
|
1501
|
+
function executeGhRepoCreate(input5) {
|
|
1502
|
+
const fullName = `${input5.org}/${input5.name}`;
|
|
1503
1503
|
const args = [
|
|
1504
1504
|
"repo",
|
|
1505
1505
|
"create",
|
|
1506
1506
|
fullName,
|
|
1507
|
-
`--${
|
|
1507
|
+
`--${input5.visibility}`,
|
|
1508
1508
|
"--source",
|
|
1509
|
-
|
|
1509
|
+
input5.folder,
|
|
1510
1510
|
"--remote",
|
|
1511
1511
|
"origin",
|
|
1512
1512
|
"--push"
|
|
@@ -1559,16 +1559,16 @@ function validateRepoVisibility(v) {
|
|
|
1559
1559
|
}
|
|
1560
1560
|
|
|
1561
1561
|
// src/lib/create-github-remote-from-folder.ts
|
|
1562
|
-
function createGithubRemoteFromFolder(
|
|
1563
|
-
validateRepoName(
|
|
1564
|
-
validateRepoVisibility(
|
|
1565
|
-
const org =
|
|
1566
|
-
log.info(`T\u1EA1o GitHub repo ${org}/${
|
|
1562
|
+
function createGithubRemoteFromFolder(input5) {
|
|
1563
|
+
validateRepoName(input5.name);
|
|
1564
|
+
validateRepoVisibility(input5.visibility);
|
|
1565
|
+
const org = input5.org ?? resolveGithubUsernameDefault();
|
|
1566
|
+
log.info(`T\u1EA1o GitHub repo ${org}/${input5.name} (${input5.visibility})...`);
|
|
1567
1567
|
const urls = executeGhRepoCreate({
|
|
1568
|
-
folder:
|
|
1568
|
+
folder: input5.folder,
|
|
1569
1569
|
org,
|
|
1570
|
-
name:
|
|
1571
|
-
visibility:
|
|
1570
|
+
name: input5.name,
|
|
1571
|
+
visibility: input5.visibility
|
|
1572
1572
|
});
|
|
1573
1573
|
log.success(`\u0110\xE3 t\u1EA1o: ${urls.sshUrl}`);
|
|
1574
1574
|
return urls;
|
|
@@ -1610,7 +1610,7 @@ function detectPackageManager() {
|
|
|
1610
1610
|
|
|
1611
1611
|
// src/lib/handle-remote-access-failure-with-account-switch.ts
|
|
1612
1612
|
import { spawnSync as spawnSync12 } from "child_process";
|
|
1613
|
-
import { select as select5 } from "@inquirer/prompts";
|
|
1613
|
+
import { input as input3, select as select5 } from "@inquirer/prompts";
|
|
1614
1614
|
|
|
1615
1615
|
// src/lib/verify-git-remote-accessible.ts
|
|
1616
1616
|
import { spawnSync as spawnSync11 } from "child_process";
|
|
@@ -1670,33 +1670,43 @@ function getReasonHint(reason, url, ghUser) {
|
|
|
1670
1670
|
case "no-access":
|
|
1671
1671
|
return ghUser ? `Repo c\xF3 th\u1EC3 private v\xE0 account '${ghUser}' kh\xF4ng c\xF3 quy\u1EC1n access. Switch sang account c\xF3 quy\u1EC1n, ho\u1EB7c xin invite t\u1EEB owner repo.` : "Repo c\xF3 th\u1EC3 private v\xE0 gh CLI ch\u01B0a login. Login tr\u01B0\u1EDBc r\u1ED3i retry.";
|
|
1672
1672
|
case "not-found":
|
|
1673
|
-
return `URL c\xF3 th\u1EC3 sai ch\xEDnh t\u1EA3, ho\u1EB7c repo \u0111\xE3 b\u1ECB x\xF3a/rename. Check: ${url}`;
|
|
1673
|
+
return `URL c\xF3 th\u1EC3 sai ch\xEDnh t\u1EA3, ho\u1EB7c repo \u0111\xE3 b\u1ECB x\xF3a/rename. Nh\u1EADp l\u1EA1i URL \u0111\xFAng. Check: ${url}`;
|
|
1674
1674
|
case "network":
|
|
1675
1675
|
return "Kh\xF4ng k\u1EBFt n\u1ED1i \u0111\u01B0\u1EE3c GitHub. Check m\u1EA1ng / VPN / firewall.";
|
|
1676
1676
|
case "timeout":
|
|
1677
1677
|
return "Network ch\u1EADm > 5s. Check m\u1EA1ng r\u1ED3i retry.";
|
|
1678
1678
|
default:
|
|
1679
|
-
return "L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh.
|
|
1679
|
+
return "L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh. URL c\xF3 th\u1EC3 sai \u2014 nh\u1EADp l\u1EA1i, ho\u1EB7c check gh auth status.";
|
|
1680
1680
|
}
|
|
1681
1681
|
}
|
|
1682
|
+
function isValidGitUrl(url) {
|
|
1683
|
+
const trimmed = url.trim();
|
|
1684
|
+
if (!trimmed) return false;
|
|
1685
|
+
return /^https?:\/\/[\w.@/-]+$/.test(trimmed) || /^git@[\w.-]+:[\w./-]+\.git$/.test(trimmed) || /^[\w.-]+\/[\w.-]+$/.test(trimmed);
|
|
1686
|
+
}
|
|
1682
1687
|
async function handleRemoteAccessFailureWithAccountSwitch(args) {
|
|
1688
|
+
let currentUrl = args.url;
|
|
1683
1689
|
let reason = args.initialReason;
|
|
1684
1690
|
let detail = args.initialDetail;
|
|
1685
1691
|
while (true) {
|
|
1686
1692
|
const ghUser = getCurrentGhUser2();
|
|
1687
|
-
log.warn(`Kh\xF4ng truy c\u1EADp \u0111\u01B0\u1EE3c ${
|
|
1693
|
+
log.warn(`Kh\xF4ng truy c\u1EADp \u0111\u01B0\u1EE3c ${currentUrl}`);
|
|
1688
1694
|
log.dim(` L\xFD do: ${reason}${detail ? ` \u2014 ${detail.slice(0, 150)}` : ""}`);
|
|
1689
|
-
log.info(getReasonHint(reason,
|
|
1695
|
+
log.info(getReasonHint(reason, currentUrl, ghUser));
|
|
1690
1696
|
if (ghUser) log.dim(` gh CLI hi\u1EC7n \u0111ang login: ${ghUser}`);
|
|
1691
1697
|
const action = await select5({
|
|
1692
1698
|
message: "C\xE1ch x\u1EED l\xFD?",
|
|
1693
1699
|
choices: [
|
|
1700
|
+
{
|
|
1701
|
+
name: "Nh\u1EADp l\u1EA1i URL \u0111\xFAng (recommended khi URL sai ch\xEDnh t\u1EA3)",
|
|
1702
|
+
value: "re-input-url"
|
|
1703
|
+
},
|
|
1694
1704
|
{
|
|
1695
1705
|
name: "Switch GitHub account (gh auth login \u2014 m\u1EDF browser)",
|
|
1696
1706
|
value: "switch"
|
|
1697
1707
|
},
|
|
1698
1708
|
{
|
|
1699
|
-
name: "T\xF4i v\u1EEBa fix (accept invite / s\u1EEDa
|
|
1709
|
+
name: "T\xF4i v\u1EEBa fix (accept invite / s\u1EEDa permission) \u2014 retry verify",
|
|
1700
1710
|
value: "retry"
|
|
1701
1711
|
},
|
|
1702
1712
|
{
|
|
@@ -1707,17 +1717,25 @@ async function handleRemoteAccessFailureWithAccountSwitch(args) {
|
|
|
1707
1717
|
});
|
|
1708
1718
|
if (action === "abort") {
|
|
1709
1719
|
throw new RemoteAccessAbortedError(
|
|
1710
|
-
`User ch\u1ECDn t\u1EA1m ng\u01B0ng. Fix access ${
|
|
1720
|
+
`User ch\u1ECDn t\u1EA1m ng\u01B0ng. Fix access ${currentUrl} r\u1ED3i ch\u1EA1y l\u1EA1i 'avatar init'.`
|
|
1711
1721
|
);
|
|
1712
1722
|
}
|
|
1723
|
+
if (action === "re-input-url") {
|
|
1724
|
+
const newUrl = await input3({
|
|
1725
|
+
message: "URL git remote (https://github.com/owner/repo.git ho\u1EB7c git@github.com:owner/repo.git):",
|
|
1726
|
+
default: currentUrl,
|
|
1727
|
+
validate: (v) => isValidGitUrl(v) || "URL kh\xF4ng \u0111\xFAng format git remote"
|
|
1728
|
+
});
|
|
1729
|
+
currentUrl = newUrl.trim();
|
|
1730
|
+
}
|
|
1713
1731
|
if (action === "switch") {
|
|
1714
1732
|
triggerGhAuthLoginInteractive2();
|
|
1715
1733
|
}
|
|
1716
|
-
log.info(
|
|
1717
|
-
const result = tryVerifyGitRemoteAccessible(
|
|
1734
|
+
log.info(`Verify remote l\u1EA1i: ${currentUrl}...`);
|
|
1735
|
+
const result = tryVerifyGitRemoteAccessible(currentUrl);
|
|
1718
1736
|
if (result.ok) {
|
|
1719
|
-
log.success(`Remote accessible: ${
|
|
1720
|
-
return;
|
|
1737
|
+
log.success(`Remote accessible: ${currentUrl}`);
|
|
1738
|
+
return { resolvedUrl: currentUrl };
|
|
1721
1739
|
}
|
|
1722
1740
|
reason = result.reason ?? "unknown";
|
|
1723
1741
|
detail = result.detail;
|
|
@@ -1834,14 +1852,16 @@ async function ensureGitHubReady(remoteUrl) {
|
|
|
1834
1852
|
const result = tryVerifyGitRemoteAccessible(remoteUrl);
|
|
1835
1853
|
if (result.ok) {
|
|
1836
1854
|
log.success(`Remote accessible: ${remoteUrl}`);
|
|
1837
|
-
|
|
1838
|
-
await handleRemoteAccessFailureWithAccountSwitch({
|
|
1839
|
-
url: remoteUrl,
|
|
1840
|
-
initialReason: result.reason ?? "unknown",
|
|
1841
|
-
initialDetail: result.detail
|
|
1842
|
-
});
|
|
1855
|
+
return { resolvedRemoteUrl: remoteUrl };
|
|
1843
1856
|
}
|
|
1857
|
+
const recovered = await handleRemoteAccessFailureWithAccountSwitch({
|
|
1858
|
+
url: remoteUrl,
|
|
1859
|
+
initialReason: result.reason ?? "unknown",
|
|
1860
|
+
initialDetail: result.detail
|
|
1861
|
+
});
|
|
1862
|
+
return { resolvedRemoteUrl: recovered.resolvedUrl };
|
|
1844
1863
|
}
|
|
1864
|
+
return {};
|
|
1845
1865
|
}
|
|
1846
1866
|
|
|
1847
1867
|
// src/lib/create-workspace-remote-via-gh.ts
|
|
@@ -1870,27 +1890,27 @@ function canCreateInNamespace(org, ghUser) {
|
|
|
1870
1890
|
reason: `'${ghUser}' kh\xF4ng ph\u1EA3i member c\u1EE7a org '${org}'. Li\xEAn h\u1EC7 admin org \u0111\u1EC3 \u0111\u01B0\u1EE3c invite, ho\u1EB7c pass --repo-org=${ghUser} t\u1EA1o d\u01B0\u1EDBi personal account.`
|
|
1871
1891
|
};
|
|
1872
1892
|
}
|
|
1873
|
-
async function createWorkspaceRemoteViaGh(
|
|
1874
|
-
validateRepoName(
|
|
1875
|
-
validateRepoVisibility(
|
|
1893
|
+
async function createWorkspaceRemoteViaGh(input5) {
|
|
1894
|
+
validateRepoName(input5.workspaceName);
|
|
1895
|
+
validateRepoVisibility(input5.visibility);
|
|
1876
1896
|
await ensureGitHubReady();
|
|
1877
1897
|
const ghUser = resolveGithubUsernameDefault();
|
|
1878
|
-
const org =
|
|
1898
|
+
const org = input5.org ?? ghUser;
|
|
1879
1899
|
const namespaceCheck = canCreateInNamespace(org, ghUser);
|
|
1880
1900
|
if (!namespaceCheck.ok) {
|
|
1881
1901
|
throw new Error(`Kh\xF4ng th\u1EC3 t\u1EA1o repo d\u01B0\u1EDBi '${org}/': ${namespaceCheck.reason}`);
|
|
1882
1902
|
}
|
|
1883
|
-
const fullName = `${org}/${
|
|
1884
|
-
log.info(`T\u1EA1o GitHub repo cho workspace: ${fullName} (${
|
|
1903
|
+
const fullName = `${org}/${input5.workspaceName}`;
|
|
1904
|
+
log.info(`T\u1EA1o GitHub repo cho workspace: ${fullName} (${input5.visibility})...`);
|
|
1885
1905
|
const r = spawnSync16(
|
|
1886
1906
|
"gh",
|
|
1887
1907
|
[
|
|
1888
1908
|
"repo",
|
|
1889
1909
|
"create",
|
|
1890
1910
|
fullName,
|
|
1891
|
-
`--${
|
|
1911
|
+
`--${input5.visibility}`,
|
|
1892
1912
|
"--source",
|
|
1893
|
-
|
|
1913
|
+
input5.workspacePath,
|
|
1894
1914
|
"--remote",
|
|
1895
1915
|
"origin",
|
|
1896
1916
|
"--push"
|
|
@@ -1902,7 +1922,7 @@ async function createWorkspaceRemoteViaGh(input4) {
|
|
|
1902
1922
|
if (stderr) process.stderr.write(`${stderr}
|
|
1903
1923
|
`);
|
|
1904
1924
|
throw new Error(
|
|
1905
|
-
`T\u1EA1o workspace remote th\u1EA5t b\u1EA1i (exit ${r.status}). Workspace v\u1EABn d\xF9ng \u0111\u01B0\u1EE3c local. Setup remote sau qua: gh repo create ${fullName} --${
|
|
1925
|
+
`T\u1EA1o workspace remote th\u1EA5t b\u1EA1i (exit ${r.status}). Workspace v\u1EABn d\xF9ng \u0111\u01B0\u1EE3c local. Setup remote sau qua: gh repo create ${fullName} --${input5.visibility} --source=. --remote=origin --push`
|
|
1906
1926
|
);
|
|
1907
1927
|
}
|
|
1908
1928
|
const sshUrl = `git@github.com:${fullName}.git`;
|
|
@@ -2500,14 +2520,15 @@ async function promptProjectStatus() {
|
|
|
2500
2520
|
});
|
|
2501
2521
|
}
|
|
2502
2522
|
async function runInitFromExistingRemote(opts, ownerEmail) {
|
|
2503
|
-
const
|
|
2523
|
+
const initialRemoteUrl = opts.clientRepo ?? await input4({
|
|
2504
2524
|
message: "URL git c\u1EE7a repo:",
|
|
2505
2525
|
validate: (v) => v.length > 0 ? true : "URL b\u1EAFt bu\u1ED9c"
|
|
2506
2526
|
});
|
|
2507
|
-
await ensureGitHubReady(
|
|
2527
|
+
const { resolvedRemoteUrl } = await ensureGitHubReady(initialRemoteUrl);
|
|
2528
|
+
const remoteUrl = resolvedRemoteUrl ?? initialRemoteUrl;
|
|
2508
2529
|
const teamOwner = opts.teamOwner ?? await promptTeamOwner(ownerEmail);
|
|
2509
2530
|
const inferredName = inferWorkspaceName(remoteUrl);
|
|
2510
|
-
const workspaceName = opts.workspaceName ?? await
|
|
2531
|
+
const workspaceName = opts.workspaceName ?? await input4({ message: "T\xEAn workspace:", default: inferredName });
|
|
2511
2532
|
const workspaceParent = resolve(opts.workspaceParent ?? ".");
|
|
2512
2533
|
const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);
|
|
2513
2534
|
await scaffoldWorkspaceWithSrcSubmodule({
|
|
@@ -2530,7 +2551,7 @@ async function runInitFromExistingRemote(opts, ownerEmail) {
|
|
|
2530
2551
|
}
|
|
2531
2552
|
async function runInitFromExistingFolder(opts, ownerEmail) {
|
|
2532
2553
|
const folderPath = resolve(
|
|
2533
|
-
opts.folderPath ?? await
|
|
2554
|
+
opts.folderPath ?? await input4({
|
|
2534
2555
|
message: "\u0110\u01B0\u1EDDng d\u1EABn folder hi\u1EC7n c\xF3:",
|
|
2535
2556
|
validate: (v) => v.length > 0 ? true : "Path b\u1EAFt bu\u1ED9c"
|
|
2536
2557
|
})
|
|
@@ -2542,7 +2563,7 @@ async function runInitFromExistingFolder(opts, ownerEmail) {
|
|
|
2542
2563
|
const remoteUrl = await getOrCreateOriginRemote(folderPath, opts);
|
|
2543
2564
|
const teamOwner = opts.teamOwner ?? await promptTeamOwner(ownerEmail);
|
|
2544
2565
|
const inferredName = opts.workspaceName ?? `${basename(folderPath)}-avatar-workspace`;
|
|
2545
|
-
const workspaceName = opts.workspaceName ?? await
|
|
2566
|
+
const workspaceName = opts.workspaceName ?? await input4({ message: "T\xEAn workspace:", default: inferredName });
|
|
2546
2567
|
const workspaceParent = resolve(opts.workspaceParent ?? ".");
|
|
2547
2568
|
const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);
|
|
2548
2569
|
await scaffoldWorkspaceWithSrcSubmodule({
|
|
@@ -2566,7 +2587,7 @@ async function runInitFromExistingFolder(opts, ownerEmail) {
|
|
|
2566
2587
|
}
|
|
2567
2588
|
async function runInitFromScratch(opts, ownerEmail) {
|
|
2568
2589
|
await ensureGitHubReady();
|
|
2569
|
-
const projectName = opts.workspaceName ?? await
|
|
2590
|
+
const projectName = opts.workspaceName ?? await input4({
|
|
2570
2591
|
message: "T\xEAn d\u1EF1 \xE1n:",
|
|
2571
2592
|
validate: (v) => v.length > 0 ? true : "T\xEAn b\u1EAFt bu\u1ED9c"
|
|
2572
2593
|
});
|
|
@@ -2651,7 +2672,7 @@ async function getOrCreateOriginRemote(folderPath, opts) {
|
|
|
2651
2672
|
{ name: "public", value: "public" }
|
|
2652
2673
|
]
|
|
2653
2674
|
});
|
|
2654
|
-
const repoName = await
|
|
2675
|
+
const repoName = await input4({
|
|
2655
2676
|
message: "T\xEAn repo:",
|
|
2656
2677
|
default: basename(folderPath)
|
|
2657
2678
|
});
|
|
@@ -2808,7 +2829,7 @@ async function resolveWorkspacePath(parent, desiredName, force) {
|
|
|
2808
2829
|
if (action === "use-alt" && alternative) {
|
|
2809
2830
|
return alternative;
|
|
2810
2831
|
}
|
|
2811
|
-
const newName = await
|
|
2832
|
+
const newName = await input4({
|
|
2812
2833
|
message: "T\xEAn workspace m\u1EDBi:",
|
|
2813
2834
|
validate: (v) => v.trim().length > 0 ? true : "T\xEAn kh\xF4ng \u0111\u01B0\u1EE3c r\u1ED7ng"
|
|
2814
2835
|
});
|
|
@@ -2818,7 +2839,7 @@ async function resolveWorkspacePath(parent, desiredName, force) {
|
|
|
2818
2839
|
}
|
|
2819
2840
|
}
|
|
2820
2841
|
async function promptTeamOwner(currentUserEmail) {
|
|
2821
|
-
return await
|
|
2842
|
+
return await input4({ message: "Team owner email:", default: currentUserEmail });
|
|
2822
2843
|
}
|
|
2823
2844
|
async function maybeCommitWorkspace(workspacePath, skipCommit) {
|
|
2824
2845
|
if (skipCommit) {
|
|
@@ -3143,7 +3164,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
|
|
|
3143
3164
|
}
|
|
3144
3165
|
|
|
3145
3166
|
// src/commands/uninstall.ts
|
|
3146
|
-
var CLI_VERSION = "1.2.
|
|
3167
|
+
var CLI_VERSION = "1.2.7";
|
|
3147
3168
|
function registerUninstallCommand(program2) {
|
|
3148
3169
|
program2.command("uninstall").description("G\u1EE1 Avatar kh\u1ECFi project \u2014 backup t\u1EF1 \u0111\u1ED9ng (M11)").option("--yes", "Skip confirm prompt").option("--no-backup", "Kh\xF4ng t\u1EA1o backup tr\u01B0\u1EDBc khi x\xF3a (nguy hi\u1EC3m)").option("--keep-submodule", "Gi\u1EEF submodule .claude/pack/").option("--keep-hooks", "Gi\u1EEF git hooks post-merge, pre-push").option("--dry-run", "Hi\u1EC3n th\u1ECB danh s\xE1ch s\u1EBD x\xF3a, kh\xF4ng th\u1EF1c thi").action(async (opts) => {
|
|
3149
3170
|
try {
|
|
@@ -3225,7 +3246,7 @@ function printUninstallSuccessBox(backupPath) {
|
|
|
3225
3246
|
}
|
|
3226
3247
|
|
|
3227
3248
|
// src/index.ts
|
|
3228
|
-
var CLI_VERSION2 = "1.2.
|
|
3249
|
+
var CLI_VERSION2 = "1.2.7";
|
|
3229
3250
|
var program = new Command();
|
|
3230
3251
|
program.name("avatar").description("AI harness CLI for NAL Vietnam engineering").version(CLI_VERSION2, "-v, --version", "Hi\u1EC3n th\u1ECB phi\xEAn b\u1EA3n Avatar CLI").addHelpText(
|
|
3231
3252
|
"beforeAll",
|