@nalvietnam/avatar-cli 1.7.1 → 1.9.0

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
@@ -1297,6 +1297,11 @@ async function checkoutTagInSubmodule(submodulePath, tag, cwd = process.cwd()) {
1297
1297
  await git(submoduleCwd).fetch(["--tags"]);
1298
1298
  await git(submoduleCwd).checkout(tag);
1299
1299
  }
1300
+ async function checkoutBranchHeadInSubmodule(submodulePath, branch, cwd = process.cwd()) {
1301
+ const submoduleCwd = join8(cwd, submodulePath);
1302
+ await git(submoduleCwd).fetch(["origin"]);
1303
+ await git(submoduleCwd).checkout(["-B", branch, `origin/${branch}`]);
1304
+ }
1300
1305
  async function listTags(cwd = process.cwd()) {
1301
1306
  const result = await git(cwd).tags();
1302
1307
  return result.all;
@@ -2308,7 +2313,7 @@ function registerGitnexusCommand(program2) {
2308
2313
  // src/commands/init.ts
2309
2314
  import { basename, join as join24, relative as relative3, resolve } from "path";
2310
2315
  import { confirm as confirm5, input as input5, select as select9 } from "@inquirer/prompts";
2311
- import boxen5 from "boxen";
2316
+ import boxen6 from "boxen";
2312
2317
 
2313
2318
  // src/lib/add-team-pack-submodule-with-retry-on-network-fail.ts
2314
2319
  import { spawnSync as spawnSync13 } from "child_process";
@@ -3196,6 +3201,42 @@ function linkExistingRemoteToWorkspace(args) {
3196
3201
  return { sshUrl, httpsUrl };
3197
3202
  }
3198
3203
 
3204
+ // src/lib/format-pack-commands-cheatsheet-box.ts
3205
+ import boxen4 from "boxen";
3206
+ var PACK_COMMAND_CHEATSHEET = [
3207
+ { cmd: "/avatar:help", desc: "H\u01B0\u1EDBng d\u1EABn s\u1EED d\u1EE5ng Avatar \u2014 ch\u1EC9 c\u1EA7n g\xF5 t\u1EF1 nhi\xEAn" },
3208
+ { cmd: "/avatar:brainstorm", desc: "Brainstorm \xFD t\u01B0\u1EDFng cho m\u1ED9t feature" },
3209
+ { cmd: "/avatar:plan", desc: "T\u1EA1o plan th\xF4ng minh v\u1EDBi prompt enhancement" },
3210
+ { cmd: "/avatar:scout", desc: "T\xECm file li\xEAn quan trong codebase, ti\u1EBFt ki\u1EC7m token" },
3211
+ { cmd: "/avatar:implement", desc: "B\u1EAFt \u0111\u1EA7u code & test theo plan c\xF3 s\u1EB5n" },
3212
+ { cmd: "/avatar:build-full-flow", desc: "Implement m\u1ED9t feature t\u1EEBng b\u01B0\u1EDBc (end-to-end)" },
3213
+ { cmd: "/avatar:fix", desc: "Ph\xE2n t\xEDch v\xE0 fix v\u1EA5n \u0111\u1EC1 t\u1EF1 \u0111i\u1EC1u h\u01B0\u1EDBng" },
3214
+ { cmd: "/avatar:debug", desc: "Debug v\u1EA5n \u0111\u1EC1 k\u1EF9 thu\u1EADt + \u0111\u01B0a ra gi\u1EA3i ph\xE1p" },
3215
+ { cmd: "/avatar:test", desc: "Ch\u1EA1y test tr\xEAn m\xE1y + ph\xE2n t\xEDch b\xE1o c\xE1o t\u1ED5ng h\u1EE3p" },
3216
+ { cmd: "/avatar:design:good", desc: "T\u1EA1o thi\u1EBFt k\u1EBF ch\u1EC9n chu, s\u1ED1ng \u0111\u1ED9ng" },
3217
+ { cmd: "/avatar:docs:init", desc: "Ph\xE2n t\xEDch codebase + t\u1EA1o t\xE0i li\u1EC7u kh\u1EDFi \u0111\u1EA7u" },
3218
+ { cmd: "/avatar:status", desc: "Xem l\u1EA1i thay \u0111\u1ED5i g\u1EA7n \u0111\xE2y + t\u1ED5ng k\u1EBFt c\xF4ng vi\u1EC7c" },
3219
+ { cmd: "/avatar:journal", desc: "Ghi nh\u1EADt k\xFD session" }
3220
+ ];
3221
+ function formatPackCommandsCheatsheetBox() {
3222
+ const maxCmdWidth = Math.max(...PACK_COMMAND_CHEATSHEET.map((e) => e.cmd.length));
3223
+ const header = chalk.bold("\u{1F3AF} Slash commands t\u1EEB team-ai-pack");
3224
+ const subheader = chalk.dim("G\xF5 trong Claude Code session \u0111\u1EC3 g\u1ECDi capability c\u1EE7a pack:");
3225
+ const lines = PACK_COMMAND_CHEATSHEET.map((e) => {
3226
+ const cmdPadded = chalk.cyan(e.cmd.padEnd(maxCmdWidth));
3227
+ return ` ${cmdPadded} ${chalk.dim(e.desc)}`;
3228
+ });
3229
+ const footer = chalk.dim(
3230
+ "Catalog \u0111\u1EA7y \u0111\u1EE7 46 commands: cat .claude/pack/scripts/commands_data.yaml"
3231
+ );
3232
+ const content = [header, subheader, "", ...lines, "", footer].join("\n");
3233
+ return boxen4(content, {
3234
+ padding: 1,
3235
+ borderStyle: "round",
3236
+ borderColor: "cyan"
3237
+ });
3238
+ }
3239
+
3199
3240
  // src/lib/merge-pack-settings-into-project-settings.ts
3200
3241
  import { promises as fs9 } from "fs";
3201
3242
  import { join as join17 } from "path";
@@ -3756,7 +3797,7 @@ function buildScaffoldVariables(args) {
3756
3797
  }
3757
3798
 
3758
3799
  // src/commands/login.ts
3759
- import boxen4 from "boxen";
3800
+ import boxen5 from "boxen";
3760
3801
  import open from "open";
3761
3802
 
3762
3803
  // src/lib/google-oauth-device-flow.ts
@@ -3903,7 +3944,7 @@ async function runLogin(opts) {
3903
3944
  "",
3904
3945
  `Ho\u1EB7c Avatar t\u1EF1 m\u1EDF browser, click ${chalk.green("Allow")}...`
3905
3946
  ].join("\n");
3906
- process.stdout.write(`${boxen4(instructions, { padding: 1, borderStyle: "round" })}
3947
+ process.stdout.write(`${boxen5(instructions, { padding: 1, borderStyle: "round" })}
3907
3948
  `);
3908
3949
  void open(verificationUrl).catch(() => {
3909
3950
  log.dim("(Kh\xF4ng m\u1EDF \u0111\u01B0\u1EE3c browser t\u1EF1 \u0111\u1ED9ng \u2014 copy URL \u1EDF tr\xEAn)");
@@ -4300,7 +4341,7 @@ async function finalizeWorkspaceScaffold(args) {
4300
4341
  await writeRootClaudeMd(args.workspacePath, updatedVars);
4301
4342
  log.dim("Updated CLAUDE.md v\u1EDBi GitNexus section");
4302
4343
  }
4303
- printInitSuccessBox(args.workspacePath, args.flow, aiResult, gitnexusResult);
4344
+ await printInitSuccessBox(args.workspacePath, args.flow, aiResult, gitnexusResult);
4304
4345
  }
4305
4346
  async function autoSyncPackOnInit(workspacePath) {
4306
4347
  const packDir = join24(workspacePath, TEAM_PACK_RELATIVE_PATH);
@@ -4494,7 +4535,7 @@ function formatGitnexusStatusLine(result) {
4494
4535
  }
4495
4536
  return ` ${chalk.yellow("GitNexus:")} skipped (${(result.reason ?? "unknown").slice(0, 40)}) \xB7 th\u1EED ${chalk.cyan("avatar gitnexus install")}`;
4496
4537
  }
4497
- function printInitSuccessBox(rootPath, flow, aiResult = null, gitnexusResult = null) {
4538
+ async function printInitSuccessBox(rootPath, flow, aiResult = null, gitnexusResult = null) {
4498
4539
  const lines = [
4499
4540
  `${chalk.green("\u2713")} Workspace s\u1EB5n s\xE0ng: ${relative3(process.cwd(), rootPath) || rootPath}`,
4500
4541
  ` ${chalk.dim(`(flow: ${flow})`)}`,
@@ -4508,8 +4549,14 @@ function printInitSuccessBox(rootPath, flow, aiResult = null, gitnexusResult = n
4508
4549
  ` ${chalk.cyan("avatar sync")} Pull team-ai-pack m\u1EDBi`,
4509
4550
  ` ${chalk.cyan("avatar uninstall")} G\u1EE1 Avatar (gi\u1EEF code)`
4510
4551
  ];
4511
- process.stdout.write(`${boxen5(lines.join("\n"), { padding: 1, borderStyle: "round" })}
4552
+ process.stdout.write(`${boxen6(lines.join("\n"), { padding: 1, borderStyle: "round" })}
4512
4553
  `);
4554
+ const packDir = join24(rootPath, TEAM_PACK_RELATIVE_PATH);
4555
+ if (await pathExists(packDir)) {
4556
+ process.stdout.write(`
4557
+ ${formatPackCommandsCheatsheetBox()}
4558
+ `);
4559
+ }
4513
4560
  }
4514
4561
 
4515
4562
  // src/lib/not-implemented-stub.ts
@@ -4561,7 +4608,7 @@ function registerSecretsCommand(program2) {
4561
4608
  // src/commands/status.ts
4562
4609
  import { promises as fs13 } from "fs";
4563
4610
  import { join as join26 } from "path";
4564
- import boxen6 from "boxen";
4611
+ import boxen7 from "boxen";
4565
4612
 
4566
4613
  // src/lib/pack-backup-manager.ts
4567
4614
  import { promises as fs12 } from "fs";
@@ -4639,7 +4686,7 @@ function renderStatusBox(s) {
4639
4686
  `${chalk.dim("Backups:")} ${s.backupCount}`,
4640
4687
  `${chalk.dim("Tech stack:")} ${s.techStackSummary}`
4641
4688
  ];
4642
- process.stdout.write(`${boxen6(lines.join("\n"), { padding: 1, borderStyle: "round" })}
4689
+ process.stdout.write(`${boxen7(lines.join("\n"), { padding: 1, borderStyle: "round" })}
4643
4690
  `);
4644
4691
  }
4645
4692
 
@@ -4689,6 +4736,7 @@ async function buildSyncPreview(packDir, claudeDir, targetVersion) {
4689
4736
  }
4690
4737
 
4691
4738
  // src/commands/sync.ts
4739
+ var DEFAULT_PACK_BRANCH = "main";
4692
4740
  async function syncAction(opts) {
4693
4741
  const projectRoot = process.cwd();
4694
4742
  const claudeDir = join28(projectRoot, ".claude");
@@ -4708,16 +4756,23 @@ async function syncAction(opts) {
4708
4756
  `Kh\xF4ng fetch \u0111\u01B0\u1EE3c tags t\u1EEB origin (${err instanceof Error ? err.message : err}). S\u1EBD d\xF9ng tag local hi\u1EC7n c\xF3.`
4709
4757
  );
4710
4758
  }
4759
+ const useLatestMode = opts.latest === true && !opts.version;
4711
4760
  const allTags = await listTags(packDir);
4712
- const targetVersion = opts.version ?? pickLatestStableSemVerTag(allTags);
4713
- if (!targetVersion) {
4714
- log.error(
4715
- `Kh\xF4ng t\xECm th\u1EA5y stable SemVer tag (vMAJOR.MINOR.PATCH) trong team-ai-pack submodule.
4761
+ let targetVersion;
4762
+ if (useLatestMode) {
4763
+ targetVersion = `${DEFAULT_PACK_BRANCH} (HEAD)`;
4764
+ } else {
4765
+ const picked = opts.version ?? pickLatestStableSemVerTag(allTags);
4766
+ if (!picked) {
4767
+ log.error(
4768
+ `Kh\xF4ng t\xECm th\u1EA5y stable SemVer tag (vMAJOR.MINOR.PATCH) trong team-ai-pack submodule.
4716
4769
  Tags hi\u1EC7n c\xF3: ${allTags.length > 0 ? allTags.join(", ") : "(none)"}
4717
- Pass --version <tag> r\xF5 r\xE0ng, ho\u1EB7c tag pack theo SemVer convention.`
4718
- );
4719
- process.exit(1);
4720
- return;
4770
+ Pass --version <tag> r\xF5 r\xE0ng, ho\u1EB7c d\xF9ng --latest \u0111\u1EC3 pull HEAD branch ${DEFAULT_PACK_BRANCH}.`
4771
+ );
4772
+ process.exit(1);
4773
+ return;
4774
+ }
4775
+ targetVersion = picked;
4721
4776
  }
4722
4777
  if (opts.dryRun) {
4723
4778
  const preview = await buildSyncPreview(packDir, claudeDir, targetVersion);
@@ -4741,8 +4796,18 @@ async function syncAction(opts) {
4741
4796
  log.info("\nDry-run done. Kh\xF4ng apply thay \u0111\u1ED5i. B\u1ECF --dry-run \u0111\u1EC3 th\u1EF1c thi.");
4742
4797
  return;
4743
4798
  }
4744
- log.info(`Checking out ${targetVersion} trong submodule...`);
4745
- await checkoutTagInSubmodule(TEAM_PACK_RELATIVE_PATH, targetVersion, projectRoot);
4799
+ if (useLatestMode) {
4800
+ log.info(`Pulling HEAD c\u1EE7a branch ${DEFAULT_PACK_BRANCH} (bleeding-edge mode)...`);
4801
+ await checkoutBranchHeadInSubmodule(TEAM_PACK_RELATIVE_PATH, DEFAULT_PACK_BRANCH, projectRoot);
4802
+ const sha = await currentCommitSha(packDir);
4803
+ log.dim(` HEAD = ${sha.slice(0, 7)}`);
4804
+ log.warn(
4805
+ "\u26A0 --latest mode: workspace pin v\xE0o commit floating, kh\xF4ng reproducible. Chuy\u1EC3n v\u1EC1 tag stable: avatar sync (no flag)."
4806
+ );
4807
+ } else {
4808
+ log.info(`Checking out ${targetVersion} trong submodule...`);
4809
+ await checkoutTagInSubmodule(TEAM_PACK_RELATIVE_PATH, targetVersion, projectRoot);
4810
+ }
4746
4811
  log.info("Creating symlink farm...");
4747
4812
  const results = await syncAllMountDirs(packDir, claudeDir, opts.force === true);
4748
4813
  reportResults(results, opts.force === true);
@@ -4799,7 +4864,7 @@ function reportResults(results, force) {
4799
4864
  }
4800
4865
  }
4801
4866
  function registerSyncCommand(program2) {
4802
- program2.command("sync").description("Pull team-ai-pack m\u1EDBi nh\u1EA5t + t\u1EA1o symlink farm v\xE0o .claude/").option("--force", "Override .claude/<dir>/ n\u1EBFu l\xE0 real dir (backup tr\u01B0\u1EDBc)").option("--version <tag>", "Pin v\xE0o version c\u1EE5 th\u1EC3 (vd: v0.2.0)").option("--dry-run", "Hi\u1EC3n th\u1ECB preview, kh\xF4ng apply thay \u0111\u1ED5i").action(syncAction);
4867
+ program2.command("sync").description("Pull team-ai-pack m\u1EDBi nh\u1EA5t + t\u1EA1o symlink farm v\xE0o .claude/").option("--force", "Override .claude/<dir>/ n\u1EBFu l\xE0 real dir (backup tr\u01B0\u1EDBc)").option("--version <tag>", "Pin v\xE0o version c\u1EE5 th\u1EC3 (vd: v0.2.0)").option("--latest", "Bleeding-edge: pull HEAD c\u1EE7a main branch (b\u1ECF qua tag SemVer)").option("--dry-run", "Hi\u1EC3n th\u1ECB preview, kh\xF4ng apply thay \u0111\u1ED5i").action(syncAction);
4803
4868
  }
4804
4869
 
4805
4870
  // src/commands/tools.ts
@@ -4813,7 +4878,7 @@ function registerToolsCommand(program2) {
4813
4878
  // src/commands/uninstall.ts
4814
4879
  import { relative as relative4 } from "path";
4815
4880
  import { confirm as confirm6 } from "@inquirer/prompts";
4816
- import boxen7 from "boxen";
4881
+ import boxen8 from "boxen";
4817
4882
 
4818
4883
  // src/lib/create-uninstall-backup-snapshot.ts
4819
4884
  import { cp, mkdir, writeFile } from "fs/promises";
@@ -4967,7 +5032,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
4967
5032
  }
4968
5033
 
4969
5034
  // src/commands/uninstall.ts
4970
- var CLI_VERSION = "1.7.1";
5035
+ var CLI_VERSION = "1.9.0";
4971
5036
  function registerUninstallCommand(program2) {
4972
5037
  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) => {
4973
5038
  try {
@@ -5044,12 +5109,12 @@ function printUninstallSuccessBox(backupPath) {
5044
5109
  lines.push(` ${chalk.dim("Backup:")} ${backupPath}`);
5045
5110
  lines.push(` ${chalk.dim("Restore:")} ${chalk.cyan(`cp -r "${backupPath}"/* .`)}`);
5046
5111
  }
5047
- process.stdout.write(`${boxen7(lines.join("\n"), { padding: 1, borderStyle: "round" })}
5112
+ process.stdout.write(`${boxen8(lines.join("\n"), { padding: 1, borderStyle: "round" })}
5048
5113
  `);
5049
5114
  }
5050
5115
 
5051
5116
  // src/index.ts
5052
- var CLI_VERSION2 = "1.7.1";
5117
+ var CLI_VERSION2 = "1.9.0";
5053
5118
  var program = new Command();
5054
5119
  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(
5055
5120
  "beforeAll",